From 6a788c7084d1fb90c1884365114ae9fd979196fe Mon Sep 17 00:00:00 2001 From: Yuxin Wu Date: Sat, 4 Aug 2018 11:36:45 -0700 Subject: [PATCH 001/672] Support empty inputs in some maxpool kernels. (#21338) --- tensorflow/core/kernels/maxpooling_op_gpu.cu.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tensorflow/core/kernels/maxpooling_op_gpu.cu.cc b/tensorflow/core/kernels/maxpooling_op_gpu.cu.cc index 0c7a236b2f..89ffe6494e 100644 --- a/tensorflow/core/kernels/maxpooling_op_gpu.cu.cc +++ b/tensorflow/core/kernels/maxpooling_op_gpu.cu.cc @@ -384,6 +384,8 @@ bool MaxPoolForwardNoMask_NCHW_VECT_C::operator()( int32* top_data, const Eigen::GpuDevice& d) { const int kThreadsPerBlock = 1024; const int output_size = batch * channels * pooled_height * pooled_width; + if (output_size == 0) + return true; MaxPoolForwardNoMaskKernel_NCHW_VECT_C<<< (output_size + kThreadsPerBlock - 1) / kThreadsPerBlock, kThreadsPerBlock, 0, d.stream()>>>(output_size, bottom_data, height, width, channels, @@ -402,6 +404,8 @@ bool MaxPoolForwardWithOptionalArgmax::operator()( int64* mask, const Eigen::GpuDevice& d, bool propagate_nans) { const int kThreadsPerBlock = 1024; const int output_size = batch * channels * pooled_height * pooled_width; + if (output_size == 0) + return true; if (propagate_nans) { MaxPoolForwardNHWC <<<(output_size + kThreadsPerBlock - 1) / kThreadsPerBlock, @@ -430,6 +434,8 @@ bool MaxPoolBackwardNoMask::operator()( const int kThreadsPerBlock = 1024; const int bottom_size = batch * channels * height * width; + if (bottom_size == 0) + return true; SetZero<<<(bottom_size + kThreadsPerBlock - 1) / kThreadsPerBlock, kThreadsPerBlock, 0, d.stream()>>>(bottom_size, bottom_diff); @@ -449,6 +455,8 @@ bool MaxPoolBackwardWithArgmax::operator()( const int64* mask, const int top_offset, const int bottom_offset, T* bottom_diff, const Eigen::GpuDevice& d) { const int kThreadsPerBlock = 1024; + if (input_size == 0) + return true; SetZero<<<(input_size + kThreadsPerBlock - 1) / kThreadsPerBlock, kThreadsPerBlock, 0, d.stream()>>>(input_size, bottom_diff); MaxPoolBackward<<<(output_size + kThreadsPerBlock - 1) / kThreadsPerBlock, @@ -466,6 +474,8 @@ bool MaxPoolGradBackwardNoMask::operator()( const int pad_l, const T* top_diff, T* bottom_diff, const Eigen::GpuDevice& d) { const int num_kernels = batch * channels * pooled_height * pooled_width; + if (num_kernels == 0) + return true; CudaLaunchConfig config = GetCudaLaunchConfig(num_kernels, d); if (data_format == FORMAT_NHWC) { @@ -489,6 +499,8 @@ bool MaxPoolGradBackwardWithArgmax::operator()( const int output_size, const int input_size, const T* top_diff, const int64* mask, const int top_offset, const int bottom_offset, T* bottom_diff, const Eigen::GpuDevice& d) { + if (input_size == 0) + return true; CudaLaunchConfig config = GetCudaLaunchConfig(output_size, d); MaxPoolGradBackward<<>>(output_size, top_diff, mask, top_offset, -- GitLab From ccccbe7259f9862e115e267fcce3d8bfb119b3cf Mon Sep 17 00:00:00 2001 From: Cibifang Date: Mon, 27 Aug 2018 09:28:30 +0800 Subject: [PATCH 002/672] Support addition of gradient operations in a graph for golang --- tensorflow/go/graph.go | 67 ++++++++++ tensorflow/go/graph_test.go | 253 ++++++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index 32a77550ee..27dc2d84c7 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -147,6 +147,73 @@ func (g *Graph) Operations() []Operation { return ops } +// AddGradients adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, +// i.e., d(y_1 + y_2 + ...)/dx_1, d(y_1 + y_2 + ...)/dx_2... +// This is a simplified version of AddGradientsWithPrefix() without prefix +func (g *Graph) AddGradients(y []Output, x []Output, dx []Output) ([]Output, error) { + return g.AddGradientsWithPrefix("", y, x, dx) +} + +// AddGradientsWithPrefix adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, +// i.e., d(y_1 + y_2 + ...)/dx_1, d(y_1 + y_2 + ...)/dx_2... +// This is a variant of AddGradients that allows to caller to pass a custom +// name prefix to the operations added to a graph to compute the gradients. +func (g *Graph) AddGradientsWithPrefix(prefix string, y []Output, x []Output, dx []Output) ([]Output, error) { + var ( + cprefix = C.CString(prefix) + + cy = make([]C.TF_Output, len(y)) + cx = make([]C.TF_Output, len(x)) + cdx = make([]C.TF_Output, len(dx)) + cdy = make([]C.TF_Output, len(x)) + + pcy *C.TF_Output + pcx *C.TF_Output + pcdx *C.TF_Output + pcdy *C.TF_Output + + status = newStatus() + ) + + if len(y) > 0 { + pcy = &cy[0] + for i, o := range y { + cy[i] = o.c() + } + } + if len(x) > 0 { + pcx = &cx[0] + for i, o := range x { + cx[i] = o.c() + } + pcdy = &cdy[0] + } + if len(dx) > 0 { + pcdx = &cdx[0] + for i, o := range dx { + cdx[i] = o.c() + } + } + + // If prefix is "", the C.TF_AddGradientsWithPrefix need cprefix to be nil but not "" + if len(prefix) == 0 { + C.TF_AddGradientsWithPrefix(g.c, nil, pcy, C.int(len(y)), pcx, C.int(len(x)), pcdx, status.c, pcdy) + } else { + C.TF_AddGradientsWithPrefix(g.c, cprefix, pcy, C.int(len(y)), pcx, C.int(len(x)), pcdx, status.c, pcdy) + } + + if err := status.Err(); err != nil { + return nil, err + } + dy := make([]Output, len(x)) + for i, co := range cdy { + op := &Operation{co.oper, g} + dy[i] = Output{op, int(co.index)} + } + + return dy, nil +} + // OpSpec is the specification of an Operation to be added to a Graph // (using Graph.AddOperation). type OpSpec struct { diff --git a/tensorflow/go/graph_test.go b/tensorflow/go/graph_test.go index b8d65c54f6..d9126f36ac 100644 --- a/tensorflow/go/graph_test.go +++ b/tensorflow/go/graph_test.go @@ -19,6 +19,7 @@ package tensorflow import ( "bytes" "fmt" + "strings" "testing" ) @@ -80,3 +81,255 @@ func TestGraphWriteToAndImport(t *testing.T) { t.Error(err) } } + +func TestGraphAddGradients(t *testing.T) { + g := NewGraph() + x1, err := Placeholder(g, "x1", Float) + if err != nil { + t.Fatal(err) + } + x2, err := Placeholder(g, "x2", Float) + if err != nil { + t.Fatal(err) + } + op0, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y0", + Input: []Input{x1}, + }) + if err != nil { + t.Fatal(err) + } + y0 := op0.Output(0) + op1, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y1", + Input: []Input{y0}, + }) + if err != nil { + t.Fatal(err) + } + y1 := op1.Output(0) + op2, err := g.AddOperation(OpSpec{ + Type: "AddN", + Input: []Input{OutputList([]Output{y0, x2})}, + }) + if err != nil { + t.Fatal(err) + } + y2 := op2.Output(0) + + grads0, err := g.AddGradients([]Output{y1}, []Output{x1}, nil) + if err != nil { + t.Fatal(err) + } + if len(grads0) != 1 { + t.Fatal(len(grads0)) + } + if grads0[0].DataType() != Float { + t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), Float) + } + + grads1, err := g.AddGradients([]Output{y2}, []Output{x1, x2}, nil) + if err != nil { + t.Fatal(err) + } + if len(grads1) != 2 { + t.Fatal(len(grads1)) + } + if grads1[0].DataType() != Float { + t.Fatalf("Got DataType %v, wanted %v", grads1[0].DataType(), Float) + } + if grads1[1].DataType() != Float { + t.Fatalf("Got DataType %v, wanted %v", grads1[1].DataType(), Float) + } + + sess, err := NewSession(g, nil) + if err != nil { + t.Fatal(err) + } + + c1, _ := NewTensor(float32(3.0)) + c2, _ := NewTensor(float32(2.0)) + outputs, err := sess.Run( + map[Output]*Tensor{x1: c1, x2: c2}, + []Output{grads0[0], grads1[0], grads1[1]}, + nil) + if err != nil { + t.Fatal(err) + } + if len(outputs) != 3 { + t.Fatal(len(outputs)) + } + if outputs[0].Value().(float32) != 108.0 { + t.Fatalf("Got %v, wanted float 108.0", outputs[0].Value()) + } + if outputs[1].Value().(float32) != 6.0 { + t.Fatalf("Got %v, wanted float 6.0", outputs[1].Value()) + } + if outputs[2].Value().(float32) != 1.0 { + t.Fatalf("Got %v, wanted float 1.0", outputs[2].Value()) + } +} + +func TestGraphAddGradientsSums(t *testing.T) { + g := NewGraph() + x, err := Placeholder(g, "x", Float) + if err != nil { + t.Fatal(err) + } + op0, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y0", + Input: []Input{x}, + }) + if err != nil { + t.Fatal(err) + } + y0 := op0.Output(0) + op1, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y1", + Input: []Input{y0}, + }) + y1 := op1.Output(0) + + grad, err := g.AddGradients([]Output{y0, y1}, []Output{x}, nil) + if err != nil { + t.Fatal(err) + } + if len(grad) != 1 { + t.Fatal(len(grad)) + } + if grad[0].DataType() != Float { + t.Fatalf("Got DataType %v, wanted %v", grad[0].DataType(), Float) + } + + sess, err := NewSession(g, nil) + if err != nil { + t.Fatal(err) + } + + c, _ := NewTensor(float32(3.0)) + outputs, err := sess.Run( + map[Output]*Tensor{x: c}, + []Output{grad[0]}, + nil) + if err != nil { + t.Fatal(err) + } + if outputs[0].Value().(float32) != 114.0 { + t.Fatalf("Got %v, wanted float 114.0", outputs[0].Value()) + } +} + +func TestGraphAddGradientsWithInitialValuesToGraph(t *testing.T) { + g := NewGraph() + x, err := Placeholder(g, "x", Float) + op0, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y0", + Input: []Input{x}, + }) + if err != nil { + t.Fatal(err) + } + y0 := op0.Output(0) + op1, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y1", + Input: []Input{y0}, + }) + if err != nil { + t.Fatal(err) + } + y1 := op1.Output(0) + + grads0, err := g.AddGradients([]Output{y1}, []Output{y0}, nil) + if err != nil { + t.Fatal(err) + } + if len(grads0) != 1 { + t.Fatal(len(grads0)) + } + if grads0[0].DataType() != Float { + t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), Float) + } + + grads1, err := g.AddGradients([]Output{y0}, []Output{x}, []Output{grads0[0]}) + if err != nil { + t.Fatal(err) + } + if len(grads1) != 1 { + t.Fatal(len(grads1)) + } + if grads1[0].DataType() != Float { + t.Fatalf("Got DataType %v, wanted %v", grads1[0].DataType(), Float) + } + + sess, err := NewSession(g, nil) + if err != nil { + t.Fatal(err) + } + + c, _ := NewTensor(float32(3.0)) + outputs, err := sess.Run( + map[Output]*Tensor{x: c}, + []Output{grads1[0]}, + nil) + if err != nil { + t.Fatal(err) + } + if outputs[0].Value().(float32) != 108.0 { + t.Fatalf("Got %v, wanted float 108.0", outputs[0].Value()) + } +} + +func TestGraphValidateGradientsNames(t *testing.T) { + g := NewGraph() + x, err := Placeholder(g, "x", Float) + if err != nil { + t.Fatal(err) + } + op0, err := g.AddOperation(OpSpec{ + Type: "Square", + Name: "y0", + Input: []Input{x}, + }) + if err != nil { + t.Fatal(err) + } + y0 := op0.Output(0) + + grads0, err := g.AddGradients([]Output{y0}, []Output{x}, nil) + if err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads0[0].Op.Name(), "gradients/") { + t.Fatalf("Got name %v, wanted started with gradients/", grads0[0].Op.Name()) + } + + grads1, err := g.AddGradients([]Output{y0}, []Output{x}, nil) + if err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads1[0].Op.Name(), "gradients_1/") { + t.Fatalf("Got name %v, wanted started with gradients_1/", grads1[0].Op.Name()) + } + + grads2, err := g.AddGradientsWithPrefix("more_gradients", []Output{y0}, []Output{x}, nil) + if err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads2[0].Op.Name(), "more_gradients/") { + t.Fatalf("Got name %v, wanted started with more_gradients/", grads2[0].Op.Name()) + } + + grads3, err := g.AddGradientsWithPrefix("even_more_gradients", []Output{y0}, []Output{x}, nil) + if err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads3[0].Op.Name(), "even_more_gradients/") { + t.Fatalf("Got name %v, wanted started with even_more_gradients/", grads3[0].Op.Name()) + } +} -- GitLab From 5d2226e93d48c1f4a0730edc573b886cc6b87e68 Mon Sep 17 00:00:00 2001 From: jackonan Date: Fri, 7 Sep 2018 10:42:55 +0800 Subject: [PATCH 003/672] Fix ps0 OOM when workers too many. When training with MonitoredTrainingSession in distributed mode, all ops related with report_uninitialized_xxx will be placed on ps0, which may lead to OOM when workers up to thousands. We use a environment variable to solve it. When OOM happens, users can set the local device to fix the problem, such as os.environ['TF_LOCAL_DEVICE'] = '/job:worker/task:index'. --- tensorflow/python/ops/resources.py | 4 +++- tensorflow/python/ops/variables.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/resources.py b/tensorflow/python/ops/resources.py index db6740643c..98ed07999f 100644 --- a/tensorflow/python/ops/resources.py +++ b/tensorflow/python/ops/resources.py @@ -21,6 +21,7 @@ from __future__ import division from __future__ import print_function import collections +import os from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -86,7 +87,8 @@ def report_uninitialized_resources(resource_list=None, resource_list = shared_resources() + local_resources() with ops.name_scope(name): # Run all operations on CPU - with ops.device("/cpu:0"): + local_device = os.environ.get("TF_LOCAL_DEVICE", "/cpu:0") + with ops.device(local_device): if not resource_list: # Return an empty tensor so we only need to check for returned tensor # size being 0 as an indication of model ready. diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index d03d93beeb..ac0b36efc5 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -19,6 +19,7 @@ from __future__ import print_function import enum # pylint: disable=g-bad-import-order +import os import six from tensorflow.core.framework import attr_value_pb2 @@ -2283,7 +2284,8 @@ def report_uninitialized_variables(var_list=None, # Run all operations on CPU if var_list: init_vars = [state_ops.is_variable_initialized(v) for v in var_list] - with ops.device("/cpu:0"): + local_device = os.environ.get("TF_LOCAL_DEVICE", "/cpu:0") + with ops.device(local_device): if not var_list: # Return an empty tensor so we only need to check for returned tensor # size being 0 as an indication of model ready. -- GitLab From a9a6c8efec20b67b0f9d49dec6c890ec4b1ac18c Mon Sep 17 00:00:00 2001 From: Cibifang Date: Sat, 8 Sep 2018 20:40:04 +0800 Subject: [PATCH 004/672] Combine AddGradients and AddGradientsWithPrefix Methods in golang --- tensorflow/go/graph.go | 13 +++---------- tensorflow/go/graph_test.go | 18 +++++++++--------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index 27dc2d84c7..6fe2b6b86d 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -147,18 +147,11 @@ func (g *Graph) Operations() []Operation { return ops } -// AddGradients adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, -// i.e., d(y_1 + y_2 + ...)/dx_1, d(y_1 + y_2 + ...)/dx_2... -// This is a simplified version of AddGradientsWithPrefix() without prefix -func (g *Graph) AddGradients(y []Output, x []Output, dx []Output) ([]Output, error) { - return g.AddGradientsWithPrefix("", y, x, dx) -} - // AddGradientsWithPrefix adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, // i.e., d(y_1 + y_2 + ...)/dx_1, d(y_1 + y_2 + ...)/dx_2... -// This is a variant of AddGradients that allows to caller to pass a custom -// name prefix to the operations added to a graph to compute the gradients. -func (g *Graph) AddGradientsWithPrefix(prefix string, y []Output, x []Output, dx []Output) ([]Output, error) { +// This methods allows to caller to pass a custom name prefix to the operations +// added to a graph to compute the gradients. +func (g *Graph) AddGradients(prefix string, y []Output, x []Output, dx []Output) ([]Output, error) { var ( cprefix = C.CString(prefix) diff --git a/tensorflow/go/graph_test.go b/tensorflow/go/graph_test.go index d9126f36ac..d8f32dbaa9 100644 --- a/tensorflow/go/graph_test.go +++ b/tensorflow/go/graph_test.go @@ -119,7 +119,7 @@ func TestGraphAddGradients(t *testing.T) { } y2 := op2.Output(0) - grads0, err := g.AddGradients([]Output{y1}, []Output{x1}, nil) + grads0, err := g.AddGradients("", []Output{y1}, []Output{x1}, nil) if err != nil { t.Fatal(err) } @@ -130,7 +130,7 @@ func TestGraphAddGradients(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), Float) } - grads1, err := g.AddGradients([]Output{y2}, []Output{x1, x2}, nil) + grads1, err := g.AddGradients("", []Output{y2}, []Output{x1, x2}, nil) if err != nil { t.Fatal(err) } @@ -194,7 +194,7 @@ func TestGraphAddGradientsSums(t *testing.T) { }) y1 := op1.Output(0) - grad, err := g.AddGradients([]Output{y0, y1}, []Output{x}, nil) + grad, err := g.AddGradients("", []Output{y0, y1}, []Output{x}, nil) if err != nil { t.Fatal(err) } @@ -245,7 +245,7 @@ func TestGraphAddGradientsWithInitialValuesToGraph(t *testing.T) { } y1 := op1.Output(0) - grads0, err := g.AddGradients([]Output{y1}, []Output{y0}, nil) + grads0, err := g.AddGradients("", []Output{y1}, []Output{y0}, nil) if err != nil { t.Fatal(err) } @@ -256,7 +256,7 @@ func TestGraphAddGradientsWithInitialValuesToGraph(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), Float) } - grads1, err := g.AddGradients([]Output{y0}, []Output{x}, []Output{grads0[0]}) + grads1, err := g.AddGradients("", []Output{y0}, []Output{x}, []Output{grads0[0]}) if err != nil { t.Fatal(err) } @@ -301,7 +301,7 @@ func TestGraphValidateGradientsNames(t *testing.T) { } y0 := op0.Output(0) - grads0, err := g.AddGradients([]Output{y0}, []Output{x}, nil) + grads0, err := g.AddGradients("", []Output{y0}, []Output{x}, nil) if err != nil { t.Fatal(err) } @@ -309,7 +309,7 @@ func TestGraphValidateGradientsNames(t *testing.T) { t.Fatalf("Got name %v, wanted started with gradients/", grads0[0].Op.Name()) } - grads1, err := g.AddGradients([]Output{y0}, []Output{x}, nil) + grads1, err := g.AddGradients("", []Output{y0}, []Output{x}, nil) if err != nil { t.Fatal(err) } @@ -317,7 +317,7 @@ func TestGraphValidateGradientsNames(t *testing.T) { t.Fatalf("Got name %v, wanted started with gradients_1/", grads1[0].Op.Name()) } - grads2, err := g.AddGradientsWithPrefix("more_gradients", []Output{y0}, []Output{x}, nil) + grads2, err := g.AddGradients("more_gradients", []Output{y0}, []Output{x}, nil) if err != nil { t.Fatal(err) } @@ -325,7 +325,7 @@ func TestGraphValidateGradientsNames(t *testing.T) { t.Fatalf("Got name %v, wanted started with more_gradients/", grads2[0].Op.Name()) } - grads3, err := g.AddGradientsWithPrefix("even_more_gradients", []Output{y0}, []Output{x}, nil) + grads3, err := g.AddGradients("even_more_gradients", []Output{y0}, []Output{x}, nil) if err != nil { t.Fatal(err) } -- GitLab From 9f64bbb0091d0e6ee917ab40e65fc19fa1425da2 Mon Sep 17 00:00:00 2001 From: Cibifang Date: Wed, 12 Sep 2018 11:26:15 +0800 Subject: [PATCH 005/672] Fix gradients test in golang 1. fix some test name. 2. add test for existing prefix. --- tensorflow/go/graph_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tensorflow/go/graph_test.go b/tensorflow/go/graph_test.go index d8f32dbaa9..067c7db5c3 100644 --- a/tensorflow/go/graph_test.go +++ b/tensorflow/go/graph_test.go @@ -223,7 +223,7 @@ func TestGraphAddGradientsSums(t *testing.T) { } } -func TestGraphAddGradientsWithInitialValuesToGraph(t *testing.T) { +func TestGraphAddGradientsWithInitialValues(t *testing.T) { g := NewGraph() x, err := Placeholder(g, "x", Float) op0, err := g.AddOperation(OpSpec{ @@ -332,4 +332,9 @@ func TestGraphValidateGradientsNames(t *testing.T) { if !strings.HasPrefix(grads3[0].Op.Name(), "even_more_gradients/") { t.Fatalf("Got name %v, wanted started with even_more_gradients/", grads3[0].Op.Name()) } + + _, err = g.AddGradients("even_more_gradients", []Output{y0}, []Output{x}, nil) + if err == nil { + t.Error("AddGradients should have failed if gradients name is already existing") + } } -- GitLab From e40c032d62075621053262758c065f9bfb9faed9 Mon Sep 17 00:00:00 2001 From: Cibifang Date: Wed, 12 Sep 2018 15:00:23 +0800 Subject: [PATCH 006/672] Support addition of gradient operations in op package for golang 1. Add Gradients method in op package Enforce uniqueness of custom prefixes for gradients. 2. Add unit test for Gradients --- tensorflow/go/op/gradients.go | 41 +++++ tensorflow/go/op/gradients_test.go | 233 +++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+) create mode 100644 tensorflow/go/op/gradients.go create mode 100644 tensorflow/go/op/gradients_test.go diff --git a/tensorflow/go/op/gradients.go b/tensorflow/go/op/gradients.go new file mode 100644 index 0000000000..2dce134d5f --- /dev/null +++ b/tensorflow/go/op/gradients.go @@ -0,0 +1,41 @@ +/* +Copyright 2016 The TensorFlow Authors. 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. +*/ + +package op + +import tf "github.com/tensorflow/tensorflow/tensorflow/go" + +// Gradients adds gradients computation ops to the graph according to scope. +// +// Arguments: +// prefix: unique string prefix applied before the names of nodes added to the graph to +// compute gradients. If null, will use "Gradients". +// y: output of the function to derive +// x: inputs of the function for which partial derivatives are computed +// dx: if not null, the partial derivatives of some loss function L w.r.t. y +// +// return the partial derivatives +func Gradients(scope *Scope, prefix string, y []tf.Output, x []tf.Output, dx ...tf.Output) (output []tf.Output) { + var err error + if prefix == "" { + prefix = "Gradients" + } + if output, err = scope.graph.AddGradients(scope.opName(scope.uniqueName(prefix)), y, x, dx); err != nil { + scope.UpdateErr("Gradients", err) + return + } + return output +} diff --git a/tensorflow/go/op/gradients_test.go b/tensorflow/go/op/gradients_test.go new file mode 100644 index 0000000000..7d03fada74 --- /dev/null +++ b/tensorflow/go/op/gradients_test.go @@ -0,0 +1,233 @@ +/* +Copyright 2016 The TensorFlow Authors. 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. +*/ + +package op + +import ( + "strings" + "testing" + + tf "github.com/tensorflow/tensorflow/tensorflow/go" +) + +func TestAddGradients(t *testing.T) { + var ( + s = NewScope() + x1 = Placeholder(s.SubScope("x1"), tf.Float) + x2 = Placeholder(s.SubScope("x2"), tf.Float) + y0 = Square(s.SubScope("y0"), x1) + y1 = Square(s.SubScope("y1"), y0) + y2 = AddN(s.SubScope("y2"), []tf.Output{y0, x2}) + ) + + grads0 := Gradients(s, "", []tf.Output{y1}, []tf.Output{x1}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if len(grads0) != 1 { + t.Fatal(len(grads0)) + } + if grads0[0].DataType() != tf.Float { + t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), tf.Float) + } + + grads1 := Gradients(s, "", []tf.Output{y2}, []tf.Output{x1, x2}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if len(grads1) != 2 { + t.Fatal(len(grads1)) + } + if grads1[0].DataType() != tf.Float { + t.Fatalf("Got DataType %v, wanted %v", grads1[0].DataType(), tf.Float) + } + if grads1[1].DataType() != tf.Float { + t.Fatalf("Got DataType %v, wanted %v", grads1[1].DataType(), tf.Float) + } + + graph, err := s.Finalize() + if err != nil { + t.Fatal(err) + } + sess, err := tf.NewSession(graph, nil) + if err != nil { + t.Fatal(err) + } + + c1, _ := tf.NewTensor(float32(3.0)) + c2, _ := tf.NewTensor(float32(3.0)) + outputs, err := sess.Run( + map[tf.Output]*tf.Tensor{x1: c1, x2: c2}, + []tf.Output{grads0[0], grads1[0], grads1[1]}, + nil) + if err != nil { + t.Fatal(err) + } + if len(outputs) != 3 { + t.Fatal(len(outputs)) + } + if outputs[0].Value().(float32) != 108.0 { + t.Fatalf("Got %v, wanted float 108.0", outputs[0].Value()) + } + if outputs[1].Value().(float32) != 6.0 { + t.Fatalf("Got %v, wanted float 6.0", outputs[1].Value()) + } + if outputs[2].Value().(float32) != 1.0 { + t.Fatalf("Got %v, wanted float 1.0", outputs[2].Value()) + } +} + +func TestAddGradientsSums(t *testing.T) { + var ( + s = NewScope() + x = Placeholder(s.SubScope("x"), tf.Float) + y0 = Square(s.SubScope("y0"), x) + y1 = Square(s.SubScope("y1"), y0) + ) + + grad := Gradients(s, "", []tf.Output{y0, y1}, []tf.Output{x}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if len(grad) != 1 { + t.Fatal(len(grad)) + } + if grad[0].DataType() != tf.Float { + t.Fatalf("Got DataType %v, wanted %v", grad[0].DataType(), tf.Float) + } + + graph, err := s.Finalize() + if err != nil { + t.Fatal(err) + } + sess, err := tf.NewSession(graph, nil) + if err != nil { + t.Fatal(err) + } + + c, _ := tf.NewTensor(float32(3.0)) + outputs, err := sess.Run( + map[tf.Output]*tf.Tensor{x: c}, + []tf.Output{grad[0]}, + nil) + if err != nil { + t.Fatal(err) + } + if outputs[0].Value().(float32) != 114.0 { + t.Fatalf("Got %v, wanted float 114.0", outputs[0].Value()) + } +} + +func TestAddGradientsWithInitialValues(t *testing.T) { + var ( + s = NewScope() + x = Placeholder(s.SubScope("x1"), tf.Float) + y0 = Square(s.SubScope("y0"), x) + y1 = Square(s.SubScope("y1"), y0) + ) + + grads0 := Gradients(s, "", []tf.Output{y1}, []tf.Output{y0}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if len(grads0) != 1 { + t.Fatal(len(grads0)) + } + if grads0[0].DataType() != tf.Float { + t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), tf.Float) + } + + grads1 := Gradients(s, "", []tf.Output{y0}, []tf.Output{x}, grads0[0]) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if len(grads1) != 1 { + t.Fatal(len(grads1)) + } + if grads1[0].DataType() != tf.Float { + t.Fatalf("Got DataType %v, wanted %v", grads1[0].DataType(), tf.Float) + } + + graph, err := s.Finalize() + if err != nil { + t.Fatal(err) + } + sess, err := tf.NewSession(graph, nil) + if err != nil { + t.Fatal(err) + } + + c, _ := tf.NewTensor(float32(3.0)) + outputs, err := sess.Run( + map[tf.Output]*tf.Tensor{x: c}, + []tf.Output{grads1[0]}, + nil) + if err != nil { + t.Fatal(err) + } + if outputs[0].Value().(float32) != 108.0 { + t.Fatalf("Got %v, wanted float 108.0", outputs[0].Value()) + } +} + +func TestValidateGradientsNames(t *testing.T) { + var ( + s = NewScope() + x = Placeholder(s.SubScope("x"), tf.Float) + y0 = Square(s.SubScope("y0"), x) + ) + + grads0 := Gradients(s, "", []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads0[0].Op.Name(), "Gradients/") { + t.Fatalf("Got name %v, wanted started with Gradients/", grads0[0].Op.Name()) + } + + grads1 := Gradients(s, "", []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads1[0].Op.Name(), "Gradients_1/") { + t.Fatalf("Got name %v, wanted started with Gradients_1/", grads1[0].Op.Name()) + } + + grads2 := Gradients(s, "more_gradients", []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads2[0].Op.Name(), "more_gradients/") { + t.Fatalf("Got name %v, wanted started with more_gradients/", grads2[0].Op.Name()) + } + + sub := s.SubScope("sub") + grads3 := Gradients(sub, "even_more_gradients", []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads3[0].Op.Name(), "sub/even_more_gradients/") { + t.Fatalf("Got name %v, wanted started with sub/even_more_gradients/", grads3[0].Op.Name()) + } + + grads4 := Gradients(sub, "even_more_gradients", []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err != nil { + t.Fatal(err) + } + if !strings.HasPrefix(grads4[0].Op.Name(), "sub/even_more_gradients_1/") { + t.Fatalf("Got name %v, wanted started with sub/even_more_gradients_1/", grads4[0].Op.Name()) + } +} -- GitLab From b9e5738fb4b5f53e8d15aadd75506f662b04643d Mon Sep 17 00:00:00 2001 From: Cibifang Date: Fri, 28 Sep 2018 07:36:41 +0800 Subject: [PATCH 007/672] Fix comment in graph.go. Method name is AddGradients but not AddGradientsWithPrefix. --- tensorflow/go/graph.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index 6fe2b6b86d..4204ad1cc4 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -147,7 +147,7 @@ func (g *Graph) Operations() []Operation { return ops } -// AddGradientsWithPrefix adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, +// AddGradients adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, // i.e., d(y_1 + y_2 + ...)/dx_1, d(y_1 + y_2 + ...)/dx_2... // This methods allows to caller to pass a custom name prefix to the operations // added to a graph to compute the gradients. -- GitLab From 72ba6b227128c29847c9d3e4ceaded1032b9b8cc Mon Sep 17 00:00:00 2001 From: Cibifang Date: Fri, 28 Sep 2018 08:20:28 +0800 Subject: [PATCH 008/672] Fix calls to C.CString() in graph.go to avoid memory leaks. --- tensorflow/go/graph.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index 4204ad1cc4..096a182840 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -153,7 +153,7 @@ func (g *Graph) Operations() []Operation { // added to a graph to compute the gradients. func (g *Graph) AddGradients(prefix string, y []Output, x []Output, dx []Output) ([]Output, error) { var ( - cprefix = C.CString(prefix) + cprefix *C.char cy = make([]C.TF_Output, len(y)) cx = make([]C.TF_Output, len(x)) @@ -189,12 +189,13 @@ func (g *Graph) AddGradients(prefix string, y []Output, x []Output, dx []Output) } // If prefix is "", the C.TF_AddGradientsWithPrefix need cprefix to be nil but not "" - if len(prefix) == 0 { - C.TF_AddGradientsWithPrefix(g.c, nil, pcy, C.int(len(y)), pcx, C.int(len(x)), pcdx, status.c, pcdy) - } else { - C.TF_AddGradientsWithPrefix(g.c, cprefix, pcy, C.int(len(y)), pcx, C.int(len(x)), pcdx, status.c, pcdy) + if len(prefix) != 0 { + cprefix = C.CString(prefix) + defer C.free(unsafe.Pointer(cprefix)) } + C.TF_AddGradientsWithPrefix(g.c, cprefix, pcy, C.int(len(y)), pcx, C.int(len(x)), pcdx, status.c, pcdy) + if err := status.Err(); err != nil { return nil, err } -- GitLab From 8c9d5eb52b0d8e551b0e751186edfcdecbef62fb Mon Sep 17 00:00:00 2001 From: Cibifang Date: Mon, 1 Oct 2018 18:02:32 +0800 Subject: [PATCH 009/672] Remove from func Gradients() in gradients.go --- tensorflow/go/op/gradients.go | 9 ++------ tensorflow/go/op/gradients_test.go | 34 ++++++++++++------------------ 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/tensorflow/go/op/gradients.go b/tensorflow/go/op/gradients.go index 2dce134d5f..2397e40bf4 100644 --- a/tensorflow/go/op/gradients.go +++ b/tensorflow/go/op/gradients.go @@ -21,19 +21,14 @@ import tf "github.com/tensorflow/tensorflow/tensorflow/go" // Gradients adds gradients computation ops to the graph according to scope. // // Arguments: -// prefix: unique string prefix applied before the names of nodes added to the graph to -// compute gradients. If null, will use "Gradients". // y: output of the function to derive // x: inputs of the function for which partial derivatives are computed // dx: if not null, the partial derivatives of some loss function L w.r.t. y // // return the partial derivatives -func Gradients(scope *Scope, prefix string, y []tf.Output, x []tf.Output, dx ...tf.Output) (output []tf.Output) { +func Gradients(scope *Scope, y []tf.Output, x []tf.Output, dx ...tf.Output) (output []tf.Output) { var err error - if prefix == "" { - prefix = "Gradients" - } - if output, err = scope.graph.AddGradients(scope.opName(scope.uniqueName(prefix)), y, x, dx); err != nil { + if output, err = scope.graph.AddGradients(scope.opName(scope.uniqueName("Gradients")), y, x, dx); err != nil { scope.UpdateErr("Gradients", err) return } diff --git a/tensorflow/go/op/gradients_test.go b/tensorflow/go/op/gradients_test.go index 7d03fada74..2bcb3e88eb 100644 --- a/tensorflow/go/op/gradients_test.go +++ b/tensorflow/go/op/gradients_test.go @@ -33,7 +33,7 @@ func TestAddGradients(t *testing.T) { y2 = AddN(s.SubScope("y2"), []tf.Output{y0, x2}) ) - grads0 := Gradients(s, "", []tf.Output{y1}, []tf.Output{x1}) + grads0 := Gradients(s, []tf.Output{y1}, []tf.Output{x1}) if err := s.Err(); err != nil { t.Fatal(err) } @@ -44,7 +44,7 @@ func TestAddGradients(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), tf.Float) } - grads1 := Gradients(s, "", []tf.Output{y2}, []tf.Output{x1, x2}) + grads1 := Gradients(s, []tf.Output{y2}, []tf.Output{x1, x2}) if err := s.Err(); err != nil { t.Fatal(err) } @@ -98,7 +98,7 @@ func TestAddGradientsSums(t *testing.T) { y1 = Square(s.SubScope("y1"), y0) ) - grad := Gradients(s, "", []tf.Output{y0, y1}, []tf.Output{x}) + grad := Gradients(s, []tf.Output{y0, y1}, []tf.Output{x}) if err := s.Err(); err != nil { t.Fatal(err) } @@ -139,7 +139,7 @@ func TestAddGradientsWithInitialValues(t *testing.T) { y1 = Square(s.SubScope("y1"), y0) ) - grads0 := Gradients(s, "", []tf.Output{y1}, []tf.Output{y0}) + grads0 := Gradients(s, []tf.Output{y1}, []tf.Output{y0}) if err := s.Err(); err != nil { t.Fatal(err) } @@ -150,7 +150,7 @@ func TestAddGradientsWithInitialValues(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), tf.Float) } - grads1 := Gradients(s, "", []tf.Output{y0}, []tf.Output{x}, grads0[0]) + grads1 := Gradients(s, []tf.Output{y0}, []tf.Output{x}, grads0[0]) if err := s.Err(); err != nil { t.Fatal(err) } @@ -190,7 +190,7 @@ func TestValidateGradientsNames(t *testing.T) { y0 = Square(s.SubScope("y0"), x) ) - grads0 := Gradients(s, "", []tf.Output{y0}, []tf.Output{x}) + grads0 := Gradients(s, []tf.Output{y0}, []tf.Output{x}) if err := s.Err(); err != nil { t.Fatal(err) } @@ -198,7 +198,7 @@ func TestValidateGradientsNames(t *testing.T) { t.Fatalf("Got name %v, wanted started with Gradients/", grads0[0].Op.Name()) } - grads1 := Gradients(s, "", []tf.Output{y0}, []tf.Output{x}) + grads1 := Gradients(s, []tf.Output{y0}, []tf.Output{x}) if err := s.Err(); err != nil { t.Fatal(err) } @@ -206,28 +206,20 @@ func TestValidateGradientsNames(t *testing.T) { t.Fatalf("Got name %v, wanted started with Gradients_1/", grads1[0].Op.Name()) } - grads2 := Gradients(s, "more_gradients", []tf.Output{y0}, []tf.Output{x}) - if err := s.Err(); err != nil { - t.Fatal(err) - } - if !strings.HasPrefix(grads2[0].Op.Name(), "more_gradients/") { - t.Fatalf("Got name %v, wanted started with more_gradients/", grads2[0].Op.Name()) - } - sub := s.SubScope("sub") - grads3 := Gradients(sub, "even_more_gradients", []tf.Output{y0}, []tf.Output{x}) + grads3 := Gradients(sub, []tf.Output{y0}, []tf.Output{x}) if err := s.Err(); err != nil { t.Fatal(err) } - if !strings.HasPrefix(grads3[0].Op.Name(), "sub/even_more_gradients/") { - t.Fatalf("Got name %v, wanted started with sub/even_more_gradients/", grads3[0].Op.Name()) + if !strings.HasPrefix(grads3[0].Op.Name(), "sub/Gradients/") { + t.Fatalf("Got name %v, wanted started with sub/Gradients/", grads3[0].Op.Name()) } - grads4 := Gradients(sub, "even_more_gradients", []tf.Output{y0}, []tf.Output{x}) + grads4 := Gradients(sub, []tf.Output{y0}, []tf.Output{x}) if err := s.Err(); err != nil { t.Fatal(err) } - if !strings.HasPrefix(grads4[0].Op.Name(), "sub/even_more_gradients_1/") { - t.Fatalf("Got name %v, wanted started with sub/even_more_gradients_1/", grads4[0].Op.Name()) + if !strings.HasPrefix(grads4[0].Op.Name(), "sub/Gradients_1/") { + t.Fatalf("Got name %v, wanted started with sub/Gradients_1/", grads4[0].Op.Name()) } } -- GitLab From 84209c3bd430f82ef247f668f8bf8b1f77420b6e Mon Sep 17 00:00:00 2001 From: jackonan Date: Sat, 6 Oct 2018 16:02:09 +0800 Subject: [PATCH 010/672] Change the key to 'TF_DEVICE_FOR_UNINITIALIZED_VARIABLE_REPORTING'. --- tensorflow/python/ops/resources.py | 2 +- tensorflow/python/ops/variables.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/resources.py b/tensorflow/python/ops/resources.py index 98ed07999f..6cd12b7bbb 100644 --- a/tensorflow/python/ops/resources.py +++ b/tensorflow/python/ops/resources.py @@ -87,7 +87,7 @@ def report_uninitialized_resources(resource_list=None, resource_list = shared_resources() + local_resources() with ops.name_scope(name): # Run all operations on CPU - local_device = os.environ.get("TF_LOCAL_DEVICE", "/cpu:0") + local_device = os.environ.get("TF_DEVICE_FOR_UNINITIALIZED_VARIABLE_REPORTING", "/cpu:0") with ops.device(local_device): if not resource_list: # Return an empty tensor so we only need to check for returned tensor diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index ac0b36efc5..784761e17e 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -2284,7 +2284,7 @@ def report_uninitialized_variables(var_list=None, # Run all operations on CPU if var_list: init_vars = [state_ops.is_variable_initialized(v) for v in var_list] - local_device = os.environ.get("TF_LOCAL_DEVICE", "/cpu:0") + local_device = os.environ.get("TF_DEVICE_FOR_UNINITIALIZED_VARIABLE_REPORTING", "/cpu:0") with ops.device(local_device): if not var_list: # Return an empty tensor so we only need to check for returned tensor -- GitLab From 406c4ad08f00aafec76e95478f4b1e7d87a5427a Mon Sep 17 00:00:00 2001 From: Alexis Louis Date: Thu, 11 Oct 2018 14:38:47 +0200 Subject: [PATCH 011/672] README Updates Clarification of code examples for fast copy-paste replication. (I did run the code myself and encountered those little missing elements) - Estimator declaration placed after config declaration - loss_fn() incoherent with previous loss variable declaration --- tensorflow/contrib/distribute/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/distribute/README.md b/tensorflow/contrib/distribute/README.md index 2e025765e4..2389b89eb6 100644 --- a/tensorflow/contrib/distribute/README.md +++ b/tensorflow/contrib/distribute/README.md @@ -131,7 +131,7 @@ def model_fn(features, labels, mode): return tf.estimator.EstimatorSpec(mode, loss=loss) if mode == tf.estimator.ModeKeys.TRAIN: - train_op = tf.train.GradientDescentOptimizer(0.2).minimize(loss_fn()) + train_op = tf.train.GradientDescentOptimizer(0.2).minimize(loss) return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op) ``` @@ -248,10 +248,10 @@ start multi-worker training using `tf.estimator.train_and_evaluate`: ```python def model_main(): - estimator = ... distribution = tf.contrib.distribute.CollectiveAllReduceStrategy( num_gpus_per_worker=2) config = tf.estimator.RunConfig(train_distribute=distribution) + estimator = tf.estimator.Estimator(model_fn=model_fn, config=config) train_spec = tf.estimator.TrainSpec(input_fn=input_fn) eval_spec = tf.estimator.EvalSpec(input_fn=eval_input_fn) tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec) @@ -324,13 +324,13 @@ start training. On your laptop, you can run ```python -estimator = ... distribution = tf.contrib.distribute.CollectiveAllReduceStrategy( num_gpus_per_worker=2) config = tf.estimator.RunConfig( experimental_distribute=tf.contrib.distribute.DistributeConfig( train_distribute=distribution, remote_cluster={"worker": ["host1:port", "host2:port", "host3:port"]})) +estimator = tf.estimator.Estimator(model_fn=model_fn, config=config) train_spec = tf.estimator.TrainSpec(input_fn=input_fn) eval_spec = tf.estimator.EvalSpec(input_fn=eval_input_fn) tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec) -- GitLab From f0cd69e047eb8f29538a27a41c17da20a1c59f2b Mon Sep 17 00:00:00 2001 From: himkt Date: Fri, 12 Oct 2018 13:17:58 +0900 Subject: [PATCH 012/672] Fix indentation in CRF1d --- tensorflow/contrib/crf/python/ops/crf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tensorflow/contrib/crf/python/ops/crf.py b/tensorflow/contrib/crf/python/ops/crf.py index 43bb43129b..7653b48e9c 100644 --- a/tensorflow/contrib/crf/python/ops/crf.py +++ b/tensorflow/contrib/crf/python/ops/crf.py @@ -38,12 +38,12 @@ tf_unary_scores, tf_sequence_lengths, tf_transition_params, _ = session.run( [unary_scores, sequence_lengths, transition_params, train_op]) for tf_unary_scores_, tf_sequence_length_ in zip(tf_unary_scores, tf_sequence_lengths): -# Remove padding. -tf_unary_scores_ = tf_unary_scores_[:tf_sequence_length_] + # Remove padding. + tf_unary_scores_ = tf_unary_scores_[:tf_sequence_length_] -# Compute the highest score and its tag sequence. -tf_viterbi_sequence, tf_viterbi_score = tf.contrib.crf.viterbi_decode( - tf_unary_scores_, tf_transition_params) + # Compute the highest score and its tag sequence. + tf_viterbi_sequence, tf_viterbi_score = tf.contrib.crf.viterbi_decode( + tf_unary_scores_, tf_transition_params) """ from __future__ import absolute_import -- GitLab From fbd637423bc82662f010cc10a320c573b2eda172 Mon Sep 17 00:00:00 2001 From: Cibifang Date: Mon, 15 Oct 2018 08:18:16 +0800 Subject: [PATCH 013/672] Fix comment for AddGradients in graph.go --- tensorflow/go/graph.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index 096a182840..fb191fb51e 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -147,10 +147,11 @@ func (g *Graph) Operations() []Operation { return ops } -// AddGradients adds operations to compute the partial derivatives of sum of `y`s w.r.t `x`s, -// i.e., d(y_1 + y_2 + ...)/dx_1, d(y_1 + y_2 + ...)/dx_2... -// This methods allows to caller to pass a custom name prefix to the operations -// added to a graph to compute the gradients. +// AddGradients add operations to compute the partial derivatives of the sum of tensors in y +// with respect to tensors in x, i.e., d(y[0] + y[1] + ...) / d x[0], d(y[0] + y[1] + ... ) / d x[1] etc. +// +// prefix, if non-empty, is the name prefix used for all operations added to the graph to compute +// these gradients. func (g *Graph) AddGradients(prefix string, y []Output, x []Output, dx []Output) ([]Output, error) { var ( cprefix *C.char -- GitLab From 310f454e928c3e78d9126cb68190ed1cfc6b28d5 Mon Sep 17 00:00:00 2001 From: Cibifang Date: Tue, 16 Oct 2018 16:53:52 +0800 Subject: [PATCH 014/672] Stop using uniqueName for Gradients in gradient.go To keep the code style consistent with other functions. --- tensorflow/go/op/gradients.go | 2 +- tensorflow/go/op/gradients_test.go | 37 +++++++++++------------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/tensorflow/go/op/gradients.go b/tensorflow/go/op/gradients.go index 2397e40bf4..2eaa7e70ab 100644 --- a/tensorflow/go/op/gradients.go +++ b/tensorflow/go/op/gradients.go @@ -28,7 +28,7 @@ import tf "github.com/tensorflow/tensorflow/tensorflow/go" // return the partial derivatives func Gradients(scope *Scope, y []tf.Output, x []tf.Output, dx ...tf.Output) (output []tf.Output) { var err error - if output, err = scope.graph.AddGradients(scope.opName(scope.uniqueName("Gradients")), y, x, dx); err != nil { + if output, err = scope.graph.AddGradients(scope.opName("Gradients"), y, x, dx); err != nil { scope.UpdateErr("Gradients", err) return } diff --git a/tensorflow/go/op/gradients_test.go b/tensorflow/go/op/gradients_test.go index 2bcb3e88eb..1febd08366 100644 --- a/tensorflow/go/op/gradients_test.go +++ b/tensorflow/go/op/gradients_test.go @@ -44,8 +44,9 @@ func TestAddGradients(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), tf.Float) } - grads1 := Gradients(s, []tf.Output{y2}, []tf.Output{x1, x2}) - if err := s.Err(); err != nil { + sub := s.SubScope("sub") + grads1 := Gradients(sub, []tf.Output{y2}, []tf.Output{x1, x2}) + if err := sub.Err(); err != nil { t.Fatal(err) } if len(grads1) != 2 { @@ -58,7 +59,7 @@ func TestAddGradients(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads1[1].DataType(), tf.Float) } - graph, err := s.Finalize() + graph, err := sub.Finalize() if err != nil { t.Fatal(err) } @@ -150,8 +151,9 @@ func TestAddGradientsWithInitialValues(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads0[0].DataType(), tf.Float) } - grads1 := Gradients(s, []tf.Output{y0}, []tf.Output{x}, grads0[0]) - if err := s.Err(); err != nil { + sub := s.SubScope("sub") + grads1 := Gradients(sub, []tf.Output{y0}, []tf.Output{x}, grads0[0]) + if err := sub.Err(); err != nil { t.Fatal(err) } if len(grads1) != 1 { @@ -161,7 +163,7 @@ func TestAddGradientsWithInitialValues(t *testing.T) { t.Fatalf("Got DataType %v, wanted %v", grads1[0].DataType(), tf.Float) } - graph, err := s.Finalize() + graph, err := sub.Finalize() if err != nil { t.Fatal(err) } @@ -198,28 +200,17 @@ func TestValidateGradientsNames(t *testing.T) { t.Fatalf("Got name %v, wanted started with Gradients/", grads0[0].Op.Name()) } - grads1 := Gradients(s, []tf.Output{y0}, []tf.Output{x}) - if err := s.Err(); err != nil { - t.Fatal(err) - } - if !strings.HasPrefix(grads1[0].Op.Name(), "Gradients_1/") { - t.Fatalf("Got name %v, wanted started with Gradients_1/", grads1[0].Op.Name()) - } - sub := s.SubScope("sub") - grads3 := Gradients(sub, []tf.Output{y0}, []tf.Output{x}) + grads1 := Gradients(sub, []tf.Output{y0}, []tf.Output{x}) if err := s.Err(); err != nil { t.Fatal(err) } - if !strings.HasPrefix(grads3[0].Op.Name(), "sub/Gradients/") { - t.Fatalf("Got name %v, wanted started with sub/Gradients/", grads3[0].Op.Name()) + if !strings.HasPrefix(grads1[0].Op.Name(), "sub/Gradients/") { + t.Fatalf("Got name %v, wanted started with sub/Gradients/", grads1[0].Op.Name()) } - grads4 := Gradients(sub, []tf.Output{y0}, []tf.Output{x}) - if err := s.Err(); err != nil { - t.Fatal(err) - } - if !strings.HasPrefix(grads4[0].Op.Name(), "sub/Gradients_1/") { - t.Fatalf("Got name %v, wanted started with sub/Gradients_1/", grads4[0].Op.Name()) + Gradients(sub, []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err == nil { + t.Error("Gradients should have failed if executed more than once for scope of the same namespace") } } -- GitLab From 9cc0aeb553d168b29abede0358f3fb3903cd8fd6 Mon Sep 17 00:00:00 2001 From: Gitea Date: Thu, 18 Oct 2018 09:44:35 +0100 Subject: [PATCH 015/672] [Docker] Upgraded images to Ubuntu 18.04 LTS. --- tensorflow/tools/docker/Dockerfile | 4 ++-- tensorflow/tools/docker/Dockerfile.devel | 4 ++-- tensorflow/tools/docker/Dockerfile.devel-mkl | 4 ++-- tensorflow/tools/docker/Dockerfile.devel-mkl-horovod | 4 ++-- tensorflow/tools/docker/Dockerfile.mkl | 4 ++-- tensorflow/tools/docker/Dockerfile.mkl-horovod | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tensorflow/tools/docker/Dockerfile b/tensorflow/tools/docker/Dockerfile index 205128ad58..6676de02a4 100644 --- a/tensorflow/tools/docker/Dockerfile +++ b/tensorflow/tools/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 LABEL maintainer="Craig Citro " @@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ libfreetype6-dev \ libhdf5-serial-dev \ - libpng12-dev \ + libpng-dev \ libzmq3-dev \ pkg-config \ python \ diff --git a/tensorflow/tools/docker/Dockerfile.devel b/tensorflow/tools/docker/Dockerfile.devel index a3893a2713..c256dd364e 100644 --- a/tensorflow/tools/docker/Dockerfile.devel +++ b/tensorflow/tools/docker/Dockerfile.devel @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 LABEL maintainer="Craig Citro " @@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libcurl3-dev \ libfreetype6-dev \ libhdf5-serial-dev \ - libpng12-dev \ + libpng-dev \ libzmq3-dev \ pkg-config \ python-dev \ diff --git a/tensorflow/tools/docker/Dockerfile.devel-mkl b/tensorflow/tools/docker/Dockerfile.devel-mkl index bd2883ddba..2341c0e8cc 100755 --- a/tensorflow/tools/docker/Dockerfile.devel-mkl +++ b/tensorflow/tools/docker/Dockerfile.devel-mkl @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 LABEL maintainer="Clayne Robison " @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libcurl3-dev \ libfreetype6-dev \ libhdf5-serial-dev \ - libpng12-dev \ + libpng-dev \ libzmq3-dev \ libssl-dev \ pkg-config \ diff --git a/tensorflow/tools/docker/Dockerfile.devel-mkl-horovod b/tensorflow/tools/docker/Dockerfile.devel-mkl-horovod index df084e029c..5e24617b21 100755 --- a/tensorflow/tools/docker/Dockerfile.devel-mkl-horovod +++ b/tensorflow/tools/docker/Dockerfile.devel-mkl-horovod @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 LABEL maintainer="Cong Xu " @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libcurl3-dev \ libfreetype6-dev \ libhdf5-serial-dev \ - libpng12-dev \ + libpng-dev \ libzmq3-dev \ pkg-config \ python-dev \ diff --git a/tensorflow/tools/docker/Dockerfile.mkl b/tensorflow/tools/docker/Dockerfile.mkl index ac41cffe4b..dad27697fa 100755 --- a/tensorflow/tools/docker/Dockerfile.mkl +++ b/tensorflow/tools/docker/Dockerfile.mkl @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 LABEL maintainer="Clayne Robison " @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ libfreetype6-dev \ libhdf5-serial-dev \ - libpng12-dev \ + libpng-dev \ libzmq3-dev \ pkg-config \ ${PYTHON} \ diff --git a/tensorflow/tools/docker/Dockerfile.mkl-horovod b/tensorflow/tools/docker/Dockerfile.mkl-horovod index 0432cd5e80..19dc45c62c 100755 --- a/tensorflow/tools/docker/Dockerfile.mkl-horovod +++ b/tensorflow/tools/docker/Dockerfile.mkl-horovod @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 LABEL maintainer="Cong Xu " @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ libfreetype6-dev \ libhdf5-serial-dev \ - libpng12-dev \ + libpng-dev \ libzmq3-dev \ pkg-config \ python \ -- GitLab From 4f9d57337b71fe0ab3f25696db456e6a446ef54a Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Mon, 22 Oct 2018 10:53:25 +0800 Subject: [PATCH 016/672] Redundant transpose removal: transpose + conv2d + transpose -> conv2d. --- tensorflow/core/graph/mkl_layout_pass.cc | 514 ++++++++++++++++-- tensorflow/core/graph/mkl_layout_pass_test.cc | 295 ++++++++++ 2 files changed, 771 insertions(+), 38 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 69735aac02..233c5ab39b 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -25,6 +25,8 @@ limitations under the License. #include #include #include +#include + #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/optimization_registry.h" #include "tensorflow/core/framework/node_def_util.h" @@ -310,6 +312,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { csinfo_.slice = "Slice"; csinfo_.softmax = "Softmax"; csinfo_.split = "Split"; + csinfo_.transpose = "Transpose"; // Element-wise ops. Ensure you also add any new ops to IsOpElementWise // in the MklUtil.h (IsMklElementWiseOp method) to ensure that the // MklInputConversion op is added before it. @@ -508,6 +511,33 @@ class MklLayoutRewritePass : public GraphOptimizationPass { minfo_.push_back({csinfo_.conv2d_grad_filter, csinfo_.bias_add_grad, csinfo_.conv2d_grad_filter_with_bias, GetConv2DBackpropFilterOrBiasAddGrad}); + + // + // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D (NHWC) + Transpose (NHWC-> + // NCHW) " => "Conv2D (NCHW). Such patterns occur frequently in Keras. + // Note: we use the term "merge" is to combine (exactly) 2 nodes into one, while "fusion" is + // for 3+ nodes situation. + // + + // Transpose + Conv2d + Transpose: + std::vector transpose_to_nhwc = { NCHW::dim::N, NCHW::dim::H, NCHW::dim::W, NCHW::dim::C }; + std::vector transpose_to_nchw = { NHWC::dim::N, NHWC::dim::C, NHWC::dim::H, NHWC::dim::W }; + auto CheckForTransposeToNHWC = + std::bind(CheckForTranspose, std::placeholders::_1, transpose_to_nhwc); + auto CheckForConv2dOp = + std::bind(CheckForMklOp, std::placeholders::_1, csinfo_.conv2d); + auto CheckForTransposeToNCHW = + std::bind(CheckForTranspose, std::placeholders::_1, transpose_to_nchw); + auto FuseConv2D = + std::bind(FuseTransposeMklOpTranspose, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, "NCHW"); + finfo_.push_back({ + "transpose-elimination for Conv2D", { + CheckForTransposeToNHWC, CheckForConv2dOp, CheckForTransposeToNCHW + }, + // CheckForMklOp + FuseConv2D, CopyAttrsConv + }); } // Standard interface to run pass @@ -530,7 +560,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { string name; // Original name of op of the node in the graph string new_name; // New name of the op of the node in the graph // A function handler to copy attributes from an old node to a new node. - std::function copy_attrs; + std::function copy_attrs; // A rule under which to rewrite this node std::function rewrite_rule; } RewriteInfo; @@ -560,6 +590,42 @@ class MklLayoutRewritePass : public GraphOptimizationPass { std::function get_node_to_be_merged; } MergeInfo; + // structure to specify information used in node fusion of 2+ operators + typedef struct { + std::string pattern_name; // name to describe this pattern, such as + // "Transpose_Mklop_Transpose". + std::vector > + node_checkers; // extra restriction checker for these ops + std::function< + Status(std::unique_ptr *, std::vector &, + std::function)> + fuse_func; + std::function copy_attrs; + } FusionInfo; + + // + // dimension indices for 2D tensor. + // + struct NCHW { + enum dim { N = 0, C = 1, H = 2, W = 3 }; + }; + + struct NHWC { + enum dim { N = 0, H = 1, W = 2, C = 3 }; + }; + + + // + // dimension indices for 3D tensor. + // + struct NCDHW { + enum dim { N = 0, C = 1, D = 2, H = 3, W = 4 }; + }; + + struct NDHWC { + enum dim { N = 0, D = 1, H = 2, W = 3, C = 4 }; + }; + /// Structure to store all constant strings /// NOTE: names are alphabetically sorted. typedef struct { @@ -619,6 +685,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { string requantize; string tanh; string tanh_grad; + string transpose; string reshape; string slice; string softmax; @@ -637,6 +704,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { /// Maintain info about nodes to be merged std::vector minfo_; + /// Maintain info about nodes to be fused + std::vector finfo_; + /// Maintain structure of constant strings static ConstStringsInfo csinfo_; @@ -815,6 +885,121 @@ class MklLayoutRewritePass : public GraphOptimizationPass { return n; } + // Return a node that can be fused with input node 'n' + // + // @return tuple. If we can find such nodes, the first + // element of the tuple is a true. Otherwise, it's false. + std::tuple, const MklLayoutRewritePass::FusionInfo> + CheckForNodeFusion(Node *n) const; + + // Fuse nodes in the vector "nodes" + Status FuseNode(std::unique_ptr *g, std::vector &nodes, + const MklLayoutRewritePass::FusionInfo fi); + + static Status FuseTransposeMklOpTranspose( + std::unique_ptr *g, std::vector &nodes, + std::function copy_attrs, + string data_format); + + static bool CheckForTranspose(const Node *node, std::vector perm) { + // + // Check node node, to see if it's "Transpose" + // + if (node->type_string() != "Transpose") + return false; + + // + // Check if has out control edge. If true, this is a training graph. + // Currently we focus on inference and do no fusion in training. + // + for (const Edge *e : node->out_edges()) { + if (e->IsControlEdge()) { + return false; + } + } + + // + // If "Transpose" has input control edges, don't fuse on it. + // + for (const Edge *e : node->in_edges()) { + if (e->IsControlEdge()) { + return false; + } + } + + // + // If "Transpose" has multiple output data edges, also don't fuse it. + // + if (node->num_outputs() > 1 || node->out_edges().size() > 1) + return false; + + // Check "perm" attribute, make sure it's what we want. + // + for (const Edge *e : node->in_edges()) { + if (!e->IsControlEdge()) { + const Node *perm_node = e->src(); + + const int kPermTensorIndex = 1; + if (perm_node->type_string() == "Const" && e->dst_input() == kPermTensorIndex) { + // we find the "perm" node, now try to retrieve its value. + const TensorProto *proto = nullptr; + CHECK_EQ(GetNodeAttr(perm_node->def(), "value", &proto).ok(), true); + + DataType type; + GetNodeAttr(perm_node->def(), "dtype", &type); + + // + // Here we directly access to the "tensor_context", rather than + // "int_val". This is because we find "int_val" is + // not set properly under some circumstances. + // + if (type == DT_INT32) { + const int type_size = 4; + const int *tensor_content = reinterpret_cast(proto->tensor_content().c_str()); + const int tensor_content_size = proto->tensor_content().size() / type_size; + + std::vector perm_value(tensor_content, tensor_content + tensor_content_size); + + return perm_value == perm; + + } else if (type == DT_INT64) { + const int type_size = 8; + const long *tensor_content = reinterpret_cast(proto->tensor_content().c_str()); + const int tensor_content_size = proto->tensor_content().size() / type_size; + + std::vector perm_value(tensor_content, tensor_content + tensor_content_size); + std::vector long_perm(perm.cbegin(), perm.cend()); + + return perm_value == long_perm; + + } + + return false; + } + } + } + + return false; + } + + static bool CheckForMklOp(const Node *node, string name = "") { + if (!name.empty() && node->type_string() != name) { + return false; + } + + // if mklop has multiple outputs, don't fuse it. + if (node->num_outputs() > 1) + return false; + + if (node->out_edges().size() > 1) + return false; + + DataType T; + TF_CHECK_OK(GetNodeAttr(node->def(), "T", &T)); + return mkl_op_registry::IsMklOp( + mkl_op_registry::GetMklOpName(node->type_string()), T); + } + // Check if the node 'n' has any applicable rewrite rule // We check for 2 scenarios for rewrite. // @@ -1070,22 +1255,39 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // We need operator-specific function to copy attributes because the framework // does not provide any generic function for it. // NOTE: names are alphabetically sorted. - static void CopyAttrsAddN(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsBiasAddGrad(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsConcat(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsConcatV2(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsConv(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsDataType(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsFusedBatchNorm(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsLRN(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsPooling(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsQuantizedPooling(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsQuantizedConv2D(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsQuantizedConcat(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsReshape(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsRequantize(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsSlice(const Node* orig_node, NodeBuilder* nb); - static void CopyAttrsSplit(const Node* orig_node, NodeBuilder* nb); + static void CopyAttrsAddN(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsBiasAddGrad(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsConcat(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsConcatV2(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsConv(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsDataType(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsFusedBatchNorm(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsLRN(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsPooling(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsQuantizedPooling(const Node* orig_node, NodeBuilder* nb, + bool change_format = false); + static void CopyAttrsQuantizedConv2D(const Node* orig_node, NodeBuilder* nb, + bool change_format = false); + static void CopyAttrsQuantizedConcat(const Node* orig_node, NodeBuilder* nb, + bool change_format = false); + static void CopyAttrsReshape(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + static void CopyAttrsRequantize(const Node* orig_node, NodeBuilder* nb, + bool change_format = false); + static void CopyAttrsSlice(const Node* orig_node, NodeBuilder* nb, + bool change_format = false); + static void CopyAttrsSplit(const Node *orig_node, NodeBuilder *nb, + bool change_format = false); + // Generate a graph node in graph 'g' representing a dummy Mkl tensor node, // using node for original node 'orig_node' and return it in '*out'. @@ -1586,8 +1788,8 @@ void MklLayoutRewritePass::AddWorkSpaceEdgeIfNeeded( // Op-specific functions to copy attributes from old node to new node ////////////////////////////////////////////////////////////////////////// -void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, - NodeBuilder* nb) { +void MklLayoutRewritePass::CopyAttrsConv(const Node *orig_node, NodeBuilder *nb, + bool change_format) { DataType T; string data_format; string padding; @@ -1599,18 +1801,72 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, TF_CHECK_OK(GetNodeAttr(orig_node->def(), "strides", &strides)); TF_CHECK_OK(GetNodeAttr(orig_node->def(), "dilations", &dilations)); TF_CHECK_OK(GetNodeAttr(orig_node->def(), "padding", &padding)); - TF_CHECK_OK(GetNodeAttr(orig_node->def(), "data_format", &data_format)); // Add attributes to new node. nb->Attr("T", T); - nb->Attr("strides", strides); - nb->Attr("dilations", dilations); nb->Attr("padding", padding); - nb->Attr("data_format", data_format); + + if (!change_format) { + nb->Attr("strides", strides); + nb->Attr("dilations", dilations); + + TF_CHECK_OK(GetNodeAttr(orig_node->def(), "data_format", &data_format)); + nb->Attr("data_format", data_format); + } else { + std::vector new_strides; + std::vector new_dilations; + if (strides.size() == 5) { + // + // "strides" and "dilations" also need to be changed according to "data_format", + // in this case, is "NDHWC" to "NCDHW". + // + + new_strides = { + strides[NDHWC::dim::N], + strides[NDHWC::dim::C], + strides[NDHWC::dim::D], + strides[NDHWC::dim::H], + strides[NDHWC::dim::W] + }; + nb->Attr("strides", new_strides); + + new_dilations = { + dilations[NDHWC::dim::N], + dilations[NDHWC::dim::C], + dilations[NDHWC::dim::D], + dilations[NDHWC::dim::H], + dilations[NDHWC::dim::W] + }; + nb->Attr("dilations", new_dilations); + + } else { + // + // "strides" and "dilations" also need to be changed according to "data_format", + // in this case, is "NHWC" to "NCHW". + // + + new_strides = { + strides[NHWC::dim::N], + strides[NHWC::dim::C], + strides[NHWC::dim::H], + strides[NHWC::dim::W] + }; + nb->Attr("strides", new_strides); + + new_dilations = { + dilations[NHWC::dim::N], + dilations[NHWC::dim::C], + dilations[NHWC::dim::H], + dilations[NHWC::dim::W] + }; + nb->Attr("dilations", new_dilations); + } + } } void MklLayoutRewritePass::CopyAttrsAddN(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; int N; @@ -1624,7 +1880,8 @@ void MklLayoutRewritePass::CopyAttrsAddN(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsBiasAddGrad(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; string data_format; std::vector strides; @@ -1641,7 +1898,8 @@ void MklLayoutRewritePass::CopyAttrsBiasAddGrad(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsLRN(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; int depth_radius; float bias; @@ -1664,7 +1922,8 @@ void MklLayoutRewritePass::CopyAttrsLRN(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsPooling(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; string data_format; string padding; @@ -1686,7 +1945,8 @@ void MklLayoutRewritePass::CopyAttrsPooling(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsDataType(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; // Get all attributes from old node. @@ -1697,7 +1957,8 @@ void MklLayoutRewritePass::CopyAttrsDataType(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsQuantizedPooling(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; string data_format; string padding; @@ -1717,7 +1978,8 @@ void MklLayoutRewritePass::CopyAttrsQuantizedPooling(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsQuantizedConv2D(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType Tinput, Tfilter, out_type; string padding; string data_format("NHWC"); @@ -1747,7 +2009,8 @@ void MklLayoutRewritePass::CopyAttrsQuantizedConv2D(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsRequantize(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType Tinput, out_type; // Get all attributes from old node. @@ -1760,7 +2023,8 @@ void MklLayoutRewritePass::CopyAttrsRequantize(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsReshape(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; DataType Tshape; @@ -1773,7 +2037,8 @@ void MklLayoutRewritePass::CopyAttrsReshape(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsSlice(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; DataType Index; @@ -1786,7 +2051,8 @@ void MklLayoutRewritePass::CopyAttrsSlice(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsSplit(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; string data_format; int num_split; @@ -1803,7 +2069,8 @@ void MklLayoutRewritePass::CopyAttrsSplit(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsConcat(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; int N; @@ -1817,7 +2084,8 @@ void MklLayoutRewritePass::CopyAttrsConcat(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsConcatV2(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; int N; DataType tidx; @@ -1834,7 +2102,8 @@ void MklLayoutRewritePass::CopyAttrsConcatV2(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsFusedBatchNorm(const Node* orig_node, - NodeBuilder* nb) { + NodeBuilder* nb, + bool change_format) { DataType T; float epsilon; string data_format; @@ -2231,7 +2500,8 @@ Status MklLayoutRewritePass::RewriteNode(std::unique_ptr* g, return s; } - ri->copy_attrs(const_cast(orig_node), &nb); + const bool kPartialCopyAttrs = false; + ri->copy_attrs(const_cast(orig_node), &nb, kPartialCopyAttrs); // Set the Mkl layer label for this op. if (DataTypeIsQuantized(orig_node->input_type(0)) || @@ -2391,6 +2661,151 @@ MklLayoutRewritePass::CheckForNodeRewrite(const Node* n) const { return nullptr; } +////////////////////////////////////////////////////////////////////////// +// Helper functions for node fusion +////////////////////////////////////////////////////////////////////////// +Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( + std::unique_ptr *g, std::vector &nodes, + std::function copy_attrs, + string data_format) { + Node *transpose_to_nhwc = nodes[0]; + Node *mklop = nodes[1]; + Node *transpose_to_nchw = nodes[2]; + + const int transpose_nhwc_num_inputs = transpose_to_nhwc->num_inputs(); + gtl::InlinedVector transpose_nhwc_control_edges; + gtl::InlinedVector, 4> transpose_nhwc_in( + transpose_nhwc_num_inputs); + FillInputs(transpose_to_nhwc, &transpose_nhwc_control_edges, + &transpose_nhwc_in); + + const int mklop_num_inputs = mklop->num_inputs(); + gtl::InlinedVector mklop_control_edges; + gtl::InlinedVector, 4> mklop_in(mklop_num_inputs); + FillInputs(mklop, &mklop_control_edges, &mklop_in); + + const int transpose_nchw_num_inputs = transpose_to_nchw->num_inputs(); + gtl::InlinedVector transpose_nchw_control_edges; + gtl::InlinedVector, 4> transpose_nchw_in( + transpose_nchw_num_inputs); + FillInputs(transpose_to_nhwc, &transpose_nchw_control_edges, + &transpose_nchw_in); + + // We will use the node name of Conv2d as the name of new node + // Build new node. We use same name as original node, but change the op + // name. + NodeBuilder nb(mklop->name(), mklop->type_string()); + + for (int i = 0; i < mklop_num_inputs; i++) { + if (mklop_in[i].first == transpose_to_nhwc) { + // Fill "x": + nb.Input(transpose_nhwc_in[0].first, transpose_nhwc_in[0].second); + } else { + // Fill inputs other than "x": + nb.Input(mklop_in[i].first, mklop_in[i].second); + } + } + + copy_attrs(const_cast(mklop), &nb, true); + nb.Attr("data_format", data_format); + + // Copy the device assigned to old node to new node. + nb.Device(mklop->def().device()); + + // Create node. + Node *new_node; + TF_CHECK_OK(nb.Finalize(&**g, &new_node)); + CHECK_NOTNULL(new_node); + + // Fill outputs. + for (const Edge *e : transpose_to_nchw->out_edges()) { + if (!e->IsControlEdge()) { + const int kConv2DWithBiasOutputSlot = 0; + CHECK_NOTNULL((*g)->AddEdge(new_node, kConv2DWithBiasOutputSlot, e->dst(), + e->dst_input())); + } + } + + // Copy device assigned to old node to new node. + new_node->set_assigned_device_name(mklop->assigned_device_name()); + + (*g)->RemoveNode(transpose_to_nhwc); + (*g)->RemoveNode(mklop); + (*g)->RemoveNode(transpose_to_nchw); + + return Status::OK(); +} + +Status +MklLayoutRewritePass::FuseNode(std::unique_ptr *g, + std::vector &nodes, + const MklLayoutRewritePass::FusionInfo fi) { + return fi.fuse_func(g, nodes, fi.copy_attrs); +} + +std::tuple, const MklLayoutRewritePass::FusionInfo> +MklLayoutRewritePass::CheckForNodeFusion(Node *a) const { + bool found_pattern = false; + std::vector nodes; + const FusionInfo *fi_ptr = nullptr; + + for (auto fi = finfo_.begin(); fi != finfo_.end(); ++fi) { + assert(fi->ops.size() == fi->node_checkers.size()); + nodes.clear(); + fi_ptr = &*fi; + // + // Make sure node "a" and its succeding nodes (b, c ...), match the pattern + // defined in fusion info (ops[0], ops[1], ...), + // aka. "a->b->c" matches "op1->op2->op3" + // + + // Initialize "current_node" as node "a". + Node *current_node = a; + for (auto node_index = 0; node_index < fi->node_checkers.size(); + ++node_index) { + // Make sure current node meet the requirement of corresponding node + // checker. + auto check_node = fi->node_checkers[node_index]; + if (current_node == nullptr || + (check_node && check_node(current_node) == false)) { + found_pattern = false; + nodes.clear(); + break; + } + + // Add current_node to "fusion_nodes": + nodes.push_back(current_node); + + // If current node is not the last node we want to check, check next node. + if (node_index != fi->node_checkers.size() - 1) { + // Find current node's direct descendant, which will be used in next + // iteration. + auto check_next_node = fi->node_checkers[node_index + 1]; + for (const Edge *e : current_node->out_edges()) { + if (!e->IsControlEdge()) { + Node *candidate_node = e->dst(); + + if (check_next_node(candidate_node) == false) { + current_node = nullptr; + } else { + current_node = candidate_node; + break; + } + } + } + } else { + found_pattern = true; + } + } + + if (found_pattern == true) { + break; + } + } + + return make_tuple(found_pattern, nodes, *fi_ptr); +} + /////////////////////////////////////////////////////////////////////////////// // Post-rewrite Mkl metadata fixup pass /////////////////////////////////////////////////////////////////////////////// @@ -2516,6 +2931,29 @@ bool MklLayoutRewritePass::RunPass(std::unique_ptr* g) { DumpGraph("After running MklLayoutRewritePass(NodeMerge)", &**g); + order.clear(); + GetReversePostOrder(**g, &order); // This will give us topological sort. + for (Node *n : order) { + // If node is not an op or it cannot run on CPU device, then skip. + if (!n->IsOp() || !CanOpRunOnCPUDevice(n)) { + continue; + } + + auto check_result = CheckForNodeFusion(n); + bool found_pattern = std::get<0>(check_result); + std::vector nodes = std::get<1>(check_result); + const FusionInfo fi = std::get<2>(check_result); + + // if "found_pattern" is true, we can do the fusion. + if (found_pattern) { + if (FuseNode(g, nodes, fi) == Status::OK()) { + result = true; + } + } + } + + DumpGraph("After running MklLayoutRewritePass(NodeFusion)", &**g); + order.clear(); GetReversePostOrder(**g, &order); // This will give us topological sort. for (Node* n : order) { diff --git a/tensorflow/core/graph/mkl_layout_pass_test.cc b/tensorflow/core/graph/mkl_layout_pass_test.cc index 7e2d1f7878..b09ef3b970 100644 --- a/tensorflow/core/graph/mkl_layout_pass_test.cc +++ b/tensorflow/core/graph/mkl_layout_pass_test.cc @@ -455,6 +455,301 @@ TEST_F(MklLayoutPassTest, NodeMerge_Conv2DWithBias_ConvBpropInput_FilterFwd) { "E:3->G:4;F->G;F:control->DMT/_3:control;G->Z;X->Y:1;X->Z:1"); } +TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Positive) { + InitGraph( + "node { name: 'Input0' op: 'Input'}" + "node { name: 'Input1' op: 'Input'}" + "node { name: 'Const0' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: '\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000'" + " }" + " }" + " }" + "}" + "node { name: 'Const1' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: '\\000\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000\\002\\000\\000\\000'" + " }" + " }" + " }" + "}" + "node { \ + name: 'Transpose0' \ + op: 'Transpose' \ + input: 'Input0' \ + input: 'Const0' \ + attr { \ + key: 'T' \ + value { \ + type: DT_FLOAT \ + } \ + } \ + attr { \ + key: 'Tperm' \ + value { \ + type: DT_INT32 \ + } \ + } \ + }" + "node { \ + name: 'Conv2D' \ + op: 'Conv2D' \ + input: 'Transpose0' \ + input: 'Input1' \ + attr { \ + key: 'T' \ + value { \ + type: DT_FLOAT \ + } \ + } \ + attr { \ + key: 'data_format' \ + value { \ + s: 'NHWC' \ + } \ + } \ + attr { \ + key: 'dilations' \ + value { \ + list { \ + i: 1 \ + i: 1 \ + i: 1 \ + i: 1 \ + } \ + } \ + } \ + attr { \ + key: 'padding' \ + value { \ + s: 'SAME' \ + } \ + } \ + attr { \ + key: 'strides' \ + value { \ + list { \ + i: 1 \ + i: 1 \ + i: 1 \ + i: 1 \ + } \ + } \ + } \ + attr { \ + key: 'use_cudnn_on_gpu' \ + value { \ + b: true \ + } \ + } \ + }" + "node { \ + name: 'Transpose1' \ + op: 'Transpose' \ + input: 'Conv2D' \ + input: 'Const1' \ + attr { \ + key: 'T' \ + value { \ + type: DT_FLOAT \ + } \ + } \ + attr { \ + key: 'Tperm' \ + value { \ + type: DT_INT32 \ + } \ + } \ + }" + "node { name: 'Relu' op: 'Relu'" + " attr { key: 'T' value { type: DT_FLOAT } }" + " input: ['Transpose1'] }"); + EXPECT_EQ(DoMklLayoutOptimizationPass(), + "Const0(Const);Const1(Const);" + "Conv2D(_MklConv2D);DMT/_0(Const);DMT/_1(Const);Input0(Input);" + "Input1(Input);Relu(_MklRelu)|Conv2D->Relu;Conv2D:2->Relu:1;DMT/_0->Conv2D:2;DMT/_1->Conv2D:3;Input0->Conv2D;" + "Input0:control->DMT/_0:control;Input0:control->DMT/_1:control;Input1->Conv2D:1"); +} + +TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Negative) { + InitGraph( + "node { name: 'Input0' op: 'Input'}" + "node { name: 'Input1' op: 'Input'}" + "node { name: 'Const0' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: '\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000'" + " }" + " }" + " }" + "}" + "node { name: 'Const1' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: '\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000'" + " }" + " }" + " }" + "}" + "node { \ + name: 'Transpose0' \ + op: 'Transpose' \ + input: 'Input0' \ + input: 'Const0' \ + attr { \ + key: 'T' \ + value { \ + type: DT_FLOAT \ + } \ + } \ + attr { \ + key: 'Tperm' \ + value { \ + type: DT_INT32 \ + } \ + } \ + }" + "node { \ + name: 'Conv2D' \ + op: 'Conv2D' \ + input: 'Transpose0' \ + input: 'Input1' \ + attr { \ + key: 'T' \ + value { \ + type: DT_FLOAT \ + } \ + } \ + attr { \ + key: 'data_format' \ + value { \ + s: 'NHWC' \ + } \ + } \ + attr { \ + key: 'dilations' \ + value { \ + list { \ + i: 1 \ + i: 1 \ + i: 1 \ + i: 1 \ + } \ + } \ + } \ + attr { \ + key: 'padding' \ + value { \ + s: 'SAME' \ + } \ + } \ + attr { \ + key: 'strides' \ + value { \ + list { \ + i: 1 \ + i: 1 \ + i: 1 \ + i: 1 \ + } \ + } \ + } \ + attr { \ + key: 'use_cudnn_on_gpu' \ + value { \ + b: true \ + } \ + } \ + }" + "node { \ + name: 'Transpose1' \ + op: 'Transpose' \ + input: 'Conv2D' \ + input: 'Const1' \ + attr { \ + key: 'T' \ + value { \ + type: DT_FLOAT \ + } \ + } \ + attr { \ + key: 'Tperm' \ + value { \ + type: DT_INT32 \ + } \ + } \ + }" + "node { name: 'Relu' op: 'Relu'" + " attr { key: 'T' value { type: DT_FLOAT } }" + " input: ['Transpose1'] }"); + EXPECT_EQ(DoMklLayoutOptimizationPass(), + "Const0(Const);Const1(Const);" + "Conv2D(_MklConv2D);DMT/_0(Const);DMT/_1(Const);DMT/_2(Const);" + "Input0(Input);Input1(Input);Relu(_MklRelu);" + "Transpose0(Transpose);Transpose1(Transpose)|Const0->Transpose0:1;Const1->Transpose1:1;" + "Conv2D->Transpose1;DMT/_0->Conv2D:2;DMT/_1->Conv2D:3;DMT/_2->Relu:1;Input0->Transpose0;" + "Input1->Conv2D:1;Transpose0->Conv2D;Transpose0:control->DMT/_0:control;" + "Transpose0:control->DMT/_1:control;Transpose1->Relu;Transpose1:control->DMT/_2:control"); +} + ///////////////////////////////////////////////////////////////////// // Unit tests related to rewriting node to Mkl node ///////////////////////////////////////////////////////////////////// -- GitLab From 76fd3b394bb170437baee31516967f4d583869be Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Thu, 25 Oct 2018 13:32:54 +0800 Subject: [PATCH 017/672] Fix clang-format issues. --- tensorflow/core/graph/mkl_layout_pass.cc | 242 +++++++++++------------ 1 file changed, 113 insertions(+), 129 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 233c5ab39b..e041ab14ca 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -22,10 +22,10 @@ limitations under the License. #include #include #include +#include #include #include #include -#include #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/optimization_registry.h" @@ -513,15 +513,19 @@ class MklLayoutRewritePass : public GraphOptimizationPass { GetConv2DBackpropFilterOrBiasAddGrad}); // - // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D (NHWC) + Transpose (NHWC-> + // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D + // (NHWC) + Transpose (NHWC-> // NCHW) " => "Conv2D (NCHW). Such patterns occur frequently in Keras. - // Note: we use the term "merge" is to combine (exactly) 2 nodes into one, while "fusion" is + // Note: we use the term "merge" is to combine (exactly) 2 nodes into one, + // while "fusion" is // for 3+ nodes situation. // // Transpose + Conv2d + Transpose: - std::vector transpose_to_nhwc = { NCHW::dim::N, NCHW::dim::H, NCHW::dim::W, NCHW::dim::C }; - std::vector transpose_to_nchw = { NHWC::dim::N, NHWC::dim::C, NHWC::dim::H, NHWC::dim::W }; + std::vector transpose_to_nhwc = {NCHW::dim::N, NCHW::dim::H, + NCHW::dim::W, NCHW::dim::C}; + std::vector transpose_to_nchw = {NHWC::dim::N, NHWC::dim::C, + NHWC::dim::H, NHWC::dim::W}; auto CheckForTransposeToNHWC = std::bind(CheckForTranspose, std::placeholders::_1, transpose_to_nhwc); auto CheckForConv2dOp = @@ -531,13 +535,12 @@ class MklLayoutRewritePass : public GraphOptimizationPass { auto FuseConv2D = std::bind(FuseTransposeMklOpTranspose, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, "NCHW"); - finfo_.push_back({ - "transpose-elimination for Conv2D", { - CheckForTransposeToNHWC, CheckForConv2dOp, CheckForTransposeToNCHW - }, - // CheckForMklOp - FuseConv2D, CopyAttrsConv - }); + finfo_.push_back( + {"transpose-elimination for Conv2D", + {CheckForTransposeToNHWC, CheckForConv2dOp, CheckForTransposeToNCHW}, + // CheckForMklOp + FuseConv2D, + CopyAttrsConv}); } // Standard interface to run pass @@ -592,20 +595,20 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // structure to specify information used in node fusion of 2+ operators typedef struct { - std::string pattern_name; // name to describe this pattern, such as - // "Transpose_Mklop_Transpose". - std::vector > - node_checkers; // extra restriction checker for these ops - std::function< - Status(std::unique_ptr *, std::vector &, - std::function)> + std::string pattern_name; // name to describe this pattern, such as + // "Transpose_Mklop_Transpose". + std::vector > + node_checkers; // extra restriction checker for these ops + std::function*, std::vector&, + std::function)> fuse_func; - std::function copy_attrs; + std::function copy_attrs; } FusionInfo; // // dimension indices for 2D tensor. - // + // struct NCHW { enum dim { N = 0, C = 1, H = 2, W = 3 }; }; @@ -614,7 +617,6 @@ class MklLayoutRewritePass : public GraphOptimizationPass { enum dim { N = 0, H = 1, W = 2, C = 3 }; }; - // // dimension indices for 3D tensor. // @@ -889,30 +891,29 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // // @return tuple. If we can find such nodes, the first // element of the tuple is a true. Otherwise, it's false. - std::tuple, const MklLayoutRewritePass::FusionInfo> - CheckForNodeFusion(Node *n) const; + std::tuple, const MklLayoutRewritePass::FusionInfo> + CheckForNodeFusion(Node* n) const; // Fuse nodes in the vector "nodes" - Status FuseNode(std::unique_ptr *g, std::vector &nodes, + Status FuseNode(std::unique_ptr* g, std::vector& nodes, const MklLayoutRewritePass::FusionInfo fi); static Status FuseTransposeMklOpTranspose( - std::unique_ptr *g, std::vector &nodes, - std::function copy_attrs, + std::unique_ptr* g, std::vector& nodes, + std::function copy_attrs, string data_format); - static bool CheckForTranspose(const Node *node, std::vector perm) { + static bool CheckForTranspose(const Node* node, std::vector perm) { // // Check node node, to see if it's "Transpose" // - if (node->type_string() != "Transpose") - return false; + if (node->type_string() != "Transpose") return false; // // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. // - for (const Edge *e : node->out_edges()) { + for (const Edge* e : node->out_edges()) { if (e->IsControlEdge()) { return false; } @@ -921,7 +922,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // // If "Transpose" has input control edges, don't fuse on it. // - for (const Edge *e : node->in_edges()) { + for (const Edge* e : node->in_edges()) { if (e->IsControlEdge()) { return false; } @@ -930,19 +931,19 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // // If "Transpose" has multiple output data edges, also don't fuse it. // - if (node->num_outputs() > 1 || node->out_edges().size() > 1) - return false; + if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; // Check "perm" attribute, make sure it's what we want. // - for (const Edge *e : node->in_edges()) { + for (const Edge* e : node->in_edges()) { if (!e->IsControlEdge()) { - const Node *perm_node = e->src(); + const Node* perm_node = e->src(); const int kPermTensorIndex = 1; - if (perm_node->type_string() == "Const" && e->dst_input() == kPermTensorIndex) { + if (perm_node->type_string() == "Const" && + e->dst_input() == kPermTensorIndex) { // we find the "perm" node, now try to retrieve its value. - const TensorProto *proto = nullptr; + const TensorProto* proto = nullptr; CHECK_EQ(GetNodeAttr(perm_node->def(), "value", &proto).ok(), true); DataType type; @@ -955,23 +956,28 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // if (type == DT_INT32) { const int type_size = 4; - const int *tensor_content = reinterpret_cast(proto->tensor_content().c_str()); - const int tensor_content_size = proto->tensor_content().size() / type_size; - - std::vector perm_value(tensor_content, tensor_content + tensor_content_size); + const int* tensor_content = + reinterpret_cast(proto->tensor_content().c_str()); + const int tensor_content_size = + proto->tensor_content().size() / type_size; + + std::vector perm_value(tensor_content, + tensor_content + tensor_content_size); return perm_value == perm; } else if (type == DT_INT64) { const int type_size = 8; - const long *tensor_content = reinterpret_cast(proto->tensor_content().c_str()); - const int tensor_content_size = proto->tensor_content().size() / type_size; - - std::vector perm_value(tensor_content, tensor_content + tensor_content_size); + const long* tensor_content = + reinterpret_cast(proto->tensor_content().c_str()); + const int tensor_content_size = + proto->tensor_content().size() / type_size; + + std::vector perm_value(tensor_content, + tensor_content + tensor_content_size); std::vector long_perm(perm.cbegin(), perm.cend()); return perm_value == long_perm; - } return false; @@ -982,17 +988,15 @@ class MklLayoutRewritePass : public GraphOptimizationPass { return false; } - static bool CheckForMklOp(const Node *node, string name = "") { + static bool CheckForMklOp(const Node* node, string name = "") { if (!name.empty() && node->type_string() != name) { return false; } // if mklop has multiple outputs, don't fuse it. - if (node->num_outputs() > 1) - return false; + if (node->num_outputs() > 1) return false; - if (node->out_edges().size() > 1) - return false; + if (node->out_edges().size() > 1) return false; DataType T; TF_CHECK_OK(GetNodeAttr(node->def(), "T", &T)); @@ -1255,23 +1259,23 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // We need operator-specific function to copy attributes because the framework // does not provide any generic function for it. // NOTE: names are alphabetically sorted. - static void CopyAttrsAddN(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsAddN(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsBiasAddGrad(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsBiasAddGrad(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsConcat(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsConcat(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsConcatV2(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsConcatV2(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsConv(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsDataType(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsDataType(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsFusedBatchNorm(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsFusedBatchNorm(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsLRN(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsLRN(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsPooling(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsPooling(const Node* orig_node, NodeBuilder* nb, bool change_format = false); static void CopyAttrsQuantizedPooling(const Node* orig_node, NodeBuilder* nb, bool change_format = false); @@ -1279,16 +1283,15 @@ class MklLayoutRewritePass : public GraphOptimizationPass { bool change_format = false); static void CopyAttrsQuantizedConcat(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsReshape(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsReshape(const Node* orig_node, NodeBuilder* nb, bool change_format = false); static void CopyAttrsRequantize(const Node* orig_node, NodeBuilder* nb, bool change_format = false); static void CopyAttrsSlice(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - static void CopyAttrsSplit(const Node *orig_node, NodeBuilder *nb, + static void CopyAttrsSplit(const Node* orig_node, NodeBuilder* nb, bool change_format = false); - // Generate a graph node in graph 'g' representing a dummy Mkl tensor node, // using node for original node 'orig_node' and return it in '*out'. // TODO(nhasabni) We should move this to mkl_util.h @@ -1788,7 +1791,7 @@ void MklLayoutRewritePass::AddWorkSpaceEdgeIfNeeded( // Op-specific functions to copy attributes from old node to new node ////////////////////////////////////////////////////////////////////////// -void MklLayoutRewritePass::CopyAttrsConv(const Node *orig_node, NodeBuilder *nb, +void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, bool change_format) { DataType T; string data_format; @@ -1817,55 +1820,40 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node *orig_node, NodeBuilder *nb, std::vector new_dilations; if (strides.size() == 5) { // - // "strides" and "dilations" also need to be changed according to "data_format", + // "strides" and "dilations" also need to be changed according to + // "data_format", // in this case, is "NDHWC" to "NCDHW". // - new_strides = { - strides[NDHWC::dim::N], - strides[NDHWC::dim::C], - strides[NDHWC::dim::D], - strides[NDHWC::dim::H], - strides[NDHWC::dim::W] - }; + new_strides = {strides[NDHWC::dim::N], strides[NDHWC::dim::C], + strides[NDHWC::dim::D], strides[NDHWC::dim::H], + strides[NDHWC::dim::W]}; nb->Attr("strides", new_strides); - new_dilations = { - dilations[NDHWC::dim::N], - dilations[NDHWC::dim::C], - dilations[NDHWC::dim::D], - dilations[NDHWC::dim::H], - dilations[NDHWC::dim::W] - }; + new_dilations = {dilations[NDHWC::dim::N], dilations[NDHWC::dim::C], + dilations[NDHWC::dim::D], dilations[NDHWC::dim::H], + dilations[NDHWC::dim::W]}; nb->Attr("dilations", new_dilations); } else { // - // "strides" and "dilations" also need to be changed according to "data_format", + // "strides" and "dilations" also need to be changed according to + // "data_format", // in this case, is "NHWC" to "NCHW". // - - new_strides = { - strides[NHWC::dim::N], - strides[NHWC::dim::C], - strides[NHWC::dim::H], - strides[NHWC::dim::W] - }; + + new_strides = {strides[NHWC::dim::N], strides[NHWC::dim::C], + strides[NHWC::dim::H], strides[NHWC::dim::W]}; nb->Attr("strides", new_strides); - new_dilations = { - dilations[NHWC::dim::N], - dilations[NHWC::dim::C], - dilations[NHWC::dim::H], - dilations[NHWC::dim::W] - }; + new_dilations = {dilations[NHWC::dim::N], dilations[NHWC::dim::C], + dilations[NHWC::dim::H], dilations[NHWC::dim::W]}; nb->Attr("dilations", new_dilations); } } } -void MklLayoutRewritePass::CopyAttrsAddN(const Node* orig_node, - NodeBuilder* nb, +void MklLayoutRewritePass::CopyAttrsAddN(const Node* orig_node, NodeBuilder* nb, bool change_format) { DataType T; int N; @@ -1897,8 +1885,7 @@ void MklLayoutRewritePass::CopyAttrsBiasAddGrad(const Node* orig_node, nb->Attr("data_format", data_format); } -void MklLayoutRewritePass::CopyAttrsLRN(const Node* orig_node, - NodeBuilder* nb, +void MklLayoutRewritePass::CopyAttrsLRN(const Node* orig_node, NodeBuilder* nb, bool change_format) { DataType T; int depth_radius; @@ -2037,8 +2024,7 @@ void MklLayoutRewritePass::CopyAttrsReshape(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsSlice(const Node* orig_node, - NodeBuilder* nb, - bool change_format) { + NodeBuilder* nb, bool change_format) { DataType T; DataType Index; @@ -2051,8 +2037,7 @@ void MklLayoutRewritePass::CopyAttrsSlice(const Node* orig_node, } void MklLayoutRewritePass::CopyAttrsSplit(const Node* orig_node, - NodeBuilder* nb, - bool change_format) { + NodeBuilder* nb, bool change_format) { DataType T; string data_format; int num_split; @@ -2665,28 +2650,28 @@ MklLayoutRewritePass::CheckForNodeRewrite(const Node* n) const { // Helper functions for node fusion ////////////////////////////////////////////////////////////////////////// Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( - std::unique_ptr *g, std::vector &nodes, - std::function copy_attrs, + std::unique_ptr* g, std::vector& nodes, + std::function copy_attrs, string data_format) { - Node *transpose_to_nhwc = nodes[0]; - Node *mklop = nodes[1]; - Node *transpose_to_nchw = nodes[2]; + Node* transpose_to_nhwc = nodes[0]; + Node* mklop = nodes[1]; + Node* transpose_to_nchw = nodes[2]; const int transpose_nhwc_num_inputs = transpose_to_nhwc->num_inputs(); - gtl::InlinedVector transpose_nhwc_control_edges; - gtl::InlinedVector, 4> transpose_nhwc_in( + gtl::InlinedVector transpose_nhwc_control_edges; + gtl::InlinedVector, 4> transpose_nhwc_in( transpose_nhwc_num_inputs); FillInputs(transpose_to_nhwc, &transpose_nhwc_control_edges, &transpose_nhwc_in); const int mklop_num_inputs = mklop->num_inputs(); - gtl::InlinedVector mklop_control_edges; - gtl::InlinedVector, 4> mklop_in(mklop_num_inputs); + gtl::InlinedVector mklop_control_edges; + gtl::InlinedVector, 4> mklop_in(mklop_num_inputs); FillInputs(mklop, &mklop_control_edges, &mklop_in); const int transpose_nchw_num_inputs = transpose_to_nchw->num_inputs(); - gtl::InlinedVector transpose_nchw_control_edges; - gtl::InlinedVector, 4> transpose_nchw_in( + gtl::InlinedVector transpose_nchw_control_edges; + gtl::InlinedVector, 4> transpose_nchw_in( transpose_nchw_num_inputs); FillInputs(transpose_to_nhwc, &transpose_nchw_control_edges, &transpose_nchw_in); @@ -2706,19 +2691,19 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( } } - copy_attrs(const_cast(mklop), &nb, true); + copy_attrs(const_cast(mklop), &nb, true); nb.Attr("data_format", data_format); // Copy the device assigned to old node to new node. nb.Device(mklop->def().device()); // Create node. - Node *new_node; + Node* new_node; TF_CHECK_OK(nb.Finalize(&**g, &new_node)); CHECK_NOTNULL(new_node); // Fill outputs. - for (const Edge *e : transpose_to_nchw->out_edges()) { + for (const Edge* e : transpose_to_nchw->out_edges()) { if (!e->IsControlEdge()) { const int kConv2DWithBiasOutputSlot = 0; CHECK_NOTNULL((*g)->AddEdge(new_node, kConv2DWithBiasOutputSlot, e->dst(), @@ -2736,18 +2721,17 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( return Status::OK(); } -Status -MklLayoutRewritePass::FuseNode(std::unique_ptr *g, - std::vector &nodes, - const MklLayoutRewritePass::FusionInfo fi) { +Status MklLayoutRewritePass::FuseNode( + std::unique_ptr* g, std::vector& nodes, + const MklLayoutRewritePass::FusionInfo fi) { return fi.fuse_func(g, nodes, fi.copy_attrs); } -std::tuple, const MklLayoutRewritePass::FusionInfo> -MklLayoutRewritePass::CheckForNodeFusion(Node *a) const { +std::tuple, const MklLayoutRewritePass::FusionInfo> +MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { bool found_pattern = false; - std::vector nodes; - const FusionInfo *fi_ptr = nullptr; + std::vector nodes; + const FusionInfo* fi_ptr = nullptr; for (auto fi = finfo_.begin(); fi != finfo_.end(); ++fi) { assert(fi->ops.size() == fi->node_checkers.size()); @@ -2760,7 +2744,7 @@ MklLayoutRewritePass::CheckForNodeFusion(Node *a) const { // // Initialize "current_node" as node "a". - Node *current_node = a; + Node* current_node = a; for (auto node_index = 0; node_index < fi->node_checkers.size(); ++node_index) { // Make sure current node meet the requirement of corresponding node @@ -2781,9 +2765,9 @@ MklLayoutRewritePass::CheckForNodeFusion(Node *a) const { // Find current node's direct descendant, which will be used in next // iteration. auto check_next_node = fi->node_checkers[node_index + 1]; - for (const Edge *e : current_node->out_edges()) { + for (const Edge* e : current_node->out_edges()) { if (!e->IsControlEdge()) { - Node *candidate_node = e->dst(); + Node* candidate_node = e->dst(); if (check_next_node(candidate_node) == false) { current_node = nullptr; @@ -2933,7 +2917,7 @@ bool MklLayoutRewritePass::RunPass(std::unique_ptr* g) { order.clear(); GetReversePostOrder(**g, &order); // This will give us topological sort. - for (Node *n : order) { + for (Node* n : order) { // If node is not an op or it cannot run on CPU device, then skip. if (!n->IsOp() || !CanOpRunOnCPUDevice(n)) { continue; @@ -2941,7 +2925,7 @@ bool MklLayoutRewritePass::RunPass(std::unique_ptr* g) { auto check_result = CheckForNodeFusion(n); bool found_pattern = std::get<0>(check_result); - std::vector nodes = std::get<1>(check_result); + std::vector nodes = std::get<1>(check_result); const FusionInfo fi = std::get<2>(check_result); // if "found_pattern" is true, we can do the fusion. -- GitLab From 8d068a857dfbeb5cd417eb342a6ba7c330e0a270 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Thu, 25 Oct 2018 13:46:07 +0800 Subject: [PATCH 018/672] Fxi clang-format issues. --- tensorflow/core/graph/mkl_layout_pass_test.cc | 238 +++++++++--------- 1 file changed, 126 insertions(+), 112 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass_test.cc b/tensorflow/core/graph/mkl_layout_pass_test.cc index b09ef3b970..f4f2ab2a97 100644 --- a/tensorflow/core/graph/mkl_layout_pass_test.cc +++ b/tensorflow/core/graph/mkl_layout_pass_test.cc @@ -457,53 +457,57 @@ TEST_F(MklLayoutPassTest, NodeMerge_Conv2DWithBias_ConvBpropInput_FilterFwd) { TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Positive) { InitGraph( - "node { name: 'Input0' op: 'Input'}" - "node { name: 'Input1' op: 'Input'}" - "node { name: 'Const0' op: 'Const'" - " attr {" - " key: 'dtype'" - " value {" - " type: DT_INT32" - " }" - " }" - " attr {" - " key: 'value'" - " value {" - " tensor {" - " dtype: DT_INT32" - " tensor_shape {" - " dim {" - " size: 4" - " }" - " }" - " tensor_content: '\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000'" - " }" - " }" - " }" - "}" - "node { name: 'Const1' op: 'Const'" - " attr {" - " key: 'dtype'" - " value {" - " type: DT_INT32" - " }" - " }" - " attr {" - " key: 'value'" - " value {" - " tensor {" - " dtype: DT_INT32" - " tensor_shape {" - " dim {" - " size: 4" - " }" - " }" - " tensor_content: '\\000\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000\\002\\000\\000\\000'" - " }" - " }" - " }" - "}" - "node { \ + "node { name: 'Input0' op: 'Input'}" + "node { name: 'Input1' op: 'Input'}" + "node { name: 'Const0' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: " + "'\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000" + "\\000\\000'" + " }" + " }" + " }" + "}" + "node { name: 'Const1' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: " + "'\\000\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000\\002\\000" + "\\000\\000'" + " }" + " }" + " }" + "}" + "node { \ name: 'Transpose0' \ op: 'Transpose' \ input: 'Input0' \ @@ -520,8 +524,8 @@ TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Positive) { type: DT_INT32 \ } \ } \ - }" - "node { \ + }" + "node { \ name: 'Conv2D' \ op: 'Conv2D' \ input: 'Transpose0' \ @@ -573,7 +577,7 @@ TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Positive) { } \ } \ }" - "node { \ + "node { \ name: 'Transpose1' \ op: 'Transpose' \ input: 'Conv2D' \ @@ -591,65 +595,71 @@ TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Positive) { } \ } \ }" - "node { name: 'Relu' op: 'Relu'" + "node { name: 'Relu' op: 'Relu'" " attr { key: 'T' value { type: DT_FLOAT } }" " input: ['Transpose1'] }"); EXPECT_EQ(DoMklLayoutOptimizationPass(), "Const0(Const);Const1(Const);" "Conv2D(_MklConv2D);DMT/_0(Const);DMT/_1(Const);Input0(Input);" - "Input1(Input);Relu(_MklRelu)|Conv2D->Relu;Conv2D:2->Relu:1;DMT/_0->Conv2D:2;DMT/_1->Conv2D:3;Input0->Conv2D;" - "Input0:control->DMT/_0:control;Input0:control->DMT/_1:control;Input1->Conv2D:1"); + "Input1(Input);Relu(_MklRelu)|Conv2D->Relu;Conv2D:2->Relu:1;DMT/" + "_0->Conv2D:2;DMT/_1->Conv2D:3;Input0->Conv2D;" + "Input0:control->DMT/_0:control;Input0:control->DMT/" + "_1:control;Input1->Conv2D:1"); } TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Negative) { InitGraph( - "node { name: 'Input0' op: 'Input'}" - "node { name: 'Input1' op: 'Input'}" - "node { name: 'Const0' op: 'Const'" - " attr {" - " key: 'dtype'" - " value {" - " type: DT_INT32" - " }" - " }" - " attr {" - " key: 'value'" - " value {" - " tensor {" - " dtype: DT_INT32" - " tensor_shape {" - " dim {" - " size: 4" - " }" - " }" - " tensor_content: '\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000'" - " }" - " }" - " }" - "}" - "node { name: 'Const1' op: 'Const'" - " attr {" - " key: 'dtype'" - " value {" - " type: DT_INT32" - " }" - " }" - " attr {" - " key: 'value'" - " value {" - " tensor {" - " dtype: DT_INT32" - " tensor_shape {" - " dim {" - " size: 4" - " }" - " }" - " tensor_content: '\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000\\000\\000'" - " }" - " }" - " }" - "}" - "node { \ + "node { name: 'Input0' op: 'Input'}" + "node { name: 'Input1' op: 'Input'}" + "node { name: 'Const0' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: " + "'\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000" + "\\000\\000'" + " }" + " }" + " }" + "}" + "node { name: 'Const1' op: 'Const'" + " attr {" + " key: 'dtype'" + " value {" + " type: DT_INT32" + " }" + " }" + " attr {" + " key: 'value'" + " value {" + " tensor {" + " dtype: DT_INT32" + " tensor_shape {" + " dim {" + " size: 4" + " }" + " }" + " tensor_content: " + "'\\000\\000\\000\\000\\002\\000\\000\\000\\003\\000\\000\\000\\001\\000" + "\\000\\000'" + " }" + " }" + " }" + "}" + "node { \ name: 'Transpose0' \ op: 'Transpose' \ input: 'Input0' \ @@ -666,8 +676,8 @@ TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Negative) { type: DT_INT32 \ } \ } \ - }" - "node { \ + }" + "node { \ name: 'Conv2D' \ op: 'Conv2D' \ input: 'Transpose0' \ @@ -719,7 +729,7 @@ TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Negative) { } \ } \ }" - "node { \ + "node { \ name: 'Transpose1' \ op: 'Transpose' \ input: 'Conv2D' \ @@ -737,17 +747,21 @@ TEST_F(MklLayoutPassTest, NodeMerge_TransposeConv2DTranspose_Negative) { } \ } \ }" - "node { name: 'Relu' op: 'Relu'" + "node { name: 'Relu' op: 'Relu'" " attr { key: 'T' value { type: DT_FLOAT } }" " input: ['Transpose1'] }"); - EXPECT_EQ(DoMklLayoutOptimizationPass(), - "Const0(Const);Const1(Const);" - "Conv2D(_MklConv2D);DMT/_0(Const);DMT/_1(Const);DMT/_2(Const);" - "Input0(Input);Input1(Input);Relu(_MklRelu);" - "Transpose0(Transpose);Transpose1(Transpose)|Const0->Transpose0:1;Const1->Transpose1:1;" - "Conv2D->Transpose1;DMT/_0->Conv2D:2;DMT/_1->Conv2D:3;DMT/_2->Relu:1;Input0->Transpose0;" - "Input1->Conv2D:1;Transpose0->Conv2D;Transpose0:control->DMT/_0:control;" - "Transpose0:control->DMT/_1:control;Transpose1->Relu;Transpose1:control->DMT/_2:control"); + EXPECT_EQ( + DoMklLayoutOptimizationPass(), + "Const0(Const);Const1(Const);" + "Conv2D(_MklConv2D);DMT/_0(Const);DMT/_1(Const);DMT/_2(Const);" + "Input0(Input);Input1(Input);Relu(_MklRelu);" + "Transpose0(Transpose);Transpose1(Transpose)|Const0->Transpose0:1;Const1-" + ">Transpose1:1;" + "Conv2D->Transpose1;DMT/_0->Conv2D:2;DMT/_1->Conv2D:3;DMT/" + "_2->Relu:1;Input0->Transpose0;" + "Input1->Conv2D:1;Transpose0->Conv2D;Transpose0:control->DMT/_0:control;" + "Transpose0:control->DMT/" + "_1:control;Transpose1->Relu;Transpose1:control->DMT/_2:control"); } ///////////////////////////////////////////////////////////////////// -- GitLab From 901912bdaa9668a4e4fa0e90b873b0f9d2d717f6 Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Fri, 26 Oct 2018 12:45:57 +0800 Subject: [PATCH 019/672] Replace "=>" with "into" for readability. Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index e041ab14ca..374c74c903 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -515,7 +515,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D // (NHWC) + Transpose (NHWC-> - // NCHW) " => "Conv2D (NCHW). Such patterns occur frequently in Keras. + // NCHW)" into "Conv2D (NCHW)". Such patterns occur frequently in Keras. // Note: we use the term "merge" is to combine (exactly) 2 nodes into one, // while "fusion" is // for 3+ nodes situation. -- GitLab From 906a3527b9f4be3446a1f9e49332555bb3dd93cc Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Fri, 26 Oct 2018 12:46:26 +0800 Subject: [PATCH 020/672] Fix a grammatically incorrect in comments. Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 374c74c903..be91763a99 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -516,7 +516,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D // (NHWC) + Transpose (NHWC-> // NCHW)" into "Conv2D (NCHW)". Such patterns occur frequently in Keras. - // Note: we use the term "merge" is to combine (exactly) 2 nodes into one, + // Note: we use the term "merge" to combine (exactly) 2 nodes into one, // while "fusion" is // for 3+ nodes situation. // -- GitLab From b7ecda56d59248845103399a2eae73348995d63b Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 12:59:01 +0800 Subject: [PATCH 021/672] Merge the line with its previous line. --- tensorflow/core/graph/mkl_layout_pass.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index be91763a99..b0ae480d3d 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -517,8 +517,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // (NHWC) + Transpose (NHWC-> // NCHW)" into "Conv2D (NCHW)". Such patterns occur frequently in Keras. // Note: we use the term "merge" to combine (exactly) 2 nodes into one, - // while "fusion" is - // for 3+ nodes situation. + // while "fusion" is for 3+ nodes situation. // // Transpose + Conv2d + Transpose: -- GitLab From 932a04eed44a7c02181245210c72decb8d12e963 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 13:00:30 +0800 Subject: [PATCH 022/672] 2+ should be 3+. --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index b0ae480d3d..2891979be2 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -592,7 +592,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { std::function get_node_to_be_merged; } MergeInfo; - // structure to specify information used in node fusion of 2+ operators + // structure to specify information used in node fusion of 3+ operators typedef struct { std::string pattern_name; // name to describe this pattern, such as // "Transpose_Mklop_Transpose". -- GitLab From f60f477407fb3e203146abdb6ec7fce6b9735d50 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 13:03:11 +0800 Subject: [PATCH 023/672] Capitalized the beginning of the sentences. --- tensorflow/core/graph/mkl_layout_pass.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 2891979be2..77715b1515 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -592,12 +592,12 @@ class MklLayoutRewritePass : public GraphOptimizationPass { std::function get_node_to_be_merged; } MergeInfo; - // structure to specify information used in node fusion of 3+ operators + // Structure to specify information used in node fusion of 3+ operators typedef struct { - std::string pattern_name; // name to describe this pattern, such as + std::string pattern_name; // Name to describe this pattern, such as // "Transpose_Mklop_Transpose". std::vector > - node_checkers; // extra restriction checker for these ops + node_checkers; // Extra restriction checker for these ops std::function*, std::vector&, std::function)> @@ -606,7 +606,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { } FusionInfo; // - // dimension indices for 2D tensor. + // Dimension indices for 2D tensor. // struct NCHW { enum dim { N = 0, C = 1, H = 2, W = 3 }; -- GitLab From a3e878dfb91d83d788d1901c863660f1fa51c951 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 13:05:07 +0800 Subject: [PATCH 024/672] Remove empty comment lines. --- tensorflow/core/graph/mkl_layout_pass.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 77715b1515..c04887c36d 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -903,37 +903,28 @@ class MklLayoutRewritePass : public GraphOptimizationPass { string data_format); static bool CheckForTranspose(const Node* node, std::vector perm) { - // // Check node node, to see if it's "Transpose" - // if (node->type_string() != "Transpose") return false; - // // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. - // for (const Edge* e : node->out_edges()) { if (e->IsControlEdge()) { return false; } } - // // If "Transpose" has input control edges, don't fuse on it. - // for (const Edge* e : node->in_edges()) { if (e->IsControlEdge()) { return false; } } - // // If "Transpose" has multiple output data edges, also don't fuse it. - // if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; // Check "perm" attribute, make sure it's what we want. - // for (const Edge* e : node->in_edges()) { if (!e->IsControlEdge()) { const Node* perm_node = e->src(); @@ -948,11 +939,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { DataType type; GetNodeAttr(perm_node->def(), "dtype", &type); - // // Here we directly access to the "tensor_context", rather than // "int_val". This is because we find "int_val" is // not set properly under some circumstances. - // if (type == DT_INT32) { const int type_size = 4; const int* tensor_content = -- GitLab From 299c1649d1d48bc8d1e6a7fad505c20f2baaae8b Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Fri, 26 Oct 2018 13:12:54 +0800 Subject: [PATCH 025/672] Fix a grammatically incorrect comment line. Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index c04887c36d..ce364c062d 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -903,7 +903,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { string data_format); static bool CheckForTranspose(const Node* node, std::vector perm) { - // Check node node, to see if it's "Transpose" + // Check if node's type is "Transpose" if (node->type_string() != "Transpose") return false; // Check if has out control edge. If true, this is a training graph. -- GitLab From 43ccbbf8b2d2ac4d46f76ee72d000120512358d3 Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Fri, 26 Oct 2018 13:21:03 +0800 Subject: [PATCH 026/672] Use "CHECK_EQ" instead of "CHECK". Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index ce364c062d..78b1353997 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -934,7 +934,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { e->dst_input() == kPermTensorIndex) { // we find the "perm" node, now try to retrieve its value. const TensorProto* proto = nullptr; - CHECK_EQ(GetNodeAttr(perm_node->def(), "value", &proto).ok(), true); + CHECK(GetNodeAttr(perm_node->def(), "value", &proto).ok()); DataType type; GetNodeAttr(perm_node->def(), "dtype", &type); -- GitLab From cd31f0bcd6b52b8d9bd5d8430bddd77388a4fff0 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 13:27:47 +0800 Subject: [PATCH 027/672] Explain the high level idea of comparing 'perm' and 'perm_node'. --- tensorflow/core/graph/mkl_layout_pass.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 78b1353997..21ceb66fca 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -924,7 +924,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // If "Transpose" has multiple output data edges, also don't fuse it. if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; - // Check "perm" attribute, make sure it's what we want. + // We compared the tensor containing the permutation order ("perm_node") + // with our desired order ("perm"). If they're exactly match, this check + // succeed and returns true. for (const Edge* e : node->in_edges()) { if (!e->IsControlEdge()) { const Node* perm_node = e->src(); @@ -934,7 +936,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { e->dst_input() == kPermTensorIndex) { // we find the "perm" node, now try to retrieve its value. const TensorProto* proto = nullptr; - CHECK(GetNodeAttr(perm_node->def(), "value", &proto).ok()); + CHECK_EQ(GetNodeAttr(perm_node->def(), "value", &proto).ok(), true); DataType type; GetNodeAttr(perm_node->def(), "dtype", &type); -- GitLab From d667d30ff7132db51537c38984c97a589d9e7612 Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Fri, 26 Oct 2018 13:46:25 +0800 Subject: [PATCH 028/672] Fix a typo. Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 21ceb66fca..bce9995371 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -941,7 +941,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { DataType type; GetNodeAttr(perm_node->def(), "dtype", &type); - // Here we directly access to the "tensor_context", rather than + // Here we directly access to the "tensor_content", rather than // "int_val". This is because we find "int_val" is // not set properly under some circumstances. if (type == DT_INT32) { -- GitLab From a11786c809cd013fd4d4f97c94ce94a524b5bc17 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 13:52:05 +0800 Subject: [PATCH 029/672] Remove some empty lines. --- tensorflow/core/graph/mkl_layout_pass.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index bce9995371..76ae4faa45 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -955,7 +955,6 @@ class MklLayoutRewritePass : public GraphOptimizationPass { tensor_content + tensor_content_size); return perm_value == perm; - } else if (type == DT_INT64) { const int type_size = 8; const long* tensor_content = @@ -969,12 +968,10 @@ class MklLayoutRewritePass : public GraphOptimizationPass { return perm_value == long_perm; } - return false; } } } - return false; } -- GitLab From 4f0c4445c9e09b4360fbce8ce8f1b50722dced56 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 13:56:30 +0800 Subject: [PATCH 030/672] Check if node is nullptr. --- tensorflow/core/graph/mkl_layout_pass.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 76ae4faa45..909f84123c 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -976,6 +976,8 @@ class MklLayoutRewritePass : public GraphOptimizationPass { } static bool CheckForMklOp(const Node* node, string name = "") { + if (node == nullptr) return false; + if (!name.empty() && node->type_string() != name) { return false; } -- GitLab From ffc909edb6b1c4376ed2870d6d65fd4b5f17460f Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 14:01:03 +0800 Subject: [PATCH 031/672] Add description for FuseTransposeMklOpTranspose(). --- tensorflow/core/graph/mkl_layout_pass.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 909f84123c..78d6962cc3 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -897,6 +897,8 @@ class MklLayoutRewritePass : public GraphOptimizationPass { Status FuseNode(std::unique_ptr* g, std::vector& nodes, const MklLayoutRewritePass::FusionInfo fi); + // Fuse tranpose(to "NHWC") + mklop("NHWC") + transpose(to "NCHW") into mklop("NCHW"). + // Here "mklop" can be any MKL-DNN supported op, such as Conv2D. static Status FuseTransposeMklOpTranspose( std::unique_ptr* g, std::vector& nodes, std::function copy_attrs, @@ -977,7 +979,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { static bool CheckForMklOp(const Node* node, string name = "") { if (node == nullptr) return false; - + if (!name.empty() && node->type_string() != name) { return false; } -- GitLab From 738039381b33e1e39bf4089fa2c1341aeddb6308 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 14:03:00 +0800 Subject: [PATCH 032/672] Remove empty comment lines. --- tensorflow/core/graph/mkl_layout_pass.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 78d6962cc3..4cfe6aff1a 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -1810,12 +1810,9 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, std::vector new_strides; std::vector new_dilations; if (strides.size() == 5) { - // // "strides" and "dilations" also need to be changed according to // "data_format", // in this case, is "NDHWC" to "NCDHW". - // - new_strides = {strides[NDHWC::dim::N], strides[NDHWC::dim::C], strides[NDHWC::dim::D], strides[NDHWC::dim::H], strides[NDHWC::dim::W]}; @@ -1827,11 +1824,9 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, nb->Attr("dilations", new_dilations); } else { - // // "strides" and "dilations" also need to be changed according to // "data_format", // in this case, is "NHWC" to "NCHW". - // new_strides = {strides[NHWC::dim::N], strides[NHWC::dim::C], strides[NHWC::dim::H], strides[NHWC::dim::W]}; -- GitLab From c4ab34f66163bc8face7f588ebba94cadd306d6f Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 14:06:57 +0800 Subject: [PATCH 033/672] Move nb->Attr() out of if statement. --- tensorflow/core/graph/mkl_layout_pass.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 4cfe6aff1a..850a6968a3 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -1821,8 +1821,6 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, new_dilations = {dilations[NDHWC::dim::N], dilations[NDHWC::dim::C], dilations[NDHWC::dim::D], dilations[NDHWC::dim::H], dilations[NDHWC::dim::W]}; - nb->Attr("dilations", new_dilations); - } else { // "strides" and "dilations" also need to be changed according to // "data_format", @@ -1834,8 +1832,8 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, new_dilations = {dilations[NHWC::dim::N], dilations[NHWC::dim::C], dilations[NHWC::dim::H], dilations[NHWC::dim::W]}; - nb->Attr("dilations", new_dilations); } + nb->Attr("dilations", new_dilations); } } -- GitLab From aa14839dfd414adda0fb0260db10f24de18e1e1c Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Fri, 26 Oct 2018 14:17:04 +0800 Subject: [PATCH 034/672] Fix a variable name mis-spelling. Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 850a6968a3..8b29f29746 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2657,7 +2657,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( gtl::InlinedVector transpose_nchw_control_edges; gtl::InlinedVector, 4> transpose_nchw_in( transpose_nchw_num_inputs); - FillInputs(transpose_to_nhwc, &transpose_nchw_control_edges, + FillInputs(transpose_to_nchw, &transpose_nchw_control_edges, &transpose_nchw_in); // We will use the node name of Conv2d as the name of new node -- GitLab From 8afe630a977c94c331c31daaca1d52da6df11303 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 14:42:35 +0800 Subject: [PATCH 035/672] Fix a typo. --- tensorflow/core/graph/mkl_layout_pass.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 8b29f29746..c6cb8552b7 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2657,7 +2657,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( gtl::InlinedVector transpose_nchw_control_edges; gtl::InlinedVector, 4> transpose_nchw_in( transpose_nchw_num_inputs); - FillInputs(transpose_to_nchw, &transpose_nchw_control_edges, + FillInputs(transpose_to_nhwc, &transpose_nchw_control_edges, &transpose_nchw_in); // We will use the node name of Conv2d as the name of new node @@ -2689,8 +2689,8 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( // Fill outputs. for (const Edge* e : transpose_to_nchw->out_edges()) { if (!e->IsControlEdge()) { - const int kConv2DWithBiasOutputSlot = 0; - CHECK_NOTNULL((*g)->AddEdge(new_node, kConv2DWithBiasOutputSlot, e->dst(), + const int kTransposeWithMklOpOutputSlot = 0; + CHECK_NOTNULL((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, e->dst(), e->dst_input())); } } -- GitLab From f05a5ac3a0a2418a7ab9e6b8a907b01b2335491a Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 14:58:53 +0800 Subject: [PATCH 036/672] Copy requested_device and assigned_device_name_index. --- tensorflow/core/graph/mkl_layout_pass.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index c6cb8552b7..125f7a15fb 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2698,6 +2698,10 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( // Copy device assigned to old node to new node. new_node->set_assigned_device_name(mklop->assigned_device_name()); + // Copy requested_device and assigned_device_name_index + new_node->set_requested_device(mklop->requested_device()); + new_node->set_assigned_device_name_index(mklop->assigned_device_name_index()); + (*g)->RemoveNode(transpose_to_nhwc); (*g)->RemoveNode(mklop); (*g)->RemoveNode(transpose_to_nchw); -- GitLab From 976a706932cfee6bcaa37970b07c064308524a2f Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 15:02:27 +0800 Subject: [PATCH 037/672] Remove an assert line. --- tensorflow/core/graph/mkl_layout_pass.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 125f7a15fb..cacf563fff 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2722,7 +2722,6 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { const FusionInfo* fi_ptr = nullptr; for (auto fi = finfo_.begin(); fi != finfo_.end(); ++fi) { - assert(fi->ops.size() == fi->node_checkers.size()); nodes.clear(); fi_ptr = &*fi; // -- GitLab From 0309943937acb3f9b0b7df011f94c3d55cd5b66c Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 26 Oct 2018 15:15:08 +0800 Subject: [PATCH 038/672] Fix a typo. --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index cacf563fff..a7f86e56da 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2657,7 +2657,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( gtl::InlinedVector transpose_nchw_control_edges; gtl::InlinedVector, 4> transpose_nchw_in( transpose_nchw_num_inputs); - FillInputs(transpose_to_nhwc, &transpose_nchw_control_edges, + FillInputs(transpose_to_nchw, &transpose_nchw_control_edges, &transpose_nchw_in); // We will use the node name of Conv2d as the name of new node -- GitLab From 1d94242feccdb2afd3583c0332de090eab2f3811 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Sat, 27 Oct 2018 00:04:52 +0800 Subject: [PATCH 039/672] Replace the greedy search algorithm in "CheckForNodeFusion()" with a stack-based one, to avoid missing some patterns. --- tensorflow/core/graph/mkl_layout_pass.cc | 78 +++++++++++++----------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index a7f86e56da..0ace4a1fd1 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -26,6 +26,8 @@ limitations under the License. #include #include #include +#include +#include #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/optimization_registry.h" @@ -2717,12 +2719,9 @@ Status MklLayoutRewritePass::FuseNode( std::tuple, const MklLayoutRewritePass::FusionInfo> MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { - bool found_pattern = false; - std::vector nodes; const FusionInfo* fi_ptr = nullptr; for (auto fi = finfo_.begin(); fi != finfo_.end(); ++fi) { - nodes.clear(); fi_ptr = &*fi; // // Make sure node "a" and its succeding nodes (b, c ...), match the pattern @@ -2730,51 +2729,60 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { // aka. "a->b->c" matches "op1->op2->op3" // - // Initialize "current_node" as node "a". - Node* current_node = a; - for (auto node_index = 0; node_index < fi->node_checkers.size(); - ++node_index) { - // Make sure current node meet the requirement of corresponding node - // checker. - auto check_node = fi->node_checkers[node_index]; - if (current_node == nullptr || - (check_node && check_node(current_node) == false)) { - found_pattern = false; - nodes.clear(); - break; - } + std::stack> work_stack; + std::set visited_nodes; + auto node_checker = fi->node_checkers.begin(); - // Add current_node to "fusion_nodes": - nodes.push_back(current_node); + Node *current_node = nullptr; + if (a != nullptr) { + work_stack.push(a); + } - // If current node is not the last node we want to check, check next node. - if (node_index != fi->node_checkers.size() - 1) { - // Find current node's direct descendant, which will be used in next - // iteration. - auto check_next_node = fi->node_checkers[node_index + 1]; - for (const Edge* e : current_node->out_edges()) { + while (!work_stack.empty()) { + current_node = work_stack.top(); + + if ((*node_checker)(current_node)){ + if (node_checker == (fi->node_checkers.end() - 1)) { + // We find a match, break and return. + std::vector nodes; + while (!work_stack.empty()) { + nodes.insert(nodes.begin(), work_stack.top()); + work_stack.pop(); + } + + return make_tuple(true, nodes, *fi_ptr); + } + + bool all_succ_has_been_visited = true; + for (const Edge *e : current_node->out_edges()) { if (!e->IsControlEdge()) { - Node* candidate_node = e->dst(); + Node *candidate_node = e->dst(); - if (check_next_node(candidate_node) == false) { - current_node = nullptr; - } else { - current_node = candidate_node; + // If the candidate node has not been visited, push it to stack. + if (visited_nodes.find(candidate_node) == visited_nodes.end()) { + work_stack.push(candidate_node); + ++ node_checker; + all_succ_has_been_visited = false; break; } + + // All successor nodes of current node has been visited (no match found), + // pop the stack and mark current node as "visited". + if (all_succ_has_been_visited) { + visited_nodes.insert(current_node); + work_stack.pop(); + -- node_checker; + } } } } else { - found_pattern = true; + // current node doesn't match, just break and stack will help us roll back. + break; } } - - if (found_pattern == true) { - break; - } } - return make_tuple(found_pattern, nodes, *fi_ptr); + return make_tuple(false, std::vector(), *fi_ptr); } /////////////////////////////////////////////////////////////////////////////// -- GitLab From 095ea5e8cf1b6df75c63dc38f9a8b0338392805f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20LI=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Tue, 30 Oct 2018 01:52:41 +0800 Subject: [PATCH 040/672] fix missing `#` in code example --- tensorflow/python/keras/layers/embeddings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/keras/layers/embeddings.py b/tensorflow/python/keras/layers/embeddings.py index 824a0b069e..d2ba8933ba 100644 --- a/tensorflow/python/keras/layers/embeddings.py +++ b/tensorflow/python/keras/layers/embeddings.py @@ -45,11 +45,11 @@ class Embedding(Layer): model = Sequential() model.add(Embedding(1000, 64, input_length=10)) # the model will take as input an integer matrix of size (batch, - input_length). + # input_length). # the largest integer (i.e. word index) in the input should be no larger - than 999 (vocabulary size). + # than 999 (vocabulary size). # now model.output_shape == (None, 10, 64), where None is the batch - dimension. + # dimension. input_array = np.random.randint(1000, size=(32, 10)) -- GitLab From 6df3eddd533c464dcb300e1896bee2bdf4146dcf Mon Sep 17 00:00:00 2001 From: Pedro Monreal Date: Tue, 30 Oct 2018 18:32:02 +0100 Subject: [PATCH 041/672] Fixed some spellings in core. --- .../common_runtime/collective_param_resolver_local.cc | 2 +- .../core/grappler/costs/op_level_cost_estimator_test.cc | 2 +- tensorflow/core/grappler/grappler_item_builder.cc | 2 +- tensorflow/core/kernels/adjust_contrast_op.cc | 4 ++-- tensorflow/core/kernels/deep_conv2d.cc | 2 +- tensorflow/core/kernels/depthwise_conv_op_gpu.cu.cc | 8 ++++---- tensorflow/core/kernels/dynamic_partition_op.cc | 2 +- tensorflow/core/kernels/fractional_avg_pool_op.cc | 2 +- tensorflow/core/kernels/fused_batch_norm_op.cc | 4 ++-- tensorflow/core/kernels/mkl_softmax_op.cc | 4 ++-- .../core/kernels/quantized_resize_bilinear_op_test.cc | 2 +- tensorflow/core/kernels/stage_op.cc | 2 +- tensorflow/core/platform/cpu_feature_guard.cc | 2 +- tensorflow/core/platform/numa_test.cc | 2 +- tensorflow/core/profiler/internal/tfprof_code.cc | 2 +- tensorflow/core/profiler/internal/tfprof_node.cc | 2 +- tensorflow/core/protobuf/master.proto | 2 +- tensorflow/core/util/tensor_bundle/tensor_bundle.cc | 4 ++-- 18 files changed, 25 insertions(+), 25 deletions(-) diff --git a/tensorflow/core/common_runtime/collective_param_resolver_local.cc b/tensorflow/core/common_runtime/collective_param_resolver_local.cc index 1bc873d0c5..44bf99764b 100644 --- a/tensorflow/core/common_runtime/collective_param_resolver_local.cc +++ b/tensorflow/core/common_runtime/collective_param_resolver_local.cc @@ -660,7 +660,7 @@ void CollectiveParamResolverLocal::CompleteInstanceSource(InstanceRec* ir, if (ir->source_rank >= 0) { ir->status = errors::Internal("Instance ", cp->instance.instance_key, " already has source ", ir->source_rank, - ", recevied second claim from ", + ", received second claim from ", cp->default_rank); } else { ir->source_rank = cp->default_rank; diff --git a/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc b/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc index 998bd59dce..c9ce63a8ef 100644 --- a/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc +++ b/tensorflow/core/grappler/costs/op_level_cost_estimator_test.cc @@ -832,7 +832,7 @@ TEST_F(OpLevelCostEstimatorTest, GetTensorShapeProtoFromTensorProto) { EXPECT_FALSE( GetTensorShapeProtoFromTensorProto(tensor_proto, &tensor_shape_proto)); - // Check GetTensorShapeProtoFromTensorProto() resturns correct values. + // Check GetTensorShapeProtoFromTensorProto() returns correct values. { std::vector shape_expected = {10, 20, 30, 40}; GetTensorProto(DT_INT32, {4}, shape_expected, diff --git a/tensorflow/core/grappler/grappler_item_builder.cc b/tensorflow/core/grappler/grappler_item_builder.cc index cf99f4908b..984760ab99 100644 --- a/tensorflow/core/grappler/grappler_item_builder.cc +++ b/tensorflow/core/grappler/grappler_item_builder.cc @@ -519,7 +519,7 @@ std::unique_ptr GrapplerItemFromMetaGraphDef( } if (!iter->second.has_tensor() || iter->second.tensor().string_val_size() != 1) { - LOG(INFO) << "Unexected AttrValue proto: " + LOG(INFO) << "Unexpected AttrValue proto: " << iter->second.DebugString(); return nullptr; } diff --git a/tensorflow/core/kernels/adjust_contrast_op.cc b/tensorflow/core/kernels/adjust_contrast_op.cc index 72155fd037..5e1ca166db 100644 --- a/tensorflow/core/kernels/adjust_contrast_op.cc +++ b/tensorflow/core/kernels/adjust_contrast_op.cc @@ -320,13 +320,13 @@ class AdjustContrastOpv2 : public AdjustContrastOpV2Base { int64 batch = outputs.dimension(0); int64 image_size = outputs.dimension(1); int64 channels = outputs.dimension(2); - // Similar to the reduction case, a straighforward implementation of this + // Similar to the reduction case, a straightforward implementation of this // does not utilize vectorization well because of the small channel size. // This algorithm repeatedly increases the area to be copied, and leads to // much better vectorinizations in the copy. for (int64 i = 0; i < batch; i++) { // Copy over the inputs into outputs in this batch. Effectively: - // outputs(i, :, k) = inputs(i, k). An example of how this algorith works: + // outputs(i, :, k) = inputs(i, k). An example of how this algorithm works: // // x = float[1, 3], y = float[2048, 3] // round 0 diff --git a/tensorflow/core/kernels/deep_conv2d.cc b/tensorflow/core/kernels/deep_conv2d.cc index 1aa8c72d66..e3dabd687c 100644 --- a/tensorflow/core/kernels/deep_conv2d.cc +++ b/tensorflow/core/kernels/deep_conv2d.cc @@ -787,7 +787,7 @@ struct TransformOutputTile { const int64 shard_base = sr * filter_shards_col + sc; const int64 out_buf_base = tile_base + out_depth_base + shard_base; - // Calcuate output indices and outputs to drop (if needed). + // Calculate output indices and outputs to drop (if needed). const int64 out_r_start = in_r + args.pad_rows - sr * tile_stride_rows; // NOTE: The index 't' for 'num_tiles is used in index calculation diff --git a/tensorflow/core/kernels/depthwise_conv_op_gpu.cu.cc b/tensorflow/core/kernels/depthwise_conv_op_gpu.cu.cc index 76afd6f18c..f429b368ab 100644 --- a/tensorflow/core/kernels/depthwise_conv_op_gpu.cu.cc +++ b/tensorflow/core/kernels/depthwise_conv_op_gpu.cu.cc @@ -175,7 +175,7 @@ __global__ __launch_bounds__(1024, 2) void DepthwiseConv2dGPUKernelNHWCSmall( assert(CanLaunchDepthwiseConv2dGPUSmall(args)); // Holds block plus halo and filter data for blockDim.x depths. extern __shared__ __align__(8) unsigned char shared_memory[]; - static_assert(sizeof(S) <= 8, "Insufficient alignement detected"); + static_assert(sizeof(S) <= 8, "Insufficient alignment detected"); S* const shared_data = reinterpret_cast(shared_memory); const int num_batches = args.batch; @@ -459,7 +459,7 @@ __global__ __launch_bounds__(1024, 2) void DepthwiseConv2dGPUKernelNCHWSmall( assert(CanLaunchDepthwiseConv2dGPUSmall(args)); // Holds block plus halo and filter data for blockDim.z depths. extern __shared__ __align__(8) unsigned char shared_memory[]; - static_assert(sizeof(S) <= 8, "Insufficient alignement detected"); + static_assert(sizeof(S) <= 8, "Insufficient alignment detected"); S* const shared_data = reinterpret_cast(shared_memory); const int num_batches = args.batch; @@ -1176,7 +1176,7 @@ __launch_bounds__(1024, 2) void DepthwiseConv2dBackpropFilterGPUKernelNHWCSmall( assert(CanLaunchDepthwiseConv2dBackpropFilterGPUSmall(args, blockDim.z)); // Holds block plus halo and filter data for blockDim.x depths. extern __shared__ __align__(8) unsigned char shared_memory[]; - static_assert(sizeof(S) <= 8, "Insufficient alignement detected"); + static_assert(sizeof(S) <= 8, "Insufficient alignment detected"); S* const shared_data = reinterpret_cast(shared_memory); const int num_batches = args.batch; @@ -1448,7 +1448,7 @@ __launch_bounds__(1024, 2) void DepthwiseConv2dBackpropFilterGPUKernelNCHWSmall( assert(CanLaunchDepthwiseConv2dBackpropFilterGPUSmall(args, blockDim.x)); // Holds block plus halo and filter data for blockDim.z depths. extern __shared__ __align__(8) unsigned char shared_memory[]; - static_assert(sizeof(S) <= 8, "Insufficient alignement detected"); + static_assert(sizeof(S) <= 8, "Insufficient alignment detected"); S* const shared_data = reinterpret_cast(shared_memory); const int num_batches = args.batch; diff --git a/tensorflow/core/kernels/dynamic_partition_op.cc b/tensorflow/core/kernels/dynamic_partition_op.cc index 3c988db5e6..572d04ae2c 100644 --- a/tensorflow/core/kernels/dynamic_partition_op.cc +++ b/tensorflow/core/kernels/dynamic_partition_op.cc @@ -142,7 +142,7 @@ class DynamicPartitionOp : public DynamicPartitionOp_Shared { OP_REQUIRES( c, FastBoundsCheck(p, num_partitions_), errors::InvalidArgument("indices[", i, - "] has been asynchronously overwitten and " + "] has been asynchronously overwritten and " "is no longer in range!")); auto oi = output_index[p]; OP_REQUIRES(c, FastBoundsCheck(oi, out_flat[p].dimension(0)), diff --git a/tensorflow/core/kernels/fractional_avg_pool_op.cc b/tensorflow/core/kernels/fractional_avg_pool_op.cc index 135d002345..61234479ea 100644 --- a/tensorflow/core/kernels/fractional_avg_pool_op.cc +++ b/tensorflow/core/kernels/fractional_avg_pool_op.cc @@ -223,7 +223,7 @@ class FractionalAvgPoolGradOp : public OpKernel { // Once we figure out the original contributors, we just need to evenly // divide the value of this element among these contributors. // - // Internally, we divide the out_backprop tensor and store it in a temparary + // Internally, we divide the out_backprop tensor and store it in a temporary // tensor of double type. And cast it to the corresponding type. typedef Eigen::Map> ConstEigenMatrixMap; diff --git a/tensorflow/core/kernels/fused_batch_norm_op.cc b/tensorflow/core/kernels/fused_batch_norm_op.cc index d89f1592bd..dbd3bb05db 100644 --- a/tensorflow/core/kernels/fused_batch_norm_op.cc +++ b/tensorflow/core/kernels/fused_batch_norm_op.cc @@ -248,7 +248,7 @@ struct FusedBatchNorm { Tensor* saved_inv_var, TensorFormat tensor_format, bool is_training) { auto* stream = context->op_device_context()->stream(); - OP_REQUIRES(context, stream, errors::Internal("No GPU stream avalible")); + OP_REQUIRES(context, stream, errors::Internal("No GPU stream available")); const int64 batch_size = GetTensorDim(x, tensor_format, 'N'); const int64 channels = GetTensorDim(x, tensor_format, 'C'); @@ -389,7 +389,7 @@ struct FusedBatchNormGrad { Tensor* scale_backprop, Tensor* offset_backprop, TensorFormat tensor_format) { auto* stream = context->op_device_context()->stream(); - OP_REQUIRES(context, stream, errors::Internal("No GPU stream avalible")); + OP_REQUIRES(context, stream, errors::Internal("No GPU stream available")); const int64 batch_size = GetTensorDim(x, tensor_format, 'N'); const int64 channels = GetTensorDim(x, tensor_format, 'C'); diff --git a/tensorflow/core/kernels/mkl_softmax_op.cc b/tensorflow/core/kernels/mkl_softmax_op.cc index cfab529662..3bf17bc449 100644 --- a/tensorflow/core/kernels/mkl_softmax_op.cc +++ b/tensorflow/core/kernels/mkl_softmax_op.cc @@ -56,7 +56,7 @@ class MklSoftmaxOp : public OpKernel { MklDnnShape src_mkl_shape; GetMklShape(context, src_idx, &src_mkl_shape); - // src_dims is the dimenstion of src_tensor + // src_dims is the dimension of src_tensor // dim of the dst will also be same as src_dims auto src_tf_shape = src_mkl_shape.IsMklTensor() ? src_mkl_shape.GetTfShape() @@ -68,7 +68,7 @@ class MklSoftmaxOp : public OpKernel { // Here "x" data format in MKL is used for 1 dim tensor, "nc" for 2 dim tensor, // "tnc" for 3 dim tensor, "nchw" for 4 dim tensor, and "ncdhw" for 5 dim tensor. // Each of the simbols has the following meaning: - // n = batch, c = channels, t = sequence lenght, h = height, + // n = batch, c = channels, t = sequence length, h = height, // w = width, d = depth switch (input_dims) { case 1: diff --git a/tensorflow/core/kernels/quantized_resize_bilinear_op_test.cc b/tensorflow/core/kernels/quantized_resize_bilinear_op_test.cc index e6133415d0..6fc4894592 100644 --- a/tensorflow/core/kernels/quantized_resize_bilinear_op_test.cc +++ b/tensorflow/core/kernels/quantized_resize_bilinear_op_test.cc @@ -273,7 +273,7 @@ void TestResizeBilinearOneDim() { << expected_val << ", " << resized_image_val; } - // Value testing with reference implemenatation + // Value testing with reference implementation CheckTensorValue(image_quantized_tensor.flat().data(), outputs.at(0).flat().data(), /*batch_size=*/1, diff --git a/tensorflow/core/kernels/stage_op.cc b/tensorflow/core/kernels/stage_op.cc index 73a02a34cf..c91bdc43cf 100644 --- a/tensorflow/core/kernels/stage_op.cc +++ b/tensorflow/core/kernels/stage_op.cc @@ -151,7 +151,7 @@ class Buffer : public ResourceBase { } // Are there a limit number of elements or a memory limit - // configued on this buffer? + // configured on this buffer? bool IsBounded() const { return capacity_ > 0 || memory_limit_ > 0; } bool IsCapacityFull() const { return buf_.size() >= capacity_; } diff --git a/tensorflow/core/platform/cpu_feature_guard.cc b/tensorflow/core/platform/cpu_feature_guard.cc index 9d00aa7b7f..2efe0c0876 100644 --- a/tensorflow/core/platform/cpu_feature_guard.cc +++ b/tensorflow/core/platform/cpu_feature_guard.cc @@ -41,7 +41,7 @@ void CheckFeatureOrDie(CPUFeature feature, const string& feature_name) { } } -// Check if CPU feature is inclued in the TensorFlow binary. +// Check if CPU feature is included in the TensorFlow binary. void CheckIfFeatureUnused(CPUFeature feature, const string& feature_name, string& missing_instructions) { if (TestCPUFeature(feature)) { diff --git a/tensorflow/core/platform/numa_test.cc b/tensorflow/core/platform/numa_test.cc index 8b39ecd59c..91789efd1e 100644 --- a/tensorflow/core/platform/numa_test.cc +++ b/tensorflow/core/platform/numa_test.cc @@ -44,7 +44,7 @@ TEST(Numa, Malloc) { TEST(Numa, SetNodeAffinity) { // NOTE(tucker): This test is not reliable when executed under tap because - // the virtual machine may not have access to all of the availble NUMA + // the virtual machine may not have access to all of the available NUMA // nodes. Not sure what to do about that. EXPECT_EQ(-1, port::NUMAGetThreadNodeAffinity()); if (port::NUMAEnabled()) { diff --git a/tensorflow/core/profiler/internal/tfprof_code.cc b/tensorflow/core/profiler/internal/tfprof_code.cc index 744e1e95de..0c26855a43 100644 --- a/tensorflow/core/profiler/internal/tfprof_code.cc +++ b/tensorflow/core/profiler/internal/tfprof_code.cc @@ -183,7 +183,7 @@ class Samples { // This method adds the statistics of graph nodes created by the python // call. void Add(const CodeNode* node, const std::vector& location_ids) { - // displayed leaf might not be true leaf. Retrive the true leaves for + // displayed leaf might not be true leaf. Retrieve the true leaves for // stats. std::vector all_leaf = FetchAllLeaf(node); CHECK(!all_leaf.empty()) << node->name(); diff --git a/tensorflow/core/profiler/internal/tfprof_node.cc b/tensorflow/core/profiler/internal/tfprof_node.cc index 86cb20de7b..8796234be0 100644 --- a/tensorflow/core/profiler/internal/tfprof_node.cc +++ b/tensorflow/core/profiler/internal/tfprof_node.cc @@ -151,7 +151,7 @@ void ExecStep::AddMemoryStats(const string& dev, } // TODO(xpan): Make this more accurate: - // High level: Memory tracking is suspicous and requires large scale + // High level: Memory tracking is suspicious and requires large scale // clean up. // Investigte the memory usage difference between CPU/GPU with OpViewTest. // diff --git a/tensorflow/core/protobuf/master.proto b/tensorflow/core/protobuf/master.proto index 03022875e6..c104463c51 100644 --- a/tensorflow/core/protobuf/master.proto +++ b/tensorflow/core/protobuf/master.proto @@ -224,7 +224,7 @@ message CloseSessionResponse { message ResetRequest { // A list of container names, which may be empty. // - // If 'container' is not empty, releases resoures in the given + // If 'container' is not empty, releases resources in the given // containers in all devices. // // If 'container' is empty, releases resources in the default diff --git a/tensorflow/core/util/tensor_bundle/tensor_bundle.cc b/tensorflow/core/util/tensor_bundle/tensor_bundle.cc index 2dcb57a1f9..3709ee5ae3 100644 --- a/tensorflow/core/util/tensor_bundle/tensor_bundle.cc +++ b/tensorflow/core/util/tensor_bundle/tensor_bundle.cc @@ -785,7 +785,7 @@ Status BundleReader::GetBundleEntryProto(StringPiece key, TF_RETURN_IF_ERROR( ParseEntryProto(iter_->key(), iter_->value(), &entry_copy)); if (!TensorShape::IsValid(entry_copy.shape())) { - return errors::DataLoss("Invaid tensor shape: ", key, " ", + return errors::DataLoss("Invalid tensor shape: ", key, " ", ProtoShortDebugString(entry_copy.shape())); } @@ -895,7 +895,7 @@ Status BundleReader::ReadCurrent(Tensor* val) { BundleEntryProto entry; TF_RETURN_IF_ERROR(ParseEntryProto(iter_->key(), iter_->value(), &entry)); if (!TensorShape::IsValid(entry.shape())) { - return errors::DataLoss("Invaid tensor shape: ", iter_->key(), " ", + return errors::DataLoss("Invalid tensor shape: ", iter_->key(), " ", ProtoShortDebugString(entry.shape())); } -- GitLab From da4235299bd7e0089108634074b659d353102969 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 10:54:36 +0800 Subject: [PATCH 042/672] Add a comment to the constraint of "inference-only" to note it will eventually be removed, if we enabled this fusion for training in the future. --- tensorflow/core/graph/mkl_layout_pass.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 0ace4a1fd1..30874dcf9e 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -912,6 +912,8 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. + // Note: this constraint will eventually be removed, if we enabled this fusion for training + // in the future. for (const Edge* e : node->out_edges()) { if (e->IsControlEdge()) { return false; -- GitLab From aab29e70ec2de097a04fb36aa2a60e2d286be1de Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 11:26:48 +0800 Subject: [PATCH 043/672] Move a cheaper early return to the top of the function. --- tensorflow/core/graph/mkl_layout_pass.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 30874dcf9e..31d11d4aaf 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -910,6 +910,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // Check if node's type is "Transpose" if (node->type_string() != "Transpose") return false; + // If "Transpose" has multiple output data edges, also don't fuse it. + if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; + // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. // Note: this constraint will eventually be removed, if we enabled this fusion for training @@ -927,9 +930,6 @@ class MklLayoutRewritePass : public GraphOptimizationPass { } } - // If "Transpose" has multiple output data edges, also don't fuse it. - if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; - // We compared the tensor containing the permutation order ("perm_node") // with our desired order ("perm"). If they're exactly match, this check // succeed and returns true. -- GitLab From 6e3d7a22a7fa5622f32cee16a9162feab8f5a376 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 11:31:43 +0800 Subject: [PATCH 044/672] Set strides outside of if-else. --- tensorflow/core/graph/mkl_layout_pass.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 31d11d4aaf..0df78ddc6f 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -1820,7 +1820,6 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, new_strides = {strides[NDHWC::dim::N], strides[NDHWC::dim::C], strides[NDHWC::dim::D], strides[NDHWC::dim::H], strides[NDHWC::dim::W]}; - nb->Attr("strides", new_strides); new_dilations = {dilations[NDHWC::dim::N], dilations[NDHWC::dim::C], dilations[NDHWC::dim::D], dilations[NDHWC::dim::H], @@ -1832,11 +1831,12 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, new_strides = {strides[NHWC::dim::N], strides[NHWC::dim::C], strides[NHWC::dim::H], strides[NHWC::dim::W]}; - nb->Attr("strides", new_strides); + new_dilations = {dilations[NHWC::dim::N], dilations[NHWC::dim::C], dilations[NHWC::dim::H], dilations[NHWC::dim::W]}; } + nb->Attr("strides", new_strides); nb->Attr("dilations", new_dilations); } } -- GitLab From 753c474ba8fbbb11d213fe650240b5f30d074058 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 11:38:29 +0800 Subject: [PATCH 045/672] Fix a comment line. --- tensorflow/core/graph/mkl_layout_pass.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 0df78ddc6f..82e714fdf9 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2664,8 +2664,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( FillInputs(transpose_to_nchw, &transpose_nchw_control_edges, &transpose_nchw_in); - // We will use the node name of Conv2d as the name of new node - // Build new node. We use same name as original node, but change the op + // We use same name as original node, but change the op // name. NodeBuilder nb(mklop->name(), mklop->type_string()); -- GitLab From fa54ac8e616127862bdb2f9f0c3e9324274e360d Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 13:03:30 +0800 Subject: [PATCH 046/672] Add a comment to clarify that patterns in finfo_ shows up first will get applied first. --- tensorflow/core/graph/mkl_layout_pass.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 82e714fdf9..f726f01ce6 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -514,6 +514,10 @@ class MklLayoutRewritePass : public GraphOptimizationPass { csinfo_.conv2d_grad_filter_with_bias, GetConv2DBackpropFilterOrBiasAddGrad}); + // The fusion patterns in "finfo_" that show up first will get applied first, + // for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, A->B->C->D to ABCD}, + // since the first gets applied first, the final graph will be ABC->D. + // // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D // (NHWC) + Transpose (NHWC-> -- GitLab From a554e9d7f8dfcc562b568c678f93a88185d7dd05 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 13:12:04 +0800 Subject: [PATCH 047/672] Use std::unordered_set instead of std::set, for better performance. --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index f726f01ce6..305b80df34 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2735,7 +2735,7 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { // std::stack> work_stack; - std::set visited_nodes; + std::unordered_set visited_nodes; auto node_checker = fi->node_checkers.begin(); Node *current_node = nullptr; -- GitLab From 13ed0286c40c81f23a73a9cd773da4d1dd27197a Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 31 Oct 2018 13:35:28 +0800 Subject: [PATCH 048/672] Fix 2 bugs in CheckNodeForFusion(): 1. The else case for node_checker fails are not handled properly. Should pop the stack, rather then break the while loop entirely. 2. The nested level of stack op when node_check succeed is wrong. --- tensorflow/core/graph/mkl_layout_pass.cc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 305b80df34..65bd568f6c 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2770,19 +2770,22 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { all_succ_has_been_visited = false; break; } - - // All successor nodes of current node has been visited (no match found), - // pop the stack and mark current node as "visited". - if (all_succ_has_been_visited) { - visited_nodes.insert(current_node); - work_stack.pop(); - -- node_checker; - } } } + + // All successor nodes of current node has been visited (no match found), + // pop the stack and mark current node as "visited". + if (all_succ_has_been_visited) { + visited_nodes.insert(current_node); + work_stack.pop(); + -- node_checker; + } + } else { - // current node doesn't match, just break and stack will help us roll back. - break; + // current node doesn't match, pop stack to roll back. + visited_nodes.insert(current_node); + work_stack.pop(); + -- node_checker; } } } -- GitLab From 1df5f7a302864741f0e814d030bebc7094553627 Mon Sep 17 00:00:00 2001 From: Fei Hu Date: Thu, 1 Nov 2018 16:34:43 -0700 Subject: [PATCH 049/672] Fix the data type issue in compute_output_shape --- tensorflow/python/keras/layers/wrappers.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/keras/layers/wrappers.py b/tensorflow/python/keras/layers/wrappers.py index c795b2aa7e..82c96e386a 100644 --- a/tensorflow/python/keras/layers/wrappers.py +++ b/tensorflow/python/keras/layers/wrappers.py @@ -441,10 +441,15 @@ class Bidirectional(Wrapper): @tf_utils.shape_type_conversion def compute_output_shape(self, input_shape): - output_shape = tuple(self.forward_layer.compute_output_shape( - input_shape).as_list()) + forward_layer_output_shape \ + = self.forward_layer.compute_output_shape(input_shape) + if getattr(forward_layer_output_shape, 'as_list', None) is None: + output_shape = tuple(forward_layer_output_shape) + else: + output_shape = tuple(forward_layer_output_shape.as_list()) + if self.return_state: - state_shape = output_shape[1:] + state_shape = list(output_shape[1:]) output_shape = output_shape[0] if self.merge_mode == 'concat': -- GitLab From 58f69a5899c8a902956b876c3fa8baab6e60e7c7 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Thu, 6 Sep 2018 15:59:07 -0700 Subject: [PATCH 050/672] Allows user to specify int8 scales via TF nodes. Basic working example - all tensors have range of -5 to 5 [skip ci] Range of -0.1 to 0.1 seems to work decently [skip ci ] Load quantization numbers from txt file. Switching between prequant and calib now controlled by two bools (in convert_node.h and convert_graph.h - working on merging to a single control arg [skip ci] stuff in scripts for testing prequantized int8 [skip ci] Add python interface using dict and support dynamic op debug prints and inference scripts propagate First mode where we simply tell the user which ranges are missing if not all are supplied. Still need to infer some ranges backward through shuffle etc. Fix ConvertIdentity bug and add error checking to input binding [skip ci] cleanup and fix more [skip ci] Set softmax range. Fix some cases of inferring ranges. Remove theoretical Matmul infer. Don't print missing ranges for internal unnamed tensors Remove unneeded conversion of dict -> unordered_map (it had bugs with python2 strings causing python2 build to fail) [skip ci] Fix syntax error and infer backwards in another shuffle situation Pass weights through quant nodes unchanged. Fix broadcast issue with Relu6. Remove some problematic backwards infers Cleanup Cleanup Change arg to use_calibrate. Add unction to copy ranges. Add comments for features which are incomplete or not used. Fix identity conversion. Add missing code for Relu6 Add missing range copies and fix issue with const ITensor* Properly compute symmetric range. Fix const cast bug Fix bug with use_calibration arg. Change quantization range interface to use Converter class. Change range inferring algorithm to allow for multiple hops. Formatting fixes. Quant ops are format-agnostic to layout optimizer now. Exclude quant ops from FP16 and FP32 graphs. Rename scales to ranges. Formatting Add tests for quantization Fix bug with symmetric range calculation by switching to std::max. Improve tests (they will be broken until Transpose op is added). Add check for when mode is not int8 and calib=true Fix tests. Add comments and checks, small fixes. Fix candidate ops check. Log missing tensors unconditionally. Improve some comments. Revert ConvertIdentity to original implementation - the name check in convert_node is sufficient and adding the no-op shuffles introduced problems Don't use shuffle no-op as conversion for quantize, instead just pass tensor through. Shuffle no-op is not optimized away like we thought so it can interfere with TRT's node fusion, causing reduced accuracy Const bool --- tensorflow/contrib/tensorrt/BUILD | 1 + .../contrib/tensorrt/convert/convert_graph.cc | 59 ++-- .../contrib/tensorrt/convert/convert_graph.h | 7 +- .../tensorrt/convert/convert_graph_test.cc | 8 +- .../contrib/tensorrt/convert/convert_nodes.cc | 252 +++++++++++++++++- .../contrib/tensorrt/convert/convert_nodes.h | 39 ++- .../tensorrt/convert/trt_optimization_pass.cc | 10 + .../tensorrt/convert/trt_optimization_pass.h | 4 +- .../contrib/tensorrt/kernels/trt_engine_op.cc | 14 +- .../contrib/tensorrt/kernels/trt_engine_op.h | 4 + .../contrib/tensorrt/ops/trt_engine_op.cc | 3 +- .../contrib/tensorrt/python/trt_convert.py | 19 +- .../contrib/tensorrt/segment/segment.cc | 4 +- tensorflow/contrib/tensorrt/segment/segment.h | 4 +- tensorflow/contrib/tensorrt/test/base_test.py | 4 +- .../tensorrt/test/quantization_test.py | 164 ++++++++++++ .../test/tf_trt_integration_test_base.py | 45 +++- .../grappler/optimizers/layout_optimizer.cc | 5 + 18 files changed, 590 insertions(+), 56 deletions(-) create mode 100644 tensorflow/contrib/tensorrt/test/quantization_test.py diff --git a/tensorflow/contrib/tensorrt/BUILD b/tensorflow/contrib/tensorrt/BUILD index 20bcd2447e..64a2fd50c3 100644 --- a/tensorflow/contrib/tensorrt/BUILD +++ b/tensorflow/contrib/tensorrt/BUILD @@ -491,6 +491,7 @@ cuda_py_tests( "test/memory_alignment_test.py", "test/multi_connection_neighbor_engine_test.py", "test/neighboring_engine_test.py", + "test/quantization_test.py", "test/rank_two_test.py", "test/reshape_transpose_test.py", "test/vgg_block_nchw_test.py", diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 1f5591fe2a..40d03ace6f 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -85,7 +85,7 @@ TrtCandidateSelector::TrtCandidateSelector( const grappler::GraphProperties& graph_properties) : graph_properties_(graph_properties) {} -Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node) { +Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node, int precision_mode) { // TODO(laigd): move this set to TrtNodeValidator where it should belong. // LINT.IfChange static const std::set candidate_ops = { @@ -128,11 +128,24 @@ Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node) { "Prod", "Max", "Min", + "Relu6", }; + bool is_supported_op_type = (candidate_ops.count(node->type_string()) || + PluginFactoryTensorRT::GetInstance()->IsPlugin(node->type_string())); +#if NV_TENSORRT_MAJOR >= 5 + static const std::set quantize_ops = { + "QuantizeV2", + "Dequantize", + "QuantizeAndDequantizeV2", + "QuantizeAndDequantizeV3", + "FakeQuantWithMinMaxVars", + }; + if (precision_mode == INT8MODE && + quantize_ops.count(node->type_string())) { + is_supported_op_type = true; + } +#endif // LINT.ThenChange(//tensorflow/contrib/tensorrt/convert/convert_nodes.cc) - const bool is_supported_op_type = - (candidate_ops.count(node->type_string()) || - PluginFactoryTensorRT::GetInstance()->IsPlugin(node->type_string())); if (!is_supported_op_type) { return errors::Unimplemented("Op type ", node->type_string(), " is not supported."); @@ -219,7 +232,8 @@ tensorflow::Status ConvertGraphDefToTensorRT( const std::vector& output_names, size_t max_batch_size, size_t max_workspace_size_bytes, tensorflow::GraphDef* new_graph_def, int precision_mode, int minimum_segment_size, bool is_dyn_op, - int max_cached_engines, std::vector cached_engine_batches) { + int max_cached_engines, std::vector cached_engine_batches, + bool use_calibration) { // Create GrapplerItem. tensorflow::grappler::GrapplerItem item; item.fetch = output_names; @@ -284,6 +298,7 @@ tensorflow::Status ConvertGraphDefToTensorRT( list->add_i(batch); } } + parameters["use_calibration"].set_b(use_calibration); // Run optimizer. tensorflow::grappler::MetaOptimizer meta_opt(nullptr, rw_cfg); @@ -563,27 +578,31 @@ tensorflow::Status CreateTRTNode(const std::vector& infos, int pos, } } } + + const bool calibrate_int8 = (info.precision_mode == INT8MODE && info.use_calibration); + // Build the engine and get its serialized representation. string segment_string; - if (info.engine_type == EngineInfo::EngineType::TRTStatic || - info.precision_mode == INT8MODE) { + if (info.engine_type == EngineInfo::EngineType::TRTStatic || + calibrate_int8) { // Create static engine for fp32/fp16 mode, and test validity of the engine - // for int8 mode. We don't want engine to fail at the calibration time. - // So we are constructing a FP32 engine here to check its validity, and if - // it is a valid engine then we put the serialized graphdef to the op. - // Otherwise we skip node creation for this engine. + // for int8 calibration mode. We don't want engine to fail at the + // calibration time. So we are constructing a FP32 engine here to check its + // validity, and if it is a valid engine then we put the serialized graphdef + // to the op. Otherwise we skip node creation for this engine. Logger trt_logger; TrtUniquePtrType engine; // TODO(sami): What happens if 1st dim is not batch? TF_RETURN_IF_ERROR(ConvertGraphDefToEngine( info.segment_graph_def, - info.precision_mode == INT8MODE ? FP32MODE : info.precision_mode, + calibrate_int8 ? FP32MODE : info.precision_mode, max_batch_size, info.max_workspace_size_bytes, input_shapes, &trt_logger, alloc, /*calibrator=*/nullptr, &engine, + info.use_calibration, /*convert_successfully=*/nullptr)); TrtUniquePtrType engine_data(engine->serialize()); segment_string = string((const char*)engine_data->data(), engine_data->size()); - if (info.precision_mode == INT8MODE) { + if (calibrate_int8) { // See above comment about why not putting this inside the 'else' branch. segment_string = info.segment_graph_def.SerializeAsString(); } @@ -595,7 +614,7 @@ tensorflow::Status CreateTRTNode(const std::vector& infos, int pos, // conversion. string prec_string; TF_RETURN_IF_ERROR(GetPrecisionModeName(info.precision_mode, &prec_string)); - if (info.precision_mode == INT8MODE && + if (info.precision_mode == INT8MODE && calibrate_int8 && !TRTResourceManager::instance()->getManager("TRTCalibration")) { LOG(ERROR) << "Failed to construct calibration storage"; } @@ -631,6 +650,7 @@ tensorflow::Status CreateTRTNode(const std::vector& infos, int pos, .Attr("cached_engine_batches", {max_batch_size}) .Attr("workspace_size_bytes", info.max_workspace_size_bytes) .Attr("precision_mode", prec_string) + .Attr("use_calibration", info.use_calibration) .Attr("OutT", out_types) .Finalize(&trt_node); if (!status.ok()) { @@ -862,12 +882,13 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { segment_options.exclude_node_list.insert(node); } segment_options.minimum_segment_size = params.minimum_segment_size; + segment_options.precision_mode = params.precision_mode; tensorflow::tensorrt::segment::SegmentNodesVector initial_segments; TrtCandidateSelector candidate_selector(*params.graph_properties); TF_RETURN_IF_ERROR(tensorrt::segment::SegmentGraph( &graph, std::bind(&TrtCandidateSelector::IsTensorRTCandidate, &candidate_selector, - std::placeholders::_1), + std::placeholders::_1, std::placeholders::_2), // Input validation is already done by TrtCandidateSelector, so we don't // need to check the input edges. [](const Edge* edge) { return true; }, OutputEdgeValidator(), @@ -901,10 +922,14 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { continue; } curr_engine.precision_mode = params.precision_mode; - curr_engine.engine_type = - (params.is_dyn_op || params.precision_mode == INT8MODE + if (params.use_calibration && params.precision_mode != INT8MODE) { + return tensorflow::errors::Unimplemented( + "Calibration with FP32 or FP16 is not implemented. "); + } + curr_engine.engine_type = ((params.is_dyn_op || params.use_calibration) ? EngineInfo::EngineType::TRTDynamic : EngineInfo::EngineType::TRTStatic); + curr_engine.use_calibration = params.use_calibration; curr_engine.cached_engine_batches = params.cached_engine_batches; curr_engine.maximum_cached_engines = params.max_cached_engines; StrAppend(&curr_engine.engine_name, "my_trt_op_", t); diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.h b/tensorflow/contrib/tensorrt/convert/convert_graph.h index 1c9d82105a..eaa1edbfe4 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.h +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.h @@ -39,7 +39,7 @@ class TrtCandidateSelector { // Returns OK iff 'node' is a TF-TRT conversion candidate, which will be added // to TRT subgraph and later converted into TRT engine. - Status IsTensorRTCandidate(const tensorflow::Node* node); + Status IsTensorRTCandidate(const tensorflow::Node* node, int precision_mode); private: // The TF-TRT node converter used to verify whether individual node is @@ -63,6 +63,7 @@ struct ConversionParams { cluster(nullptr), is_dyn_op(false), fixed_input_size(true), + use_calibration(true), max_cached_engines(1) {} const tensorflow::GraphDef* input_graph_def; const std::vector* output_names; @@ -76,6 +77,7 @@ struct ConversionParams { bool is_dyn_op; // Whether to create engine on conversion or execution time bool fixed_input_size; // Assume non-batch ranks of input tensors are fixed int max_cached_engines; // maximum number of cached engines + bool use_calibration; std::vector cached_engine_batches; // list of cached engines }; @@ -95,7 +97,8 @@ tensorflow::Status ConvertGraphDefToTensorRT( size_t max_workspace_size_bytes, tensorflow::GraphDef* new_graph_def, int precision_mode = 1, int minimum_segment_size = 3, bool is_dyn_op = false, int max_cached_engines = 1, - std::vector cached_engine_batches = {}); + std::vector cached_engine_batches = {}, + bool use_calibration = true); // Method to call from optimization pass tensorflow::Status ConvertAfterShapes(ConversionParams& params); diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc b/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc index f10729987f..925de7885f 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc @@ -94,16 +94,16 @@ TEST(TrtCandidateSelector, Basics) { TF_EXPECT_OK(graph_properties.InferStatically(true)); TrtCandidateSelector selector(graph_properties); - TF_EXPECT_OK(selector.IsTensorRTCandidate(matmul.operation.node())); + TF_EXPECT_OK(selector.IsTensorRTCandidate(matmul.operation.node(), FP32MODE)); ExpectStatus( - selector.IsTensorRTCandidate(incompatible_matmul.operation.node()), + selector.IsTensorRTCandidate(incompatible_matmul.operation.node(), FP32MODE), error::INVALID_ARGUMENT, "transpose_a is not supported for TensorRT FullyConnected " "(op: MatMul), at: incompatible_matmul"); - ExpectStatus(selector.IsTensorRTCandidate(unsupported_op.operation.node()), + ExpectStatus(selector.IsTensorRTCandidate(unsupported_op.operation.node(), FP32MODE), error::UNIMPLEMENTED, "Op type Sin is not supported"); ExpectStatus(selector.IsTensorRTCandidate( - matmul_with_incompatible_input.operation.node()), + matmul_with_incompatible_input.operation.node(), FP32MODE), error::INTERNAL, "Failed to convert input with index 0 to a TRT_TensorOrWeights"); } diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index a6f954391d..48e8a6fc51 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -95,6 +95,9 @@ inline tensorflow::Status ConvertDType(tensorflow::DataType tf_dtype, case tensorflow::DataType::DT_INT8: *trt_dtype = nvinfer1::DataType::kINT8; break; + case tensorflow::DataType::DT_QINT8: + *trt_dtype = nvinfer1::DataType::kINT8; + break; case tensorflow::DataType::DT_HALF: *trt_dtype = nvinfer1::DataType::kHALF; break; @@ -634,6 +637,16 @@ void ReorderCKtoKC(const TRT_ShapedWeights& iweights, ostrides); break; } + case tensorflow::DataType::DT_INT8: + case tensorflow::DataType::DT_UINT8: + case tensorflow::DataType::DT_QINT8: + case tensorflow::DataType::DT_QUINT8: { + Reorder2({k, c}, static_cast(iweights.GetValues()), + istrides, + static_cast(const_cast(oweights->GetValues())), + ostrides); + break; + } default: LOG(FATAL) << "Unsupported type in reorder expected fp32 or fp16 but got " << DataTypeString(iweights.type_); @@ -812,13 +825,18 @@ Status Converter::ConvertNode(const NodeDef& node_def) { TRT_TensorOrWeights& output = outputs[i]; string output_name = node_def.name(); if (i != 0) output_name = StrCat(output_name, ":", i); - // We need to check the name before setting it. For Identity op where the - // output is the input, if its input is one of the engine input, setting - // the name here will overwrite engine input bindings which will cause - // runtime error. + // We need to check the name before setting it. If the input is one of the + // engine input, setting the name here will overwrite engine input + // bindings which will cause runtime error. if (output.is_tensor()) { const char* tensor_name = output.tensor()->getName(); - if (tensor_name == nullptr || std::strlen(tensor_name) == 0) { + if (!tensorflow::str_util::StartsWith(tensor_name, kInputPHName)) { + // TRT initializes tensor names as "(Unnamed ITensor* N)". We rename + // them to match their corresponding TensorFlow name. + // Note: ITensors that we create internally within TF-TRT which are + // not inputs or outputs of a node will not be renamed. This is a + // potential cause of confusion if an error message or warning + // mentions the unnamed tensor. output.tensor()->setName(output_name.c_str()); } } @@ -930,6 +948,7 @@ Status Converter::TransposeTensor(nvinfer1::ITensor* input_tensor, nvinfer1::IShuffleLayer* layer = this->network()->addShuffle(*input_tensor); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Transpose"); + MarkQuantizationRangesAsInferrable(input_tensor, layer->getOutput(0)); nvinfer1::Permutation permutation; for (int32_t i = 0; i < dims.nbDims; ++i) { @@ -976,6 +995,8 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, *const_cast(input.tensor())); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Reshape"); layer->setReshapeDimensions(dims); + MarkQuantizationRangesAsInferrable( + const_cast(input.tensor()), layer->getOutput(0)); *tensor = layer->getOutput(0); } } else { @@ -987,6 +1008,95 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, return tensorflow::Status::OK(); } +void Converter::MarkQuantizationRangesAsInferrable(nvinfer1::ITensor* input, + nvinfer1::ITensor* output) { + quantization_infer_.push_back({input, output}); + quantization_infer_.push_back({output, input}); +} + +void Converter::ProvideQuantizationRange(nvinfer1::ITensor* tensor, + float min_range, float max_range) { + float symmetric_range = std::max(std::abs(min_range), std::abs(max_range)); + quantization_ranges_[tensor] = symmetric_range; +} + +void Converter::ApplyQuantizationRanges(bool warn_missing_ranges) { + // Infer ranges across marked ops + PropagateQuantizationRanges(); + // Get all tensors from network + std::set all_tensors; + std::set tensors_missing_ranges; + for (int i = 0; i < this->network()->getNbLayers(); i++) { + nvinfer1::ILayer* layer = this->network()->getLayer(i); + for (int j = 0; j < layer->getNbInputs(); j++) + all_tensors.insert(layer->getInput(j)); + for (int j = 0; j < layer->getNbOutputs(); j++) + all_tensors.insert(layer->getOutput(j)); + } + // Apply ranges + for (auto tensor : all_tensors) { + auto it = quantization_ranges_.find(tensor); + if (it != quantization_ranges_.end()) { + float range = it->second; + VLOG(1) << "Setting range for: " << tensor->getName() << ": " << range; +#if NV_TENSORRT_MAJOR >= 5 + tensor->setDynamicRange(-range, range); +#endif + } else { + tensors_missing_ranges.insert(tensor); + } + } + // Warn user about tensors that are missing ranges. If TRT fuses some layers + // then these tensors may not actually be required, which is why this is + // just a warning. If we are still missing ranges even after fusion, + // Builder::buildCudaEngine() will return nullptr and we will catch the + // error at that point. + if (warn_missing_ranges) { + for (auto tensor : tensors_missing_ranges) { + // Note: there may be some warnings for "(Unnamed ITensor* N)". These + // are tensors which are created internally by TF-TRT. The ranges for + // these unnamed ITensors are always inferred from user provided ranges, + // thus there will also be a warning for the range(s) the user missed. + LOG(WARNING) << "Quantization range was not found for " + << tensor->getName() << ". " + << "This might be okay if TensorRT does not need the range" + << "(e.g. due to node fusion)."; + } + } +} + +void Converter::PropagateQuantizationRanges() { + // Propagate ranges across edges in quantization_infer_ until no new + // information is added. + // Note: this function modifies quantization_infer_, it might be better to + // modify a copy instead if we for some reason need quantization_infer_ + // later. + bool information_added = true; + while (information_added) { + information_added = false; + for (auto it = quantization_infer_.begin(); + it != quantization_infer_.end();) { + auto input_tensor_range = quantization_ranges_.find(it->first); + auto output_tensor_range = quantization_ranges_.find(it->second); + if (input_tensor_range != quantization_ranges_.end() && + output_tensor_range == quantization_ranges_.end()) { + // Input has range but output doesn't: copy range + quantization_ranges_[it->second] = input_tensor_range->second; + information_added = true; + VLOG(1) << "Copy quantization range: " + << it->first->getName() << " -> " << it->second->getName(); + } + // We can remove edges when the output range is known + if (quantization_ranges_.find(it->second) != + quantization_ranges_.end()) { + it = quantization_infer_.erase(it); + } else { + ++it; + } + } + } +} + Status Converter::GetInputs(const tensorflow::NodeDef& node_def, std::vector* inputs) const { for (auto const& input_name : node_def.input()) { @@ -1788,6 +1898,8 @@ tensorflow::Status ConvertPool(OpConverterParams* params) { nvinfer1::DimsHW(padding[0].first, padding[1].first), nvinfer1::DimsHW(padding[0].second, padding[1].second)); TFTRT_RETURN_ERROR_IF_NULLPTR(pad_layer, node_def.name()); + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), pad_layer->getOutput(0)); padding = {{0, 0}, {0, 0}}; tensor = pad_layer->getOutput(0); } @@ -1795,6 +1907,11 @@ tensorflow::Status ConvertPool(OpConverterParams* params) { nvinfer1::IPoolingLayer* layer = params->converter->network()->addPooling( *const_cast(tensor), type, ksize); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); + // TODO(tmorris): Average pooling may not be entirely safe to infer + // quantization range through (at least forwards - backwards should be fine). + // Max pooling is okay. + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), layer->getOutput(0)); layer->setStride(stride); layer->setPadding({padding[0].first, padding[1].first}); @@ -1823,6 +1940,101 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { return tensorflow::Status::OK(); } +tensorflow::Status ConvertQuantize(OpConverterParams* params) { + const auto& inputs = params->inputs; + const auto& node_def = params->node_def; + if (inputs.at(0).is_weights()) { + params->outputs->push_back(inputs.at(0)); + return tensorflow::Status::OK(); + } + nvinfer1::ITensor* tensor = const_cast(inputs.at(0).tensor()); + // Min + TRT_ShapedWeights weights_min = inputs.at(1).weights(); + auto weights_min_ptr = static_cast(const_cast(weights_min.GetValues())); + float min_range = weights_min_ptr[0]; + // Max + TRT_ShapedWeights weights_max = inputs.at(2).weights(); + auto weights_max_ptr = static_cast(const_cast(weights_max.GetValues())); + float max_range = weights_max_ptr[0]; + // Store ranges for tensor + params->converter->ProvideQuantizationRange(tensor, min_range, max_range); + // Sometimes, TRT may not quantize a tensor, either because it chooses to + // execute a higher precision kernel or because of op fusion. In these cases, + // accuracy will suffer if the model was trained to expect quantization at + // that tensor. We should consider adding a clip(tensor, min_range, max_range) + // operation here to ensure that any arbitrarily placed quantize node will + // execute as expected. However, this will negatively affect performance. If + // users train their models in a way which models inference as close as + // possible (i.e. not quantizing in place where fusion will occur), then there + // is no problem with the current implementation. + params->outputs->push_back(inputs.at(0)); + return tensorflow::Status::OK(); +} + +// TODO(pdavoodi): we should update relu6 implementation once TensorRT supports +// Relu6 natively. +tensorflow::Status ConvertRelu6(OpConverterParams* params) { + const auto& inputs = params->inputs; + const auto& node_def = params->node_def; + // *************************************************************************** + // TensorRT does not implement Relu6 natively. This function converts Relu6 op + // to available TensorRT ops: Relu6(x) = min(Relu(x), 6) + // *************************************************************************** + + // Input Tensor + const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); + + // Relu operation i.e. Relu(x) = max(0, x) + nvinfer1::IActivationLayer* relu_layer = + params->converter->network()->addActivation( + *const_cast(tensor), + nvinfer1::ActivationType::kRELU); + TFTRT_RETURN_ERROR_IF_NULLPTR(relu_layer, node_def.name()); + + // Large range of relu is problematic during quantization in INT8 precision mode. + // Setting dynamic range of relu = [0.f, 6.0f] helps with quantization. + // TRT only uses dynamic ranges in INT8 precision mode, + // and this does not affect the FP32 path. + params->converter->ProvideQuantizationRange( + relu_layer->getOutput(0), 0.0f, 6.0f); + + // Create a constant layer to store the floating point weight i.e. 6.0f This + // tensor will be broadcasted uniformly during elementwise `min` operation. + // The constant has to have the same rank as the input in order for TRT to + // broadcast + nvinfer1::Dims dims; + dims.nbDims = relu_layer->getOutput(0)->getDimensions().nbDims; + for (int i = 0; i < dims.nbDims; i++) + dims.d[i] = 1; + TRT_ShapedWeights weights = params->weight_store->GetTempWeights( + tensorflow::DataType::DT_FLOAT, dims); + auto weights_ptr = static_cast(const_cast( + weights.GetValues())); + weights_ptr[0] = 6.f; + nvinfer1::IConstantLayer* const6_layer = + params->converter->network()->addConstant(dims, weights.GetTrtWeights()); + TFTRT_RETURN_ERROR_IF_NULLPTR(const6_layer, node_def.name()); + params->converter->ProvideQuantizationRange( + const6_layer->getOutput(0), 0.0f, 6.0f); + + // ElementWise Min Operation + // Min op is a nop for INT8 execution path, as the input tensor + // to this layer will only have values in range [0.f, 6.0f]. + const nvinfer1::ITensor* tensor_l = relu_layer->getOutput(0); + const nvinfer1::ITensor* tensor_r = const6_layer->getOutput(0); + nvinfer1::IElementWiseLayer* relu6_layer = + params->converter->network()->addElementWise( + *const_cast(tensor_l), + *const_cast(tensor_r), + nvinfer1::ElementWiseOperation::kMIN); + TFTRT_RETURN_ERROR_IF_NULLPTR(relu6_layer, node_def.name()); + nvinfer1::ITensor* output_tensor = relu6_layer->getOutput(0); + params->converter->ProvideQuantizationRange(output_tensor, 0.0f, 6.0f); + + params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); + return tensorflow::Status::OK(); +} + tensorflow::Status ConvertScale(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; @@ -1872,6 +2084,9 @@ tensorflow::Status ConvertScale(OpConverterParams* params) { params->converter->network()->addShuffle( *const_cast(tensor)); TFTRT_RETURN_ERROR_IF_NULLPTR(shuffle_layer, node_def.name()); + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), shuffle_layer->getOutput(0)); + nvinfer1::Dims reshape_dims; reshape_dims.nbDims = 3; reshape_dims.d[0] = 0; // 0 copy from the input @@ -1911,6 +2126,8 @@ tensorflow::Status ConvertScale(OpConverterParams* params) { if (channel_index != 0) { shuffle_layer->setSecondTranspose(permutation); } + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(output_tensor), shuffle_layer->getOutput(0)); output_tensor = shuffle_layer->getOutput(0); } @@ -2069,6 +2286,9 @@ tensorflow::Status ConvertConst(OpConverterParams* params) { } tensorflow::Status ConvertIdentity(OpConverterParams* params) { + // TODO(tmorris): TRT's Identity layer does not get optimized away as of TRT + // 5.0, however once we know that it does it would be nice to use that + // instead. params->outputs->push_back(params->inputs.at(0)); return tensorflow::Status::OK(); } @@ -2691,6 +2911,8 @@ tensorflow::Status ConvertSoftmax(OpConverterParams* params) { layer->setAxes(1 << (nbDims - 1)); nvinfer1::ITensor* output_tensor = layer->getOutput(0); + // Quantization range for SoftMax is always (0, 1) + params->converter->ProvideQuantizationRange(output_tensor, 0.0f, 1.0f); params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); return tensorflow::Status::OK(); } @@ -2787,6 +3009,14 @@ void Converter::RegisterOpConverters() { op_registry_["MatMul"] = ConvertMatMul; op_registry_["BatchMatMul"] = ConvertBatchMatMul; op_registry_["TopKV2"] = ConvertTopK; + op_registry_["Relu6"] = ConvertRelu6; +# if NV_TENSORRT_MAJOR >= 5 + op_registry_["QuantizeV2"] = ConvertQuantize; + op_registry_["Dequantize"] = ConvertQuantize; + op_registry_["QuantizeAndDequantizeV2"] = ConvertQuantize; + op_registry_["QuantizeAndDequantizeV3"] = ConvertQuantize; + op_registry_["FakeQuantWithMinMaxVars"] = ConvertQuantize; +#endif plugin_converter_ = ConvertPlugin; } @@ -2798,6 +3028,7 @@ tensorflow::Status ConvertGraphDefToEngine( Logger* logger, nvinfer1::IGpuAllocator* allocator, TRTInt8Calibrator* calibrator, TrtUniquePtrType* engine, + bool use_calibration, bool* convert_successfully) { engine->reset(); if (convert_successfully) *convert_successfully = false; @@ -2812,7 +3043,11 @@ tensorflow::Status ConvertGraphDefToEngine( builder->setHalf2Mode(true); } else if (precision_mode == INT8MODE) { builder->setInt8Mode(true); - builder->setInt8Calibrator(calibrator); + if (use_calibration) { + builder->setInt8Calibrator(calibrator); + } else { + builder->setInt8Calibrator(nullptr); + } } // Create the network. @@ -2881,6 +3116,11 @@ tensorflow::Status ConvertGraphDefToEngine( TF_RETURN_IF_ERROR(converter.RenameAndMarkOutputTensors(output_tensors)); if (convert_successfully) *convert_successfully = true; + // Apply user provided quantization ranges to tensors + const bool warn_missing_ranges = (precision_mode == INT8MODE && + !use_calibration); + converter.ApplyQuantizationRanges(warn_missing_ranges); + // Build the engine. VLOG(1) << "Starting engine creation"; engine->reset(builder->buildCudaEngine(*converter.network())); diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.h b/tensorflow/contrib/tensorrt/convert/convert_nodes.h index 5cc28b33e7..2daca99ed9 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.h +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.h @@ -92,7 +92,8 @@ struct EngineInfo { EngineInfo() : engine_type(EngineType::TRTStatic), max_workspace_size_bytes(0), - precision_mode(FP32MODE) {} + precision_mode(FP32MODE), + use_calibration(true) {} string engine_name; string device; @@ -109,6 +110,7 @@ struct EngineInfo { int maximum_cached_engines; std::vector cached_engine_batches; int precision_mode; + bool use_calibration; }; // Constructs a graphdef from the segment in the given graph. Adds placeholder @@ -146,6 +148,7 @@ tensorflow::Status ConvertGraphDefToEngine( Logger* logger, nvinfer1::IGpuAllocator* allocator, TRTInt8Calibrator* calibrator, TrtUniquePtrType* engine, + bool use_calibration, bool* convert_successfully); // Helper class for the segmenter to determine whether an output edge from the @@ -425,6 +428,22 @@ class Converter { // Is the converter operating in fp16 mode? bool is_fp16() const { return is_fp16_; } + // This should be called on the inputs and outputs of any layer we create + // where we know that the quantization range does not change during that + // operation. (e.g. Reshape, Transpose, Identity, MaxPool). + void MarkQuantizationRangesAsInferrable(nvinfer1::ITensor* input, + nvinfer1::ITensor* output); + + // This function should be called when we know the quantization range of a + // tensor, either from a quantize/dequantize node or when the output is a + // fixed range (e.g. SoftMax, Relu6, Sigmoid). + void ProvideQuantizationRange(nvinfer1::ITensor* tensor, + float min_range, float max_range); + + // Should be called when full TRT network has been constructed and before + // building the engine. + void ApplyQuantizationRanges(bool warn_missing_ranges); + // Below are helper methods for op converters to add different layers to the // TRT network. @@ -457,6 +476,8 @@ class Converter { void RegisterOpConverters(); + void PropagateQuantizationRanges(); + // Registered op converters by op type. std::unordered_map op_registry_; @@ -472,6 +493,22 @@ class Converter { // Store the weights added during construction of trt_network_. TrtWeightStore weight_store_; + // During conversion, this table is populated with quantization ranges per + // tensor. ApplyQuantizationRanges() will use this table to set the TensorRT + // quantization ranges. Since TRT only supports symmetric ranges, we will + // store the range as a single float = max(abs(min_range), abs(max_range)). + // Range refers to the floating point values, e.g. min_range = 0.0f, max_range + // = 6.0f for Relu6. + std::unordered_map quantization_ranges_; + + // Edges where quantization ranges can be inferred (copied) across ops - from + // first tensor to second tensor. PropagateQuantizationRanges() will propagate + // known ranges from quantization_ranges_ across these edges, adding the new + // ranges to quantization_ranges_ so that they can be applied in + // ApplyQuantizationRanges(). + std::vector> + quantization_infer_; + const bool is_fp16_; // Batch size of inputs to trt_network_ added by AddInputTensor(). During diff --git a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc index b30d94b028..4ac7e21d34 100644 --- a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc +++ b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc @@ -67,6 +67,9 @@ tensorflow::Status TRTOptimizationPass::Init( TF_RETURN_IF_ERROR(GetPrecisionMode( Uppercase(params.at("precision_mode").s()), &precision_mode_)); } + if (params.count("use_calibration")) { + use_calibration_ = params.at("use_calibration").b(); + } return tensorflow::Status::OK(); } @@ -222,6 +225,12 @@ tensorflow::Status TRTOptimizationPass::Optimize( TF_RETURN_IF_ERROR(static_graph_properties.InferStatically(true)); tensorflow::tensorrt::convert::ConversionParams cp; + if (use_calibration_ && precision_mode_ != INT8MODE) { + LOG(ERROR) << "Calibration with FP32 or FP16 is not implemented. " + << "Falling back to use_calibration = False."; + use_calibration_ = false; + } + std::vector nodes_to_preserve; for (const auto& n : item.NodesToPreserve()) { auto tokens = str_util::Split(n, ":"); @@ -250,6 +259,7 @@ tensorflow::Status TRTOptimizationPass::Optimize( cp.is_dyn_op = is_dynamic_op_; cp.cached_engine_batches = batches_; cp.max_cached_engines = max_cached_batches_; + cp.use_calibration = use_calibration_; auto status = tensorflow::tensorrt::convert::ConvertAfterShapes(cp); VLOG(1) << "Returning from " << name_; return status; diff --git a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h index 71b51d1368..3e8dc0978e 100644 --- a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h +++ b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h @@ -38,7 +38,8 @@ class TRTOptimizationPass : public tensorflow::grappler::CustomGraphOptimizer { maximum_batch_size_(-1), is_dynamic_op_(false), max_cached_batches_(1), - max_workspace_size_bytes_(256LL << 20) { + max_workspace_size_bytes_(256LL << 20), + use_calibration_(true) { VLOG(1) << "Constructing " << name_; } @@ -67,6 +68,7 @@ class TRTOptimizationPass : public tensorflow::grappler::CustomGraphOptimizer { std::vector batches_; int max_cached_batches_; int64_t max_workspace_size_bytes_; + bool use_calibration_; }; } // namespace convert diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc index 019446813a..780343d662 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc @@ -124,8 +124,10 @@ TRTEngineOp::TRTEngineOp(OpKernelConstruction* context) OP_REQUIRES_OK(context, context->GetAttr("segment_funcdef_name", &funcdef_name_)); OP_REQUIRES_OK(context, GetPrecisionMode(precision_string, &precision_mode_)); - calibration_mode_ = - (precision_mode_ == INT8MODE && calibration_data.size() == 0); + OP_REQUIRES_OK(context, + context->GetAttr("use_calibration", &use_calibration_)); + calibration_mode_ = (use_calibration_ && + (precision_mode_ == INT8MODE && calibration_data.size() == 0)); if (calibration_data.size()) { calibrator_.reset(new TRTInt8Calibrator(calibration_data)); calibration_data.resize(0); @@ -308,7 +310,7 @@ bool TRTEngineOp::ExecuteTrtEngine( std::vector buffers(num_binding); for (int i = 0; i < ctx->num_inputs(); i++) { const string input_name = StrCat(kInputPHName, i); - const size_t binding_index = + const int binding_index = trt_engine_ptr->getBindingIndex(input_name.c_str()); if (binding_index == -1) { LOG(ERROR) << "Input node not found, at " << input_name; @@ -345,7 +347,7 @@ bool TRTEngineOp::ExecuteTrtEngine( for (int i = 0; i < ctx->num_outputs(); i++) { // Create an output tensor const string output_name = StrCat(kOutputPHName, i); - const size_t binding_index = + const int binding_index = trt_engine_ptr->getBindingIndex(output_name.c_str()); Tensor* output_tensor = nullptr; @@ -497,7 +499,8 @@ TRTEngineOp::EngineCtxPair& TRTEngineOp::GetEngine(int batch_size, // means calibration_mode_ is true and this path won't get executed. auto status = convert::ConvertGraphDefToEngine( segment_graph_, precision_mode_, batch_size, workspace_size_, shapes, - &logger, allocator, calibrator_.get(), &engine, &convert_successfully); + &logger, allocator, calibrator_.get(), &engine, + use_calibration_, &convert_successfully); if (!status.ok()) { if (convert_successfully) { // This means it fail to build the engine even when the network is built @@ -586,6 +589,7 @@ tensorflow::Status TRTEngineOp::AllocateCalibrationResources( *segment_graph, INT8MODE, cres->calibrator_->getBatchSize(), workspace_size_bytes, shapes, &cres->logger_, cres->allocator_.get(), cres->calibrator_.get(), &cres->engine_, + /*use_calibration=*/true, /*convert_successfully=*/nullptr); if (!s.ok()) { LOG(ERROR) << "Calibration failed: " << s; diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h index 8fe0675891..b545f497f3 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h @@ -130,6 +130,10 @@ class TRTEngineOp : public AsyncOpKernel { // The finalized calibrator for inference. std::unique_ptr calibrator_; + + // If true, create calibration graph for INT8 mode. Otherwise, we are using + // user-provided quantization ranges. + bool use_calibration_; }; } // namespace tensorrt diff --git a/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc b/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc index e0c7b62723..ce04e5806e 100644 --- a/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc @@ -39,8 +39,9 @@ REGISTER_OP("TRTEngineOp") .Attr("cached_engine_batches: list(int) = []") .Attr("max_cached_engines_count: int = 1") .Attr("workspace_size_bytes: int") - .Attr("precision_mode: {'FP32', 'FP16', 'INT8', 'INT8CALIB'}") + .Attr("precision_mode: {'FP32', 'FP16', 'INT8'}") .Attr("calibration_data: string = ''") + .Attr("use_calibration: bool = true") .Input("in_tensor: InT") .Output("out_tensor: OutT"); // TODO(jie): TF requires concrete output shape for concrete input shapes. diff --git a/tensorflow/contrib/tensorrt/python/trt_convert.py b/tensorflow/contrib/tensorrt/python/trt_convert.py index bb81fbf93f..98a647dc57 100644 --- a/tensorflow/contrib/tensorrt/python/trt_convert.py +++ b/tensorflow/contrib/tensorrt/python/trt_convert.py @@ -70,7 +70,8 @@ def tensorrt_rewriter_config(rewriter_config=None, minimum_segment_size=3, is_dynamic_op=False, maximum_cached_engines=1, - cached_engine_batch_sizes=None): + cached_engine_batch_sizes=None, + use_calibration=True): """Returns a RewriterConfig proto for TRT transformation. Args: @@ -95,6 +96,12 @@ def tensorrt_rewriter_config(rewriter_config=None, use this list to determine the batch sizes of the cached engines, instead of making the decision on the fly. This is useful when we know the most common batch size(s) the application is going to generate. + use_calibration: this argument is ignored if precision_mode is not INT8. + if set to True, a calibration graph will be created to calibrate the + missing ranges. The calibration graph must be converted to an inference + graph using calib_graph_to_infer_graph() after running calibration. + if set to False, quantization ranges will be expected for every tensor in + the graph. If a range is missing, an error will occur. Returns: A RewriterConfig proto which sets a TensorRTOptimizer to run Grappler. @@ -138,6 +145,7 @@ def tensorrt_rewriter_config(rewriter_config=None, "maximum_cached_engines items.") optimizer.parameter_map["cached_engine_batches"].list.i.extend( cached_engine_batch_sizes) + optimizer.parameter_map["use_calibration"].b = use_calibration return rewriter_config @@ -151,6 +159,7 @@ def create_inference_graph(input_graph_def, maximum_cached_engines=1, cached_engine_batch_sizes=None, rewriter_config=None, + use_calibration=True, input_saved_model_dir=None, input_saved_model_tags=None, output_saved_model_dir=None, @@ -184,6 +193,12 @@ def create_inference_graph(input_graph_def, common batch size(s) the application is going to generate. rewriter_config: a RewriterConfig proto to append the TensorRTOptimizer to. If None, it will create one with default settings. + use_calibration: this argument is ignored if precision_mode is not INT8. + if set to True, a calibration graph will be created to calibrate the + missing ranges. The calibration graph must be converted to an inference + graph using calib_graph_to_infer_graph() after running calibration. + if set to False, quantization ranges will be expected for every tensor in + the graph. If a range is missing, an error will occur. input_saved_model_dir: the directory to load the SavedModel which contains the input graph to transforms. Used only when input_graph_def is None. input_saved_model_tags: list of tags to load the SavedModel. @@ -326,7 +341,7 @@ def create_inference_graph(input_graph_def, rewriter_config = tensorrt_rewriter_config( rewriter_config, max_batch_size, max_workspace_size_bytes, precision_mode, minimum_segment_size, is_dynamic_op, maximum_cached_engines, - cached_engine_batch_sizes) + cached_engine_batch_sizes, use_calibration) # Run Grappler. transformed_graph_def = tf_optimizer.OptimizeGraph( diff --git a/tensorflow/contrib/tensorrt/segment/segment.cc b/tensorflow/contrib/tensorrt/segment/segment.cc index 4f64b7a952..80acab9ea3 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.cc +++ b/tensorflow/contrib/tensorrt/segment/segment.cc @@ -389,7 +389,7 @@ void ContractEdge(SimpleEdge* edge, SimpleGraph* graph, tensorflow::Status SegmentGraph( const tensorflow::Graph* tf_graph, - const std::function& candidate_fn, + const std::function& candidate_fn, const std::function& input_candidate_fn, const std::function& output_candidate_fn, const SegmentOptions& options, SegmentNodesVector* segments) { @@ -414,7 +414,7 @@ tensorflow::Status SegmentGraph( << " (excluded by segmenter option)."; node = nullptr; } else { - const Status status = candidate_fn(node->tf_node()); + const Status status = candidate_fn(node->tf_node(), options.precision_mode); if (!status.ok()) { VLOG(1) << "Not a TF-TRT candidate: " << node->name() << ": " << status; node = nullptr; diff --git a/tensorflow/contrib/tensorrt/segment/segment.h b/tensorflow/contrib/tensorrt/segment/segment.h index b9693aad1b..802daec6a6 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.h +++ b/tensorflow/contrib/tensorrt/segment/segment.h @@ -38,6 +38,8 @@ struct SegmentOptions { // Segment must contain at least this many nodes. int minimum_segment_size = 2; std::set exclude_node_list; + // Quantization nodes are only included for quantized precisions + int precision_mode; }; // Get the subgraphs of a graph that can be handled by TensorRT. @@ -51,7 +53,7 @@ struct SegmentOptions { // @return the status. tensorflow::Status SegmentGraph( const tensorflow::Graph* tf_graph, - const std::function& candidate_fn, + const std::function& candidate_fn, const std::function& input_candidate_fn, const std::function& output_candidate_fn, const SegmentOptions& options, SegmentNodesVector* segments); diff --git a/tensorflow/contrib/tensorrt/test/base_test.py b/tensorflow/contrib/tensorrt/test/base_test.py index 18096e0ff1..cbff661f99 100644 --- a/tensorflow/contrib/tensorrt/test/base_test.py +++ b/tensorflow/contrib/tensorrt/test/base_test.py @@ -197,7 +197,9 @@ class PartiallyConvertedTestA(trt_test.TfTrtIntegrationTestBase): """Whether to run the test.""" # Disable the test in fp16 mode since multiple matmul and add ops together # can cause overflow. - return run_params.precision_mode != "FP16" + return ((run_params.precision_mode != "FP16") and + not (trt_test.IsQuantizationMode(run_params.precision_mode) and + not run_params.use_calibration)) class PartiallyConvertedTestB(PartiallyConvertedTestA): diff --git a/tensorflow/contrib/tensorrt/test/quantization_test.py b/tensorflow/contrib/tensorrt/test/quantization_test.py new file mode 100644 index 0000000000..a6934bf490 --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/quantization_test.py @@ -0,0 +1,164 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Model script to test TF-TensorRT integration.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.contrib.tensorrt.test import tf_trt_integration_test_base as trt_test +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import nn +from tensorflow.python.ops import nn_impl +from tensorflow.python.ops import nn_ops +from tensorflow.python.ops import gen_array_ops +from tensorflow.python.platform import test + + +def build_graph(input_name, input_dims, output_name, + add_quantization_nodes=False, dtype=dtypes.float32): + def quantize(x, r): + if add_quantization_nodes: + x = gen_array_ops.fake_quant_with_min_max_vars(x, -r, r) + return x + g = ops.Graph() + with g.as_default(): + x = array_ops.placeholder( + dtype=dtype, shape=[None] + input_dims[1:], name=input_name) + x = quantize(x, 100) + filt1 = constant_op.constant( + 0.3, shape=(3, 3, 1, 32), dtype=dtype, name='filt1') + x = nn.conv2d(x, filt1, strides=[1, 1, 1, 1], padding='VALID') + bias1 = constant_op.constant(0.3, shape=(32,), name="bias1", dtype=dtype) + x = nn.bias_add(x, bias1) + + x = quantize(x, 6) + x = nn.relu6(x) + filt2 = constant_op.constant( + 0.3, shape=(3, 3, 32, 64), dtype=dtype, name='filt2') + x = nn.conv2d(x, filt2, strides=[1, 1, 1, 1], padding='VALID') + bias2 = constant_op.constant(0.3, shape=(64,), name="bias2", dtype=dtype) + x = nn.bias_add(x, bias2) + + x = quantize(x, 6) + x = nn.relu6(x) + x = math_ops.reduce_mean(x, [1, 2]) + x = quantize(x, 6) + # FC1 + fc_w1 = constant_op.constant( + 0.3, shape=(64, 512), dtype=dtype, name='fc_w1') + x = math_ops.matmul(x, fc_w1) + x = quantize(x, 6) + fc_b1 = constant_op.constant( + 0.3, shape=(512,), dtype=dtype, name='fc_b1') + x = nn.bias_add(x, fc_b1) + x = quantize(x, 6) + x = nn.relu6(x) + # FC2 + fc_w2 = constant_op.constant( + 0.3, shape=(512, 10), dtype=dtype, name='fc_w2') + x = math_ops.matmul(x, fc_w2) + x = quantize(x, 25) + fc_b2 = constant_op.constant( + 0.3, shape=(10,), dtype=dtype, name='fc_b2') + x = nn.bias_add(x, fc_b2) + x = quantize(x, 25) + x = array_ops.identity(x, name=output_name) + return g + +class QuantizationMissingAllRangesTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Create a graph containing single segment with no quantization ranges.""" + input_name = "input" + input_dims = [100, 28, 28, 1] + output_name = "output" + g = build_graph(input_name, input_dims, output_name, + add_quantization_nodes=False) + return trt_test.TfTrtIntegrationTestParams( + gdef=g.as_graph_def(), + input_names=[input_name], + input_dims=[input_dims], + output_names=[output_name], + expected_output_dims=[(100, 10)]) + + def ShouldRunTest(self, run_params): + return (run_params.precision_mode == "INT8" and + not run_params.use_optimizer and + not run_params.dynamic_engine) + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + if run_params.use_calibration: + return ["my_trt_op_0"] + return [] + +class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Create a graph containing single segment with no quantization ranges.""" + input_name = "input" + input_dims = [100, 28, 28, 1] + output_name = "output" + g = build_graph(input_name, input_dims, output_name, + add_quantization_nodes=True) + return trt_test.TfTrtIntegrationTestParams( + gdef=g.as_graph_def(), + input_names=[input_name], + input_dims=[input_dims], + output_names=[output_name], + expected_output_dims=[(100, 10)]) + + def ShouldRunTest(self, run_params): + return (run_params.precision_mode == "INT8" and + not run_params.use_optimizer) + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + return ["my_trt_op_0"] + +class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Create a graph containing single segment with no quantization ranges.""" + input_name = "input" + input_dims = [100, 28, 28, 1] + output_name = "output" + g = build_graph(input_name, input_dims, output_name, + add_quantization_nodes=True) + return trt_test.TfTrtIntegrationTestParams( + gdef=g.as_graph_def(), + input_names=[input_name], + input_dims=[input_dims], + output_names=[output_name], + expected_output_dims=[(100, 10)]) + + def ShouldRunTest(self, run_params): + return (run_params.precision_mode == "FP32" or + run_params.precision_mode == "FP16") + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + return ["my_trt_op_0", "my_trt_op_1", "my_trt_op_2", "my_trt_op_3", + "my_trt_op_4", "my_trt_op_5", "my_trt_op_6"] + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py index a725d0651c..a6f51640b7 100644 --- a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py +++ b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py @@ -42,14 +42,15 @@ TfTrtIntegrationTestParams = namedtuple("TfTrtIntegrationTestParams", [ "gdef", "input_names", "input_dims", "output_names", "expected_output_dims" ]) -RunParams = namedtuple( - "RunParams", - ["use_optimizer", "precision_mode", "dynamic_engine", "test_name"]) +RunParams = namedtuple("RunParams", [ + "use_optimizer", "precision_mode", "dynamic_engine", "test_name", + "use_calibration" +]) ConversionParams = namedtuple("ConversionParams", [ "max_batch_size", "max_workspace_size_bytes", "precision_mode", "minimum_segment_size", "is_dynamic_op", "maximum_cached_engines", - "cached_engine_batch_sizes", "rewriter_config" + "cached_engine_batch_sizes", "rewriter_config", "use_calibration" ]) PRECISION_MODES = ["FP32", "FP16", "INT8"] @@ -139,11 +140,15 @@ class TfTrtIntegrationTestBase(test_util.TensorFlowTestCase): is_dynamic_op=run_params.dynamic_engine, maximum_cached_engines=1, cached_engine_batch_sizes=None, - rewriter_config=None) + rewriter_config=None, + use_calibration=run_params.use_calibration) def ShouldRunTest(self, run_params): """Whether to run the test.""" - return True + # This setting combination requires quantization nodes to be present in + # order to build the engine. + return not (IsQuantizationMode(run_params.precision_mode) and + not run_params.use_calibration) def VerifyRunForEngine(self, engine_name, graph_state, expect_run=True): """Verify the state of a particular engine after sess.run().""" @@ -209,7 +214,8 @@ class TfTrtIntegrationTestBase(test_util.TensorFlowTestCase): conversion_params.minimum_segment_size, conversion_params.is_dynamic_op, conversion_params.maximum_cached_engines, - conversion_params.cached_engine_batch_sizes) + conversion_params.cached_engine_batch_sizes, + conversion_params.use_calibration) graph_options = config_pb2.GraphOptions(rewrite_options=rewriter_cfg) else: @@ -301,7 +307,8 @@ class TfTrtIntegrationTestBase(test_util.TensorFlowTestCase): is_dynamic_op=conversion_params.is_dynamic_op, maximum_cached_engines=conversion_params.maximum_cached_engines, cached_engine_batch_sizes=conversion_params.cached_engine_batch_sizes, - rewriter_config=conversion_params.rewriter_config) + rewriter_config=conversion_params.rewriter_config, + use_calibration=conversion_params.use_calibration) def _WriteGraph(self, run_params, gdef, graph_state): if graph_state == GraphState.ORIGINAL: @@ -400,9 +407,13 @@ class TfTrtIntegrationTestBase(test_util.TensorFlowTestCase): is_dynamic_engine = not node.attr["static_engine"].b self.assertEqual(run_params.dynamic_engine, is_dynamic_engine, node.name) + self.assertEqual(node.attr["use_calibration"].b, + run_params.use_calibration, + node.name) has_calibration_data = len(node.attr["calibration_data"].s) if (IsQuantizationMode(run_params.precision_mode) and + run_params.use_calibration and graph_state == GraphState.INFERENCE): self.assertTrue(has_calibration_data, node.name) else: @@ -449,7 +460,8 @@ class TfTrtIntegrationTestBase(test_util.TensorFlowTestCase): config_no_trt, GraphState.ORIGINAL) # Run calibration if necessary. - if IsQuantizationMode(run_params.precision_mode): + if (IsQuantizationMode(run_params.precision_mode) and + run_params.use_calibration): calib_config = self._GetConfigProto(run_params, GraphState.CALIBRATE) logging.info("Running calibration graph, config:\n%s", str(calib_config)) @@ -519,18 +531,24 @@ def _AddTests(test_class): use_optimizer_options = [False, True] dynamic_engine_options = [False, True] - for (use_optimizer, precision_mode, dynamic_engine) in itertools.product( - use_optimizer_options, PRECISION_MODES, dynamic_engine_options): + use_calibration_options = [False, True] + opts = itertools.product(use_optimizer_options, PRECISION_MODES, + dynamic_engine_options, use_calibration_options) + for (use_optimizer, precision_mode, dynamic_engine, use_calibration) in opts: if IsQuantizationMode(precision_mode): if use_optimizer: # TODO(aaroey): if use_optimizer is True we need to get the inference # graphdef using custom python wrapper class, which is not currently # supported yet. continue - if not dynamic_engine: + if not dynamic_engine and use_calibration: # TODO(aaroey): construction of static calibration engine is not # supported yet. continue + else: + if use_calibration: + # Don't calibrate in FP32 or FP16 mode + continue conversion = "OptimizerConversion" if use_optimizer else "ToolConversion" engine_type = ("DynamicEngine" if dynamic_engine else "StaticEngine") @@ -539,7 +557,8 @@ def _AddTests(test_class): use_optimizer=use_optimizer, precision_mode=precision_mode, dynamic_engine=dynamic_engine, - test_name=test_name) + test_name=test_name, + use_calibration=use_calibration) setattr(test_class, "testTfTrt_" + test_name, _GetTest(run_params)) diff --git a/tensorflow/core/grappler/optimizers/layout_optimizer.cc b/tensorflow/core/grappler/optimizers/layout_optimizer.cc index 7dc62e24df..50e03467d4 100644 --- a/tensorflow/core/grappler/optimizers/layout_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/layout_optimizer.cc @@ -108,6 +108,7 @@ std::set GetOpsFormatAgnostic() { "Conj", "Cos", "Cosh", + "Dequantize", "Digamma", "Div", "Elu", @@ -119,6 +120,7 @@ std::set GetOpsFormatAgnostic() { "Exit", "Exp", "Expm1", + "FakeQuantWithMinMaxVars", "Fill", "Floor", "FloorDiv", @@ -161,6 +163,9 @@ std::set GetOpsFormatAgnostic() { "PreventGradient", "Prod", "Polygamma", + "QuantizeAndDequantizeV2", + "QuantizeAndDequantizeV3", + "QuantizeV2", "Pow", "Real", "RealDiv", -- GitLab From abda4224e8d6b8e227a579a481e9f0ebe5fdb346 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Thu, 18 Oct 2018 15:14:38 -0700 Subject: [PATCH 051/672] Add FakeQuantWithMinMaxArgs --- .../contrib/tensorrt/convert/convert_graph.cc | 1 + .../contrib/tensorrt/convert/convert_nodes.cc | 33 ++++++++++++++----- .../grappler/optimizers/layout_optimizer.cc | 1 + 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 40d03ace6f..b9c6dc7fde 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -139,6 +139,7 @@ Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node, i "QuantizeAndDequantizeV2", "QuantizeAndDequantizeV3", "FakeQuantWithMinMaxVars", + "FakeQuantWithMinMaxArgs", }; if (precision_mode == INT8MODE && quantize_ops.count(node->type_string())) { diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 48e8a6fc51..f3358ba11d 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -1947,15 +1947,29 @@ tensorflow::Status ConvertQuantize(OpConverterParams* params) { params->outputs->push_back(inputs.at(0)); return tensorflow::Status::OK(); } - nvinfer1::ITensor* tensor = const_cast(inputs.at(0).tensor()); - // Min - TRT_ShapedWeights weights_min = inputs.at(1).weights(); - auto weights_min_ptr = static_cast(const_cast(weights_min.GetValues())); - float min_range = weights_min_ptr[0]; - // Max - TRT_ShapedWeights weights_max = inputs.at(2).weights(); - auto weights_max_ptr = static_cast(const_cast(weights_max.GetValues())); - float max_range = weights_max_ptr[0]; + float min_range = 0.0f; + float max_range = 0.0f; + if (inputs.size() == 1) { + // Get ranges from attributes + TFAttrs attrs(node_def); + min_range = attrs.get("min"); + max_range = attrs.get("max"); + } else if (inputs.size() == 3) { + // Get ranges from inputs + // Min + TRT_ShapedWeights weights_min = inputs.at(1).weights(); + auto weights_min_ptr = static_cast(const_cast( + weights_min.GetValues())); + min_range = weights_min_ptr[0]; + // Max + TRT_ShapedWeights weights_max = inputs.at(2).weights(); + auto weights_max_ptr = static_cast(const_cast( + weights_max.GetValues())); + max_range = weights_max_ptr[0]; + } else { + return tensorflow::errors::InvalidArgument( + "Expected 1 or 3 inputs for quantize node, at ", node_def.name()); + } // Store ranges for tensor params->converter->ProvideQuantizationRange(tensor, min_range, max_range); // Sometimes, TRT may not quantize a tensor, either because it chooses to @@ -3016,6 +3030,7 @@ void Converter::RegisterOpConverters() { op_registry_["QuantizeAndDequantizeV2"] = ConvertQuantize; op_registry_["QuantizeAndDequantizeV3"] = ConvertQuantize; op_registry_["FakeQuantWithMinMaxVars"] = ConvertQuantize; + op_registry_["FakeQuantWithMinMaxArgs"] = ConvertQuantize; #endif plugin_converter_ = ConvertPlugin; diff --git a/tensorflow/core/grappler/optimizers/layout_optimizer.cc b/tensorflow/core/grappler/optimizers/layout_optimizer.cc index 50e03467d4..b40438e98f 100644 --- a/tensorflow/core/grappler/optimizers/layout_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/layout_optimizer.cc @@ -121,6 +121,7 @@ std::set GetOpsFormatAgnostic() { "Exp", "Expm1", "FakeQuantWithMinMaxVars", + "FakeQuantWithMinMaxArgs", "Fill", "Floor", "FloorDiv", -- GitLab From 6e07831307ebad7f154052cc387da22b6169a4d1 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 23 Oct 2018 17:48:18 -0700 Subject: [PATCH 052/672] Add more checks on quantize node inputs. Add ConvertQuantize tests Fix line length formatting Set quantization range for IConstantLayer created when weights are reshaped via PrepareTensorForShape. Since the weights are constant we can use the value of the weights to determine the range. Add missing inference of quantization range. Allow ConvertReshape to work on weights Fix reshape for weights Fix reshape for weights again --- .../contrib/tensorrt/convert/convert_nodes.cc | 56 +++++++++++++- .../contrib/tensorrt/convert/convert_nodes.h | 4 + .../tensorrt/convert/convert_nodes_test.cc | 67 ++++++++++++++++ .../tensorrt/test/quantization_test.py | 76 ++++++++----------- 4 files changed, 156 insertions(+), 47 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index f3358ba11d..f3403fbdc6 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -969,6 +969,32 @@ Status Converter::TransposeTensor(nvinfer1::ITensor* input_tensor, return tensorflow::Status::OK(); } +Status Converter::GetWeightRange(const TRT_ShapedWeights& weights, + float* out_min, + float* out_max) { + switch (weights.type_) { + case tensorflow::DataType::DT_FLOAT: { + auto inp = static_cast(weights.GetValues()); + auto result = std::minmax_element(inp, inp + weights.count()); + *out_min = *result.first; + *out_max = *result.second; + break; + } + case tensorflow::DataType::DT_HALF: { + auto inp = static_cast(weights.GetValues()); + auto result = std::minmax_element(inp, inp + weights.count()); + *out_min = Eigen::half_impl::half_to_float(*result.first); + *out_max = Eigen::half_impl::half_to_float(*result.second); + break; + } + default: + return tensorflow::errors::Unimplemented( + "Data type not supported: " + + tensorflow::DataTypeString(weights.type_)); + } + return tensorflow::Status::OK(); +} + Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, const nvinfer1::Dims& dims, const nvinfer1::ITensor** tensor) { @@ -1004,6 +1030,21 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, this->network()->addConstant(dims, input.weights().GetTrtWeights()); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Reshape"); *tensor = layer->getOutput(0); + // We need to set a quantization range for the output tensor of the + // IConstantLayer. Here we set the range to [min(weights), max(weights)]. + float min_range = 0.0f; + float max_range = 0.0f; + TF_RETURN_IF_ERROR( + GetWeightRange(input.weights(), &min_range, &max_range)); + // Avoid setting range to 0 because TRT will throw an error. If the weights + // are zero then the range doesn't matter: using 127.0f should ensure the + // quantized weight will be exactly zero. + if (min_range == 0.0f && max_range == 0.0f) { + min_range = -127.0f; + max_range = 127.0f; + } + ProvideQuantizationRange(const_cast(*tensor), + min_range, max_range); } return tensorflow::Status::OK(); } @@ -1555,6 +1596,8 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) { nvinfer1::DimsHW(padding[0].first, padding[1].first), nvinfer1::DimsHW(padding[0].second, padding[1].second)); TFTRT_RETURN_ERROR_IF_NULLPTR(pad_layer, node_def.name()); + ctx.MarkQuantizationRangesAsInferrable( + const_cast(tensor), pad_layer->getOutput(0)); padding = {{0, 0}, {0, 0}}; tensor = pad_layer->getOutput(0); VLOG(2) << "TENSOR after: " << DebugString(tensor->getDimensions()); @@ -1943,7 +1986,9 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { tensorflow::Status ConvertQuantize(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; - if (inputs.at(0).is_weights()) { + if (inputs.size() > 0 && inputs.at(0).is_weights()) { + // TensorRT will automatically quantize weights, so we will ignore ranges + // for weights. params->outputs->push_back(inputs.at(0)); return tensorflow::Status::OK(); } @@ -1952,10 +1997,19 @@ tensorflow::Status ConvertQuantize(OpConverterParams* params) { if (inputs.size() == 1) { // Get ranges from attributes TFAttrs attrs(node_def); + if (attrs.count("min") == 0 || attrs.count("max") == 0) { + return tensorflow::errors::InvalidArgument( + "Min or max attribute not found for quantize, at ", node_def.name()); + } min_range = attrs.get("min"); max_range = attrs.get("max"); } else if (inputs.size() == 3) { // Get ranges from inputs + if (!inputs.at(1).is_weights() || !inputs.at(2).is_weights()) { + return tensorflow::errors::InvalidArgument( + "Min and max for quantize must be weights not tensors, at ", + node_def.name()); + } // Min TRT_ShapedWeights weights_min = inputs.at(1).weights(); auto weights_min_ptr = static_cast(const_cast( diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.h b/tensorflow/contrib/tensorrt/convert/convert_nodes.h index 2daca99ed9..ec9cea38d5 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.h +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.h @@ -478,6 +478,10 @@ class Converter { void PropagateQuantizationRanges(); + // Gets the min and max value in a TRT_ShapedWeights + Status GetWeightRange(const TRT_ShapedWeights& weights, + float* out_min, float* out_max); + // Registered op converters by op type. std::unordered_map op_registry_; diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index c3a39395f3..38df6995b6 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -434,6 +434,10 @@ class ConverterTest : public ::testing::Test { int batch_size() const { return converter_->batch_size_; } + std::unordered_map* GetQuantizationRanges() { + return &quantization_ranges_; + } + private: Logger logger_; // These members are ordered in a way such that the destruction order is: @@ -1130,6 +1134,69 @@ TEST_F(OpConverterTest, ConvertMatMul) { EXPECT_THAT(output_data, ElementsAre(2, 3)); } } +} + +TEST_F(ConverterTest, ConvertQuantize) { + { + // Input list is empty, should fail. + NodeDef node_def = + MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {}); + ExpectStatus(converter_.ConvertNode(node_def), error::INVALID_ARGUMENT, + "Expected 1 or 3 inputs for quantize node, at my_quantize"); + } + { + // Missing attributes, should fail + converter_.Reset(); + NodeDef node_def = + MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {"input"}); + AddTestTensor("input", {1, 2, 3}); + ExpectStatus(converter_.ConvertNode(node_def), error::INVALID_ARGUMENT, + "Min or max attribute not found for quantize, at my_quantize"); + } + { + // All inputs are tensors, should fail + converter_.Reset(); + NodeDef node_def = MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", + {"input", "weights_min", "weights_max"}); + AddTestTensor("input", {1, 2, 3}); + AddTestTensor("weights_min", {1}); + AddTestTensor("weights_max", {1}); + ExpectStatus(converter_.ConvertNode(node_def), error::INVALID_ARGUMENT, + "Min and max for quantize must be weights not tensors, at my_quantize"); + } + { + // Ranges set via attributes, ok. + converter_.Reset(); + NodeDef node_def = + MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {"input"}); + AddTestTensor("input", {1, 2, 3}); + AttrValue attr_min; + attr_min.set_f(-6.0f); + AttrValue attr_max; + attr_max.set_f(6.0f); + node_def.mutable_attr()->insert({"min", attr_min}); + node_def.mutable_attr()->insert({"max", attr_max}); + TF_EXPECT_OK(converter_.ConvertNode(node_def)); + TRT_TensorOrWeights output = converter_.GetTensorOrWeights("my_quantize"); + EXPECT_TRUE(output.is_tensor()); + auto ranges = converter_.GetQuantizationRanges(); + EXPECT_EQ((*ranges).count(output.tensor()), 1); + EXPECT_EQ((*ranges)[output.tensor()], 6.0f); + } + { + // Ranges set via inputs, ok. + converter_.Reset(); + NodeDef node_def = MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", + {"input", "weights_min", "weights_max"}); + AddTestTensor("input", {1, 2, 3}); + AddTestWeights("weights_min", DT_FLOAT, {1}, {-6.0f}); + AddTestWeights("weights_max", DT_FLOAT, {1}, {6.0f}); + TF_EXPECT_OK(converter_.ConvertNode(node_def)); + TRT_TensorOrWeights output = converter_.GetTensorOrWeights("my_quantize"); + EXPECT_TRUE(output.is_tensor()); + auto ranges = converter_.GetQuantizationRanges(); + EXPECT_EQ((*ranges).count(output.tensor()), 1); + EXPECT_EQ((*ranges)[output.tensor()], 6.0f); } } diff --git a/tensorflow/contrib/tensorrt/test/quantization_test.py b/tensorflow/contrib/tensorrt/test/quantization_test.py index a6934bf490..f32b15b038 100644 --- a/tensorflow/contrib/tensorrt/test/quantization_test.py +++ b/tensorflow/contrib/tensorrt/test/quantization_test.py @@ -43,44 +43,13 @@ def build_graph(input_name, input_dims, output_name, with g.as_default(): x = array_ops.placeholder( dtype=dtype, shape=[None] + input_dims[1:], name=input_name) - x = quantize(x, 100) - filt1 = constant_op.constant( - 0.3, shape=(3, 3, 1, 32), dtype=dtype, name='filt1') - x = nn.conv2d(x, filt1, strides=[1, 1, 1, 1], padding='VALID') - bias1 = constant_op.constant(0.3, shape=(32,), name="bias1", dtype=dtype) - x = nn.bias_add(x, bias1) - - x = quantize(x, 6) - x = nn.relu6(x) - filt2 = constant_op.constant( - 0.3, shape=(3, 3, 32, 64), dtype=dtype, name='filt2') - x = nn.conv2d(x, filt2, strides=[1, 1, 1, 1], padding='VALID') - bias2 = constant_op.constant(0.3, shape=(64,), name="bias2", dtype=dtype) - x = nn.bias_add(x, bias2) - - x = quantize(x, 6) - x = nn.relu6(x) - x = math_ops.reduce_mean(x, [1, 2]) - x = quantize(x, 6) - # FC1 - fc_w1 = constant_op.constant( - 0.3, shape=(64, 512), dtype=dtype, name='fc_w1') - x = math_ops.matmul(x, fc_w1) - x = quantize(x, 6) - fc_b1 = constant_op.constant( - 0.3, shape=(512,), dtype=dtype, name='fc_b1') - x = nn.bias_add(x, fc_b1) - x = quantize(x, 6) - x = nn.relu6(x) - # FC2 - fc_w2 = constant_op.constant( - 0.3, shape=(512, 10), dtype=dtype, name='fc_w2') - x = math_ops.matmul(x, fc_w2) - x = quantize(x, 25) - fc_b2 = constant_op.constant( - 0.3, shape=(10,), dtype=dtype, name='fc_b2') - x = nn.bias_add(x, fc_b2) - x = quantize(x, 25) + x = quantize(x, 10.0) + x = x + 5 + x = quantize(x, 15.0) + x = x - 5 + x = quantize(x, 10.0) + x = x * 0.1 + x = quantize(x, 1.0) x = array_ops.identity(x, name=output_name) return g @@ -89,7 +58,7 @@ class QuantizationMissingAllRangesTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Create a graph containing single segment with no quantization ranges.""" input_name = "input" - input_dims = [100, 28, 28, 1] + input_dims = [100, 100] output_name = "output" g = build_graph(input_name, input_dims, output_name, add_quantization_nodes=False) @@ -98,7 +67,7 @@ class QuantizationMissingAllRangesTest(trt_test.TfTrtIntegrationTestBase): input_names=[input_name], input_dims=[input_dims], output_names=[output_name], - expected_output_dims=[(100, 10)]) + expected_output_dims=[(100, 100)]) def ShouldRunTest(self, run_params): return (run_params.precision_mode == "INT8" and @@ -116,7 +85,7 @@ class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Create a graph containing single segment with no quantization ranges.""" input_name = "input" - input_dims = [100, 28, 28, 1] + input_dims = [100, 100] output_name = "output" g = build_graph(input_name, input_dims, output_name, add_quantization_nodes=True) @@ -125,7 +94,7 @@ class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): input_names=[input_name], input_dims=[input_dims], output_names=[output_name], - expected_output_dims=[(100, 10)]) + expected_output_dims=[(100, 100)]) def ShouldRunTest(self, run_params): return (run_params.precision_mode == "INT8" and @@ -135,12 +104,20 @@ class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): """Return the expected engines to build.""" return ["my_trt_op_0"] + def ExpectedAbsoluteTolerance(self, run_params): + """The absolute tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + + def ExpectedRelativeTolerance(self, run_params): + """The relative tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Create a graph containing single segment with no quantization ranges.""" input_name = "input" - input_dims = [100, 28, 28, 1] + input_dims = [100, 100] output_name = "output" g = build_graph(input_name, input_dims, output_name, add_quantization_nodes=True) @@ -149,7 +126,7 @@ class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): input_names=[input_name], input_dims=[input_dims], output_names=[output_name], - expected_output_dims=[(100, 10)]) + expected_output_dims=[(100, 100)]) def ShouldRunTest(self, run_params): return (run_params.precision_mode == "FP32" or @@ -157,8 +134,15 @@ class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0", "my_trt_op_1", "my_trt_op_2", "my_trt_op_3", - "my_trt_op_4", "my_trt_op_5", "my_trt_op_6"] + return ["my_trt_op_0", "my_trt_op_1", "my_trt_op_2"] + + def ExpectedAbsoluteTolerance(self, run_params): + """The absolute tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + + def ExpectedRelativeTolerance(self, run_params): + """The relative tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 if __name__ == "__main__": test.main() -- GitLab From 9dda56272f87cc1ebd66eeaa6e8f3cf0421fe4fe Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Fri, 2 Nov 2018 14:25:37 -0700 Subject: [PATCH 053/672] Fix merge conflicts --- tensorflow/contrib/tensorrt/convert/convert_nodes.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index f3403fbdc6..456840e537 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -1596,7 +1596,7 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) { nvinfer1::DimsHW(padding[0].first, padding[1].first), nvinfer1::DimsHW(padding[0].second, padding[1].second)); TFTRT_RETURN_ERROR_IF_NULLPTR(pad_layer, node_def.name()); - ctx.MarkQuantizationRangesAsInferrable( + params->converter->MarkQuantizationRangesAsInferrable( const_cast(tensor), pad_layer->getOutput(0)); padding = {{0, 0}, {0, 0}}; tensor = pad_layer->getOutput(0); @@ -2025,7 +2025,10 @@ tensorflow::Status ConvertQuantize(OpConverterParams* params) { "Expected 1 or 3 inputs for quantize node, at ", node_def.name()); } // Store ranges for tensor - params->converter->ProvideQuantizationRange(tensor, min_range, max_range); + params->converter->ProvideQuantizationRange( + const_cast(inputs.at(0).tensor()), + min_range, + max_range); // Sometimes, TRT may not quantize a tensor, either because it chooses to // execute a higher precision kernel or because of op fusion. In these cases, // accuracy will suffer if the model was trained to expect quantization at -- GitLab From 08159b275a5e66e5713ab25befcd7b2034d631bb Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Fri, 2 Nov 2018 15:39:14 -0700 Subject: [PATCH 054/672] Improve use_calibration arg documentation --- .../contrib/tensorrt/python/trt_convert.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tensorflow/contrib/tensorrt/python/trt_convert.py b/tensorflow/contrib/tensorrt/python/trt_convert.py index 98a647dc57..95f47c9014 100644 --- a/tensorflow/contrib/tensorrt/python/trt_convert.py +++ b/tensorflow/contrib/tensorrt/python/trt_convert.py @@ -100,8 +100,11 @@ def tensorrt_rewriter_config(rewriter_config=None, if set to True, a calibration graph will be created to calibrate the missing ranges. The calibration graph must be converted to an inference graph using calib_graph_to_infer_graph() after running calibration. - if set to False, quantization ranges will be expected for every tensor in - the graph. If a range is missing, an error will occur. + if set to False, quantization nodes will be expected for every tensor in + the graph (exlcuding those which will be fused). If a range is missing, + an error will occur. Please note that accuracy may be negatively affected + if there is a mismatch between which tensors TRT quantizes and which + tensors were trained with fake quantization. Returns: A RewriterConfig proto which sets a TensorRTOptimizer to run Grappler. @@ -176,7 +179,7 @@ def create_inference_graph(input_graph_def, max_workspace_size_bytes: the maximum GPU temporary memory which the TRT engine can use at execution time. This corresponds to the 'workspaceSize' parameter of nvinfer1::IBuilder::setMaxWorkspaceSize(). - precision_mode: one of TrtPrecisionMode.supported_precision_modes(). + precision_mode: one of TrtPrecisionMode.supported_precision_modes(). minimum_segment_size: the minimum number of nodes required for a subgraph to be replaced by TRTEngineOp. is_dynamic_op: whether to generate dynamic TRT ops which will build the TRT @@ -197,8 +200,11 @@ def create_inference_graph(input_graph_def, if set to True, a calibration graph will be created to calibrate the missing ranges. The calibration graph must be converted to an inference graph using calib_graph_to_infer_graph() after running calibration. - if set to False, quantization ranges will be expected for every tensor in - the graph. If a range is missing, an error will occur. + if set to False, quantization nodes will be expected for every tensor in + the graph (exlcuding those which will be fused). If a range is missing, + an error will occur. Please note that accuracy may be negatively affected + if there is a mismatch between which tensors TRT quantizes and which + tensors were trained with fake quantization. input_saved_model_dir: the directory to load the SavedModel which contains the input graph to transforms. Used only when input_graph_def is None. input_saved_model_tags: list of tags to load the SavedModel. -- GitLab From b11c33a5d1792ba7e4ff0a687d43c0322b3458d0 Mon Sep 17 00:00:00 2001 From: Fei Hu Date: Mon, 5 Nov 2018 11:37:17 -0800 Subject: [PATCH 055/672] Update the code style for line break --- tensorflow/python/keras/layers/wrappers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/keras/layers/wrappers.py b/tensorflow/python/keras/layers/wrappers.py index 82c96e386a..c4feab651c 100644 --- a/tensorflow/python/keras/layers/wrappers.py +++ b/tensorflow/python/keras/layers/wrappers.py @@ -441,8 +441,8 @@ class Bidirectional(Wrapper): @tf_utils.shape_type_conversion def compute_output_shape(self, input_shape): - forward_layer_output_shape \ - = self.forward_layer.compute_output_shape(input_shape) + forward_layer_output_shape = self.forward_layer.compute_output_shape( + input_shape) if getattr(forward_layer_output_shape, 'as_list', None) is None: output_shape = tuple(forward_layer_output_shape) else: -- GitLab From c5b1ad0ea01634d0fb6bf6ba59ce014f1e66b6d9 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Thu, 25 Oct 2018 22:20:40 +0000 Subject: [PATCH 056/672] Improve shape function of tf.sparse_reduce_sum This fix tries to address the issue raised in 23114 where the shape function of tf.sparse_reduce_sum did not infer the shape even if the input shape were known. This fix improves the shape function. This fix fixes 23114. Signed-off-by: Yong Tang --- tensorflow/core/ops/sparse_ops.cc | 41 ++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/ops/sparse_ops.cc b/tensorflow/core/ops/sparse_ops.cc index bc0cb2095d..c54c8e87c7 100644 --- a/tensorflow/core/ops/sparse_ops.cc +++ b/tensorflow/core/ops/sparse_ops.cc @@ -423,7 +423,46 @@ REGISTER_OP("SparseReduceSum") .Attr("keep_dims: bool = False") .Output("output: T") .Attr("T: numbertype") - .SetShapeFn(shape_inference::UnknownShape); + .SetShapeFn([](InferenceContext* c) { + bool keep_dims = false; + TF_RETURN_IF_ERROR(c->GetAttr("keep_dims", &keep_dims)); + + const Tensor* shape_tensor = c->input_tensor(2); + const Tensor* axes_tensor = c->input_tensor(3); + if (shape_tensor != nullptr && axes_tensor != nullptr) { + auto shape_vec = shape_tensor->flat(); + auto axes_vec = axes_tensor->flat(); + + int64 ndims = shape_vec.size(); + std::unordered_set axes; + for (int i = 0; i < axes_vec.size(); i++) { + axes.insert((axes_vec(i) + ndims) % ndims); + } + + std::vector dims; + if (keep_dims) { + dims.reserve(ndims); + for (int d = 0; d < ndims; ++d) { + if (axes.find(d) == axes.end()) { + dims.push_back(c->MakeDim(shape_vec(d))); + } else { + dims.push_back(c->MakeDim(1)); + } + } + } else { + for (int d = 0; d < ndims; ++d) { + if (axes.find(d) == axes.end()) { + dims.push_back(c->MakeDim(shape_vec(d))); + } + } + + } + + c->set_output(0, c->MakeShape(dims)); + return Status::OK(); + } + return shape_inference::UnknownShape(c); + }); REGISTER_OP("SparseReduceSumSparse") .Input("input_indices: int64") -- GitLab From e008c4dc79bbf9cea6a6137a9f465718835a9c40 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Thu, 25 Oct 2018 22:23:06 +0000 Subject: [PATCH 057/672] Add test case for improved shape function of tf.sparse_reduce_sum Signed-off-by: Yong Tang --- .../python/kernel_tests/sparse_ops_test.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index a45ce2e13b..7594fa8889 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -657,6 +657,7 @@ class SparseReduceTest(test_util.TensorFlowTestCase): self._compare(sp_t, reduction_axes, ndims, True, False) self._compare(sp_t, reduction_axes, ndims, True, True) + def testSimpleAndRandomInputs(self): if np.__version__ == "1.13.0": self.skipTest("numpy 1.13.0 bug") @@ -722,6 +723,45 @@ class SparseReduceTest(test_util.TensorFlowTestCase): reduced.eval().shape) self.assertLess(err, 1e-3) + def _testSparseReduceSumShape(self, sp_t, reduction_axes, ndims, keep_dims): + densified = sparse_ops.sparse_tensor_to_dense(sp_t).eval() + + np_ans = densified + if reduction_axes is None: + np_ans = np.sum(np_ans, keepdims=keep_dims) + else: + if not isinstance(reduction_axes, list): # Single scalar. + reduction_axes = [reduction_axes] + reduction_axes = np.array(reduction_axes).astype(np.int32) + # Handles negative axes. + reduction_axes = (reduction_axes + ndims) % ndims + # Loop below depends on sorted. + reduction_axes.sort() + for ra in reduction_axes.ravel()[::-1]: + np_ans = np.sum(np_ans, axis=ra, keepdims=keep_dims) + + tf_ans = sparse_ops.sparse_reduce_sum(sp_t, reduction_axes, keep_dims) + self.assertAllEqual(np_ans.shape, tf_ans.get_shape().as_list()) + + def testSparseReduceSumShape(self): + sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape) + + with self.session(use_gpu=False): + self._testSparseReduceSumShape(sp_t, None, ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, None, ndims=2, keep_dims=True) + self._testSparseReduceSumShape(sp_t, 0, ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, 0, ndims=2, keep_dims=True) + self._testSparseReduceSumShape(sp_t, [1], ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, [1], ndims=2, keep_dims=True) + self._testSparseReduceSumShape(sp_t, [0, 1], ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, [0, 1], ndims=2, keep_dims=True) + self._testSparseReduceSumShape(sp_t, [1, 0], ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, [1, 0], ndims=2, keep_dims=True) + self._testSparseReduceSumShape(sp_t, [-1], ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, [-1], ndims=2, keep_dims=True) + self._testSparseReduceSumShape(sp_t, [1, -2], ndims=2, keep_dims=False) + self._testSparseReduceSumShape(sp_t, [1, -2], ndims=2, keep_dims=True) + class SparseMathOpsTest(test_util.TensorFlowTestCase): -- GitLab From b51975e5339edba945b6c750f7a140dff7b4bcf9 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Thu, 25 Oct 2018 22:29:11 +0000 Subject: [PATCH 058/672] Improvement in tests Signed-off-by: Yong Tang --- .../python/kernel_tests/sparse_ops_test.py | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index 7594fa8889..2ebc10c4a9 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -747,20 +747,14 @@ class SparseReduceTest(test_util.TensorFlowTestCase): sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape) with self.session(use_gpu=False): - self._testSparseReduceSumShape(sp_t, None, ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, None, ndims=2, keep_dims=True) - self._testSparseReduceSumShape(sp_t, 0, ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, 0, ndims=2, keep_dims=True) - self._testSparseReduceSumShape(sp_t, [1], ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, [1], ndims=2, keep_dims=True) - self._testSparseReduceSumShape(sp_t, [0, 1], ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, [0, 1], ndims=2, keep_dims=True) - self._testSparseReduceSumShape(sp_t, [1, 0], ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, [1, 0], ndims=2, keep_dims=True) - self._testSparseReduceSumShape(sp_t, [-1], ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, [-1], ndims=2, keep_dims=True) - self._testSparseReduceSumShape(sp_t, [1, -2], ndims=2, keep_dims=False) - self._testSparseReduceSumShape(sp_t, [1, -2], ndims=2, keep_dims=True) + for keep_dims in [True, False]: + self._testSparseReduceSumShape(sp_t, None, ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, 0, ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, [1], ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, [0, 1], ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, [1, 0], ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, [-1], ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, [1, -2], ndims=2, keep_dims=keep_dims) class SparseMathOpsTest(test_util.TensorFlowTestCase): -- GitLab From 71787f94307d6f8f18255883f53d1544e09f005b Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Thu, 25 Oct 2018 22:33:07 +0000 Subject: [PATCH 059/672] Pylint fix Signed-off-by: Yong Tang --- tensorflow/python/kernel_tests/sparse_ops_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index 2ebc10c4a9..f81de76716 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -748,13 +748,13 @@ class SparseReduceTest(test_util.TensorFlowTestCase): with self.session(use_gpu=False): for keep_dims in [True, False]: - self._testSparseReduceSumShape(sp_t, None, ndims=2, keep_dims=keep_dims) - self._testSparseReduceSumShape(sp_t, 0, ndims=2, keep_dims=keep_dims) - self._testSparseReduceSumShape(sp_t, [1], ndims=2, keep_dims=keep_dims) - self._testSparseReduceSumShape(sp_t, [0, 1], ndims=2, keep_dims=keep_dims) - self._testSparseReduceSumShape(sp_t, [1, 0], ndims=2, keep_dims=keep_dims) - self._testSparseReduceSumShape(sp_t, [-1], ndims=2, keep_dims=keep_dims) - self._testSparseReduceSumShape(sp_t, [1, -2], ndims=2, keep_dims=keep_dims) + self._testSparseReduceSumShape(sp_t, None, 2, keep_dims) + self._testSparseReduceSumShape(sp_t, 0, 2, keep_dims) + self._testSparseReduceSumShape(sp_t, [1], 2, keep_dims) + self._testSparseReduceSumShape(sp_t, [0, 1], 2, keep_dims) + self._testSparseReduceSumShape(sp_t, [1, 0], 2, keep_dims) + self._testSparseReduceSumShape(sp_t, [-1], 2, keep_dims) + self._testSparseReduceSumShape(sp_t, [1, -2], 2, keep_dims) class SparseMathOpsTest(test_util.TensorFlowTestCase): -- GitLab From 74784ac463b55adcae0534b117d4ccd5eac82c0c Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Wed, 31 Oct 2018 20:12:55 +0000 Subject: [PATCH 060/672] Fix `Experimental clang-format Check` Signed-off-by: Yong Tang --- tensorflow/core/ops/sparse_ops.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/core/ops/sparse_ops.cc b/tensorflow/core/ops/sparse_ops.cc index c54c8e87c7..95d009c9b2 100644 --- a/tensorflow/core/ops/sparse_ops.cc +++ b/tensorflow/core/ops/sparse_ops.cc @@ -455,7 +455,6 @@ REGISTER_OP("SparseReduceSum") dims.push_back(c->MakeDim(shape_vec(d))); } } - } c->set_output(0, c->MakeShape(dims)); -- GitLab From e64bfb83dc7338720a9a7bc5c4414a1f6379dfe4 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 4 Nov 2018 18:43:45 +0000 Subject: [PATCH 061/672] Fix //tensorflow/core:ops_sparse_ops_test Signed-off-by: Yong Tang --- tensorflow/core/ops/sparse_ops_test.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tensorflow/core/ops/sparse_ops_test.cc b/tensorflow/core/ops/sparse_ops_test.cc index 6a9b5ce4d3..00283c5993 100644 --- a/tensorflow/core/ops/sparse_ops_test.cc +++ b/tensorflow/core/ops/sparse_ops_test.cc @@ -133,6 +133,13 @@ TEST(SparseOpsTest, SparseToDense_ShapeFn) { TEST(SparseOpsTest, SparseReduceSum_ShapeFn) { ShapeInferenceTestOp op("SparseReduceSum"); + TF_ASSERT_OK(NodeDefBuilder("test", "SparseReduceSum") + .Input({"input_indices", 0, DT_INT64}) + .Input({"input_values", 1, DT_INT64}) + .Input({"input_shape", 2, DT_INT64}) + .Input({"reduction_axes", 3, DT_INT32}) + .Attr("keep_dims", false) + .Finalize(&op.node_def)); // Shape fn always yields unknown. INFER_OK(op, "?;?;?;?", "?"); -- GitLab From 70768d6b0614eeb12d8cd07c2a3b1e4795d73dc7 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 4 Nov 2018 18:46:02 +0000 Subject: [PATCH 062/672] Add shape function to SparseReduceMax Signed-off-by: Yong Tang --- tensorflow/core/ops/sparse_ops.cc | 87 +++++++++++++++++-------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/tensorflow/core/ops/sparse_ops.cc b/tensorflow/core/ops/sparse_ops.cc index 95d009c9b2..3529d47449 100644 --- a/tensorflow/core/ops/sparse_ops.cc +++ b/tensorflow/core/ops/sparse_ops.cc @@ -39,6 +39,51 @@ Status SparseSparseMinOrMaxShapeFn(InferenceContext* c) { return Status::OK(); } +Status SparseReduceShapeFn(InferenceContext* c) { + // Input 0: input_indices + // Input 1: input_values + // Input 2: input_shape + // Input 3: reduction_axes + // Attr: keep_dims + bool keep_dims = false; + TF_RETURN_IF_ERROR(c->GetAttr("keep_dims", &keep_dims)); + + const Tensor* shape_tensor = c->input_tensor(2); + const Tensor* axes_tensor = c->input_tensor(3); + if (shape_tensor != nullptr && axes_tensor != nullptr) { + auto shape_vec = shape_tensor->flat(); + auto axes_vec = axes_tensor->flat(); + + int64 ndims = shape_vec.size(); + std::unordered_set axes; + for (int i = 0; i < axes_vec.size(); i++) { + axes.insert((axes_vec(i) + ndims) % ndims); + } + + std::vector dims; + if (keep_dims) { + dims.reserve(ndims); + for (int d = 0; d < ndims; ++d) { + if (axes.find(d) == axes.end()) { + dims.push_back(c->MakeDim(shape_vec(d))); + } else { + dims.push_back(c->MakeDim(1)); + } + } + } else { + for (int d = 0; d < ndims; ++d) { + if (axes.find(d) == axes.end()) { + dims.push_back(c->MakeDim(shape_vec(d))); + } + } + } + + c->set_output(0, c->MakeShape(dims)); + return Status::OK(); + } + return shape_inference::UnknownShape(c); +} + } // namespace REGISTER_OP("SparseAddGrad") @@ -401,7 +446,7 @@ REGISTER_OP("SparseReduceMax") .Attr("keep_dims: bool = False") .Output("output: T") .Attr("T: realnumbertype") - .SetShapeFn(shape_inference::UnknownShape); + .SetShapeFn(SparseReduceShapeFn); REGISTER_OP("SparseReduceMaxSparse") .Input("input_indices: int64") @@ -423,45 +468,7 @@ REGISTER_OP("SparseReduceSum") .Attr("keep_dims: bool = False") .Output("output: T") .Attr("T: numbertype") - .SetShapeFn([](InferenceContext* c) { - bool keep_dims = false; - TF_RETURN_IF_ERROR(c->GetAttr("keep_dims", &keep_dims)); - - const Tensor* shape_tensor = c->input_tensor(2); - const Tensor* axes_tensor = c->input_tensor(3); - if (shape_tensor != nullptr && axes_tensor != nullptr) { - auto shape_vec = shape_tensor->flat(); - auto axes_vec = axes_tensor->flat(); - - int64 ndims = shape_vec.size(); - std::unordered_set axes; - for (int i = 0; i < axes_vec.size(); i++) { - axes.insert((axes_vec(i) + ndims) % ndims); - } - - std::vector dims; - if (keep_dims) { - dims.reserve(ndims); - for (int d = 0; d < ndims; ++d) { - if (axes.find(d) == axes.end()) { - dims.push_back(c->MakeDim(shape_vec(d))); - } else { - dims.push_back(c->MakeDim(1)); - } - } - } else { - for (int d = 0; d < ndims; ++d) { - if (axes.find(d) == axes.end()) { - dims.push_back(c->MakeDim(shape_vec(d))); - } - } - } - - c->set_output(0, c->MakeShape(dims)); - return Status::OK(); - } - return shape_inference::UnknownShape(c); - }); + .SetShapeFn(SparseReduceShapeFn); REGISTER_OP("SparseReduceSumSparse") .Input("input_indices: int64") -- GitLab From 1b5467a65dab5007754c3aa1bd9f3fd5b3797cc6 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 4 Nov 2018 18:59:38 +0000 Subject: [PATCH 063/672] Add additional test cases for sparse_reduce_max shape function Signed-off-by: Yong Tang --- .../python/kernel_tests/sparse_ops_test.py | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index f81de76716..372c27bf09 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -657,7 +657,6 @@ class SparseReduceTest(test_util.TensorFlowTestCase): self._compare(sp_t, reduction_axes, ndims, True, False) self._compare(sp_t, reduction_axes, ndims, True, True) - def testSimpleAndRandomInputs(self): if np.__version__ == "1.13.0": self.skipTest("numpy 1.13.0 bug") @@ -723,12 +722,19 @@ class SparseReduceTest(test_util.TensorFlowTestCase): reduced.eval().shape) self.assertLess(err, 1e-3) - def _testSparseReduceSumShape(self, sp_t, reduction_axes, ndims, keep_dims): + def _testSparseReduceShape(self, sp_t, reduction_axes, ndims, keep_dims, + do_sum): densified = sparse_ops.sparse_tensor_to_dense(sp_t).eval() + np_op = np.sum + tf_op = sparse_ops.sparse_reduce_sum + if not do_sum: + np_op = np.max + tf_op = sparse_ops.sparse_reduce_max + np_ans = densified if reduction_axes is None: - np_ans = np.sum(np_ans, keepdims=keep_dims) + np_ans = np_op(np_ans, keepdims=keep_dims) else: if not isinstance(reduction_axes, list): # Single scalar. reduction_axes = [reduction_axes] @@ -738,23 +744,24 @@ class SparseReduceTest(test_util.TensorFlowTestCase): # Loop below depends on sorted. reduction_axes.sort() for ra in reduction_axes.ravel()[::-1]: - np_ans = np.sum(np_ans, axis=ra, keepdims=keep_dims) + np_ans = np_op(np_ans, axis=ra, keepdims=keep_dims) - tf_ans = sparse_ops.sparse_reduce_sum(sp_t, reduction_axes, keep_dims) + tf_ans = tf_op(sp_t, reduction_axes, keep_dims) self.assertAllEqual(np_ans.shape, tf_ans.get_shape().as_list()) - def testSparseReduceSumShape(self): + def testSparseReduceSumOrMaxShape(self): sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape) with self.session(use_gpu=False): - for keep_dims in [True, False]: - self._testSparseReduceSumShape(sp_t, None, 2, keep_dims) - self._testSparseReduceSumShape(sp_t, 0, 2, keep_dims) - self._testSparseReduceSumShape(sp_t, [1], 2, keep_dims) - self._testSparseReduceSumShape(sp_t, [0, 1], 2, keep_dims) - self._testSparseReduceSumShape(sp_t, [1, 0], 2, keep_dims) - self._testSparseReduceSumShape(sp_t, [-1], 2, keep_dims) - self._testSparseReduceSumShape(sp_t, [1, -2], 2, keep_dims) + for do_sum in [True, False]: + for keep_dims in [True, False]: + self._testSparseReduceShape(sp_t, None, 2, keep_dims, do_sum) + self._testSparseReduceShape(sp_t, 0, 2, keep_dims, do_sum) + self._testSparseReduceShape(sp_t, [1], 2, keep_dims, do_sum) + self._testSparseReduceShape(sp_t, [0, 1], 2, keep_dims, do_sum) + self._testSparseReduceShape(sp_t, [1, 0], 2, keep_dims, do_sum) + self._testSparseReduceShape(sp_t, [-1], 2, keep_dims, do_sum) + self._testSparseReduceShape(sp_t, [1, -2], 2, keep_dims, do_sum) class SparseMathOpsTest(test_util.TensorFlowTestCase): -- GitLab From b399b3281d494bf8f9b04a6f4df01ad6073026d5 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Mon, 5 Nov 2018 19:31:25 +0000 Subject: [PATCH 064/672] Move shape function to common_shape_fns.cc Signed-off-by: Yong Tang --- tensorflow/core/framework/common_shape_fns.cc | 45 +++++++++++++++++ tensorflow/core/framework/common_shape_fns.h | 3 ++ tensorflow/core/ops/sparse_ops.cc | 49 +------------------ 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/tensorflow/core/framework/common_shape_fns.cc b/tensorflow/core/framework/common_shape_fns.cc index e934cbfb54..b6000f1dd0 100644 --- a/tensorflow/core/framework/common_shape_fns.cc +++ b/tensorflow/core/framework/common_shape_fns.cc @@ -1549,6 +1549,51 @@ Status ExplicitShapes(InferenceContext* c) { return Status::OK(); } +Status SparseReduceShapeFn(InferenceContext* c) { + // Input 0: input_indices + // Input 1: input_values + // Input 2: input_shape + // Input 3: reduction_axes + // Attr: keep_dims + bool keep_dims = false; + TF_RETURN_IF_ERROR(c->GetAttr("keep_dims", &keep_dims)); + + const Tensor* shape_tensor = c->input_tensor(2); + const Tensor* axes_tensor = c->input_tensor(3); + if (shape_tensor != nullptr && axes_tensor != nullptr) { + auto shape_vec = shape_tensor->flat(); + auto axes_vec = axes_tensor->flat(); + + int64 ndims = shape_vec.size(); + std::unordered_set axes; + for (int i = 0; i < axes_vec.size(); i++) { + axes.insert((axes_vec(i) + ndims) % ndims); + } + + std::vector dims; + if (keep_dims) { + dims.reserve(ndims); + for (int d = 0; d < ndims; ++d) { + if (axes.find(d) == axes.end()) { + dims.push_back(c->MakeDim(shape_vec(d))); + } else { + dims.push_back(c->MakeDim(1)); + } + } + } else { + for (int d = 0; d < ndims; ++d) { + if (axes.find(d) == axes.end()) { + dims.push_back(c->MakeDim(shape_vec(d))); + } + } + } + + c->set_output(0, c->MakeShape(dims)); + return Status::OK(); + } + return UnknownShape(c); +} + } // namespace shape_inference } // namespace tensorflow diff --git a/tensorflow/core/framework/common_shape_fns.h b/tensorflow/core/framework/common_shape_fns.h index 3a496e06ae..362899b947 100644 --- a/tensorflow/core/framework/common_shape_fns.h +++ b/tensorflow/core/framework/common_shape_fns.h @@ -310,6 +310,9 @@ Status ExplicitShape(InferenceContext* c); // Shape function for multiple-output ops with an explicit "shapes" attribute. Status ExplicitShapes(InferenceContext* c); +// Shape function for SparseReduceMax and SparseReduceSum. +Status SparseReduceShapeFn(InferenceContext* c); + } // namespace shape_inference } // namespace tensorflow diff --git a/tensorflow/core/ops/sparse_ops.cc b/tensorflow/core/ops/sparse_ops.cc index 3529d47449..de08a10784 100644 --- a/tensorflow/core/ops/sparse_ops.cc +++ b/tensorflow/core/ops/sparse_ops.cc @@ -39,51 +39,6 @@ Status SparseSparseMinOrMaxShapeFn(InferenceContext* c) { return Status::OK(); } -Status SparseReduceShapeFn(InferenceContext* c) { - // Input 0: input_indices - // Input 1: input_values - // Input 2: input_shape - // Input 3: reduction_axes - // Attr: keep_dims - bool keep_dims = false; - TF_RETURN_IF_ERROR(c->GetAttr("keep_dims", &keep_dims)); - - const Tensor* shape_tensor = c->input_tensor(2); - const Tensor* axes_tensor = c->input_tensor(3); - if (shape_tensor != nullptr && axes_tensor != nullptr) { - auto shape_vec = shape_tensor->flat(); - auto axes_vec = axes_tensor->flat(); - - int64 ndims = shape_vec.size(); - std::unordered_set axes; - for (int i = 0; i < axes_vec.size(); i++) { - axes.insert((axes_vec(i) + ndims) % ndims); - } - - std::vector dims; - if (keep_dims) { - dims.reserve(ndims); - for (int d = 0; d < ndims; ++d) { - if (axes.find(d) == axes.end()) { - dims.push_back(c->MakeDim(shape_vec(d))); - } else { - dims.push_back(c->MakeDim(1)); - } - } - } else { - for (int d = 0; d < ndims; ++d) { - if (axes.find(d) == axes.end()) { - dims.push_back(c->MakeDim(shape_vec(d))); - } - } - } - - c->set_output(0, c->MakeShape(dims)); - return Status::OK(); - } - return shape_inference::UnknownShape(c); -} - } // namespace REGISTER_OP("SparseAddGrad") @@ -446,7 +401,7 @@ REGISTER_OP("SparseReduceMax") .Attr("keep_dims: bool = False") .Output("output: T") .Attr("T: realnumbertype") - .SetShapeFn(SparseReduceShapeFn); + .SetShapeFn(shape_inference::SparseReduceShapeFn); REGISTER_OP("SparseReduceMaxSparse") .Input("input_indices: int64") @@ -468,7 +423,7 @@ REGISTER_OP("SparseReduceSum") .Attr("keep_dims: bool = False") .Output("output: T") .Attr("T: numbertype") - .SetShapeFn(SparseReduceShapeFn); + .SetShapeFn(shape_inference::SparseReduceShapeFn); REGISTER_OP("SparseReduceSumSparse") .Input("input_indices: int64") -- GitLab From 3043dc1546a807f4a5a770853c11e4de9a3e205b Mon Sep 17 00:00:00 2001 From: mrTsjolder Date: Tue, 6 Nov 2018 10:02:28 +0100 Subject: [PATCH 065/672] update references and unify citation style Refer to published work if possible. Use (author-year) style in text and have links in `References` field of docs. --- tensorflow/python/ops/init_ops.py | 72 +++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/tensorflow/python/ops/init_ops.py b/tensorflow/python/ops/init_ops.py index 4fe6d05620..a7978a2985 100644 --- a/tensorflow/python/ops/init_ops.py +++ b/tensorflow/python/ops/init_ops.py @@ -360,8 +360,7 @@ class UniformUnitScaling(Initializer): A similar calculation for convolutional networks gives an analogous result with `dim` equal to the product of the first 3 dimensions. When nonlinearities are present, we need to multiply this by a constant `factor`. - See [Sussillo et al., 2014](https://arxiv.org/abs/1412.6558) - ([pdf](http://arxiv.org/pdf/1412.6558.pdf)) for deeper motivation, experiments + See (Sussillo et al., 2014) for deeper motivation, experiments and the calculation of constants. In section 2.3 there, the constants were numerically computed: for a linear layer it's 1.0, relu: ~1.43, tanh: ~1.15. @@ -371,6 +370,10 @@ class UniformUnitScaling(Initializer): `tf.set_random_seed` for behavior. dtype: The data type. Only floating point types are supported. + + References: + [Sussillo et al., 2014](https://arxiv.org/abs/1412.6558) + ([pdf](http://arxiv.org/pdf/1412.6558.pdf)) """ @deprecated(None, @@ -532,6 +535,10 @@ class Orthogonal(Initializer): `tf.set_random_seed` for behavior. dtype: The data type. + + References: + [Saxe et al., 2014](https://openreview.net/forum?id=_wzZwKpTDF_9C) + ([pdf](https://arxiv.org/pdf/1312.6120.pdf)) """ def __init__(self, gain=1.0, seed=None, dtype=dtypes.float32): @@ -576,7 +583,7 @@ class ConvolutionDeltaOrthogonal(Initializer): The shape of the tensor must have length 3, 4 or 5. The number of input filters must not exceed the number of output filters. The center pixels of the tensor form an orthogonal matrix. Other pixels are set to be zero. See - algorithm 2 in [Xiao et al., 2018]: https://arxiv.org/abs/1806.05393 + algorithm 2 in (Xiao et al., 2018). Args: @@ -586,6 +593,10 @@ class ConvolutionDeltaOrthogonal(Initializer): seed: A Python integer. Used to create random seeds. See `tf.set_random_seed` for behavior. dtype: The data type. + + References: + [Xiao et al., 2018](http://proceedings.mlr.press/v80/xiao18a.html) + ([pdf](http://proceedings.mlr.press/v80/xiao18a/xiao18a.pdf)) """ def __init__(self, gain=1.0, seed=None, dtype=dtypes.float32): @@ -642,6 +653,10 @@ class ConvolutionOrthogonal(Initializer): seed: A Python integer. Used to create random seeds. See `tf.set_random_seed` for behavior. dtype: The data type. + + References: + [Xiao et al., 2018](http://proceedings.mlr.press/v80/xiao18a.html) + ([pdf](http://proceedings.mlr.press/v80/xiao18a/xiao18a.pdf)) """ def __init__(self, gain=1.0, seed=None, dtype=dtypes.float32): @@ -698,7 +713,7 @@ class ConvolutionOrthogonal2D(ConvolutionOrthogonal): filters must not exceed the number of output filters. The orthogonality(==isometry) is exact when the inputs are circular padded. There are finite-width effects with non-circular padding (e.g. zero padding). - See algorithm 1 in [Xiao et al., 2018]: https://arxiv.org/abs/1806.05393 + See algorithm 1 in (Xiao et al., 2018). Args: gain: Multiplicative factor to apply to the orthogonal matrix. Default is 1. @@ -707,6 +722,10 @@ class ConvolutionOrthogonal2D(ConvolutionOrthogonal): seed: A Python integer. Used to create random seeds. See `tf.set_random_seed` for behavior. dtype: The data type. + + References: + [Xiao et al., 2018](http://proceedings.mlr.press/v80/xiao18a.html) + ([pdf](http://proceedings.mlr.press/v80/xiao18a/xiao18a.pdf)) """ def __call__(self, shape, dtype=None, partition_info=None): @@ -834,7 +853,7 @@ class ConvolutionOrthogonal1D(ConvolutionOrthogonal): filters must not exceed the number of output filters. The orthogonality(==isometry) is exact when the inputs are circular padded. There are finite-width effects with non-circular padding (e.g. zero padding). - See algorithm 1 in [Xiao et al., 2018]: https://arxiv.org/abs/1806.05393 + See algorithm 1 in (Xiao et al., 2018). Args: gain: Multiplicative factor to apply to the orthogonal matrix. Default is 1. @@ -844,6 +863,10 @@ class ConvolutionOrthogonal1D(ConvolutionOrthogonal): `tf.set_random_seed` for behavior. dtype: The data type. + + References: + [Xiao et al., 2018](http://proceedings.mlr.press/v80/xiao18a.html) + ([pdf](http://proceedings.mlr.press/v80/xiao18a/xiao18a.pdf)) """ def __call__(self, shape, dtype=None, partition_info=None): @@ -951,7 +974,7 @@ class ConvolutionOrthogonal3D(ConvolutionOrthogonal): filters must not exceed the number of output filters. The orthogonality(==isometry) is exact when the inputs are circular padded. There are finite-width effects with non-circular padding (e.g. zero padding). - See algorithm 1 [Xiao et al., 2018] in: https://arxiv.org/abs/1806.05393 + See algorithm 1 (Xiao et al., 2018). Args: gain: Multiplicative factor to apply to the orthogonal matrix. Default is 1. @@ -960,6 +983,10 @@ class ConvolutionOrthogonal3D(ConvolutionOrthogonal): seed: A Python integer. Used to create random seeds. See `tf.set_random_seed` for behavior. dtype: The data type. + + References: + [Xiao et al., 2018](http://proceedings.mlr.press/v80/xiao18a.html) + ([pdf](http://proceedings.mlr.press/v80/xiao18a/xiao18a.pdf)) """ def __call__(self, shape, dtype=None, partition_info=None): @@ -1139,13 +1166,15 @@ class GlorotUniform(VarianceScaling): where `fan_in` is the number of input units in the weight tensor and `fan_out` is the number of output units in the weight tensor. - Reference: http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf - Args: seed: A Python integer. Used to create random seeds. See `tf.set_random_seed` for behavior. dtype: The data type. Only floating point types are supported. + + References: + [Glorot et al., 2010](http://proceedings.mlr.press/v9/glorot10a.html) + ([pdf](http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf)) """ def __init__(self, @@ -1181,13 +1210,15 @@ class GlorotNormal(VarianceScaling): where `fan_in` is the number of input units in the weight tensor and `fan_out` is the number of output units in the weight tensor. - Reference: http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf - Args: seed: A Python integer. Used to create random seeds. See `tf.set_random_seed` for behavior. dtype: The data type. Only floating point types are supported. + + References: + [Glorot et al., 2010](http://proceedings.mlr.press/v9/glorot10a.html) + ([pdf](http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf)) """ def __init__(self, @@ -1244,9 +1275,11 @@ def lecun_normal(seed=None): An initializer. References: - - [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515) - - [Efficient - Backprop](http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf) + - Self-Normalizing Neural Networks, + [Klambauer et al., 2017](https://papers.nips.cc/paper/6698-self-normalizing-neural-networks) + ([pdf](https://papers.nips.cc/paper/6698-self-normalizing-neural-networks.pdf)) + - Efficient Backprop, + [Lecun et al., 1998](http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf) """ return VarianceScaling( scale=1., mode="fan_in", distribution="truncated_normal", seed=seed) @@ -1267,8 +1300,11 @@ def lecun_uniform(seed=None): An initializer. References: - LeCun 98, Efficient Backprop, - http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf + - Self-Normalizing Neural Networks, + [Klambauer et al., 2017](https://papers.nips.cc/paper/6698-self-normalizing-neural-networks) + ([pdf](https://papers.nips.cc/paper/6698-self-normalizing-neural-networks.pdf)) + - Efficient Backprop, + [Lecun et al., 1998](http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf) """ return VarianceScaling( scale=1., mode="fan_in", distribution="uniform", seed=seed) @@ -1289,7 +1325,8 @@ def he_normal(seed=None): An initializer. References: - He et al., http://arxiv.org/abs/1502.01852 + [He et al., 2015](https://www.cv-foundation.org/openaccess/content_iccv_2015/html/He_Delving_Deep_into_ICCV_2015_paper.html) + ([pdf](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/He_Delving_Deep_into_ICCV_2015_paper.pdf)) """ return VarianceScaling( scale=2., mode="fan_in", distribution="truncated_normal", seed=seed) @@ -1310,7 +1347,8 @@ def he_uniform(seed=None): An initializer. References: - He et al., http://arxiv.org/abs/1502.01852 + [He et al., 2015](https://www.cv-foundation.org/openaccess/content_iccv_2015/html/He_Delving_Deep_into_ICCV_2015_paper.html) + ([pdf](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/He_Delving_Deep_into_ICCV_2015_paper.pdf)) """ return VarianceScaling( scale=2., mode="fan_in", distribution="uniform", seed=seed) -- GitLab From f60e430827c759755922cdaea80ae6af954cb934 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 6 Nov 2018 15:33:35 -0800 Subject: [PATCH 066/672] Quantization-aware training full test on MNIST --- .../tensorrt/test/quantization_mnist_test.py | 197 ++++++++++++++++++ .../quantization_mnist_test_data/checkpoint | 2 + .../model.ckpt-14070.data-00000-of-00001 | Bin 0 -> 686728 bytes .../model.ckpt-14070.index | Bin 0 -> 961 bytes 4 files changed, 199 insertions(+) create mode 100644 tensorflow/contrib/tensorrt/test/quantization_mnist_test.py create mode 100644 tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/checkpoint create mode 100644 tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 create mode 100644 tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py new file mode 100644 index 0000000000..e648c3388f --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py @@ -0,0 +1,197 @@ +import tensorflow as tf +import tensorflow.contrib.tensorrt as trt +import numpy as np +import argparse +from tensorflow.python.framework import test_util +from tensorflow.python.platform import test + +INPUT_NODE_NAME = 'input' +OUTPUT_NODE_NAME = 'output' + +def build_graph(x): + def quantize(x, r): + x = tf.fake_quant_with_min_max_args(x, -r, r) + return x + + def dense_layer(x, num_inputs, num_outputs, quantization_range, name='dense'): + """Equivalent to tf.layers.dense but with a quantization range between + the MatMul and BiasAdd.""" + with tf.variable_scope(name) as scope: + kernel = tf.get_variable('kernel', shape=[num_inputs, num_outputs], + dtype=tf.float32, initializer=tf.keras.initializers.glorot_uniform()) + bias = tf.get_variable('bias', shape=[num_outputs,], + dtype=tf.float32, initializer=tf.keras.initializers.zeros()) + x = tf.matmul(x, kernel) + x = quantize(x, quantization_range) + x = tf.nn.bias_add(x, bias) + return x + + x = quantize(x, 1) + # Conv + Bias + Relu6 + x = tf.layers.conv2d(x, filters=32, kernel_size=3, use_bias=True) + x = tf.nn.relu6(x) + # Conv + Bias + Relu6 + x = tf.layers.conv2d(x, filters=64, kernel_size=3, use_bias=True) + x = tf.nn.relu6(x) + x = tf.reduce_mean(x, [1, 2]) + x = quantize(x, 6) + # FC1 + x = dense_layer(x, 64, 512, 6, name='dense') + x = quantize(x, 6) + x = tf.nn.relu6(x) + # FC2 + x = dense_layer(x, 512, 10, 25, name='dense_1') + x = quantize(x, 25) + x = tf.identity(x, name=OUTPUT_NODE_NAME) + return x + +def preprocess_fn(x, y): + x = tf.cast(x, tf.float32) + x = tf.expand_dims(x, axis=2) + x = 2.0 * (x / 255.0) - 1.0 + y = tf.cast(y, tf.int32) + return x, y + +def run(is_training, use_trt, batch_size, num_epochs, model_dir): + """Train or evaluate the model. + + Args: + is_training: Whether to train or evaluate the model. In training mode, + quantization will be simulated where the fake_quant_with_min_max_args + are placed. + use_trt: If true, use TRT INT8 mode for evaluation, which will perform real + quantization. Otherwise use native TensorFlow which will perform + simulated quantization. Ignored if is_training is True. + batch_size: Batch size. + num_epochs: How many epochs to train. Ignored if is_training is False. + model_dir: Where to save or load checkpoint. + """ + # Get dataset + train, test = tf.keras.datasets.mnist.load_data() + + def eval_input_fn(): + mnist_x, mnist_y = test + dataset = tf.data.Dataset.from_tensor_slices((mnist_x, mnist_y)) + dataset = dataset.apply(tf.data.experimental.map_and_batch( + map_func=preprocess_fn, + batch_size=batch_size, + num_parallel_calls=8)) + dataset = dataset.prefetch(buffer_size=tf.contrib.data.AUTOTUNE) + dataset = dataset.repeat(count=1) + iterator = dataset.make_one_shot_iterator() + features, labels = iterator.get_next() + return features, labels + + def train_input_fn(): + mnist_x, mnist_y = train + dataset = tf.data.Dataset.from_tensor_slices((mnist_x, mnist_y)) + dataset = dataset.shuffle(2*len(mnist_x)) + dataset = dataset.apply(tf.data.experimental.map_and_batch( + map_func=preprocess_fn, + batch_size=batch_size, + num_parallel_calls=8)) + dataset = dataset.prefetch(buffer_size=tf.contrib.data.AUTOTUNE) + dataset = dataset.repeat(count=num_epochs) + iterator = dataset.make_one_shot_iterator() + features, labels = iterator.get_next() + return features, labels + + def model_fn(features, labels, mode): + if is_training: + logits_out = build_graph(features) + else: + graph_def = get_graph_def(use_trt, batch_size, model_dir) + logits_out = tf.import_graph_def(graph_def, + input_map={INPUT_NODE_NAME: features}, + return_elements=[OUTPUT_NODE_NAME+':0'], + name='')[0] + loss = tf.losses.sparse_softmax_cross_entropy( + labels=labels, + logits=logits_out) + tf.summary.scalar('loss', loss) + classes_out = tf.argmax(logits_out, axis=1, name='classes_out') + accuracy = tf.metrics.accuracy( + labels=labels, + predictions=classes_out, + name='acc_op') + tf.summary.scalar('accuracy', accuracy[1]) + if mode == tf.estimator.ModeKeys.EVAL: + return tf.estimator.EstimatorSpec( + mode, + loss=loss, + eval_metric_ops={'accuracy': accuracy}) + elif mode == tf.estimator.ModeKeys.TRAIN: + optimizer = tf.train.AdamOptimizer(learning_rate=1e-2) + train_op = optimizer.minimize( + loss, + global_step=tf.train.get_global_step()) + return tf.estimator.EstimatorSpec( + mode, + loss=loss, + train_op=train_op) + + tf_config = tf.ConfigProto() + tf_config.gpu_options.allow_growth = True + estimator = tf.estimator.Estimator( + model_fn=model_fn, + model_dir=model_dir, + config=tf.estimator.RunConfig(session_config=tf_config)) + if is_training: + estimator.train(train_input_fn) + results = estimator.evaluate(eval_input_fn) + print('accuracy:', results['accuracy']) + return results + +def get_graph_def(use_trt, batch_size, model_dir): + # Load graph and freeze + with tf.Graph().as_default() as graph: + with tf.Session() as sess: + x = tf.placeholder(shape=(None, 28, 28, 1), + dtype=tf.float32, + name=INPUT_NODE_NAME) + logits_out = build_graph(x) + # Load weights + saver = tf.train.Saver() + checkpoint_file = tf.train.latest_checkpoint(model_dir) + saver.restore(sess, checkpoint_file) + # Freeze + graph_def = tf.graph_util.convert_variables_to_constants( + sess, + sess.graph_def, + output_node_names=[OUTPUT_NODE_NAME] + ) + # Convert with TF-TRT + if use_trt: + print('nodes before:', len(graph_def.node)) + graph_def = trt.create_inference_graph(graph_def, + outputs=[OUTPUT_NODE_NAME], + max_batch_size=batch_size, + precision_mode='int8', + max_workspace_size_bytes=4096 << 19, + minimum_segment_size=2, + use_calibration=False, + ) + print('tftrt total nodes:', len(graph_def.node)) + print('trt only nodes', + len([1 for n in graph_def.node if str(n.op)=='TRTEngineOp'])) + return graph_def + + +class QuantizationAwareTrainingMNISTTest(test_util.TensorFlowTestCase): + + def testEval(self): + acc_tf = run(is_training=False, + use_trt=False, + batch_size=128, + num_epochs=None, + model_dir='./quantization_mnist_test_data')['accuracy'] + acc_tftrt = run(is_training=False, + use_trt=True, + batch_size=128, + num_epochs=None, + model_dir='./quantization_mnist_test_data')['accuracy'] + self.assertAllClose(acc_tf, 0.9717) + self.assertAllClose(acc_tftrt, 0.9744) + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/checkpoint b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/checkpoint new file mode 100644 index 0000000000..4e69206e97 --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/checkpoint @@ -0,0 +1,2 @@ +model_checkpoint_path: "model.ckpt-14070" +all_model_checkpoint_paths: "model.ckpt-14070" diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 new file mode 100644 index 0000000000000000000000000000000000000000..c1876b7a4c53a13696bd5a5aabce09a7455e36d7 GIT binary patch literal 686728 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

vZd%xd(SYt9!aXY_Y`NPb)Kb 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

@H!{2liR=)l(KkK}p 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∨uwp|Q7Hvg9{wGM3iX5$t+V|Sa? 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

99!M?g{`dLyC`1MkP!eG8uE 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

a<}`@ryZol_#Xz#9YbW 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%0D(dy+X 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 literal 0 HcmV?d00001 diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index new file mode 100644 index 0000000000000000000000000000000000000000..d338a78f056628943e0d7a59899e11fa5444b717 GIT binary patch literal 961 zcmZQzVB=tvV&Y(A;O0(BElD(tFUT)XE#hDlV$fhQT~;k<#lp^Ogb-9<(O@w>WoOgF zz%7)VpI2s-qMwwRSj@pF#3IDRp`gH_(ZFb$JojM&H> zkg}UI);9?;$%C!IqDB;?CVPk2LpFBdctd0#I4E?;X*4jIx~>RW#f$0%2Zas=kd$AJ zPr4A27aSBiltAKF-@j|*WK+QE1qC4{4hMw}6^(`iET%#23!?d16|wmNs_qF3SmB)< zJ`NEkMGRj+RW0EJt2!33+KPcoG$l2!I2GmsX;u{RphgFm!UnL^oaVv^C7z#p<=5#SjC>p$sdH_ zZbnF7)c{M&RCmQPaPz0<NO#21&O7I1J1F(@>A)zsiHozOD*J_7>-!%Id61||^W y(DO~%Aes?G9Qd?w0|O&-2E%JM5Em@gvh&&A4{RKN+4w<1_;L8}hHjNo_uBx6l+IZI literal 0 HcmV?d00001 -- GitLab From de0ed5a2bf01342d4c23357d3abf39eb68bb0b2a Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 6 Nov 2018 15:44:39 -0800 Subject: [PATCH 067/672] Add quantization mnist test to BUILD --- tensorflow/contrib/tensorrt/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/contrib/tensorrt/BUILD b/tensorflow/contrib/tensorrt/BUILD index 64a2fd50c3..1721305d6d 100644 --- a/tensorflow/contrib/tensorrt/BUILD +++ b/tensorflow/contrib/tensorrt/BUILD @@ -491,6 +491,7 @@ cuda_py_tests( "test/memory_alignment_test.py", "test/multi_connection_neighbor_engine_test.py", "test/neighboring_engine_test.py", + "test/quantization_mnist_test.py", "test/quantization_test.py", "test/rank_two_test.py", "test/reshape_transpose_test.py", -- GitLab From 47cbd92e296ba18149fb78b87726426475fcd2f4 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 7 Nov 2018 09:52:33 +0800 Subject: [PATCH 068/672] 'op name' -> 'op type' --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 65bd568f6c..e6c3916e5d 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2669,7 +2669,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( &transpose_nchw_in); // We use same name as original node, but change the op - // name. + // type. NodeBuilder nb(mklop->name(), mklop->type_string()); for (int i = 0; i < mklop_num_inputs; i++) { -- GitLab From 64329f85785c190467798f25a746291a813f192f Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 7 Nov 2018 09:56:58 +0800 Subject: [PATCH 069/672] Add a comment: storing the output slots of input nodes. --- tensorflow/core/graph/mkl_layout_pass.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index e6c3916e5d..01f1aa9078 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2672,6 +2672,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( // type. NodeBuilder nb(mklop->name(), mklop->type_string()); + // Storing the output slots of the input nodes. for (int i = 0; i < mklop_num_inputs; i++) { if (mklop_in[i].first == transpose_to_nhwc) { // Fill "x": -- GitLab From 81f02368365e096c27f37adc7c9af08905855ed1 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 7 Nov 2018 14:28:10 +0800 Subject: [PATCH 070/672] New algorithm applied to "CheckForNodeFusion()", to cover the pattern "A->B->C;A->C". --- tensorflow/core/graph/mkl_layout_pass.cc | 57 +++++++++++------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 01f1aa9078..fa32a3e061 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -915,17 +915,17 @@ class MklLayoutRewritePass : public GraphOptimizationPass { if (node->type_string() != "Transpose") return false; // If "Transpose" has multiple output data edges, also don't fuse it. - if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; + // if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. // Note: this constraint will eventually be removed, if we enabled this fusion for training // in the future. - for (const Edge* e : node->out_edges()) { - if (e->IsControlEdge()) { - return false; - } - } + // for (const Edge* e : node->out_edges()) { + // if (e->IsControlEdge()) { + // return false; + // } + // } // If "Transpose" has input control edges, don't fuse on it. for (const Edge* e : node->in_edges()) { @@ -2736,12 +2736,13 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { // std::stack> work_stack; - std::unordered_set visited_nodes; + std::stack current_neighbor_stack; auto node_checker = fi->node_checkers.begin(); Node *current_node = nullptr; if (a != nullptr) { work_stack.push(a); + current_neighbor_stack.push(a->out_edges().begin()); } while (!work_stack.empty()) { @@ -2759,33 +2760,29 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { return make_tuple(true, nodes, *fi_ptr); } - bool all_succ_has_been_visited = true; - for (const Edge *e : current_node->out_edges()) { - if (!e->IsControlEdge()) { - Node *candidate_node = e->dst(); - - // If the candidate node has not been visited, push it to stack. - if (visited_nodes.find(candidate_node) == visited_nodes.end()) { - work_stack.push(candidate_node); - ++ node_checker; - all_succ_has_been_visited = false; - break; - } - } - } - - // All successor nodes of current node has been visited (no match found), - // pop the stack and mark current node as "visited". - if (all_succ_has_been_visited) { - visited_nodes.insert(current_node); - work_stack.pop(); - -- node_checker; + auto ¤t_neighbor_iter = current_neighbor_stack.top(); + if (current_neighbor_iter == current_node->out_edges().end()) { + // All output edges have been exhausted, pop the stack + // and roll back to the preceding node. + work_stack.pop(); + current_neighbor_stack.pop(); + -- node_checker; + } else { + // Found a edge not been visited, go through this edge + // and get the next neighbor. + Node *neighbor_node = (*current_neighbor_iter)->dst(); + work_stack.push(neighbor_node); + current_neighbor_stack.push(neighbor_node->out_edges().begin()); + ++ node_checker; + + // Increase current_neighbor_iter, which is at the top of stack. + ++ current_neighbor_iter; } - } else { // current node doesn't match, pop stack to roll back. - visited_nodes.insert(current_node); + // visited_nodes.insert(current_node); work_stack.pop(); + current_neighbor_stack.pop(); -- node_checker; } } -- GitLab From 2ee1c5a0d6b99574f48e7f0de9b94559d824b022 Mon Sep 17 00:00:00 2001 From: Tongxuan Liu Date: Wed, 7 Nov 2018 14:44:12 +0800 Subject: [PATCH 071/672] RendezvousMgr & CancellationMgr are already aborted, shouldn't send RPC call any more When RendezvousMgr & CancellationMgr are already aborted, following RPC couldn't handled by CancellationMgr. At the moment, remote service is already closed, client would hang here. --- tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc | 8 ++++++++ .../core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc b/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc index 94f522c04e..fbccbead03 100644 --- a/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc +++ b/tensorflow/contrib/gdr/gdr_rendezvous_mgr.cc @@ -170,6 +170,14 @@ class GdrRemoteRendezvous : public BaseRemoteRendezvous { // Record "call" in active_ so that it can be aborted cleanly. RegisterCall(call); + // RendezvousMgr already aborted, shouldn't send RPC call any more + if (!call->status().ok()) { + done(call->status(), Args(), Args(), Tensor(), false); + session()->worker_cache->ReleaseWorker(src_worker, rwi); + delete call; + return; + } + // Start "call". Ref(); call->Start([this, call, src_worker, rwi, done]() { diff --git a/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc b/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc index b8cb538503..9fb920404f 100644 --- a/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc +++ b/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.cc @@ -244,6 +244,15 @@ void RpcRemoteRendezvous::RecvFromRemoteAsync( // Record "call" in active_ so that it can be aborted cleanly. RegisterCall(call); + // RendezvousMgr already aborted, shouldn't send RPC call any more + if (!call->status().ok()) { + call->done()(call->status(), Args(), Args(), Tensor(), false); + session()->worker_cache->ReleaseWorker(call->src_worker_, call->wi_); + call->wi_ = nullptr; + get_call_freelist()->Release(call, session()->worker_cache.get()); + return; + } + // Start "call". Ref(); call->Start([this, call]() { -- GitLab From 623b4fef5351713697ba1bd54a4a60945a6e2afa Mon Sep 17 00:00:00 2001 From: "Jiang,Zhoulong" Date: Fri, 9 Nov 2018 15:12:56 +0800 Subject: [PATCH 072/672] Fix memory leak issue in MklFusedBatchNorm --- tensorflow/core/util/mkl_util.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow/core/util/mkl_util.h b/tensorflow/core/util/mkl_util.h index 7988364716..8f40032924 100644 --- a/tensorflow/core/util/mkl_util.h +++ b/tensorflow/core/util/mkl_util.h @@ -1616,6 +1616,9 @@ class MklDnnData { cpu_engine_(e) {} ~MklDnnData() { + if (allocated_buffer_ != nullptr) { + cpu_allocator()->DeallocateRaw(allocated_buffer_); + } cpu_engine_ = nullptr; // We don't own this. delete (user_memory_); delete (reorder_memory_); -- GitLab From da089db8e6c868f7fab11e45cbea182daccdb393 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Fri, 9 Nov 2018 09:47:51 -0800 Subject: [PATCH 073/672] Fixes for @aaroey's review. Fix MNIST integration test imports and add the data dependencies as a build rule. GetWeightRange will now only be called in int8mode no calib mode. Make precision_mode a member of TrtCandidateSelect instead of argument to IsCandidate. Make precision_mode, use_calibration members of Converter Remove QINT8 from ConvertDType. Remove QINT8, UINT8, INT8, QUINT8 from RedorderCK. These are no longer needed after removing QuantizeV2 and Dequantize support. Refactor ApplyQuantizatioNRanges() to make it easier to test. ConvertQuantize will explicitly look for the different ops by name. Add checks to Relu6. Add unit tests for new functions in Converter. Add comments to clarify some logic --- tensorflow/contrib/tensorrt/BUILD | 23 +- .../contrib/tensorrt/convert/convert_graph.cc | 19 +- .../contrib/tensorrt/convert/convert_graph.h | 8 +- .../tensorrt/convert/convert_graph_test.cc | 10 +- .../contrib/tensorrt/convert/convert_nodes.cc | 178 +++++----- .../contrib/tensorrt/convert/convert_nodes.h | 17 +- .../tensorrt/convert/convert_nodes_test.cc | 315 +++++++++++++++--- .../contrib/tensorrt/segment/segment.cc | 4 +- tensorflow/contrib/tensorrt/segment/segment.h | 2 +- .../tensorrt/test/quantization_mnist_test.py | 55 ++- .../test/quantization_mnist_test_data/BUILD | 14 + ...f-00001 => model.ckpt.data-00000-of-00001} | Bin ...odel.ckpt-14070.index => model.ckpt.index} | Bin .../test/tf_trt_integration_test_base.py | 2 + 14 files changed, 476 insertions(+), 171 deletions(-) create mode 100644 tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/BUILD rename tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/{model.ckpt-14070.data-00000-of-00001 => model.ckpt.data-00000-of-00001} (100%) rename tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/{model.ckpt-14070.index => model.ckpt.index} (100%) diff --git a/tensorflow/contrib/tensorrt/BUILD b/tensorflow/contrib/tensorrt/BUILD index 1721305d6d..64c0fecf87 100644 --- a/tensorflow/contrib/tensorrt/BUILD +++ b/tensorflow/contrib/tensorrt/BUILD @@ -491,7 +491,6 @@ cuda_py_tests( "test/memory_alignment_test.py", "test/multi_connection_neighbor_engine_test.py", "test/neighboring_engine_test.py", - "test/quantization_mnist_test.py", "test/quantization_test.py", "test/rank_two_test.py", "test/reshape_transpose_test.py", @@ -510,6 +509,28 @@ cuda_py_tests( ], ) +cuda_py_tests( + name = "tf_trt_quantization_mnist_integration_test", + srcs = [ + "test/quantization_mnist_test.py", + ], + additional_deps = [ + ":tf_trt_integration_test_base", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python/keras:keras", + "//tensorflow/python/estimator:estimator", + ], + data =[ + "//tensorflow/contrib/tensorrt/test/quantization_mnist_test_data:quantization_mnist_data", + ], + tags = [ + "no_cuda_on_cpu_tap", + "no_windows", + "nomac", + ], +) + cuda_py_tests( name = "tf_trt_integration_test_no_oss", srcs = [ diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index b9c6dc7fde..b1443e7791 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -82,10 +82,11 @@ std::vector GetLoadedTensorRTVersion() { } TrtCandidateSelector::TrtCandidateSelector( - const grappler::GraphProperties& graph_properties) - : graph_properties_(graph_properties) {} + const grappler::GraphProperties& graph_properties, + int precision_mode) + : graph_properties_(graph_properties), precision_mode_(precision_mode) {} -Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node, int precision_mode) { +Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node) { // TODO(laigd): move this set to TrtNodeValidator where it should belong. // LINT.IfChange static const std::set candidate_ops = { @@ -134,14 +135,15 @@ Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node, i PluginFactoryTensorRT::GetInstance()->IsPlugin(node->type_string())); #if NV_TENSORRT_MAJOR >= 5 static const std::set quantize_ops = { - "QuantizeV2", - "Dequantize", "QuantizeAndDequantizeV2", "QuantizeAndDequantizeV3", "FakeQuantWithMinMaxVars", "FakeQuantWithMinMaxArgs", }; - if (precision_mode == INT8MODE && + // In INT8 mode, we will always apply the quantization ranges provided by + // these ops to the relevant tensors. This happens regardless of the value of + // use_calibration. + if (precision_mode_ == INT8MODE && quantize_ops.count(node->type_string())) { is_supported_op_type = true; } @@ -885,11 +887,12 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { segment_options.minimum_segment_size = params.minimum_segment_size; segment_options.precision_mode = params.precision_mode; tensorflow::tensorrt::segment::SegmentNodesVector initial_segments; - TrtCandidateSelector candidate_selector(*params.graph_properties); + TrtCandidateSelector candidate_selector(*params.graph_properties, + params.precision_mode); TF_RETURN_IF_ERROR(tensorrt::segment::SegmentGraph( &graph, std::bind(&TrtCandidateSelector::IsTensorRTCandidate, &candidate_selector, - std::placeholders::_1, std::placeholders::_2), + std::placeholders::_1), // Input validation is already done by TrtCandidateSelector, so we don't // need to check the input edges. [](const Edge* edge) { return true; }, OutputEdgeValidator(), diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.h b/tensorflow/contrib/tensorrt/convert/convert_graph.h index eaa1edbfe4..366d69115b 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.h +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.h @@ -35,17 +35,21 @@ namespace convert { // supported by TRT. class TrtCandidateSelector { public: - TrtCandidateSelector(const grappler::GraphProperties& graph_properties); + TrtCandidateSelector(const grappler::GraphProperties& graph_properties, + int precision_mode); // Returns OK iff 'node' is a TF-TRT conversion candidate, which will be added // to TRT subgraph and later converted into TRT engine. - Status IsTensorRTCandidate(const tensorflow::Node* node, int precision_mode); + Status IsTensorRTCandidate(const tensorflow::Node* node); private: // The TF-TRT node converter used to verify whether individual node is // supported. It will operate in validation-only mode. TrtNodeValidator validator_; + // Quantization ops are only converted when using quantized precisions. + int precision_mode_; + // GraphProperties of the graph whose nodes are to be validated by // IsTensorRTCandidate(). const grappler::GraphProperties& graph_properties_; diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc b/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc index 925de7885f..e2a7c40f30 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc @@ -93,17 +93,17 @@ TEST(TrtCandidateSelector, Basics) { grappler::GraphProperties graph_properties(item); TF_EXPECT_OK(graph_properties.InferStatically(true)); - TrtCandidateSelector selector(graph_properties); - TF_EXPECT_OK(selector.IsTensorRTCandidate(matmul.operation.node(), FP32MODE)); + TrtCandidateSelector selector(graph_properties, FP32MODE); + TF_EXPECT_OK(selector.IsTensorRTCandidate(matmul.operation.node())); ExpectStatus( - selector.IsTensorRTCandidate(incompatible_matmul.operation.node(), FP32MODE), + selector.IsTensorRTCandidate(incompatible_matmul.operation.node()), error::INVALID_ARGUMENT, "transpose_a is not supported for TensorRT FullyConnected " "(op: MatMul), at: incompatible_matmul"); - ExpectStatus(selector.IsTensorRTCandidate(unsupported_op.operation.node(), FP32MODE), + ExpectStatus(selector.IsTensorRTCandidate(unsupported_op.operation.node()), error::UNIMPLEMENTED, "Op type Sin is not supported"); ExpectStatus(selector.IsTensorRTCandidate( - matmul_with_incompatible_input.operation.node(), FP32MODE), + matmul_with_incompatible_input.operation.node()), error::INTERNAL, "Failed to convert input with index 0 to a TRT_TensorOrWeights"); } diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 456840e537..b8aa49506b 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -95,9 +95,6 @@ inline tensorflow::Status ConvertDType(tensorflow::DataType tf_dtype, case tensorflow::DataType::DT_INT8: *trt_dtype = nvinfer1::DataType::kINT8; break; - case tensorflow::DataType::DT_QINT8: - *trt_dtype = nvinfer1::DataType::kINT8; - break; case tensorflow::DataType::DT_HALF: *trt_dtype = nvinfer1::DataType::kHALF; break; @@ -637,16 +634,6 @@ void ReorderCKtoKC(const TRT_ShapedWeights& iweights, ostrides); break; } - case tensorflow::DataType::DT_INT8: - case tensorflow::DataType::DT_UINT8: - case tensorflow::DataType::DT_QINT8: - case tensorflow::DataType::DT_QUINT8: { - Reorder2({k, c}, static_cast(iweights.GetValues()), - istrides, - static_cast(const_cast(oweights->GetValues())), - ostrides); - break; - } default: LOG(FATAL) << "Unsupported type in reorder expected fp32 or fp16 but got " << DataTypeString(iweights.type_); @@ -799,8 +786,12 @@ Status TrtNodeValidator::ConvertConstToWeights( return status; } -Converter::Converter(nvinfer1::INetworkDefinition* trt_network, bool is_fp16) - : trt_network_(trt_network), is_fp16_(is_fp16) { +Converter::Converter(nvinfer1::INetworkDefinition* trt_network, + int precision_mode, + bool use_calibration) + : trt_network_(trt_network), + precision_mode_(precision_mode), + use_calibration_(use_calibration) { this->RegisterOpConverters(); } @@ -971,7 +962,7 @@ Status Converter::TransposeTensor(nvinfer1::ITensor* input_tensor, Status Converter::GetWeightRange(const TRT_ShapedWeights& weights, float* out_min, - float* out_max) { + float* out_max) const { switch (weights.type_) { case tensorflow::DataType::DT_FLOAT: { auto inp = static_cast(weights.GetValues()); @@ -987,9 +978,16 @@ Status Converter::GetWeightRange(const TRT_ShapedWeights& weights, *out_max = Eigen::half_impl::half_to_float(*result.second); break; } + case tensorflow::DataType::DT_INT32: { + auto inp = static_cast(weights.GetValues()); + auto result = std::minmax_element(inp, inp + weights.count()); + *out_min = static_cast(*result.first); + *out_max = static_cast(*result.second); + break; + } default: return tensorflow::errors::Unimplemented( - "Data type not supported: " + + "Data type not supported for GetWeightRange: " + tensorflow::DataTypeString(weights.type_)); } return tensorflow::Status::OK(); @@ -1030,21 +1028,24 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, this->network()->addConstant(dims, input.weights().GetTrtWeights()); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Reshape"); *tensor = layer->getOutput(0); - // We need to set a quantization range for the output tensor of the - // IConstantLayer. Here we set the range to [min(weights), max(weights)]. - float min_range = 0.0f; - float max_range = 0.0f; - TF_RETURN_IF_ERROR( - GetWeightRange(input.weights(), &min_range, &max_range)); - // Avoid setting range to 0 because TRT will throw an error. If the weights - // are zero then the range doesn't matter: using 127.0f should ensure the - // quantized weight will be exactly zero. - if (min_range == 0.0f && max_range == 0.0f) { - min_range = -127.0f; - max_range = 127.0f; - } - ProvideQuantizationRange(const_cast(*tensor), - min_range, max_range); + if (precision_mode() == INT8MODE && !use_calibration()) { + // If we are in int8 mode and not calibrating, we need to explicitly set a + // quantization range for the output tensor of the IConstantLayer. Here we + // set the range to [min(weights), max(weights)]. + float min_range = 0.0f; + float max_range = 0.0f; + TF_RETURN_IF_ERROR( + GetWeightRange(input.weights(), &min_range, &max_range)); + // Avoid setting range to 0 because TRT will throw an error. If the weights + // are zero then the range doesn't matter: using 127.0f should ensure the + // quantized weight will be exactly zero. + if (min_range == 0.0f && max_range == 0.0f) { + min_range = -127.0f; + max_range = 127.0f; + } + ProvideQuantizationRange(const_cast(*tensor), + min_range, max_range); + } } return tensorflow::Status::OK(); } @@ -1064,44 +1065,45 @@ void Converter::ProvideQuantizationRange(nvinfer1::ITensor* tensor, void Converter::ApplyQuantizationRanges(bool warn_missing_ranges) { // Infer ranges across marked ops PropagateQuantizationRanges(); - // Get all tensors from network - std::set all_tensors; - std::set tensors_missing_ranges; - for (int i = 0; i < this->network()->getNbLayers(); i++) { - nvinfer1::ILayer* layer = this->network()->getLayer(i); - for (int j = 0; j < layer->getNbInputs(); j++) - all_tensors.insert(layer->getInput(j)); - for (int j = 0; j < layer->getNbOutputs(); j++) - all_tensors.insert(layer->getOutput(j)); - } // Apply ranges - for (auto tensor : all_tensors) { - auto it = quantization_ranges_.find(tensor); - if (it != quantization_ranges_.end()) { - float range = it->second; - VLOG(1) << "Setting range for: " << tensor->getName() << ": " << range; + for (auto pair : quantization_ranges_) { + nvinfer1::ITensor* tensor = pair.first; + const float range = pair.second; #if NV_TENSORRT_MAJOR >= 5 - tensor->setDynamicRange(-range, range); + VLOG(1) << "Setting range for: " << tensor->getName() << ": " << range; + tensor->setDynamicRange(-range, range); #endif - } else { - tensors_missing_ranges.insert(tensor); - } } + // Warn user about tensors that are missing ranges. If TRT fuses some layers // then these tensors may not actually be required, which is why this is // just a warning. If we are still missing ranges even after fusion, // Builder::buildCudaEngine() will return nullptr and we will catch the // error at that point. if (warn_missing_ranges) { - for (auto tensor : tensors_missing_ranges) { - // Note: there may be some warnings for "(Unnamed ITensor* N)". These - // are tensors which are created internally by TF-TRT. The ranges for - // these unnamed ITensors are always inferred from user provided ranges, - // thus there will also be a warning for the range(s) the user missed. - LOG(WARNING) << "Quantization range was not found for " - << tensor->getName() << ". " - << "This might be okay if TensorRT does not need the range" - << "(e.g. due to node fusion)."; + // Get all tensors from network + std::set all_tensors; + for (int i = 0; i < this->network()->getNbLayers(); i++) { + nvinfer1::ILayer* layer = this->network()->getLayer(i); + for (int j = 0; j < layer->getNbInputs(); j++) { + all_tensors.insert(layer->getInput(j)); + } + for (int j = 0; j < layer->getNbOutputs(); j++) { + all_tensors.insert(layer->getOutput(j)); + } + } + // Find tensors with no ranges + for (auto tensor : all_tensors) { + if (quantization_ranges_.find(tensor) == quantization_ranges_.end()) { + // Note: there may be some warnings for "(Unnamed ITensor* N)". These + // are tensors which are created internally by TF-TRT. The ranges for + // these unnamed ITensors are always inferred from user provided ranges, + // thus there will also be a warning for the range(s) the user missed. + LOG(WARNING) << "Quantization range was not found for " + << tensor->getName() << ". " + << "This is okay if TensorRT does not need the range " + << "(e.g. due to node fusion)."; + } } } } @@ -1446,7 +1448,7 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, } } - if (params->converter->is_fp16()) { + if (params->converter->precision_mode() == FP16MODE) { weights = ConvertFP32ToFP16(params->weight_store, weights); } @@ -1549,7 +1551,7 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) { return tensorflow::errors::Internal( "Conv2D expects kernel of dimension 4, at: " + node_def.name()); } - if (params->converter->is_fp16()) { + if (params->converter->precision_mode() == FP16MODE) { weights_rsck = ConvertFP32ToFP16(params->weight_store, inputs.at(1).weights()); } @@ -1986,7 +1988,16 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { tensorflow::Status ConvertQuantize(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; - if (inputs.size() > 0 && inputs.at(0).is_weights()) { + if ((inputs.size() == 0) || + (inputs.size() != 1 && node_def.op() == "FakeQuantWithMinMaxArgs") || + (inputs.size() != 3 && node_def.op() == "FakeQuantWithMinMaxVars") || + (inputs.size() != 3 && node_def.op() == "QuantizeAndDequantizeV2") || + (inputs.size() != 4 && node_def.op() == "QuantizeAndDequantizeV3")) { + return tensorflow::errors::InvalidArgument( + "Invalid number of inputs for ", node_def.op(), ", at ", + node_def.name()); + } + if (inputs.at(0).is_weights()) { // TensorRT will automatically quantize weights, so we will ignore ranges // for weights. params->outputs->push_back(inputs.at(0)); @@ -1994,21 +2005,24 @@ tensorflow::Status ConvertQuantize(OpConverterParams* params) { } float min_range = 0.0f; float max_range = 0.0f; - if (inputs.size() == 1) { - // Get ranges from attributes + if (node_def.op() == "FakeQuantWithMinMaxArgs") { + // Get ranges via node attributes. TFAttrs attrs(node_def); if (attrs.count("min") == 0 || attrs.count("max") == 0) { return tensorflow::errors::InvalidArgument( - "Min or max attribute not found for quantize, at ", node_def.name()); + "Min or max attribute not found for ", node_def.op(), " at ", + node_def.name()); } min_range = attrs.get("min"); max_range = attrs.get("max"); - } else if (inputs.size() == 3) { - // Get ranges from inputs + } else if (node_def.op() == "FakeQuantWithMinMaxVars" || + node_def.op() == "QuantizeAndDequantizeV2" || + node_def.op() == "QuantizeAndDequantizeV3") { + // Get ranges via inputs. if (!inputs.at(1).is_weights() || !inputs.at(2).is_weights()) { return tensorflow::errors::InvalidArgument( - "Min and max for quantize must be weights not tensors, at ", - node_def.name()); + "Min and max inputs for ", node_def.op(), + " must be weights not tensors, at ", node_def.name()); } // Min TRT_ShapedWeights weights_min = inputs.at(1).weights(); @@ -2022,7 +2036,8 @@ tensorflow::Status ConvertQuantize(OpConverterParams* params) { max_range = weights_max_ptr[0]; } else { return tensorflow::errors::InvalidArgument( - "Expected 1 or 3 inputs for quantize node, at ", node_def.name()); + "Unknown quantization op \"", node_def.op(), "\", at ", + node_def.name()); } // Store ranges for tensor params->converter->ProvideQuantizationRange( @@ -2047,6 +2062,16 @@ tensorflow::Status ConvertQuantize(OpConverterParams* params) { tensorflow::Status ConvertRelu6(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; + if (inputs.size() != 1) { + return tensorflow::errors::InvalidArgument( + "Invalid number of inputs for Relu6, at ", + node_def.name()); + } + if (inputs.at(0).is_weights()) { + return tensorflow::errors::Unimplemented( + "Relu6 is only implemented for tensors, not weights, at ", + node_def.name()); + } // *************************************************************************** // TensorRT does not implement Relu6 natively. This function converts Relu6 op // to available TensorRT ops: Relu6(x) = min(Relu(x), 6) @@ -2075,8 +2100,9 @@ tensorflow::Status ConvertRelu6(OpConverterParams* params) { // broadcast nvinfer1::Dims dims; dims.nbDims = relu_layer->getOutput(0)->getDimensions().nbDims; - for (int i = 0; i < dims.nbDims; i++) + for (int i = 0; i < dims.nbDims; i++) { dims.d[i] = 1; + } TRT_ShapedWeights weights = params->weight_store->GetTempWeights( tensorflow::DataType::DT_FLOAT, dims); auto weights_ptr = static_cast(const_cast( @@ -2091,7 +2117,7 @@ tensorflow::Status ConvertRelu6(OpConverterParams* params) { // ElementWise Min Operation // Min op is a nop for INT8 execution path, as the input tensor // to this layer will only have values in range [0.f, 6.0f]. - const nvinfer1::ITensor* tensor_l = relu_layer->getOutput(0); + const nvinfer1::ITensor* tensor_l = relu_layer->getOutput(0); const nvinfer1::ITensor* tensor_r = const6_layer->getOutput(0); nvinfer1::IElementWiseLayer* relu6_layer = params->converter->network()->addElementWise( @@ -2117,7 +2143,7 @@ tensorflow::Status ConvertScale(OpConverterParams* params) { const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); TRT_ShapedWeights weights = inputs.at(1).weights(); - if (params->converter->is_fp16()) { + if (params->converter->precision_mode() == FP16MODE) { weights = ConvertFP32ToFP16(params->weight_store, inputs.at(1).weights()); } @@ -3082,8 +3108,6 @@ void Converter::RegisterOpConverters() { op_registry_["TopKV2"] = ConvertTopK; op_registry_["Relu6"] = ConvertRelu6; # if NV_TENSORRT_MAJOR >= 5 - op_registry_["QuantizeV2"] = ConvertQuantize; - op_registry_["Dequantize"] = ConvertQuantize; op_registry_["QuantizeAndDequantizeV2"] = ConvertQuantize; op_registry_["QuantizeAndDequantizeV3"] = ConvertQuantize; op_registry_["FakeQuantWithMinMaxVars"] = ConvertQuantize; @@ -3132,7 +3156,7 @@ tensorflow::Status ConvertGraphDefToEngine( // Build the network VLOG(1) << "Starting engine conversion "; - Converter converter(trt_network.get(), precision_mode == FP16MODE); + Converter converter(trt_network.get(), precision_mode, use_calibration); std::vector> output_tensors; // Graph nodes are already topologically sorted during construction for (const auto& node_def : gdef.node()) { diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.h b/tensorflow/contrib/tensorrt/convert/convert_nodes.h index ec9cea38d5..78749124a2 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.h +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.h @@ -395,7 +395,9 @@ class TrtNodeValidator { // Class to convert TF nodes to TRT network. class Converter { public: - Converter(nvinfer1::INetworkDefinition* trt_network, bool is_fp16); + Converter(nvinfer1::INetworkDefinition* trt_network, + int precision_mode, + bool use_calibration); ////////////////////////////////////////////////////////////////////////////// // Methods used by the TRT engine builder to build a TRT network from a TF @@ -425,8 +427,11 @@ class Converter { // to add TRT layers. nvinfer1::INetworkDefinition* network() { return trt_network_; } - // Is the converter operating in fp16 mode? - bool is_fp16() const { return is_fp16_; } + // What precision are we targeting? + int precision_mode() const { return precision_mode_; } + + // Calibration will be or was previously performed on this network? + bool use_calibration() const { return use_calibration_; } // This should be called on the inputs and outputs of any layer we create // where we know that the quantization range does not change during that @@ -480,7 +485,7 @@ class Converter { // Gets the min and max value in a TRT_ShapedWeights Status GetWeightRange(const TRT_ShapedWeights& weights, - float* out_min, float* out_max); + float* out_min, float* out_max) const; // Registered op converters by op type. std::unordered_map op_registry_; @@ -513,7 +518,9 @@ class Converter { std::vector> quantization_infer_; - const bool is_fp16_; + const int precision_mode_; + + const bool use_calibration_; // Batch size of inputs to trt_network_ added by AddInputTensor(). During // network construction it will update this, use it to verify the batch diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 38df6995b6..77cf3e7ef0 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -133,11 +133,12 @@ void ValidateWeights(const TRT_ShapedWeights& weights, // Fake ITensor implementation for testing purposes. class FakeITensor : public nvinfer1::ITensor { public: - FakeITensor() {} + FakeITensor() : dynamic_range_(0.0f) {} - FakeITensor(const nvinfer1::Dims& dims) : dims_(dims) {} + FakeITensor(const nvinfer1::Dims& dims) : dims_(dims), dynamic_range_(0.0f) {} - FakeITensor(const std::vector& dims) : dims_(GetTestDims(dims)) {} + FakeITensor(const std::vector& dims) : dims_(GetTestDims(dims)), + dynamic_range_(0.0f) {} void setName(const char* name) override { name_ = name; } @@ -166,7 +167,12 @@ class FakeITensor : public nvinfer1::ITensor { } #if NV_TENSORRT_MAJOR >= 5 - bool setDynamicRange(float min, float max) override {} + bool setDynamicRange(float min, float max) override { + dynamic_range_ = std::max(std::abs(min), std::abs(max)); + return true; + } + + float getDynamicRange() { return dynamic_range_; } #endif private: @@ -174,6 +180,7 @@ class FakeITensor : public nvinfer1::ITensor { nvinfer1::Dims dims_; nvinfer1::DataType type_; nvinfer1::TensorLocation location_; + float dynamic_range_; }; TEST(TRT_ShapedWeights_Test, Basic) { @@ -405,7 +412,9 @@ class ConverterTest : public ::testing::Test { ConverterTest() { builder_.reset(nvinfer1::createInferBuilder(logger_)); network_.reset(builder_->createNetwork()); - converter_.reset(new Converter(network_.get(), /*fp16=*/false)); + converter_.reset(new Converter(network_.get(), + /*precision_mode=*/FP32MODE, + /*use_calibration=*/false)); weight_store_ = &converter_->weight_store_; } @@ -432,10 +441,19 @@ class ConverterTest : public ::testing::Test { return converter_->GetInputs(node_def, inputs); } + Status GetWeightRange(const TRT_ShapedWeights& weights, + float* out_min, float* out_max) const { + return converter_->GetWeightRange(weights, out_min, out_max); + } + + void PropagateQuantizationRanges() { + converter_->PropagateQuantizationRanges(); + } + int batch_size() const { return converter_->batch_size_; } - std::unordered_map* GetQuantizationRanges() { - return &quantization_ranges_; + std::unordered_map& quantization_ranges() { + return converter_->quantization_ranges_; } private: @@ -660,6 +678,82 @@ TEST_F(ConverterTest, AddAndGetTensorOrWeights) { "tensor/weights my_tensor already exist"); } +TEST_F(ConverterTest, GetWeightRange) { + TRT_ShapedWeights weights = + weight_store_->GetTempWeights(DT_FLOAT, GetTestDims({2, 3})); + const std::vector values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; + memcpy(const_cast(weights.GetValues()), values.data(), + weights.size_bytes()); + + float out_min = 0.0f; + float out_max = 0.0f; + TF_EXPECT_OK(GetWeightRange(weights, &out_min, &out_max)); + EXPECT_EQ(1.0f, out_min); + EXPECT_EQ(6.0f, out_max); +} + +TEST_F(ConverterTest, ProvideQuantizationRange) { + FakeITensor fake_tensor; + // Assymetric range + converter_->ProvideQuantizationRange(&fake_tensor, 0.0f, 6.0f); + EXPECT_EQ(quantization_ranges()[&fake_tensor], 6.0f); + converter_->ProvideQuantizationRange(&fake_tensor, 1.0f, 6.0f); + EXPECT_EQ(quantization_ranges()[&fake_tensor], 6.0f); + converter_->ProvideQuantizationRange(&fake_tensor, -8.0f, 6.0f); + EXPECT_EQ(quantization_ranges()[&fake_tensor], 8.0f); + converter_->ProvideQuantizationRange(&fake_tensor, -8.123f, -6.123f); + EXPECT_EQ(quantization_ranges()[&fake_tensor], 8.123f); + // Symmetric range + converter_->ProvideQuantizationRange(&fake_tensor, -6.123f, 6.123f); + EXPECT_EQ(quantization_ranges()[&fake_tensor], 6.123f); +} + +TEST_F(ConverterTest, ApplyQuantizationRanges) { + // input -> infer1 -> infer2 -> infer3 + FakeITensor input; + FakeITensor infer_1; + FakeITensor infer_2; + FakeITensor infer_3; + FakeITensor not_infer; + converter_->ProvideQuantizationRange(&input, -5.0f, 5.0f); + converter_->ProvideQuantizationRange(¬_infer, -100.0f, 100.0f); + converter_->MarkQuantizationRangesAsInferrable(&input, &infer_1); + converter_->MarkQuantizationRangesAsInferrable(&infer_1, &infer_2); + converter_->MarkQuantizationRangesAsInferrable(&infer_2, &infer_3); + + // Input range should be inferred along the chain and applied to tensors. + converter_->ApplyQuantizationRanges(/*warn_missing_ranges=*/false); +#if NV_TENSORRT_MAJOR >= 5 + EXPECT_EQ(input.getDynamicRange(), 5.0f); + EXPECT_EQ(infer_1.getDynamicRange(), 5.0f); + EXPECT_EQ(infer_2.getDynamicRange(), 5.0f); + EXPECT_EQ(infer_3.getDynamicRange(), 5.0f); + EXPECT_EQ(not_infer.getDynamicRange(), 100.0f); +#endif +} + +TEST_F(ConverterTest, PropagateQuantizationRanges) { + // input <-> infer1 <-> infer2 <-> infer3 + FakeITensor input; + FakeITensor infer_1; + FakeITensor infer_2; + FakeITensor infer_3; + FakeITensor not_infer; + converter_->ProvideQuantizationRange(&input, -5.0f, 5.0f); + converter_->MarkQuantizationRangesAsInferrable(&input, &infer_1); + converter_->MarkQuantizationRangesAsInferrable(&infer_1, &infer_2); + converter_->MarkQuantizationRangesAsInferrable(&infer_3, &infer_2); + + // Input range should be inferred along the chain. + PropagateQuantizationRanges(); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges[&input], 5.0f); + EXPECT_EQ(ranges[&infer_1], 5.0f); + EXPECT_EQ(ranges[&infer_2], 5.0f); + EXPECT_EQ(ranges[&infer_3], 5.0f); + EXPECT_EQ(ranges.count(¬_infer), 0); +} + // Class to test various op converters, using both a TrtNodeValidator and // Converter. class OpConverterTest : public ::testing::Test { @@ -688,7 +782,9 @@ class OpConverterTest : public ::testing::Test { // Reset the validator and converter. validator_.reset(new TrtNodeValidator); - converter_.reset(new Converter(network_.get(), /*fp16=*/false)); + converter_.reset(new Converter(network_.get(), + /*precision_mode=*/FP32MODE, + /*use_calibration=*/false)); // Reset other related artifacts. scope_ = Scope::NewRootScope(); @@ -830,6 +926,11 @@ class OpConverterTest : public ::testing::Test { } } + // Expose quantization_ranges_ for tests + std::unordered_map& quantization_ranges() { + return converter_->quantization_ranges_; + } + std::unique_ptr converter_; std::unique_ptr validator_; @@ -1134,69 +1235,177 @@ TEST_F(OpConverterTest, ConvertMatMul) { EXPECT_THAT(output_data, ElementsAre(2, 3)); } } + } } -TEST_F(ConverterTest, ConvertQuantize) { +TEST_F(OpConverterTest, ConvertQuantize) { { // Input list is empty, should fail. - NodeDef node_def = - MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {}); - ExpectStatus(converter_.ConvertNode(node_def), error::INVALID_ARGUMENT, - "Expected 1 or 3 inputs for quantize node, at my_quantize"); + NodeDef node_def = MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", + {}); + RunConversion( + node_def, error::INVALID_ARGUMENT, + "Invalid number of inputs for QuantizeAndDequantizeV2, at my_quantize"); } { - // Missing attributes, should fail - converter_.Reset(); - NodeDef node_def = - MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {"input"}); + // FakeQuantWithMinMaxArgs attributes are empty, should fail. + NodeDef node_def = MakeNodeDef("my_quantize", "FakeQuantWithMinMaxArgs", + {"input"}); AddTestTensor("input", {1, 2, 3}); - ExpectStatus(converter_.ConvertNode(node_def), error::INVALID_ARGUMENT, - "Min or max attribute not found for quantize, at my_quantize"); + RunConversion( + node_def, error::INVALID_ARGUMENT, + "Min or max attribute not found for FakeQuantWithMinMaxArgs " + "at my_quantize"); } { - // All inputs are tensors, should fail - converter_.Reset(); - NodeDef node_def = MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", - {"input", "weights_min", "weights_max"}); + // FakeQuantWithMinMaxArgs ranges set via attributes, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + ops::FakeQuantWithMinMaxArgs::Attrs quantize_attrs; + quantize_attrs.min_ = -6.0f; + quantize_attrs.max_ = 6.0f; + auto quantize = + ops::FakeQuantWithMinMaxArgs(s.WithOpName("my_quantize"), input, quantize_attrs); + const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); - AddTestTensor("weights_min", {1}); - AddTestTensor("weights_max", {1}); - ExpectStatus(converter_.ConvertNode(node_def), error::INVALID_ARGUMENT, - "Min and max for quantize must be weights not tensors, at my_quantize"); + RunConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges.count(output.tensor()), 1); + EXPECT_EQ(ranges[output.tensor()], 6.0f); } { - // Ranges set via attributes, ok. - converter_.Reset(); - NodeDef node_def = - MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {"input"}); + // FakeQuantWithMinMaxVars ranges set via inputs, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto quantize = ops::FakeQuantWithMinMaxVars(s.WithOpName("my_quantize"), + input, + weights_min, + weights_max); + const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); - AttrValue attr_min; - attr_min.set_f(-6.0f); - AttrValue attr_max; - attr_max.set_f(6.0f); - node_def.mutable_attr()->insert({"min", attr_min}); - node_def.mutable_attr()->insert({"max", attr_max}); - TF_EXPECT_OK(converter_.ConvertNode(node_def)); - TRT_TensorOrWeights output = converter_.GetTensorOrWeights("my_quantize"); + AddTestWeights("weights_min", {1}, {-6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); + RunConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); EXPECT_TRUE(output.is_tensor()); - auto ranges = converter_.GetQuantizationRanges(); - EXPECT_EQ((*ranges).count(output.tensor()), 1); - EXPECT_EQ((*ranges)[output.tensor()], 6.0f); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges.count(output.tensor()), 1); + EXPECT_EQ(ranges[output.tensor()], 6.0f); } { - // Ranges set via inputs, ok. - converter_.Reset(); - NodeDef node_def = MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", - {"input", "weights_min", "weights_max"}); + // QuantizeAndDequantizeV2 ranges set via inputs, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto quantize = ops::QuantizeAndDequantizeV2(s.WithOpName("my_quantize"), + input, + weights_min, + weights_max); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + AddTestWeights("weights_min", {1}, {-6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); + RunConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges.count(output.tensor()), 1); + EXPECT_EQ(ranges[output.tensor()], 6.0f); + } + { + // QuantizeAndDequantizeV3 ranges set via inputs, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto num_bits = ops::Placeholder(s.WithOpName("num_bits"), DT_INT32); + auto quantize = ops::QuantizeAndDequantizeV3(s.WithOpName("my_quantize"), + input, + weights_min, + weights_max, + num_bits); + const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); - AddTestWeights("weights_min", DT_FLOAT, {1}, {-6.0f}); - AddTestWeights("weights_max", DT_FLOAT, {1}, {6.0f}); - TF_EXPECT_OK(converter_.ConvertNode(node_def)); - TRT_TensorOrWeights output = converter_.GetTensorOrWeights("my_quantize"); + AddTestWeights("weights_min", {1}, {-6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); + AddTestWeights("num_bits", {1}, {8}); + RunConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); EXPECT_TRUE(output.is_tensor()); - auto ranges = converter_.GetQuantizationRanges(); - EXPECT_EQ((*ranges).count(output.tensor()), 1); - EXPECT_EQ((*ranges)[output.tensor()], 6.0f); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges.count(output.tensor()), 1); + EXPECT_EQ(ranges[output.tensor()], 6.0f); + } + { + // QuantizeAndDequantizeV2 Range inputs are tensors, should fail. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto quantize = ops::QuantizeAndDequantizeV2(s.WithOpName("my_quantize"), + input, + weights_min, + weights_max); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + AddTestTensor("weights_min", {1}); + AddTestTensor("weights_max", {1}); + RunConversion(node_def, error::INVALID_ARGUMENT, + "Min and max inputs for QuantizeAndDequantizeV2 must be weights not " + "tensors, at my_quantize"); + } +} + +TEST_F(OpConverterTest, ConvertRelu6) { + { + // Input list is empty, should fail. + NodeDef node_def = MakeNodeDef("my_relu6", "Relu6", {}); + RunConversion( + node_def, error::INVALID_ARGUMENT, + "Invalid number of inputs for Relu6, at my_relu6"); + } + + // Get the NodeDef for Relu6. + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto relu6 = ops::Relu6(s.WithOpName("my_relu6"), input); + const NodeDef& node_def = relu6.operation.node()->def(); + + { + // Clip tensor values and set quantization ranges, ok. + Reset(); + AddTestTensor("input", {1, 2, 3}); + RunConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_relu6", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges[output.tensor()], 6.0f); + + std::vector output_data(6); + BuildAndRun("input", {-100, -1, 0, 3, 5, 9}, "my_relu6", &output_data); + EXPECT_THAT(output_data, ElementsAre(0, 0, 0, 3, 5, 6)); + } + { + // Input is weights, should fail. + Reset(); + AddTestWeights("input", {1, 2, 3}, {-100, -1, 0, 3, 5, 9}); + RunConversion(node_def, error::UNIMPLEMENTED, + "Relu6 is only implemented for tensors, not weights, at my_relu6"); } } diff --git a/tensorflow/contrib/tensorrt/segment/segment.cc b/tensorflow/contrib/tensorrt/segment/segment.cc index 80acab9ea3..4f64b7a952 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.cc +++ b/tensorflow/contrib/tensorrt/segment/segment.cc @@ -389,7 +389,7 @@ void ContractEdge(SimpleEdge* edge, SimpleGraph* graph, tensorflow::Status SegmentGraph( const tensorflow::Graph* tf_graph, - const std::function& candidate_fn, + const std::function& candidate_fn, const std::function& input_candidate_fn, const std::function& output_candidate_fn, const SegmentOptions& options, SegmentNodesVector* segments) { @@ -414,7 +414,7 @@ tensorflow::Status SegmentGraph( << " (excluded by segmenter option)."; node = nullptr; } else { - const Status status = candidate_fn(node->tf_node(), options.precision_mode); + const Status status = candidate_fn(node->tf_node()); if (!status.ok()) { VLOG(1) << "Not a TF-TRT candidate: " << node->name() << ": " << status; node = nullptr; diff --git a/tensorflow/contrib/tensorrt/segment/segment.h b/tensorflow/contrib/tensorrt/segment/segment.h index 802daec6a6..b6ae1cf462 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.h +++ b/tensorflow/contrib/tensorrt/segment/segment.h @@ -53,7 +53,7 @@ struct SegmentOptions { // @return the status. tensorflow::Status SegmentGraph( const tensorflow::Graph* tf_graph, - const std::function& candidate_fn, + const std::function& candidate_fn, const std::function& input_candidate_fn, const std::function& output_candidate_fn, const SegmentOptions& options, SegmentNodesVector* segments); diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py index e648c3388f..d160cb3380 100644 --- a/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py +++ b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py @@ -1,9 +1,31 @@ -import tensorflow as tf -import tensorflow.contrib.tensorrt as trt +# Copyright 2018 The TensorFlow Authors. 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 numpy as np -import argparse +import os + +import tensorflow as tf +from tensorflow.contrib.tensorrt.python.trt_convert import create_inference_graph +from tensorflow.core.protobuf import config_pb2 +from tensorflow.python.keras.datasets import mnist from tensorflow.python.framework import test_util from tensorflow.python.platform import test +from tensorflow.python import estimator as tf_estimator +from tensorflow.python.estimator.estimator import Estimator +from tensorflow.python.estimator.run_config import RunConfig +from tensorflow.python.estimator.model_fn import ModeKeys, EstimatorSpec INPUT_NODE_NAME = 'input' OUTPUT_NODE_NAME = 'output' @@ -67,7 +89,7 @@ def run(is_training, use_trt, batch_size, num_epochs, model_dir): model_dir: Where to save or load checkpoint. """ # Get dataset - train, test = tf.keras.datasets.mnist.load_data() + train, test = mnist.load_data() def eval_input_fn(): mnist_x, mnist_y = test @@ -76,7 +98,6 @@ def run(is_training, use_trt, batch_size, num_epochs, model_dir): map_func=preprocess_fn, batch_size=batch_size, num_parallel_calls=8)) - dataset = dataset.prefetch(buffer_size=tf.contrib.data.AUTOTUNE) dataset = dataset.repeat(count=1) iterator = dataset.make_one_shot_iterator() features, labels = iterator.get_next() @@ -90,7 +111,6 @@ def run(is_training, use_trt, batch_size, num_epochs, model_dir): map_func=preprocess_fn, batch_size=batch_size, num_parallel_calls=8)) - dataset = dataset.prefetch(buffer_size=tf.contrib.data.AUTOTUNE) dataset = dataset.repeat(count=num_epochs) iterator = dataset.make_one_shot_iterator() features, labels = iterator.get_next() @@ -115,27 +135,27 @@ def run(is_training, use_trt, batch_size, num_epochs, model_dir): predictions=classes_out, name='acc_op') tf.summary.scalar('accuracy', accuracy[1]) - if mode == tf.estimator.ModeKeys.EVAL: - return tf.estimator.EstimatorSpec( + if mode == ModeKeys.EVAL: + return EstimatorSpec( mode, loss=loss, eval_metric_ops={'accuracy': accuracy}) - elif mode == tf.estimator.ModeKeys.TRAIN: + elif mode == ModeKeys.TRAIN: optimizer = tf.train.AdamOptimizer(learning_rate=1e-2) train_op = optimizer.minimize( loss, global_step=tf.train.get_global_step()) - return tf.estimator.EstimatorSpec( + return EstimatorSpec( mode, loss=loss, train_op=train_op) - tf_config = tf.ConfigProto() + tf_config = config_pb2.ConfigProto() tf_config.gpu_options.allow_growth = True - estimator = tf.estimator.Estimator( + estimator = Estimator( model_fn=model_fn, - model_dir=model_dir, - config=tf.estimator.RunConfig(session_config=tf_config)) + model_dir=None, + config=RunConfig(session_config=tf_config)) if is_training: estimator.train(train_input_fn) results = estimator.evaluate(eval_input_fn) @@ -163,7 +183,7 @@ def get_graph_def(use_trt, batch_size, model_dir): # Convert with TF-TRT if use_trt: print('nodes before:', len(graph_def.node)) - graph_def = trt.create_inference_graph(graph_def, + graph_def = create_inference_graph(graph_def, outputs=[OUTPUT_NODE_NAME], max_batch_size=batch_size, precision_mode='int8', @@ -180,16 +200,17 @@ def get_graph_def(use_trt, batch_size, model_dir): class QuantizationAwareTrainingMNISTTest(test_util.TensorFlowTestCase): def testEval(self): + model_dir = test.test_src_dir_path('contrib/tensorrt/test/quantization_mnist_test_data') acc_tf = run(is_training=False, use_trt=False, batch_size=128, num_epochs=None, - model_dir='./quantization_mnist_test_data')['accuracy'] + model_dir=model_dir)['accuracy'] acc_tftrt = run(is_training=False, use_trt=True, batch_size=128, num_epochs=None, - model_dir='./quantization_mnist_test_data')['accuracy'] + model_dir=model_dir)['accuracy'] self.assertAllClose(acc_tf, 0.9717) self.assertAllClose(acc_tftrt, 0.9744) diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/BUILD b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/BUILD new file mode 100644 index 0000000000..f38c2c5f4d --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/BUILD @@ -0,0 +1,14 @@ +# Checkpoint files for quantization MNIST test. + +package( + default_visibility = ["//visibility:public"], +) + +licenses(["notice"]) # Apache 2.0 + +filegroup( + name = "quantization_mnist_data", + srcs = glob( + ["**"], + ), +) \ No newline at end of file diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.data-00000-of-00001 similarity index 100% rename from tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 rename to tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.data-00000-of-00001 diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.index similarity index 100% rename from tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index rename to tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.index diff --git a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py index a6f51640b7..8804f2bc8f 100644 --- a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py +++ b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py @@ -542,6 +542,8 @@ def _AddTests(test_class): # supported yet. continue if not dynamic_engine and use_calibration: + # Static engine with use_calibration=False will be static, so we want to + # test that. If use_calibration=True, only dynamic op is supported. # TODO(aaroey): construction of static calibration engine is not # supported yet. continue -- GitLab From 1bb3c61392634bf6a2b6ad5c1c3dc554204fc9fc Mon Sep 17 00:00:00 2001 From: Fei Hu Date: Fri, 9 Nov 2018 17:00:11 -0800 Subject: [PATCH 074/672] parallel_for: add converter for MaxPool3D, MaxPool3DGrad, MaxPool3DGradGrad --- .../ops/parallel_for/control_flow_ops_test.py | 20 ++++++++++++++++++- tensorflow/python/ops/parallel_for/pfor.py | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py index 171369b724..d44966078c 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py @@ -794,11 +794,29 @@ class NNTest(PForTest): def test_max_pool(self): x = random_ops.random_uniform([3, 2, 12, 12, 3]) ksize = [1, 3, 3, 1] + strides = [1, 2, 2, 1] def loop_fn(i): x1 = array_ops.gather(x, i) output = nn.max_pool( - x1, ksize, strides=[1, 2, 2, 1], padding="VALID", data_format="NHWC") + x1, ksize, strides=strides, padding="VALID", data_format="NHWC") + loss = nn.l2_loss(output) + ones = array_ops.ones_like(output) + grad = gradient_ops.gradients(loss, x1, grad_ys=ones) + grad_grad = gradient_ops.gradients(grad, ones) + return output, grad, grad_grad + + self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 3) + + def test_max_pool3D(self): + x = random_ops.random_uniform([3, 3, 2, 12, 12, 3]) + ksize = [1, 1, 3, 3, 1] + strides = [1, 1, 2, 2, 1] + + def loop_fn(i): + x1 = array_ops.gather(x, i) + output = nn.max_pool3d( + x1, ksize, strides=strides, padding="VALID", data_format="NDHWC") loss = nn.l2_loss(output) ones = array_ops.ones_like(output) grad = gradient_ops.gradients(loss, x1, grad_ys=ones) diff --git a/tensorflow/python/ops/parallel_for/pfor.py b/tensorflow/python/ops/parallel_for/pfor.py index e6f140a941..d789dc65b1 100644 --- a/tensorflow/python/ops/parallel_for/pfor.py +++ b/tensorflow/python/ops/parallel_for/pfor.py @@ -1303,7 +1303,10 @@ def _inputs_with_flattening(pfor_input, input_indices): @RegisterPForWithArgs("Conv2D", dims=[0]) @RegisterPForWithArgs("AvgPool", dims=[0]) @RegisterPForWithArgs("MaxPool", dims=[0]) +@RegisterPForWithArgs("MaxPool3D", dims=[0]) +@RegisterPForWithArgs("MaxPool3DGrad", dims=[0, 1, 2]) @RegisterPForWithArgs("MaxPoolGrad", dims=[0, 1, 2]) +@RegisterPForWithArgs("MaxPool3DGradGrad", dims=[0, 1, 2]) @RegisterPForWithArgs("MaxPoolGradGrad", dims=[0, 1, 2]) @RegisterPForWithArgs("SoftmaxCrossEntropyWithLogits", dims=[0, 1]) def _convert_flatten_batch(pfor_input, op_type, dims): -- GitLab From ced3c110f02148bab77d06352ec0465fd87962c0 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Mon, 12 Nov 2018 10:30:55 +0800 Subject: [PATCH 075/672] Revert a change: accidently comment a few lines. --- tensorflow/core/graph/mkl_layout_pass.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index fa32a3e061..ac3c817982 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -915,17 +915,17 @@ class MklLayoutRewritePass : public GraphOptimizationPass { if (node->type_string() != "Transpose") return false; // If "Transpose" has multiple output data edges, also don't fuse it. - // if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; + if (node->num_outputs() > 1 || node->out_edges().size() > 1) return false; // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. // Note: this constraint will eventually be removed, if we enabled this fusion for training // in the future. - // for (const Edge* e : node->out_edges()) { - // if (e->IsControlEdge()) { - // return false; - // } - // } + for (const Edge* e : node->out_edges()) { + if (e->IsControlEdge()) { + return false; + } + } // If "Transpose" has input control edges, don't fuse on it. for (const Edge* e : node->in_edges()) { -- GitLab From 17f1bdd9dda6f690df6fc298ed5c884e197a5d99 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Mon, 12 Nov 2018 13:08:50 +0800 Subject: [PATCH 076/672] Some modifications to "CheckForNodeFusion()": 1. check for match before push; 2. use "nodes" instead of "work_stack"; 3. get rid of "fi_ptr"; --- tensorflow/core/graph/mkl_layout_pass.cc | 70 +++++++++--------------- 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index ac3c817982..a5d2008a37 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2725,70 +2725,54 @@ Status MklLayoutRewritePass::FuseNode( std::tuple, const MklLayoutRewritePass::FusionInfo> MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { - const FusionInfo* fi_ptr = nullptr; + // Stores matched nodes, in the same order as node_checkers. + std::vector nodes; for (auto fi = finfo_.begin(); fi != finfo_.end(); ++fi) { - fi_ptr = &*fi; // // Make sure node "a" and its succeding nodes (b, c ...), match the pattern // defined in fusion info (ops[0], ops[1], ...), - // aka. "a->b->c" matches "op1->op2->op3" + // a.k.a. "a->b->c" matches "op1->op2->op3" // - std::stack> work_stack; + // Stores the first unvisted outgoing edge of each matched node in "nodes". std::stack current_neighbor_stack; - auto node_checker = fi->node_checkers.begin(); + nodes.clear(); - Node *current_node = nullptr; - if (a != nullptr) { - work_stack.push(a); + auto node_checker = fi->node_checkers.begin(); + if (a != nullptr && (*node_checker)(a)) { + nodes.push_back(a); current_neighbor_stack.push(a->out_edges().begin()); + ++ node_checker; } - while (!work_stack.empty()) { - current_node = work_stack.top(); + while (!nodes.empty()) { + auto& current_neighbor_iter = current_neighbor_stack.top(); - if ((*node_checker)(current_node)){ - if (node_checker == (fi->node_checkers.end() - 1)) { - // We find a match, break and return. - std::vector nodes; - while (!work_stack.empty()) { - nodes.insert(nodes.begin(), work_stack.top()); - work_stack.pop(); - } - - return make_tuple(true, nodes, *fi_ptr); - } + if (current_neighbor_iter != nodes.back()->out_edges().end()) { + // Found an unvisited edge. Goes through the edge to get the neighbor. + Node* neighbor_node = (*current_neighbor_iter)->dst(); + ++current_neighbor_stack.top(); // Retrieves the next unvisited edge. - auto ¤t_neighbor_iter = current_neighbor_stack.top(); - if (current_neighbor_iter == current_node->out_edges().end()) { - // All output edges have been exhausted, pop the stack - // and roll back to the preceding node. - work_stack.pop(); - current_neighbor_stack.pop(); - -- node_checker; - } else { - // Found a edge not been visited, go through this edge - // and get the next neighbor. - Node *neighbor_node = (*current_neighbor_iter)->dst(); - work_stack.push(neighbor_node); - current_neighbor_stack.push(neighbor_node->out_edges().begin()); - ++ node_checker; - - // Increase current_neighbor_iter, which is at the top of stack. - ++ current_neighbor_iter; + if ((*node_checker)(neighbor_node)) { + // Found a match. Stores the node and moves to the next checker. + nodes.push_back(neighbor_node); + current_neighbor_stack.push(neighbor_node->out_edges().begin()); + if (++node_checker == fi->node_checkers.end()) { + return make_tuple(true, nodes, *fi); + } } } else { - // current node doesn't match, pop stack to roll back. - // visited_nodes.insert(current_node); - work_stack.pop(); + // Removes the current node since none of its neighbor leads to a + // further match. + nodes.pop_back(); current_neighbor_stack.pop(); - -- node_checker; + --node_checker; } } } - return make_tuple(false, std::vector(), *fi_ptr); + return make_tuple(false, std::vector(), FusionInfo()); } /////////////////////////////////////////////////////////////////////////////// -- GitLab From 9b90cbd5f4ff02160def3cffc34d56ceaa2da916 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Mon, 12 Nov 2018 13:18:09 +0800 Subject: [PATCH 077/672] Apply clang-format-3.8 --- tensorflow/core/graph/mkl_layout_pass.cc | 29 +++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index a5d2008a37..d46e7165ff 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -22,12 +22,12 @@ limitations under the License. #include #include #include +#include +#include #include #include #include #include -#include -#include #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/optimization_registry.h" @@ -514,8 +514,10 @@ class MklLayoutRewritePass : public GraphOptimizationPass { csinfo_.conv2d_grad_filter_with_bias, GetConv2DBackpropFilterOrBiasAddGrad}); - // The fusion patterns in "finfo_" that show up first will get applied first, - // for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, A->B->C->D to ABCD}, + // The fusion patterns in "finfo_" that show up first will get applied + // first, + // for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, A->B->C->D + // to ABCD}, // since the first gets applied first, the final graph will be ABC->D. // @@ -903,7 +905,8 @@ class MklLayoutRewritePass : public GraphOptimizationPass { Status FuseNode(std::unique_ptr* g, std::vector& nodes, const MklLayoutRewritePass::FusionInfo fi); - // Fuse tranpose(to "NHWC") + mklop("NHWC") + transpose(to "NCHW") into mklop("NCHW"). + // Fuse tranpose(to "NHWC") + mklop("NHWC") + transpose(to "NCHW") into + // mklop("NCHW"). // Here "mklop" can be any MKL-DNN supported op, such as Conv2D. static Status FuseTransposeMklOpTranspose( std::unique_ptr* g, std::vector& nodes, @@ -919,8 +922,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { // Check if has out control edge. If true, this is a training graph. // Currently we focus on inference and do no fusion in training. - // Note: this constraint will eventually be removed, if we enabled this fusion for training - // in the future. + // Note: this constraint will eventually be removed, if we enabled this + // fusion for training + // in the future. for (const Edge* e : node->out_edges()) { if (e->IsControlEdge()) { return false; @@ -1835,7 +1839,6 @@ void MklLayoutRewritePass::CopyAttrsConv(const Node* orig_node, NodeBuilder* nb, new_strides = {strides[NHWC::dim::N], strides[NHWC::dim::C], strides[NHWC::dim::H], strides[NHWC::dim::W]}; - new_dilations = {dilations[NHWC::dim::N], dilations[NHWC::dim::C], dilations[NHWC::dim::H], dilations[NHWC::dim::W]}; @@ -2698,8 +2701,8 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( for (const Edge* e : transpose_to_nchw->out_edges()) { if (!e->IsControlEdge()) { const int kTransposeWithMklOpOutputSlot = 0; - CHECK_NOTNULL((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, e->dst(), - e->dst_input())); + CHECK_NOTNULL((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, + e->dst(), e->dst_input())); } } @@ -2726,7 +2729,7 @@ Status MklLayoutRewritePass::FuseNode( std::tuple, const MklLayoutRewritePass::FusionInfo> MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { // Stores matched nodes, in the same order as node_checkers. - std::vector nodes; + std::vector nodes; for (auto fi = finfo_.begin(); fi != finfo_.end(); ++fi) { // @@ -2743,7 +2746,7 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { if (a != nullptr && (*node_checker)(a)) { nodes.push_back(a); current_neighbor_stack.push(a->out_edges().begin()); - ++ node_checker; + ++node_checker; } while (!nodes.empty()) { @@ -2772,7 +2775,7 @@ MklLayoutRewritePass::CheckForNodeFusion(Node* a) const { } } - return make_tuple(false, std::vector(), FusionInfo()); + return make_tuple(false, std::vector(), FusionInfo()); } /////////////////////////////////////////////////////////////////////////////// -- GitLab From e9853febd5cf870523ddd99ef6e4fa45cd7047bd Mon Sep 17 00:00:00 2001 From: Anders Huss Date: Mon, 12 Nov 2018 08:59:58 +0100 Subject: [PATCH 078/672] fix issue in expanding of mask in keras.backend.rnn --- tensorflow/python/keras/backend.py | 6 +- tensorflow/python/keras/backend_test.py | 118 ++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/keras/backend.py b/tensorflow/python/keras/backend.py index 0be6302a98..017491ac76 100644 --- a/tensorflow/python/keras/backend.py +++ b/tensorflow/python/keras/backend.py @@ -3337,9 +3337,9 @@ def rnn(step_function, assert not nest.is_sequence(input_t) rank_diff = len(input_t.shape) - len(mask_t.shape) for _ in range(rank_diff): - mask_t = array_ops.expand_dims(mask_t) - expand_dims = [1] + input_t.shape.as_list()[1:] - return array_ops.tile(mask_t, expand_dims) + mask_t = array_ops.expand_dims(mask_t, -1) + multiples = [1] + input_t.shape.as_list()[1:] + return array_ops.tile(mask_t, multiples) if unroll: if not time_steps: diff --git a/tensorflow/python/keras/backend_test.py b/tensorflow/python/keras/backend_test.py index d8aa3e9b52..edb2af7e01 100644 --- a/tensorflow/python/keras/backend_test.py +++ b/tensorflow/python/keras/backend_test.py @@ -1223,6 +1223,124 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): for s, u_s in zip(additional_state_list[2], additional_state_list[3]): self.assertAllClose(s, u_s, atol=1e-04) + def test_rnn_output_and_state_masking_independent(self): + num_samples = 2 + num_timesteps = 4 + state_and_io_size = 2 + mask_last_num_timesteps = 2 # for second sample only + + # a step function that just outputs inputs, + # but increments states +1 per timestep + def step_function(inputs, states): + return inputs, [s + 1 for s in states] + + inputs_vals = np.random.random( + (num_samples, num_timesteps, state_and_io_size)) + initial_state_vals = np.random.random((num_samples, state_and_io_size)) + # masking of two last timesteps for second sample only + mask_vals = np.ones((num_samples, num_timesteps)) + mask_vals[1, -mask_last_num_timesteps:] = 0 + + # outputs expected to be same as inputs for the first sample + expected_outputs = inputs_vals.copy() + # but for the second sample all outputs in masked region should be the same + # as last output before masked region + expected_outputs[1, -mask_last_num_timesteps:] = \ + expected_outputs[1, -(mask_last_num_timesteps + 1)] + + expected_state = initial_state_vals.copy() + # first state should be incremented for every timestep (no masking) + expected_state[0] += num_timesteps + # second state should not be incremented for last two timesteps + expected_state[1] += (num_timesteps - mask_last_num_timesteps) + + # verify same expected output for `unroll=true/false` + inputs = keras.backend.variable(inputs_vals) + initial_states = [keras.backend.variable(initial_state_vals)] + mask = keras.backend.variable(mask_vals) + for unroll in [True, False]: + last_output, outputs, last_states = keras.backend.rnn( + step_function, + inputs, + initial_states, + mask=mask, + unroll=unroll, + input_length=num_timesteps if unroll else None) + + self.assertAllClose( + keras.backend.eval(outputs), expected_outputs) + self.assertAllClose( + keras.backend.eval(last_states[0]), expected_state) + + def test_rnn_output_num_dim_larger_than_2_masking(self): + num_samples = 3 + num_timesteps = 4 + num_features = 5 + + def step_function(inputs, states): + outputs = keras.backend.tile(keras.backend.expand_dims(inputs), [1, 1, 2]) + return outputs, [keras.backend.identity(s) for s in states] + # Note: cannot just return states (which can be a problem) -> + # tensorflow/python/ops/resource_variable_ops.py", line 824, in set_shape + # NotImplementedError: ResourceVariable does not implement set_shape() + + inputs_vals = np.random.random((num_samples, num_timesteps, num_features)) + initial_state_vals = np.random.random((num_samples, 6)) + mask_vals = np.ones((num_samples, num_timesteps)) + mask_vals[-1, -1] = 0 # final timestep masked for last sample + + expected_outputs = np.repeat(inputs_vals[..., None], repeats=2, axis=-1) + # for the last sample, the final timestep (in masked region) should be the + # same as the second to final output (before masked region) + expected_outputs[-1, -1] = expected_outputs[-1, -2] + + inputs = keras.backend.variable(inputs_vals) + initial_states = [keras.backend.variable(initial_state_vals)] + mask = keras.backend.variable(mask_vals) + for unroll in [True, False]: + last_output, outputs, last_states = keras.backend.rnn( + step_function, + inputs, + initial_states, + mask=mask, + unroll=unroll, + input_length=num_timesteps if unroll else None) + + self.assertAllClose(keras.backend.eval(outputs), expected_outputs) + + def test_rnn_state_num_dim_larger_than_2_masking(self): + num_samples = 3 + num_timesteps = 4 + + def step_function(inputs, states): + return inputs, [s + 1 for s in states] + + inputs_vals = np.random.random((num_samples, num_timesteps, 5)) + initial_state_vals = np.random.random((num_samples, 6, 7)) + mask_vals = np.ones((num_samples, num_timesteps)) + mask_vals[0, -2:] = 0 # final two timesteps masked for first sample + + expected_last_state = initial_state_vals.copy() + expected_last_state[0] += (num_timesteps - 2) + expected_last_state[1:] += num_timesteps + + inputs = keras.backend.variable(inputs_vals) + initial_states = [keras.backend.variable(initial_state_vals)] + mask = keras.backend.variable(mask_vals) + for unroll in [True, False]: + last_output, outputs, last_states = keras.backend.rnn( + step_function, + inputs, + initial_states, + mask=mask, + unroll=unroll, + input_length=num_timesteps if unroll else None) + + # not updated last timestep: + self.assertAllClose( + keras.backend.eval(last_states[0]), + expected_last_state) + def test_normalize_batch_in_training(self): val = np.random.random((10, 3, 10, 10)) x = keras.backend.variable(val) -- GitLab From fc541f794a27918ca6233734ab1f443489ddab5f Mon Sep 17 00:00:00 2001 From: Fei Hu Date: Mon, 12 Nov 2018 21:40:44 -0800 Subject: [PATCH 079/672] Fix the coding style issue --- tensorflow/python/ops/parallel_for/control_flow_ops_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py index d44966078c..7d13014687 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py @@ -808,7 +808,7 @@ class NNTest(PForTest): self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 3) - def test_max_pool3D(self): + def test_max_pool3d(self): x = random_ops.random_uniform([3, 3, 2, 12, 12, 3]) ksize = [1, 1, 3, 3, 1] strides = [1, 1, 2, 2, 1] @@ -816,7 +816,7 @@ class NNTest(PForTest): def loop_fn(i): x1 = array_ops.gather(x, i) output = nn.max_pool3d( - x1, ksize, strides=strides, padding="VALID", data_format="NDHWC") + x1, ksize, strides=strides, padding="VALID", data_format="NDHWC") loss = nn.l2_loss(output) ones = array_ops.ones_like(output) grad = gradient_ops.gradients(loss, x1, grad_ys=ones) -- GitLab From b8417cde632f191a6a86c61bec7b828371d6fe62 Mon Sep 17 00:00:00 2001 From: NEWPLAN Date: Tue, 13 Nov 2018 15:15:42 +0800 Subject: [PATCH 080/672] fix spelling error fix spelling error for documents. --- tensorflow/python/client/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/client/session.py b/tensorflow/python/client/session.py index 06c66dda9f..22303e95c1 100644 --- a/tensorflow/python/client/session.py +++ b/tensorflow/python/client/session.py @@ -828,7 +828,7 @@ class BaseSession(SessionInterface): nested list, tuple, namedtuple, dict, or OrderedDict containing graph elements at its leaves. A graph element can be one of the following types: - * An `tf.Operation`. + * A `tf.Operation`. The corresponding fetched value will be `None`. * A `tf.Tensor`. The corresponding fetched value will be a numpy ndarray containing the -- GitLab From 13fa6ecddff7931717dfce47598e88f48edcb6b6 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 13 Nov 2018 10:45:57 -0800 Subject: [PATCH 081/672] Fix data dependency bug --- .../tensorrt/test/quantization_mnist_test.py | 3 ++- ...f-00001 => model.ckpt-14070.data-00000-of-00001} | Bin .../{model.ckpt.index => model.ckpt-14070.index} | Bin 3 files changed, 2 insertions(+), 1 deletion(-) rename tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/{model.ckpt.data-00000-of-00001 => model.ckpt-14070.data-00000-of-00001} (100%) rename tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/{model.ckpt.index => model.ckpt-14070.index} (100%) diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py index d160cb3380..2586d936ef 100644 --- a/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py +++ b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py @@ -200,7 +200,8 @@ def get_graph_def(use_trt, batch_size, model_dir): class QuantizationAwareTrainingMNISTTest(test_util.TensorFlowTestCase): def testEval(self): - model_dir = test.test_src_dir_path('contrib/tensorrt/test/quantization_mnist_test_data') + model_dir = test.test_src_dir_path( + 'contrib/tensorrt/test/quantization_mnist_test_data') acc_tf = run(is_training=False, use_trt=False, batch_size=128, diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.data-00000-of-00001 b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 similarity index 100% rename from tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.data-00000-of-00001 rename to tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.data-00000-of-00001 diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.index b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index similarity index 100% rename from tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt.index rename to tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index -- GitLab From 72c01582a37ef838820ae3cde33ea270eb0fae03 Mon Sep 17 00:00:00 2001 From: Guangda Lai <31743510+aaroey@users.noreply.github.com> Date: Sat, 10 Nov 2018 18:27:33 -0800 Subject: [PATCH 082/672] Fix some formatting/compilation issues --- tensorflow/contrib/tensorrt/BUILD | 4 +- .../contrib/tensorrt/convert/convert_nodes.cc | 24 +++--- .../tensorrt/convert/convert_nodes_test.cc | 75 ++++++++----------- 3 files changed, 48 insertions(+), 55 deletions(-) diff --git a/tensorflow/contrib/tensorrt/BUILD b/tensorflow/contrib/tensorrt/BUILD index 64c0fecf87..f30c31a789 100644 --- a/tensorflow/contrib/tensorrt/BUILD +++ b/tensorflow/contrib/tensorrt/BUILD @@ -521,8 +521,8 @@ cuda_py_tests( "//tensorflow/python/keras:keras", "//tensorflow/python/estimator:estimator", ], - data =[ - "//tensorflow/contrib/tensorrt/test/quantization_mnist_test_data:quantization_mnist_data", + data = [ + "//tensorflow/contrib/tensorrt/test/quantization_mnist_test_data:quantization_mnist_data", ], tags = [ "no_cuda_on_cpu_tap", diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index b8aa49506b..ca06152fac 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -425,7 +425,9 @@ class TRT_TensorOrWeights::SimpleITensor : public nvinfer1::ITensor { void setLocation(nvinfer1::TensorLocation location) override {} #if NV_TENSORRT_MAJOR >= 5 - bool setDynamicRange(float min, float max) override {} + bool setDynamicRange(float min, float max) override { return true; } + + float getDynamicRange() const override { return 0; } #endif private: @@ -818,7 +820,7 @@ Status Converter::ConvertNode(const NodeDef& node_def) { if (i != 0) output_name = StrCat(output_name, ":", i); // We need to check the name before setting it. If the input is one of the // engine input, setting the name here will overwrite engine input - // bindings which will cause runtime error. + // bindings which will cause runtime error. if (output.is_tensor()) { const char* tensor_name = output.tensor()->getName(); if (!tensorflow::str_util::StartsWith(tensor_name, kInputPHName)) { @@ -1074,7 +1076,7 @@ void Converter::ApplyQuantizationRanges(bool warn_missing_ranges) { tensor->setDynamicRange(-range, range); #endif } - + // Warn user about tensors that are missing ranges. If TRT fuses some layers // then these tensors may not actually be required, which is why this is // just a warning. If we are still missing ranges even after fusion, @@ -2077,23 +2079,23 @@ tensorflow::Status ConvertRelu6(OpConverterParams* params) { // to available TensorRT ops: Relu6(x) = min(Relu(x), 6) // *************************************************************************** - // Input Tensor + // Input Tensor const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); - + // Relu operation i.e. Relu(x) = max(0, x) - nvinfer1::IActivationLayer* relu_layer = + nvinfer1::IActivationLayer* relu_layer = params->converter->network()->addActivation( *const_cast(tensor), nvinfer1::ActivationType::kRELU); TFTRT_RETURN_ERROR_IF_NULLPTR(relu_layer, node_def.name()); - + // Large range of relu is problematic during quantization in INT8 precision mode. // Setting dynamic range of relu = [0.f, 6.0f] helps with quantization. // TRT only uses dynamic ranges in INT8 precision mode, // and this does not affect the FP32 path. params->converter->ProvideQuantizationRange( relu_layer->getOutput(0), 0.0f, 6.0f); - + // Create a constant layer to store the floating point weight i.e. 6.0f This // tensor will be broadcasted uniformly during elementwise `min` operation. // The constant has to have the same rank as the input in order for TRT to @@ -2108,18 +2110,18 @@ tensorflow::Status ConvertRelu6(OpConverterParams* params) { auto weights_ptr = static_cast(const_cast( weights.GetValues())); weights_ptr[0] = 6.f; - nvinfer1::IConstantLayer* const6_layer = + nvinfer1::IConstantLayer* const6_layer = params->converter->network()->addConstant(dims, weights.GetTrtWeights()); TFTRT_RETURN_ERROR_IF_NULLPTR(const6_layer, node_def.name()); params->converter->ProvideQuantizationRange( const6_layer->getOutput(0), 0.0f, 6.0f); - + // ElementWise Min Operation // Min op is a nop for INT8 execution path, as the input tensor // to this layer will only have values in range [0.f, 6.0f]. const nvinfer1::ITensor* tensor_l = relu_layer->getOutput(0); const nvinfer1::ITensor* tensor_r = const6_layer->getOutput(0); - nvinfer1::IElementWiseLayer* relu6_layer = + nvinfer1::IElementWiseLayer* relu6_layer = params->converter->network()->addElementWise( *const_cast(tensor_l), *const_cast(tensor_r), diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 77cf3e7ef0..257394c0a3 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -137,8 +137,8 @@ class FakeITensor : public nvinfer1::ITensor { FakeITensor(const nvinfer1::Dims& dims) : dims_(dims), dynamic_range_(0.0f) {} - FakeITensor(const std::vector& dims) : dims_(GetTestDims(dims)), - dynamic_range_(0.0f) {} + FakeITensor(const std::vector& dims) + : dims_(GetTestDims(dims)), dynamic_range_(0.0f) {} void setName(const char* name) override { name_ = name; } @@ -172,7 +172,7 @@ class FakeITensor : public nvinfer1::ITensor { return true; } - float getDynamicRange() { return dynamic_range_; } + float getDynamicRange() const override { return dynamic_range_; } #endif private: @@ -441,8 +441,8 @@ class ConverterTest : public ::testing::Test { return converter_->GetInputs(node_def, inputs); } - Status GetWeightRange(const TRT_ShapedWeights& weights, - float* out_min, float* out_max) const { + Status GetWeightRange(const TRT_ShapedWeights& weights, float* out_min, + float* out_max) const { return converter_->GetWeightRange(weights, out_min, out_max); } @@ -1241,21 +1241,20 @@ TEST_F(OpConverterTest, ConvertMatMul) { TEST_F(OpConverterTest, ConvertQuantize) { { // Input list is empty, should fail. - NodeDef node_def = MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", - {}); + NodeDef node_def = + MakeNodeDef("my_quantize", "QuantizeAndDequantizeV2", {}); RunConversion( node_def, error::INVALID_ARGUMENT, "Invalid number of inputs for QuantizeAndDequantizeV2, at my_quantize"); } { // FakeQuantWithMinMaxArgs attributes are empty, should fail. - NodeDef node_def = MakeNodeDef("my_quantize", "FakeQuantWithMinMaxArgs", - {"input"}); + NodeDef node_def = + MakeNodeDef("my_quantize", "FakeQuantWithMinMaxArgs", {"input"}); AddTestTensor("input", {1, 2, 3}); - RunConversion( - node_def, error::INVALID_ARGUMENT, - "Min or max attribute not found for FakeQuantWithMinMaxArgs " - "at my_quantize"); + RunConversion(node_def, error::INVALID_ARGUMENT, + "Min or max attribute not found for FakeQuantWithMinMaxArgs " + "at my_quantize"); } { // FakeQuantWithMinMaxArgs ranges set via attributes, ok. @@ -1265,8 +1264,8 @@ TEST_F(OpConverterTest, ConvertQuantize) { ops::FakeQuantWithMinMaxArgs::Attrs quantize_attrs; quantize_attrs.min_ = -6.0f; quantize_attrs.max_ = 6.0f; - auto quantize = - ops::FakeQuantWithMinMaxArgs(s.WithOpName("my_quantize"), input, quantize_attrs); + auto quantize = ops::FakeQuantWithMinMaxArgs(s.WithOpName("my_quantize"), + input, quantize_attrs); const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); RunConversion(node_def); @@ -1284,14 +1283,12 @@ TEST_F(OpConverterTest, ConvertQuantize) { auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); - auto quantize = ops::FakeQuantWithMinMaxVars(s.WithOpName("my_quantize"), - input, - weights_min, - weights_max); + auto quantize = ops::FakeQuantWithMinMaxVars( + s.WithOpName("my_quantize"), input, weights_min, weights_max); const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); AddTestWeights("weights_min", {1}, {-6.0f}); - AddTestWeights("weights_max", {1}, {6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); RunConversion(node_def); TRT_TensorOrWeights output; TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); @@ -1307,14 +1304,12 @@ TEST_F(OpConverterTest, ConvertQuantize) { auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); - auto quantize = ops::QuantizeAndDequantizeV2(s.WithOpName("my_quantize"), - input, - weights_min, - weights_max); + auto quantize = ops::QuantizeAndDequantizeV2( + s.WithOpName("my_quantize"), input, weights_min, weights_max); const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); AddTestWeights("weights_min", {1}, {-6.0f}); - AddTestWeights("weights_max", {1}, {6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); RunConversion(node_def); TRT_TensorOrWeights output; TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); @@ -1331,16 +1326,13 @@ TEST_F(OpConverterTest, ConvertQuantize) { auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); auto num_bits = ops::Placeholder(s.WithOpName("num_bits"), DT_INT32); - auto quantize = ops::QuantizeAndDequantizeV3(s.WithOpName("my_quantize"), - input, - weights_min, - weights_max, - num_bits); + auto quantize = ops::QuantizeAndDequantizeV3( + s.WithOpName("my_quantize"), input, weights_min, weights_max, num_bits); const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); AddTestWeights("weights_min", {1}, {-6.0f}); - AddTestWeights("weights_max", {1}, {6.0f}); - AddTestWeights("num_bits", {1}, {8}); + AddTestWeights("weights_max", {1}, {6.0f}); + AddTestWeights("num_bits", {1}, {8}); RunConversion(node_def); TRT_TensorOrWeights output; TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); @@ -1356,15 +1348,14 @@ TEST_F(OpConverterTest, ConvertQuantize) { auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); - auto quantize = ops::QuantizeAndDequantizeV2(s.WithOpName("my_quantize"), - input, - weights_min, - weights_max); + auto quantize = ops::QuantizeAndDequantizeV2( + s.WithOpName("my_quantize"), input, weights_min, weights_max); const NodeDef& node_def = quantize.operation.node()->def(); AddTestTensor("input", {1, 2, 3}); AddTestTensor("weights_min", {1}); AddTestTensor("weights_max", {1}); - RunConversion(node_def, error::INVALID_ARGUMENT, + RunConversion( + node_def, error::INVALID_ARGUMENT, "Min and max inputs for QuantizeAndDequantizeV2 must be weights not " "tensors, at my_quantize"); } @@ -1374,9 +1365,8 @@ TEST_F(OpConverterTest, ConvertRelu6) { { // Input list is empty, should fail. NodeDef node_def = MakeNodeDef("my_relu6", "Relu6", {}); - RunConversion( - node_def, error::INVALID_ARGUMENT, - "Invalid number of inputs for Relu6, at my_relu6"); + RunConversion(node_def, error::INVALID_ARGUMENT, + "Invalid number of inputs for Relu6, at my_relu6"); } // Get the NodeDef for Relu6. @@ -1384,7 +1374,7 @@ TEST_F(OpConverterTest, ConvertRelu6) { auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); auto relu6 = ops::Relu6(s.WithOpName("my_relu6"), input); const NodeDef& node_def = relu6.operation.node()->def(); - + { // Clip tensor values and set quantization ranges, ok. Reset(); @@ -1404,7 +1394,8 @@ TEST_F(OpConverterTest, ConvertRelu6) { // Input is weights, should fail. Reset(); AddTestWeights("input", {1, 2, 3}, {-100, -1, 0, 3, 5, 9}); - RunConversion(node_def, error::UNIMPLEMENTED, + RunConversion( + node_def, error::UNIMPLEMENTED, "Relu6 is only implemented for tensors, not weights, at my_relu6"); } } -- GitLab From 21177b1a53f7ff3a8f964f4ecc73dc009ae9f2fe Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 14 Nov 2018 09:30:31 +0800 Subject: [PATCH 083/672] Format a wired comment made by clang-format-3.8 --- tensorflow/core/graph/mkl_layout_pass.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index d46e7165ff..dffd7ef4a4 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -515,10 +515,8 @@ class MklLayoutRewritePass : public GraphOptimizationPass { GetConv2DBackpropFilterOrBiasAddGrad}); // The fusion patterns in "finfo_" that show up first will get applied - // first, - // for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, A->B->C->D - // to ABCD}, - // since the first gets applied first, the final graph will be ABC->D. + // first, for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, A->B->C->D + // to ABCD}, since the first gets applied first, the final graph will be ABC->D. // // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D -- GitLab From 88b2369fe7c4451c63ff0599f7477897dabff2e0 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Wed, 14 Nov 2018 14:34:05 +0800 Subject: [PATCH 084/672] Break very long lines into 2. --- tensorflow/core/graph/mkl_layout_pass.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index dffd7ef4a4..bac434886f 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -515,8 +515,9 @@ class MklLayoutRewritePass : public GraphOptimizationPass { GetConv2DBackpropFilterOrBiasAddGrad}); // The fusion patterns in "finfo_" that show up first will get applied - // first, for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, A->B->C->D - // to ABCD}, since the first gets applied first, the final graph will be ABC->D. + // first, for example, graph "A->B->C-D" and finfo_ is {A->B->C to ABC, + // A->B->C->D to ABCD}, since the first gets applied first, the final + // graph will be ABC->D. // // Add rules to fuse sequences such as "Transpose (NCHW -> NHWC) + Conv2D -- GitLab From be2e12057eb40c360c419f1fe1fc238a22e0501c Mon Sep 17 00:00:00 2001 From: Anders Huss Date: Wed, 14 Nov 2018 08:38:43 +0100 Subject: [PATCH 085/672] fix coding style issues in new rnn tests --- tensorflow/python/keras/backend_test.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/tensorflow/python/keras/backend_test.py b/tensorflow/python/keras/backend_test.py index edb2af7e01..99b53e69c3 100644 --- a/tensorflow/python/keras/backend_test.py +++ b/tensorflow/python/keras/backend_test.py @@ -1248,18 +1248,18 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): expected_outputs[1, -mask_last_num_timesteps:] = \ expected_outputs[1, -(mask_last_num_timesteps + 1)] - expected_state = initial_state_vals.copy() + expected_last_state = initial_state_vals.copy() # first state should be incremented for every timestep (no masking) - expected_state[0] += num_timesteps + expected_last_state[0] += num_timesteps # second state should not be incremented for last two timesteps - expected_state[1] += (num_timesteps - mask_last_num_timesteps) + expected_last_state[1] += (num_timesteps - mask_last_num_timesteps) # verify same expected output for `unroll=true/false` inputs = keras.backend.variable(inputs_vals) initial_states = [keras.backend.variable(initial_state_vals)] mask = keras.backend.variable(mask_vals) for unroll in [True, False]: - last_output, outputs, last_states = keras.backend.rnn( + _, outputs, last_states = keras.backend.rnn( step_function, inputs, initial_states, @@ -1267,10 +1267,9 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): unroll=unroll, input_length=num_timesteps if unroll else None) - self.assertAllClose( - keras.backend.eval(outputs), expected_outputs) - self.assertAllClose( - keras.backend.eval(last_states[0]), expected_state) + self.assertAllClose(keras.backend.eval(outputs), expected_outputs) + self.assertAllClose(keras.backend.eval( + last_states[0]), expected_last_state) def test_rnn_output_num_dim_larger_than_2_masking(self): num_samples = 3 @@ -1298,7 +1297,7 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): initial_states = [keras.backend.variable(initial_state_vals)] mask = keras.backend.variable(mask_vals) for unroll in [True, False]: - last_output, outputs, last_states = keras.backend.rnn( + _, outputs, _ = keras.backend.rnn( step_function, inputs, initial_states, @@ -1313,7 +1312,7 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): num_timesteps = 4 def step_function(inputs, states): - return inputs, [s + 1 for s in states] + return inputs, [s + 1 for s in states] inputs_vals = np.random.random((num_samples, num_timesteps, 5)) initial_state_vals = np.random.random((num_samples, 6, 7)) @@ -1328,7 +1327,7 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): initial_states = [keras.backend.variable(initial_state_vals)] mask = keras.backend.variable(mask_vals) for unroll in [True, False]: - last_output, outputs, last_states = keras.backend.rnn( + _, _, last_states = keras.backend.rnn( step_function, inputs, initial_states, @@ -1336,10 +1335,8 @@ class BackendNNOpsTest(test.TestCase, parameterized.TestCase): unroll=unroll, input_length=num_timesteps if unroll else None) - # not updated last timestep: self.assertAllClose( - keras.backend.eval(last_states[0]), - expected_last_state) + keras.backend.eval(last_states[0]), expected_last_state) def test_normalize_batch_in_training(self): val = np.random.random((10, 3, 10, 10)) -- GitLab From 0c8fa0351a2da1706e179571a9637dee55966e64 Mon Sep 17 00:00:00 2001 From: Vadim Borisov Date: Wed, 14 Nov 2018 14:13:36 +0100 Subject: [PATCH 086/672] Update README.md --- tensorflow/contrib/quantize/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/quantize/README.md b/tensorflow/contrib/quantize/README.md index a1f2b59026..9085d9fa71 100644 --- a/tensorflow/contrib/quantize/README.md +++ b/tensorflow/contrib/quantize/README.md @@ -28,7 +28,7 @@ Since it's difficult to add these fake quantization operations to all the required locations in the model, there's a function available that rewrites the training graph. To create a fake quantized training graph: -``` +```python # Build forward pass of model. loss = tf.losses.get_total_loss() @@ -51,7 +51,7 @@ The rewritten *eval graph* is non-trivially different from the *training graph* since the quantization ops affect the batch normalization step. Because of this, we've added a separate rewrite for the *eval graph*: -``` +```python # Build eval model logits = tf.nn.softmax_cross_entropy_with_logits_v2(...) -- GitLab From f1f54862ae4d2d63e9702dee66aaa08efd24d41f Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 14 Nov 2018 12:59:23 -0800 Subject: [PATCH 087/672] Fix QuantizationMissingAllRangesTest: the network was too simple and TRT was chosing not to quantize it. --- .../contrib/tensorrt/test/quantization_test.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tensorflow/contrib/tensorrt/test/quantization_test.py b/tensorflow/contrib/tensorrt/test/quantization_test.py index f32b15b038..83295ce2bd 100644 --- a/tensorflow/contrib/tensorrt/test/quantization_test.py +++ b/tensorflow/contrib/tensorrt/test/quantization_test.py @@ -43,6 +43,7 @@ def build_graph(input_name, input_dims, output_name, with g.as_default(): x = array_ops.placeholder( dtype=dtype, shape=[None] + input_dims[1:], name=input_name) + x = quantize(x, 10.0) x = x + 5 x = quantize(x, 15.0) @@ -50,6 +51,9 @@ def build_graph(input_name, input_dims, output_name, x = quantize(x, 10.0) x = x * 0.1 x = quantize(x, 1.0) + w = constant_op.constant(np.ones((10, 1)), dtype=dtypes.float32) + x = math_ops.matmul(x, w) + x = quantize(x, 10.0) x = array_ops.identity(x, name=output_name) return g @@ -58,7 +62,7 @@ class QuantizationMissingAllRangesTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Create a graph containing single segment with no quantization ranges.""" input_name = "input" - input_dims = [100, 100] + input_dims = [128, 10] output_name = "output" g = build_graph(input_name, input_dims, output_name, add_quantization_nodes=False) @@ -67,7 +71,7 @@ class QuantizationMissingAllRangesTest(trt_test.TfTrtIntegrationTestBase): input_names=[input_name], input_dims=[input_dims], output_names=[output_name], - expected_output_dims=[(100, 100)]) + expected_output_dims=[(128, 1)]) def ShouldRunTest(self, run_params): return (run_params.precision_mode == "INT8" and @@ -85,7 +89,7 @@ class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Create a graph containing single segment with no quantization ranges.""" input_name = "input" - input_dims = [100, 100] + input_dims = [128, 10] output_name = "output" g = build_graph(input_name, input_dims, output_name, add_quantization_nodes=True) @@ -94,7 +98,7 @@ class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): input_names=[input_name], input_dims=[input_dims], output_names=[output_name], - expected_output_dims=[(100, 100)]) + expected_output_dims=[(128, 1)]) def ShouldRunTest(self, run_params): return (run_params.precision_mode == "INT8" and @@ -117,7 +121,7 @@ class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Create a graph containing single segment with no quantization ranges.""" input_name = "input" - input_dims = [100, 100] + input_dims = [128, 10] output_name = "output" g = build_graph(input_name, input_dims, output_name, add_quantization_nodes=True) @@ -126,7 +130,7 @@ class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): input_names=[input_name], input_dims=[input_dims], output_names=[output_name], - expected_output_dims=[(100, 100)]) + expected_output_dims=[(128, 1)]) def ShouldRunTest(self, run_params): return (run_params.precision_mode == "FP32" or @@ -134,7 +138,7 @@ class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0", "my_trt_op_1", "my_trt_op_2"] + return ["my_trt_op_0", "my_trt_op_1", "my_trt_op_2", "my_trt_op_3"] def ExpectedAbsoluteTolerance(self, run_params): """The absolute tolerance to compare floating point results.""" -- GitLab From 09efdc5aa73127a1aca84b32f29c5a20f1bd097a Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 14 Nov 2018 14:00:24 -0800 Subject: [PATCH 088/672] Identified a few more situations where quantization range needs to be inferred. In some cases, it is impossible to infer these ranges. --- .../contrib/tensorrt/convert/convert_nodes.cc | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index ca06152fac..bc29bf8ffa 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -1467,6 +1467,10 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, *const_cast(tensor), nvinfer1::UnaryOperation::kNEG); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); + // Since quantization ranges are symmetric, the same range as the input + // will work for the negation of the input. + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), layer->getOutput(0)); tensor = layer->getOutput(0); } else { TRT_ShapedWeights neg_weights = @@ -1478,6 +1482,23 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, } } else if (node_def.op() == "Div" || node_def.op() == "RealDiv") { if (swapped_inputs) { + // We need to infer the quantization range for this intermediate + // tensor. + // x -> [Recip] -> 1/x -> [Scale] -> s/x + // ^ + // need range for this + // We have the quantization scales for x and s/x - can we divide the scale + // for s/x by s? Only if it was a scalar... + // Because of this issue, fall back to BinaryTensorOpTensor if we are + // doing INT8 with no calibration. There is most likely no performance + // penalty by falling back here. + if (params->converter->precision_mode() == INT8MODE && + !params->converter->use_calibration()) { + return tensorflow::errors::Unimplemented( + "Intermediate quantization range cannot be determined without" + " calibration. Falling back to BinaryTensorOpTensor for ", + node_def.op(), ", at ", node_def.name()); + } scale_weights = weights; nvinfer1::IUnaryLayer* layer = params->converter->network()->addUnary( *const_cast(tensor), @@ -2409,6 +2430,12 @@ tensorflow::Status ConvertBinary(OpConverterParams* params) { node_def.name()); } + // TODO(tmorris): TRT plans to deprecate IScaleLayer and will replace it with + // IElementwiseLayer. At that point, we can remove BinaryTensorOpWeight. For + // now, the performance will be slightly better with IScaleLayer because it + // can be fused in more situations. However, most of the benefits of + // IScaleLayer are when the layer performs both a shift and a scale, which we + // don't do except for convolutions. // Try to convert into Scale layer first (for better performance) // Since scale layer supports restricted broadcast policy and op types, we // allow failure and try to handle it through Elementwise op @@ -2451,6 +2478,18 @@ tensorflow::Status ConvertUnary(OpConverterParams* params) { nvinfer1::IUnaryLayer* layer; if (node_def.op() == "Rsqrt") { + // We will need a quantization range for intermediate tensor + // if not using calibration. + // x -> [Sqrt] -> sqrt(x) -> [Recip] -> 1/sqrt(x) + // ^ + // need range here + if (params->converter->precision_mode() == INT8MODE && + !params->converter->use_calibration()) { + return tensorflow::errors::Unimplemented( + "Intermediate quantization range cannot be determined without" + " calibration for Rsqrt, consider replacing with " + "Sqrt -> FakeQuant -> Reciprocal ops, at ", node_def.name()); + } layer = params->converter->network()->addUnary( *const_cast(tensor), nvinfer1::UnaryOperation::kSQRT); -- GitLab From b51ad2408b5050ee497a3af602d4bbd950f89973 Mon Sep 17 00:00:00 2001 From: Sami Kama Date: Fri, 16 Nov 2018 14:16:23 -0800 Subject: [PATCH 089/672] Add option to disable nccl --- configure.py | 1 + tensorflow/BUILD | 6 +++ tensorflow/core/BUILD | 111 +++++++++++++++++++++------------------- tensorflow/python/BUILD | 1 + tools/bazel.rc | 2 + 5 files changed, 67 insertions(+), 54 deletions(-) diff --git a/configure.py b/configure.py index 234561d94a..f663f6df6f 100644 --- a/configure.py +++ b/configure.py @@ -1694,6 +1694,7 @@ def main(): config_info_line('nohdfs', 'Disable HDFS support.') config_info_line('noignite', 'Disable Apacha Ignite support.') config_info_line('nokafka', 'Disable Apache Kafka support.') + config_info_line('nonccl', 'Disable NVIDIA NCCL support.') if __name__ == '__main__': diff --git a/tensorflow/BUILD b/tensorflow/BUILD index 2dc70c359c..ab70486002 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -246,6 +246,12 @@ config_setting( visibility = ["//visibility:public"], ) +config_setting( + name = "no_nccl_support", + define_values = {"no_nccl_support": "true"}, + visibility = ["//visibility:public"], +) + # Crosses between platforms and file system libraries not supported on those # platforms due to limitations in nested select() statements. config_setting( diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 73e8db58a8..3237c34a99 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -1349,60 +1349,63 @@ cc_library( name = "all_kernels_statically_linked", visibility = ["//visibility:private"], deps = [ - "//tensorflow/core/kernels:array", - "//tensorflow/core/kernels:audio", - "//tensorflow/core/kernels:batch_kernels", - "//tensorflow/core/kernels:bincount_op", - "//tensorflow/core/kernels:boosted_trees_ops", - "//tensorflow/core/kernels:candidate_sampler_ops", - "//tensorflow/core/kernels:checkpoint_ops", - "//tensorflow/core/kernels:collective_ops", - "//tensorflow/core/kernels:control_flow_ops", - "//tensorflow/core/kernels:ctc_ops", - "//tensorflow/core/kernels:cudnn_rnn_kernels", - "//tensorflow/core/kernels:data_flow", - "//tensorflow/core/kernels:dataset_ops", - "//tensorflow/core/kernels:decode_proto_op", - "//tensorflow/core/kernels:encode_proto_op", - "//tensorflow/core/kernels:fake_quant_ops", - "//tensorflow/core/kernels:function_ops", - "//tensorflow/core/kernels:functional_ops", - "//tensorflow/core/kernels:grappler", - "//tensorflow/core/kernels:histogram_op", - "//tensorflow/core/kernels:image", - "//tensorflow/core/kernels:io", - "//tensorflow/core/kernels:linalg", - "//tensorflow/core/kernels:list_kernels", - "//tensorflow/core/kernels:lookup", - "//tensorflow/core/kernels:logging", - "//tensorflow/core/kernels:manip", - "//tensorflow/core/kernels:math", - "//tensorflow/core/kernels:multinomial_op", - "//tensorflow/core/kernels:nn", - "//tensorflow/core/kernels:parameterized_truncated_normal_op", - "//tensorflow/core/kernels:parsing", - "//tensorflow/core/kernels:partitioned_function_ops", - "//tensorflow/core/kernels:ragged_ops", - "//tensorflow/core/kernels:random_ops", - "//tensorflow/core/kernels:random_poisson_op", - "//tensorflow/core/kernels:remote_fused_graph_ops", - "//tensorflow/core/kernels:required", - "//tensorflow/core/kernels:resource_variable_ops", - "//tensorflow/core/kernels:rpc_op", - "//tensorflow/core/kernels:scoped_allocator_ops", - "//tensorflow/core/kernels:sdca_ops", - "//tensorflow/core/kernels:searchsorted_op", - "//tensorflow/core/kernels:set_kernels", - "//tensorflow/core/kernels:sparse", - "//tensorflow/core/kernels:state", - "//tensorflow/core/kernels:stateless_random_ops", - "//tensorflow/core/kernels:string", - "//tensorflow/core/kernels:summary_kernels", - "//tensorflow/core/kernels:training_ops", - "//tensorflow/core/kernels:word2vec_kernels", - ] + tf_additional_cloud_kernel_deps() + if_not_tx2_llvm_or_windows_cuda([ - "//tensorflow/core/kernels:nccl_kernels", - ]) + if_not_windows([ + "//tensorflow/core/kernels:array", + "//tensorflow/core/kernels:audio", + "//tensorflow/core/kernels:batch_kernels", + "//tensorflow/core/kernels:bincount_op", + "//tensorflow/core/kernels:boosted_trees_ops", + "//tensorflow/core/kernels:candidate_sampler_ops", + "//tensorflow/core/kernels:checkpoint_ops", + "//tensorflow/core/kernels:collective_ops", + "//tensorflow/core/kernels:control_flow_ops", + "//tensorflow/core/kernels:ctc_ops", + "//tensorflow/core/kernels:cudnn_rnn_kernels", + "//tensorflow/core/kernels:data_flow", + "//tensorflow/core/kernels:dataset_ops", + "//tensorflow/core/kernels:decode_proto_op", + "//tensorflow/core/kernels:encode_proto_op", + "//tensorflow/core/kernels:fake_quant_ops", + "//tensorflow/core/kernels:function_ops", + "//tensorflow/core/kernels:functional_ops", + "//tensorflow/core/kernels:grappler", + "//tensorflow/core/kernels:histogram_op", + "//tensorflow/core/kernels:image", + "//tensorflow/core/kernels:io", + "//tensorflow/core/kernels:linalg", + "//tensorflow/core/kernels:list_kernels", + "//tensorflow/core/kernels:lookup", + "//tensorflow/core/kernels:logging", + "//tensorflow/core/kernels:manip", + "//tensorflow/core/kernels:math", + "//tensorflow/core/kernels:multinomial_op", + "//tensorflow/core/kernels:nn", + "//tensorflow/core/kernels:parameterized_truncated_normal_op", + "//tensorflow/core/kernels:parsing", + "//tensorflow/core/kernels:partitioned_function_ops", + "//tensorflow/core/kernels:ragged_ops", + "//tensorflow/core/kernels:random_ops", + "//tensorflow/core/kernels:random_poisson_op", + "//tensorflow/core/kernels:remote_fused_graph_ops", + "//tensorflow/core/kernels:required", + "//tensorflow/core/kernels:resource_variable_ops", + "//tensorflow/core/kernels:rpc_op", + "//tensorflow/core/kernels:scoped_allocator_ops", + "//tensorflow/core/kernels:sdca_ops", + "//tensorflow/core/kernels:searchsorted_op", + "//tensorflow/core/kernels:set_kernels", + "//tensorflow/core/kernels:sparse", + "//tensorflow/core/kernels:state", + "//tensorflow/core/kernels:stateless_random_ops", + "//tensorflow/core/kernels:string", + "//tensorflow/core/kernels:summary_kernels", + "//tensorflow/core/kernels:training_ops", + "//tensorflow/core/kernels:word2vec_kernels", + ] + tf_additional_cloud_kernel_deps() + + select({ + "//tensorflow:no_nccl_support": [], + "//tensorflow:with_cuda_support_windows_override": [], + "//conditions:default": ["//tensorflow/core/kernels:nccl_kernels"], + }) + if_not_windows([ "//tensorflow/core/kernels:fact_op", "//tensorflow/core/kernels:array_not_windows", "//tensorflow/core/kernels:math_not_windows", diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index e55b2a0e92..4d9ed5eea4 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -5778,6 +5778,7 @@ cuda_py_test( "no_oss", "noguitar", "notap", + "no_nccl" ], ) diff --git a/tools/bazel.rc b/tools/bazel.rc index 8c2052ee8a..76da3470dc 100644 --- a/tools/bazel.rc +++ b/tools/bazel.rc @@ -72,6 +72,8 @@ build:nogcp --define=no_gcp_support=true build:nohdfs --define=no_hdfs_support=true build:nokafka --define=no_kafka_support=true build:noignite --define=no_ignite_support=true +build:nonccl --define=no_nccl_support=true +test:nonccl --define=no_nccl_support=true --test_tag_filters=-no_nccl build --define=use_fast_cpp_protos=true build --define=allow_oversize_protos=true -- GitLab From 12d86380c897be13c16bfebf09ddd6593c464655 Mon Sep 17 00:00:00 2001 From: "Li, Guizi" Date: Sat, 17 Nov 2018 15:21:59 +0800 Subject: [PATCH 090/672] update mklml version to make it consistent with mkldnn. --- tensorflow/workspace.bzl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index fd800cf67d..b3c4938dd0 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -77,31 +77,31 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): mkl_repository( name = "mkl_linux", build_file = clean_dep("//third_party/mkl:mkl.BUILD"), - sha256 = "e2233534a9d15c387e22260997af4312a39e9f86f791768409be273b5453c4e6", - strip_prefix = "mklml_lnx_2019.0.20180710", + sha256 = "f00dc3b142a5be399bdeebd7e7ea369545a35d4fb84c86f98b6b048d72685295", + strip_prefix = "mklml_lnx_2019.0.1.20180928", urls = [ - "https://mirror.bazel.build/github.com/intel/mkl-dnn/releases/download/v0.16/mklml_lnx_2019.0.20180710.tgz", - "https://github.com/intel/mkl-dnn/releases/download/v0.16/mklml_lnx_2019.0.20180710.tgz", + "https://mirror.bazel.build/github.com/intel/mkl-dnn/releases/download/v0.17-rc/mklml_lnx_2019.0.1.20180928.tgz", + "https://github.com/intel/mkl-dnn/releases/download/v0.17-rc/mklml_lnx_2019.0.1.20180928.tgz", ], ) mkl_repository( name = "mkl_windows", build_file = clean_dep("//third_party/mkl:mkl.BUILD"), - sha256 = "3fdcff17b018a0082491adf3ba143358265336a801646e46e0191ec8d58d24a2", - strip_prefix = "mklml_win_2019.0.20180710", + sha256 = "efef90b7b9613fab10f44c8ac4ff28db613a112c64ed94826d7e44df09c44b0b", + strip_prefix = "mklml_win_2019.0.1.20180928", urls = [ - "https://mirror.bazel.build/github.com/intel/mkl-dnn/releases/download/v0.16/mklml_win_2019.0.20180710.zip", - "https://github.com/intel/mkl-dnn/releases/download/v0.16/mklml_win_2019.0.20180710.zip", + "https://mirror.bazel.build/github.com/intel/mkl-dnn/releases/download/v0.17-rc/mklml_win_2019.0.1.20180928.zip", + "https://github.com/intel/mkl-dnn/releases/download/v0.17-rc/mklml_win_2019.0.1.20180928.zip", ], ) mkl_repository( name = "mkl_darwin", build_file = clean_dep("//third_party/mkl:mkl.BUILD"), - sha256 = "411a30014a938eb83fb9f37b3dbe8e371b106fc1dd621fc23123cadc72737ce6", - strip_prefix = "mklml_mac_2019.0.20180710", + sha256 = "83f02938a0c095274db7b8b7b694157abafa3837c5cbaef740440d466c86a477", + strip_prefix = "mklml_mac_2019.0.1.20180928", urls = [ - "https://mirror.bazel.build/github.com/intel/mkl-dnn/releases/download/v0.16/mklml_mac_2019.0.20180710.tgz", - "https://github.com/intel/mkl-dnn/releases/download/v0.16/mklml_mac_2019.0.20180710.tgz", + "https://mirror.bazel.build/github.com/intel/mkl-dnn/releases/download/v0.17-rc/mklml_mac_2019.0.1.20180928.tgz", + "https://github.com/intel/mkl-dnn/releases/download/v0.17-rc/mklml_mac_2019.0.1.20180928.tgz", ], ) -- GitLab From 6ee836b86245a8dc989a7e66bd39a96b2d5b26e4 Mon Sep 17 00:00:00 2001 From: Sami Kama Date: Mon, 19 Nov 2018 09:55:37 -0800 Subject: [PATCH 091/672] Review changes --- tensorflow/python/BUILD | 1 - tools/bazel.rc | 1 - 2 files changed, 2 deletions(-) diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 4d9ed5eea4..e55b2a0e92 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -5778,7 +5778,6 @@ cuda_py_test( "no_oss", "noguitar", "notap", - "no_nccl" ], ) diff --git a/tools/bazel.rc b/tools/bazel.rc index 76da3470dc..1fdf51f53e 100644 --- a/tools/bazel.rc +++ b/tools/bazel.rc @@ -73,7 +73,6 @@ build:nohdfs --define=no_hdfs_support=true build:nokafka --define=no_kafka_support=true build:noignite --define=no_ignite_support=true build:nonccl --define=no_nccl_support=true -test:nonccl --define=no_nccl_support=true --test_tag_filters=-no_nccl build --define=use_fast_cpp_protos=true build --define=allow_oversize_protos=true -- GitLab From b7bc8650cd673e2b12ed2a9b5a81d8074cee1e2a Mon Sep 17 00:00:00 2001 From: Bryan Cutler Date: Mon, 19 Nov 2018 16:08:25 -0800 Subject: [PATCH 092/672] fixed grammar in dataset_ops and readers --- tensorflow/python/data/ops/dataset_ops.py | 28 +++++++++++------------ tensorflow/python/data/ops/readers.py | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index cf51fdffdd..37802b9105 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -278,9 +278,9 @@ class DatasetV2(object): Note that if `tensors` contains a NumPy array, and eager execution is not enabled, the values will be embedded in the graph as one or more `tf.constant` operations. For large datasets (> 1 GB), this can waste - memory and run into byte limits of graph serialization. If tensors contains - one or more large NumPy arrays, consider the alternative described in - [this guide](https://tensorflow.org/guide/datasets#consuming_numpy_arrays). + memory and run into byte limits of graph serialization. If `tensors` + contains one or more large NumPy arrays, consider the alternative described + in [this guide](https://tensorflow.org/guide/datasets#consuming_numpy_arrays). Args: tensors: A nested structure of tensors. @@ -297,9 +297,9 @@ class DatasetV2(object): Note that if `tensors` contains a NumPy array, and eager execution is not enabled, the values will be embedded in the graph as one or more `tf.constant` operations. For large datasets (> 1 GB), this can waste - memory and run into byte limits of graph serialization. If tensors contains - one or more large NumPy arrays, consider the alternative described in - [this guide](https://tensorflow.org/guide/datasets#consuming_numpy_arrays). + memory and run into byte limits of graph serialization. If `tensors` + contains one or more large NumPy arrays, consider the alternative described + in [this guide](https://tensorflow.org/guide/datasets#consuming_numpy_arrays). Args: tensors: A nested structure of tensors, each having the same size in the @@ -566,7 +566,7 @@ class DatasetV2(object): ``` Args: - *args: follow same semantics as python's xrange. + *args: follows the same semantics as python's xrange. len(args) == 1 -> start = 0, stop = args[0], step = 1 len(args) == 2 -> start = args[0], stop = args[1], step = 1 len(args) == 3 -> start = args[0], stop = args[1, stop = args[2] @@ -852,10 +852,10 @@ class DatasetV2(object): Raises: ValueError: if `num_shards` or `index` are illegal values. Note: error - checking is done on a best-effort basis, and aren't guaranteed to be - caught upon dataset creation. (e.g. providing in a placeholder tensor - bypasses the early checking, and will instead result in an error during - a session.run call.) + checking is done on a best-effort basis, and errors aren't guaranteed + to be caught upon dataset creation. (e.g. providing in a placeholder + tensor bypasses the early checking, and will instead result in an error + during a session.run call.) """ num_shards = ops.convert_to_tensor( num_shards, name="num_shards", dtype=dtypes.int64) @@ -892,7 +892,7 @@ class DatasetV2(object): batch_size: A `tf.int64` scalar `tf.Tensor`, representing the number of consecutive elements of this dataset to combine in a single batch. drop_remainder: (Optional.) A `tf.bool` scalar `tf.Tensor`, representing - whether the last batch should be dropped in the case its has fewer than + whether the last batch should be dropped in the case it has fewer than `batch_size` elements; the default behavior is not to drop the smaller batch. @@ -949,7 +949,7 @@ class DatasetV2(object): respective components. Defaults are `0` for numeric types and the empty string for string types. drop_remainder: (Optional.) A `tf.bool` scalar `tf.Tensor`, representing - whether the last batch should be dropped in the case its has fewer than + whether the last batch should be dropped in the case it has fewer than `batch_size` elements; the default behavior is not to drop the smaller batch. @@ -1573,7 +1573,7 @@ class DatasetV1Adapter(DatasetV1): class Options(object): """Represents options for tf.data.Dataset. - An `Options` object can be for instance used to control which static + An `Options` object can be, for instance, used to control which static optimizations to apply or whether to use performance modeling to dynamically tune the parallelism of operations such as `tf.data.Dataset.map` or `tf.data.Dataset.interleave`. diff --git a/tensorflow/python/data/ops/readers.py b/tensorflow/python/data/ops/readers.py index 8a563122a0..85999444d9 100644 --- a/tensorflow/python/data/ops/readers.py +++ b/tensorflow/python/data/ops/readers.py @@ -180,7 +180,7 @@ class TFRecordDatasetV2(dataset_ops.DatasetV2): def __init__(self, filenames, compression_type=None, buffer_size=None, num_parallel_reads=None): - """Creates a `TFRecordDataset` to read for one or more TFRecord files. + """Creates a `TFRecordDataset` to read one or more TFRecord files. NOTE: The `num_parallel_reads` argument can be used to improve performance when reading from a remote filesystem. -- GitLab From 8414baa94d62b23024b3a5a6b3dea23f3dcb4568 Mon Sep 17 00:00:00 2001 From: Bryan Cutler Date: Mon, 19 Nov 2018 16:08:45 -0800 Subject: [PATCH 093/672] fixed grammar in experimental enumerate_ops --- tensorflow/python/data/experimental/ops/enumerate_ops.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/data/experimental/ops/enumerate_ops.py b/tensorflow/python/data/experimental/ops/enumerate_ops.py index a1af98f552..f38cab12a7 100644 --- a/tensorflow/python/data/experimental/ops/enumerate_ops.py +++ b/tensorflow/python/data/experimental/ops/enumerate_ops.py @@ -26,9 +26,9 @@ from tensorflow.python.util.tf_export import tf_export @tf_export("data.experimental.enumerate_dataset") def enumerate_dataset(start=0): - """A transformation that enumerate the elements of a dataset. + """A transformation that enumerates the elements of a dataset. - It is Similar to python's `enumerate`. + It is similar to python's `enumerate`. For example: ```python -- GitLab From e13fa8d670b2dba7ba337471c918e5dbbeca3072 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Wed, 14 Nov 2018 08:33:51 -0800 Subject: [PATCH 094/672] TF-TRT: Improve log Add more information to the log including unsupported ops. --- .../contrib/tensorrt/convert/convert_graph.cc | 13 +++++---- .../contrib/tensorrt/convert/convert_nodes.cc | 2 +- .../contrib/tensorrt/kernels/trt_engine_op.cc | 4 +-- .../contrib/tensorrt/segment/segment.cc | 27 ++++++++++++++++--- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index f95ffe4100..9428fad309 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -435,7 +435,8 @@ tensorflow::Status GetEngineInfo( << "but this shouldn't have happened"; info->device = *segment_devices.begin(); } else { - LOG(ERROR) << "Can't find a device placement for the op!"; + VLOG(1) << "No device is assigned to the segment. " + << "A device will be assigned during graph execution (inference)."; } return Status::OK(); } @@ -875,10 +876,8 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { // need to check the input edges. [](const Edge* edge) { return true; }, OutputEdgeValidator(), segment_options, &initial_segments)); - if (initial_segments.size() > 1) { - VLOG(0) << "MULTIPLE tensorrt candidate conversion: " - << initial_segments.size(); - } + VLOG(0) << "Number of TensorRT candidate segments: " + << initial_segments.size(); // Get the EngineInfo for each segment. std::unordered_map node_map; @@ -910,7 +909,7 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { : EngineInfo::EngineType::TRTStatic); curr_engine.cached_engine_batches = params.cached_engine_batches; curr_engine.maximum_cached_engines = params.max_cached_engines; - StrAppend(&curr_engine.engine_name, "my_trt_op_", t); + StrAppend(&curr_engine.engine_name, "TRTEngineOp_", t); status = RegisterSegmentFunctionToFunctionLibrary( &graph, curr_engine.segment_graph_def, curr_engine.engine_name); if (!status.ok()) { @@ -971,7 +970,7 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { &graph, alloc.get(), &engine_nodes); // If status is ok, we successfully added the node to the graph and can // remove segment ops. Otherwise graph is not modified. - string msg = StrCat("Engine ", engine.engine_name, " creation for segment ", + string msg = StrCat("Adding TensorRT node ", engine.engine_name, " for segment ", i, ", composed of ", converted_segments.at(i).first.size(), " nodes"); if (VLOG_IS_ON(1)) { diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index af9bbbfdfd..68015a9a78 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -2982,7 +2982,7 @@ tensorflow::Status ConvertSegmentToGraphDef( } } *common_scope = local_scope; - VLOG(0) << "Segment @scope '" << local_scope << "', converted to graph"; + VLOG(1) << "Converted TensorRT candidate segment @scope '" << local_scope << "' to a GraphDef"; return tensorflow::Status::OK(); } diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc index 019446813a..3cdad69f49 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc @@ -491,8 +491,8 @@ TRTEngineOp::EngineCtxPair& TRTEngineOp::GetEngine(int batch_size, } TrtUniquePtrType engine; bool convert_successfully = false; - VLOG(0) << name() << " Constructing a new engine with batch size " - << batch_size; + VLOG(0) << "Building a new TensorRT engine for " << name() + << " with batch size " << batch_size; // Up to this point, calibrator_ can never be empty, since otherwise it // means calibration_mode_ is true and this path won't get executed. auto status = convert::ConvertGraphDefToEngine( diff --git a/tensorflow/contrib/tensorrt/segment/segment.cc b/tensorflow/contrib/tensorrt/segment/segment.cc index 4f64b7a952..9ee7b76e30 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.cc +++ b/tensorflow/contrib/tensorrt/segment/segment.cc @@ -406,22 +406,43 @@ tensorflow::Status SegmentGraph( // Use a union-find to collect the nodes that belong to the same // segment. A node value of nullptr indicates that the node is not a candidate // for TRT. + std::unordered_set unsupported_ops; + int num_unsupported_ops = 0; std::vector> node_segments; for (int i = 0; i < graph->num_node_ids(); ++i) { SimpleNode* node = graph->FindNodeId(i); if (options.exclude_node_list.count(node->name()) != 0) { - VLOG(1) << "Not a TF-TRT candidate: " << node->name() - << " (excluded by segmenter option)."; + VLOG(1) << "Not a TF-TRT candidate, " + << "(Op type: " << node->tf_node()->type_string() << "), " + << "(Op name: " << node->name() << "), " + << "(Reason: excluded by segmenter option)"; + unsupported_ops.emplace(node->tf_node()->type_string()); + num_unsupported_ops++; node = nullptr; } else { const Status status = candidate_fn(node->tf_node()); if (!status.ok()) { - VLOG(1) << "Not a TF-TRT candidate: " << node->name() << ": " << status; + VLOG(1) << "Not a TF-TRT candidate, " + << "(Op type: " << node->tf_node()->type_string() << "), " + << "(Op name: " << node->name() << "), " + << "(Reason: " << status << ")"; + unsupported_ops.emplace(node->tf_node()->type_string()); + num_unsupported_ops++; node = nullptr; } } node_segments.emplace_back(node); } + string msg = "There are " + + std::to_string(num_unsupported_ops) + + " unsupported ops of " + + std::to_string(unsupported_ops.size()) + + " different types in the graph: "; + for (const auto& elem: unsupported_ops) { + msg += elem + ", "; + } + LOG(INFO) << msg << "(For more information see " + << "https://docs.nvidia.com/deeplearning/dgx/integrate-tf-trt/index.html#support-ops)."; // The segmentation algorithm below visits nodes in reverse topological order // and attempts to merge nodes along output edges. That means that subgraphs -- GitLab From 0864b3eb3e3fa56c42501656703dec52e46ab8e4 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 01:02:12 -0800 Subject: [PATCH 095/672] compat: Update forward compatibility horizon to 2018-11-20 PiperOrigin-RevId: 222204359 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 43a5eb4e7f..1b8114dd26 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 19) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 20) @tf_export("compat.forward_compatible") -- GitLab From 30dcdb99aaf7139ea09bb049f15192ec72ebf47b Mon Sep 17 00:00:00 2001 From: Ilya Biryukov Date: Tue, 20 Nov 2018 01:43:24 -0800 Subject: [PATCH 096/672] Update downloadable clang to r346388, subrevision 3 PiperOrigin-RevId: 222210141 --- third_party/clang_toolchain/download_clang.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/third_party/clang_toolchain/download_clang.bzl b/third_party/clang_toolchain/download_clang.bzl index 9023e250b2..a941ee1c99 100644 --- a/third_party/clang_toolchain/download_clang.bzl +++ b/third_party/clang_toolchain/download_clang.bzl @@ -40,14 +40,14 @@ def download_clang(repo_ctx, out_folder): # Latest CLANG_REVISION and CLANG_SUB_REVISION of the Chromiums's release # can be found in https://chromium.googlesource.com/chromium/src/tools/clang/+/master/scripts/update.py CLANG_REVISION = "346388" - CLANG_SUB_REVISION = 1 + CLANG_SUB_REVISION = 3 package_version = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION) checksums = { - "Linux_x64": "5e5564e4e743414c7eaec9fd9e739732ddd2a343e49bde4c88fc2530b1c598b9", - "Mac": "19271a7cc5c2bcaf9643d3dd622b5458569dc662bbc58f63b129cf6e3a4e3243", - "Win": "60b0bd1f11e53892109f4159e2aba0f803604823e07875ca98b82bd5628d7f4d", + "Linux_x64": "d47b7ac4756c3f8e3bbfa0e81bf199ec8e9faa3a6b11573f0705e9c04af7ad51", + "Mac": "de2b0c701e19cda633ea02804866dd24d8506afb8cae51fbcce3415b76f4ded3", + "Win": "c7d27f13b41aa9eaaf9760903962e9b2b0f8261058df0d35170711dc60545a7d", } platform_folder = _get_platform_folder(repo_ctx.os.name) -- GitLab From 07f6ed9896bcf6f193f794a6c22398c3a6bcada6 Mon Sep 17 00:00:00 2001 From: Cibifang Date: Tue, 20 Nov 2018 18:48:51 +0800 Subject: [PATCH 097/672] Fix comment for AddGradients in graph.go --- tensorflow/go/graph.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index fb191fb51e..84e81c7755 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -147,7 +147,7 @@ func (g *Graph) Operations() []Operation { return ops } -// AddGradients add operations to compute the partial derivatives of the sum of tensors in y +// AddGradients adds operations to compute the partial derivatives of the sum of tensors in y // with respect to tensors in x, i.e., d(y[0] + y[1] + ...) / d x[0], d(y[0] + y[1] + ... ) / d x[1] etc. // // prefix, if non-empty, is the name prefix used for all operations added to the graph to compute -- GitLab From 8b118ec4bee5f76b6672ddb79fcb095d75705e22 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Tue, 20 Nov 2018 02:57:03 -0800 Subject: [PATCH 098/672] Improve the sort implementation for the CPU backend. We can use the same trick as on the other backends to cast the floating types to integer types and then comparing these. This is faster. Also use stable_sort instead of sort to simplify the custom comparators. PiperOrigin-RevId: 222217591 --- .../xla/service/cpu/runtime_key_value_sort.cc | 80 +++++++++---------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc b/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc index 669eeb95f3..c7fc101ec7 100644 --- a/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc +++ b/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc @@ -17,6 +17,7 @@ limitations under the License. #include #include #include +#include #include #include #include @@ -41,61 +42,58 @@ void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { std::sort(row_to_sort, row_to_sort + num_elements); } -// For floating point numbers, we want a total order comparator. -NaN and NaN -// should appear at the beginning and end of the ordering, and -0.0 should -// appear before 0.0. Also we want to have a stable sort, so if the keys are the -// same, we compare the index values. -template -bool LessThan(KeyType lhs, int64 lhs_index, KeyType rhs, int64 rhs_index) { - bool lhs_is_negative = std::signbit(lhs); - bool rhs_is_negative = std::signbit(rhs); - // If the signs are different, we can just compare the signs. - if (lhs_is_negative != rhs_is_negative) { - return lhs_is_negative && !rhs_is_negative; - } - bool lhs_nan = std::isnan(lhs); - bool rhs_nan = std::isnan(rhs); - // Exactly one number is nan? - if (lhs_nan != rhs_nan) { - if (lhs_nan) { - return lhs_is_negative; - } - return !rhs_is_negative; +// We would like a total order of floating point numbers so that the +// sort has a predictable behavior in the presence of NaNs. Rather +// than using floating point comparison, we use the following trick: +// If f is a float, and +// x = bit_cast(f); +// y = x < 0 ? 0x7FFFFFFF - x : x; +// then y is ordered as an int32 such that finite values have the +// obvious order, -0 is ordered before 0, and -NaN and NaN appear at +// the beginning and end of the ordering. +template +CastType Convert(KeyType value) { + CastType casted_value; + memcpy(&casted_value, &value, sizeof(CastType)); + if (casted_value < 0) { + return std::numeric_limits::max() - casted_value; } - if (lhs != rhs) { - return lhs < rhs; - } - return lhs_index < rhs_index; + return casted_value; +} + +template +bool LessThan(KeyType lhs, KeyType rhs) { + return Convert(lhs) < Convert(rhs); } template <> void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { - std::sort(row_to_sort, row_to_sort + num_elements, - [](const std::pair& lhs, - const std::pair& rhs) -> bool { - return LessThan(lhs.first, lhs.second, rhs.first, rhs.second); - }); + std::stable_sort(row_to_sort, row_to_sort + num_elements, + [](const std::pair& lhs, + const std::pair& rhs) -> bool { + return LessThan(lhs.first, rhs.first); + }); } template <> void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { - std::sort(row_to_sort, row_to_sort + num_elements, - [](const std::pair& lhs, - const std::pair& rhs) -> bool { - return LessThan(lhs.first, lhs.second, rhs.first, rhs.second); - }); + std::stable_sort(row_to_sort, row_to_sort + num_elements, + [](const std::pair& lhs, + const std::pair& rhs) -> bool { + return LessThan(lhs.first, rhs.first); + }); } template <> void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { - std::sort(row_to_sort, row_to_sort + num_elements, - [](const std::pair& lhs, - const std::pair& rhs) -> bool { - return LessThan( - Eigen::half_impl::half_to_float(lhs.first), lhs.second, - Eigen::half_impl::half_to_float(rhs.first), rhs.second); - }); + std::stable_sort(row_to_sort, row_to_sort + num_elements, + [](const std::pair& lhs, + const std::pair& rhs) -> bool { + return LessThan( + Eigen::half_impl::half_to_float(lhs.first), + Eigen::half_impl::half_to_float(rhs.first)); + }); } template -- GitLab From 4a51de309e95173c78558873542fd2dcdd1889dd Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 06:11:31 -0800 Subject: [PATCH 099/672] Optimize XlaDevice::Sync by allowing it to happen asynchronously. PiperOrigin-RevId: 222234647 --- tensorflow/compiler/jit/xla_device.cc | 25 ++++++++++++++++++++++ tensorflow/compiler/jit/xla_device.h | 1 + tensorflow/core/common_runtime/device.cc | 2 ++ tensorflow/core/common_runtime/device.h | 10 +++++++++ tensorflow/core/common_runtime/executor.cc | 17 +++++++++------ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/tensorflow/compiler/jit/xla_device.cc b/tensorflow/compiler/jit/xla_device.cc index 738bac54cc..4201ff91a8 100644 --- a/tensorflow/compiler/jit/xla_device.cc +++ b/tensorflow/compiler/jit/xla_device.cc @@ -410,6 +410,31 @@ Status XlaDevice::Sync() { return Status::OK(); } +void XlaDevice::Sync(const DoneCallback& done) { + VLOG(1) << "XlaDevice::Sync (asynchronous)"; + std::shared_ptr stream; + { + mutex_lock lock(mu_); + stream = stream_; + } + if (!stream) { + done(Status::OK()); + return; + } + + stream->ThenEnqueueOnBackgroundThread( + [this, stream, done](se::StreamExecutor*) { + tracing::ScopedActivity activity("XlaDevice::Sync::Callback", + /*is_expensive=*/true); + mutex_lock lock(mu_); + while (outstanding_asynchronous_operations_ > 0) { + outstanding_asynchronous_operations_cv_.wait(lock); + } + done(stream->ok() ? Status::OK() + : errors::Internal("XlaDevice::Sync() failed.")); + }); +} + Status XlaDevice::MakeTensorFromProto(const TensorProto& tensor_proto, const AllocatorAttributes alloc_attrs, Tensor* tensor) { diff --git a/tensorflow/compiler/jit/xla_device.h b/tensorflow/compiler/jit/xla_device.h index dc8f49a9c9..c8bb276cdb 100644 --- a/tensorflow/compiler/jit/xla_device.h +++ b/tensorflow/compiler/jit/xla_device.h @@ -135,6 +135,7 @@ class XlaDevice : public LocalDevice { void ComputeAsync(AsyncOpKernel* op_kernel, OpKernelContext* context, AsyncOpKernel::DoneCallback done) override; Status Sync() override; + void Sync(const DoneCallback& done) override; Status FillContextMap(const Graph* graph, DeviceContextMap* device_context_map) override diff --git a/tensorflow/core/common_runtime/device.cc b/tensorflow/core/common_runtime/device.cc index 8fc64fff69..9925814a48 100644 --- a/tensorflow/core/common_runtime/device.cc +++ b/tensorflow/core/common_runtime/device.cc @@ -36,6 +36,8 @@ Device::~Device() { } } +void Device::Sync(const DoneCallback& done) { done(Sync()); } + // static DeviceAttributes Device::BuildDeviceAttributes( const string& name, DeviceType device, Bytes memory_limit, diff --git a/tensorflow/core/common_runtime/device.h b/tensorflow/core/common_runtime/device.h index 2ef1547cd9..8dfbb21eda 100644 --- a/tensorflow/core/common_runtime/device.h +++ b/tensorflow/core/common_runtime/device.h @@ -55,6 +55,9 @@ class DeviceMgr; class Device : public DeviceBase { public: + // Callback type that takes a Status and returns void. + typedef std::function DoneCallback; + Device(Env* env, const DeviceAttributes& device_attributes); ~Device() override; @@ -112,6 +115,13 @@ class Device : public DeviceBase { // at completion. virtual Status Sync() = 0; + // Calls the given callback when all operations queued on the device at the + // time of the call have completed. The callback is passed any error pending + // on the device at completion. + // TODO(b/112409994): Consolidate these two APIs, removing the synchronous + // version. + virtual void Sync(const DoneCallback& done); + // Override this to return true for devices that require a Sync() call before // session completion. virtual bool RequiresSyncOnCompletion() const { return false; } diff --git a/tensorflow/core/common_runtime/executor.cc b/tensorflow/core/common_runtime/executor.cc index b9115f86ff..77b249c2b4 100644 --- a/tensorflow/core/common_runtime/executor.cc +++ b/tensorflow/core/common_runtime/executor.cc @@ -1713,7 +1713,7 @@ void ExecutorState::Process(TaggedNode tagged_node, int64 scheduled_nsec) { auto done = [this, state]() { Device* device = impl_->params_.device; NodeExecStatsInterface* stats = state->stats; // Shorthand - Entry* first_input = state->first_input; // Shorthand + Entry* first_input = state->first_input; // Shorthand nodestats::SetOpEnd(stats); EntryVector outputs; @@ -2394,18 +2394,23 @@ void ExecutorState::Finish() { auto done_cb = std::move(done_cb_); auto runner = std::move(runner_); mu_.unlock(); + CHECK(done_cb != nullptr); Device* device = impl_->params_.device; + if ((sync_on_finish_ && status.ok()) || device->RequiresSyncOnCompletion()) { // Block until the device has finished all queued operations. For // devices like GPUs that continue to execute Ops after their Compute // methods have completed, this ensures that control is not returned to // the user until the step (and its side-effects) has actually completed. - status.Update(device->Sync()); + device->Sync([=](Status new_status) mutable { + status.Update(new_status); + delete this; + runner([=]() { done_cb(status); }); + }); + } else { + delete this; + runner([=]() { done_cb(status); }); } - - delete this; - CHECK(done_cb != nullptr); - runner([=]() { done_cb(status); }); } void ExecutorState::FindOrCreateChildFrame(FrameState* frame, int64 iter, -- GitLab From cdd3a982536242b123559c6ae785c2894888184a Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Tue, 20 Nov 2018 07:10:28 -0800 Subject: [PATCH 100/672] Handle deeply nested concatenates with same operands. Currently we would generate an exponential number of basic blocks. With this CL, we generate each unique operand only once, and use a PHI node for the source index input. PiperOrigin-RevId: 222240704 --- tensorflow/compiler/xla/service/BUILD | 1 + .../xla/service/elemental_ir_emitter.cc | 65 +++++++++++++++---- tensorflow/compiler/xla/tests/concat_test.cc | 26 ++++++++ 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index d5e73fe1a8..1bd04d2785 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -2984,6 +2984,7 @@ cc_library( "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", "@llvm//:core", "@llvm//:transform_utils", diff --git a/tensorflow/compiler/xla/service/elemental_ir_emitter.cc b/tensorflow/compiler/xla/service/elemental_ir_emitter.cc index f98c943669..00bb430206 100644 --- a/tensorflow/compiler/xla/service/elemental_ir_emitter.cc +++ b/tensorflow/compiler/xla/service/elemental_ir_emitter.cc @@ -22,6 +22,7 @@ limitations under the License. // IWYU pragma: no_include "llvm/IR/Intrinsics.gen.inc" #include "absl/algorithm/container.h" +#include "absl/container/flat_hash_map.h" #include "absl/strings/str_cat.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Instructions.h" @@ -1671,26 +1672,66 @@ StatusOr ElementalIrEmitter::EmitElementalConcatenate( b_->SetInsertPoint(init_block); + // Assign a unique id for each *different* operand, and count how often each + // operand is used. If all operands are different, the usage count will be 1 + // for each operand. + absl::flat_hash_map to_unique_operand_id; + std::vector operand_usage_count; + for (const auto* operand : hlo->operands()) { + if (to_unique_operand_id.contains(operand)) { + ++operand_usage_count[to_unique_operand_id[operand]]; + } else { + int64 unique_operand_id = to_unique_operand_id.size(); + to_unique_operand_id[operand] = unique_operand_id; + operand_usage_count.push_back(1); + } + } + + // To avoid that we emit the same operand more than once, we create one basic + // block for each *different* operand with a PHI node for the different source + // index inputs. + std::vector emit_operand_blocks( + to_unique_operand_id.size(), nullptr); + std::vector source_index_phis(to_unique_operand_id.size(), + nullptr); + for (const auto* operand : hlo->operands()) { + int64 operand_id = to_unique_operand_id[operand]; + if (emit_operand_blocks[operand_id] != nullptr) { + continue; + } + + emit_operand_blocks[operand_id] = llvm_ir::CreateBasicBlock( + exit_block, StrCat("concat_index_from_operand_id", operand_id), b_); + auto saved_insert_point = b_->GetInsertPoint(); + llvm_ir::SetToFirstInsertPoint(emit_operand_blocks[operand_id], b_); + source_index_phis[operand_id] = + PHI(source_index.GetType(), operand_usage_count[operand_id]); + auto operand_index = source_index; + operand_index[concat_dim] = source_index_phis[operand_id]; + + // Create the terminator of the block before calling operand generators, + // because they require non-degenerate basic blocks. + b_->SetInsertPoint(llvm::BranchInst::Create( + exit_block, /*InsertAtEnd=*/emit_operand_blocks[operand_id])); + TF_ASSIGN_OR_RETURN(llvm::Value * value, + operand_to_generator.at(operand)(operand_index)); + output->addIncoming(value, b_->GetInsertBlock()); + b_->SetInsertPoint(init_block, saved_insert_point); + } + for (int64 operand_idx = 0; operand_idx < hlo->operand_count(); ++operand_idx) { const HloInstruction* operand = hlo->operand(operand_idx); - auto true_block = llvm_ir::CreateBasicBlock( - exit_block, StrCat("concat_index_from_operand", operand_idx), b_); auto false_block = llvm_ir::CreateBasicBlock( exit_block, StrCat("concat_index_not_from_operand", operand_idx), b_); auto concat_dim_size = llvm::ConstantInt::get(source_index[concat_dim]->getType(), operand->shape().dimensions(concat_dim)); - CondBr(ICmpULT(source_index[concat_dim], concat_dim_size), true_block, - false_block); - - // Create the terminator of the true block before calling operand - // generators, because they require non-degenerate basic blocks. - b_->SetInsertPoint( - llvm::BranchInst::Create(exit_block, /*InsertAtEnd=*/true_block)); - TF_ASSIGN_OR_RETURN(llvm::Value * value, - operand_to_generator.at(operand)(source_index)); - output->addIncoming(value, b_->GetInsertBlock()); + int64 operand_id = to_unique_operand_id[operand]; + source_index_phis[operand_id]->addIncoming(source_index[concat_dim], + b_->GetInsertBlock()); + CondBr(ICmpULT(source_index[concat_dim], concat_dim_size), + emit_operand_blocks[operand_id], false_block); // Subtract the size of the concat dimension of the current operand // from the source index. diff --git a/tensorflow/compiler/xla/tests/concat_test.cc b/tensorflow/compiler/xla/tests/concat_test.cc index 9811a015e9..4f5b525a34 100644 --- a/tensorflow/compiler/xla/tests/concat_test.cc +++ b/tensorflow/compiler/xla/tests/concat_test.cc @@ -492,6 +492,32 @@ XLA_TEST_F(ConcatTest, ConcatR3WeirdDims) { ComputeAndCompareR3(&builder, expected, {p0.get(), p1.get()}); } +XLA_TEST_F(ConcatTest, ConcatDeeplyNested) { + XlaBuilder builder(TestName()); + auto a_literal = LiteralUtil::CreateR1({256.0}); + auto a = Parameter(&builder, 0, a_literal.shape(), "x"); + auto b = ConcatInDim(&builder, {a, a}, 0); + auto c = ConcatInDim(&builder, {b, b}, 0); + auto d = ConcatInDim(&builder, {c, c}, 0); + auto e = ConcatInDim(&builder, {d, d}, 0); + auto f = ConcatInDim(&builder, {e, e}, 0); + auto g = ConcatInDim(&builder, {f, f}, 0); + auto h = ConcatInDim(&builder, {g, g}, 0); + auto i = ConcatInDim(&builder, {h, h}, 0); + auto j = ConcatInDim(&builder, {i, i}, 0); + auto k = ConcatInDim(&builder, {j, j}, 0); + auto l = ConcatInDim(&builder, {k, k}, 0); + auto m = ConcatInDim(&builder, {l, l}, 0); + auto n = ConcatInDim(&builder, {m, m}, 0); + auto o = ConcatInDim(&builder, {n, n}, 0); + auto p = ConcatInDim(&builder, {o, o}, 0); + auto q = ConcatInDim(&builder, {p, p}, 0); + ConcatInDim(&builder, {q, q}, 0); + std::vector expected(131072, 256.0); + auto a_data = client_->TransferToServer(a_literal).ConsumeValueOrDie(); + ComputeAndCompareR1(&builder, expected, {a_data.get()}); +} + // Describes a binary rank-2 concatenation test. struct R2BinarySpec { int64 lhs_dim0; -- GitLab From f25493f9c0ae0dec6db31dfe7fd19ed01b57c23d Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 07:44:36 -0800 Subject: [PATCH 101/672] Re-create the gcc-nvcc remote configuration. Given that the nvcc path is hard-coded in the config, move it from a cuda-agnostic location to one that includes the cuda version. PiperOrigin-RevId: 222244416 --- .../ubuntu14.04/cuda9.0-cudnn7/cuda/BUILD | 10 +- .../cuda9.0-cudnn7/cuda/build_defs.bzl | 6 +- .../ubuntu14.04/gcc-nvcc-cuda9.0/BUILD | 87 + .../ubuntu14.04/gcc-nvcc-cuda9.0/CROSSTOOL | 1431 +++++++++++++++++ .../bin/crosstool_wrapper_driver_is_not_gcc | 264 +++ .../windows/msvc_wrapper_for_nvcc.bat | 20 + .../windows/msvc_wrapper_for_nvcc.py | 192 +++ .../preconfig/ubuntu14.04/py3/BUILD | 4 +- 8 files changed, 2003 insertions(+), 11 deletions(-) create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/BUILD create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/CROSSTOOL create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/clang/bin/crosstool_wrapper_driver_is_not_gcc create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.bat create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.py diff --git a/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/BUILD b/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/BUILD index 247e0ace24..c6930904b5 100755 --- a/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/BUILD +++ b/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/BUILD @@ -1188,7 +1188,7 @@ genrule( "cuda/include/vector_types.h", ], cmd = """ -if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp "/usr/local/cuda-9.0/include/CL/cl.h" "$(@D)/cuda/include/CL/cl.h" && cp "/usr/local/cuda-9.0/include/CL/cl.hpp" "$(@D)/cuda/include/CL/cl.hpp" && cp "/usr/local/cuda-9.0/include/CL/cl_egl.h" "$(@D)/cuda/include/CL/cl_egl.h" && cp "/usr/local/cuda-9.0/include/CL/cl_ext.h" "$(@D)/cuda/include/CL/cl_ext.h" && cp "/usr/local/cuda-9.0/include/CL/cl_gl.h" "$(@D)/cuda/include/CL/cl_gl.h" && cp "/usr/local/cuda-9.0/include/CL/cl_gl_ext.h" "$(@D)/cuda/include/CL/cl_gl_ext.h" && cp "/usr/local/cuda-9.0/include/CL/cl_platform.h" "$(@D)/cuda/include/CL/cl_platform.h" && cp "/usr/local/cuda-9.0/include/CL/opencl.h" "$(@D)/cuda/include/CL/opencl.h" && cp "/usr/local/cuda-9.0/include/builtin_types.h" "$(@D)/cuda/include/builtin_types.h" && cp "/usr/local/cuda-9.0/include/channel_descriptor.h" "$(@D)/cuda/include/channel_descriptor.h" && cp "/usr/local/cuda-9.0/include/common_functions.h" "$(@D)/cuda/include/common_functions.h" && cp "/usr/local/cuda-9.0/include/cooperative_groups.h" "$(@D)/cuda/include/cooperative_groups.h" && cp "/usr/local/cuda-9.0/include/cooperative_groups_helpers.h" "$(@D)/cuda/include/cooperative_groups_helpers.h" && cp "/usr/local/cuda-9.0/include/crt/common_functions.h" "$(@D)/cuda/include/crt/common_functions.h" && cp "/usr/local/cuda-9.0/include/crt/device_double_functions.h" "$(@D)/cuda/include/crt/device_double_functions.h" && cp "/usr/local/cuda-9.0/include/crt/device_double_functions.hpp" "$(@D)/cuda/include/crt/device_double_functions.hpp" && cp "/usr/local/cuda-9.0/include/crt/device_functions.h" "$(@D)/cuda/include/crt/device_functions.h" && cp "/usr/local/cuda-9.0/include/crt/device_functions.hpp" "$(@D)/cuda/include/crt/device_functions.hpp" && cp "/usr/local/cuda-9.0/include/crt/func_macro.h" "$(@D)/cuda/include/crt/func_macro.h" && cp "/usr/local/cuda-9.0/include/crt/host_config.h" "$(@D)/cuda/include/crt/host_config.h" && cp "/usr/local/cuda-9.0/include/crt/host_defines.h" "$(@D)/cuda/include/crt/host_defines.h" && cp "/usr/local/cuda-9.0/include/crt/host_runtime.h" "$(@D)/cuda/include/crt/host_runtime.h" && cp "/usr/local/cuda-9.0/include/crt/math_functions.h" "$(@D)/cuda/include/crt/math_functions.h" && cp "/usr/local/cuda-9.0/include/crt/math_functions.hpp" "$(@D)/cuda/include/crt/math_functions.hpp" && cp "/usr/local/cuda-9.0/include/crt/mma.h" "$(@D)/cuda/include/crt/mma.h" && cp "/usr/local/cuda-9.0/include/crt/mma.hpp" "$(@D)/cuda/include/crt/mma.hpp" && cp "/usr/local/cuda-9.0/include/crt/nvfunctional" "$(@D)/cuda/include/crt/nvfunctional" && cp "/usr/local/cuda-9.0/include/crt/sm_70_rt.h" "$(@D)/cuda/include/crt/sm_70_rt.h" && cp "/usr/local/cuda-9.0/include/crt/sm_70_rt.hpp" "$(@D)/cuda/include/crt/sm_70_rt.hpp" && cp "/usr/local/cuda-9.0/include/crt/storage_class.h" "$(@D)/cuda/include/crt/storage_class.h" && cp "/usr/local/cuda-9.0/include/cuComplex.h" "$(@D)/cuda/include/cuComplex.h" && cp "/usr/local/cuda-9.0/include/cublas.h" "$(@D)/cuda/include/cublas.h" && cp "/usr/local/cuda-9.0/include/cublasXt.h" "$(@D)/cuda/include/cublasXt.h" && cp "/usr/local/cuda-9.0/include/cublas_api.h" "$(@D)/cuda/include/cublas_api.h" && cp "/usr/local/cuda-9.0/include/cublas_v2.h" "$(@D)/cuda/include/cublas_v2.h" && cp "/usr/local/cuda-9.0/include/cuda.h" "$(@D)/cuda/include/cuda.h" && cp "/usr/local/cuda-9.0/include/cudaEGL.h" "$(@D)/cuda/include/cudaEGL.h" && cp "/usr/local/cuda-9.0/include/cudaGL.h" "$(@D)/cuda/include/cudaGL.h" && cp "/usr/local/cuda-9.0/include/cudaProfiler.h" "$(@D)/cuda/include/cudaProfiler.h" && cp "/usr/local/cuda-9.0/include/cudaVDPAU.h" "$(@D)/cuda/include/cudaVDPAU.h" && cp "/usr/local/cuda-9.0/include/cuda_device_runtime_api.h" "$(@D)/cuda/include/cuda_device_runtime_api.h" && cp "/usr/local/cuda-9.0/include/cuda_fp16.h" "$(@D)/cuda/include/cuda_fp16.h" && cp "/usr/local/cuda-9.0/include/cuda_fp16.hpp" "$(@D)/cuda/include/cuda_fp16.hpp" && cp "/usr/local/cuda-9.0/include/cuda_gl_interop.h" "$(@D)/cuda/include/cuda_gl_interop.h" && cp "/usr/local/cuda-9.0/include/cuda_occupancy.h" "$(@D)/cuda/include/cuda_occupancy.h" && cp "/usr/local/cuda-9.0/include/cuda_profiler_api.h" "$(@D)/cuda/include/cuda_profiler_api.h" && cp "/usr/local/cuda-9.0/include/cuda_runtime.h" "$(@D)/cuda/include/cuda_runtime.h" && cp "/usr/local/cuda-9.0/include/cuda_runtime_api.h" "$(@D)/cuda/include/cuda_runtime_api.h" && cp "/usr/local/cuda-9.0/include/cuda_surface_types.h" "$(@D)/cuda/include/cuda_surface_types.h" && cp "/usr/local/cuda-9.0/include/cuda_texture_types.h" "$(@D)/cuda/include/cuda_texture_types.h" && cp "/usr/local/cuda-9.0/include/cuda_vdpau_interop.h" "$(@D)/cuda/include/cuda_vdpau_interop.h" && cp "/usr/local/cuda-9.0/include/cudalibxt.h" "$(@D)/cuda/include/cudalibxt.h" && cp "/usr/local/cuda-9.0/include/cufft.h" "$(@D)/cuda/include/cufft.h" && cp "/usr/local/cuda-9.0/include/cufftXt.h" "$(@D)/cuda/include/cufftXt.h" && cp "/usr/local/cuda-9.0/include/cufftw.h" "$(@D)/cuda/include/cufftw.h" && cp "/usr/local/cuda-9.0/include/curand.h" "$(@D)/cuda/include/curand.h" && cp "/usr/local/cuda-9.0/include/curand_discrete.h" "$(@D)/cuda/include/curand_discrete.h" && cp "/usr/local/cuda-9.0/include/curand_discrete2.h" "$(@D)/cuda/include/curand_discrete2.h" && cp "/usr/local/cuda-9.0/include/curand_globals.h" "$(@D)/cuda/include/curand_globals.h" && cp "/usr/local/cuda-9.0/include/curand_kernel.h" "$(@D)/cuda/include/curand_kernel.h" && cp "/usr/local/cuda-9.0/include/curand_lognormal.h" "$(@D)/cuda/include/curand_lognormal.h" && cp "/usr/local/cuda-9.0/include/curand_mrg32k3a.h" "$(@D)/cuda/include/curand_mrg32k3a.h" && cp "/usr/local/cuda-9.0/include/curand_mtgp32.h" "$(@D)/cuda/include/curand_mtgp32.h" && cp "/usr/local/cuda-9.0/include/curand_mtgp32_host.h" "$(@D)/cuda/include/curand_mtgp32_host.h" && cp "/usr/local/cuda-9.0/include/curand_mtgp32_kernel.h" "$(@D)/cuda/include/curand_mtgp32_kernel.h" && cp "/usr/local/cuda-9.0/include/curand_mtgp32dc_p_11213.h" "$(@D)/cuda/include/curand_mtgp32dc_p_11213.h" && cp "/usr/local/cuda-9.0/include/curand_normal.h" "$(@D)/cuda/include/curand_normal.h" && cp "/usr/local/cuda-9.0/include/curand_normal_static.h" "$(@D)/cuda/include/curand_normal_static.h" && cp "/usr/local/cuda-9.0/include/curand_philox4x32_x.h" "$(@D)/cuda/include/curand_philox4x32_x.h" && cp "/usr/local/cuda-9.0/include/curand_poisson.h" "$(@D)/cuda/include/curand_poisson.h" && cp "/usr/local/cuda-9.0/include/curand_precalc.h" "$(@D)/cuda/include/curand_precalc.h" && cp "/usr/local/cuda-9.0/include/curand_uniform.h" "$(@D)/cuda/include/curand_uniform.h" && cp "/usr/local/cuda-9.0/include/cusolverDn.h" "$(@D)/cuda/include/cusolverDn.h" && cp "/usr/local/cuda-9.0/include/cusolverRf.h" "$(@D)/cuda/include/cusolverRf.h" && cp "/usr/local/cuda-9.0/include/cusolverSp.h" "$(@D)/cuda/include/cusolverSp.h" && cp "/usr/local/cuda-9.0/include/cusolverSp_LOWLEVEL_PREVIEW.h" "$(@D)/cuda/include/cusolverSp_LOWLEVEL_PREVIEW.h" && cp "/usr/local/cuda-9.0/include/cusolver_common.h" "$(@D)/cuda/include/cusolver_common.h" && cp "/usr/local/cuda-9.0/include/cusparse.h" "$(@D)/cuda/include/cusparse.h" && cp "/usr/local/cuda-9.0/include/cusparse_v2.h" "$(@D)/cuda/include/cusparse_v2.h" && cp "/usr/local/cuda-9.0/include/device_atomic_functions.h" "$(@D)/cuda/include/device_atomic_functions.h" && cp "/usr/local/cuda-9.0/include/device_atomic_functions.hpp" "$(@D)/cuda/include/device_atomic_functions.hpp" && cp "/usr/local/cuda-9.0/include/device_double_functions.h" "$(@D)/cuda/include/device_double_functions.h" && cp "/usr/local/cuda-9.0/include/device_double_functions.hpp" "$(@D)/cuda/include/device_double_functions.hpp" && cp "/usr/local/cuda-9.0/include/device_functions.h" "$(@D)/cuda/include/device_functions.h" && cp "/usr/local/cuda-9.0/include/device_functions.hpp" "$(@D)/cuda/include/device_functions.hpp" && cp "/usr/local/cuda-9.0/include/device_functions_decls.h" "$(@D)/cuda/include/device_functions_decls.h" && cp "/usr/local/cuda-9.0/include/device_launch_parameters.h" "$(@D)/cuda/include/device_launch_parameters.h" && cp "/usr/local/cuda-9.0/include/device_types.h" "$(@D)/cuda/include/device_types.h" && cp "/usr/local/cuda-9.0/include/driver_functions.h" "$(@D)/cuda/include/driver_functions.h" && cp "/usr/local/cuda-9.0/include/driver_types.h" "$(@D)/cuda/include/driver_types.h" && cp "/usr/local/cuda-9.0/include/dynlink_cuda.h" "$(@D)/cuda/include/dynlink_cuda.h" && cp "/usr/local/cuda-9.0/include/dynlink_cuda_cuda.h" "$(@D)/cuda/include/dynlink_cuda_cuda.h" && cp "/usr/local/cuda-9.0/include/dynlink_cuviddec.h" "$(@D)/cuda/include/dynlink_cuviddec.h" && cp "/usr/local/cuda-9.0/include/dynlink_nvcuvid.h" "$(@D)/cuda/include/dynlink_nvcuvid.h" && cp "/usr/local/cuda-9.0/include/fatBinaryCtl.h" "$(@D)/cuda/include/fatBinaryCtl.h" && cp "/usr/local/cuda-9.0/include/fatbinary.h" "$(@D)/cuda/include/fatbinary.h" && cp "/usr/local/cuda-9.0/include/host_config.h" "$(@D)/cuda/include/host_config.h" && cp "/usr/local/cuda-9.0/include/host_defines.h" "$(@D)/cuda/include/host_defines.h" && cp "/usr/local/cuda-9.0/include/library_types.h" "$(@D)/cuda/include/library_types.h" && cp "/usr/local/cuda-9.0/include/math_constants.h" "$(@D)/cuda/include/math_constants.h" && cp "/usr/local/cuda-9.0/include/math_functions.h" "$(@D)/cuda/include/math_functions.h" && cp "/usr/local/cuda-9.0/include/math_functions.hpp" "$(@D)/cuda/include/math_functions.hpp" && cp "/usr/local/cuda-9.0/include/math_functions_dbl_ptx3.h" "$(@D)/cuda/include/math_functions_dbl_ptx3.h" && cp "/usr/local/cuda-9.0/include/math_functions_dbl_ptx3.hpp" "$(@D)/cuda/include/math_functions_dbl_ptx3.hpp" && cp "/usr/local/cuda-9.0/include/mma.h" "$(@D)/cuda/include/mma.h" && cp "/usr/local/cuda-9.0/include/npp.h" "$(@D)/cuda/include/npp.h" && cp "/usr/local/cuda-9.0/include/nppcore.h" "$(@D)/cuda/include/nppcore.h" && cp "/usr/local/cuda-9.0/include/nppdefs.h" "$(@D)/cuda/include/nppdefs.h" && cp "/usr/local/cuda-9.0/include/nppi.h" "$(@D)/cuda/include/nppi.h" && cp "/usr/local/cuda-9.0/include/nppi_arithmetic_and_logical_operations.h" "$(@D)/cuda/include/nppi_arithmetic_and_logical_operations.h" && cp "/usr/local/cuda-9.0/include/nppi_color_conversion.h" "$(@D)/cuda/include/nppi_color_conversion.h" && cp "/usr/local/cuda-9.0/include/nppi_compression_functions.h" "$(@D)/cuda/include/nppi_compression_functions.h" && cp "/usr/local/cuda-9.0/include/nppi_computer_vision.h" "$(@D)/cuda/include/nppi_computer_vision.h" && cp "/usr/local/cuda-9.0/include/nppi_data_exchange_and_initialization.h" "$(@D)/cuda/include/nppi_data_exchange_and_initialization.h" && cp "/usr/local/cuda-9.0/include/nppi_filtering_functions.h" "$(@D)/cuda/include/nppi_filtering_functions.h" && cp "/usr/local/cuda-9.0/include/nppi_geometry_transforms.h" "$(@D)/cuda/include/nppi_geometry_transforms.h" && cp "/usr/local/cuda-9.0/include/nppi_linear_transforms.h" "$(@D)/cuda/include/nppi_linear_transforms.h" && cp "/usr/local/cuda-9.0/include/nppi_morphological_operations.h" "$(@D)/cuda/include/nppi_morphological_operations.h" && cp "/usr/local/cuda-9.0/include/nppi_statistics_functions.h" "$(@D)/cuda/include/nppi_statistics_functions.h" && cp "/usr/local/cuda-9.0/include/nppi_support_functions.h" "$(@D)/cuda/include/nppi_support_functions.h" && cp "/usr/local/cuda-9.0/include/nppi_threshold_and_compare_operations.h" "$(@D)/cuda/include/nppi_threshold_and_compare_operations.h" && cp "/usr/local/cuda-9.0/include/npps.h" "$(@D)/cuda/include/npps.h" && cp "/usr/local/cuda-9.0/include/npps_arithmetic_and_logical_operations.h" "$(@D)/cuda/include/npps_arithmetic_and_logical_operations.h" && cp "/usr/local/cuda-9.0/include/npps_conversion_functions.h" "$(@D)/cuda/include/npps_conversion_functions.h" && cp "/usr/local/cuda-9.0/include/npps_filtering_functions.h" "$(@D)/cuda/include/npps_filtering_functions.h" && cp "/usr/local/cuda-9.0/include/npps_initialization.h" "$(@D)/cuda/include/npps_initialization.h" && cp "/usr/local/cuda-9.0/include/npps_statistics_functions.h" "$(@D)/cuda/include/npps_statistics_functions.h" && cp "/usr/local/cuda-9.0/include/npps_support_functions.h" "$(@D)/cuda/include/npps_support_functions.h" && cp "/usr/local/cuda-9.0/include/nppversion.h" "$(@D)/cuda/include/nppversion.h" && cp "/usr/local/cuda-9.0/include/nvToolsExt.h" "$(@D)/cuda/include/nvToolsExt.h" && cp "/usr/local/cuda-9.0/include/nvToolsExtCuda.h" "$(@D)/cuda/include/nvToolsExtCuda.h" && cp "/usr/local/cuda-9.0/include/nvToolsExtCudaRt.h" "$(@D)/cuda/include/nvToolsExtCudaRt.h" && cp "/usr/local/cuda-9.0/include/nvToolsExtMeta.h" "$(@D)/cuda/include/nvToolsExtMeta.h" && cp "/usr/local/cuda-9.0/include/nvToolsExtSync.h" "$(@D)/cuda/include/nvToolsExtSync.h" && cp "/usr/local/cuda-9.0/include/nvblas.h" "$(@D)/cuda/include/nvblas.h" && cp "/usr/local/cuda-9.0/include/nvfunctional" "$(@D)/cuda/include/nvfunctional" && cp "/usr/local/cuda-9.0/include/nvgraph.h" "$(@D)/cuda/include/nvgraph.h" && cp "/usr/local/cuda-9.0/include/nvml.h" "$(@D)/cuda/include/nvml.h" && cp "/usr/local/cuda-9.0/include/nvrtc.h" "$(@D)/cuda/include/nvrtc.h" && cp "/usr/local/cuda-9.0/include/sm_20_atomic_functions.h" "$(@D)/cuda/include/sm_20_atomic_functions.h" && cp "/usr/local/cuda-9.0/include/sm_20_atomic_functions.hpp" "$(@D)/cuda/include/sm_20_atomic_functions.hpp" && cp "/usr/local/cuda-9.0/include/sm_20_intrinsics.h" "$(@D)/cuda/include/sm_20_intrinsics.h" && cp "/usr/local/cuda-9.0/include/sm_20_intrinsics.hpp" "$(@D)/cuda/include/sm_20_intrinsics.hpp" && cp "/usr/local/cuda-9.0/include/sm_30_intrinsics.h" "$(@D)/cuda/include/sm_30_intrinsics.h" && cp "/usr/local/cuda-9.0/include/sm_30_intrinsics.hpp" "$(@D)/cuda/include/sm_30_intrinsics.hpp" && cp "/usr/local/cuda-9.0/include/sm_32_atomic_functions.h" "$(@D)/cuda/include/sm_32_atomic_functions.h" && cp "/usr/local/cuda-9.0/include/sm_32_atomic_functions.hpp" "$(@D)/cuda/include/sm_32_atomic_functions.hpp" && cp "/usr/local/cuda-9.0/include/sm_32_intrinsics.h" "$(@D)/cuda/include/sm_32_intrinsics.h" && cp "/usr/local/cuda-9.0/include/sm_32_intrinsics.hpp" "$(@D)/cuda/include/sm_32_intrinsics.hpp" && cp "/usr/local/cuda-9.0/include/sm_35_atomic_functions.h" "$(@D)/cuda/include/sm_35_atomic_functions.h" && cp "/usr/local/cuda-9.0/include/sm_35_intrinsics.h" "$(@D)/cuda/include/sm_35_intrinsics.h" && cp "/usr/local/cuda-9.0/include/sm_60_atomic_functions.h" "$(@D)/cuda/include/sm_60_atomic_functions.h" && cp "/usr/local/cuda-9.0/include/sm_60_atomic_functions.hpp" "$(@D)/cuda/include/sm_60_atomic_functions.hpp" && cp "/usr/local/cuda-9.0/include/sm_61_intrinsics.h" "$(@D)/cuda/include/sm_61_intrinsics.h" && cp "/usr/local/cuda-9.0/include/sm_61_intrinsics.hpp" "$(@D)/cuda/include/sm_61_intrinsics.hpp" && cp "/usr/local/cuda-9.0/include/sobol_direction_vectors.h" "$(@D)/cuda/include/sobol_direction_vectors.h" && cp "/usr/local/cuda-9.0/include/surface_functions.h" "$(@D)/cuda/include/surface_functions.h" && cp "/usr/local/cuda-9.0/include/surface_functions.hpp" "$(@D)/cuda/include/surface_functions.hpp" && cp "/usr/local/cuda-9.0/include/surface_indirect_functions.h" "$(@D)/cuda/include/surface_indirect_functions.h" && cp "/usr/local/cuda-9.0/include/surface_indirect_functions.hpp" "$(@D)/cuda/include/surface_indirect_functions.hpp" && cp "/usr/local/cuda-9.0/include/surface_types.h" "$(@D)/cuda/include/surface_types.h" && cp "/usr/local/cuda-9.0/include/texture_fetch_functions.h" "$(@D)/cuda/include/texture_fetch_functions.h" && cp "/usr/local/cuda-9.0/include/texture_fetch_functions.hpp" "$(@D)/cuda/include/texture_fetch_functions.hpp" && cp "/usr/local/cuda-9.0/include/texture_indirect_functions.h" "$(@D)/cuda/include/texture_indirect_functions.h" && cp "/usr/local/cuda-9.0/include/texture_indirect_functions.hpp" "$(@D)/cuda/include/texture_indirect_functions.hpp" && cp "/usr/local/cuda-9.0/include/texture_types.h" "$(@D)/cuda/include/texture_types.h" && cp "/usr/local/cuda-9.0/include/thrust/adjacent_difference.h" "$(@D)/cuda/include/thrust/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/advance.h" "$(@D)/cuda/include/thrust/advance.h" && cp "/usr/local/cuda-9.0/include/thrust/binary_search.h" "$(@D)/cuda/include/thrust/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/complex.h" "$(@D)/cuda/include/thrust/complex.h" && cp "/usr/local/cuda-9.0/include/thrust/copy.h" "$(@D)/cuda/include/thrust/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/count.h" "$(@D)/cuda/include/thrust/count.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/adjacent_difference.inl" "$(@D)/cuda/include/thrust/detail/adjacent_difference.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/advance.inl" "$(@D)/cuda/include/thrust/detail/advance.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/allocator_traits.h" "$(@D)/cuda/include/thrust/detail/allocator/allocator_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/allocator_traits.inl" "$(@D)/cuda/include/thrust/detail/allocator/allocator_traits.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/copy_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/copy_construct_range.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/copy_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/copy_construct_range.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/default_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/default_construct_range.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/default_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/default_construct_range.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/destroy_range.h" "$(@D)/cuda/include/thrust/detail/allocator/destroy_range.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/destroy_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/destroy_range.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/fill_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/fill_construct_range.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/fill_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/fill_construct_range.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/malloc_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/malloc_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/malloc_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/malloc_allocator.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/no_throw_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/no_throw_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/tagged_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/tagged_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/tagged_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/tagged_allocator.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/temporary_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/temporary_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/allocator/temporary_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/temporary_allocator.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/binary_search.inl" "$(@D)/cuda/include/thrust/detail/binary_search.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/arithmetic.h" "$(@D)/cuda/include/thrust/detail/complex/arithmetic.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/c99math.h" "$(@D)/cuda/include/thrust/detail/complex/c99math.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/catrig.h" "$(@D)/cuda/include/thrust/detail/complex/catrig.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/catrigf.h" "$(@D)/cuda/include/thrust/detail/complex/catrigf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/ccosh.h" "$(@D)/cuda/include/thrust/detail/complex/ccosh.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/ccoshf.h" "$(@D)/cuda/include/thrust/detail/complex/ccoshf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/cexp.h" "$(@D)/cuda/include/thrust/detail/complex/cexp.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/cexpf.h" "$(@D)/cuda/include/thrust/detail/complex/cexpf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/clog.h" "$(@D)/cuda/include/thrust/detail/complex/clog.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/clogf.h" "$(@D)/cuda/include/thrust/detail/complex/clogf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/complex.inl" "$(@D)/cuda/include/thrust/detail/complex/complex.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/cpow.h" "$(@D)/cuda/include/thrust/detail/complex/cpow.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/cpowf.h" "$(@D)/cuda/include/thrust/detail/complex/cpowf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/cproj.h" "$(@D)/cuda/include/thrust/detail/complex/cproj.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/csinh.h" "$(@D)/cuda/include/thrust/detail/complex/csinh.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/csinhf.h" "$(@D)/cuda/include/thrust/detail/complex/csinhf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/csqrt.h" "$(@D)/cuda/include/thrust/detail/complex/csqrt.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/csqrtf.h" "$(@D)/cuda/include/thrust/detail/complex/csqrtf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/ctanh.h" "$(@D)/cuda/include/thrust/detail/complex/ctanh.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/ctanhf.h" "$(@D)/cuda/include/thrust/detail/complex/ctanhf.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/math_private.h" "$(@D)/cuda/include/thrust/detail/complex/math_private.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/complex/stream.h" "$(@D)/cuda/include/thrust/detail/complex/stream.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config.h" "$(@D)/cuda/include/thrust/detail/config.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/compiler.h" "$(@D)/cuda/include/thrust/detail/config/compiler.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/compiler_fence.h" "$(@D)/cuda/include/thrust/detail/config/compiler_fence.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/config.h" "$(@D)/cuda/include/thrust/detail/config/config.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/debug.h" "$(@D)/cuda/include/thrust/detail/config/debug.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/device_system.h" "$(@D)/cuda/include/thrust/detail/config/device_system.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/exec_check_disable.h" "$(@D)/cuda/include/thrust/detail/config/exec_check_disable.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/forceinline.h" "$(@D)/cuda/include/thrust/detail/config/forceinline.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/global_workarounds.h" "$(@D)/cuda/include/thrust/detail/config/global_workarounds.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/host_device.h" "$(@D)/cuda/include/thrust/detail/config/host_device.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/host_system.h" "$(@D)/cuda/include/thrust/detail/config/host_system.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/config/simple_defines.h" "$(@D)/cuda/include/thrust/detail/config/simple_defines.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/contiguous_storage.h" "$(@D)/cuda/include/thrust/detail/contiguous_storage.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/contiguous_storage.inl" "$(@D)/cuda/include/thrust/detail/contiguous_storage.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/copy.h" "$(@D)/cuda/include/thrust/detail/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/copy.inl" "$(@D)/cuda/include/thrust/detail/copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/copy_if.h" "$(@D)/cuda/include/thrust/detail/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/copy_if.inl" "$(@D)/cuda/include/thrust/detail/copy_if.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/count.inl" "$(@D)/cuda/include/thrust/detail/count.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/cstdint.h" "$(@D)/cuda/include/thrust/detail/cstdint.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_delete.inl" "$(@D)/cuda/include/thrust/detail/device_delete.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_free.inl" "$(@D)/cuda/include/thrust/detail/device_free.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_malloc.inl" "$(@D)/cuda/include/thrust/detail/device_malloc.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_new.inl" "$(@D)/cuda/include/thrust/detail/device_new.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_ptr.inl" "$(@D)/cuda/include/thrust/detail/device_ptr.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_reference.inl" "$(@D)/cuda/include/thrust/detail/device_reference.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/device_vector.inl" "$(@D)/cuda/include/thrust/detail/device_vector.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/dispatch/is_trivial_copy.h" "$(@D)/cuda/include/thrust/detail/dispatch/is_trivial_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/distance.inl" "$(@D)/cuda/include/thrust/detail/distance.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/equal.inl" "$(@D)/cuda/include/thrust/detail/equal.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/execute_with_allocator.h" "$(@D)/cuda/include/thrust/detail/execute_with_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/execution_policy.h" "$(@D)/cuda/include/thrust/detail/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/extrema.inl" "$(@D)/cuda/include/thrust/detail/extrema.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/fill.inl" "$(@D)/cuda/include/thrust/detail/fill.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/find.inl" "$(@D)/cuda/include/thrust/detail/find.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/for_each.inl" "$(@D)/cuda/include/thrust/detail/for_each.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/function.h" "$(@D)/cuda/include/thrust/detail/function.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional.inl" "$(@D)/cuda/include/thrust/detail/functional.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/actor.h" "$(@D)/cuda/include/thrust/detail/functional/actor.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/actor.inl" "$(@D)/cuda/include/thrust/detail/functional/actor.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/argument.h" "$(@D)/cuda/include/thrust/detail/functional/argument.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/composite.h" "$(@D)/cuda/include/thrust/detail/functional/composite.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/arithmetic_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/arithmetic_operators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/assignment_operator.h" "$(@D)/cuda/include/thrust/detail/functional/operators/assignment_operator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/bitwise_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/bitwise_operators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/compound_assignment_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/compound_assignment_operators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/logical_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/logical_operators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/operator_adaptors.h" "$(@D)/cuda/include/thrust/detail/functional/operators/operator_adaptors.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/relational_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/relational_operators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/placeholder.h" "$(@D)/cuda/include/thrust/detail/functional/placeholder.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/functional/value.h" "$(@D)/cuda/include/thrust/detail/functional/value.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/gather.inl" "$(@D)/cuda/include/thrust/detail/gather.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/generate.inl" "$(@D)/cuda/include/thrust/detail/generate.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/get_iterator_value.h" "$(@D)/cuda/include/thrust/detail/get_iterator_value.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/host_vector.inl" "$(@D)/cuda/include/thrust/detail/host_vector.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/inner_product.inl" "$(@D)/cuda/include/thrust/detail/inner_product.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/integer_math.h" "$(@D)/cuda/include/thrust/detail/integer_math.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/integer_traits.h" "$(@D)/cuda/include/thrust/detail/integer_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/internal_functional.h" "$(@D)/cuda/include/thrust/detail/internal_functional.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/logical.inl" "$(@D)/cuda/include/thrust/detail/logical.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/detail/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/merge.inl" "$(@D)/cuda/include/thrust/detail/merge.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/minmax.h" "$(@D)/cuda/include/thrust/detail/minmax.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/mismatch.inl" "$(@D)/cuda/include/thrust/detail/mismatch.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/mpl/math.h" "$(@D)/cuda/include/thrust/detail/mpl/math.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/numeric_traits.h" "$(@D)/cuda/include/thrust/detail/numeric_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/overlapped_copy.h" "$(@D)/cuda/include/thrust/detail/overlapped_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/pair.inl" "$(@D)/cuda/include/thrust/detail/pair.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/partition.inl" "$(@D)/cuda/include/thrust/detail/partition.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/pointer.h" "$(@D)/cuda/include/thrust/detail/pointer.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/pointer.inl" "$(@D)/cuda/include/thrust/detail/pointer.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/range/head_flags.h" "$(@D)/cuda/include/thrust/detail/range/head_flags.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/range/tail_flags.h" "$(@D)/cuda/include/thrust/detail/range/tail_flags.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/raw_pointer_cast.h" "$(@D)/cuda/include/thrust/detail/raw_pointer_cast.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/raw_reference_cast.h" "$(@D)/cuda/include/thrust/detail/raw_reference_cast.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/reduce.inl" "$(@D)/cuda/include/thrust/detail/reduce.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/reference.h" "$(@D)/cuda/include/thrust/detail/reference.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/reference.inl" "$(@D)/cuda/include/thrust/detail/reference.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/reference_forward_declaration.h" "$(@D)/cuda/include/thrust/detail/reference_forward_declaration.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/remove.inl" "$(@D)/cuda/include/thrust/detail/remove.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/replace.inl" "$(@D)/cuda/include/thrust/detail/replace.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/reverse.inl" "$(@D)/cuda/include/thrust/detail/reverse.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/scan.inl" "$(@D)/cuda/include/thrust/detail/scan.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/scatter.inl" "$(@D)/cuda/include/thrust/detail/scatter.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/seq.h" "$(@D)/cuda/include/thrust/detail/seq.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/sequence.inl" "$(@D)/cuda/include/thrust/detail/sequence.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/set_operations.inl" "$(@D)/cuda/include/thrust/detail/set_operations.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/sort.inl" "$(@D)/cuda/include/thrust/detail/sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/static_assert.h" "$(@D)/cuda/include/thrust/detail/static_assert.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/static_map.h" "$(@D)/cuda/include/thrust/detail/static_map.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/swap.h" "$(@D)/cuda/include/thrust/detail/swap.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/swap.inl" "$(@D)/cuda/include/thrust/detail/swap.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/swap_ranges.inl" "$(@D)/cuda/include/thrust/detail/swap_ranges.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/tabulate.inl" "$(@D)/cuda/include/thrust/detail/tabulate.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/temporary_array.h" "$(@D)/cuda/include/thrust/detail/temporary_array.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/temporary_array.inl" "$(@D)/cuda/include/thrust/detail/temporary_array.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/detail/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/transform.inl" "$(@D)/cuda/include/thrust/detail/transform.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/transform_reduce.inl" "$(@D)/cuda/include/thrust/detail/transform_reduce.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/transform_scan.inl" "$(@D)/cuda/include/thrust/detail/transform_scan.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/trivial_sequence.h" "$(@D)/cuda/include/thrust/detail/trivial_sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/tuple.inl" "$(@D)/cuda/include/thrust/detail/tuple.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/tuple_meta_transform.h" "$(@D)/cuda/include/thrust/detail/tuple_meta_transform.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/tuple_transform.h" "$(@D)/cuda/include/thrust/detail/tuple_transform.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h" "$(@D)/cuda/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/function_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits/function_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/has_member_function.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_member_function.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/has_nested_type.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_nested_type.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/has_trivial_assign.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_trivial_assign.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/is_call_possible.h" "$(@D)/cuda/include/thrust/detail/type_traits/is_call_possible.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/is_metafunction_defined.h" "$(@D)/cuda/include/thrust/detail/type_traits/is_metafunction_defined.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/iterator/is_discard_iterator.h" "$(@D)/cuda/include/thrust/detail/type_traits/iterator/is_discard_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/iterator/is_output_iterator.h" "$(@D)/cuda/include/thrust/detail/type_traits/iterator/is_output_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/minimum_type.h" "$(@D)/cuda/include/thrust/detail/type_traits/minimum_type.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/pointer_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits/pointer_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/type_traits/result_of_adaptable_function.h" "$(@D)/cuda/include/thrust/detail/type_traits/result_of_adaptable_function.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/uninitialized_copy.inl" "$(@D)/cuda/include/thrust/detail/uninitialized_copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/uninitialized_fill.inl" "$(@D)/cuda/include/thrust/detail/uninitialized_fill.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/unique.inl" "$(@D)/cuda/include/thrust/detail/unique.inl" && cp "/usr/local/cuda-9.0/include/thrust/detail/use_default.h" "$(@D)/cuda/include/thrust/detail/use_default.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/util/align.h" "$(@D)/cuda/include/thrust/detail/util/align.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/util/blocking.h" "$(@D)/cuda/include/thrust/detail/util/blocking.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/vector_base.h" "$(@D)/cuda/include/thrust/detail/vector_base.h" && cp "/usr/local/cuda-9.0/include/thrust/detail/vector_base.inl" "$(@D)/cuda/include/thrust/detail/vector_base.inl" && cp "/usr/local/cuda-9.0/include/thrust/device_allocator.h" "$(@D)/cuda/include/thrust/device_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/device_delete.h" "$(@D)/cuda/include/thrust/device_delete.h" && cp "/usr/local/cuda-9.0/include/thrust/device_free.h" "$(@D)/cuda/include/thrust/device_free.h" && cp "/usr/local/cuda-9.0/include/thrust/device_malloc.h" "$(@D)/cuda/include/thrust/device_malloc.h" && cp "/usr/local/cuda-9.0/include/thrust/device_malloc_allocator.h" "$(@D)/cuda/include/thrust/device_malloc_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/device_new.h" "$(@D)/cuda/include/thrust/device_new.h" && cp "/usr/local/cuda-9.0/include/thrust/device_new_allocator.h" "$(@D)/cuda/include/thrust/device_new_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/device_ptr.h" "$(@D)/cuda/include/thrust/device_ptr.h" && cp "/usr/local/cuda-9.0/include/thrust/device_reference.h" "$(@D)/cuda/include/thrust/device_reference.h" && cp "/usr/local/cuda-9.0/include/thrust/device_vector.h" "$(@D)/cuda/include/thrust/device_vector.h" && cp "/usr/local/cuda-9.0/include/thrust/distance.h" "$(@D)/cuda/include/thrust/distance.h" && cp "/usr/local/cuda-9.0/include/thrust/equal.h" "$(@D)/cuda/include/thrust/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/execution_policy.h" "$(@D)/cuda/include/thrust/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/extrema.h" "$(@D)/cuda/include/thrust/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/fill.h" "$(@D)/cuda/include/thrust/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/find.h" "$(@D)/cuda/include/thrust/find.h" && cp "/usr/local/cuda-9.0/include/thrust/for_each.h" "$(@D)/cuda/include/thrust/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/functional.h" "$(@D)/cuda/include/thrust/functional.h" && cp "/usr/local/cuda-9.0/include/thrust/gather.h" "$(@D)/cuda/include/thrust/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/generate.h" "$(@D)/cuda/include/thrust/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/host_vector.h" "$(@D)/cuda/include/thrust/host_vector.h" && cp "/usr/local/cuda-9.0/include/thrust/inner_product.h" "$(@D)/cuda/include/thrust/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/constant_iterator.h" "$(@D)/cuda/include/thrust/iterator/constant_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/counting_iterator.h" "$(@D)/cuda/include/thrust/iterator/counting_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/any_assign.h" "$(@D)/cuda/include/thrust/iterator/detail/any_assign.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/any_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/any_system_tag.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/constant_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/constant_iterator_base.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/counting_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/counting_iterator.inl" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/device_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/device_system_tag.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/discard_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/discard_iterator_base.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/distance_from_result.h" "$(@D)/cuda/include/thrust/iterator/detail/distance_from_result.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/host_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/host_system_tag.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/is_iterator_category.h" "$(@D)/cuda/include/thrust/iterator/detail/is_iterator_category.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/is_trivial_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/is_trivial_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_adaptor_base.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_adaptor_base.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_category_to_system.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_to_system.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_category_to_traversal.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_to_traversal.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_facade_category.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_facade_category.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_traits.inl" "$(@D)/cuda/include/thrust/iterator/detail/iterator_traits.inl" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_traversal_tags.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_traversal_tags.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/join_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/join_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/minimum_category.h" "$(@D)/cuda/include/thrust/iterator/detail/minimum_category.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/minimum_system.h" "$(@D)/cuda/include/thrust/iterator/detail/minimum_system.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/normal_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/normal_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/permutation_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/permutation_iterator_base.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/retag.h" "$(@D)/cuda/include/thrust/iterator/detail/retag.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/reverse_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/reverse_iterator.inl" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/reverse_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/reverse_iterator_base.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/tagged_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/tagged_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/transform_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/transform_iterator.inl" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/transform_output_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/transform_output_iterator.inl" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/tuple_of_iterator_references.h" "$(@D)/cuda/include/thrust/iterator/detail/tuple_of_iterator_references.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/universal_categories.h" "$(@D)/cuda/include/thrust/iterator/detail/universal_categories.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/zip_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/zip_iterator.inl" && cp "/usr/local/cuda-9.0/include/thrust/iterator/detail/zip_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/zip_iterator_base.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/discard_iterator.h" "$(@D)/cuda/include/thrust/iterator/discard_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/iterator_adaptor.h" "$(@D)/cuda/include/thrust/iterator/iterator_adaptor.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/iterator_categories.h" "$(@D)/cuda/include/thrust/iterator/iterator_categories.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/iterator_facade.h" "$(@D)/cuda/include/thrust/iterator/iterator_facade.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/iterator_traits.h" "$(@D)/cuda/include/thrust/iterator/iterator_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/permutation_iterator.h" "$(@D)/cuda/include/thrust/iterator/permutation_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/retag.h" "$(@D)/cuda/include/thrust/iterator/retag.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/reverse_iterator.h" "$(@D)/cuda/include/thrust/iterator/reverse_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/transform_iterator.h" "$(@D)/cuda/include/thrust/iterator/transform_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/transform_output_iterator.h" "$(@D)/cuda/include/thrust/iterator/transform_output_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/iterator/zip_iterator.h" "$(@D)/cuda/include/thrust/iterator/zip_iterator.h" && cp "/usr/local/cuda-9.0/include/thrust/logical.h" "$(@D)/cuda/include/thrust/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/memory.h" "$(@D)/cuda/include/thrust/memory.h" && cp "/usr/local/cuda-9.0/include/thrust/merge.h" "$(@D)/cuda/include/thrust/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/mismatch.h" "$(@D)/cuda/include/thrust/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/pair.h" "$(@D)/cuda/include/thrust/pair.h" && cp "/usr/local/cuda-9.0/include/thrust/partition.h" "$(@D)/cuda/include/thrust/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/random.h" "$(@D)/cuda/include/thrust/random.h" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/discard_block_engine.inl" "$(@D)/cuda/include/thrust/random/detail/discard_block_engine.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/linear_congruential_engine.inl" "$(@D)/cuda/include/thrust/random/detail/linear_congruential_engine.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/linear_congruential_engine_discard.h" "$(@D)/cuda/include/thrust/random/detail/linear_congruential_engine_discard.h" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/linear_feedback_shift_engine.inl" "$(@D)/cuda/include/thrust/random/detail/linear_feedback_shift_engine.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h" "$(@D)/cuda/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/mod.h" "$(@D)/cuda/include/thrust/random/detail/mod.h" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/normal_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/normal_distribution.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/normal_distribution_base.h" "$(@D)/cuda/include/thrust/random/detail/normal_distribution_base.h" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/random_core_access.h" "$(@D)/cuda/include/thrust/random/detail/random_core_access.h" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/subtract_with_carry_engine.inl" "$(@D)/cuda/include/thrust/random/detail/subtract_with_carry_engine.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/uniform_int_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/uniform_int_distribution.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/uniform_real_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/uniform_real_distribution.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/xor_combine_engine.inl" "$(@D)/cuda/include/thrust/random/detail/xor_combine_engine.inl" && cp "/usr/local/cuda-9.0/include/thrust/random/detail/xor_combine_engine_max.h" "$(@D)/cuda/include/thrust/random/detail/xor_combine_engine_max.h" && cp "/usr/local/cuda-9.0/include/thrust/random/discard_block_engine.h" "$(@D)/cuda/include/thrust/random/discard_block_engine.h" && cp "/usr/local/cuda-9.0/include/thrust/random/linear_congruential_engine.h" "$(@D)/cuda/include/thrust/random/linear_congruential_engine.h" && cp "/usr/local/cuda-9.0/include/thrust/random/linear_feedback_shift_engine.h" "$(@D)/cuda/include/thrust/random/linear_feedback_shift_engine.h" && cp "/usr/local/cuda-9.0/include/thrust/random/normal_distribution.h" "$(@D)/cuda/include/thrust/random/normal_distribution.h" && cp "/usr/local/cuda-9.0/include/thrust/random/subtract_with_carry_engine.h" "$(@D)/cuda/include/thrust/random/subtract_with_carry_engine.h" && cp "/usr/local/cuda-9.0/include/thrust/random/uniform_int_distribution.h" "$(@D)/cuda/include/thrust/random/uniform_int_distribution.h" && cp "/usr/local/cuda-9.0/include/thrust/random/uniform_real_distribution.h" "$(@D)/cuda/include/thrust/random/uniform_real_distribution.h" && cp "/usr/local/cuda-9.0/include/thrust/random/xor_combine_engine.h" "$(@D)/cuda/include/thrust/random/xor_combine_engine.h" && cp "/usr/local/cuda-9.0/include/thrust/reduce.h" "$(@D)/cuda/include/thrust/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/remove.h" "$(@D)/cuda/include/thrust/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/replace.h" "$(@D)/cuda/include/thrust/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/reverse.h" "$(@D)/cuda/include/thrust/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/scan.h" "$(@D)/cuda/include/thrust/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/scatter.h" "$(@D)/cuda/include/thrust/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/sequence.h" "$(@D)/cuda/include/thrust/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/set_operations.h" "$(@D)/cuda/include/thrust/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/sort.h" "$(@D)/cuda/include/thrust/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/swap.h" "$(@D)/cuda/include/thrust/swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/cpp/detail/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/cpp/detail/assign_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/cpp/detail/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/copy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/cpp/detail/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/count.h" "$(@D)/cuda/include/thrust/system/cpp/detail/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/equal.h" "$(@D)/cuda/include/thrust/system/cpp/detail/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/extrema.h" "$(@D)/cuda/include/thrust/system/cpp/detail/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/fill.h" "$(@D)/cuda/include/thrust/system/cpp/detail/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/find.h" "$(@D)/cuda/include/thrust/system/cpp/detail/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/for_each.h" "$(@D)/cuda/include/thrust/system/cpp/detail/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/gather.h" "$(@D)/cuda/include/thrust/system/cpp/detail/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/generate.h" "$(@D)/cuda/include/thrust/system/cpp/detail/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/get_value.h" "$(@D)/cuda/include/thrust/system/cpp/detail/get_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/cpp/detail/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/cpp/detail/iter_swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/logical.h" "$(@D)/cuda/include/thrust/system/cpp/detail/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/cpp/detail/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/memory.inl" "$(@D)/cuda/include/thrust/system/cpp/detail/memory.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/merge.h" "$(@D)/cuda/include/thrust/system/cpp/detail/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/cpp/detail/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/par.h" "$(@D)/cuda/include/thrust/system/cpp/detail/par.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/partition.h" "$(@D)/cuda/include/thrust/system/cpp/detail/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/reduce.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/remove.h" "$(@D)/cuda/include/thrust/system/cpp/detail/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/replace.h" "$(@D)/cuda/include/thrust/system/cpp/detail/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/reverse.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/scan.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/scatter.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/sequence.h" "$(@D)/cuda/include/thrust/system/cpp/detail/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/cpp/detail/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/sort.h" "$(@D)/cuda/include/thrust/system/cpp/detail/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/cpp/detail/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/cpp/detail/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/cpp/detail/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/transform.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/cpp/detail/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/unique.h" "$(@D)/cuda/include/thrust/system/cpp/detail/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/vector.inl" "$(@D)/cuda/include/thrust/system/cpp/detail/vector.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/execution_policy.h" "$(@D)/cuda/include/thrust/system/cpp/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/memory.h" "$(@D)/cuda/include/thrust/system/cpp/memory.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cpp/vector.h" "$(@D)/cuda/include/thrust/system/cpp/vector.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/config.h" "$(@D)/cuda/include/thrust/system/cuda/config.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/cuda/detail/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/cuda/detail/assign_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/cuda/detail/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/copy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/cuda/detail/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/agent_launcher.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/agent_launcher.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/alignment.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/alignment.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/triple_chevron_launch.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/triple_chevron_launch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/util.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/util.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/count.h" "$(@D)/cuda/include/thrust/system/cuda/detail/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cross_system.h" "$(@D)/cuda/include/thrust/system/cuda/detail/cross_system.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_csrt.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_csrt.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_row_based.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_row_based.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_load.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_load.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_scan.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_store.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_store.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/cub.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/cub.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_partition.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_partition.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_scan.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_select.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_select.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_csrt.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_csrt.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_row_based.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_row_based.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/host/mutex.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/host/mutex.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_allocator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_allocator.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_arch.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_arch.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_debug.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_debug.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_device.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_device.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_macro.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_macro.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_namespace.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_namespace.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_ptx.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_ptx.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_type.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_type.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/equal.h" "$(@D)/cuda/include/thrust/system/cuda/detail/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/error.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/error.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/extrema.h" "$(@D)/cuda/include/thrust/system/cuda/detail/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/fill.h" "$(@D)/cuda/include/thrust/system/cuda/detail/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/find.h" "$(@D)/cuda/include/thrust/system/cuda/detail/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/for_each.h" "$(@D)/cuda/include/thrust/system/cuda/detail/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/gather.h" "$(@D)/cuda/include/thrust/system/cuda/detail/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/generate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/get_value.h" "$(@D)/cuda/include/thrust/system/cuda/detail/get_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h" "$(@D)/cuda/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/guarded_driver_types.h" "$(@D)/cuda/include/thrust/system/cuda/detail/guarded_driver_types.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/cuda/detail/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/internal/copy_cross_system.h" "$(@D)/cuda/include/thrust/system/cuda/detail/internal/copy_cross_system.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/internal/copy_device_to_device.h" "$(@D)/cuda/include/thrust/system/cuda/detail/internal/copy_device_to_device.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/cuda/detail/iter_swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/logical.h" "$(@D)/cuda/include/thrust/system/cuda/detail/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/cuda/detail/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/memory.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/memory.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/memory_buffer.h" "$(@D)/cuda/include/thrust/system/cuda/detail/memory_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/merge.h" "$(@D)/cuda/include/thrust/system/cuda/detail/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/cuda/detail/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/par.h" "$(@D)/cuda/include/thrust/system/cuda/detail/par.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/par_to_seq.h" "$(@D)/cuda/include/thrust/system/cuda/detail/par_to_seq.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/parallel_for.h" "$(@D)/cuda/include/thrust/system/cuda/detail/parallel_for.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/partition.h" "$(@D)/cuda/include/thrust/system/cuda/detail/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/reduce.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/remove.h" "$(@D)/cuda/include/thrust/system/cuda/detail/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/replace.h" "$(@D)/cuda/include/thrust/system/cuda/detail/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/reverse.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/scan.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/scatter.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/sequence.h" "$(@D)/cuda/include/thrust/system/cuda/detail/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/cuda/detail/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/sort.h" "$(@D)/cuda/include/thrust/system/cuda/detail/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/cuda/detail/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/cuda/detail/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/terminate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/terminate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/transform.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/cuda/detail/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/unique.h" "$(@D)/cuda/include/thrust/system/cuda/detail/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/util.h" "$(@D)/cuda/include/thrust/system/cuda/detail/util.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/vector.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/vector.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/error.h" "$(@D)/cuda/include/thrust/system/cuda/error.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/execution_policy.h" "$(@D)/cuda/include/thrust/system/cuda/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/experimental/pinned_allocator.h" "$(@D)/cuda/include/thrust/system/cuda/experimental/pinned_allocator.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/memory.h" "$(@D)/cuda/include/thrust/system/cuda/memory.h" && cp "/usr/local/cuda-9.0/include/thrust/system/cuda/vector.h" "$(@D)/cuda/include/thrust/system/cuda/vector.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/adl/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/assign_value.h" "$(@D)/cuda/include/thrust/system/detail/adl/assign_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/adl/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/copy.h" "$(@D)/cuda/include/thrust/system/detail/adl/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/adl/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/count.h" "$(@D)/cuda/include/thrust/system/detail/adl/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/equal.h" "$(@D)/cuda/include/thrust/system/detail/adl/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/extrema.h" "$(@D)/cuda/include/thrust/system/detail/adl/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/fill.h" "$(@D)/cuda/include/thrust/system/detail/adl/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/find.h" "$(@D)/cuda/include/thrust/system/detail/adl/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/for_each.h" "$(@D)/cuda/include/thrust/system/detail/adl/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/gather.h" "$(@D)/cuda/include/thrust/system/detail/adl/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/generate.h" "$(@D)/cuda/include/thrust/system/detail/adl/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/get_value.h" "$(@D)/cuda/include/thrust/system/detail/adl/get_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/adl/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/iter_swap.h" "$(@D)/cuda/include/thrust/system/detail/adl/iter_swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/logical.h" "$(@D)/cuda/include/thrust/system/detail/adl/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/detail/adl/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/merge.h" "$(@D)/cuda/include/thrust/system/detail/adl/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/adl/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/partition.h" "$(@D)/cuda/include/thrust/system/detail/adl/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/reduce.h" "$(@D)/cuda/include/thrust/system/detail/adl/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/remove.h" "$(@D)/cuda/include/thrust/system/detail/adl/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/replace.h" "$(@D)/cuda/include/thrust/system/detail/adl/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/reverse.h" "$(@D)/cuda/include/thrust/system/detail/adl/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/scan.h" "$(@D)/cuda/include/thrust/system/detail/adl/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/scatter.h" "$(@D)/cuda/include/thrust/system/detail/adl/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/sequence.h" "$(@D)/cuda/include/thrust/system/detail/adl/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/adl/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/sort.h" "$(@D)/cuda/include/thrust/system/detail/adl/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/adl/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/adl/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/adl/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/transform.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/adl/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/adl/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/unique.h" "$(@D)/cuda/include/thrust/system/detail/adl/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/adl/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/bad_alloc.h" "$(@D)/cuda/include/thrust/system/detail/bad_alloc.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/errno.h" "$(@D)/cuda/include/thrust/system/detail/errno.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/error_category.inl" "$(@D)/cuda/include/thrust/system/detail/error_category.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/error_code.inl" "$(@D)/cuda/include/thrust/system/detail/error_code.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/error_condition.inl" "$(@D)/cuda/include/thrust/system/detail/error_condition.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/generic/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/adjacent_difference.inl" "$(@D)/cuda/include/thrust/system/detail/generic/adjacent_difference.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/advance.h" "$(@D)/cuda/include/thrust/system/detail/generic/advance.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/advance.inl" "$(@D)/cuda/include/thrust/system/detail/generic/advance.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/generic/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/binary_search.inl" "$(@D)/cuda/include/thrust/system/detail/generic/binary_search.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy.h" "$(@D)/cuda/include/thrust/system/detail/generic/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy.inl" "$(@D)/cuda/include/thrust/system/detail/generic/copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/generic/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy_if.inl" "$(@D)/cuda/include/thrust/system/detail/generic/copy_if.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/count.h" "$(@D)/cuda/include/thrust/system/detail/generic/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/count.inl" "$(@D)/cuda/include/thrust/system/detail/generic/count.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/distance.h" "$(@D)/cuda/include/thrust/system/detail/generic/distance.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/distance.inl" "$(@D)/cuda/include/thrust/system/detail/generic/distance.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/equal.h" "$(@D)/cuda/include/thrust/system/detail/generic/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/equal.inl" "$(@D)/cuda/include/thrust/system/detail/generic/equal.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/extrema.h" "$(@D)/cuda/include/thrust/system/detail/generic/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/extrema.inl" "$(@D)/cuda/include/thrust/system/detail/generic/extrema.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/fill.h" "$(@D)/cuda/include/thrust/system/detail/generic/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/find.h" "$(@D)/cuda/include/thrust/system/detail/generic/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/find.inl" "$(@D)/cuda/include/thrust/system/detail/generic/find.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/for_each.h" "$(@D)/cuda/include/thrust/system/detail/generic/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/gather.h" "$(@D)/cuda/include/thrust/system/detail/generic/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/gather.inl" "$(@D)/cuda/include/thrust/system/detail/generic/gather.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/generate.h" "$(@D)/cuda/include/thrust/system/detail/generic/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/generate.inl" "$(@D)/cuda/include/thrust/system/detail/generic/generate.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/generic/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/inner_product.inl" "$(@D)/cuda/include/thrust/system/detail/generic/inner_product.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/logical.h" "$(@D)/cuda/include/thrust/system/detail/generic/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/memory.h" "$(@D)/cuda/include/thrust/system/detail/generic/memory.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/memory.inl" "$(@D)/cuda/include/thrust/system/detail/generic/memory.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/merge.h" "$(@D)/cuda/include/thrust/system/detail/generic/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/merge.inl" "$(@D)/cuda/include/thrust/system/detail/generic/merge.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/generic/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/mismatch.inl" "$(@D)/cuda/include/thrust/system/detail/generic/mismatch.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/partition.h" "$(@D)/cuda/include/thrust/system/detail/generic/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/partition.inl" "$(@D)/cuda/include/thrust/system/detail/generic/partition.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce.h" "$(@D)/cuda/include/thrust/system/detail/generic/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reduce.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reduce_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/remove.h" "$(@D)/cuda/include/thrust/system/detail/generic/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/remove.inl" "$(@D)/cuda/include/thrust/system/detail/generic/remove.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/replace.h" "$(@D)/cuda/include/thrust/system/detail/generic/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/replace.inl" "$(@D)/cuda/include/thrust/system/detail/generic/replace.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reverse.h" "$(@D)/cuda/include/thrust/system/detail/generic/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reverse.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reverse.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scalar/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/generic/scalar/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scalar/binary_search.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scalar/binary_search.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan.h" "$(@D)/cuda/include/thrust/system/detail/generic/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scan.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scan_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scatter.h" "$(@D)/cuda/include/thrust/system/detail/generic/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scatter.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scatter.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/select_system.h" "$(@D)/cuda/include/thrust/system/detail/generic/select_system.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sequence.h" "$(@D)/cuda/include/thrust/system/detail/generic/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sequence.inl" "$(@D)/cuda/include/thrust/system/detail/generic/sequence.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/generic/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/set_operations.inl" "$(@D)/cuda/include/thrust/system/detail/generic/set_operations.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sort.h" "$(@D)/cuda/include/thrust/system/detail/generic/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sort.inl" "$(@D)/cuda/include/thrust/system/detail/generic/sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/generic/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/swap_ranges.inl" "$(@D)/cuda/include/thrust/system/detail/generic/swap_ranges.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/generic/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/tabulate.inl" "$(@D)/cuda/include/thrust/system/detail/generic/tabulate.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/tag.h" "$(@D)/cuda/include/thrust/system/detail/generic/tag.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/generic/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/temporary_buffer.inl" "$(@D)/cuda/include/thrust/system/detail/generic/temporary_buffer.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_reduce.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform_reduce.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_scan.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform_scan.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/type_traits.h" "$(@D)/cuda/include/thrust/system/detail/generic/type_traits.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_copy.inl" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_fill.inl" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_fill.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique.h" "$(@D)/cuda/include/thrust/system/detail/generic/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique.inl" "$(@D)/cuda/include/thrust/system/detail/generic/unique.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/unique_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/internal/decompose.h" "$(@D)/cuda/include/thrust/system/detail/internal/decompose.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/sequential/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/assign_value.h" "$(@D)/cuda/include/thrust/system/detail/sequential/assign_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/sequential/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy_backward.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy_backward.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/count.h" "$(@D)/cuda/include/thrust/system/detail/sequential/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/equal.h" "$(@D)/cuda/include/thrust/system/detail/sequential/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/execution_policy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/extrema.h" "$(@D)/cuda/include/thrust/system/detail/sequential/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/fill.h" "$(@D)/cuda/include/thrust/system/detail/sequential/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/find.h" "$(@D)/cuda/include/thrust/system/detail/sequential/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/for_each.h" "$(@D)/cuda/include/thrust/system/detail/sequential/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/gather.h" "$(@D)/cuda/include/thrust/system/detail/sequential/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/general_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/general_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/generate.h" "$(@D)/cuda/include/thrust/system/detail/sequential/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/get_value.h" "$(@D)/cuda/include/thrust/system/detail/sequential/get_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/sequential/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/insertion_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/insertion_sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/iter_swap.h" "$(@D)/cuda/include/thrust/system/detail/sequential/iter_swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/logical.h" "$(@D)/cuda/include/thrust/system/detail/sequential/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/detail/sequential/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/merge.h" "$(@D)/cuda/include/thrust/system/detail/sequential/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/merge.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/merge.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/sequential/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/partition.h" "$(@D)/cuda/include/thrust/system/detail/sequential/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/reduce.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/remove.h" "$(@D)/cuda/include/thrust/system/detail/sequential/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/replace.h" "$(@D)/cuda/include/thrust/system/detail/sequential/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/reverse.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/scan.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/scatter.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/sequence.h" "$(@D)/cuda/include/thrust/system/detail/sequential/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/sequential/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_merge_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_merge_sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_merge_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_merge_sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_primitive_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_primitive_sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_primitive_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_primitive_sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_radix_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_radix_sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_radix_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_radix_sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/sequential/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/sequential/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/sequential/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/transform.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/trivial_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/trivial_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/sequential/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/unique.h" "$(@D)/cuda/include/thrust/system/detail/sequential/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/detail/system_error.inl" "$(@D)/cuda/include/thrust/system/detail/system_error.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/error_code.h" "$(@D)/cuda/include/thrust/system/error_code.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/omp/detail/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/omp/detail/assign_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/omp/detail/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy.h" "$(@D)/cuda/include/thrust/system/omp/detail/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy.inl" "$(@D)/cuda/include/thrust/system/omp/detail/copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/omp/detail/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy_if.inl" "$(@D)/cuda/include/thrust/system/omp/detail/copy_if.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/count.h" "$(@D)/cuda/include/thrust/system/omp/detail/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/default_decomposition.h" "$(@D)/cuda/include/thrust/system/omp/detail/default_decomposition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/default_decomposition.inl" "$(@D)/cuda/include/thrust/system/omp/detail/default_decomposition.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/equal.h" "$(@D)/cuda/include/thrust/system/omp/detail/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/omp/detail/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/extrema.h" "$(@D)/cuda/include/thrust/system/omp/detail/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/fill.h" "$(@D)/cuda/include/thrust/system/omp/detail/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/find.h" "$(@D)/cuda/include/thrust/system/omp/detail/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/for_each.h" "$(@D)/cuda/include/thrust/system/omp/detail/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/for_each.inl" "$(@D)/cuda/include/thrust/system/omp/detail/for_each.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/gather.h" "$(@D)/cuda/include/thrust/system/omp/detail/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/generate.h" "$(@D)/cuda/include/thrust/system/omp/detail/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/get_value.h" "$(@D)/cuda/include/thrust/system/omp/detail/get_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/omp/detail/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/omp/detail/iter_swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/logical.h" "$(@D)/cuda/include/thrust/system/omp/detail/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/omp/detail/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/memory.inl" "$(@D)/cuda/include/thrust/system/omp/detail/memory.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/merge.h" "$(@D)/cuda/include/thrust/system/omp/detail/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/omp/detail/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/par.h" "$(@D)/cuda/include/thrust/system/omp/detail/par.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/partition.h" "$(@D)/cuda/include/thrust/system/omp/detail/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/partition.inl" "$(@D)/cuda/include/thrust/system/omp/detail/partition.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_intervals.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_intervals.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_intervals.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_intervals.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/remove.h" "$(@D)/cuda/include/thrust/system/omp/detail/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/remove.inl" "$(@D)/cuda/include/thrust/system/omp/detail/remove.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/replace.h" "$(@D)/cuda/include/thrust/system/omp/detail/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reverse.h" "$(@D)/cuda/include/thrust/system/omp/detail/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/scan.h" "$(@D)/cuda/include/thrust/system/omp/detail/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/scatter.h" "$(@D)/cuda/include/thrust/system/omp/detail/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/sequence.h" "$(@D)/cuda/include/thrust/system/omp/detail/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/omp/detail/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/sort.h" "$(@D)/cuda/include/thrust/system/omp/detail/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/sort.inl" "$(@D)/cuda/include/thrust/system/omp/detail/sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/omp/detail/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/omp/detail/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/omp/detail/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/transform.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/omp/detail/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/omp/detail/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique.h" "$(@D)/cuda/include/thrust/system/omp/detail/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique.inl" "$(@D)/cuda/include/thrust/system/omp/detail/unique.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/omp/detail/unique_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/detail/vector.inl" "$(@D)/cuda/include/thrust/system/omp/detail/vector.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/execution_policy.h" "$(@D)/cuda/include/thrust/system/omp/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/memory.h" "$(@D)/cuda/include/thrust/system/omp/memory.h" && cp "/usr/local/cuda-9.0/include/thrust/system/omp/vector.h" "$(@D)/cuda/include/thrust/system/omp/vector.h" && cp "/usr/local/cuda-9.0/include/thrust/system/system_error.h" "$(@D)/cuda/include/thrust/system/system_error.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/tbb/detail/adjacent_difference.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/tbb/detail/assign_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/tbb/detail/binary_search.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/copy.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/tbb/detail/copy_if.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy_if.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/copy_if.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/count.h" "$(@D)/cuda/include/thrust/system/tbb/detail/count.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/equal.h" "$(@D)/cuda/include/thrust/system/tbb/detail/equal.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/extrema.h" "$(@D)/cuda/include/thrust/system/tbb/detail/extrema.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/fill.h" "$(@D)/cuda/include/thrust/system/tbb/detail/fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/find.h" "$(@D)/cuda/include/thrust/system/tbb/detail/find.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/for_each.h" "$(@D)/cuda/include/thrust/system/tbb/detail/for_each.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/for_each.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/for_each.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/gather.h" "$(@D)/cuda/include/thrust/system/tbb/detail/gather.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/generate.h" "$(@D)/cuda/include/thrust/system/tbb/detail/generate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/get_value.h" "$(@D)/cuda/include/thrust/system/tbb/detail/get_value.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/tbb/detail/inner_product.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/tbb/detail/iter_swap.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/logical.h" "$(@D)/cuda/include/thrust/system/tbb/detail/logical.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/tbb/detail/malloc_and_free.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/memory.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/memory.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/merge.h" "$(@D)/cuda/include/thrust/system/tbb/detail/merge.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/merge.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/merge.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/tbb/detail/mismatch.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/par.h" "$(@D)/cuda/include/thrust/system/tbb/detail/par.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/partition.h" "$(@D)/cuda/include/thrust/system/tbb/detail/partition.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/partition.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/partition.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce_intervals.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_intervals.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/remove.h" "$(@D)/cuda/include/thrust/system/tbb/detail/remove.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/remove.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/remove.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/replace.h" "$(@D)/cuda/include/thrust/system/tbb/detail/replace.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reverse.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reverse.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scan.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scan.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/scan.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scan_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scatter.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scatter.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/sequence.h" "$(@D)/cuda/include/thrust/system/tbb/detail/sequence.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/tbb/detail/set_operations.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/sort.h" "$(@D)/cuda/include/thrust/system/tbb/detail/sort.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/sort.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/sort.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/tbb/detail/swap_ranges.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/tbb/detail/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/tbb/detail/temporary_buffer.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/transform.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/tbb/detail/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique.h" "$(@D)/cuda/include/thrust/system/tbb/detail/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/unique.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/unique_by_key.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/unique_by_key.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/vector.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/vector.inl" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/execution_policy.h" "$(@D)/cuda/include/thrust/system/tbb/execution_policy.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/memory.h" "$(@D)/cuda/include/thrust/system/tbb/memory.h" && cp "/usr/local/cuda-9.0/include/thrust/system/tbb/vector.h" "$(@D)/cuda/include/thrust/system/tbb/vector.h" && cp "/usr/local/cuda-9.0/include/thrust/system_error.h" "$(@D)/cuda/include/thrust/system_error.h" && cp "/usr/local/cuda-9.0/include/thrust/tabulate.h" "$(@D)/cuda/include/thrust/tabulate.h" && cp "/usr/local/cuda-9.0/include/thrust/transform.h" "$(@D)/cuda/include/thrust/transform.h" && cp "/usr/local/cuda-9.0/include/thrust/transform_reduce.h" "$(@D)/cuda/include/thrust/transform_reduce.h" && cp "/usr/local/cuda-9.0/include/thrust/transform_scan.h" "$(@D)/cuda/include/thrust/transform_scan.h" && cp "/usr/local/cuda-9.0/include/thrust/tuple.h" "$(@D)/cuda/include/thrust/tuple.h" && cp "/usr/local/cuda-9.0/include/thrust/uninitialized_copy.h" "$(@D)/cuda/include/thrust/uninitialized_copy.h" && cp "/usr/local/cuda-9.0/include/thrust/uninitialized_fill.h" "$(@D)/cuda/include/thrust/uninitialized_fill.h" && cp "/usr/local/cuda-9.0/include/thrust/unique.h" "$(@D)/cuda/include/thrust/unique.h" && cp "/usr/local/cuda-9.0/include/thrust/version.h" "$(@D)/cuda/include/thrust/version.h" && cp "/usr/local/cuda-9.0/include/vector_functions.h" "$(@D)/cuda/include/vector_functions.h" && cp "/usr/local/cuda-9.0/include/vector_functions.hpp" "$(@D)/cuda/include/vector_functions.hpp" && cp "/usr/local/cuda-9.0/include/vector_types.h" "$(@D)/cuda/include/vector_types.h" +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-9.0/include/CL/cl.h" "$(@D)/cuda/include/CL/cl.h" && cp -f "/usr/local/cuda-9.0/include/CL/cl.hpp" "$(@D)/cuda/include/CL/cl.hpp" && cp -f "/usr/local/cuda-9.0/include/CL/cl_egl.h" "$(@D)/cuda/include/CL/cl_egl.h" && cp -f "/usr/local/cuda-9.0/include/CL/cl_ext.h" "$(@D)/cuda/include/CL/cl_ext.h" && cp -f "/usr/local/cuda-9.0/include/CL/cl_gl.h" "$(@D)/cuda/include/CL/cl_gl.h" && cp -f "/usr/local/cuda-9.0/include/CL/cl_gl_ext.h" "$(@D)/cuda/include/CL/cl_gl_ext.h" && cp -f "/usr/local/cuda-9.0/include/CL/cl_platform.h" "$(@D)/cuda/include/CL/cl_platform.h" && cp -f "/usr/local/cuda-9.0/include/CL/opencl.h" "$(@D)/cuda/include/CL/opencl.h" && cp -f "/usr/local/cuda-9.0/include/builtin_types.h" "$(@D)/cuda/include/builtin_types.h" && cp -f "/usr/local/cuda-9.0/include/channel_descriptor.h" "$(@D)/cuda/include/channel_descriptor.h" && cp -f "/usr/local/cuda-9.0/include/common_functions.h" "$(@D)/cuda/include/common_functions.h" && cp -f "/usr/local/cuda-9.0/include/cooperative_groups.h" "$(@D)/cuda/include/cooperative_groups.h" && cp -f "/usr/local/cuda-9.0/include/cooperative_groups_helpers.h" "$(@D)/cuda/include/cooperative_groups_helpers.h" && cp -f "/usr/local/cuda-9.0/include/crt/common_functions.h" "$(@D)/cuda/include/crt/common_functions.h" && cp -f "/usr/local/cuda-9.0/include/crt/device_double_functions.h" "$(@D)/cuda/include/crt/device_double_functions.h" && cp -f "/usr/local/cuda-9.0/include/crt/device_double_functions.hpp" "$(@D)/cuda/include/crt/device_double_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/crt/device_functions.h" "$(@D)/cuda/include/crt/device_functions.h" && cp -f "/usr/local/cuda-9.0/include/crt/device_functions.hpp" "$(@D)/cuda/include/crt/device_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/crt/func_macro.h" "$(@D)/cuda/include/crt/func_macro.h" && cp -f "/usr/local/cuda-9.0/include/crt/host_config.h" "$(@D)/cuda/include/crt/host_config.h" && cp -f "/usr/local/cuda-9.0/include/crt/host_defines.h" "$(@D)/cuda/include/crt/host_defines.h" && cp -f "/usr/local/cuda-9.0/include/crt/host_runtime.h" "$(@D)/cuda/include/crt/host_runtime.h" && cp -f "/usr/local/cuda-9.0/include/crt/math_functions.h" "$(@D)/cuda/include/crt/math_functions.h" && cp -f "/usr/local/cuda-9.0/include/crt/math_functions.hpp" "$(@D)/cuda/include/crt/math_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/crt/mma.h" "$(@D)/cuda/include/crt/mma.h" && cp -f "/usr/local/cuda-9.0/include/crt/mma.hpp" "$(@D)/cuda/include/crt/mma.hpp" && cp -f "/usr/local/cuda-9.0/include/crt/nvfunctional" "$(@D)/cuda/include/crt/nvfunctional" && cp -f "/usr/local/cuda-9.0/include/crt/sm_70_rt.h" "$(@D)/cuda/include/crt/sm_70_rt.h" && cp -f "/usr/local/cuda-9.0/include/crt/sm_70_rt.hpp" "$(@D)/cuda/include/crt/sm_70_rt.hpp" && cp -f "/usr/local/cuda-9.0/include/crt/storage_class.h" "$(@D)/cuda/include/crt/storage_class.h" && cp -f "/usr/local/cuda-9.0/include/cuComplex.h" "$(@D)/cuda/include/cuComplex.h" && cp -f "/usr/local/cuda-9.0/include/cublas.h" "$(@D)/cuda/include/cublas.h" && cp -f "/usr/local/cuda-9.0/include/cublasXt.h" "$(@D)/cuda/include/cublasXt.h" && cp -f "/usr/local/cuda-9.0/include/cublas_api.h" "$(@D)/cuda/include/cublas_api.h" && cp -f "/usr/local/cuda-9.0/include/cublas_v2.h" "$(@D)/cuda/include/cublas_v2.h" && cp -f "/usr/local/cuda-9.0/include/cuda.h" "$(@D)/cuda/include/cuda.h" && cp -f "/usr/local/cuda-9.0/include/cudaEGL.h" "$(@D)/cuda/include/cudaEGL.h" && cp -f "/usr/local/cuda-9.0/include/cudaGL.h" "$(@D)/cuda/include/cudaGL.h" && cp -f "/usr/local/cuda-9.0/include/cudaProfiler.h" "$(@D)/cuda/include/cudaProfiler.h" && cp -f "/usr/local/cuda-9.0/include/cudaVDPAU.h" "$(@D)/cuda/include/cudaVDPAU.h" && cp -f "/usr/local/cuda-9.0/include/cuda_device_runtime_api.h" "$(@D)/cuda/include/cuda_device_runtime_api.h" && cp -f "/usr/local/cuda-9.0/include/cuda_fp16.h" "$(@D)/cuda/include/cuda_fp16.h" && cp -f "/usr/local/cuda-9.0/include/cuda_fp16.hpp" "$(@D)/cuda/include/cuda_fp16.hpp" && cp -f "/usr/local/cuda-9.0/include/cuda_gl_interop.h" "$(@D)/cuda/include/cuda_gl_interop.h" && cp -f "/usr/local/cuda-9.0/include/cuda_occupancy.h" "$(@D)/cuda/include/cuda_occupancy.h" && cp -f "/usr/local/cuda-9.0/include/cuda_profiler_api.h" "$(@D)/cuda/include/cuda_profiler_api.h" && cp -f "/usr/local/cuda-9.0/include/cuda_runtime.h" "$(@D)/cuda/include/cuda_runtime.h" && cp -f "/usr/local/cuda-9.0/include/cuda_runtime_api.h" "$(@D)/cuda/include/cuda_runtime_api.h" && cp -f "/usr/local/cuda-9.0/include/cuda_surface_types.h" "$(@D)/cuda/include/cuda_surface_types.h" && cp -f "/usr/local/cuda-9.0/include/cuda_texture_types.h" "$(@D)/cuda/include/cuda_texture_types.h" && cp -f "/usr/local/cuda-9.0/include/cuda_vdpau_interop.h" "$(@D)/cuda/include/cuda_vdpau_interop.h" && cp -f "/usr/local/cuda-9.0/include/cudalibxt.h" "$(@D)/cuda/include/cudalibxt.h" && cp -f "/usr/local/cuda-9.0/include/cufft.h" "$(@D)/cuda/include/cufft.h" && cp -f "/usr/local/cuda-9.0/include/cufftXt.h" "$(@D)/cuda/include/cufftXt.h" && cp -f "/usr/local/cuda-9.0/include/cufftw.h" "$(@D)/cuda/include/cufftw.h" && cp -f "/usr/local/cuda-9.0/include/curand.h" "$(@D)/cuda/include/curand.h" && cp -f "/usr/local/cuda-9.0/include/curand_discrete.h" "$(@D)/cuda/include/curand_discrete.h" && cp -f "/usr/local/cuda-9.0/include/curand_discrete2.h" "$(@D)/cuda/include/curand_discrete2.h" && cp -f "/usr/local/cuda-9.0/include/curand_globals.h" "$(@D)/cuda/include/curand_globals.h" && cp -f "/usr/local/cuda-9.0/include/curand_kernel.h" "$(@D)/cuda/include/curand_kernel.h" && cp -f "/usr/local/cuda-9.0/include/curand_lognormal.h" "$(@D)/cuda/include/curand_lognormal.h" && cp -f "/usr/local/cuda-9.0/include/curand_mrg32k3a.h" "$(@D)/cuda/include/curand_mrg32k3a.h" && cp -f "/usr/local/cuda-9.0/include/curand_mtgp32.h" "$(@D)/cuda/include/curand_mtgp32.h" && cp -f "/usr/local/cuda-9.0/include/curand_mtgp32_host.h" "$(@D)/cuda/include/curand_mtgp32_host.h" && cp -f "/usr/local/cuda-9.0/include/curand_mtgp32_kernel.h" "$(@D)/cuda/include/curand_mtgp32_kernel.h" && cp -f "/usr/local/cuda-9.0/include/curand_mtgp32dc_p_11213.h" "$(@D)/cuda/include/curand_mtgp32dc_p_11213.h" && cp -f "/usr/local/cuda-9.0/include/curand_normal.h" "$(@D)/cuda/include/curand_normal.h" && cp -f "/usr/local/cuda-9.0/include/curand_normal_static.h" "$(@D)/cuda/include/curand_normal_static.h" && cp -f "/usr/local/cuda-9.0/include/curand_philox4x32_x.h" "$(@D)/cuda/include/curand_philox4x32_x.h" && cp -f "/usr/local/cuda-9.0/include/curand_poisson.h" "$(@D)/cuda/include/curand_poisson.h" && cp -f "/usr/local/cuda-9.0/include/curand_precalc.h" "$(@D)/cuda/include/curand_precalc.h" && cp -f "/usr/local/cuda-9.0/include/curand_uniform.h" "$(@D)/cuda/include/curand_uniform.h" && cp -f "/usr/local/cuda-9.0/include/cusolverDn.h" "$(@D)/cuda/include/cusolverDn.h" && cp -f "/usr/local/cuda-9.0/include/cusolverRf.h" "$(@D)/cuda/include/cusolverRf.h" && cp -f "/usr/local/cuda-9.0/include/cusolverSp.h" "$(@D)/cuda/include/cusolverSp.h" && cp -f "/usr/local/cuda-9.0/include/cusolverSp_LOWLEVEL_PREVIEW.h" "$(@D)/cuda/include/cusolverSp_LOWLEVEL_PREVIEW.h" && cp -f "/usr/local/cuda-9.0/include/cusolver_common.h" "$(@D)/cuda/include/cusolver_common.h" && cp -f "/usr/local/cuda-9.0/include/cusparse.h" "$(@D)/cuda/include/cusparse.h" && cp -f "/usr/local/cuda-9.0/include/cusparse_v2.h" "$(@D)/cuda/include/cusparse_v2.h" && cp -f "/usr/local/cuda-9.0/include/device_atomic_functions.h" "$(@D)/cuda/include/device_atomic_functions.h" && cp -f "/usr/local/cuda-9.0/include/device_atomic_functions.hpp" "$(@D)/cuda/include/device_atomic_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/device_double_functions.h" "$(@D)/cuda/include/device_double_functions.h" && cp -f "/usr/local/cuda-9.0/include/device_double_functions.hpp" "$(@D)/cuda/include/device_double_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/device_functions.h" "$(@D)/cuda/include/device_functions.h" && cp -f "/usr/local/cuda-9.0/include/device_functions.hpp" "$(@D)/cuda/include/device_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/device_functions_decls.h" "$(@D)/cuda/include/device_functions_decls.h" && cp -f "/usr/local/cuda-9.0/include/device_launch_parameters.h" "$(@D)/cuda/include/device_launch_parameters.h" && cp -f "/usr/local/cuda-9.0/include/device_types.h" "$(@D)/cuda/include/device_types.h" && cp -f "/usr/local/cuda-9.0/include/driver_functions.h" "$(@D)/cuda/include/driver_functions.h" && cp -f "/usr/local/cuda-9.0/include/driver_types.h" "$(@D)/cuda/include/driver_types.h" && cp -f "/usr/local/cuda-9.0/include/dynlink_cuda.h" "$(@D)/cuda/include/dynlink_cuda.h" && cp -f "/usr/local/cuda-9.0/include/dynlink_cuda_cuda.h" "$(@D)/cuda/include/dynlink_cuda_cuda.h" && cp -f "/usr/local/cuda-9.0/include/dynlink_cuviddec.h" "$(@D)/cuda/include/dynlink_cuviddec.h" && cp -f "/usr/local/cuda-9.0/include/dynlink_nvcuvid.h" "$(@D)/cuda/include/dynlink_nvcuvid.h" && cp -f "/usr/local/cuda-9.0/include/fatBinaryCtl.h" "$(@D)/cuda/include/fatBinaryCtl.h" && cp -f "/usr/local/cuda-9.0/include/fatbinary.h" "$(@D)/cuda/include/fatbinary.h" && cp -f "/usr/local/cuda-9.0/include/host_config.h" "$(@D)/cuda/include/host_config.h" && cp -f "/usr/local/cuda-9.0/include/host_defines.h" "$(@D)/cuda/include/host_defines.h" && cp -f "/usr/local/cuda-9.0/include/library_types.h" "$(@D)/cuda/include/library_types.h" && cp -f "/usr/local/cuda-9.0/include/math_constants.h" "$(@D)/cuda/include/math_constants.h" && cp -f "/usr/local/cuda-9.0/include/math_functions.h" "$(@D)/cuda/include/math_functions.h" && cp -f "/usr/local/cuda-9.0/include/math_functions.hpp" "$(@D)/cuda/include/math_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/math_functions_dbl_ptx3.h" "$(@D)/cuda/include/math_functions_dbl_ptx3.h" && cp -f "/usr/local/cuda-9.0/include/math_functions_dbl_ptx3.hpp" "$(@D)/cuda/include/math_functions_dbl_ptx3.hpp" && cp -f "/usr/local/cuda-9.0/include/mma.h" "$(@D)/cuda/include/mma.h" && cp -f "/usr/local/cuda-9.0/include/npp.h" "$(@D)/cuda/include/npp.h" && cp -f "/usr/local/cuda-9.0/include/nppcore.h" "$(@D)/cuda/include/nppcore.h" && cp -f "/usr/local/cuda-9.0/include/nppdefs.h" "$(@D)/cuda/include/nppdefs.h" && cp -f "/usr/local/cuda-9.0/include/nppi.h" "$(@D)/cuda/include/nppi.h" && cp -f "/usr/local/cuda-9.0/include/nppi_arithmetic_and_logical_operations.h" "$(@D)/cuda/include/nppi_arithmetic_and_logical_operations.h" && cp -f "/usr/local/cuda-9.0/include/nppi_color_conversion.h" "$(@D)/cuda/include/nppi_color_conversion.h" && cp -f "/usr/local/cuda-9.0/include/nppi_compression_functions.h" "$(@D)/cuda/include/nppi_compression_functions.h" && cp -f "/usr/local/cuda-9.0/include/nppi_computer_vision.h" "$(@D)/cuda/include/nppi_computer_vision.h" && cp -f "/usr/local/cuda-9.0/include/nppi_data_exchange_and_initialization.h" "$(@D)/cuda/include/nppi_data_exchange_and_initialization.h" && cp -f "/usr/local/cuda-9.0/include/nppi_filtering_functions.h" "$(@D)/cuda/include/nppi_filtering_functions.h" && cp -f "/usr/local/cuda-9.0/include/nppi_geometry_transforms.h" "$(@D)/cuda/include/nppi_geometry_transforms.h" && cp -f "/usr/local/cuda-9.0/include/nppi_linear_transforms.h" "$(@D)/cuda/include/nppi_linear_transforms.h" && cp -f "/usr/local/cuda-9.0/include/nppi_morphological_operations.h" "$(@D)/cuda/include/nppi_morphological_operations.h" && cp -f "/usr/local/cuda-9.0/include/nppi_statistics_functions.h" "$(@D)/cuda/include/nppi_statistics_functions.h" && cp -f "/usr/local/cuda-9.0/include/nppi_support_functions.h" "$(@D)/cuda/include/nppi_support_functions.h" && cp -f "/usr/local/cuda-9.0/include/nppi_threshold_and_compare_operations.h" "$(@D)/cuda/include/nppi_threshold_and_compare_operations.h" && cp -f "/usr/local/cuda-9.0/include/npps.h" "$(@D)/cuda/include/npps.h" && cp -f "/usr/local/cuda-9.0/include/npps_arithmetic_and_logical_operations.h" "$(@D)/cuda/include/npps_arithmetic_and_logical_operations.h" && cp -f "/usr/local/cuda-9.0/include/npps_conversion_functions.h" "$(@D)/cuda/include/npps_conversion_functions.h" && cp -f "/usr/local/cuda-9.0/include/npps_filtering_functions.h" "$(@D)/cuda/include/npps_filtering_functions.h" && cp -f "/usr/local/cuda-9.0/include/npps_initialization.h" "$(@D)/cuda/include/npps_initialization.h" && cp -f "/usr/local/cuda-9.0/include/npps_statistics_functions.h" "$(@D)/cuda/include/npps_statistics_functions.h" && cp -f "/usr/local/cuda-9.0/include/npps_support_functions.h" "$(@D)/cuda/include/npps_support_functions.h" && cp -f "/usr/local/cuda-9.0/include/nppversion.h" "$(@D)/cuda/include/nppversion.h" && cp -f "/usr/local/cuda-9.0/include/nvToolsExt.h" "$(@D)/cuda/include/nvToolsExt.h" && cp -f "/usr/local/cuda-9.0/include/nvToolsExtCuda.h" "$(@D)/cuda/include/nvToolsExtCuda.h" && cp -f "/usr/local/cuda-9.0/include/nvToolsExtCudaRt.h" "$(@D)/cuda/include/nvToolsExtCudaRt.h" && cp -f "/usr/local/cuda-9.0/include/nvToolsExtMeta.h" "$(@D)/cuda/include/nvToolsExtMeta.h" && cp -f "/usr/local/cuda-9.0/include/nvToolsExtSync.h" "$(@D)/cuda/include/nvToolsExtSync.h" && cp -f "/usr/local/cuda-9.0/include/nvblas.h" "$(@D)/cuda/include/nvblas.h" && cp -f "/usr/local/cuda-9.0/include/nvfunctional" "$(@D)/cuda/include/nvfunctional" && cp -f "/usr/local/cuda-9.0/include/nvgraph.h" "$(@D)/cuda/include/nvgraph.h" && cp -f "/usr/local/cuda-9.0/include/nvml.h" "$(@D)/cuda/include/nvml.h" && cp -f "/usr/local/cuda-9.0/include/nvrtc.h" "$(@D)/cuda/include/nvrtc.h" && cp -f "/usr/local/cuda-9.0/include/sm_20_atomic_functions.h" "$(@D)/cuda/include/sm_20_atomic_functions.h" && cp -f "/usr/local/cuda-9.0/include/sm_20_atomic_functions.hpp" "$(@D)/cuda/include/sm_20_atomic_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/sm_20_intrinsics.h" "$(@D)/cuda/include/sm_20_intrinsics.h" && cp -f "/usr/local/cuda-9.0/include/sm_20_intrinsics.hpp" "$(@D)/cuda/include/sm_20_intrinsics.hpp" && cp -f "/usr/local/cuda-9.0/include/sm_30_intrinsics.h" "$(@D)/cuda/include/sm_30_intrinsics.h" && cp -f "/usr/local/cuda-9.0/include/sm_30_intrinsics.hpp" "$(@D)/cuda/include/sm_30_intrinsics.hpp" && cp -f "/usr/local/cuda-9.0/include/sm_32_atomic_functions.h" "$(@D)/cuda/include/sm_32_atomic_functions.h" && cp -f "/usr/local/cuda-9.0/include/sm_32_atomic_functions.hpp" "$(@D)/cuda/include/sm_32_atomic_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/sm_32_intrinsics.h" "$(@D)/cuda/include/sm_32_intrinsics.h" && cp -f "/usr/local/cuda-9.0/include/sm_32_intrinsics.hpp" "$(@D)/cuda/include/sm_32_intrinsics.hpp" && cp -f "/usr/local/cuda-9.0/include/sm_35_atomic_functions.h" "$(@D)/cuda/include/sm_35_atomic_functions.h" && cp -f "/usr/local/cuda-9.0/include/sm_35_intrinsics.h" "$(@D)/cuda/include/sm_35_intrinsics.h" && cp -f "/usr/local/cuda-9.0/include/sm_60_atomic_functions.h" "$(@D)/cuda/include/sm_60_atomic_functions.h" && cp -f "/usr/local/cuda-9.0/include/sm_60_atomic_functions.hpp" "$(@D)/cuda/include/sm_60_atomic_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/sm_61_intrinsics.h" "$(@D)/cuda/include/sm_61_intrinsics.h" && cp -f "/usr/local/cuda-9.0/include/sm_61_intrinsics.hpp" "$(@D)/cuda/include/sm_61_intrinsics.hpp" && cp -f "/usr/local/cuda-9.0/include/sobol_direction_vectors.h" "$(@D)/cuda/include/sobol_direction_vectors.h" && cp -f "/usr/local/cuda-9.0/include/surface_functions.h" "$(@D)/cuda/include/surface_functions.h" && cp -f "/usr/local/cuda-9.0/include/surface_functions.hpp" "$(@D)/cuda/include/surface_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/surface_indirect_functions.h" "$(@D)/cuda/include/surface_indirect_functions.h" && cp -f "/usr/local/cuda-9.0/include/surface_indirect_functions.hpp" "$(@D)/cuda/include/surface_indirect_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/surface_types.h" "$(@D)/cuda/include/surface_types.h" && cp -f "/usr/local/cuda-9.0/include/texture_fetch_functions.h" "$(@D)/cuda/include/texture_fetch_functions.h" && cp -f "/usr/local/cuda-9.0/include/texture_fetch_functions.hpp" "$(@D)/cuda/include/texture_fetch_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/texture_indirect_functions.h" "$(@D)/cuda/include/texture_indirect_functions.h" && cp -f "/usr/local/cuda-9.0/include/texture_indirect_functions.hpp" "$(@D)/cuda/include/texture_indirect_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/texture_types.h" "$(@D)/cuda/include/texture_types.h" && cp -f "/usr/local/cuda-9.0/include/thrust/adjacent_difference.h" "$(@D)/cuda/include/thrust/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/advance.h" "$(@D)/cuda/include/thrust/advance.h" && cp -f "/usr/local/cuda-9.0/include/thrust/binary_search.h" "$(@D)/cuda/include/thrust/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/complex.h" "$(@D)/cuda/include/thrust/complex.h" && cp -f "/usr/local/cuda-9.0/include/thrust/copy.h" "$(@D)/cuda/include/thrust/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/count.h" "$(@D)/cuda/include/thrust/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/adjacent_difference.inl" "$(@D)/cuda/include/thrust/detail/adjacent_difference.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/advance.inl" "$(@D)/cuda/include/thrust/detail/advance.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/allocator_traits.h" "$(@D)/cuda/include/thrust/detail/allocator/allocator_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/allocator_traits.inl" "$(@D)/cuda/include/thrust/detail/allocator/allocator_traits.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/copy_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/copy_construct_range.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/copy_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/copy_construct_range.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/default_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/default_construct_range.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/default_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/default_construct_range.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/destroy_range.h" "$(@D)/cuda/include/thrust/detail/allocator/destroy_range.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/destroy_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/destroy_range.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/fill_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/fill_construct_range.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/fill_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/fill_construct_range.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/malloc_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/malloc_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/malloc_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/malloc_allocator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/no_throw_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/no_throw_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/tagged_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/tagged_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/tagged_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/tagged_allocator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/temporary_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/temporary_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/allocator/temporary_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/temporary_allocator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/binary_search.inl" "$(@D)/cuda/include/thrust/detail/binary_search.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/arithmetic.h" "$(@D)/cuda/include/thrust/detail/complex/arithmetic.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/c99math.h" "$(@D)/cuda/include/thrust/detail/complex/c99math.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/catrig.h" "$(@D)/cuda/include/thrust/detail/complex/catrig.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/catrigf.h" "$(@D)/cuda/include/thrust/detail/complex/catrigf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/ccosh.h" "$(@D)/cuda/include/thrust/detail/complex/ccosh.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/ccoshf.h" "$(@D)/cuda/include/thrust/detail/complex/ccoshf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/cexp.h" "$(@D)/cuda/include/thrust/detail/complex/cexp.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/cexpf.h" "$(@D)/cuda/include/thrust/detail/complex/cexpf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/clog.h" "$(@D)/cuda/include/thrust/detail/complex/clog.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/clogf.h" "$(@D)/cuda/include/thrust/detail/complex/clogf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/complex.inl" "$(@D)/cuda/include/thrust/detail/complex/complex.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/cpow.h" "$(@D)/cuda/include/thrust/detail/complex/cpow.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/cpowf.h" "$(@D)/cuda/include/thrust/detail/complex/cpowf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/cproj.h" "$(@D)/cuda/include/thrust/detail/complex/cproj.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/csinh.h" "$(@D)/cuda/include/thrust/detail/complex/csinh.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/csinhf.h" "$(@D)/cuda/include/thrust/detail/complex/csinhf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/csqrt.h" "$(@D)/cuda/include/thrust/detail/complex/csqrt.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/csqrtf.h" "$(@D)/cuda/include/thrust/detail/complex/csqrtf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/ctanh.h" "$(@D)/cuda/include/thrust/detail/complex/ctanh.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/ctanhf.h" "$(@D)/cuda/include/thrust/detail/complex/ctanhf.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/math_private.h" "$(@D)/cuda/include/thrust/detail/complex/math_private.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/complex/stream.h" "$(@D)/cuda/include/thrust/detail/complex/stream.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config.h" "$(@D)/cuda/include/thrust/detail/config.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/compiler.h" "$(@D)/cuda/include/thrust/detail/config/compiler.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/compiler_fence.h" "$(@D)/cuda/include/thrust/detail/config/compiler_fence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/config.h" "$(@D)/cuda/include/thrust/detail/config/config.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/debug.h" "$(@D)/cuda/include/thrust/detail/config/debug.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/device_system.h" "$(@D)/cuda/include/thrust/detail/config/device_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/exec_check_disable.h" "$(@D)/cuda/include/thrust/detail/config/exec_check_disable.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/forceinline.h" "$(@D)/cuda/include/thrust/detail/config/forceinline.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/global_workarounds.h" "$(@D)/cuda/include/thrust/detail/config/global_workarounds.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/host_device.h" "$(@D)/cuda/include/thrust/detail/config/host_device.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/host_system.h" "$(@D)/cuda/include/thrust/detail/config/host_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/config/simple_defines.h" "$(@D)/cuda/include/thrust/detail/config/simple_defines.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/contiguous_storage.h" "$(@D)/cuda/include/thrust/detail/contiguous_storage.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/contiguous_storage.inl" "$(@D)/cuda/include/thrust/detail/contiguous_storage.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/copy.h" "$(@D)/cuda/include/thrust/detail/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/copy.inl" "$(@D)/cuda/include/thrust/detail/copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/copy_if.h" "$(@D)/cuda/include/thrust/detail/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/copy_if.inl" "$(@D)/cuda/include/thrust/detail/copy_if.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/count.inl" "$(@D)/cuda/include/thrust/detail/count.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/cstdint.h" "$(@D)/cuda/include/thrust/detail/cstdint.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_delete.inl" "$(@D)/cuda/include/thrust/detail/device_delete.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_free.inl" "$(@D)/cuda/include/thrust/detail/device_free.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_malloc.inl" "$(@D)/cuda/include/thrust/detail/device_malloc.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_new.inl" "$(@D)/cuda/include/thrust/detail/device_new.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_ptr.inl" "$(@D)/cuda/include/thrust/detail/device_ptr.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_reference.inl" "$(@D)/cuda/include/thrust/detail/device_reference.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/device_vector.inl" "$(@D)/cuda/include/thrust/detail/device_vector.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/dispatch/is_trivial_copy.h" "$(@D)/cuda/include/thrust/detail/dispatch/is_trivial_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/distance.inl" "$(@D)/cuda/include/thrust/detail/distance.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/equal.inl" "$(@D)/cuda/include/thrust/detail/equal.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/execute_with_allocator.h" "$(@D)/cuda/include/thrust/detail/execute_with_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/execution_policy.h" "$(@D)/cuda/include/thrust/detail/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/extrema.inl" "$(@D)/cuda/include/thrust/detail/extrema.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/fill.inl" "$(@D)/cuda/include/thrust/detail/fill.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/find.inl" "$(@D)/cuda/include/thrust/detail/find.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/for_each.inl" "$(@D)/cuda/include/thrust/detail/for_each.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/function.h" "$(@D)/cuda/include/thrust/detail/function.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional.inl" "$(@D)/cuda/include/thrust/detail/functional.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/actor.h" "$(@D)/cuda/include/thrust/detail/functional/actor.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/actor.inl" "$(@D)/cuda/include/thrust/detail/functional/actor.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/argument.h" "$(@D)/cuda/include/thrust/detail/functional/argument.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/composite.h" "$(@D)/cuda/include/thrust/detail/functional/composite.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/arithmetic_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/arithmetic_operators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/assignment_operator.h" "$(@D)/cuda/include/thrust/detail/functional/operators/assignment_operator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/bitwise_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/bitwise_operators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/compound_assignment_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/compound_assignment_operators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/logical_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/logical_operators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/operator_adaptors.h" "$(@D)/cuda/include/thrust/detail/functional/operators/operator_adaptors.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/operators/relational_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/relational_operators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/placeholder.h" "$(@D)/cuda/include/thrust/detail/functional/placeholder.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/functional/value.h" "$(@D)/cuda/include/thrust/detail/functional/value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/gather.inl" "$(@D)/cuda/include/thrust/detail/gather.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/generate.inl" "$(@D)/cuda/include/thrust/detail/generate.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/get_iterator_value.h" "$(@D)/cuda/include/thrust/detail/get_iterator_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/host_vector.inl" "$(@D)/cuda/include/thrust/detail/host_vector.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/inner_product.inl" "$(@D)/cuda/include/thrust/detail/inner_product.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/integer_math.h" "$(@D)/cuda/include/thrust/detail/integer_math.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/integer_traits.h" "$(@D)/cuda/include/thrust/detail/integer_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/internal_functional.h" "$(@D)/cuda/include/thrust/detail/internal_functional.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/logical.inl" "$(@D)/cuda/include/thrust/detail/logical.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/merge.inl" "$(@D)/cuda/include/thrust/detail/merge.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/minmax.h" "$(@D)/cuda/include/thrust/detail/minmax.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/mismatch.inl" "$(@D)/cuda/include/thrust/detail/mismatch.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/mpl/math.h" "$(@D)/cuda/include/thrust/detail/mpl/math.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/numeric_traits.h" "$(@D)/cuda/include/thrust/detail/numeric_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/overlapped_copy.h" "$(@D)/cuda/include/thrust/detail/overlapped_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/pair.inl" "$(@D)/cuda/include/thrust/detail/pair.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/partition.inl" "$(@D)/cuda/include/thrust/detail/partition.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/pointer.h" "$(@D)/cuda/include/thrust/detail/pointer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/pointer.inl" "$(@D)/cuda/include/thrust/detail/pointer.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/range/head_flags.h" "$(@D)/cuda/include/thrust/detail/range/head_flags.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/range/tail_flags.h" "$(@D)/cuda/include/thrust/detail/range/tail_flags.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/raw_pointer_cast.h" "$(@D)/cuda/include/thrust/detail/raw_pointer_cast.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/raw_reference_cast.h" "$(@D)/cuda/include/thrust/detail/raw_reference_cast.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/reduce.inl" "$(@D)/cuda/include/thrust/detail/reduce.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/reference.h" "$(@D)/cuda/include/thrust/detail/reference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/reference.inl" "$(@D)/cuda/include/thrust/detail/reference.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/reference_forward_declaration.h" "$(@D)/cuda/include/thrust/detail/reference_forward_declaration.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/remove.inl" "$(@D)/cuda/include/thrust/detail/remove.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/replace.inl" "$(@D)/cuda/include/thrust/detail/replace.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/reverse.inl" "$(@D)/cuda/include/thrust/detail/reverse.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/scan.inl" "$(@D)/cuda/include/thrust/detail/scan.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/scatter.inl" "$(@D)/cuda/include/thrust/detail/scatter.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/seq.h" "$(@D)/cuda/include/thrust/detail/seq.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/sequence.inl" "$(@D)/cuda/include/thrust/detail/sequence.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/set_operations.inl" "$(@D)/cuda/include/thrust/detail/set_operations.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/sort.inl" "$(@D)/cuda/include/thrust/detail/sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/static_assert.h" "$(@D)/cuda/include/thrust/detail/static_assert.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/static_map.h" "$(@D)/cuda/include/thrust/detail/static_map.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/swap.h" "$(@D)/cuda/include/thrust/detail/swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/swap.inl" "$(@D)/cuda/include/thrust/detail/swap.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/swap_ranges.inl" "$(@D)/cuda/include/thrust/detail/swap_ranges.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/tabulate.inl" "$(@D)/cuda/include/thrust/detail/tabulate.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/temporary_array.h" "$(@D)/cuda/include/thrust/detail/temporary_array.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/temporary_array.inl" "$(@D)/cuda/include/thrust/detail/temporary_array.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/transform.inl" "$(@D)/cuda/include/thrust/detail/transform.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/transform_reduce.inl" "$(@D)/cuda/include/thrust/detail/transform_reduce.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/transform_scan.inl" "$(@D)/cuda/include/thrust/detail/transform_scan.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/trivial_sequence.h" "$(@D)/cuda/include/thrust/detail/trivial_sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/tuple.inl" "$(@D)/cuda/include/thrust/detail/tuple.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/tuple_meta_transform.h" "$(@D)/cuda/include/thrust/detail/tuple_meta_transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/tuple_transform.h" "$(@D)/cuda/include/thrust/detail/tuple_transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h" "$(@D)/cuda/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/function_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits/function_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/has_member_function.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_member_function.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/has_nested_type.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_nested_type.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/has_trivial_assign.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_trivial_assign.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/is_call_possible.h" "$(@D)/cuda/include/thrust/detail/type_traits/is_call_possible.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/is_metafunction_defined.h" "$(@D)/cuda/include/thrust/detail/type_traits/is_metafunction_defined.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/iterator/is_discard_iterator.h" "$(@D)/cuda/include/thrust/detail/type_traits/iterator/is_discard_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/iterator/is_output_iterator.h" "$(@D)/cuda/include/thrust/detail/type_traits/iterator/is_output_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/minimum_type.h" "$(@D)/cuda/include/thrust/detail/type_traits/minimum_type.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/pointer_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits/pointer_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/type_traits/result_of_adaptable_function.h" "$(@D)/cuda/include/thrust/detail/type_traits/result_of_adaptable_function.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/uninitialized_copy.inl" "$(@D)/cuda/include/thrust/detail/uninitialized_copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/uninitialized_fill.inl" "$(@D)/cuda/include/thrust/detail/uninitialized_fill.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/unique.inl" "$(@D)/cuda/include/thrust/detail/unique.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/use_default.h" "$(@D)/cuda/include/thrust/detail/use_default.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/util/align.h" "$(@D)/cuda/include/thrust/detail/util/align.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/util/blocking.h" "$(@D)/cuda/include/thrust/detail/util/blocking.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/vector_base.h" "$(@D)/cuda/include/thrust/detail/vector_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/detail/vector_base.inl" "$(@D)/cuda/include/thrust/detail/vector_base.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/device_allocator.h" "$(@D)/cuda/include/thrust/device_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_delete.h" "$(@D)/cuda/include/thrust/device_delete.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_free.h" "$(@D)/cuda/include/thrust/device_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_malloc.h" "$(@D)/cuda/include/thrust/device_malloc.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_malloc_allocator.h" "$(@D)/cuda/include/thrust/device_malloc_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_new.h" "$(@D)/cuda/include/thrust/device_new.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_new_allocator.h" "$(@D)/cuda/include/thrust/device_new_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_ptr.h" "$(@D)/cuda/include/thrust/device_ptr.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_reference.h" "$(@D)/cuda/include/thrust/device_reference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/device_vector.h" "$(@D)/cuda/include/thrust/device_vector.h" && cp -f "/usr/local/cuda-9.0/include/thrust/distance.h" "$(@D)/cuda/include/thrust/distance.h" && cp -f "/usr/local/cuda-9.0/include/thrust/equal.h" "$(@D)/cuda/include/thrust/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/execution_policy.h" "$(@D)/cuda/include/thrust/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/extrema.h" "$(@D)/cuda/include/thrust/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/fill.h" "$(@D)/cuda/include/thrust/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/find.h" "$(@D)/cuda/include/thrust/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/for_each.h" "$(@D)/cuda/include/thrust/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/functional.h" "$(@D)/cuda/include/thrust/functional.h" && cp -f "/usr/local/cuda-9.0/include/thrust/gather.h" "$(@D)/cuda/include/thrust/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/generate.h" "$(@D)/cuda/include/thrust/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/host_vector.h" "$(@D)/cuda/include/thrust/host_vector.h" && cp -f "/usr/local/cuda-9.0/include/thrust/inner_product.h" "$(@D)/cuda/include/thrust/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/constant_iterator.h" "$(@D)/cuda/include/thrust/iterator/constant_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/counting_iterator.h" "$(@D)/cuda/include/thrust/iterator/counting_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/any_assign.h" "$(@D)/cuda/include/thrust/iterator/detail/any_assign.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/any_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/any_system_tag.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/constant_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/constant_iterator_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/counting_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/counting_iterator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/device_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/device_system_tag.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/discard_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/discard_iterator_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/distance_from_result.h" "$(@D)/cuda/include/thrust/iterator/detail/distance_from_result.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/host_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/host_system_tag.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/is_iterator_category.h" "$(@D)/cuda/include/thrust/iterator/detail/is_iterator_category.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/is_trivial_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/is_trivial_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_adaptor_base.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_adaptor_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_category_to_system.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_to_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_category_to_traversal.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_to_traversal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_facade_category.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_facade_category.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_traits.inl" "$(@D)/cuda/include/thrust/iterator/detail/iterator_traits.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/iterator_traversal_tags.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_traversal_tags.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/join_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/join_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/minimum_category.h" "$(@D)/cuda/include/thrust/iterator/detail/minimum_category.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/minimum_system.h" "$(@D)/cuda/include/thrust/iterator/detail/minimum_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/normal_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/normal_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/permutation_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/permutation_iterator_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/retag.h" "$(@D)/cuda/include/thrust/iterator/detail/retag.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/reverse_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/reverse_iterator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/reverse_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/reverse_iterator_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/tagged_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/tagged_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/transform_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/transform_iterator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/transform_output_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/transform_output_iterator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/tuple_of_iterator_references.h" "$(@D)/cuda/include/thrust/iterator/detail/tuple_of_iterator_references.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/universal_categories.h" "$(@D)/cuda/include/thrust/iterator/detail/universal_categories.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/zip_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/zip_iterator.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/detail/zip_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/zip_iterator_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/discard_iterator.h" "$(@D)/cuda/include/thrust/iterator/discard_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/iterator_adaptor.h" "$(@D)/cuda/include/thrust/iterator/iterator_adaptor.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/iterator_categories.h" "$(@D)/cuda/include/thrust/iterator/iterator_categories.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/iterator_facade.h" "$(@D)/cuda/include/thrust/iterator/iterator_facade.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/iterator_traits.h" "$(@D)/cuda/include/thrust/iterator/iterator_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/permutation_iterator.h" "$(@D)/cuda/include/thrust/iterator/permutation_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/retag.h" "$(@D)/cuda/include/thrust/iterator/retag.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/reverse_iterator.h" "$(@D)/cuda/include/thrust/iterator/reverse_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/transform_iterator.h" "$(@D)/cuda/include/thrust/iterator/transform_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/transform_output_iterator.h" "$(@D)/cuda/include/thrust/iterator/transform_output_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/iterator/zip_iterator.h" "$(@D)/cuda/include/thrust/iterator/zip_iterator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/logical.h" "$(@D)/cuda/include/thrust/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/memory.h" "$(@D)/cuda/include/thrust/memory.h" && cp -f "/usr/local/cuda-9.0/include/thrust/merge.h" "$(@D)/cuda/include/thrust/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/mismatch.h" "$(@D)/cuda/include/thrust/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/pair.h" "$(@D)/cuda/include/thrust/pair.h" && cp -f "/usr/local/cuda-9.0/include/thrust/partition.h" "$(@D)/cuda/include/thrust/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random.h" "$(@D)/cuda/include/thrust/random.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/discard_block_engine.inl" "$(@D)/cuda/include/thrust/random/detail/discard_block_engine.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/linear_congruential_engine.inl" "$(@D)/cuda/include/thrust/random/detail/linear_congruential_engine.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/linear_congruential_engine_discard.h" "$(@D)/cuda/include/thrust/random/detail/linear_congruential_engine_discard.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/linear_feedback_shift_engine.inl" "$(@D)/cuda/include/thrust/random/detail/linear_feedback_shift_engine.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h" "$(@D)/cuda/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/mod.h" "$(@D)/cuda/include/thrust/random/detail/mod.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/normal_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/normal_distribution.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/normal_distribution_base.h" "$(@D)/cuda/include/thrust/random/detail/normal_distribution_base.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/random_core_access.h" "$(@D)/cuda/include/thrust/random/detail/random_core_access.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/subtract_with_carry_engine.inl" "$(@D)/cuda/include/thrust/random/detail/subtract_with_carry_engine.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/uniform_int_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/uniform_int_distribution.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/uniform_real_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/uniform_real_distribution.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/xor_combine_engine.inl" "$(@D)/cuda/include/thrust/random/detail/xor_combine_engine.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/random/detail/xor_combine_engine_max.h" "$(@D)/cuda/include/thrust/random/detail/xor_combine_engine_max.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/discard_block_engine.h" "$(@D)/cuda/include/thrust/random/discard_block_engine.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/linear_congruential_engine.h" "$(@D)/cuda/include/thrust/random/linear_congruential_engine.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/linear_feedback_shift_engine.h" "$(@D)/cuda/include/thrust/random/linear_feedback_shift_engine.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/normal_distribution.h" "$(@D)/cuda/include/thrust/random/normal_distribution.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/subtract_with_carry_engine.h" "$(@D)/cuda/include/thrust/random/subtract_with_carry_engine.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/uniform_int_distribution.h" "$(@D)/cuda/include/thrust/random/uniform_int_distribution.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/uniform_real_distribution.h" "$(@D)/cuda/include/thrust/random/uniform_real_distribution.h" && cp -f "/usr/local/cuda-9.0/include/thrust/random/xor_combine_engine.h" "$(@D)/cuda/include/thrust/random/xor_combine_engine.h" && cp -f "/usr/local/cuda-9.0/include/thrust/reduce.h" "$(@D)/cuda/include/thrust/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/remove.h" "$(@D)/cuda/include/thrust/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/replace.h" "$(@D)/cuda/include/thrust/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/reverse.h" "$(@D)/cuda/include/thrust/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/scan.h" "$(@D)/cuda/include/thrust/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/scatter.h" "$(@D)/cuda/include/thrust/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/sequence.h" "$(@D)/cuda/include/thrust/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/set_operations.h" "$(@D)/cuda/include/thrust/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/sort.h" "$(@D)/cuda/include/thrust/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/swap.h" "$(@D)/cuda/include/thrust/swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/cpp/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/cpp/detail/assign_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/cpp/detail/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/copy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/cpp/detail/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/count.h" "$(@D)/cuda/include/thrust/system/cpp/detail/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/equal.h" "$(@D)/cuda/include/thrust/system/cpp/detail/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/extrema.h" "$(@D)/cuda/include/thrust/system/cpp/detail/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/fill.h" "$(@D)/cuda/include/thrust/system/cpp/detail/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/find.h" "$(@D)/cuda/include/thrust/system/cpp/detail/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/for_each.h" "$(@D)/cuda/include/thrust/system/cpp/detail/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/gather.h" "$(@D)/cuda/include/thrust/system/cpp/detail/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/generate.h" "$(@D)/cuda/include/thrust/system/cpp/detail/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/get_value.h" "$(@D)/cuda/include/thrust/system/cpp/detail/get_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/cpp/detail/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/cpp/detail/iter_swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/logical.h" "$(@D)/cuda/include/thrust/system/cpp/detail/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/cpp/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/memory.inl" "$(@D)/cuda/include/thrust/system/cpp/detail/memory.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/merge.h" "$(@D)/cuda/include/thrust/system/cpp/detail/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/cpp/detail/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/par.h" "$(@D)/cuda/include/thrust/system/cpp/detail/par.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/partition.h" "$(@D)/cuda/include/thrust/system/cpp/detail/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/reduce.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/remove.h" "$(@D)/cuda/include/thrust/system/cpp/detail/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/replace.h" "$(@D)/cuda/include/thrust/system/cpp/detail/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/reverse.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/scan.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/scatter.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/sequence.h" "$(@D)/cuda/include/thrust/system/cpp/detail/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/cpp/detail/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/sort.h" "$(@D)/cuda/include/thrust/system/cpp/detail/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/cpp/detail/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/cpp/detail/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/cpp/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/transform.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/cpp/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/unique.h" "$(@D)/cuda/include/thrust/system/cpp/detail/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/detail/vector.inl" "$(@D)/cuda/include/thrust/system/cpp/detail/vector.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/execution_policy.h" "$(@D)/cuda/include/thrust/system/cpp/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/memory.h" "$(@D)/cuda/include/thrust/system/cpp/memory.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cpp/vector.h" "$(@D)/cuda/include/thrust/system/cpp/vector.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/config.h" "$(@D)/cuda/include/thrust/system/cuda/config.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/cuda/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/cuda/detail/assign_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/cuda/detail/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/copy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/cuda/detail/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/agent_launcher.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/agent_launcher.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/alignment.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/alignment.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/triple_chevron_launch.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/triple_chevron_launch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/core/util.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/util.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/count.h" "$(@D)/cuda/include/thrust/system/cuda/detail/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cross_system.h" "$(@D)/cuda/include/thrust/system/cuda/detail/cross_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_csrt.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_csrt.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_row_based.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_row_based.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_load.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_load.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_scan.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/block_store.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_store.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/cub.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/cub.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_partition.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_partition.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_scan.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_select.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_select.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_csrt.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_csrt.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_row_based.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_row_based.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/host/mutex.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/host/mutex.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_allocator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_allocator.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_arch.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_arch.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_debug.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_debug.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_device.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_device.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_macro.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_macro.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_namespace.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_namespace.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_ptx.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_ptx.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/util_type.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_type.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/equal.h" "$(@D)/cuda/include/thrust/system/cuda/detail/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/error.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/error.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/extrema.h" "$(@D)/cuda/include/thrust/system/cuda/detail/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/fill.h" "$(@D)/cuda/include/thrust/system/cuda/detail/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/find.h" "$(@D)/cuda/include/thrust/system/cuda/detail/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/for_each.h" "$(@D)/cuda/include/thrust/system/cuda/detail/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/gather.h" "$(@D)/cuda/include/thrust/system/cuda/detail/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/generate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/get_value.h" "$(@D)/cuda/include/thrust/system/cuda/detail/get_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h" "$(@D)/cuda/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/guarded_driver_types.h" "$(@D)/cuda/include/thrust/system/cuda/detail/guarded_driver_types.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/cuda/detail/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/internal/copy_cross_system.h" "$(@D)/cuda/include/thrust/system/cuda/detail/internal/copy_cross_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/internal/copy_device_to_device.h" "$(@D)/cuda/include/thrust/system/cuda/detail/internal/copy_device_to_device.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/cuda/detail/iter_swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/logical.h" "$(@D)/cuda/include/thrust/system/cuda/detail/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/cuda/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/memory.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/memory.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/memory_buffer.h" "$(@D)/cuda/include/thrust/system/cuda/detail/memory_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/merge.h" "$(@D)/cuda/include/thrust/system/cuda/detail/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/cuda/detail/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/par.h" "$(@D)/cuda/include/thrust/system/cuda/detail/par.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/par_to_seq.h" "$(@D)/cuda/include/thrust/system/cuda/detail/par_to_seq.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/parallel_for.h" "$(@D)/cuda/include/thrust/system/cuda/detail/parallel_for.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/partition.h" "$(@D)/cuda/include/thrust/system/cuda/detail/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/reduce.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/remove.h" "$(@D)/cuda/include/thrust/system/cuda/detail/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/replace.h" "$(@D)/cuda/include/thrust/system/cuda/detail/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/reverse.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/scan.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/scatter.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/sequence.h" "$(@D)/cuda/include/thrust/system/cuda/detail/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/cuda/detail/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/sort.h" "$(@D)/cuda/include/thrust/system/cuda/detail/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/cuda/detail/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/cuda/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/terminate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/terminate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/transform.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/cuda/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/unique.h" "$(@D)/cuda/include/thrust/system/cuda/detail/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/util.h" "$(@D)/cuda/include/thrust/system/cuda/detail/util.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/detail/vector.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/vector.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/error.h" "$(@D)/cuda/include/thrust/system/cuda/error.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/execution_policy.h" "$(@D)/cuda/include/thrust/system/cuda/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/experimental/pinned_allocator.h" "$(@D)/cuda/include/thrust/system/cuda/experimental/pinned_allocator.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/memory.h" "$(@D)/cuda/include/thrust/system/cuda/memory.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/cuda/vector.h" "$(@D)/cuda/include/thrust/system/cuda/vector.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/adl/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/assign_value.h" "$(@D)/cuda/include/thrust/system/detail/adl/assign_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/adl/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/copy.h" "$(@D)/cuda/include/thrust/system/detail/adl/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/adl/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/count.h" "$(@D)/cuda/include/thrust/system/detail/adl/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/equal.h" "$(@D)/cuda/include/thrust/system/detail/adl/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/extrema.h" "$(@D)/cuda/include/thrust/system/detail/adl/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/fill.h" "$(@D)/cuda/include/thrust/system/detail/adl/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/find.h" "$(@D)/cuda/include/thrust/system/detail/adl/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/for_each.h" "$(@D)/cuda/include/thrust/system/detail/adl/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/gather.h" "$(@D)/cuda/include/thrust/system/detail/adl/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/generate.h" "$(@D)/cuda/include/thrust/system/detail/adl/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/get_value.h" "$(@D)/cuda/include/thrust/system/detail/adl/get_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/adl/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/iter_swap.h" "$(@D)/cuda/include/thrust/system/detail/adl/iter_swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/logical.h" "$(@D)/cuda/include/thrust/system/detail/adl/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/detail/adl/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/merge.h" "$(@D)/cuda/include/thrust/system/detail/adl/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/adl/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/partition.h" "$(@D)/cuda/include/thrust/system/detail/adl/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/reduce.h" "$(@D)/cuda/include/thrust/system/detail/adl/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/remove.h" "$(@D)/cuda/include/thrust/system/detail/adl/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/replace.h" "$(@D)/cuda/include/thrust/system/detail/adl/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/reverse.h" "$(@D)/cuda/include/thrust/system/detail/adl/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/scan.h" "$(@D)/cuda/include/thrust/system/detail/adl/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/scatter.h" "$(@D)/cuda/include/thrust/system/detail/adl/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/sequence.h" "$(@D)/cuda/include/thrust/system/detail/adl/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/adl/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/sort.h" "$(@D)/cuda/include/thrust/system/detail/adl/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/adl/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/adl/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/adl/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/transform.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/adl/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/adl/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/unique.h" "$(@D)/cuda/include/thrust/system/detail/adl/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/adl/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/bad_alloc.h" "$(@D)/cuda/include/thrust/system/detail/bad_alloc.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/errno.h" "$(@D)/cuda/include/thrust/system/detail/errno.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/error_category.inl" "$(@D)/cuda/include/thrust/system/detail/error_category.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/error_code.inl" "$(@D)/cuda/include/thrust/system/detail/error_code.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/error_condition.inl" "$(@D)/cuda/include/thrust/system/detail/error_condition.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/generic/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/adjacent_difference.inl" "$(@D)/cuda/include/thrust/system/detail/generic/adjacent_difference.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/advance.h" "$(@D)/cuda/include/thrust/system/detail/generic/advance.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/advance.inl" "$(@D)/cuda/include/thrust/system/detail/generic/advance.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/generic/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/binary_search.inl" "$(@D)/cuda/include/thrust/system/detail/generic/binary_search.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy.h" "$(@D)/cuda/include/thrust/system/detail/generic/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy.inl" "$(@D)/cuda/include/thrust/system/detail/generic/copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/generic/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/copy_if.inl" "$(@D)/cuda/include/thrust/system/detail/generic/copy_if.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/count.h" "$(@D)/cuda/include/thrust/system/detail/generic/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/count.inl" "$(@D)/cuda/include/thrust/system/detail/generic/count.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/distance.h" "$(@D)/cuda/include/thrust/system/detail/generic/distance.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/distance.inl" "$(@D)/cuda/include/thrust/system/detail/generic/distance.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/equal.h" "$(@D)/cuda/include/thrust/system/detail/generic/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/equal.inl" "$(@D)/cuda/include/thrust/system/detail/generic/equal.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/extrema.h" "$(@D)/cuda/include/thrust/system/detail/generic/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/extrema.inl" "$(@D)/cuda/include/thrust/system/detail/generic/extrema.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/fill.h" "$(@D)/cuda/include/thrust/system/detail/generic/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/find.h" "$(@D)/cuda/include/thrust/system/detail/generic/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/find.inl" "$(@D)/cuda/include/thrust/system/detail/generic/find.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/for_each.h" "$(@D)/cuda/include/thrust/system/detail/generic/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/gather.h" "$(@D)/cuda/include/thrust/system/detail/generic/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/gather.inl" "$(@D)/cuda/include/thrust/system/detail/generic/gather.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/generate.h" "$(@D)/cuda/include/thrust/system/detail/generic/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/generate.inl" "$(@D)/cuda/include/thrust/system/detail/generic/generate.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/generic/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/inner_product.inl" "$(@D)/cuda/include/thrust/system/detail/generic/inner_product.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/logical.h" "$(@D)/cuda/include/thrust/system/detail/generic/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/memory.h" "$(@D)/cuda/include/thrust/system/detail/generic/memory.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/memory.inl" "$(@D)/cuda/include/thrust/system/detail/generic/memory.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/merge.h" "$(@D)/cuda/include/thrust/system/detail/generic/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/merge.inl" "$(@D)/cuda/include/thrust/system/detail/generic/merge.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/generic/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/mismatch.inl" "$(@D)/cuda/include/thrust/system/detail/generic/mismatch.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/partition.h" "$(@D)/cuda/include/thrust/system/detail/generic/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/partition.inl" "$(@D)/cuda/include/thrust/system/detail/generic/partition.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce.h" "$(@D)/cuda/include/thrust/system/detail/generic/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reduce.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reduce_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/remove.h" "$(@D)/cuda/include/thrust/system/detail/generic/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/remove.inl" "$(@D)/cuda/include/thrust/system/detail/generic/remove.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/replace.h" "$(@D)/cuda/include/thrust/system/detail/generic/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/replace.inl" "$(@D)/cuda/include/thrust/system/detail/generic/replace.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reverse.h" "$(@D)/cuda/include/thrust/system/detail/generic/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/reverse.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reverse.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scalar/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/generic/scalar/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scalar/binary_search.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scalar/binary_search.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan.h" "$(@D)/cuda/include/thrust/system/detail/generic/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scan.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scan_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scan_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scatter.h" "$(@D)/cuda/include/thrust/system/detail/generic/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/scatter.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scatter.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/select_system.h" "$(@D)/cuda/include/thrust/system/detail/generic/select_system.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sequence.h" "$(@D)/cuda/include/thrust/system/detail/generic/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sequence.inl" "$(@D)/cuda/include/thrust/system/detail/generic/sequence.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/generic/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/set_operations.inl" "$(@D)/cuda/include/thrust/system/detail/generic/set_operations.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sort.h" "$(@D)/cuda/include/thrust/system/detail/generic/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/sort.inl" "$(@D)/cuda/include/thrust/system/detail/generic/sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/generic/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/swap_ranges.inl" "$(@D)/cuda/include/thrust/system/detail/generic/swap_ranges.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/generic/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/tabulate.inl" "$(@D)/cuda/include/thrust/system/detail/generic/tabulate.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/tag.h" "$(@D)/cuda/include/thrust/system/detail/generic/tag.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/generic/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/temporary_buffer.inl" "$(@D)/cuda/include/thrust/system/detail/generic/temporary_buffer.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_reduce.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform_reduce.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/transform_scan.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform_scan.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/type_traits.h" "$(@D)/cuda/include/thrust/system/detail/generic/type_traits.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_copy.inl" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/uninitialized_fill.inl" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_fill.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique.h" "$(@D)/cuda/include/thrust/system/detail/generic/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique.inl" "$(@D)/cuda/include/thrust/system/detail/generic/unique.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/generic/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/unique_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/internal/decompose.h" "$(@D)/cuda/include/thrust/system/detail/internal/decompose.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/sequential/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/assign_value.h" "$(@D)/cuda/include/thrust/system/detail/sequential/assign_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/sequential/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy_backward.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy_backward.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/count.h" "$(@D)/cuda/include/thrust/system/detail/sequential/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/equal.h" "$(@D)/cuda/include/thrust/system/detail/sequential/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/execution_policy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/extrema.h" "$(@D)/cuda/include/thrust/system/detail/sequential/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/fill.h" "$(@D)/cuda/include/thrust/system/detail/sequential/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/find.h" "$(@D)/cuda/include/thrust/system/detail/sequential/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/for_each.h" "$(@D)/cuda/include/thrust/system/detail/sequential/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/gather.h" "$(@D)/cuda/include/thrust/system/detail/sequential/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/general_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/general_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/generate.h" "$(@D)/cuda/include/thrust/system/detail/sequential/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/get_value.h" "$(@D)/cuda/include/thrust/system/detail/sequential/get_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/sequential/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/insertion_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/insertion_sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/iter_swap.h" "$(@D)/cuda/include/thrust/system/detail/sequential/iter_swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/logical.h" "$(@D)/cuda/include/thrust/system/detail/sequential/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/detail/sequential/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/merge.h" "$(@D)/cuda/include/thrust/system/detail/sequential/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/merge.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/merge.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/sequential/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/partition.h" "$(@D)/cuda/include/thrust/system/detail/sequential/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/reduce.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/remove.h" "$(@D)/cuda/include/thrust/system/detail/sequential/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/replace.h" "$(@D)/cuda/include/thrust/system/detail/sequential/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/reverse.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/scan.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/scatter.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/sequence.h" "$(@D)/cuda/include/thrust/system/detail/sequential/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/sequential/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_merge_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_merge_sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_merge_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_merge_sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_primitive_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_primitive_sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_primitive_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_primitive_sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_radix_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_radix_sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/stable_radix_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_radix_sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/sequential/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/sequential/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/sequential/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/transform.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/trivial_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/trivial_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/sequential/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/unique.h" "$(@D)/cuda/include/thrust/system/detail/sequential/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/sequential/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/detail/system_error.inl" "$(@D)/cuda/include/thrust/system/detail/system_error.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/error_code.h" "$(@D)/cuda/include/thrust/system/error_code.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/omp/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/omp/detail/assign_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/omp/detail/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy.h" "$(@D)/cuda/include/thrust/system/omp/detail/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy.inl" "$(@D)/cuda/include/thrust/system/omp/detail/copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/omp/detail/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/copy_if.inl" "$(@D)/cuda/include/thrust/system/omp/detail/copy_if.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/count.h" "$(@D)/cuda/include/thrust/system/omp/detail/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/default_decomposition.h" "$(@D)/cuda/include/thrust/system/omp/detail/default_decomposition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/default_decomposition.inl" "$(@D)/cuda/include/thrust/system/omp/detail/default_decomposition.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/equal.h" "$(@D)/cuda/include/thrust/system/omp/detail/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/omp/detail/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/extrema.h" "$(@D)/cuda/include/thrust/system/omp/detail/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/fill.h" "$(@D)/cuda/include/thrust/system/omp/detail/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/find.h" "$(@D)/cuda/include/thrust/system/omp/detail/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/for_each.h" "$(@D)/cuda/include/thrust/system/omp/detail/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/for_each.inl" "$(@D)/cuda/include/thrust/system/omp/detail/for_each.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/gather.h" "$(@D)/cuda/include/thrust/system/omp/detail/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/generate.h" "$(@D)/cuda/include/thrust/system/omp/detail/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/get_value.h" "$(@D)/cuda/include/thrust/system/omp/detail/get_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/omp/detail/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/omp/detail/iter_swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/logical.h" "$(@D)/cuda/include/thrust/system/omp/detail/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/omp/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/memory.inl" "$(@D)/cuda/include/thrust/system/omp/detail/memory.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/merge.h" "$(@D)/cuda/include/thrust/system/omp/detail/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/omp/detail/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/par.h" "$(@D)/cuda/include/thrust/system/omp/detail/par.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/partition.h" "$(@D)/cuda/include/thrust/system/omp/detail/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/partition.inl" "$(@D)/cuda/include/thrust/system/omp/detail/partition.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_intervals.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_intervals.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reduce_intervals.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_intervals.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/remove.h" "$(@D)/cuda/include/thrust/system/omp/detail/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/remove.inl" "$(@D)/cuda/include/thrust/system/omp/detail/remove.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/replace.h" "$(@D)/cuda/include/thrust/system/omp/detail/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/reverse.h" "$(@D)/cuda/include/thrust/system/omp/detail/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/scan.h" "$(@D)/cuda/include/thrust/system/omp/detail/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/scatter.h" "$(@D)/cuda/include/thrust/system/omp/detail/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/sequence.h" "$(@D)/cuda/include/thrust/system/omp/detail/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/omp/detail/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/sort.h" "$(@D)/cuda/include/thrust/system/omp/detail/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/sort.inl" "$(@D)/cuda/include/thrust/system/omp/detail/sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/omp/detail/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/omp/detail/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/omp/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/transform.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/omp/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/omp/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique.h" "$(@D)/cuda/include/thrust/system/omp/detail/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique.inl" "$(@D)/cuda/include/thrust/system/omp/detail/unique.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/omp/detail/unique_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/detail/vector.inl" "$(@D)/cuda/include/thrust/system/omp/detail/vector.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/execution_policy.h" "$(@D)/cuda/include/thrust/system/omp/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/memory.h" "$(@D)/cuda/include/thrust/system/omp/memory.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/omp/vector.h" "$(@D)/cuda/include/thrust/system/omp/vector.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/system_error.h" "$(@D)/cuda/include/thrust/system/system_error.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/tbb/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/tbb/detail/assign_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/tbb/detail/binary_search.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/copy.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/tbb/detail/copy_if.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/copy_if.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/copy_if.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/count.h" "$(@D)/cuda/include/thrust/system/tbb/detail/count.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/equal.h" "$(@D)/cuda/include/thrust/system/tbb/detail/equal.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/extrema.h" "$(@D)/cuda/include/thrust/system/tbb/detail/extrema.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/fill.h" "$(@D)/cuda/include/thrust/system/tbb/detail/fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/find.h" "$(@D)/cuda/include/thrust/system/tbb/detail/find.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/for_each.h" "$(@D)/cuda/include/thrust/system/tbb/detail/for_each.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/for_each.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/for_each.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/gather.h" "$(@D)/cuda/include/thrust/system/tbb/detail/gather.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/generate.h" "$(@D)/cuda/include/thrust/system/tbb/detail/generate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/get_value.h" "$(@D)/cuda/include/thrust/system/tbb/detail/get_value.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/tbb/detail/inner_product.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/tbb/detail/iter_swap.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/logical.h" "$(@D)/cuda/include/thrust/system/tbb/detail/logical.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/tbb/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/memory.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/memory.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/merge.h" "$(@D)/cuda/include/thrust/system/tbb/detail/merge.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/merge.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/merge.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/tbb/detail/mismatch.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/par.h" "$(@D)/cuda/include/thrust/system/tbb/detail/par.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/partition.h" "$(@D)/cuda/include/thrust/system/tbb/detail/partition.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/partition.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/partition.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reduce_intervals.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_intervals.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/remove.h" "$(@D)/cuda/include/thrust/system/tbb/detail/remove.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/remove.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/remove.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/replace.h" "$(@D)/cuda/include/thrust/system/tbb/detail/replace.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/reverse.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reverse.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scan.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scan.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/scan.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scan_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/scatter.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scatter.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/sequence.h" "$(@D)/cuda/include/thrust/system/tbb/detail/sequence.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/tbb/detail/set_operations.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/sort.h" "$(@D)/cuda/include/thrust/system/tbb/detail/sort.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/sort.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/sort.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/tbb/detail/swap_ranges.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/tbb/detail/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/tbb/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/transform.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/tbb/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique.h" "$(@D)/cuda/include/thrust/system/tbb/detail/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/unique.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/unique_by_key.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/unique_by_key.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/detail/vector.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/vector.inl" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/execution_policy.h" "$(@D)/cuda/include/thrust/system/tbb/execution_policy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/memory.h" "$(@D)/cuda/include/thrust/system/tbb/memory.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system/tbb/vector.h" "$(@D)/cuda/include/thrust/system/tbb/vector.h" && cp -f "/usr/local/cuda-9.0/include/thrust/system_error.h" "$(@D)/cuda/include/thrust/system_error.h" && cp -f "/usr/local/cuda-9.0/include/thrust/tabulate.h" "$(@D)/cuda/include/thrust/tabulate.h" && cp -f "/usr/local/cuda-9.0/include/thrust/transform.h" "$(@D)/cuda/include/thrust/transform.h" && cp -f "/usr/local/cuda-9.0/include/thrust/transform_reduce.h" "$(@D)/cuda/include/thrust/transform_reduce.h" && cp -f "/usr/local/cuda-9.0/include/thrust/transform_scan.h" "$(@D)/cuda/include/thrust/transform_scan.h" && cp -f "/usr/local/cuda-9.0/include/thrust/tuple.h" "$(@D)/cuda/include/thrust/tuple.h" && cp -f "/usr/local/cuda-9.0/include/thrust/uninitialized_copy.h" "$(@D)/cuda/include/thrust/uninitialized_copy.h" && cp -f "/usr/local/cuda-9.0/include/thrust/uninitialized_fill.h" "$(@D)/cuda/include/thrust/uninitialized_fill.h" && cp -f "/usr/local/cuda-9.0/include/thrust/unique.h" "$(@D)/cuda/include/thrust/unique.h" && cp -f "/usr/local/cuda-9.0/include/thrust/version.h" "$(@D)/cuda/include/thrust/version.h" && cp -f "/usr/local/cuda-9.0/include/vector_functions.h" "$(@D)/cuda/include/vector_functions.h" && cp -f "/usr/local/cuda-9.0/include/vector_functions.hpp" "$(@D)/cuda/include/vector_functions.hpp" && cp -f "/usr/local/cuda-9.0/include/vector_types.h" "$(@D)/cuda/include/vector_types.h" """, ) @@ -1198,7 +1198,7 @@ genrule( "cuda/nvvm/libdevice/libdevice.10.bc", ], cmd = """ -if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp "/usr/local/cuda-9.0/nvvm/libdevice/libdevice.10.bc" "$(@D)//libdevice.10.bc" +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-9.0/nvvm/libdevice/libdevice.10.bc" "$(@D)//libdevice.10.bc" """, ) @@ -1235,7 +1235,7 @@ genrule( "cuda/extras/CUPTI/include/openacc/cupti_openacc.h", ], cmd = """ -if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/gl.h" "$(@D)/cuda/extras/CUPTI/include/GL/gl.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glew.h" "$(@D)/cuda/extras/CUPTI/include/GL/glew.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glext.h" "$(@D)/cuda/extras/CUPTI/include/GL/glext.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glu.h" "$(@D)/cuda/extras/CUPTI/include/GL/glu.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glut.h" "$(@D)/cuda/extras/CUPTI/include/GL/glut.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glx.h" "$(@D)/cuda/extras/CUPTI/include/GL/glx.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glxext.h" "$(@D)/cuda/extras/CUPTI/include/GL/glxext.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/wglew.h" "$(@D)/cuda/extras/CUPTI/include/GL/wglew.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/GL/wglext.h" "$(@D)/cuda/extras/CUPTI/include/GL/wglext.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cuda_stdint.h" "$(@D)/cuda/extras/CUPTI/include/cuda_stdint.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti.h" "$(@D)/cuda/extras/CUPTI/include/cupti.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_activity.h" "$(@D)/cuda/extras/CUPTI/include/cupti_activity.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_callbacks.h" "$(@D)/cuda/extras/CUPTI/include/cupti_callbacks.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_driver_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_driver_cbid.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_events.h" "$(@D)/cuda/extras/CUPTI/include/cupti_events.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_metrics.h" "$(@D)/cuda/extras/CUPTI/include/cupti_metrics.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_nvtx_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_nvtx_cbid.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_result.h" "$(@D)/cuda/extras/CUPTI/include/cupti_result.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_runtime_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_runtime_cbid.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_version.h" "$(@D)/cuda/extras/CUPTI/include/cupti_version.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cudaGL_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cudaGL_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cudaVDPAU_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cudaVDPAU_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_gl_interop_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_gl_interop_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_runtime_api_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_runtime_api_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/generated_nvtx_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_nvtx_meta.h" && cp "/usr/local/cuda-9.0/extras/CUPTI/include/openacc/cupti_openacc.h" "$(@D)/cuda/extras/CUPTI/include/openacc/cupti_openacc.h" +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/gl.h" "$(@D)/cuda/extras/CUPTI/include/GL/gl.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glew.h" "$(@D)/cuda/extras/CUPTI/include/GL/glew.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glext.h" "$(@D)/cuda/extras/CUPTI/include/GL/glext.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glu.h" "$(@D)/cuda/extras/CUPTI/include/GL/glu.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glut.h" "$(@D)/cuda/extras/CUPTI/include/GL/glut.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glx.h" "$(@D)/cuda/extras/CUPTI/include/GL/glx.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/glxext.h" "$(@D)/cuda/extras/CUPTI/include/GL/glxext.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/wglew.h" "$(@D)/cuda/extras/CUPTI/include/GL/wglew.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/GL/wglext.h" "$(@D)/cuda/extras/CUPTI/include/GL/wglext.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cuda_stdint.h" "$(@D)/cuda/extras/CUPTI/include/cuda_stdint.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti.h" "$(@D)/cuda/extras/CUPTI/include/cupti.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_activity.h" "$(@D)/cuda/extras/CUPTI/include/cupti_activity.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_callbacks.h" "$(@D)/cuda/extras/CUPTI/include/cupti_callbacks.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_driver_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_driver_cbid.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_events.h" "$(@D)/cuda/extras/CUPTI/include/cupti_events.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_metrics.h" "$(@D)/cuda/extras/CUPTI/include/cupti_metrics.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_nvtx_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_nvtx_cbid.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_result.h" "$(@D)/cuda/extras/CUPTI/include/cupti_result.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_runtime_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_runtime_cbid.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/cupti_version.h" "$(@D)/cuda/extras/CUPTI/include/cupti_version.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cudaGL_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cudaGL_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cudaVDPAU_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cudaVDPAU_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_gl_interop_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_gl_interop_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_runtime_api_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_runtime_api_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/generated_nvtx_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_nvtx_meta.h" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/include/openacc/cupti_openacc.h" "$(@D)/cuda/extras/CUPTI/include/openacc/cupti_openacc.h" """, ) @@ -1253,7 +1253,7 @@ genrule( "cuda/lib/libcupti.so.9.0", ], cmd = """ -if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/stubs/libcuda.so" "$(@D)/cuda/lib/libcuda.so" && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcudart.so.9.0.176" "$(@D)/cuda/lib/libcudart.so.9.0" && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcudart_static.a" "$(@D)/cuda/lib/libcudart_static.a" && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcublas.so.9.0.480" "$(@D)/cuda/lib/libcublas.so.9.0" && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcusolver.so.9.0.176" "$(@D)/cuda/lib/libcusolver.so.9.0" && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcurand.so.9.0.176" "$(@D)/cuda/lib/libcurand.so.9.0" && cp "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcufft.so.9.0.176" "$(@D)/cuda/lib/libcufft.so.9.0" && cp "/usr/lib/x86_64-linux-gnu/libcudnn.so.7.1.4" "$(@D)/cuda/lib/libcudnn.so.7" && cp "/usr/local/cuda/extras/CUPTI/lib64/libcupti.so.9.0.176" "$(@D)/cuda/lib/libcupti.so.9.0" +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/stubs/libcuda.so" "$(@D)/cuda/lib/libcuda.so" && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcudart.so.9.0.176" "$(@D)/cuda/lib/libcudart.so.9.0" && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcudart_static.a" "$(@D)/cuda/lib/libcudart_static.a" && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcublas.so.9.0.480" "$(@D)/cuda/lib/libcublas.so.9.0" && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcusolver.so.9.0.176" "$(@D)/cuda/lib/libcusolver.so.9.0" && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcurand.so.9.0.176" "$(@D)/cuda/lib/libcurand.so.9.0" && cp -f "/usr/local/cuda-9.0/targets/x86_64-linux/lib/libcufft.so.9.0.176" "$(@D)/cuda/lib/libcufft.so.9.0" && cp -f "/usr/lib/x86_64-linux-gnu/libcudnn.so.7.1.4" "$(@D)/cuda/lib/libcudnn.so.7" && cp -f "/usr/local/cuda-9.0/extras/CUPTI/lib64/libcupti.so.9.0.176" "$(@D)/cuda/lib/libcupti.so.9.0" """, ) @@ -1263,6 +1263,6 @@ genrule( "cuda/include/cudnn.h", ], cmd = """ -if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp "/usr/include/cudnn.h" "$(@D)/cudnn.h" +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/include/cudnn.h" "$(@D)/cudnn.h" """, ) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/build_defs.bzl b/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/build_defs.bzl index 5c6703aab4..a53c891d8b 100755 --- a/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/build_defs.bzl +++ b/third_party/toolchains/preconfig/ubuntu14.04/cuda9.0-cudnn7/cuda/build_defs.bzl @@ -9,15 +9,13 @@ def if_cuda(if_true, if_false = []): return select({ "@local_config_cuda//cuda:using_nvcc": if_true, "@local_config_cuda//cuda:using_clang": if_true, - "//conditions:default": if_false + "//conditions:default": if_false, }) - def cuda_default_copts(): """Default options for all CUDA compilations.""" return if_cuda(["-x", "cuda", "-DGOOGLE_CUDA=1"] + []) - def cuda_is_configured(): """Returns true if CUDA was enabled during the configure process.""" return True @@ -29,5 +27,5 @@ def if_cuda_is_configured(x): --config=cuda. Used to allow non-CUDA code to depend on CUDA libraries. """ if cuda_is_configured(): - return x + return x return [] diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/BUILD b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/BUILD new file mode 100755 index 0000000000..6442e7628a --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/BUILD @@ -0,0 +1,87 @@ +licenses(["restricted"]) + +package(default_visibility = ["//visibility:public"]) + +toolchain( + name = "toolchain-linux-x86_64", + exec_compatible_with = [ + "@bazel_tools//platforms:linux", + "@bazel_tools//platforms:x86_64", + ], + target_compatible_with = [ + "@bazel_tools//platforms:linux", + "@bazel_tools//platforms:x86_64", + ], + toolchain = ":cc-compiler-local", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain_suite( + name = "toolchain", + toolchains = { + "local|compiler": ":cc-compiler-local", + "darwin|compiler": ":cc-compiler-darwin", + "x64_windows|msvc-cl": ":cc-compiler-windows", + }, +) + +cc_toolchain( + name = "cc-compiler-local", + all_files = ":crosstool_wrapper_driver_is_not_gcc", + compiler_files = ":empty", + cpu = "local", + dwp_files = ":empty", + dynamic_runtime_libs = [":empty"], + linker_files = ":crosstool_wrapper_driver_is_not_gcc", + objcopy_files = ":empty", + static_runtime_libs = [":empty"], + strip_files = ":empty", + # To support linker flags that need to go to the start of command line + # we need the toolchain to support parameter files. Parameter files are + # last on the command line and contain all shared libraries to link, so all + # regular options will be left of them. + supports_param_files = 1, +) + +cc_toolchain( + name = "cc-compiler-darwin", + all_files = ":crosstool_wrapper_driver_is_not_gcc", + compiler_files = ":empty", + cpu = "darwin", + dwp_files = ":empty", + dynamic_runtime_libs = [":empty"], + linker_files = ":crosstool_wrapper_driver_is_not_gcc", + objcopy_files = ":empty", + static_runtime_libs = [":empty"], + strip_files = ":empty", + supports_param_files = 0, +) + +cc_toolchain( + name = "cc-compiler-windows", + all_files = ":windows_msvc_wrapper_files", + compiler_files = ":empty", + cpu = "x64_windows", + dwp_files = ":empty", + dynamic_runtime_libs = [":empty"], + linker_files = ":windows_msvc_wrapper_files", + objcopy_files = ":empty", + static_runtime_libs = [":empty"], + strip_files = ":empty", + supports_param_files = 1, +) + +filegroup( + name = "empty", + srcs = [], +) + +filegroup( + name = "crosstool_wrapper_driver_is_not_gcc", + srcs = ["clang/bin/crosstool_wrapper_driver_is_not_gcc"], +) + +filegroup( + name = "windows_msvc_wrapper_files", + srcs = glob(["windows/msvc_*"]), +) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/CROSSTOOL b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/CROSSTOOL new file mode 100755 index 0000000000..0d89a539b8 --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/CROSSTOOL @@ -0,0 +1,1431 @@ +major_version: "local" +minor_version: "" +default_target_cpu: "same_as_host" + +default_toolchain { + cpu: "k8" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "piii" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "arm" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "darwin" + toolchain_identifier: "local_darwin" +} +default_toolchain { + cpu: "ppc" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "x64_windows" + toolchain_identifier: "local_windows" +} + +toolchain { + abi_version: "local" + abi_libc_version: "local" + compiler: "compiler" + host_system_name: "local" + needsPic: true + target_libc: "local" + target_cpu: "local" + target_system_name: "local" + toolchain_identifier: "local_linux" + + feature { + name: "c++11" + flag_set { + action: "c++-compile" + flag_group { + flag: "-std=c++11" + } + } + } + + feature { + name: "stdlib" + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-lstdc++" + } + } + } + + feature { + name: "determinism" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + flag: "-Wno-builtin-macro-redefined" + flag: "-D__DATE__=\"redacted\"" + flag: "-D__TIMESTAMP__=\"redacted\"" + flag: "-D__TIME__=\"redacted\"" + } + } + } + + feature { + name: "alwayslink" + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-Wl,-no-as-needed" + } + } + } + + # This feature will be enabled for builds that support pic by bazel. + feature { + name: "pic" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + expand_if_all_available: "pic" + flag: "-fPIC" + } + flag_group { + expand_if_none_available: "pic" + flag: "-fPIE" + } + } + } + + # Security hardening on by default. + feature { + name: "hardening" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now + # have it enabled by default. + flag: "-U_FORTIFY_SOURCE" + flag: "-D_FORTIFY_SOURCE=1" + flag: "-fstack-protector" + } + } + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-Wl,-z,relro,-z,now" + } + } + flag_set { + action: "c++-link-executable" + flag_group { + flag: "-pie" + flag: "-Wl,-z,relro,-z,now" + } + } + } + + feature { + name: "warnings" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # All warnings are enabled. Maybe enable -Werror as well? + flag: "-Wall" + + } + } + } + + # Keep stack frames for debugging, even in opt mode. + feature { + name: "frame-pointer" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-fno-omit-frame-pointer" + } + } + } + + feature { + name: "build-id" + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + # Stamp the binary with a unique identifier. + flag: "-Wl,--build-id=md5" + flag: "-Wl,--hash-style=gnu" + } + } + } + + feature { + name: "no-canonical-prefixes" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-no-canonical-prefixes" + flag: "-fno-canonical-system-headers" + } + } + } + + feature { + name: "disable-assertions" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-DNDEBUG" + } + } + } + + feature { + name: "linker-bin-path" + + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-B/usr/bin" + } + } + } + + feature { + name: "common" + implies: "stdlib" + implies: "c++11" + implies: "determinism" + implies: "alwayslink" + implies: "hardening" + implies: "warnings" + implies: "frame-pointer" + implies: "build-id" + implies: "no-canonical-prefixes" + implies: "linker-bin-path" + } + + feature { + name: "opt" + implies: "common" + implies: "disable-assertions" + + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # No debug symbols. + # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt + # or even generally? However, that can't happen here, as it requires + # special handling in Bazel. + flag: "-g0" + + # Conservative choice for -O + # -O3 can increase binary size and even slow down the resulting binaries. + # Profile first and / or use FDO if you need better performance than this. + flag: "-O2" + + # Removal of unused code and data at link time (can this increase binary size in some cases?). + flag: "-ffunction-sections" + flag: "-fdata-sections" + } + } + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-Wl,--gc-sections" + } + } + } + + feature { + name: "fastbuild" + implies: "common" + } + + feature { + name: "dbg" + implies: "common" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-g" + } + } + } + + # Set clang as a C/C++ compiler. + tool_path { name: "gcc" path: "clang/bin/crosstool_wrapper_driver_is_not_gcc" } + + # Use the default system toolchain for everything else. + tool_path { name: "ar" path: "/usr/bin/ar" } + tool_path { name: "compat-ld" path: "/usr/bin/ld" } + tool_path { name: "cpp" path: "/usr/bin/cpp" } + tool_path { name: "dwp" path: "/usr/bin/dwp" } + tool_path { name: "gcov" path: "/usr/bin/gcov" } + tool_path { name: "ld" path: "/usr/bin/ld" } + tool_path { name: "nm" path: "/usr/bin/nm" } + tool_path { name: "objcopy" path: "/usr/bin/objcopy" } + tool_path { name: "objdump" path: "/usr/bin/objdump" } + tool_path { name: "strip" path: "/usr/bin/strip" } + + # Enabled dynamic linking. + linking_mode_flags { mode: DYNAMIC } + + cxx_builtin_include_directory: "/usr/include/c++/4.8" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu/c++/4.8" + cxx_builtin_include_directory: "/usr/include/c++/4.8/backward" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include" + cxx_builtin_include_directory: "/usr/local/include" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu" + cxx_builtin_include_directory: "/usr/include" + cxx_builtin_include_directory: "/usr/local/cuda-9.0/targets/x86_64-linux/include" + cxx_builtin_include_directory: "/usr/local/cuda-9.0/include" + cxx_builtin_include_directory: "/usr/local/cuda-9.0/extras/CUPTI/include" + cxx_builtin_include_directory: "/usr/include" +} + +toolchain { + abi_version: "local" + abi_libc_version: "local" + compiler: "compiler" + host_system_name: "local" + needsPic: true + target_libc: "macosx" + target_cpu: "darwin" + target_system_name: "local" + toolchain_identifier: "local_darwin" + feature { + name: "c++11" + flag_set { + action: "c++-compile" + flag_group { + flag: "-std=c++11" + } + } + } + + feature { + name: "stdlib" + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-lc++" + } + } + } + + feature { + name: "determinism" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + flag: "-Wno-builtin-macro-redefined" + flag: "-D__DATE__=\"redacted\"" + flag: "-D__TIMESTAMP__=\"redacted\"" + flag: "-D__TIME__=\"redacted\"" + } + } + } + + # This feature will be enabled for builds that support pic by bazel. + feature { + name: "pic" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + expand_if_all_available: "pic" + flag: "-fPIC" + } + flag_group { + expand_if_none_available: "pic" + flag: "-fPIE" + } + } + } + + # Security hardening on by default. + feature { + name: "hardening" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now + # have it enabled by default. + flag: "-U_FORTIFY_SOURCE" + flag: "-D_FORTIFY_SOURCE=1" + flag: "-fstack-protector" + } + } + flag_set { + action: "c++-link-executable" + flag_group { + flag: "-pie" + } + } + } + + feature { + name: "warnings" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # All warnings are enabled. Maybe enable -Werror as well? + flag: "-Wall" + + } + } + } + + # Keep stack frames for debugging, even in opt mode. + feature { + name: "frame-pointer" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-fno-omit-frame-pointer" + } + } + } + + feature { + name: "no-canonical-prefixes" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag:"-no-canonical-prefixes" + } + } + } + + feature { + name: "disable-assertions" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-DNDEBUG" + } + } + } + + feature { + name: "linker-bin-path" + + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-B/usr/bin" + } + } + } + + feature { + name: "undefined-dynamic" + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-undefined" + flag: "dynamic_lookup" + } + } + } + + feature { + name: "common" + implies: "stdlib" + implies: "c++11" + implies: "determinism" + implies: "hardening" + implies: "warnings" + implies: "frame-pointer" + implies: "no-canonical-prefixes" + implies: "linker-bin-path" + implies: "undefined-dynamic" + } + + feature { + name: "opt" + implies: "common" + implies: "disable-assertions" + + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # No debug symbols. + # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt + # or even generally? However, that can't happen here, as it requires + # special handling in Bazel. + flag: "-g0" + + # Conservative choice for -O + # -O3 can increase binary size and even slow down the resulting binaries. + # Profile first and / or use FDO if you need better performance than this. + flag: "-O2" + + # Removal of unused code and data at link time (can this increase binary size in some cases?). + flag: "-ffunction-sections" + flag: "-fdata-sections" + } + } + } + + feature { + name: "fastbuild" + implies: "common" + } + + feature { + name: "dbg" + implies: "common" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-g" + } + } + } + + # Set clang as a C/C++ compiler. + tool_path { name: "gcc" path: "clang/bin/crosstool_wrapper_driver_is_not_gcc" } + + # Use the default system toolchain for everything else. + tool_path { name: "ar" path: "/usr/bin/libtool" } + tool_path { name: "compat-ld" path: "/usr/bin/ld" } + tool_path { name: "cpp" path: "/usr/bin/cpp" } + tool_path { name: "dwp" path: "/usr/bin/dwp" } + tool_path { name: "gcov" path: "/usr/bin/gcov" } + tool_path { name: "ld" path: "/usr/bin/ld" } + tool_path { name: "nm" path: "/usr/bin/nm" } + tool_path { name: "objcopy" path: "/usr/bin/objcopy" } + tool_path { name: "objdump" path: "/usr/bin/objdump" } + tool_path { name: "strip" path: "/usr/bin/strip" } + + # Enabled dynamic linking. + linking_mode_flags { mode: DYNAMIC } + + cxx_builtin_include_directory: "/usr/include/c++/4.8" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu/c++/4.8" + cxx_builtin_include_directory: "/usr/include/c++/4.8/backward" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include" + cxx_builtin_include_directory: "/usr/local/include" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu" + cxx_builtin_include_directory: "/usr/include" + cxx_builtin_include_directory: "/usr/local/cuda-9.0/targets/x86_64-linux/include" + cxx_builtin_include_directory: "/usr/local/cuda-9.0/include" + cxx_builtin_include_directory: "/usr/local/cuda-9.0/extras/CUPTI/include" + cxx_builtin_include_directory: "/usr/include" +} + +toolchain { + toolchain_identifier: "local_windows" + host_system_name: "local" + target_system_name: "local" + + abi_version: "local" + abi_libc_version: "local" + target_cpu: "x64_windows" + compiler: "msvc-cl" + target_libc: "msvcrt" + + + + tool_path { + name: "ar" + path: "" + } + tool_path { + name: "ml" + path: "" + } + tool_path { + name: "cpp" + path: "" + } + tool_path { + name: "gcc" + path: "" + } + tool_path { + name: "gcov" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "ld" + path: "" + } + tool_path { + name: "nm" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "objcopy" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "objdump" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "strip" + path: "wrapper/bin/msvc_nop.bat" + } + supports_interface_shared_objects: true + + # TODO(pcloudy): Review those flags below, they should be defined by cl.exe + compiler_flag: "/DCOMPILER_MSVC" + + # Don't define min/max macros in windows.h. + compiler_flag: "/DNOMINMAX" + + # Platform defines. + compiler_flag: "/D_WIN32_WINNT=0x0600" + # Turn off warning messages. + compiler_flag: "/D_CRT_SECURE_NO_DEPRECATE" + compiler_flag: "/D_CRT_SECURE_NO_WARNINGS" + compiler_flag: "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS" + + # Useful options to have on for compilation. + # Increase the capacity of object files to 2^32 sections. + compiler_flag: "/bigobj" + # Allocate 500MB for precomputed headers. + compiler_flag: "/Zm500" + # Use unsigned char by default. + compiler_flag: "/J" + # Use function level linking. + compiler_flag: "/Gy" + # Use string pooling. + compiler_flag: "/GF" + # Catch C++ exceptions only and tell the compiler to assume that functions declared + # as extern "C" never throw a C++ exception. + compiler_flag: "/EHsc" + + # Globally disabled warnings. + # Don't warn about elements of array being be default initialized. + compiler_flag: "/wd4351" + # Don't warn about no matching delete found. + compiler_flag: "/wd4291" + # Don't warn about diamond inheritance patterns. + compiler_flag: "/wd4250" + # Don't warn about insecure functions (e.g. non _s functions). + compiler_flag: "/wd4996" + + linker_flag: "/MACHINE:X64" + + feature { + name: "no_legacy_features" + } + + # Suppress startup banner. + feature { + name: "nologo" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "c++-header-parsing" + action: "assemble" + action: "preprocess-assemble" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-static-library" + flag_group { + flag: "/nologo" + } + } + } + + feature { + name: 'has_configured_linker_path' + } + + # This feature indicates strip is not supported, building stripped binary will just result a copy of orignial binary + feature { + name: 'no_stripping' + } + + # This feature indicates this is a toolchain targeting Windows. + feature { + name: 'targets_windows' + implies: 'copy_dynamic_libraries_to_binary' + enabled: true + } + + feature { + name: 'copy_dynamic_libraries_to_binary' + } + + action_config { + config_name: 'assemble' + action_name: 'assemble' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'sysroot' + } + + action_config { + config_name: 'preprocess-assemble' + action_name: 'preprocess-assemble' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'sysroot' + } + + action_config { + config_name: 'c-compile' + action_name: 'c-compile' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'legacy_compile_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'parse_showincludes' + implies: 'user_compile_flags' + implies: 'sysroot' + implies: 'unfiltered_compile_flags' + } + + action_config { + config_name: 'c++-compile' + action_name: 'c++-compile' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'legacy_compile_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'parse_showincludes' + implies: 'user_compile_flags' + implies: 'sysroot' + implies: 'unfiltered_compile_flags' + } + + action_config { + config_name: 'c++-link-executable' + action_name: 'c++-link-executable' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'user_link_flags' + implies: 'legacy_link_flags' + implies: 'linker_subsystem_flag' + implies: 'linker_param_file' + implies: 'msvc_env' + implies: 'no_stripping' + } + + action_config { + config_name: 'c++-link-dynamic-library' + action_name: 'c++-link-dynamic-library' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'shared_flag' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'user_link_flags' + implies: 'legacy_link_flags' + implies: 'linker_subsystem_flag' + implies: 'linker_param_file' + implies: 'msvc_env' + implies: 'no_stripping' + implies: 'has_configured_linker_path' + implies: 'def_file' + } + + action_config { + config_name: 'c++-link-nodeps-dynamic-library' + action_name: 'c++-link-nodeps-dynamic-library' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'shared_flag' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'user_link_flags' + implies: 'legacy_link_flags' + implies: 'linker_subsystem_flag' + implies: 'linker_param_file' + implies: 'msvc_env' + implies: 'no_stripping' + implies: 'has_configured_linker_path' + implies: 'def_file' + } + + action_config { + config_name: 'c++-link-static-library' + action_name: 'c++-link-static-library' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'archiver_flags' + implies: 'input_param_flags' + implies: 'linker_param_file' + implies: 'msvc_env' + } + + # TODO(b/65151735): Remove legacy_compile_flags feature when legacy fields are + # not used in this crosstool + feature { + name: 'legacy_compile_flags' + flag_set { + expand_if_all_available: 'legacy_compile_flags' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + iterate_over: 'legacy_compile_flags' + flag: '%{legacy_compile_flags}' + } + } + } + + feature { + name: "msvc_env" + env_set { + action: "c-compile" + action: "c++-compile" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "c++-header-parsing" + action: "assemble" + action: "preprocess-assemble" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-static-library" + env_entry { + key: "PATH" + value: "" + } + env_entry { + key: "INCLUDE" + value: "" + } + env_entry { + key: "LIB" + value: "" + } + env_entry { + key: "TMP" + value: "" + } + env_entry { + key: "TEMP" + value: "" + } + } + } + + feature { + name: 'include_paths' + flag_set { + action: "assemble" + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + flag_group { + iterate_over: 'quote_include_paths' + flag: '/I%{quote_include_paths}' + } + flag_group { + iterate_over: 'include_paths' + flag: '/I%{include_paths}' + } + flag_group { + iterate_over: 'system_include_paths' + flag: '/I%{system_include_paths}' + } + } + } + + feature { + name: "preprocessor_defines" + flag_set { + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-module-compile" + flag_group { + flag: "/D%{preprocessor_defines}" + iterate_over: "preprocessor_defines" + } + } + } + + # Tell Bazel to parse the output of /showIncludes + feature { + name: 'parse_showincludes' + flag_set { + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-module-compile' + action: 'c++-header-parsing' + flag_group { + flag: "/showIncludes" + } + } + } + + + feature { + name: 'generate_pdb_file' + requires: { + feature: 'dbg' + } + requires: { + feature: 'fastbuild' + } + } + + feature { + name: 'shared_flag' + flag_set { + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: '/DLL' + } + } + } + + feature { + name: 'linkstamps' + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + expand_if_all_available: 'linkstamp_paths' + flag_group { + iterate_over: 'linkstamp_paths' + flag: '%{linkstamp_paths}' + } + } + } + + feature { + name: 'output_execpath_flags' + flag_set { + expand_if_all_available: 'output_execpath' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: '/OUT:%{output_execpath}' + } + } + } + + feature { + name: 'archiver_flags' + flag_set { + expand_if_all_available: 'output_execpath' + action: 'c++-link-static-library' + flag_group { + flag: '/OUT:%{output_execpath}' + } + } + } + + feature { + name: 'input_param_flags' + flag_set { + expand_if_all_available: 'interface_library_output_path' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/IMPLIB:%{interface_library_output_path}" + } + } + flag_set { + expand_if_all_available: 'libopts' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'libopts' + flag: '%{libopts}' + } + } + flag_set { + expand_if_all_available: 'libraries_to_link' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + action: 'c++-link-static-library' + flag_group { + iterate_over: 'libraries_to_link' + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'object_file_group' + } + iterate_over: 'libraries_to_link.object_files' + flag_group { + flag: '%{libraries_to_link.object_files}' + } + } + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'object_file' + } + flag_group { + flag: '%{libraries_to_link.name}' + } + } + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'interface_library' + } + flag_group { + flag: '%{libraries_to_link.name}' + } + } + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'static_library' + } + flag_group { + expand_if_false: 'libraries_to_link.is_whole_archive' + flag: '%{libraries_to_link.name}' + } + flag_group { + expand_if_true: 'libraries_to_link.is_whole_archive' + flag: '/WHOLEARCHIVE:%{libraries_to_link.name}' + } + } + } + } + } + + # Since this feature is declared earlier in the CROSSTOOL than + # "user_link_flags", this feature will be applied prior to it anwyhere they + # are both implied. And since "user_link_flags" contains the linkopts from + # the build rule, this allows the user to override the /SUBSYSTEM in the BUILD + # file. + feature { + name: 'linker_subsystem_flag' + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: '/SUBSYSTEM:CONSOLE' + } + } + } + + # The "user_link_flags" contains user-defined linkopts (from build rules) + # so it should be defined after features that declare user-overridable flags. + # For example the "linker_subsystem_flag" defines a default "/SUBSYSTEM" flag + # but we want to let the user override it, therefore "link_flag_subsystem" is + # defined earlier in the CROSSTOOL file than "user_link_flags". + feature { + name: 'user_link_flags' + flag_set { + expand_if_all_available: 'user_link_flags' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'user_link_flags' + flag: '%{user_link_flags}' + } + } + } + feature { + name: 'legacy_link_flags' + flag_set { + expand_if_all_available: 'legacy_link_flags' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'legacy_link_flags' + flag: '%{legacy_link_flags}' + } + } + } + + feature { + name: 'linker_param_file' + flag_set { + expand_if_all_available: 'linker_param_file' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + action: 'c++-link-static-library' + flag_group { + flag: '@%{linker_param_file}' + } + } + } + + feature { + name: 'static_link_msvcrt' + } + + feature { + name: 'static_link_msvcrt_no_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MT" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:libcmt.lib" + } + } + requires: { feature: 'fastbuild'} + requires: { feature: 'opt'} + } + + feature { + name: 'dynamic_link_msvcrt_no_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MD" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:msvcrt.lib" + } + } + requires: { feature: 'fastbuild'} + requires: { feature: 'opt'} + } + + feature { + name: 'static_link_msvcrt_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MTd" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:libcmtd.lib" + } + } + requires: { feature: 'dbg'} + } + + feature { + name: 'dynamic_link_msvcrt_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MDd" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:msvcrtd.lib" + } + } + requires: { feature: 'dbg'} + } + + feature { + name: 'dbg' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/Od" + flag: "/Z7" + flag: "/DDEBUG" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEBUG:FULL" + flag: "/INCREMENTAL:NO" + } + } + implies: 'generate_pdb_file' + } + + feature { + name: 'fastbuild' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/Od" + flag: "/Z7" + flag: "/DDEBUG" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEBUG:FASTLINK" + flag: "/INCREMENTAL:NO" + } + } + implies: 'generate_pdb_file' + } + + feature { + name: 'opt' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/O2" + flag: "/DNDEBUG" + } + } + } + + feature { + name: 'user_compile_flags' + flag_set { + expand_if_all_available: 'user_compile_flags' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + iterate_over: 'user_compile_flags' + flag: '%{user_compile_flags}' + } + } + } + + feature { + name: 'sysroot' + flag_set { + expand_if_all_available: 'sysroot' + action: 'assemble' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'sysroot' + flag: '--sysroot=%{sysroot}' + } + } + } + + feature { + name: 'unfiltered_compile_flags' + flag_set { + expand_if_all_available: 'unfiltered_compile_flags' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + iterate_over: 'unfiltered_compile_flags' + flag: '%{unfiltered_compile_flags}' + } + } + } + + feature { + name: 'compiler_output_flags' + flag_set { + action: 'assemble' + flag_group { + expand_if_all_available: 'output_file' + expand_if_none_available: 'output_assembly_file' + expand_if_none_available: 'output_preprocess_file' + flag: '/Fo%{output_file}' + flag: '/Zi' + } + } + flag_set { + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + expand_if_all_available: 'output_file' + expand_if_none_available: 'output_assembly_file' + expand_if_none_available: 'output_preprocess_file' + flag: '/Fo%{output_file}' + } + flag_group { + expand_if_all_available: 'output_file' + expand_if_all_available: 'output_assembly_file' + flag: '/Fa%{output_file}' + } + flag_group { + expand_if_all_available: 'output_file' + expand_if_all_available: 'output_preprocess_file' + flag: '/P' + flag: '/Fi%{output_file}' + } + } + } + + feature { + name: 'compiler_input_flags' + flag_set { + action: 'assemble' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + expand_if_all_available: 'source_file' + flag: '/c' + flag: '%{source_file}' + } + } + } + + feature { + name : 'def_file', + flag_set { + expand_if_all_available: 'def_file_path' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEF:%{def_file_path}" + # We can specify a different DLL name in DEF file, /ignore:4070 suppresses + # the warning message about DLL name doesn't match the default one. + # See https://msdn.microsoft.com/en-us/library/sfkk2fz7.aspx + flag: "/ignore:4070" + } + } + } + + feature { + name: 'windows_export_all_symbols' + } + + feature { + name: 'no_windows_export_all_symbols' + } + + linking_mode_flags { mode: DYNAMIC } +} diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/clang/bin/crosstool_wrapper_driver_is_not_gcc b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/clang/bin/crosstool_wrapper_driver_is_not_gcc new file mode 100755 index 0000000000..63893d3722 --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/clang/bin/crosstool_wrapper_driver_is_not_gcc @@ -0,0 +1,264 @@ +#!/usr/bin/env python +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Crosstool wrapper for compiling CUDA programs. + +SYNOPSIS: + crosstool_wrapper_is_not_gcc [options passed in by cc_library() + or cc_binary() rule] + +DESCRIPTION: + This script is expected to be called by the cc_library() or cc_binary() bazel + rules. When the option "-x cuda" is present in the list of arguments passed + to this script, it invokes the nvcc CUDA compiler. Most arguments are passed + as is as a string to --compiler-options of nvcc. When "-x cuda" is not + present, this wrapper invokes hybrid_driver_is_not_gcc with the input + arguments as is. + +NOTES: + Changes to the contents of this file must be propagated from + //third_party/gpus/crosstool/crosstool_wrapper_is_not_gcc to + //third_party/gpus/crosstool/v*/*/clang/bin/crosstool_wrapper_is_not_gcc +""" + +from __future__ import print_function + +__author__ = 'keveman@google.com (Manjunath Kudlur)' + +from argparse import ArgumentParser +import os +import subprocess +import re +import sys +import pipes + +# Template values set by cuda_autoconf. +CPU_COMPILER = ('/usr/bin/gcc') +GCC_HOST_COMPILER_PATH = ('/usr/bin/gcc') + +NVCC_PATH = '/usr/local/cuda-9.0/bin/nvcc' +PREFIX_DIR = os.path.dirname(GCC_HOST_COMPILER_PATH) +NVCC_VERSION = '9.0' + +def Log(s): + print('gpus/crosstool: {0}'.format(s)) + + +def GetOptionValue(argv, option): + """Extract the list of values for option from the argv list. + + Args: + argv: A list of strings, possibly the argv passed to main(). + option: The option whose value to extract, without the leading '-'. + + Returns: + A list of values, either directly following the option, + (eg., -opt val1 val2) or values collected from multiple occurrences of + the option (eg., -opt val1 -opt val2). + """ + + parser = ArgumentParser() + parser.add_argument('-' + option, nargs='*', action='append') + args, _ = parser.parse_known_args(argv) + if not args or not vars(args)[option]: + return [] + else: + return sum(vars(args)[option], []) + + +def GetHostCompilerOptions(argv): + """Collect the -isystem, -iquote, and --sysroot option values from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + + Returns: + The string that can be used as the --compiler-options to nvcc. + """ + + parser = ArgumentParser() + parser.add_argument('-isystem', nargs='*', action='append') + parser.add_argument('-iquote', nargs='*', action='append') + parser.add_argument('--sysroot', nargs=1) + parser.add_argument('-g', nargs='*', action='append') + parser.add_argument('-fno-canonical-system-headers', action='store_true') + + args, _ = parser.parse_known_args(argv) + + opts = '' + + if args.isystem: + opts += ' -isystem ' + ' -isystem '.join(sum(args.isystem, [])) + if args.iquote: + opts += ' -iquote ' + ' -iquote '.join(sum(args.iquote, [])) + if args.g: + opts += ' -g' + ' -g'.join(sum(args.g, [])) + if args.fno_canonical_system_headers: + opts += ' -fno-canonical-system-headers' + if args.sysroot: + opts += ' --sysroot ' + args.sysroot[0] + + return opts + +def _update_options(nvcc_options): + if NVCC_VERSION in ("7.0",): + return nvcc_options + + update_options = { "relaxed-constexpr" : "expt-relaxed-constexpr" } + return [ update_options[opt] if opt in update_options else opt + for opt in nvcc_options ] + +def GetNvccOptions(argv): + """Collect the -nvcc_options values from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + + Returns: + The string that can be passed directly to nvcc. + """ + + parser = ArgumentParser() + parser.add_argument('-nvcc_options', nargs='*', action='append') + + args, _ = parser.parse_known_args(argv) + + if args.nvcc_options: + options = _update_options(sum(args.nvcc_options, [])) + return ' '.join(['--'+a for a in options]) + return '' + + +def InvokeNvcc(argv, log=False): + """Call nvcc with arguments assembled from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + log: True if logging is requested. + + Returns: + The return value of calling os.system('nvcc ' + args) + """ + + host_compiler_options = GetHostCompilerOptions(argv) + nvcc_compiler_options = GetNvccOptions(argv) + opt_option = GetOptionValue(argv, 'O') + m_options = GetOptionValue(argv, 'm') + m_options = ''.join([' -m' + m for m in m_options if m in ['32', '64']]) + include_options = GetOptionValue(argv, 'I') + out_file = GetOptionValue(argv, 'o') + depfiles = GetOptionValue(argv, 'MF') + defines = GetOptionValue(argv, 'D') + defines = ''.join([' -D' + define for define in defines]) + undefines = GetOptionValue(argv, 'U') + undefines = ''.join([' -U' + define for define in undefines]) + std_options = GetOptionValue(argv, 'std') + # currently only c++11 is supported by Cuda 7.0 std argument + nvcc_allowed_std_options = ["c++11"] + std_options = ''.join([' -std=' + define + for define in std_options if define in nvcc_allowed_std_options]) + + # The list of source files get passed after the -c option. I don't know of + # any other reliable way to just get the list of source files to be compiled. + src_files = GetOptionValue(argv, 'c') + + # Pass -w through from host to nvcc, but don't do anything fancier with + # warnings-related flags, since they're not necessarily the same across + # compilers. + warning_options = ' -w' if '-w' in argv else '' + + if len(src_files) == 0: + return 1 + if len(out_file) != 1: + return 1 + + opt = (' -O2' if (len(opt_option) > 0 and int(opt_option[0]) > 0) + else ' -g -G') + + includes = (' -I ' + ' -I '.join(include_options) + if len(include_options) > 0 + else '') + + # Unfortunately, there are other options that have -c prefix too. + # So allowing only those look like C/C++ files. + src_files = [f for f in src_files if + re.search('\.cpp$|\.cc$|\.c$|\.cxx$|\.C$', f)] + srcs = ' '.join(src_files) + out = ' -o ' + out_file[0] + + supported_cuda_compute_capabilities = [ "3.0" ] + nvccopts = '-D_FORCE_INLINES ' + for capability in supported_cuda_compute_capabilities: + capability = capability.replace('.', '') + nvccopts += r'-gencode=arch=compute_%s,\"code=sm_%s,compute_%s\" ' % ( + capability, capability, capability) + nvccopts += ' ' + nvcc_compiler_options + nvccopts += undefines + nvccopts += defines + nvccopts += std_options + nvccopts += m_options + nvccopts += warning_options + + if depfiles: + # Generate the dependency file + depfile = depfiles[0] + cmd = (NVCC_PATH + ' ' + nvccopts + + ' --compiler-options "' + host_compiler_options + '"' + + ' --compiler-bindir=' + GCC_HOST_COMPILER_PATH + + ' -I .' + + ' -x cu ' + opt + includes + ' ' + srcs + ' -M -o ' + depfile) + if log: Log(cmd) + exit_status = os.system(cmd) + if exit_status != 0: + return exit_status + + cmd = (NVCC_PATH + ' ' + nvccopts + + ' --compiler-options "' + host_compiler_options + ' -fPIC"' + + ' --compiler-bindir=' + GCC_HOST_COMPILER_PATH + + ' -I .' + + ' -x cu ' + opt + includes + ' -c ' + srcs + out) + + # TODO(zhengxq): for some reason, 'gcc' needs this help to find 'as'. + # Need to investigate and fix. + cmd = 'PATH=' + PREFIX_DIR + ':$PATH ' + cmd + if log: Log(cmd) + return os.system(cmd) + + +def main(): + parser = ArgumentParser() + parser.add_argument('-x', nargs=1) + parser.add_argument('--cuda_log', action='store_true') + args, leftover = parser.parse_known_args(sys.argv[1:]) + + if args.x and args.x[0] == 'cuda': + if args.cuda_log: Log('-x cuda') + leftover = [pipes.quote(s) for s in leftover] + if args.cuda_log: Log('using nvcc') + return InvokeNvcc(leftover, log=args.cuda_log) + + # Strip our flags before passing through to the CPU compiler for files which + # are not -x cuda. We can't just pass 'leftover' because it also strips -x. + # We not only want to pass -x to the CPU compiler, but also keep it in its + # relative location in the argv list (the compiler is actually sensitive to + # this). + cpu_compiler_flags = [flag for flag in sys.argv[1:] + if not flag.startswith(('--cuda_log'))] + + return subprocess.call([CPU_COMPILER] + cpu_compiler_flags) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.bat b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.bat new file mode 100755 index 0000000000..e896e654fd --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.bat @@ -0,0 +1,20 @@ +:: Copyright 2015 The TensorFlow Authors. 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. +:: ============================================================================= + +:: Invoke msvc_wrapper_for_nvcc.py, which is located in the same directory. +@echo OFF +set arg0=%~0 +for %%F in ("%arg0%") do set DRIVER_BIN=%%~dpF +"/usr/bin/python3" -B "%DRIVER_BIN%\msvc_wrapper_for_nvcc.py" %* diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.py b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.py new file mode 100755 index 0000000000..859b3196d5 --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda9.0/windows/msvc_wrapper_for_nvcc.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Crosstool wrapper for compiling CUDA programs with nvcc on Windows. + +DESCRIPTION: + This script is the Windows version of //third_party/gpus/crosstool/crosstool_wrapper_is_not_gcc +""" + +from __future__ import print_function + +from argparse import ArgumentParser +import os +import subprocess +import re +import sys +import pipes + +# Template values set by cuda_autoconf. +CPU_COMPILER = ('/usr/bin/gcc') +GCC_HOST_COMPILER_PATH = ('/usr/bin/gcc') + +NVCC_PATH = '/usr/local/cuda-9.0/bin/nvcc' +NVCC_VERSION = '9.0' +NVCC_TEMP_DIR = "C:\\Windows\\Temp\\nvcc_inter_files_tmp_dir" +supported_cuda_compute_capabilities = [ "3.0" ] + +def Log(s): + print('gpus/crosstool: {0}'.format(s)) + + +def GetOptionValue(argv, option): + """Extract the list of values for option from options. + + Args: + option: The option whose value to extract, without the leading '/'. + + Returns: + 1. A list of values, either directly following the option, + (eg., /opt val1 val2) or values collected from multiple occurrences of + the option (eg., /opt val1 /opt val2). + 2. The leftover options. + """ + + parser = ArgumentParser(prefix_chars='/') + parser.add_argument('/' + option, nargs='*', action='append') + args, leftover = parser.parse_known_args(argv) + if args and vars(args)[option]: + return (sum(vars(args)[option], []), leftover) + return ([], leftover) + +def _update_options(nvcc_options): + if NVCC_VERSION in ("7.0",): + return nvcc_options + + update_options = { "relaxed-constexpr" : "expt-relaxed-constexpr" } + return [ update_options[opt] if opt in update_options else opt + for opt in nvcc_options ] + +def GetNvccOptions(argv): + """Collect the -nvcc_options values from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + + Returns: + 1. The string that can be passed directly to nvcc. + 2. The leftover options. + """ + + parser = ArgumentParser() + parser.add_argument('-nvcc_options', nargs='*', action='append') + + args, leftover = parser.parse_known_args(argv) + + if args.nvcc_options: + options = _update_options(sum(args.nvcc_options, [])) + return (['--' + a for a in options], leftover) + return ([], leftover) + + +def InvokeNvcc(argv, log=False): + """Call nvcc with arguments assembled from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + log: True if logging is requested. + + Returns: + The return value of calling os.system('nvcc ' + args) + """ + + src_files = [f for f in argv if + re.search('\.cpp$|\.cc$|\.c$|\.cxx$|\.C$', f)] + if len(src_files) == 0: + raise Error('No source files found for cuda compilation.') + + out_file = [ f for f in argv if f.startswith('/Fo') ] + if len(out_file) != 1: + raise Error('Please sepecify exactly one output file for cuda compilation.') + out = ['-o', out_file[0][len('/Fo'):]] + + nvcc_compiler_options, argv = GetNvccOptions(argv) + + opt_option, argv = GetOptionValue(argv, 'O') + opt = ['-g', '-G'] + if (len(opt_option) > 0 and opt_option[0] != 'd'): + opt = ['-O2'] + + include_options, argv = GetOptionValue(argv, 'I') + includes = ["-I " + include for include in include_options] + + defines, argv = GetOptionValue(argv, 'D') + defines = ['-D' + define for define in defines] + + undefines, argv = GetOptionValue(argv, 'U') + undefines = ['-U' + define for define in undefines] + + # The rest of the unrecongized options should be passed to host compiler + host_compiler_options = [option for option in argv if option not in (src_files + out_file)] + + m_options = ["-m64"] + + nvccopts = ['-D_FORCE_INLINES'] + for capability in supported_cuda_compute_capabilities: + capability = capability.replace('.', '') + nvccopts += [r'-gencode=arch=compute_%s,"code=sm_%s,compute_%s"' % ( + capability, capability, capability)] + nvccopts += nvcc_compiler_options + nvccopts += undefines + nvccopts += defines + nvccopts += m_options + nvccopts += ['--compiler-options="' + " ".join(host_compiler_options) + '"'] + nvccopts += ['-x', 'cu'] + opt + includes + out + ['-c'] + src_files + # If we don't specify --keep-dir, nvcc will generate intermediate files under TEMP + # Put them under NVCC_TEMP_DIR instead, then Bazel can ignore files under NVCC_TEMP_DIR during dependency check + # http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#options-for-guiding-compiler-driver + # Different actions are sharing NVCC_TEMP_DIR, so we cannot remove it if the directory already exists. + if os.path.isfile(NVCC_TEMP_DIR): + os.remove(NVCC_TEMP_DIR) + if not os.path.exists(NVCC_TEMP_DIR): + os.makedirs(NVCC_TEMP_DIR) + nvccopts += ['--keep', '--keep-dir', NVCC_TEMP_DIR] + cmd = [NVCC_PATH] + nvccopts + if log: + Log(cmd) + proc = subprocess.Popen(cmd, + stdout=sys.stdout, + stderr=sys.stderr, + env=os.environ.copy(), + shell=True) + proc.wait() + return proc.returncode + +def main(): + parser = ArgumentParser() + parser.add_argument('-x', nargs=1) + parser.add_argument('--cuda_log', action='store_true') + args, leftover = parser.parse_known_args(sys.argv[1:]) + + if args.x and args.x[0] == 'cuda': + if args.cuda_log: Log('-x cuda') + leftover = [pipes.quote(s) for s in leftover] + if args.cuda_log: Log('using nvcc') + return InvokeNvcc(leftover, log=args.cuda_log) + + # Strip our flags before passing through to the CPU compiler for files which + # are not -x cuda. We can't just pass 'leftover' because it also strips -x. + # We not only want to pass -x to the CPU compiler, but also keep it in its + # relative location in the argv list (the compiler is actually sensitive to + # this). + cpu_compiler_flags = [flag for flag in sys.argv[1:] + if not flag.startswith(('--cuda_log')) + and not flag.startswith(('-nvcc_options'))] + + return subprocess.call([CPU_COMPILER] + cpu_compiler_flags) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/py3/BUILD b/third_party/toolchains/preconfig/ubuntu14.04/py3/BUILD index e021df9e1e..460c879d32 100755 --- a/third_party/toolchains/preconfig/ubuntu14.04/py3/BUILD +++ b/third_party/toolchains/preconfig/ubuntu14.04/py3/BUILD @@ -136,7 +136,7 @@ genrule( "python_include/weakrefobject.h", ], cmd = """ -cp "/usr/include/python3.4m/Python-ast.h" "$(@D)/python_include/Python-ast.h" && cp "/usr/include/python3.4m/Python.h" "$(@D)/python_include/Python.h" && cp "/usr/include/python3.4m/abstract.h" "$(@D)/python_include/abstract.h" && cp "/usr/include/python3.4m/accu.h" "$(@D)/python_include/accu.h" && cp "/usr/include/python3.4m/asdl.h" "$(@D)/python_include/asdl.h" && cp "/usr/include/python3.4m/ast.h" "$(@D)/python_include/ast.h" && cp "/usr/include/python3.4m/bitset.h" "$(@D)/python_include/bitset.h" && cp "/usr/include/python3.4m/bltinmodule.h" "$(@D)/python_include/bltinmodule.h" && cp "/usr/include/python3.4m/boolobject.h" "$(@D)/python_include/boolobject.h" && cp "/usr/include/python3.4m/bytearrayobject.h" "$(@D)/python_include/bytearrayobject.h" && cp "/usr/include/python3.4m/bytes_methods.h" "$(@D)/python_include/bytes_methods.h" && cp "/usr/include/python3.4m/bytesobject.h" "$(@D)/python_include/bytesobject.h" && cp "/usr/include/python3.4m/cellobject.h" "$(@D)/python_include/cellobject.h" && cp "/usr/include/python3.4m/ceval.h" "$(@D)/python_include/ceval.h" && cp "/usr/include/python3.4m/classobject.h" "$(@D)/python_include/classobject.h" && cp "/usr/include/python3.4m/code.h" "$(@D)/python_include/code.h" && cp "/usr/include/python3.4m/codecs.h" "$(@D)/python_include/codecs.h" && cp "/usr/include/python3.4m/compile.h" "$(@D)/python_include/compile.h" && cp "/usr/include/python3.4m/complexobject.h" "$(@D)/python_include/complexobject.h" && cp "/usr/include/python3.4m/datetime.h" "$(@D)/python_include/datetime.h" && cp "/usr/include/python3.4m/descrobject.h" "$(@D)/python_include/descrobject.h" && cp "/usr/include/python3.4m/dictobject.h" "$(@D)/python_include/dictobject.h" && cp "/usr/include/python3.4m/dtoa.h" "$(@D)/python_include/dtoa.h" && cp "/usr/include/python3.4m/dynamic_annotations.h" "$(@D)/python_include/dynamic_annotations.h" && cp "/usr/include/python3.4m/enumobject.h" "$(@D)/python_include/enumobject.h" && cp "/usr/include/python3.4m/errcode.h" "$(@D)/python_include/errcode.h" && cp "/usr/include/python3.4m/eval.h" "$(@D)/python_include/eval.h" && cp "/usr/include/python3.4m/fileobject.h" "$(@D)/python_include/fileobject.h" && cp "/usr/include/python3.4m/fileutils.h" "$(@D)/python_include/fileutils.h" && cp "/usr/include/python3.4m/floatobject.h" "$(@D)/python_include/floatobject.h" && cp "/usr/include/python3.4m/frameobject.h" "$(@D)/python_include/frameobject.h" && cp "/usr/include/python3.4m/funcobject.h" "$(@D)/python_include/funcobject.h" && cp "/usr/include/python3.4m/genobject.h" "$(@D)/python_include/genobject.h" && cp "/usr/include/python3.4m/graminit.h" "$(@D)/python_include/graminit.h" && cp "/usr/include/python3.4m/grammar.h" "$(@D)/python_include/grammar.h" && cp "/usr/include/python3.4m/import.h" "$(@D)/python_include/import.h" && cp "/usr/include/python3.4m/intrcheck.h" "$(@D)/python_include/intrcheck.h" && cp "/usr/include/python3.4m/iterobject.h" "$(@D)/python_include/iterobject.h" && cp "/usr/include/python3.4m/listobject.h" "$(@D)/python_include/listobject.h" && cp "/usr/include/python3.4m/longintrepr.h" "$(@D)/python_include/longintrepr.h" && cp "/usr/include/python3.4m/longobject.h" "$(@D)/python_include/longobject.h" && cp "/usr/include/python3.4m/marshal.h" "$(@D)/python_include/marshal.h" && cp "/usr/include/python3.4m/memoryobject.h" "$(@D)/python_include/memoryobject.h" && cp "/usr/include/python3.4m/metagrammar.h" "$(@D)/python_include/metagrammar.h" && cp "/usr/include/python3.4m/methodobject.h" "$(@D)/python_include/methodobject.h" && cp "/usr/include/python3.4m/modsupport.h" "$(@D)/python_include/modsupport.h" && cp "/usr/include/python3.4m/moduleobject.h" "$(@D)/python_include/moduleobject.h" && cp "/usr/include/python3.4m/namespaceobject.h" "$(@D)/python_include/namespaceobject.h" && cp "/usr/include/python3.4m/node.h" "$(@D)/python_include/node.h" && cp "/usr/include/python3.4m/object.h" "$(@D)/python_include/object.h" && cp "/usr/include/python3.4m/objimpl.h" "$(@D)/python_include/objimpl.h" && cp "/usr/include/python3.4m/opcode.h" "$(@D)/python_include/opcode.h" && cp "/usr/include/python3.4m/osdefs.h" "$(@D)/python_include/osdefs.h" && cp "/usr/include/python3.4m/parsetok.h" "$(@D)/python_include/parsetok.h" && cp "/usr/include/python3.4m/patchlevel.h" "$(@D)/python_include/patchlevel.h" && cp "/usr/include/python3.4m/pgen.h" "$(@D)/python_include/pgen.h" && cp "/usr/include/python3.4m/pgenheaders.h" "$(@D)/python_include/pgenheaders.h" && cp "/usr/include/python3.4m/py_curses.h" "$(@D)/python_include/py_curses.h" && cp "/usr/include/python3.4m/pyarena.h" "$(@D)/python_include/pyarena.h" && cp "/usr/include/python3.4m/pyatomic.h" "$(@D)/python_include/pyatomic.h" && cp "/usr/include/python3.4m/pycapsule.h" "$(@D)/python_include/pycapsule.h" && cp "/usr/include/python3.4m/pyconfig.h" "$(@D)/python_include/pyconfig.h" && cp "/usr/include/python3.4m/pyctype.h" "$(@D)/python_include/pyctype.h" && cp "/usr/include/python3.4m/pydebug.h" "$(@D)/python_include/pydebug.h" && cp "/usr/include/python3.4m/pyerrors.h" "$(@D)/python_include/pyerrors.h" && cp "/usr/include/python3.4m/pyexpat.h" "$(@D)/python_include/pyexpat.h" && cp "/usr/include/python3.4m/pyfpe.h" "$(@D)/python_include/pyfpe.h" && cp "/usr/include/python3.4m/pygetopt.h" "$(@D)/python_include/pygetopt.h" && cp "/usr/include/python3.4m/pyhash.h" "$(@D)/python_include/pyhash.h" && cp "/usr/include/python3.4m/pymacconfig.h" "$(@D)/python_include/pymacconfig.h" && cp "/usr/include/python3.4m/pymacro.h" "$(@D)/python_include/pymacro.h" && cp "/usr/include/python3.4m/pymath.h" "$(@D)/python_include/pymath.h" && cp "/usr/include/python3.4m/pymem.h" "$(@D)/python_include/pymem.h" && cp "/usr/include/python3.4m/pyport.h" "$(@D)/python_include/pyport.h" && cp "/usr/include/python3.4m/pystate.h" "$(@D)/python_include/pystate.h" && cp "/usr/include/python3.4m/pystrcmp.h" "$(@D)/python_include/pystrcmp.h" && cp "/usr/include/python3.4m/pystrtod.h" "$(@D)/python_include/pystrtod.h" && cp "/usr/include/python3.4m/pythonrun.h" "$(@D)/python_include/pythonrun.h" && cp "/usr/include/python3.4m/pythread.h" "$(@D)/python_include/pythread.h" && cp "/usr/include/python3.4m/pytime.h" "$(@D)/python_include/pytime.h" && cp "/usr/include/python3.4m/rangeobject.h" "$(@D)/python_include/rangeobject.h" && cp "/usr/include/python3.4m/setobject.h" "$(@D)/python_include/setobject.h" && cp "/usr/include/python3.4m/sliceobject.h" "$(@D)/python_include/sliceobject.h" && cp "/usr/include/python3.4m/structmember.h" "$(@D)/python_include/structmember.h" && cp "/usr/include/python3.4m/structseq.h" "$(@D)/python_include/structseq.h" && cp "/usr/include/python3.4m/symtable.h" "$(@D)/python_include/symtable.h" && cp "/usr/include/python3.4m/sysmodule.h" "$(@D)/python_include/sysmodule.h" && cp "/usr/include/python3.4m/token.h" "$(@D)/python_include/token.h" && cp "/usr/include/python3.4m/traceback.h" "$(@D)/python_include/traceback.h" && cp "/usr/include/python3.4m/tupleobject.h" "$(@D)/python_include/tupleobject.h" && cp "/usr/include/python3.4m/typeslots.h" "$(@D)/python_include/typeslots.h" && cp "/usr/include/python3.4m/ucnhash.h" "$(@D)/python_include/ucnhash.h" && cp "/usr/include/python3.4m/unicodeobject.h" "$(@D)/python_include/unicodeobject.h" && cp "/usr/include/python3.4m/warnings.h" "$(@D)/python_include/warnings.h" && cp "/usr/include/python3.4m/weakrefobject.h" "$(@D)/python_include/weakrefobject.h" +cp -f "/usr/include/python3.4m/Python-ast.h" "$(@D)/python_include/Python-ast.h" && cp -f "/usr/include/python3.4m/Python.h" "$(@D)/python_include/Python.h" && cp -f "/usr/include/python3.4m/abstract.h" "$(@D)/python_include/abstract.h" && cp -f "/usr/include/python3.4m/accu.h" "$(@D)/python_include/accu.h" && cp -f "/usr/include/python3.4m/asdl.h" "$(@D)/python_include/asdl.h" && cp -f "/usr/include/python3.4m/ast.h" "$(@D)/python_include/ast.h" && cp -f "/usr/include/python3.4m/bitset.h" "$(@D)/python_include/bitset.h" && cp -f "/usr/include/python3.4m/bltinmodule.h" "$(@D)/python_include/bltinmodule.h" && cp -f "/usr/include/python3.4m/boolobject.h" "$(@D)/python_include/boolobject.h" && cp -f "/usr/include/python3.4m/bytearrayobject.h" "$(@D)/python_include/bytearrayobject.h" && cp -f "/usr/include/python3.4m/bytes_methods.h" "$(@D)/python_include/bytes_methods.h" && cp -f "/usr/include/python3.4m/bytesobject.h" "$(@D)/python_include/bytesobject.h" && cp -f "/usr/include/python3.4m/cellobject.h" "$(@D)/python_include/cellobject.h" && cp -f "/usr/include/python3.4m/ceval.h" "$(@D)/python_include/ceval.h" && cp -f "/usr/include/python3.4m/classobject.h" "$(@D)/python_include/classobject.h" && cp -f "/usr/include/python3.4m/code.h" "$(@D)/python_include/code.h" && cp -f "/usr/include/python3.4m/codecs.h" "$(@D)/python_include/codecs.h" && cp -f "/usr/include/python3.4m/compile.h" "$(@D)/python_include/compile.h" && cp -f "/usr/include/python3.4m/complexobject.h" "$(@D)/python_include/complexobject.h" && cp -f "/usr/include/python3.4m/datetime.h" "$(@D)/python_include/datetime.h" && cp -f "/usr/include/python3.4m/descrobject.h" "$(@D)/python_include/descrobject.h" && cp -f "/usr/include/python3.4m/dictobject.h" "$(@D)/python_include/dictobject.h" && cp -f "/usr/include/python3.4m/dtoa.h" "$(@D)/python_include/dtoa.h" && cp -f "/usr/include/python3.4m/dynamic_annotations.h" "$(@D)/python_include/dynamic_annotations.h" && cp -f "/usr/include/python3.4m/enumobject.h" "$(@D)/python_include/enumobject.h" && cp -f "/usr/include/python3.4m/errcode.h" "$(@D)/python_include/errcode.h" && cp -f "/usr/include/python3.4m/eval.h" "$(@D)/python_include/eval.h" && cp -f "/usr/include/python3.4m/fileobject.h" "$(@D)/python_include/fileobject.h" && cp -f "/usr/include/python3.4m/fileutils.h" "$(@D)/python_include/fileutils.h" && cp -f "/usr/include/python3.4m/floatobject.h" "$(@D)/python_include/floatobject.h" && cp -f "/usr/include/python3.4m/frameobject.h" "$(@D)/python_include/frameobject.h" && cp -f "/usr/include/python3.4m/funcobject.h" "$(@D)/python_include/funcobject.h" && cp -f "/usr/include/python3.4m/genobject.h" "$(@D)/python_include/genobject.h" && cp -f "/usr/include/python3.4m/graminit.h" "$(@D)/python_include/graminit.h" && cp -f "/usr/include/python3.4m/grammar.h" "$(@D)/python_include/grammar.h" && cp -f "/usr/include/python3.4m/import.h" "$(@D)/python_include/import.h" && cp -f "/usr/include/python3.4m/intrcheck.h" "$(@D)/python_include/intrcheck.h" && cp -f "/usr/include/python3.4m/iterobject.h" "$(@D)/python_include/iterobject.h" && cp -f "/usr/include/python3.4m/listobject.h" "$(@D)/python_include/listobject.h" && cp -f "/usr/include/python3.4m/longintrepr.h" "$(@D)/python_include/longintrepr.h" && cp -f "/usr/include/python3.4m/longobject.h" "$(@D)/python_include/longobject.h" && cp -f "/usr/include/python3.4m/marshal.h" "$(@D)/python_include/marshal.h" && cp -f "/usr/include/python3.4m/memoryobject.h" "$(@D)/python_include/memoryobject.h" && cp -f "/usr/include/python3.4m/metagrammar.h" "$(@D)/python_include/metagrammar.h" && cp -f "/usr/include/python3.4m/methodobject.h" "$(@D)/python_include/methodobject.h" && cp -f "/usr/include/python3.4m/modsupport.h" "$(@D)/python_include/modsupport.h" && cp -f "/usr/include/python3.4m/moduleobject.h" "$(@D)/python_include/moduleobject.h" && cp -f "/usr/include/python3.4m/namespaceobject.h" "$(@D)/python_include/namespaceobject.h" && cp -f "/usr/include/python3.4m/node.h" "$(@D)/python_include/node.h" && cp -f "/usr/include/python3.4m/object.h" "$(@D)/python_include/object.h" && cp -f "/usr/include/python3.4m/objimpl.h" "$(@D)/python_include/objimpl.h" && cp -f "/usr/include/python3.4m/opcode.h" "$(@D)/python_include/opcode.h" && cp -f "/usr/include/python3.4m/osdefs.h" "$(@D)/python_include/osdefs.h" && cp -f "/usr/include/python3.4m/parsetok.h" "$(@D)/python_include/parsetok.h" && cp -f "/usr/include/python3.4m/patchlevel.h" "$(@D)/python_include/patchlevel.h" && cp -f "/usr/include/python3.4m/pgen.h" "$(@D)/python_include/pgen.h" && cp -f "/usr/include/python3.4m/pgenheaders.h" "$(@D)/python_include/pgenheaders.h" && cp -f "/usr/include/python3.4m/py_curses.h" "$(@D)/python_include/py_curses.h" && cp -f "/usr/include/python3.4m/pyarena.h" "$(@D)/python_include/pyarena.h" && cp -f "/usr/include/python3.4m/pyatomic.h" "$(@D)/python_include/pyatomic.h" && cp -f "/usr/include/python3.4m/pycapsule.h" "$(@D)/python_include/pycapsule.h" && cp -f "/usr/include/python3.4m/pyconfig.h" "$(@D)/python_include/pyconfig.h" && cp -f "/usr/include/python3.4m/pyctype.h" "$(@D)/python_include/pyctype.h" && cp -f "/usr/include/python3.4m/pydebug.h" "$(@D)/python_include/pydebug.h" && cp -f "/usr/include/python3.4m/pyerrors.h" "$(@D)/python_include/pyerrors.h" && cp -f "/usr/include/python3.4m/pyexpat.h" "$(@D)/python_include/pyexpat.h" && cp -f "/usr/include/python3.4m/pyfpe.h" "$(@D)/python_include/pyfpe.h" && cp -f "/usr/include/python3.4m/pygetopt.h" "$(@D)/python_include/pygetopt.h" && cp -f "/usr/include/python3.4m/pyhash.h" "$(@D)/python_include/pyhash.h" && cp -f "/usr/include/python3.4m/pymacconfig.h" "$(@D)/python_include/pymacconfig.h" && cp -f "/usr/include/python3.4m/pymacro.h" "$(@D)/python_include/pymacro.h" && cp -f "/usr/include/python3.4m/pymath.h" "$(@D)/python_include/pymath.h" && cp -f "/usr/include/python3.4m/pymem.h" "$(@D)/python_include/pymem.h" && cp -f "/usr/include/python3.4m/pyport.h" "$(@D)/python_include/pyport.h" && cp -f "/usr/include/python3.4m/pystate.h" "$(@D)/python_include/pystate.h" && cp -f "/usr/include/python3.4m/pystrcmp.h" "$(@D)/python_include/pystrcmp.h" && cp -f "/usr/include/python3.4m/pystrtod.h" "$(@D)/python_include/pystrtod.h" && cp -f "/usr/include/python3.4m/pythonrun.h" "$(@D)/python_include/pythonrun.h" && cp -f "/usr/include/python3.4m/pythread.h" "$(@D)/python_include/pythread.h" && cp -f "/usr/include/python3.4m/pytime.h" "$(@D)/python_include/pytime.h" && cp -f "/usr/include/python3.4m/rangeobject.h" "$(@D)/python_include/rangeobject.h" && cp -f "/usr/include/python3.4m/setobject.h" "$(@D)/python_include/setobject.h" && cp -f "/usr/include/python3.4m/sliceobject.h" "$(@D)/python_include/sliceobject.h" && cp -f "/usr/include/python3.4m/structmember.h" "$(@D)/python_include/structmember.h" && cp -f "/usr/include/python3.4m/structseq.h" "$(@D)/python_include/structseq.h" && cp -f "/usr/include/python3.4m/symtable.h" "$(@D)/python_include/symtable.h" && cp -f "/usr/include/python3.4m/sysmodule.h" "$(@D)/python_include/sysmodule.h" && cp -f "/usr/include/python3.4m/token.h" "$(@D)/python_include/token.h" && cp -f "/usr/include/python3.4m/traceback.h" "$(@D)/python_include/traceback.h" && cp -f "/usr/include/python3.4m/tupleobject.h" "$(@D)/python_include/tupleobject.h" && cp -f "/usr/include/python3.4m/typeslots.h" "$(@D)/python_include/typeslots.h" && cp -f "/usr/include/python3.4m/ucnhash.h" "$(@D)/python_include/ucnhash.h" && cp -f "/usr/include/python3.4m/unicodeobject.h" "$(@D)/python_include/unicodeobject.h" && cp -f "/usr/include/python3.4m/warnings.h" "$(@D)/python_include/warnings.h" && cp -f "/usr/include/python3.4m/weakrefobject.h" "$(@D)/python_include/weakrefobject.h" """, ) @@ -171,6 +171,6 @@ genrule( "numpy_include/numpy/utils.h", ], cmd = """ -cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/__multiarray_api.h" "$(@D)/numpy_include/numpy/__multiarray_api.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/__ufunc_api.h" "$(@D)/numpy_include/numpy/__ufunc_api.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/_neighborhood_iterator_imp.h" "$(@D)/numpy_include/numpy/_neighborhood_iterator_imp.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/_numpyconfig.h" "$(@D)/numpy_include/numpy/_numpyconfig.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/arrayobject.h" "$(@D)/numpy_include/numpy/arrayobject.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/arrayscalars.h" "$(@D)/numpy_include/numpy/arrayscalars.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/halffloat.h" "$(@D)/numpy_include/numpy/halffloat.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/multiarray_api.txt" "$(@D)/numpy_include/numpy/multiarray_api.txt" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ndarrayobject.h" "$(@D)/numpy_include/numpy/ndarrayobject.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ndarraytypes.h" "$(@D)/numpy_include/numpy/ndarraytypes.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/noprefix.h" "$(@D)/numpy_include/numpy/noprefix.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h" "$(@D)/numpy_include/numpy/npy_1_7_deprecated_api.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_3kcompat.h" "$(@D)/numpy_include/numpy/npy_3kcompat.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_common.h" "$(@D)/numpy_include/numpy/npy_common.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_cpu.h" "$(@D)/numpy_include/numpy/npy_cpu.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_endian.h" "$(@D)/numpy_include/numpy/npy_endian.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_interrupt.h" "$(@D)/numpy_include/numpy/npy_interrupt.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_math.h" "$(@D)/numpy_include/numpy/npy_math.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_no_deprecated_api.h" "$(@D)/numpy_include/numpy/npy_no_deprecated_api.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_os.h" "$(@D)/numpy_include/numpy/npy_os.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/numpyconfig.h" "$(@D)/numpy_include/numpy/numpyconfig.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/old_defines.h" "$(@D)/numpy_include/numpy/old_defines.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/oldnumeric.h" "$(@D)/numpy_include/numpy/oldnumeric.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ufunc_api.txt" "$(@D)/numpy_include/numpy/ufunc_api.txt" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ufuncobject.h" "$(@D)/numpy_include/numpy/ufuncobject.h" && cp "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/utils.h" "$(@D)/numpy_include/numpy/utils.h" +cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/__multiarray_api.h" "$(@D)/numpy_include/numpy/__multiarray_api.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/__ufunc_api.h" "$(@D)/numpy_include/numpy/__ufunc_api.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/_neighborhood_iterator_imp.h" "$(@D)/numpy_include/numpy/_neighborhood_iterator_imp.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/_numpyconfig.h" "$(@D)/numpy_include/numpy/_numpyconfig.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/arrayobject.h" "$(@D)/numpy_include/numpy/arrayobject.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/arrayscalars.h" "$(@D)/numpy_include/numpy/arrayscalars.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/halffloat.h" "$(@D)/numpy_include/numpy/halffloat.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/multiarray_api.txt" "$(@D)/numpy_include/numpy/multiarray_api.txt" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ndarrayobject.h" "$(@D)/numpy_include/numpy/ndarrayobject.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ndarraytypes.h" "$(@D)/numpy_include/numpy/ndarraytypes.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/noprefix.h" "$(@D)/numpy_include/numpy/noprefix.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h" "$(@D)/numpy_include/numpy/npy_1_7_deprecated_api.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_3kcompat.h" "$(@D)/numpy_include/numpy/npy_3kcompat.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_common.h" "$(@D)/numpy_include/numpy/npy_common.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_cpu.h" "$(@D)/numpy_include/numpy/npy_cpu.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_endian.h" "$(@D)/numpy_include/numpy/npy_endian.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_interrupt.h" "$(@D)/numpy_include/numpy/npy_interrupt.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_math.h" "$(@D)/numpy_include/numpy/npy_math.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_no_deprecated_api.h" "$(@D)/numpy_include/numpy/npy_no_deprecated_api.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/npy_os.h" "$(@D)/numpy_include/numpy/npy_os.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/numpyconfig.h" "$(@D)/numpy_include/numpy/numpyconfig.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/old_defines.h" "$(@D)/numpy_include/numpy/old_defines.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/oldnumeric.h" "$(@D)/numpy_include/numpy/oldnumeric.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ufunc_api.txt" "$(@D)/numpy_include/numpy/ufunc_api.txt" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/ufuncobject.h" "$(@D)/numpy_include/numpy/ufuncobject.h" && cp -f "/usr/local/lib/python3.4/dist-packages/numpy/core/include/numpy/utils.h" "$(@D)/numpy_include/numpy/utils.h" """, ) -- GitLab From d692984d21ff115067164aea9629fa9e9dc0dce1 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Tue, 20 Nov 2018 08:06:34 -0800 Subject: [PATCH 102/672] Fixes issue loading cached_value from resourcevariable proto. PiperOrigin-RevId: 222247164 --- .../kernel_tests/resource_variable_ops_test.py | 14 ++++++++++++++ tensorflow/python/ops/resource_variable_ops.py | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index eedc2d263d..c351a18c8f 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -568,6 +568,20 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): v.load(2.0) self.assertEqual(2.0, self.evaluate(v.value())) + def testToFromProtoCachedValue(self): + with ops.Graph().as_default(): + v_def = resource_variable_ops.ResourceVariable( + initial_value=constant_op.constant(3.0)).to_proto() + v_prime = resource_variable_ops.ResourceVariable(variable_def=v_def) + self.assertTrue(getattr(v_prime, "_cached_value", None) is None) + + other_v_def = resource_variable_ops.ResourceVariable( + caching_device="cpu:0", + initial_value=constant_op.constant(3.0)).to_proto() + other_v_prime = resource_variable_ops.ResourceVariable( + variable_def=other_v_def) + self.assertTrue(other_v_prime._cached_value is not None) + def testVariableDefInitializedInstances(self): with ops.Graph().as_default(), self.cached_session() as sess: v_def = resource_variable_ops.ResourceVariable( diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index 488b6fcbcd..c20f8fb938 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -519,7 +519,10 @@ class ResourceVariable(variables.RefVariable): snapshot = g.as_graph_element( ops.prepend_name_scope( variable_def.snapshot_name, import_scope=import_scope)) - self._cached_value = snapshot + if snapshot.op.type != "ReadVariableOp": + self._cached_value = snapshot + else: + self._cached_value = None while snapshot.op.type != "ReadVariableOp": snapshot = snapshot.op.inputs[0] self._graph_element = snapshot -- GitLab From dcc76a5c4945406455213b05fb8c084b5a8b9b6d Mon Sep 17 00:00:00 2001 From: "William D. Irons" Date: Tue, 20 Nov 2018 10:35:18 -0600 Subject: [PATCH 103/672] Add PYTHONPATH to bazelrc when necessary When the user choosen python_lib_path was retreived from the PYTHONPATH environment variable, need to set PYTHONPATH in the bazelrc file so bazel includes it in all the build operations. Fixes tensorflow#23695 --- configure.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configure.py b/configure.py index 234561d94a..17ab7a0d63 100644 --- a/configure.py +++ b/configure.py @@ -238,6 +238,13 @@ def setup_python(environ_cp): write_to_bazelrc('build --python_path=\"%s"' % python_bin_path) environ_cp['PYTHON_BIN_PATH'] = python_bin_path + # If choosen python_lib_path is from a path specified in the PYTHONPATH + # variable, need to tell bazel to include PYTHONPATH + if environ_cp.get('PYTHONPATH'): + python_paths = environ_cp.get('PYTHONPATH').split(':') + if python_lib_path in python_paths: + write_action_env_to_bazelrc('PYTHONPATH', environ_cp.get('PYTHONPATH')) + # Write tools/python_bin_path.sh with open( os.path.join(_TF_WORKSPACE_ROOT, 'tools', 'python_bin_path.sh'), -- GitLab From 1e4bb841565552ea2e27474abae8c8c1833a753e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 09:02:05 -0800 Subject: [PATCH 104/672] Add Dockerfile for cuda 10. PiperOrigin-RevId: 222254468 --- ...Dockerfile.rbe.cuda10.0-cudnn7-ubuntu14.04 | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tensorflow/tools/ci_build/Dockerfile.rbe.cuda10.0-cudnn7-ubuntu14.04 diff --git a/tensorflow/tools/ci_build/Dockerfile.rbe.cuda10.0-cudnn7-ubuntu14.04 b/tensorflow/tools/ci_build/Dockerfile.rbe.cuda10.0-cudnn7-ubuntu14.04 new file mode 100644 index 0000000000..85b9d94313 --- /dev/null +++ b/tensorflow/tools/ci_build/Dockerfile.rbe.cuda10.0-cudnn7-ubuntu14.04 @@ -0,0 +1,75 @@ +# To push a new version, run: +# $ docker build -f Dockerfile.rbe.cuda10.0-cudnn7-ubuntu14.04 \ +# --tag "gcr.io/asci-toolchain/nosla-cuda10.0-cudnn7-ubuntu14.04" . +# $ docker push gcr.io/asci-toolchain/nosla-cuda10.0-cudnn7-ubuntu14.04 + +FROM ubuntu:14.04 +LABEL maintainer="Manuel Klimek " + +RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates apt-transport-https gnupg-curl && \ + rm -rf /var/lib/apt/lists/* && \ + NVIDIA_GPGKEY_SUM=d1be581509378368edeec8c1eb2958702feedf3bc3d17011adbf24efacce4ab5 && \ + NVIDIA_GPGKEY_FPR=ae09fe4bbd223a84b2ccfce3f60f4b3d7fa2af80 && \ + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub && \ + apt-key adv --export --no-emit-version -a $NVIDIA_GPGKEY_FPR | tail -n +2 > cudasign.pub && \ + echo "$NVIDIA_GPGKEY_SUM cudasign.pub" | sha256sum -c --strict - && rm cudasign.pub && \ + echo "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/cuda.list && \ + echo "deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/nvidia-ml.list + +ENV CUDA_VERSION 10.0.130 +ENV CUDA_PKG_VERSION 10-0=$CUDA_VERSION-1 +ENV CUDNN_VERSION 7.3.1.20 +ENV NCCL_VERSION 2.3.5 +ENV NVIDIA_DRIVER_CAPABILITIES compute,utility +ENV NVIDIA_REQUIRE_CUDA "cuda>=10.0,driver>=410" +ENV NVIDIA_VISIBLE_DEVICES all +ENV PATH /usr/local/cuda/bin:${PATH} + +# TODO(b/110903506): /usr/loca/cuda/lib64/stubs should not be needed in +# LD_LIBRARY_PATH. The stubs/libcuda.so is not meant to used at runtime. The +# correct way to pass the path to bfd-ld is to pass +# -Wl,-rpath-link=/usr/local/cuda/lib64/stubs to all binaries transitively +# depending on libcuda. Optimally, builds targeting cuda would do that +# internally. +ENV LIBRARY_PATH /usr/local/cuda/lib64/stubs + +LABEL com.nvidia.cudnn.version="${CUDNN_VERSION}" + +RUN apt-get update && apt-get install -y --no-install-recommends \ + cuda-command-line-tools-$CUDA_PKG_VERSION \ + cuda-compat-10-0=410.48-1 \ + cuda-cudart-$CUDA_PKG_VERSION \ + cuda-libraries-$CUDA_PKG_VERSION \ + cuda-libraries-dev-$CUDA_PKG_VERSION \ + cuda-minimal-build-$CUDA_PKG_VERSION \ + cuda-nvml-dev-$CUDA_PKG_VERSION \ + cuda-nvtx-$CUDA_PKG_VERSION \ + libcudnn7=$CUDNN_VERSION-1+cuda10.0 \ + libcudnn7=$CUDNN_VERSION-1+cuda10.0 \ + libcudnn7-dev=$CUDNN_VERSION-1+cuda10.0 \ + libnccl2=$NCCL_VERSION-2+cuda10.0 \ + libnccl-dev=$NCCL_VERSION-2+cuda10.0 && \ + ln -s cuda-10.0 /usr/local/cuda && \ + apt-mark hold libcudnn7 && \ + apt-mark hold libnccl2 && \ + rm -rf /var/lib/apt/lists/* + +# TODO(b/110903506): Provide a link to the SONAME of libcuda.so. +# https://github.com/NVIDIA/nvidia-docker/issues/775 +RUN ln -s libcuda.so /usr/local/cuda/lib64/stubs/libcuda.so.1 + +# TODO(klimek): Once the TODO in tensorflow's configure.py to correctly find +# libnccl is resolved, delete this block. +RUN ln -s /usr/lib/x86_64-linux-gnu/libnccl.so /usr/lib/libnccl.so \ + && ln -s /usr/lib/x86_64-linux-gnu/libnccl.so /usr/lib/libnccl.so.2 + +# Copy and run the install scripts. +COPY install/*.sh /install/ +ARG DEBIAN_FRONTEND=noninteractive +RUN /install/install_bootstrap_deb_packages.sh +RUN add-apt-repository -y ppa:openjdk-r/ppa && \ + add-apt-repository -y ppa:george-edison55/cmake-3.x +RUN /install/install_deb_packages.sh +RUN /install/install_pip_packages.sh +RUN /install/install_golang.sh + -- GitLab From 6afb388d49ab32055caf71974e863f5f1db65e0d Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 09:13:31 -0800 Subject: [PATCH 105/672] Add tensorflow implementation of ctc_loss that runs on gpu/tpu. PiperOrigin-RevId: 222256226 --- tensorflow/python/kernel_tests/BUILD | 2 +- .../python/kernel_tests/ctc_loss_op_test.py | 546 +++++++++++- tensorflow/python/ops/ctc_ops.py | 793 +++++++++++++++++- .../tools/api/golden/v1/tensorflow.nn.pbtxt | 12 + .../tools/api/golden/v2/tensorflow.nn.pbtxt | 10 +- 5 files changed, 1354 insertions(+), 9 deletions(-) diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index 41099ba2e8..19facca5a6 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -270,7 +270,7 @@ tf_py_test( ], ) -tf_py_test( +cuda_py_test( name = "ctc_loss_op_test", size = "small", srcs = ["ctc_loss_op_test.py"], diff --git a/tensorflow/python/kernel_tests/ctc_loss_op_test.py b/tensorflow/python/kernel_tests/ctc_loss_op_test.py index cfc7cb98aa..b38776ec5b 100644 --- a/tensorflow/python/kernel_tests/ctc_loss_op_test.py +++ b/tensorflow/python/kernel_tests/ctc_loss_op_test.py @@ -23,9 +23,15 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import ops +from tensorflow.python.framework import random_seed from tensorflow.python.framework import sparse_tensor +from tensorflow.python.ops import array_ops from tensorflow.python.ops import ctc_ops from tensorflow.python.ops import gradients_impl +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import random_ops +from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test @@ -52,6 +58,24 @@ def SimpleSparseTensorFrom(x): return sparse_tensor.SparseTensor(x_ix, x_val, x_shape) +def _ctc_loss_v2(labels, inputs, sequence_length, + preprocess_collapse_repeated=False, + ctc_merge_repeated=True, + ignore_longer_outputs_than_inputs=False, + time_major=True): + """Call ctc_loss_v2 with v1 args.""" + assert not preprocess_collapse_repeated + assert ctc_merge_repeated + assert not ignore_longer_outputs_than_inputs + return ctc_ops.ctc_loss_v2( + labels=labels, + logits=inputs, + logit_length=sequence_length, + label_length=None, + blank_index=-1, + logits_time_major=time_major) + + class CTCLossTest(test.TestCase): def _testCTCLoss(self, @@ -66,7 +90,7 @@ class CTCLossTest(test.TestCase): inputs_t = constant_op.constant(inputs) with self.cached_session(use_gpu=False) as sess: - loss = ctc_ops.ctc_loss( + loss = _ctc_loss_v2( inputs=inputs_t, labels=labels, sequence_length=seq_lens) grad = gradients_impl.gradients(loss, [inputs_t])[0] @@ -234,9 +258,9 @@ class CTCLossTest(test.TestCase): inputs_t_transposed = constant_op.constant(inputs.transpose(1, 0, 2)) with self.session(use_gpu=False) as sess: - loss = ctc_ops.ctc_loss( + loss = _ctc_loss_v2( inputs=inputs_t, labels=labels, sequence_length=seq_lens) - loss_transposed = ctc_ops.ctc_loss( + loss_transposed = _ctc_loss_v2( inputs=inputs_t_transposed, labels=labels, sequence_length=seq_lens, @@ -253,7 +277,7 @@ class CTCLossTest(test.TestCase): v = [1.0] with self.session(use_gpu=False): - loss = ctc_ops.ctc_loss( + loss = _ctc_loss_v2( inputs=inputs_t, labels=labels, sequence_length=seq_lens) # Taking ths second gradient should fail, since it is not # yet supported. @@ -272,7 +296,519 @@ class CTCLossTest(test.TestCase): with self.session(use_gpu=False) as sess: with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, "batch_size must not be 0"): - sess.run(ctc_ops.ctc_loss(labels, inputs, sequence_lengths)) + sess.run(_ctc_loss_v2(labels, inputs, sequence_lengths)) + + +class CTCLossTestV2(test.TestCase): + + def testCtcLossV2(self): + random_seed.set_random_seed(5) + + batch_size = 8 + num_labels = 6 + max_label_length = 5 + num_frames = 12 + + labels = random_ops.random_uniform( + [batch_size, max_label_length], minval=1, maxval=num_labels, + dtype=dtypes.int64) + logits = random_ops.random_uniform([num_frames, batch_size, num_labels]) + + label_length = random_ops.random_uniform( + [batch_size], minval=2, maxval=max_label_length, dtype=dtypes.int64) + label_mask = array_ops.sequence_mask( + label_length, maxlen=max_label_length, dtype=label_length.dtype) + labels *= label_mask + logit_length = [num_frames] * batch_size + + ref_loss = ctc_ops.ctc_loss_v2( + labels=labels, + logits=logits, + label_length=label_length, + logit_length=logit_length) + ref_grad = gradients_impl.gradients(ref_loss, [logits]) + + sparse_labels = ctc_ops.dense_labels_to_sparse(labels, label_length) + + def assert_same_loss_and_grads(loss): + with self.cached_session() as sess: + self.assertAllClose(*sess.run([loss, ref_loss])) + grad = gradients_impl.gradients(loss, [logits]) + self.assertAllClose(*sess.run([grad, ref_grad]), rtol=2e-06, atol=2e-06) + + assert_same_loss_and_grads( + ctc_ops.ctc_loss_v2( + labels=sparse_labels, + logits=logits, + label_length=label_length, + logit_length=logit_length, + blank_index=0)) + + def testCtcLossDenseIsSameAsCtcLoss(self): + with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): + random_seed.set_random_seed(5) + + batch_size = 8 + num_labels = 6 + label_length = 5 + num_frames = 12 + logits = random_ops.random_uniform([num_frames, batch_size, num_labels]) + labels = random_ops.random_uniform( + [batch_size, label_length], minval=1, maxval=num_labels, + dtype=dtypes.int64) + + label_lengths = random_ops.random_uniform( + [batch_size], minval=2, maxval=label_length, dtype=dtypes.int64) + label_mask = array_ops.sequence_mask( + label_lengths, maxlen=label_length, dtype=label_lengths.dtype) + labels *= label_mask + + logit_lengths = [num_frames] * batch_size + + ctc_loss = ctc_ops.ctc_loss_dense( + labels=labels, + logits=logits, + label_length=label_lengths, + logit_length=logit_lengths) + ctc_loss_grads = gradients_impl.gradients(ctc_loss, [logits])[0] + + # Shift labels down by one (move blank from 0 to num_labels -1) + tf_ctc_loss_labels = math_ops.cast(labels, dtypes.int32) - 1 + tf_nn_ctc_logits = array_ops.concat([ + logits[:, :, 1:], + logits[:, :, 0:1], + ], axis=2) + + tf_ctc_loss_labels = ctc_ops.dense_labels_to_sparse( + tf_ctc_loss_labels, label_lengths) + + tf_nn_ctc_loss = ctc_ops.ctc_loss( + labels=tf_ctc_loss_labels, + inputs=tf_nn_ctc_logits, + sequence_length=logit_lengths, + time_major=True) + tf_nn_ctc_grads = gradients_impl.gradients(tf_nn_ctc_loss, [logits])[0] + + with self.cached_session() as sess: + for _ in range(32): + self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, atol=2e-06) + + def testCtcLossDenseUniqueFastPathIsSameAsCtcLoss(self): + random_seed.set_random_seed(5) + + batch_size = 8 + num_labels = 6 + label_length = 5 + num_frames = 12 + logits = random_ops.random_uniform([num_frames, batch_size, num_labels]) + labels = random_ops.random_uniform( + [batch_size, label_length], minval=1, maxval=num_labels, + dtype=dtypes.int64) + + label_lengths = random_ops.random_uniform( + [batch_size], minval=2, maxval=label_length, dtype=dtypes.int64) + label_mask = array_ops.sequence_mask( + label_lengths, maxlen=label_length, dtype=label_lengths.dtype) + labels *= label_mask + + logit_lengths = [num_frames] * batch_size + + ctc_loss = ctc_ops.ctc_loss_dense( + labels=labels, + logits=logits, + label_length=label_lengths, + logit_length=logit_lengths, + unique=ctc_ops.ctc_unique_labels(labels)) + ctc_loss_grads = gradients_impl.gradients(ctc_loss, [logits])[0] + + # Shift labels down by one (move blank from 0 to num_labels -1) + tf_ctc_loss_labels = math_ops.cast(labels, dtypes.int32) - 1 + tf_nn_ctc_logits = array_ops.concat([ + logits[:, :, 1:], + logits[:, :, 0:1], + ], axis=2) + + tf_ctc_loss_labels = ctc_ops.dense_labels_to_sparse( + tf_ctc_loss_labels, label_lengths) + + tf_nn_ctc_loss = ctc_ops.ctc_loss( + labels=tf_ctc_loss_labels, + inputs=tf_nn_ctc_logits, + sequence_length=logit_lengths, + time_major=True) + tf_nn_ctc_grads = gradients_impl.gradients(tf_nn_ctc_loss, [logits])[0] + + with self.cached_session() as sess: + for _ in range(32): + self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, atol=2e-06) + + def testCtcLossDenseWithBlankIndexIsSameAsCtcLoss(self): + random_seed.set_random_seed(5) + + batch_size = 8 + num_labels = 6 + label_length = 5 + num_frames = 12 + logits = random_ops.random_uniform([num_frames, batch_size, num_labels]) + labels = random_ops.random_uniform( + [batch_size, label_length], minval=0, maxval=num_labels-1, + dtype=dtypes.int64) + + label_lengths = random_ops.random_uniform( + [batch_size], minval=2, maxval=label_length, dtype=dtypes.int64) + label_mask = array_ops.sequence_mask( + label_lengths, maxlen=label_length, dtype=label_lengths.dtype) + labels *= label_mask + + logit_lengths = [num_frames] * batch_size + + tf_ctc_loss_labels = math_ops.cast(labels, dtypes.int32) + tf_ctc_loss_labels = ctc_ops.dense_labels_to_sparse( + tf_ctc_loss_labels, label_lengths) + + tf_nn_ctc_loss = ctc_ops.ctc_loss( + labels=tf_ctc_loss_labels, + inputs=logits, + sequence_length=logit_lengths, + time_major=True) + tf_nn_ctc_grads = gradients_impl.gradients(tf_nn_ctc_loss, [logits])[0] + + # Shift the blank logits/labels to be somewhere in the middle. + blank_index = 2 + shifted_logits = array_ops.concat([ + logits[:, :, :blank_index], + logits[:, :, -1:], + logits[:, :, blank_index:-1], + ], axis=2) + shifted_labels = array_ops.where(labels < blank_index, labels, labels + 1) + + ctc_loss = ctc_ops.ctc_loss_dense( + labels=shifted_labels, + logits=shifted_logits, + label_length=label_lengths, + logit_length=logit_lengths, + blank_index=blank_index) + ctc_loss_grads = gradients_impl.gradients(ctc_loss, [logits])[0] + + with self.cached_session() as sess: + for _ in range(32): + self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, atol=2e-06) + + def testCtcLossDenseWithNegativeBlankIndexIsSameAsCtcLoss(self): + with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): + random_seed.set_random_seed(5) + + batch_size = 8 + num_labels = 6 + label_length = 5 + num_frames = 12 + logits = random_ops.random_uniform([num_frames, batch_size, num_labels]) + labels = random_ops.random_uniform( + [batch_size, label_length], minval=0, maxval=num_labels-1, + dtype=dtypes.int64) + + label_lengths = random_ops.random_uniform( + [batch_size], minval=2, maxval=label_length, dtype=dtypes.int64) + label_mask = array_ops.sequence_mask( + label_lengths, maxlen=label_length, dtype=label_lengths.dtype) + labels *= label_mask + + logit_lengths = [num_frames] * batch_size + + ctc_loss = ctc_ops.ctc_loss_dense( + labels=labels, + logits=logits, + label_length=label_lengths, + logit_length=logit_lengths, + blank_index=-1) + ctc_loss_grads = gradients_impl.gradients(ctc_loss, [logits])[0] + + tf_ctc_loss_labels = math_ops.cast(labels, dtypes.int32) + tf_ctc_loss_labels = ctc_ops.dense_labels_to_sparse( + tf_ctc_loss_labels, label_lengths) + + tf_nn_ctc_loss = ctc_ops.ctc_loss( + labels=tf_ctc_loss_labels, + inputs=logits, + sequence_length=logit_lengths, + time_major=True) + tf_nn_ctc_grads = gradients_impl.gradients(tf_nn_ctc_loss, [logits])[0] + + with self.cached_session() as sess: + for _ in range(32): + self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, atol=2e-06) + + def testCollapseRepeated(self): + collapsed, new_seq_lengths = ctc_ops.collapse_repeated( + labels=[[1, 3, 3, 3, 0], + [1, 4, 4, 4, 0], + [4, 2, 2, 9, 4]], + seq_length=[4, 5, 5]) + self.assertAllEqual(new_seq_lengths, [2, 3, 4]) + self.assertAllEqual( + collapsed, + [[1, 3, 0, 0], + [1, 4, 0, 0], + [4, 2, 9, 4]]) + + def testCollapseRepeatedPreservesDtypes(self): + collapsed, new_seq_lengths = ctc_ops.collapse_repeated( + labels=constant_op.constant( + [[1, 3, 3, 3, 0], + [1, 4, 4, 4, 0], + [4, 2, 2, 9, 4]], + dtype=dtypes.int64), + seq_length=constant_op.constant([4, 5, 5], dtype=dtypes.int64)) + self.assertEqual(new_seq_lengths.dtype, dtypes.int64) + self.assertEqual(collapsed.dtype, dtypes.int64) + self.assertAllEqual(new_seq_lengths, [2, 3, 4]) + self.assertAllEqual( + collapsed, + [[1, 3, 0, 0], + [1, 4, 0, 0], + [4, 2, 9, 4]]) + + def testCollapseRepeatedExtraPadding(self): + collapsed, new_seq_lengths = ctc_ops.collapse_repeated( + labels=[[1, 3, 3, 3, 0, 0, 0], + [1, 4, 4, 4, 0, 1, 2], + [4, 2, 2, 9, 4, 0, 0]], + seq_length=[4, 5, 5]) + self.assertAllEqual(new_seq_lengths, [2, 3, 4]) + self.assertAllEqual( + collapsed, + [[1, 3, 0, 0], + [1, 4, 0, 0], + [4, 2, 9, 4]]) + + def testCollapseRepeatedFrontRepeats(self): + collapsed, new_seq_lengths = ctc_ops.collapse_repeated( + labels=[[1, 1, 1, 2, 2], + [1, 1, 1, 2, 2], + [1, 1, 1, 2, 2]], + seq_length=[5, 4, 3]) + self.assertAllEqual(new_seq_lengths, [2, 2, 1]) + self.assertAllEqual( + collapsed, + [[1, 2], + [1, 2], + [1, 0]]) + + def testCollapseRepeatedAllLabelsTheSame(self): + collapsed, new_seq_lengths = ctc_ops.collapse_repeated( + labels=[[1, 1, 1, 1, 1], + [1, 1, 1, 1, 1], + [1, 1, 1, 1, 1]], + seq_length=[4, 5, 1]) + self.assertAllEqual(new_seq_lengths, [1, 1, 1]) + self.assertAllEqual( + collapsed, + [[1], + [1], + [1]]) + + def testDenseSequencesToSparse(self): + labels = [[1, 3, 3, 3, 0], + [1, 4, 4, 4, 0], + [4, 2, 2, 9, 4]] + length = [4, 5, 5] + sparse = ctc_ops.dense_labels_to_sparse(labels, length) + new_dense = sparse_ops.sparse_tensor_to_dense(sparse) + + self.assertAllEqual(labels, new_dense) + + padded_labels = [[1, 3, 3, 3, 0, 0, 0, 0], + [1, 4, 4, 4, 0, 0, 0, 0], + [4, 2, 2, 9, 4, 0, 0, 0]] + length = [4, 5, 5] + sparse = ctc_ops.dense_labels_to_sparse(padded_labels, length) + padded_dense = sparse_ops.sparse_tensor_to_dense(sparse) + + self.assertAllEqual(padded_dense, new_dense) + + def testUnique(self): + labels = [ + [3, 4, 4, 3], + [1, 1, 1, 0], + ] + unique, idx = ctc_ops.ctc_unique_labels(labels) + self.assertAllEqual([ + [3, 4, 0, 0], + [1, 0, 0, 0], + ], unique) + self.assertAllEqual([ + [0, 1, 1, 0], + [0, 0, 0, 1], + ], idx) + + def testSumStates(self): + idx = [ + [0, 1, 0, 1], + [0, 0, 0, 1], + ] + states = math_ops.log([ + [[1.0, 2.0, 3.0, 4.0], + [5.0, 6.0, 7.0, 8.0]], + [[0.1, 0.2, 0.3, 0.4], + [0.5, 0.6, 0.7, 0.8]], + ]) + sum_of_states = math_ops.exp(ctc_ops._sum_states(idx, states)) + self.assertAllClose([ + [[4.0, 6.0, 0.0, 0.0], + [18.0, 8.0, 0.0, 0.0]], + [[0.4, 0.6, 0.0, 0.0], + [1.8, 0.8, 0.0, 0.0]] + ], sum_of_states) + + def testStateToOlabel(self): + labels = [ + [3, 4, 3, 4], + [1, 1, 1, 0], + ] + num_labels = 8 + + # 3 frames, 2 batch, 10 states (5 label, 5 blank). + states = [ + [[0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20], + [0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30]], + [[1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0], + [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0]], + [[11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0], + [21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0]], + ] + labels = ops.convert_to_tensor(labels) + states = math_ops.log(states) + olabel = ctc_ops._state_to_olabel(labels, num_labels, states) + olabel = math_ops.exp(olabel) + blank = olabel[:, :, 0] + self.assertAllClose(blank, [ + [0.16 + 0.17 + 0.18 + 0.19 + 0.20, + 0.26 + 0.27 + 0.28 + 0.29 + 0.30], + [1.6 + 1.7 + 1.8 + 1.9 + 2.0, + 2.6 + 2.7 + 2.8 + 2.9 + 3.0], + [16.0 + 17.0 + 18.0 + 19.0 + 20.0, + 26.0 + 27.0 + 28.0 + 29.0 + 30.0] + ]) + self.assertAllClose(olabel[:, :, 1:], [ + [[0.0, 0.0, 0.12 + 0.14, 0.13 + 0.15, 0.0, 0.0, 0.0], + [0.22 + 0.23 + 0.24, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + [[0.0, 0.0, 1.2 + 1.4, 1.3 + 1.5, 0.0, 0.0, 0.0], + [2.2 + 2.3 + 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + [[0.0, 0.0, 12.0 + 14.0, 13.0 + 15.0, 0.0, 0.0, 0.0], + [22.0 + 23.0 + 24.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + ]) + + def testStateToOlabelUnique(self): + labels = [ + [3, 4, 3, 4], + [1, 1, 1, 0], + ] + num_labels = 8 + + # 3 frames, 2 batch, 10 states (5 label, 5 blank). + states = [ + [[0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20], + [0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30]], + [[1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0], + [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0]], + [[11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0], + [21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0]], + ] + labels = ops.convert_to_tensor(labels) + states = math_ops.log(states) + olabel = ctc_ops._state_to_olabel_unique( + labels, num_labels, states, ctc_ops.ctc_unique_labels(labels)) + olabel = math_ops.exp(olabel) + blank = olabel[:, :, 0] + self.assertAllClose(blank, [ + [0.16 + 0.17 + 0.18 + 0.19 + 0.20, + 0.26 + 0.27 + 0.28 + 0.29 + 0.30], + [1.6 + 1.7 + 1.8 + 1.9 + 2.0, + 2.6 + 2.7 + 2.8 + 2.9 + 3.0], + [16.0 + 17.0 + 18.0 + 19.0 + 20.0, + 26.0 + 27.0 + 28.0 + 29.0 + 30.0]]) + self.assertAllClose(olabel[:, :, 1:], [ + [[0.0, 0.0, 0.12 + 0.14, 0.13 + 0.15, 0.0, 0.0, 0.0], + [0.22 + 0.23 + 0.24, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + [[0.0, 0.0, 1.2 + 1.4, 1.3 + 1.5, 0.0, 0.0, 0.0], + [2.2 + 2.3 + 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + [[0.0, 0.0, 12.0 + 14.0, 13.0 + 15.0, 0.0, 0.0, 0.0], + [22.0 + 23.0 + 24.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], + ]) + + def testScan(self): + with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): + out = ctc_ops._scan( + lambda accum, elem: accum + elem, + constant_op.constant([1.0, 2.0, 3.0]), 23.0) + self.assertAllEqual([24.0, 26.0, 29.0], out) + + out = ctc_ops._scan( + lambda a, e: a + e, + constant_op.constant([1.0, 2.0, 3.0]), 23.0, + inclusive=True) + self.assertAllEqual([23.0, 24.0, 26.0, 29.0], out) + + out = ctc_ops._scan( + lambda a, e: a + e, + constant_op.constant([1.0, 2.0, 3.0]), 23.0, + reverse=True) + self.assertAllEqual([29.0, 28.0, 26.0], out) + + out = ctc_ops._scan( + lambda a, e: a + e, + constant_op.constant([1.0, 2.0, 3.0]), 23.0, + reverse=True, + inclusive=True) + self.assertAllEqual([29.0, 28.0, 26.0, 23.0], out) + + out = ctc_ops._scan( + lambda a, e: a + e, + constant_op.constant([[0.0, 1.0], [2.0, 3.0], [4.0, 5.0]]), + constant_op.constant([23.0, 24.0])) + self.assertAllEqual([[23.0, 25.0], [25.0, 28.0], [29.0, 33.0]], out) + + def testScanCapturesVariables(self): + with self.cached_session() as sess: + x = random_ops.random_uniform([]) + fn = lambda accum, elem: accum + x * elem + out = ctc_ops._scan(fn, constant_op.constant([0.0, 1.0, 2.0]), 23.0) + self.assertAllEqual(*sess.run([ + [23.0 + x * 0.0, 23.0 + x * 1.0, 23.0 + x * 3.0], out + ])) + + def testScanMultipleAccumulators(self): + with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): + def fn(accum, elem): + accum_a, accum_b = accum + return accum_a + elem, accum_b * elem + out = ctc_ops._scan( + fn, constant_op.constant([1.0, 2.0, 3.0]), + (23.0, constant_op.constant([1.0, 2.0]))) + a, b = out + self.assertAllEqual([24.0, 26.0, 29.0], a) + self.assertAllEqual([[1.0, 2.0], [2.0, 4.0], [6.0, 12.0]], b) + + def testScanMultipleElements(self): + with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): + def fn(accum, elem): + elem_a, elem_b = elem + return accum + (elem_a * elem_b) + elems_a = constant_op.constant([1.0, 2.0, 3.0]) + elems_b = constant_op.constant([[1.0, 2.0], [2.0, 3.0], [3.0, 4.0]]) + out = ctc_ops._scan( + fn, (elems_a, elems_b), + initial=constant_op.constant([0.0, 0.0])) + self.assertAllEqual( + [[1.0, 2.0], [5.0, 8.0], [14.0, 20.0]], out) if __name__ == "__main__": test.main() diff --git a/tensorflow/python/ops/ctc_ops.py b/tensorflow/python/ops/ctc_ops.py index e1071afd8e..3a7eb9355a 100644 --- a/tensorflow/python/ops/ctc_ops.py +++ b/tensorflow/python/ops/ctc_ops.py @@ -19,17 +19,27 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import function from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.ops import array_ops +from tensorflow.python.ops import functional_ops from tensorflow.python.ops import gen_ctc_ops +from tensorflow.python.ops import inplace_ops +from tensorflow.python.ops import linalg_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import nn_ops +from tensorflow.python.ops import sparse_ops from tensorflow.python.ops.nn_grad import _BroadcastMul +from tensorflow.python.util import nest from tensorflow.python.util.tf_export import tf_export # pylint: disable=protected-access, invalid-name -@tf_export("nn.ctc_loss") +@tf_export(v1=["nn.ctc_loss"]) def ctc_loss(labels, inputs, sequence_length, preprocess_collapse_repeated=False, ctc_merge_repeated=True, @@ -336,6 +346,785 @@ def ctc_beam_search_decoder_v2(inputs, sequence_length, beam_width=100, ops.NotDifferentiable("CTCGreedyDecoder") +ops.NotDifferentiable("CTCBeamSearchDecoder") -ops.NotDifferentiable("CTCBeamSearchDecoder") +def _ctc_state_trans(label_seq): + """Compute CTC alignment model transition matrix. + + Args: + label_seq: tensor of shape [batch_size, max_seq_length] + + Returns: + tensor of shape [batch_size, states, states] with a state transition matrix + computed for each sequence of the batch. + """ + + with ops.name_scope("ctc_state_trans"): + label_seq = ops.convert_to_tensor(label_seq, name="label_seq") + batch_size = _get_dim(label_seq, 0) + num_labels = _get_dim(label_seq, 1) + + num_label_states = num_labels + 1 + num_states = 2 * num_label_states + + label_states = math_ops.range(num_label_states) + blank_states = label_states + num_label_states + + # Start state to first label. + start_to_label = [[1, 0]] + + # Blank to label transitions. + blank_to_label = array_ops.stack([label_states[1:], blank_states[:-1]], 1) + + # Label to blank transitions. + label_to_blank = array_ops.stack([blank_states, label_states], 1) + + # Scatter transitions that don't depend on sequence. + indices = array_ops.concat( + [start_to_label, blank_to_label, label_to_blank], 0) + values = array_ops.ones([_get_dim(indices, 0)]) + trans = array_ops.scatter_nd( + indices, values, shape=[num_states, num_states]) + trans += linalg_ops.eye(num_states) # Self-loops. + + # Label to label transitions. Disallow transitions between repeated labels + # with no blank state in between. + batch_idx = array_ops.zeros_like(label_states[2:]) + indices = array_ops.stack( + [batch_idx, label_states[2:], label_states[1:-1]], 1) + indices = array_ops.tile( + array_ops.expand_dims(indices, 0), [batch_size, 1, 1]) + batch_idx = array_ops.expand_dims(math_ops.range(batch_size), 1) * [1, 0, 0] + indices += array_ops.expand_dims(batch_idx, 1) + repeats = math_ops.equal(label_seq[:, :-1], label_seq[:, 1:]) + values = 1.0 - math_ops.cast(repeats, dtypes.float32) + batched_shape = [batch_size, num_states, num_states] + label_to_label = array_ops.scatter_nd(indices, values, batched_shape) + + return array_ops.expand_dims(trans, 0) + label_to_label + + +def ctc_state_log_probs(seq_lengths, max_seq_length): + """Computes CTC alignment initial and final state log probabilities. + + Create the initial/final state values directly as log values to avoid + having to take a float64 log on tpu (which does not exist). + + Args: + seq_lengths: int tensor of shape [batch_size], seq lengths in the batch. + max_seq_length: int, max sequence length possible. + + Returns: + initial_state_log_probs, final_state_log_probs + """ + + batch_size = _get_dim(seq_lengths, 0) + num_label_states = max_seq_length + 1 + num_duration_states = 2 + num_states = num_duration_states * num_label_states + log_0 = math_ops.cast( + math_ops.log(math_ops.cast(0, dtypes.float64) + 1e-307), + dtypes.float32) + + initial_state_log_probs = array_ops.one_hot( + indices=array_ops.zeros([batch_size], dtype=dtypes.int32), + depth=num_states, + on_value=0.0, + off_value=log_0, axis=1) + + label_final_state_mask = array_ops.one_hot( + seq_lengths, depth=num_label_states, axis=0) + duration_final_state_mask = array_ops.ones( + [num_duration_states, 1, batch_size]) + final_state_mask = duration_final_state_mask * label_final_state_mask + final_state_log_probs = (1.0 - final_state_mask) * log_0 + final_state_log_probs = array_ops.reshape( + final_state_log_probs, [num_states, batch_size]) + + return initial_state_log_probs, array_ops.transpose(final_state_log_probs) + + +def _ilabel_to_state(labels, num_labels, ilabel_log_probs): + """Project ilabel log probs to state log probs.""" + + num_label_states = _get_dim(labels, 1) + blank = ilabel_log_probs[:, :, :1] + blank = array_ops.tile(blank, [1, 1, num_label_states + 1]) + one_hot = array_ops.one_hot(labels, depth=num_labels) + one_hot = array_ops.expand_dims(one_hot, axis=0) + ilabel_log_probs = array_ops.expand_dims(ilabel_log_probs, axis=2) + state_log_probs = math_ops.reduce_sum(ilabel_log_probs * one_hot, axis=3) + state_log_probs = array_ops.concat([state_log_probs, blank], axis=2) + return array_ops.pad( + state_log_probs, [[0, 0], [0, 0], [1, 0]], + constant_values=math_ops.log(0.0)) + + +def _state_to_olabel(labels, num_labels, states): + """Sum state log probs to ilabel log probs.""" + + num_label_states = _get_dim(labels, 1) + 1 + label_states = states[:, :, 1:num_label_states] + blank_states = states[:, :, num_label_states:] + one_hot = array_ops.one_hot( + labels - 1, depth=(num_labels - 1), + on_value=0.0, off_value=math_ops.log(0.0)) + one_hot = array_ops.expand_dims(one_hot, axis=0) + label_states = array_ops.expand_dims(label_states, axis=3) + label_olabels = math_ops.reduce_logsumexp(label_states + one_hot, axis=2) + blank_olabels = math_ops.reduce_logsumexp( + blank_states, axis=2, keepdims=True) + return array_ops.concat([blank_olabels, label_olabels], axis=-1) + + +# pylint: disable=redefined-outer-name +def _state_to_olabel_unique(labels, num_labels, states, unique): + """Sum state log probs to ilabel log probs using unique label indices.""" + + num_label_states = _get_dim(labels, 1) + 1 + label_states = states[:, :, 1:num_label_states] + blank_states = states[:, :, num_label_states:] + + unique_y, unique_idx = unique + mul_reduce = _sum_states(unique_idx, label_states) + + num_frames = states.shape[0] + batch_size = states.shape[1] + num_states = num_label_states - 1 + batch_state_major = array_ops.transpose(mul_reduce, perm=[1, 2, 0]) + batch_state_major = array_ops.reshape( + batch_state_major, [batch_size * num_states, num_frames]) + batch_offset = math_ops.range(batch_size, dtype=unique_y.dtype) * num_labels + indices = unique_y + array_ops.expand_dims(batch_offset, axis=-1) + indices = array_ops.reshape(indices, [-1, 1]) + scatter = array_ops.scatter_nd( + indices=indices, + updates=batch_state_major, + shape=[batch_size * num_labels, num_frames]) + scatter = array_ops.reshape(scatter, [batch_size, num_labels, num_frames]) + scatter = array_ops.where( + math_ops.equal(scatter, 0.0), + array_ops.fill(array_ops.shape(scatter), math_ops.log(0.0)), + scatter) + label_olabels = array_ops.transpose(scatter, [2, 0, 1]) + label_olabels = label_olabels[:, :, 1:] + + blank_olabels = math_ops.reduce_logsumexp( + blank_states, axis=2, keepdims=True) + + return array_ops.concat([blank_olabels, label_olabels], axis=-1) + + +def ctc_loss_and_grad(logits, labels, label_length, logit_length, unique=None): + """Computes the CTC loss and gradients. + + Most users will want fwd_bwd.ctc_loss + + This function returns the computed gradient, it does not have a gradient + of its own defined. + + Args: + logits: tensor of shape [frames, batch_size, num_labels] + labels: tensor of shape [batch_size, max_label_seq_length] + label_length: tensor of shape [batch_size] + Length of reference label sequence in labels. + logit_length: tensor of shape [batch_size] + Length of input sequence in logits. + unique: (optional) unique label indices as computed by unique(labels) + If supplied, enables an implementation that is faster and more memory + efficient on TPU. + + Returns: + loss: tensor of shape [batch_size] + gradient: tensor of shape [frames, batch_size, num_labels] + """ + + num_labels = _get_dim(logits, 2) + max_label_seq_length = _get_dim(labels, 1) + + ilabel_log_probs = nn_ops.log_softmax(logits) + state_log_probs = _ilabel_to_state(labels, num_labels, ilabel_log_probs) + state_trans_probs = _ctc_state_trans(labels) + initial_state_log_probs, final_state_log_probs = ctc_state_log_probs( + label_length, max_label_seq_length) + fwd_bwd_log_probs, log_likelihood = _forward_backward_log( + state_trans_log_probs=math_ops.log(state_trans_probs), + initial_state_log_probs=initial_state_log_probs, + final_state_log_probs=final_state_log_probs, + observed_log_probs=state_log_probs, + sequence_length=logit_length) + + if unique: + olabel_log_probs = _state_to_olabel_unique( + labels, num_labels, fwd_bwd_log_probs, unique) + else: + olabel_log_probs = _state_to_olabel(labels, num_labels, fwd_bwd_log_probs) + + grad = math_ops.exp(ilabel_log_probs) - math_ops.exp(olabel_log_probs) + loss = -log_likelihood + return loss, grad + + +def _ctc_loss_grad(op, grad_loss, _): + grad = op.outputs[1] + grad = [array_ops.reshape(grad_loss, [1, -1, 1]) * grad] + grad += [None] * (len(op.inputs) - len(grad)) + return grad + + +def _ctc_loss_shape(op): + return [op.inputs[2].get_shape(), op.inputs[0].get_shape()] + + +@tf_export("nn.ctc_loss", v1=["nn.ctc_loss_v2"]) +def ctc_loss_v2(labels, logits, label_length, logit_length, + logits_time_major=True, unique=None, + blank_index=None, name=None): + """Computes CTC (Connectionist Temporal Classification) loss. + + This op implements the CTC loss as presented in the article: + + [A. Graves, S. Fernandez, F. Gomez, J. Schmidhuber. + Connectionist Temporal Classification: Labeling Unsegmented Sequence Data + with Recurrent Neural Networks. ICML 2006, Pittsburgh, USA, + pp. 369-376.](http://www.cs.toronto.edu/~graves/icml_2006.pdf) + + Notes: + - Same as the "Classic CTC" in TensorFlow 1.x's tf.nn.ctc_loss setting of + preprocess_collapse_repeated=False, ctc_merge_repeated=True + - Labels may be supplied as either a dense, zero-padded tensor with a + vector of label sequence lengths OR as a SparseTensor. + - On TPU and GPU: + - Only dense padded labels are supported. + - On CPU: + - Caller may use SparseTensor or dense padded labels but calling with + a SparseTensor will be significantly faster. + - Default blank label is 0 rather num_classes - 1, unless overridden by + blank_index. + + Args: + labels: tensor of shape [batch_size, max_label_seq_length] or SparseTensor + logits: tensor of shape [frames, batch_size, num_labels], + if logits_time_major == False, shape is [batch_size, frames, num_labels]. + label_length: tensor of shape [batch_size], None if labels is SparseTensor + Length of reference label sequence in labels. + logit_length: tensor of shape [batch_size] + Length of input sequence in logits. + logits_time_major: (optional) If True (default), logits is shaped + [time, batch, logits]. If False, shape is [batch, time, logits] + unique: (optional) Unique label indices as computed by + ctc_unique_labels(labels). If supplied, enable a faster, memory + efficient implementation on TPU. + blank_index: (optional) Set the class index to use for the blank label. + Negative values will start from num_classes, ie, -1 will reproduce the + ctc_loss behavior of using num_classes - 1 for the blank symbol. + There is some memory/performance overhead to switching from the default + of 0 as an additional shifted copy of the logits may be created. + name: A name for this `Op`. Defaults to "ctc_loss_dense". + + Returns: + loss: tensor of shape [batch_size], negative log probabilities. + """ + if isinstance(labels, sparse_tensor.SparseTensor): + if blank_index is None: + raise ValueError( + "blank_index must be given when using SparseTensor labels.") + + if blank_index < 0: + blank_index += _get_dim(logits, 2) + + if blank_index != _get_dim(logits, 2) - 1: + logits = array_ops.concat([ + logits[:, :, :blank_index], + logits[:, :, blank_index+1:], + logits[:, :, blank_index:blank_index+1], + ], axis=2) + labels = sparse_tensor.SparseTensor( + labels.indices, + array_ops.where(labels.values < blank_index, + labels.values, + labels.values - 1), + labels.dense_shape) + + return ctc_loss(labels=labels, + inputs=logits, + sequence_length=logit_length, + time_major=logits_time_major) + + if blank_index is None: + blank_index = 0 + + return ctc_loss_dense(labels=labels, + logits=logits, + label_length=label_length, + logit_length=logit_length, + logits_time_major=logits_time_major, + unique=unique, + blank_index=blank_index, + name=name) + + +def ctc_loss_dense(labels, logits, label_length, logit_length, + logits_time_major=True, unique=None, + blank_index=0, name=None): + """Computes CTC (Connectionist Temporal Classification) loss. + + This op implements the CTC loss as presented in the article: + + [A. Graves, S. Fernandez, F. Gomez, J. Schmidhuber. + Connectionist Temporal Classification: Labeling Unsegmented Sequence Data + with Recurrent Neural Networks. ICML 2006, Pittsburgh, USA, + pp. 369-376.](http://www.cs.toronto.edu/~graves/icml_2006.pdf) + + Using the batched forward backward algorithm described in: + + [Sim, K. C., Narayanan, A., Bagby, T., Sainath, T. N., & Bacchiani, M. + Improving the efficiency of forward-backward algorithm using batched + computation in TensorFlow. + Automatic Speech Recognition and Understanding Workshop (ASRU), + 2017 IEEE (pp. 258-264). + ](https://ieeexplore.ieee.org/iel7/8260578/8268903/08268944.pdf) + + Notes: + Significant differences from tf.nn.ctc_loss: + Supports GPU and TPU (tf.nn.ctc_loss supports CPU only): + For batched operations, GPU and TPU are significantly faster than using + ctc_loss on CPU. + This implementation runs on CPU, but significantly slower than ctc_loss. + Blank label is 0 rather num_classes - 1, unless overridden by blank_index. + Logits and labels are dense arrays with padding rather than SparseTensor. + The only mode supported is the same as: + preprocess_collapse_repeated=False, ctc_merge_repeated=True + To collapse labels, the caller can preprocess label sequence first. + + The dense implementation supports both CPU, GPU and TPU. A fast path is + provided that significantly improves memory use for large vocabulary if the + caller preprocesses label sequences to get unique label indices on the CPU + (eg. in the data input pipeline) using ctc_ops.unique and simplies this in + the optional "unique" kwarg. This is especially useful for TPU and GPU but + also works with if used on CPU. + + Args: + labels: tensor of shape [batch_size, max_label_seq_length] + logits: tensor of shape [frames, batch_size, num_labels], + if logits_time_major == False, shape is [batch_size, frames, num_labels]. + label_length: tensor of shape [batch_size] + Length of reference label sequence in labels. + logit_length: tensor of shape [batch_size] + Length of input sequence in logits. + logits_time_major: (optional) If True (default), logits is shaped + [time, batch, logits]. If False, shape is [batch, time, logits] + unique: (optional) Unique label indices as computed by unique(labels). + If supplied, enable a faster, memory efficient implementation on TPU. + blank_index: (optional) Set the class index to use for the blank label. + Negative values will start from num_classes, ie, -1 will reproduce the + ctc_loss behavior of using num_classes - 1 for the blank symbol. + There is some memory/performance overhead to switching from the default + of 0 as an additional shifted copy of the logits may be created. + name: A name for this `Op`. Defaults to "ctc_loss_dense". + + Returns: + loss: tensor of shape [batch_size], negative log probabilities. + """ + + with ops.name_scope(name, "ctc_loss_dense", + [logits, labels, label_length, logit_length]): + logits = ops.convert_to_tensor(logits, name="logits") + labels = ops.convert_to_tensor(labels, name="labels") + label_length = ops.convert_to_tensor(label_length, name="label_length") + logit_length = ops.convert_to_tensor(logit_length, name="logit_length") + + if not logits_time_major: + logits = array_ops.transpose(logits, perm=[1, 0, 2]) + + if blank_index != 0: + if blank_index < 0: + blank_index += _get_dim(logits, 2) + logits = array_ops.concat([ + logits[:, :, blank_index:blank_index+1], + logits[:, :, :blank_index], + logits[:, :, blank_index+1:], + ], axis=2) + labels = array_ops.where(labels < blank_index, labels + 1, labels) + + args = [logits, labels, label_length, logit_length] + + if unique: + unique_y, unique_idx = unique + args.extend([unique_y, unique_idx]) + + # TODO(tombagby): Update to tfe.defun + @function.Defun(*[x.dtype for x in args], + python_grad_func=_ctc_loss_grad, + shape_func=_ctc_loss_shape) + def compute_ctc_loss(logits_t, labels_t, label_length_t, logit_length_t, + *unique_t): + """Compute CTC loss.""" + logits_t.set_shape(logits.shape) + labels_t.set_shape(labels.shape) + label_length_t.set_shape(label_length.shape) + logit_length_t.set_shape(logit_length.shape) + kwargs = dict( + logits=logits_t, + labels=labels_t, + label_length=label_length_t, + logit_length=logit_length_t) + if unique_t: + kwargs["unique"] = unique_t + return ctc_loss_and_grad(**kwargs) + + return compute_ctc_loss(*args)[0] + + +@tf_export("nn.collapse_repeated") +def collapse_repeated(labels, seq_length, name=None): + """Merge repeated labels into single labels. + + Args: + labels: Tensor of shape (batch, max value in seq_length) + seq_length: Tensor of shape (batch), sequence length of each batch element. + name: A name for this `Op`. Defaults to "collapse_repeated_labels". + + Returns: + tuple of Tensor of shape (batch, max_seq_length) with repeated labels + collapsed and padded to max_seq_length, eg: + [[A, A, B, B, A], + [A, B, C, D, E]] => [[A, B, A, 0, 0], + [A, B, C, D, E]] + and int tensor of shape [batch] with new sequence lengths. + """ + + with ops.name_scope(name, "collapse_repeated_labels", + [labels, seq_length]): + labels = ops.convert_to_tensor(labels, name="labels") + seq_length = ops.convert_to_tensor(seq_length, name="seq_length") + + # Mask labels that don't equal previous label. + label_mask = array_ops.concat( + [array_ops.ones_like(labels[:, :1], dtypes.bool), + math_ops.not_equal(labels[:, 1:], labels[:, :-1])], + axis=1) + + # Filter labels that aren't in the original sequence. + maxlen = _get_dim(labels, 1) + seq_mask = array_ops.sequence_mask(seq_length, maxlen=maxlen) + label_mask = math_ops.logical_and(label_mask, seq_mask) + + # Count masks for new sequence lengths. + new_seq_len = math_ops.reduce_sum( + math_ops.cast(label_mask, dtypes.int32), axis=1) + + # Mask indexes based on sequence length mask. + new_maxlen = math_ops.reduce_max(new_seq_len) + idx_mask = array_ops.sequence_mask(new_seq_len, maxlen=new_maxlen) + + # Flatten everything and mask out labels to keep and sparse indices. + flat_labels = array_ops.reshape(labels, [-1]) + flat_label_mask = array_ops.reshape(label_mask, [-1]) + flat_idx_mask = array_ops.reshape(idx_mask, [-1]) + idx = math_ops.range(_get_dim(flat_idx_mask, 0)) + + # Scatter to flat shape. + flat = array_ops.scatter_nd( + indices=array_ops.expand_dims( + array_ops.boolean_mask(idx, flat_idx_mask), axis=1), + updates=array_ops.boolean_mask(flat_labels, flat_label_mask), + shape=array_ops.shape(flat_idx_mask)) + + # Reshape back to square batch. + batch_size = _get_dim(labels, 0) + new_shape = [batch_size, new_maxlen] + return (array_ops.reshape(flat, new_shape), + math_ops.cast(new_seq_len, seq_length.dtype)) + + +def dense_labels_to_sparse(dense, length): + """Convert dense labels with sequence lengths to sparse tensor. + + Args: + dense: tensor of shape [batch, max_length] + length: int tensor of shape [batch] + The length of each sequence in dense. + + Returns: + tf.SparseTensor with values only for the valid elements of sequences. + """ + + flat_values = array_ops.reshape(dense, [-1]) + flat_indices = math_ops.range( + array_ops.shape(flat_values, out_type=dtypes.int64)[0]) + mask = array_ops.sequence_mask(length, maxlen=array_ops.shape(dense)[1]) + flat_mask = array_ops.reshape(mask, [-1]) + indices = array_ops.expand_dims( + array_ops.boolean_mask(flat_indices, flat_mask), 1) + values = array_ops.boolean_mask(flat_values, flat_mask) + sparse = sparse_tensor.SparseTensor( + indices=indices, values=math_ops.cast(values, dtypes.int32), + dense_shape=array_ops.shape(flat_values, out_type=dtypes.int64)) + reshaped = sparse_ops.sparse_reshape(sparse, array_ops.shape(dense)) + max_length = math_ops.reduce_max(length) + return sparse_tensor.SparseTensor( + indices=reshaped.indices, + values=reshaped.values, + dense_shape=[ + math_ops.cast(reshaped.dense_shape[0], dtypes.int64), + math_ops.cast(max_length, dtypes.int64)]) + + +@tf_export("nn.ctc_unique_labels") +def ctc_unique_labels(labels, name=None): + """Get unique labels and indices for batched labels for tf.nn.ctc_loss. + + For use with tf.nn.ctc_loss_v2 optional argument `unique`: This op can be + used to preprocess labels in input pipeline to for better speed/memory use + computing the ctc loss on TPU. + + Example: + ctc_unique_labels([[3, 4, 4, 3]]) -> + unique labels padded with 0: [[3, 4, 0, 0]] + indices of original labels in unique: [0, 1, 1, 0] + + Args: + labels: tensor of shape [batch_size, max_label_length] padded with 0. + name: A name for this `Op`. Defaults to "ctc_unique_labels". + + Returns: + tuple of + - unique labels, tensor of shape `[batch_size, max_label_length]` + - indices into unique labels, shape `[batch_size, max_label_length]` + """ + + with ops.name_scope(name, "ctc_unique_labels", [labels]): + labels = ops.convert_to_tensor(labels, name="labels") + def _unique(x): + u = array_ops.unique(x) + y = array_ops.pad( + u.y, [[0, _get_dim(u.idx, 0) - _get_dim(u.y, 0)]]) + y = math_ops.cast(y, dtypes.int64) + return [y, u.idx] + return functional_ops.map_fn( + _unique, labels, dtype=[dtypes.int64, dtypes.int32]) + + +def _sum_states(idx, states): + """Take logsumexp for each unique state out of all label states. + + Args: + idx: tensor of shape [batch, label_length] + For each sequence, indices into a set of unique labels as computed by + calling unique. + states: tensor of shape [frames, batch, label_length] + Log probabilities for each label state. + + Returns: + tensor of shape [frames, batch_size, label_length], log probabilites summed + for each unique label of the sequence. + """ + + with ops.name_scope("sum_states"): + idx = ops.convert_to_tensor(idx, name="idx") + num_states = _get_dim(states, 2) + states = array_ops.expand_dims(states, axis=2) + one_hot = array_ops.one_hot( + idx, depth=num_states, on_value=0.0, off_value=math_ops.log(0.0), + axis=1) + return math_ops.reduce_logsumexp(states + one_hot, axis=-1) + + +def _forward_backward_log(state_trans_log_probs, initial_state_log_probs, + final_state_log_probs, observed_log_probs, + sequence_length): + """Forward-backward algorithm computed in log domain. + + Args: + state_trans_log_probs: tensor of shape [states, states] or + if different transition matrix per batch [batch_size, states, states] + initial_state_log_probs: tensor of shape [batch_size, states] + final_state_log_probs: tensor of shape [batch_size, states] + observed_log_probs: tensor of shape [frames, batch_size, states] + sequence_length: tensor of shape [batch_size] + + Returns: + forward backward log probabilites: tensor of shape [frames, batch, states] + log_likelihood: tensor of shape [batch_size] + + Raises: + ValueError: If state_trans_log_probs has unknown or incorrect rank. + """ + + if state_trans_log_probs.shape.ndims == 2: + perm = [1, 0] + elif state_trans_log_probs.shape.ndims == 3: + perm = [0, 2, 1] + else: + raise ValueError( + "state_trans_log_probs rank must be known and == 2 or 3, is: %s" % + state_trans_log_probs.shape.ndims) + + bwd_state_trans_log_probs = array_ops.transpose(state_trans_log_probs, perm) + batch_size = _get_dim(observed_log_probs, 1) + + def _forward(state_log_prob, obs_log_prob): + state_log_prob = array_ops.expand_dims(state_log_prob, axis=1) # Broadcast. + state_log_prob += state_trans_log_probs + state_log_prob = math_ops.reduce_logsumexp(state_log_prob, axis=-1) + state_log_prob += obs_log_prob + log_prob_sum = math_ops.reduce_logsumexp( + state_log_prob, axis=-1, keepdims=True) + state_log_prob -= log_prob_sum + return state_log_prob + + fwd = _scan(_forward, observed_log_probs, initial_state_log_probs, + inclusive=True) + + def _backward(accs, elems): + """Calculate log probs and cumulative sum masked for sequence length.""" + state_log_prob, cum_log_sum = accs + obs_log_prob, mask = elems + state_log_prob += obs_log_prob + state_log_prob = array_ops.expand_dims(state_log_prob, axis=1) # Broadcast. + state_log_prob += bwd_state_trans_log_probs + state_log_prob = math_ops.reduce_logsumexp(state_log_prob, axis=-1) + + log_prob_sum = math_ops.reduce_logsumexp( + state_log_prob, axis=-1, keepdims=True) + state_log_prob -= log_prob_sum + + cum_log_sum += array_ops.squeeze(log_prob_sum) * mask + batched_mask = array_ops.expand_dims(mask, axis=1) + out = state_log_prob * batched_mask + out += final_state_log_probs * (1.0 - batched_mask) + return out, cum_log_sum + + zero_log_sum = array_ops.zeros([batch_size]) + maxlen = _get_dim(observed_log_probs, 0) + mask = array_ops.sequence_mask(sequence_length, maxlen, dtypes.float32) + mask = array_ops.transpose(mask, perm=[1, 0]) + + bwd, cum_log_sum = _scan(_backward, (observed_log_probs, mask), + (final_state_log_probs, zero_log_sum), + reverse=True, inclusive=True) + + fwd_bwd_log_probs = fwd[1:] + bwd[1:] + fwd_bwd_log_probs_sum = math_ops.reduce_logsumexp( + fwd_bwd_log_probs, axis=2, keepdims=True) + fwd_bwd_log_probs -= fwd_bwd_log_probs_sum + fwd_bwd_log_probs += math_ops.log(array_ops.expand_dims(mask, axis=2)) + + log_likelihood = bwd[0, :, 0] + cum_log_sum[0] + + return fwd_bwd_log_probs, log_likelihood + + +# TODO(tombagby): This is currently faster for the ctc implementation than using +# functional_ops.scan, but could be replaced by that or something similar if +# things change. +def _scan(fn, elems, initial, reverse=False, inclusive=False, final_only=False): + """Repeatedly applies callable `fn` to a sequence of elements. + + Implemented by functional_ops.While, tpu friendly, no gradient. + + This is similar to functional_ops.scan but significantly faster on tpu/gpu + for the forward backward use case. + + Examples: + scan(lambda a, e: a + e, [1.0, 2.0, 3.0], 1.0) => [2.0, 3.0, 4.0] + + Multiple accumulators: + scan(lambda a, e: (a[0] + e, a[1] * e), [1.0, 2.0, 3.0], (0.0, 1.0)) + + Multiple inputs: + scan(lambda a, e: a + (e[0] * e[1]), (elems1, elems2), 0.0) + + Args: + fn: callable, fn(accumulators, element) return new accumulator values. + The (possibly nested) sequence of accumulators is the same as `initial` + and the return value must have the same structure. + elems: A (possibly nested) tensor which will be unpacked along the first + dimension. The resulting slices will be the second argument to fn. The + first dimension of all nested input tensors must be the same. + initial: A tensor or (possibly nested) sequence of tensors with initial + values for the accumulators. + reverse: (optional) True enables scan and output elems in reverse order. + inclusive: (optional) True includes the initial accumulator values in the + output. Length of output will be len(elem sequence) + 1. Not meaningful + if final_only is True. + final_only: (optional) When True, return only the final accumulated values, + not the concatenation of accumulated values for each input. + + Returns: + A (possibly nested) sequence of tensors with the results of applying fn + to tensors unpacked from elems and previous accumulator values. + """ + + flat_elems = [ops.convert_to_tensor(x) for x in nest.flatten(elems)] + num_elems = array_ops.shape(flat_elems[0])[0] + pack_elems = lambda x: nest.pack_sequence_as(structure=elems, flat_sequence=x) + flat_initial = [ops.convert_to_tensor(x) for x in nest.flatten(initial)] + pack = lambda x: nest.pack_sequence_as(structure=initial, flat_sequence=x) + accum_dtypes = [x.dtype for x in flat_initial] + num_accums = len(flat_initial) + + # Types for counter, [outputs], [accumulators] loop arguments. + if final_only: + loop_dtypes = [dtypes.int32, dtypes.int32] + accum_dtypes + else: + loop_dtypes = [dtypes.int32, dtypes.int32] + accum_dtypes + accum_dtypes + + # TODO(tombagby): Update to tfe.defun + @function.Defun(*loop_dtypes) + def cond(i, num_elems, *args): + del args + return i >= 0 if reverse else i < num_elems + + # The loop *args are [output tensors] + [accumulator tensors] which must + # be paired. Each output corresponds to one accumulator. + @function.Defun(*loop_dtypes) + def body(i, num_elems, *args): + """Loop body.""" + i.set_shape([]) + if final_only: + accum = args + else: + out, accum = args[:num_accums], args[num_accums:] + slices = [array_ops.gather(e, i) for e in flat_elems] + accum = fn(pack(accum), pack_elems(slices)) + flat_accum = nest.flatten(accum) + if final_only: + new_out = [] + else: + update_i = i + 1 if inclusive and not reverse else i + new_out = [inplace_ops.alias_inplace_update(x, update_i, y) + for x, y in zip(out, flat_accum)] + i = i - 1 if reverse else i + 1 + return [i, num_elems] + new_out + flat_accum + + init_i = (array_ops.shape(flat_elems[0])[0] - 1 if reverse + else constant_op.constant(0, dtype=dtypes.int32)) + outputs = [] + if not final_only: + num_outputs = array_ops.shape(flat_elems[0])[0] + (1 if inclusive else 0) + for initial_accum in flat_initial: + out_shape = array_ops.concat( + [[num_outputs], array_ops.shape(initial_accum)], 0) + out = inplace_ops.empty(out_shape, dtype=initial_accum.dtype, init=True) + if inclusive: + out = inplace_ops.alias_inplace_add( + out, init_i + (1 if reverse else 0), initial_accum) + outputs.append(out) + loop_in = [init_i, num_elems] + outputs + flat_initial + hostmem = [ + i for i, x in enumerate(loop_in) + if x.dtype.base_dtype in (dtypes.int32, dtypes.int64) + ] + + # TODO(tombagby): Update to while_v2. + loop_results = functional_ops.While(loop_in, cond, body, hostmem=hostmem) + out = loop_results[2:num_accums + 2] + return pack(out) + + +def _get_dim(tensor, i): + """Get value of tensor shape[i] preferring static value if available.""" + return tensor.shape[i].value or array_ops.shape(tensor)[i] diff --git a/tensorflow/tools/api/golden/v1/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.nn.pbtxt index e781287d6c..48501e1b58 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.nn.pbtxt @@ -44,6 +44,10 @@ tf_module { name: "bidirectional_dynamic_rnn" argspec: "args=[\'cell_fw\', \'cell_bw\', \'inputs\', \'sequence_length\', \'initial_state_fw\', \'initial_state_bw\', \'dtype\', \'parallel_iterations\', \'swap_memory\', \'time_major\', \'scope\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\', \'False\', \'False\', \'None\'], " } + member_method { + name: "collapse_repeated" + argspec: "args=[\'labels\', \'seq_length\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "compute_accidental_hits" argspec: "args=[\'true_classes\', \'sampled_candidates\', \'num_true\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " @@ -108,6 +112,14 @@ tf_module { name: "ctc_loss" argspec: "args=[\'labels\', \'inputs\', \'sequence_length\', \'preprocess_collapse_repeated\', \'ctc_merge_repeated\', \'ignore_longer_outputs_than_inputs\', \'time_major\'], varargs=None, keywords=None, defaults=[\'False\', \'True\', \'False\', \'True\'], " } + member_method { + name: "ctc_loss_v2" + argspec: "args=[\'labels\', \'logits\', \'label_length\', \'logit_length\', \'logits_time_major\', \'unique\', \'blank_index\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'None\', \'None\', \'None\'], " + } + member_method { + name: "ctc_unique_labels" + argspec: "args=[\'labels\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "depth_to_space" argspec: "args=[\'input\', \'block_size\', \'name\', \'data_format\'], varargs=None, keywords=None, defaults=[\'None\', \'NHWC\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index 34ca2078b9..eb1e793b0f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -44,6 +44,10 @@ tf_module { name: "bidirectional_dynamic_rnn" argspec: "args=[\'cell_fw\', \'cell_bw\', \'inputs\', \'sequence_length\', \'initial_state_fw\', \'initial_state_bw\', \'dtype\', \'parallel_iterations\', \'swap_memory\', \'time_major\', \'scope\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\', \'False\', \'False\', \'None\'], " } + member_method { + name: "collapse_repeated" + argspec: "args=[\'labels\', \'seq_length\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "compute_accidental_hits" argspec: "args=[\'true_classes\', \'sampled_candidates\', \'num_true\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " @@ -98,7 +102,11 @@ tf_module { } member_method { name: "ctc_loss" - argspec: "args=[\'labels\', \'inputs\', \'sequence_length\', \'preprocess_collapse_repeated\', \'ctc_merge_repeated\', \'ignore_longer_outputs_than_inputs\', \'time_major\'], varargs=None, keywords=None, defaults=[\'False\', \'True\', \'False\', \'True\'], " + argspec: "args=[\'labels\', \'logits\', \'label_length\', \'logit_length\', \'logits_time_major\', \'unique\', \'blank_index\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'None\', \'None\', \'None\'], " + } + member_method { + name: "ctc_unique_labels" + argspec: "args=[\'labels\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "depth_to_space" -- GitLab From 177b34c3b1520c846dc83cb187bba7eca75e3503 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 20 Nov 2018 09:21:31 -0800 Subject: [PATCH 106/672] Disable header parsing for broken targets PiperOrigin-RevId: 222257218 --- tensorflow/lite/experimental/writer/BUILD | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tensorflow/lite/experimental/writer/BUILD b/tensorflow/lite/experimental/writer/BUILD index 506c668cf2..57ce636367 100644 --- a/tensorflow/lite/experimental/writer/BUILD +++ b/tensorflow/lite/experimental/writer/BUILD @@ -1,6 +1,9 @@ -package(default_visibility = [ - "//visibility:public", -]) +package( + default_visibility = [ + "//visibility:public", + ], + features = ["-parse_headers"], +) licenses(["notice"]) # Apache 2.0 -- GitLab From 1bcdfbac8161b9c925ef0dc10288cfe207f21d36 Mon Sep 17 00:00:00 2001 From: Brennan Saeta Date: Tue, 20 Nov 2018 09:39:18 -0800 Subject: [PATCH 107/672] [Perf] Use a shared lock to avoid slow paths Whenever a tf function is invoked, it calls ResourceMgr::Cleanup. Because most functions do not use the step container, this is often a no-op. Unfortunately, it grabs an exclusive lock on the process-wide (or session-wide) resource manager. This sometimes causes the slow-path to be taken when there are lots of concurrent function invocations (each using their own step counter). As a performance optimization, we first check (using a non-exclusive lock) whether there is a step container that needs to be cleaned up in the first place. PiperOrigin-RevId: 222259910 --- tensorflow/core/framework/resource_mgr.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/framework/resource_mgr.cc b/tensorflow/core/framework/resource_mgr.cc index 508a8d3149..9f3204ab96 100644 --- a/tensorflow/core/framework/resource_mgr.cc +++ b/tensorflow/core/framework/resource_mgr.cc @@ -204,12 +204,19 @@ Status ResourceMgr::Delete(const ResourceHandle& handle) { } Status ResourceMgr::Cleanup(const string& container) { + { + tf_shared_lock l(mu_); + if (!gtl::FindOrNull(containers_, container)) { + // Nothing to cleanup. + return Status::OK(); + } + } Container* b = nullptr; { mutex_lock l(mu_); auto iter = containers_.find(container); if (iter == containers_.end()) { - // Nothing to cleanup, it's OK. + // Nothing to cleanup, it's OK (concurrent cleanup). return Status::OK(); } b = iter->second; -- GitLab From 7f4a9f8467afee61d037c25ba65fd0601dcf9dcd Mon Sep 17 00:00:00 2001 From: Tong Shen Date: Tue, 20 Nov 2018 09:40:02 -0800 Subject: [PATCH 108/672] Handle edges within same XLA cluster in ExtractOutsideCompilationForFunction(). This change will make sure that outside compilation to outside compilation data edges don't go through XLA cluster. PiperOrigin-RevId: 222260022 --- tensorflow/compiler/jit/encapsulate_util.cc | 312 ++++++++++++++++-- tensorflow/compiler/jit/encapsulate_util.h | 97 ++++-- .../compiler/jit/encapsulate_util_test.cc | 21 +- .../jit/extract_outside_compilation_pass.cc | 16 +- .../extract_outside_compilation_pass_test.cc | 15 +- 5 files changed, 374 insertions(+), 87 deletions(-) diff --git a/tensorflow/compiler/jit/encapsulate_util.cc b/tensorflow/compiler/jit/encapsulate_util.cc index 28ec37b1b9..bcc3213285 100644 --- a/tensorflow/compiler/jit/encapsulate_util.cc +++ b/tensorflow/compiler/jit/encapsulate_util.cc @@ -86,7 +86,7 @@ Status ProcessControlEdges(Graph* g, const string& xla_computation_attr_name, continue; } else if (src_xla_computation && !dst_xla_computation) { if (src_outside_compilation) { - // Case 1d: outside compilation to host computation control edge. + // Case 1c: outside compilation to host computation control edge. edges_to_remove.push_back(e); TF_RETURN_IF_ERROR(AppendToListAttr( @@ -94,7 +94,7 @@ Status ProcessControlEdges(Graph* g, const string& xla_computation_attr_name, } } else if (!src_xla_computation && dst_xla_computation) { if (dst_outside_compilation) { - // Case 1d: host computation control to outside compilation edge. + // Case 1c: host computation control to outside compilation edge. edges_to_remove.push_back(e); TF_RETURN_IF_ERROR(AppendToListAttr( @@ -103,40 +103,24 @@ Status ProcessControlEdges(Graph* g, const string& xla_computation_attr_name, } else { // src_xla_computation && dst_xla_computation if (*src_xla_computation != *dst_xla_computation) { if (src_outside_compilation && dst_outside_compilation) { - // Case 1c: outside compilation to outside compilation control edge. + // Case 1b: outside compilation to outside compilation control edge. edges_to_remove.push_back(e); TF_RETURN_IF_ERROR(AppendToListAttr( e->dst(), kXlaControlDependenciesAttrName, e->src()->name())); } else if (src_outside_compilation && !dst_outside_compilation) { - // Case 1b: outside compilation to another XLA computaition control + // Case 1a: outside compilation to another XLA computaition control // edge. TF_RETURN_IF_ERROR(AppendToListAttr( e->src(), kXlaConnectedToOtherXlaComputationAttrName, *dst_xla_computation)); } else if (!src_outside_compilation && dst_outside_compilation) { - // Case 1b: another XLA computaition to outside compilation control + // Case 1a: another XLA computaition to outside compilation control // edge. TF_RETURN_IF_ERROR(AppendToListAttr( e->dst(), kXlaConnectedFromOtherXlaComputationAttrName, *src_xla_computation)); } - } else { // *src_xla_computation == *dst_xla_computation - if (src_outside_compilation && dst_outside_compilation) { - if (*src_outside_compilation != *dst_outside_compilation) { - // Case 1c: outside compilation to outside compilation control edge. - edges_to_remove.push_back(e); - - TF_RETURN_IF_ERROR(AppendToListAttr( - e->dst(), kXlaControlDependenciesAttrName, e->src()->name())); - } - } else if (src_outside_compilation && !dst_outside_compilation) { - // Case 1a: outside compilation to its XLA computation control edge. - ReplaceAttr(e->src(), kXlaConnectedToXlaComputationAttrName, true); - } else if (!src_outside_compilation && dst_outside_compilation) { - // Case 1a: XLA computation to outside compilation in it control edge. - ReplaceAttr(e->dst(), kXlaConnectedFromXlaComputationAttrName, true); - } } } } @@ -181,12 +165,6 @@ Status ProcessXlaToXlaDataEdges(Graph* g, edges.push_back(EdgeInfo{e->dst_input(), e->dst()->id()}); VLOG(4) << "XLA -> XLA edge: " << e->DebugString(); } - } else { // *src_xla_computation == *dst_xla_computation - if (src_outside_compilation && dst_outside_compilation && - *src_outside_compilation != *dst_outside_compilation) { - edges.push_back(EdgeInfo{e->dst_input(), e->dst()->id()}); - VLOG(4) << "XLA -> XLA edge: " << e->DebugString(); - } } } @@ -594,14 +572,242 @@ Status AddControlDependencies( return Status::OK(); } +// Step 1 for `PreprocessEdgesBetweenOutsideCompilations`. See comments of +// `PreprocessEdgesBetweenOutsideCompilations` for details. +Status PreprocessControlEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name) { + // Gather edges to remove. We should not remove the edge while iterating. + std::vector edges_to_remove; + for (const Edge* e : g->edges()) { + if (!e->IsControlEdge()) { + continue; + } + + auto src_outside_compilation = + GetStringAttr(*e->src(), outside_compilation_attr_name); + auto dst_outside_compilation = + GetStringAttr(*e->dst(), outside_compilation_attr_name); + + if (src_outside_compilation && dst_outside_compilation) { + if (*src_outside_compilation != *dst_outside_compilation) { + // Case 1a: outside compilation to outside compilation control edge. + edges_to_remove.push_back(e); + + TF_RETURN_IF_ERROR(AppendToListAttr( + e->dst(), kXlaControlDependenciesWithinXlaClusterAttrName, + e->src()->name())); + } + } else if (src_outside_compilation && !dst_outside_compilation) { + // Case 1b: outside compilation to its XLA computation control edge. + ReplaceAttr(e->src(), kXlaConnectedToXlaComputationAttrName, true); + } else if (!src_outside_compilation && dst_outside_compilation) { + // Case 1b: XLA computation to outside compilation in it control edge. + ReplaceAttr(e->dst(), kXlaConnectedFromXlaComputationAttrName, true); + } + } + + for (auto e : edges_to_remove) { + g->RemoveEdge(e); + } + return Status::OK(); +} + +// Step 2 for `PreprocessEdgesBetweenOutsideCompilations`. See comments of +// `PreprocessEdgesBetweenOutsideCompilations` for details. +Status PreprocessDataEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name) { + // Gather edges between outside compilation and host computation. Notice that + // we do not store `Edge*` directly because we remove some nodes while adding + // Identity nodes, and those Edge pointers might be invalidated. + struct EdgeInfo { + int dst_input, dst_node_id; + }; + std::vector edges; + for (const Edge* e : g->edges()) { + if (e->IsControlEdge()) { + continue; + } + + auto src_outside_compilation = + GetStringAttr(*e->src(), outside_compilation_attr_name); + auto dst_outside_compilation = + GetStringAttr(*e->dst(), outside_compilation_attr_name); + + if (src_outside_compilation && dst_outside_compilation && + *src_outside_compilation != *dst_outside_compilation) { + edges.push_back(EdgeInfo{e->dst_input(), e->dst()->id()}); + VLOG(4) << "Oc -> oc edge: " << e->DebugString(); + } + } + + // Remove the edge from host to outside compilation. Add a placeholder as + // outside compilation node input. + std::map placeholders; + for (int i = 0; i < edges.size(); i++) { + Node* dst = g->FindNodeId(edges[i].dst_node_id); + const Edge* e; + TF_RETURN_IF_ERROR(dst->input_edge(edges[i].dst_input, &e)); + Node* src = e->src(); + int src_output = e->src_output(), dst_input = e->dst_input(); + g->RemoveEdge(e); + + // Find or create placeholder node. + string new_name = absl::StrCat(src->name(), "_oc_to_oc_placeholder"); + auto iter = placeholders.find(new_name); + Node* placeholder_node; + if (iter == placeholders.end()) { + NodeDefBuilder placeholder_builder(new_name, "Placeholder"); + placeholder_builder.Attr("dtype", src->output_type(src_output)); + string outside_compilation_attr; + TF_RETURN_IF_ERROR(GetNodeAttr(dst->attrs(), + outside_compilation_attr_name, + &outside_compilation_attr)); + placeholder_builder.Attr(outside_compilation_attr_name, + outside_compilation_attr); + placeholder_builder.Attr(kOutsideCompilationOriginalNodeAttrName, + src->name()); + placeholder_builder.Attr(kOutsideCompilationSrcOutputAttrName, + src_output); + NodeDef placeholder_def; + TF_RETURN_IF_ERROR(placeholder_builder.Finalize(&placeholder_def)); + Status s; + placeholder_node = g->AddNode(placeholder_def, &s); + TF_RETURN_IF_ERROR(s); + placeholders[new_name] = placeholder_node; + } else { + placeholder_node = iter->second; + } + g->AddEdge(placeholder_node, 0, dst, dst_input); + + // Replace `e->dst()` because its input node changed. + NodeDef new_def = dst->def(); + *new_def.mutable_input(dst_input) = placeholder_node->name(); + TF_ASSIGN_OR_RETURN(Node * dst_replace_node, ReplaceNode(g, dst, new_def)); + + // Other edge in `edges` might have `e->dst()` as src or dst + // node. Before removing `e->dst()`, replace those edges with + // corresponding edges for `dst_replace_node`. + for (int j = i + 1; j < edges.size(); j++) { + if (edges[j].dst_node_id == edges[i].dst_node_id) { + edges[j].dst_node_id = dst_replace_node->id(); + } + } + } + return Status::OK(); +} + +// Step 1 for `PostprocessEdgesBetweenOutsideCompilations`. See comments of +// `PostprocessEdgesBetweenOutsideCompilations` for details. +Status PostprocessDataEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name) { + // Gather all outside compilation to outside compilation nodes. + std::vector placeholder_nodes; + for (Node* n : g->nodes()) { + if (n->type_string() == "Placeholder" && + HasNodeAttr(n->def(), kOutsideCompilationOriginalNodeAttrName)) { + placeholder_nodes.push_back(n); + } + } + + // Remove the placeholder nodes, and reconnect original edge. + auto node_name_index = g->BuildNodeNameIndex(); + for (auto n : placeholder_nodes) { + string node_name; + int node_src_output; + TF_RETURN_IF_ERROR(GetNodeAttr( + n->attrs(), kOutsideCompilationOriginalNodeAttrName, &node_name)); + TF_RETURN_IF_ERROR(GetNodeAttr( + n->attrs(), kOutsideCompilationSrcOutputAttrName, &node_src_output)); + auto iter = node_name_index.find(node_name); + if (iter == node_name_index.end()) { + return errors::Internal( + "Cannot find original node for oc -> host placeholder node ", + node_name); + } + + // Change all usage node to use the original node instead. + Node* original_node = iter->second; + std::vector control_edges; + std::vector data_edges; + for (auto e : n->out_edges()) { + if (e->IsControlEdge()) { + control_edges.push_back(e); + } else { + data_edges.push_back({e->dst(), e->src_output(), e->dst_input()}); + } + } + for (const Edge* e : control_edges) { + g->AddControlEdge(original_node, e->dst()); + g->RemoveEdge(e); + } + for (int i = 0; i < data_edges.size(); i++) { + Node* dst = data_edges[i].dst; + NodeDef new_def = dst->def(); + int dst_input = data_edges[i].dst_input; + *new_def.mutable_input(dst_input) = + absl::StrCat(original_node->name(), ":", node_src_output); + TF_ASSIGN_OR_RETURN(Node * replace_node, ReplaceNode(g, dst, new_def)); + + const Edge* edge_to_replace = nullptr; + TF_RETURN_IF_ERROR(replace_node->input_edge(dst_input, &edge_to_replace)); + g->RemoveEdge(edge_to_replace); + g->AddEdge(original_node, node_src_output, replace_node, dst_input); + + // Other edges might have `dst` as dst node. Update those edges with + // `replace_node`. + for (int j = i + 1; j < data_edges.size(); j++) { + if (data_edges[j].dst == dst) { + data_edges[j].dst = replace_node; + } + } + + // Other placeholder node might have `dst` as original node. Update + // `node_name_index` with `replace_node`. + node_name_index[replace_node->name()] = replace_node; + } + + // Remove placeholder node. + g->RemoveNode(n); + } + return Status::OK(); +} + +// Step 2 for `PostprocessEdgesBetweenOutsideCompilations`. See comments of +// `PostprocessEdgesBetweenOutsideCompilations` for details. +Status PostprocessControlEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name) { + auto node_name_index = g->BuildNodeNameIndex(); + + // Reconnect outside compilation to outside compilation control edge. + for (Node* n : g->nodes()) { + std::vector control_deps; + Status s = + GetNodeAttr(n->attrs(), kXlaControlDependenciesWithinXlaClusterAttrName, + &control_deps); + if (!s.ok()) { + if (s.code() != error::NOT_FOUND) { + return s; + } else { + continue; + } + } else { + n->ClearAttr(kXlaControlDependenciesWithinXlaClusterAttrName); + for (const string& control_input : control_deps) { + auto iter = node_name_index.find(control_input); + if (iter == node_name_index.end()) { + return errors::Internal("Cannot find original node for ", + control_input); + } + g->AddControlEdge(iter->second, n); + } + } + } + return Status::OK(); +} } // namespace const char kXlaInferredShapesAttrName[] = "_xla_inferred_shapes"; -const char kXlaConnectedToXlaComputationAttrName[] = - "_xla_connected_to_xla_computation"; -const char kXlaConnectedFromXlaComputationAttrName[] = - "_xla_connected_from_xla_computation"; const char kXlaConnectedToOtherXlaComputationAttrName[] = "_xla_connected_to_other_xla_computation"; const char kXlaConnectedFromOtherXlaComputationAttrName[] = @@ -616,6 +822,15 @@ const char kHostToOutsideCompilationOriginalNodeAttrName[] = "_xla_host_to_oc_node_name"; const char kHostToOutsideCompilationSrcOutputAttrName[] = "_xla_host_to_oc_src_output"; +const char kXlaConnectedToXlaComputationAttrName[] = + "_xla_connected_to_xla_computation"; +const char kXlaConnectedFromXlaComputationAttrName[] = + "_xla_connected_from_xla_computation"; +const char kOutsideCompilationOriginalNodeAttrName[] = + "_xla_oc_to_oc_node_name"; +const char kOutsideCompilationSrcOutputAttrName[] = "_xla_oc_to_oc_src_output"; +const char kXlaControlDependenciesWithinXlaClusterAttrName[] = + "_xla_control_dependencies_within_xla_cluster"; Status PerformStaticShapeInferenceBeforeEncapsulation( Graph* g, const string& xla_computation_attr_name, @@ -699,4 +914,39 @@ Status PostprocessForEncapsulation( return Status::OK(); } +Status PreprocessEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name) { + // Remove edges from source node to outside compilation nodes, and edges + // from outside compilation nodes to sink node. + std::vector edges_to_remove; + for (const Edge* e : g->source_node()->out_edges()) { + if (HasNodeAttr(e->dst()->def(), outside_compilation_attr_name)) { + edges_to_remove.push_back(e); + } + } + for (const Edge* e : g->sink_node()->in_edges()) { + if (HasNodeAttr(e->src()->def(), outside_compilation_attr_name)) { + edges_to_remove.push_back(e); + } + } + for (auto e : edges_to_remove) { + g->RemoveEdge(e); + } + + TF_RETURN_IF_ERROR(PreprocessControlEdgesBetweenOutsideCompilations( + g, outside_compilation_attr_name)); + TF_RETURN_IF_ERROR(PreprocessDataEdgesBetweenOutsideCompilations( + g, outside_compilation_attr_name)); + return Status::OK(); +} + +Status PostprocessEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name) { + TF_RETURN_IF_ERROR(PostprocessDataEdgesBetweenOutsideCompilations( + g, outside_compilation_attr_name)); + TF_RETURN_IF_ERROR(PostprocessControlEdgesBetweenOutsideCompilations( + g, outside_compilation_attr_name)); + return Status::OK(); +} + } // namespace tensorflow diff --git a/tensorflow/compiler/jit/encapsulate_util.h b/tensorflow/compiler/jit/encapsulate_util.h index 5e0c4bf6a0..e363bc5754 100644 --- a/tensorflow/compiler/jit/encapsulate_util.h +++ b/tensorflow/compiler/jit/encapsulate_util.h @@ -44,14 +44,6 @@ Status PerformStaticShapeInferenceBeforeEncapsulation( Graph* g, const string& xla_computation_attr_name, const string& outside_compilation_attr_name); -// Attribute indicating that some ops in this node's XLA computation has control -// dependency on this node. Attribute value will always be "true". -extern const char kXlaConnectedToXlaComputationAttrName[]; - -// Attribute indicating that this node has control dependency on some ops in -// this node's XLA computation. Attribute value will always be "true". -extern const char kXlaConnectedFromXlaComputationAttrName[]; - // Attribute indicating that some ops in other XLA computation has control // dependency on this node. Attribute value will be a list of string (XLA // computation names). @@ -81,6 +73,14 @@ extern const char kOutsideCompilationToHostOriginalNodeAttrName[]; // int (src_output for original edge). extern const char kOutsideCompilationToHostSrcOutputAttrName[]; +// Attribute indicating that some ops in this node's XLA computation has control +// dependency on this node. Attribute value will always be "true". +extern const char kXlaConnectedToXlaComputationAttrName[]; + +// Attribute indicating that this node has control dependency on some ops in +// this node's XLA computation. Attribute value will always be "true". +extern const char kXlaConnectedFromXlaComputationAttrName[]; + // Attribute indicating that this is an Placeholder node added to act as a // temporary input node for an host node. Attribute value will be string // (original input node name). @@ -91,19 +91,31 @@ extern const char kHostToOutsideCompilationOriginalNodeAttrName[]; // for original edge). extern const char kHostToOutsideCompilationSrcOutputAttrName[]; -// Preprocesses the graph for encapsulation. It will perform the following -// operations in order: +// Attribute indicating that this is an Placeholder node added to act as a +// temporary input node for an outside compilation node. Attribute value will be +// string (original input node name). +extern const char kOutsideCompilationOriginalNodeAttrName[]; + +// Attribute indicating that this is an Placeholder node added to act as a +// temporary input node for an outside compilation node. Attribute value will be +// int (src_output for original edge). +extern const char kOutsideCompilationSrcOutputAttrName[]; + +// Attribute indicating that this node has control dependencies on some other +// nodes within the same XLA cluster. Attribute value will be a list of string +// (node names). +extern const char kXlaControlDependenciesWithinXlaClusterAttrName[]; + +// Preprocesses edges between different XLA clusters for encapsulation. It will +// perform the following operations in order: // -// 1a. For control edges between outside compilation and its XLA computation, -// add attr "kXlaConnected{From, To}XlaComputationAttrName = true" to the -// outside compilation node. -// 1b. For control edges between outside compilation and another XLA +// 1a. For control edges between outside compilation and another XLA // computation, add attr "kXlaConnected{From, To}OtherXlaComputationAttrName // = XLA computation node name" to the outside compilation node. -// 1c. For control edges between different outside compilations, remove the edge -// and add attr "kXlaControlDependenciesAttrName = src node name" to dst -// node. -// 1d. For control edges between outside compilation and host computation, +// 1b. For control edges between different outside compilations (in different +// XLA computations), remove the edge and add attr +// "kXlaControlDependenciesAttrName = src node name" to dst node. +// 1c. For control edges between outside compilation and host computation, // remove the edge and add attr "kXlaControlDependenciesAttrName = src node // name" to dst node. // 2. For data edges between different XLA computations, if either src or dst @@ -146,26 +158,53 @@ struct XlaClusterInfo { const std::map host_compute_core; }; -// Postprocesses the graph for encapsulation. This function reverts what -// `PreprocessForEncapsulation` did. It will perform the following operations in -// order: +// Postprocesses edges between different XLA clusters for encapsulation. This +// function reverts what `PreprocessForEncapsulation` did. It will perform the +// following operations in order: // // 1. Remove Placeholder nodes between outside compilation and host computation // (created in `PreprocessForEncapsulation` step 3). // 2. Remove Identity nodes created in `PreprocessForEncapsulation` step 2. -// 3a. Reconnect control edges between different outside compilations (marked by -// `PreprocessForEncapsulation` step 1c) and control edges between outside -// compilation and host computation (marked by `PreprocessForEncapsulation` -// step 1d). -// 3b. Reconnect control edges between outside compilation and another XLA -// computation (marked by `PreprocessForEncapsulation` step 1b). -// Notice that control edges marked by `PreprocessForEncapsulation` step 1a are -// not handled here. They are handled in `RewriteOutsideCompilationSubgraphFn`. +// 3a. Reconnect control edges between outside compilation and another XLA +// computation (marked by `PreprocessForEncapsulation` step 1a). +// 3b. Reconnect control edges between different outside compilations (marked by +// `PreprocessForEncapsulation` step 1b). +// 3c. Reconnect control edges between outside compilation and host computation +// (marked by `PreprocessForEncapsulation` step 1c). Status PostprocessForEncapsulation( Graph* g, const string& xla_computation_attr_name, const string& outside_compilation_attr_name, const std::unordered_map& clusters); +// Preprocesses edges within the same XLA cluster. It will perform the following +// operations in order: +// +// 0. Remove edges from source node to outside compilation nodes, and edges +// from outside compilation nodes to sink node. +// 1a. For edges between different outside compilation clusters, remove the edge +// and add attr "kXlaControlDependenciesWithinXlaClusterAttrName = src node +// name" to dst node. +// 1b. For control edges between outside compilation and its XLA computation, +// add attr "kXlaConnected{From, To}XlaComputationAttrName = true" to the +// outside compilation node. +// 2. For data edges between different outside compilations, remove the edge +// and create a Placeholder node as dst node's input. +Status PreprocessEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name); + +// Postprocesses edges within the same XLA cluster. This function reverts what +// `PreprocessEdgesBetweenOutsideCompilations` did. It will perform the +// following operations in order: +// +// 1. Remove Placeholder nodes between different outside compilations (created +// in `PreprocessEdgesBetweenOutsideCompilations` step 2). +// 2a. Reconnect control edges between different outside compilations (marked by +// `PreprocessEdgesBetweenOutsideCompilations` step 1a). +// Notice that control edges marked by +// `PreprocessEdgesBetweenOutsideCompilations` step 1b are not handled here. +// They are handled in `RewriteOutsideCompilationSubgraphFn`. +Status PostprocessEdgesBetweenOutsideCompilations( + Graph* g, const string& outside_compilation_attr_name); } // namespace tensorflow #endif // TENSORFLOW_COMPILER_JIT_ENCAPSULATE_UTIL_H_ diff --git a/tensorflow/compiler/jit/encapsulate_util_test.cc b/tensorflow/compiler/jit/encapsulate_util_test.cc index 7255df3112..25c32cef01 100644 --- a/tensorflow/compiler/jit/encapsulate_util_test.cc +++ b/tensorflow/compiler/jit/encapsulate_util_test.cc @@ -107,28 +107,19 @@ TEST(PreprocessForEncapsulationTest, ControlEdges) { identity4_node->AddAttr("_xla", "1"); identity4_node->AddAttr("_oc", "0"); identity5_node->AddAttr("_xla", "1"); - // Case 1a: control edges between outside compilation and its XLA computation. - g.AddControlEdge(add_node, identity0_node); - g.AddControlEdge(identity0_node, identity1_node); - // Case 1b: control edges between outside compilation and another XLA + // Case 1a: control edges between outside compilation and another XLA // computation. g.AddControlEdge(identity0_node, identity3_node); g.AddControlEdge(identity1_node, identity4_node); - // Case 1c: control edges between different outside compilations. + // Case 1b: control edges between different outside compilations. g.AddControlEdge(identity0_node, identity4_node); - // Case 1d: control edges between outside compilation and host computation. + // Case 1c: control edges between outside compilation and host computation. g.AddControlEdge(const0_node, identity0_node); g.AddControlEdge(identity0_node, identity2_node); TF_CHECK_OK(PreprocessForEncapsulation(&g, "_xla", "_oc")); - // Case 1a: add attr "_xla_connected_{from/to}_xla_computation = true" to the - // outside compilation node. - EXPECT_TRUE(HasNodeAttr(identity0_node->def(), - kXlaConnectedFromXlaComputationAttrName)); - EXPECT_TRUE(HasNodeAttr(identity0_node->def(), - kXlaConnectedToXlaComputationAttrName)); - // Case 1b: add attr "_xla_control_deps_{from/to} = XLA computation node name" + // Case 1a: add attr "_xla_control_deps_{from/to} = XLA computation node name" // to the outside compilation node. std::vector attr; TF_CHECK_OK(GetNodeAttr(identity0_node->def(), @@ -140,13 +131,13 @@ TEST(PreprocessForEncapsulationTest, ControlEdges) { kXlaConnectedFromOtherXlaComputationAttrName, &attr)); EXPECT_EQ(attr.size(), 1); EXPECT_EQ(attr[0], "0"); - // Case 1c: add attr "_xla_control_deps = src node name" to dst node. + // Case 1b: add attr "_xla_control_deps = src node name" to dst node. attr.clear(); TF_CHECK_OK(GetNodeAttr(identity4_node->def(), kXlaControlDependenciesAttrName, &attr)); EXPECT_EQ(attr.size(), 1); EXPECT_EQ(attr[0], "identity0"); - // Case 1d: add attr "_xla_control_deps = src node name" to dst node. + // Case 1c: add attr "_xla_control_deps = src node name" to dst node. attr.clear(); TF_CHECK_OK(GetNodeAttr(identity0_node->def(), kXlaControlDependenciesAttrName, &attr)); diff --git a/tensorflow/compiler/jit/extract_outside_compilation_pass.cc b/tensorflow/compiler/jit/extract_outside_compilation_pass.cc index 8b3587c508..e3c7e2f89b 100644 --- a/tensorflow/compiler/jit/extract_outside_compilation_pass.cc +++ b/tensorflow/compiler/jit/extract_outside_compilation_pass.cc @@ -366,7 +366,7 @@ Status ReplaceOrRemoveOutsideCompilationCallNode( // replace this node with compilation result node. // 3) all outside compilation graphs. Status ConstructHostGraph( - const string& xla_cluster_name, + const string& xla_cluster_name, const string& outside_compilation_attr_name, const std::vector& outside_compilation_host_graphs, FunctionLibraryDefinition* fld, std::unique_ptr* host_graph) { host_graph->reset(new Graph(fld)); @@ -476,6 +476,10 @@ Status ConstructHostGraph( host_graph->get(), std::unordered_set{(*host_graph)->sink_node()}); + // Postprocess edges between different outside compilations. + TF_RETURN_IF_ERROR(PostprocessEdgesBetweenOutsideCompilations( + host_graph->get(), outside_compilation_attr_name)); + if (VLOG_IS_ON(4)) { dump_graph::DumpGraphToFile( absl::StrCat("extract_outside_compilation_host_graph_for_", @@ -801,6 +805,11 @@ Status ExtractOutsideCompilationForFunction( }, &fbody)); std::unique_ptr fbody_deleter(fbody); + + // Preprocess edges between different outside compilations. They will be + // restored in `ConstructHostGraph()`. + TF_RETURN_IF_ERROR(PreprocessEdgesBetweenOutsideCompilations( + fbody->graph, outside_compilation_attr_name)); if (VLOG_IS_ON(4)) { dump_graph::DumpGraphToFile( absl::StrCat("extract_outside_compilation_for_func_before_", func_name), @@ -860,8 +869,9 @@ Status ExtractOutsideCompilationForFunction( // Construct host graph. if (!outside_compilation_host_graphs.empty()) { - TF_RETURN_IF_ERROR(ConstructHostGraph( - xla_cluster_name, outside_compilation_host_graphs, fld, host_graph)); + TF_RETURN_IF_ERROR( + ConstructHostGraph(xla_cluster_name, outside_compilation_attr_name, + outside_compilation_host_graphs, fld, host_graph)); } // Remove the outside compilation graphs from function library. diff --git a/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc b/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc index c5bd64f004..bff956100d 100644 --- a/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc +++ b/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc @@ -290,21 +290,18 @@ TEST(ExtractOutsideCompilationForFunctionTest, Basic) { TF_CHECK_OK(GetNodeAttr(host_compute_1->attrs(), "shapes", &shapes)); EXPECT_EQ(shapes.size(), 1); EXPECT_EQ(shapes[0].dim_size(), 1); - // Check XlaHostCompute nodes' "shape_inference_graph" attr. "0" should have a - // non-empty value, and "1" should have an empty value. + // Check XlaHostCompute nodes' "shape_inference_graph" attr. Both should have + // empty values. string shape_inference_graph; TF_CHECK_OK(GetNodeAttr(host_compute_0->attrs(), "shape_inference_graph", &shape_inference_graph)); - EXPECT_EQ(shape_inference_graph, - "_outside_compilation_shape_inference_cluster_0"); + EXPECT_EQ(shape_inference_graph, ""); TF_CHECK_OK(GetNodeAttr(host_compute_1->attrs(), "shape_inference_graph", &shape_inference_graph)); EXPECT_EQ(shape_inference_graph, ""); // Check `shape_inference_graphs`. - EXPECT_EQ(shape_inference_graphs.size(), 1); - EXPECT_EQ(shape_inference_graphs[0], - "_outside_compilation_shape_inference_cluster_0"); + EXPECT_EQ(shape_inference_graphs.size(), 0); // Check `host_graph`: verify we have key placeholder and sequencer. Node *key_placeholder = nullptr, *sequencer = nullptr; @@ -333,8 +330,8 @@ TEST(ExtractOutsideCompilationForFunctionTest, Basic) { send_recv_nodes.push_back(n); } } - EXPECT_EQ(num_send_from_host, 2); - EXPECT_EQ(num_recv_at_host, 2); + EXPECT_EQ(num_send_from_host, 1); + EXPECT_EQ(num_recv_at_host, 1); for (Node *n : send_recv_nodes) { Node *input_node; TF_CHECK_OK(n->input_node(n->num_inputs() - 1, &input_node)); -- GitLab From f1324400026ce07b859cc0f4c2db989ad0559f42 Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Tue, 20 Nov 2018 09:48:45 -0800 Subject: [PATCH 109/672] Update tf.export and deprecation notice for the rest of RNN cell and layers. PiperOrigin-RevId: 222261282 --- tensorflow/python/ops/rnn.py | 10 +- tensorflow/python/ops/rnn_cell_impl.py | 5 +- .../tools/api/golden/v2/tensorflow.nn.pbtxt | 8 - ...orflow.nn.rnn_cell.-multi-r-n-n-cell.pbtxt | 205 ------------------ .../golden/v2/tensorflow.nn.rnn_cell.pbtxt | 4 - 5 files changed, 12 insertions(+), 220 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.-multi-r-n-n-cell.pbtxt diff --git a/tensorflow/python/ops/rnn.py b/tensorflow/python/ops/rnn.py index 57ecb50557..c23b85847c 100644 --- a/tensorflow/python/ops/rnn.py +++ b/tensorflow/python/ops/rnn.py @@ -348,7 +348,10 @@ def _reverse_seq(input_seq, lengths): return results -@tf_export("nn.bidirectional_dynamic_rnn") +@deprecation.deprecated(None, "Please use `keras.layers.Bidirectional(" + "keras.layers.RNN(cell))`, which is equivalent to " + "this API") +@tf_export(v1=["nn.bidirectional_dynamic_rnn"]) def bidirectional_dynamic_rnn(cell_fw, cell_bw, inputs, sequence_length=None, initial_state_fw=None, initial_state_bw=None, dtype=None, parallel_iterations=None, @@ -1490,7 +1493,10 @@ def static_state_saving_rnn(cell, return (outputs, state) -@tf_export("nn.static_bidirectional_rnn") +@deprecation.deprecated(None, "Please use `keras.layers.Bidirectional(" + "keras.layers.RNN(cell, unroll=True))`, which is " + "equivalent to this API") +@tf_export(v1=["nn.static_bidirectional_rnn"]) def static_bidirectional_rnn(cell_fw, cell_bw, inputs, diff --git a/tensorflow/python/ops/rnn_cell_impl.py b/tensorflow/python/ops/rnn_cell_impl.py index 050b486893..2bc1ad4e04 100644 --- a/tensorflow/python/ops/rnn_cell_impl.py +++ b/tensorflow/python/ops/rnn_cell_impl.py @@ -1394,7 +1394,7 @@ class DeviceWrapper(RNNCell): return self._cell(inputs, state, scope=scope) -@tf_export("nn.rnn_cell.MultiRNNCell") +@tf_export(v1=["nn.rnn_cell.MultiRNNCell"]) class MultiRNNCell(RNNCell): """RNN cell composed sequentially of multiple simple cells. @@ -1407,6 +1407,9 @@ class MultiRNNCell(RNNCell): ``` """ + @deprecated(None, "This class is equivalent as " + "tf.keras.layers.StackedRNNCells, and will be replaced by " + "that in Tensorflow 2.0.") def __init__(self, cells, state_is_tuple=True): """Create a RNN cell composed sequentially of a number of RNNCells. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index eb1e793b0f..19380337d8 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -40,10 +40,6 @@ tf_module { name: "bias_add" argspec: "args=[\'value\', \'bias\', \'data_format\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } - member_method { - name: "bidirectional_dynamic_rnn" - argspec: "args=[\'cell_fw\', \'cell_bw\', \'inputs\', \'sequence_length\', \'initial_state_fw\', \'initial_state_bw\', \'dtype\', \'parallel_iterations\', \'swap_memory\', \'time_major\', \'scope\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\', \'False\', \'False\', \'None\'], " - } member_method { name: "collapse_repeated" argspec: "args=[\'labels\', \'seq_length\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " @@ -292,10 +288,6 @@ tf_module { name: "sparse_softmax_cross_entropy_with_logits" argspec: "args=[\'_sentinel\', \'labels\', \'logits\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } - member_method { - name: "static_bidirectional_rnn" - argspec: "args=[\'cell_fw\', \'cell_bw\', \'inputs\', \'initial_state_fw\', \'initial_state_bw\', \'dtype\', \'sequence_length\', \'scope\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " - } member_method { name: "static_state_saving_rnn" argspec: "args=[\'cell\', \'inputs\', \'state_saver\', \'state_name\', \'sequence_length\', \'scope\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.-multi-r-n-n-cell.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.-multi-r-n-n-cell.pbtxt deleted file mode 100644 index f53567af52..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.-multi-r-n-n-cell.pbtxt +++ /dev/null @@ -1,205 +0,0 @@ -path: "tensorflow.nn.rnn_cell.MultiRNNCell" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "activity_regularizer" - mtype: "" - } - member { - name: "dtype" - mtype: "" - } - member { - name: "graph" - mtype: "" - } - member { - name: "inbound_nodes" - mtype: "" - } - member { - name: "input" - mtype: "" - } - member { - name: "input_mask" - mtype: "" - } - member { - name: "input_shape" - mtype: "" - } - member { - name: "losses" - mtype: "" - } - member { - name: "name" - mtype: "" - } - member { - name: "non_trainable_variables" - mtype: "" - } - member { - name: "non_trainable_weights" - mtype: "" - } - member { - name: "outbound_nodes" - mtype: "" - } - member { - name: "output" - mtype: "" - } - member { - name: "output_mask" - mtype: "" - } - member { - name: "output_shape" - mtype: "" - } - member { - name: "output_size" - mtype: "" - } - member { - name: "scope_name" - mtype: "" - } - member { - name: "state_size" - mtype: "" - } - member { - name: "trainable_variables" - mtype: "" - } - member { - name: "trainable_weights" - mtype: "" - } - member { - name: "updates" - mtype: "" - } - member { - name: "variables" - mtype: "" - } - member { - name: "weights" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'cells\', \'state_is_tuple\'], varargs=None, keywords=None, defaults=[\'True\'], " - } - member_method { - name: "add_loss" - argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "add_metric" - argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "add_update" - argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "add_variable" - argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" - } - member_method { - name: "add_weight" - argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\', \'use_resource\', \'synchronization\', \'aggregation\', \'partitioner\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'VariableSynchronization.AUTO\', \'VariableAggregation.NONE\', \'None\'], " - } - member_method { - name: "apply" - argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" - } - member_method { - name: "build" - argspec: "args=[\'self\', \'_\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "call" - argspec: "args=[\'self\', \'inputs\', \'state\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "compute_mask" - argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "compute_output_shape" - argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "count_params" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "from_config" - argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_config" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_initial_state" - argspec: "args=[\'self\', \'inputs\', \'batch_size\', \'dtype\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " - } - member_method { - name: "get_input_at" - argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_input_mask_at" - argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_input_shape_at" - argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_losses_for" - argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_output_at" - argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_output_mask_at" - argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_output_shape_at" - argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_updates_for" - argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_weights" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "set_weights" - argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "zero_state" - argspec: "args=[\'self\', \'batch_size\', \'dtype\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.pbtxt index 3c78b07b39..b1f687f529 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.rnn_cell.pbtxt @@ -12,10 +12,6 @@ tf_module { name: "LSTMStateTuple" mtype: "" } - member { - name: "MultiRNNCell" - mtype: "" - } member { name: "RNNCell" mtype: "" -- GitLab From 4c75fb1cb917320acb386cf26adeb8e5151ca4f6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 09:58:14 -0800 Subject: [PATCH 110/672] Improve error message reporting for check_numerics gradient. At present the op message is only printed if the numeric check fails during the op's 'forward' computation. If the check fails during the gradient, there is no identifier on *which* op's gradient failed. This is the Python equivalent of https://github.com/tensorflow/tensorflow/commit/7e48bada PiperOrigin-RevId: 222262823 --- tensorflow/python/ops/array_grad.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/array_grad.py b/tensorflow/python/ops/array_grad.py index 68c392bf28..6edc193361 100644 --- a/tensorflow/python/ops/array_grad.py +++ b/tensorflow/python/ops/array_grad.py @@ -489,10 +489,12 @@ def _GatherNdGrad(op, grad): @ops.RegisterGradient("CheckNumerics") -def _CheckNumericsGrad(_, grad): +def _CheckNumericsGrad(op, grad): """Gradient for check_numerics op.""" return array_ops.check_numerics( - grad, "Not a number (NaN) or infinity (Inf) values detected in gradient.") + grad, + "Not a number (NaN) or infinity (Inf) values detected in gradient. %s" % + op.get_attr("message")) @ops.RegisterGradient("PlaceholderWithDefault") -- GitLab From 3275747a481a5bbc8d099a063c356d0938fdeea9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 10:07:02 -0800 Subject: [PATCH 111/672] [TF:XLA] Fix the output type of ArgMaxCustomCallOp. PiperOrigin-RevId: 222264582 --- tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc index e310db2162..42bf4b06e5 100644 --- a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc +++ b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc @@ -119,6 +119,10 @@ class ArgMaxCustomCallOp : public XlaOpKernel { ", but got shape: ", input_shape.DebugString())); } + const DataType dtype = output_type(0); + xla::PrimitiveType output_type; + OP_REQUIRES_OK(ctx, DataTypeToPrimitiveType(dtype, &output_type)); + output = xla::ConvertElementType(output, output_type); ctx->SetOutput(0, output); } -- GitLab From 0add015954ded4642855918e8346b4f107f8c2b6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 10:17:06 -0800 Subject: [PATCH 112/672] [TF:XLA] Implement StatelessMultinomial. PiperOrigin-RevId: 222266213 --- .../compiler/tests/categorical_op_test.py | 31 +++++++++ .../compiler/tf2xla/kernels/categorical_op.cc | 66 +++++++++++++++++-- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/tensorflow/compiler/tests/categorical_op_test.py b/tensorflow/compiler/tests/categorical_op_test.py index 532e2b5748..15108487cf 100644 --- a/tensorflow/compiler/tests/categorical_op_test.py +++ b/tensorflow/compiler/tests/categorical_op_test.py @@ -27,6 +27,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import random_seed from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops +from tensorflow.python.ops import stateless_random_ops from tensorflow.python.platform import googletest @@ -138,6 +139,36 @@ class CategoricalTest(xla_test.XLATestCase): chi2 = self._chi2(probs, freqs) self.assertLess(chi2, 1e-3) + def testStatelessMultinomialIsInRange(self): + for dtype in self.float_types: + for output_dtype in self.output_dtypes(): + with self.cached_session() as sess: + with self.test_scope(): + seed_t = array_ops.placeholder(dtypes.int32, shape=[2]) + x = stateless_random_ops.stateless_multinomial( + array_ops.ones(shape=[1, 20], dtype=dtype), + 1000, + seed_t, + output_dtype=output_dtype) + y = sess.run(x, {seed_t: [0x12345678, 0xabcdef12]}) + self.assertTrue((y >= 0).sum() == 1000) + self.assertTrue((y < 20).sum() == 1000) + + def testDeterminismMultinomial(self): + # Stateless values should be equal iff the seeds are equal (roughly) + num_samples = 10 + with self.cached_session(), self.test_scope(): + seed_t = array_ops.placeholder(dtypes.int32, shape=[2]) + seeds = [(x, y) for x in range(5) for y in range(5)] * 3 + for logits in ([[0.1, 0.25, 0.5, 0.15]], [[0.5, 0.5], [0.8, 0.2], + [0.25, 0.75]]): + pure = stateless_random_ops.stateless_multinomial( + logits, num_samples, seed=seed_t) + values = [(seed, pure.eval(feed_dict={seed_t: seed})) for seed in seeds] + for s0, v0 in values: + for s1, v1 in values: + self.assertEqual(s0 == s1, np.all(v0 == v1)) + if __name__ == '__main__': googletest.main() diff --git a/tensorflow/compiler/tf2xla/kernels/categorical_op.cc b/tensorflow/compiler/tf2xla/kernels/categorical_op.cc index ad85940920..3e398fff95 100644 --- a/tensorflow/compiler/tf2xla/kernels/categorical_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/categorical_op.cc @@ -21,10 +21,13 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/lib/arithmetic.h" +#include "tensorflow/compiler/xla/client/lib/prng.h" #include "tensorflow/compiler/xla/client/xla_builder.h" +#include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/tensor_shape.h" +#include "tensorflow/core/framework/types.pb.h" namespace tensorflow { namespace { @@ -57,8 +60,6 @@ class CategoricalOp : public XlaOpKernel { const int64 batch_size = logits_shape.dim_size(0); const int64 num_classes = logits_shape.dim_size(1); - xla::XlaBuilder* builder = ctx->builder(); - xla::Shape uniform_shape; int class_dimension; if (num_samples > 1) { @@ -83,16 +84,16 @@ class CategoricalOp : public XlaOpKernel { xla::ShapeUtil::MakeShape(uniform_xla_type, uniform_shape_array); class_dimension = 1; } - xla::XlaOp uniforms = - xla::RngUniform(XlaHelpers::Zero(builder, input_type(0)), - XlaHelpers::One(builder, input_type(0)), uniform_shape); + xla::PrimitiveType type; + OP_REQUIRES_OK(ctx, DataTypeToPrimitiveType(input_type(0), &type)); + xla::XlaOp log_uniforms = GetLogUniforms(uniform_shape, type, ctx); // Use Gumbel softmax trick to generate categorical samples. // See: // https://hips.seas.harvard.edu/blog/2013/04/06/the-gumbel-max-trick-for-discrete-distributions/ // TODO(b/68769470): Switch to using a cumulative sum approach. auto softmax_entries = - xla::Sub(logits, xla::Log(-xla::Log(uniforms)), + xla::Sub(logits, log_uniforms, /*broadcast_dimensions=*/{0, class_dimension}); xla::PrimitiveType xla_output_type; @@ -107,6 +108,16 @@ class CategoricalOp : public XlaOpKernel { ctx->SetOutput(0, argmax); } + virtual xla::XlaOp GetLogUniforms(xla::Shape uniform_shape, + xla::PrimitiveType type, + XlaOpKernelContext* ctx) { + xla::XlaBuilder* builder = ctx->builder(); + auto uniforms = + xla::RngUniform(XlaHelpers::Zero(builder, input_type(0)), + XlaHelpers::One(builder, input_type(0)), uniform_shape); + return xla::Log(-xla::Log(uniforms)); + } + private: TF_DISALLOW_COPY_AND_ASSIGN(CategoricalOp); }; @@ -115,5 +126,48 @@ class CategoricalOp : public XlaOpKernel { REGISTER_XLA_OP(Name("Multinomial").CompileTimeConstantInput("num_samples"), CategoricalOp); +class StatelessCategoricalOp : public CategoricalOp { + public: + explicit StatelessCategoricalOp(OpKernelConstruction* ctx) + : CategoricalOp(ctx) { + OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &dtype_)); + } + + xla::XlaOp GetLogUniforms(xla::Shape uniform_shape, xla::PrimitiveType type, + XlaOpKernelContext* ctx) override { + xla::XlaOp seed = ctx->Input(2); + auto seed0 = xla::Reshape(xla::Slice(seed, {0}, {1}, {1}), {}); + auto seed1 = xla::Reshape(xla::Slice(seed, {1}, {2}, {1}), {}); + + xla::XlaBuilder* builder = ctx->builder(); + if (uniform_shape.element_type() == xla::BF16) { + uniform_shape.set_element_type(xla::F32); + } + auto uniforms = xla::StatelessRngUniform( + {seed0, seed1}, uniform_shape, XlaHelpers::Zero(builder, DT_FLOAT), + XlaHelpers::One(builder, DT_FLOAT)); + return xla::ConvertElementType(xla::Log(-xla::Log(uniforms)), type); + } + + void Compile(XlaOpKernelContext* ctx) override { + TensorShape seed_shape = ctx->InputShape(2); + OP_REQUIRES(ctx, seed_shape.dims() == 1 && seed_shape.dim_size(0) == 2, + errors::InvalidArgument("seed must have shape [2], not ", + seed_shape.DebugString())); + CategoricalOp::Compile(ctx); + } + + private: + DataType dtype_; + + TF_DISALLOW_COPY_AND_ASSIGN(StatelessCategoricalOp); +}; + +REGISTER_XLA_OP(Name("StatelessMultinomial") + .CompileTimeConstantInput("num_samples") + .TypeConstraint("T", {DT_FLOAT, DT_BFLOAT16}) + .TypeConstraint("Tseed", DT_INT32), + StatelessCategoricalOp); + } // anonymous namespace } // namespace tensorflow -- GitLab From f0335444ce854f5e47e26631b2be708dff2d2224 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 10:24:36 -0800 Subject: [PATCH 113/672] TFTRT: change all instances of VLOG(0) to LOG(INFO) --- tensorflow/contrib/tensorrt/convert/convert_graph.cc | 4 ++-- tensorflow/contrib/tensorrt/convert/convert_nodes.cc | 2 +- tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc | 4 ++-- tensorflow/contrib/tensorrt/resources/trt_resources.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 9428fad309..69c8be8b57 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -170,7 +170,7 @@ tensorflow::Status BuildNodeMap( tensorflow::Status ConvertCalibGraphToInferGraph( const tensorflow::GraphDef& graph_def, tensorflow::GraphDef* infer_graph, bool is_dyn_op) { - VLOG(0) << "Starting Calib Conversion"; + LOG(INFO) << "Starting Calib Conversion"; infer_graph->CopyFrom(graph_def); auto trt_rm = TRTResourceManager::instance(); auto calib_rm = trt_rm->getManager("TRTCalibration"); @@ -876,7 +876,7 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { // need to check the input edges. [](const Edge* edge) { return true; }, OutputEdgeValidator(), segment_options, &initial_segments)); - VLOG(0) << "Number of TensorRT candidate segments: " + LOG(INFO) << "Number of TensorRT candidate segments: " << initial_segments.size(); // Get the EngineInfo for each segment. diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 68015a9a78..0e4dca5960 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -130,7 +130,7 @@ void GetOutputProperties(const grappler::GraphProperties& graph_properties, *dtype = out_shape.dtype(); *shape = out_shape.shape(); } else { - VLOG(0) << "Unknown output shape" << node->name(); + LOG(INFO) << "Unknown output shape" << node->name(); *dtype = node->output_type(out_port); } } diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc index 3cdad69f49..cff6be9759 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc @@ -491,7 +491,7 @@ TRTEngineOp::EngineCtxPair& TRTEngineOp::GetEngine(int batch_size, } TrtUniquePtrType engine; bool convert_successfully = false; - VLOG(0) << "Building a new TensorRT engine for " << name() + LOG(INFO) << "Building a new TensorRT engine for " << name() << " with batch size " << batch_size; // Up to this point, calibrator_ can never be empty, since otherwise it // means calibration_mode_ is true and this path won't get executed. @@ -567,7 +567,7 @@ tensorflow::Status TRTEngineOp::AllocateCalibrationResources( const int64 workspace_size_bytes = workspace_size_; cres->thr_.reset(new std::thread([cres, label, segment_graph, shapes, platform_gpu_id, workspace_size_bytes]() { - VLOG(0) << "Starting calibration thread on device " << platform_gpu_id + LOG(INFO) << "Starting calibration thread on device " << platform_gpu_id << ", Calibration Resource @ " << cres; auto err = cudaSetDevice(platform_gpu_id); if (err != cudaSuccess) { diff --git a/tensorflow/contrib/tensorrt/resources/trt_resources.h b/tensorflow/contrib/tensorrt/resources/trt_resources.h index 840da6e78d..6b68f92d16 100644 --- a/tensorflow/contrib/tensorrt/resources/trt_resources.h +++ b/tensorflow/contrib/tensorrt/resources/trt_resources.h @@ -39,7 +39,7 @@ namespace tensorrt { class TRTCalibrationResource : public tensorflow::ResourceBase { public: ~TRTCalibrationResource() { - VLOG(0) << "Destroying Calibration Resource " << std::endl << DebugString(); + LOG(INFO) << "Destroying Calibration Resource " << std::endl << DebugString(); builder_.reset(); engine_.reset(); // We need to manually destroy the builder and engine before the allocator -- GitLab From 1c850ad297ff2b3236a440893b1a3b1ebc8a8ca7 Mon Sep 17 00:00:00 2001 From: Yanhui Liang Date: Tue, 20 Nov 2018 10:40:47 -0800 Subject: [PATCH 114/672] Change signature of tf.image.crop_and_resize and tf.image.extract_image_patches for TF 2.0. PiperOrigin-RevId: 222270163 --- .../python_api/api_def_CropAndResize.pbtxt | 4 +- .../api_def_ExtractImagePatches.pbtxt | 8 +-- tensorflow/python/ops/array_ops.py | 45 ++++++++++++ tensorflow/python/ops/image_ops_impl.py | 69 +++++++++++++++++++ .../api/golden/v2/tensorflow.image.pbtxt | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 9 +++ 6 files changed, 127 insertions(+), 12 deletions(-) diff --git a/tensorflow/core/api_def/python_api/api_def_CropAndResize.pbtxt b/tensorflow/core/api_def/python_api/api_def_CropAndResize.pbtxt index ce65f8172d..2559a6c80b 100644 --- a/tensorflow/core/api_def/python_api/api_def_CropAndResize.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_CropAndResize.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "CropAndResize" - endpoint { - name: "image.crop_and_resize" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_ExtractImagePatches.pbtxt b/tensorflow/core/api_def/python_api/api_def_ExtractImagePatches.pbtxt index 0bd8b1c11a..17921dea4d 100644 --- a/tensorflow/core/api_def/python_api/api_def_ExtractImagePatches.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_ExtractImagePatches.pbtxt @@ -1,10 +1,4 @@ op { graph_op_name: "ExtractImagePatches" - endpoint { - name: "image.extract_image_patches" - } - endpoint { - name: "extract_image_patches" - deprecation_version: 2 - } + visibility: HIDDEN } diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 2a7989e889..85a2c9192d 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -3201,3 +3201,48 @@ def searchsorted(sorted_sequence, quantize.__doc__ = gen_array_ops.quantize_v2.__doc__ + + +@tf_export("image.extract_image_patches", v1=[]) +def extract_image_patches_v2( + images, + sizes, + strides, + rates, + padding, + name=None): + # pylint: disable=line-too-long + r"""Extract `patches` from `images` and put them in the \"depth\" output dimension. + + Args: + images: A 4-D Tensor with shape `[batch, in_rows, in_cols, depth] + sizes: The size of the sliding window for each dimension of `images`. + strides: A 1-D Tensor of length 4. How far the centers of two consecutive + patches are in the images. Must be: `[1, stride_rows, stride_cols, 1]`. + rates: A 1-D Tensor of length 4. Must be: `[1, rate_rows, rate_cols, 1]`. + This is the input stride, specifying how far two consecutive patch samples + are in the input. Equivalent to extracting patches with `patch_sizes_eff = + patch_sizes + (patch_sizes - 1) * (rates - 1)`, followed by subsampling + them spatially by a factor of `rates`. This is equivalent to `rate` in + dilated (a.k.a. Atrous) convolutions. + padding: The type of padding algorithm to use. + We specify the size-related attributes as: ```python ksizes = [1, + ksize_rows, ksize_cols, 1] strides = [1, strides_rows, strides_cols, 1] + rates = [1, rates_rows, rates_cols, 1] + name: A name for the operation (optional). + + Returns: + A 4-D Tensor. Has the same type as `images`, and with shape `[batch, + out_rows, out_cols, ksize_rows * ksize_cols * depth]` containing image + patches with size `ksize_rows x ksize_cols x depth` vectorized in the + \"depth\" dimension. Note `out_rows` and `out_cols` are the dimensions of + the output patches. + """ + # pylint: enable=line-too-long + return gen_array_ops.extract_image_patches( + images, sizes, strides, rates, padding, name) + +extract_image_patches_deprecation = deprecation.deprecated_args( + None, "ksizes is deprecated, use sizes instead", "ksizes") +tf_export(v1=["image.extract_image_patches", "extract_image_patches"])( + extract_image_patches_deprecation(gen_array_ops.extract_image_patches)) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 4d1357abbc..c4b5db9418 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -2861,3 +2861,72 @@ resize_nearest_neighbor_deprecation = deprecation.deprecated( 'instead.')) tf_export(v1=['image.resize_nearest_neighbor'])( resize_nearest_neighbor_deprecation(gen_image_ops.resize_nearest_neighbor)) + + +@tf_export('image.crop_and_resize', v1=[]) +def crop_and_resize_v2( + image, + boxes, + box_indices, + crop_size, + method='bilinear', + extrapolation_value=0, + name=None): + """Extracts crops from the input image tensor and resizes them. + + Extracts crops from the input image tensor and resizes them using bilinear + sampling or nearest neighbor sampling (possibly with aspect ratio change) to a + common output size specified by `crop_size`. This is more general than the + `crop_to_bounding_box` op which extracts a fixed size slice from the input + image and does not allow resizing or aspect ratio change. + + Returns a tensor with `crops` from the input `image` at positions defined at + the bounding box locations in `boxes`. The cropped boxes are all resized (with + bilinear or nearest neighbor interpolation) to a fixed + `size = [crop_height, crop_width]`. The result is a 4-D tensor + `[num_boxes, crop_height, crop_width, depth]`. The resizing is corner aligned. + In particular, if `boxes = [[0, 0, 1, 1]]`, the method will give identical + results to using `tf.image.resize_bilinear()` or + `tf.image.resize_nearest_neighbor()`(depends on the `method` argument) with + `align_corners=True`. + + Args: + image: A 4-D tensor of shape `[batch, image_height, image_width, depth]`. + Both `image_height` and `image_width` need to be positive. + boxes: A 2-D tensor of shape `[num_boxes, 4]`. The `i`-th row of the tensor + specifies the coordinates of a box in the `box_ind[i]` image and is + specified in normalized coordinates `[y1, x1, y2, x2]`. A normalized + coordinate value of `y` is mapped to the image coordinate at `y * + (image_height - 1)`, so as the `[0, 1]` interval of normalized image + height is mapped to `[0, image_height - 1]` in image height coordinates. + We do allow `y1` > `y2`, in which case the sampled crop is an up-down + flipped version of the original image. The width dimension is treated + similarly. Normalized coordinates outside the `[0, 1]` range are allowed, + in which case we use `extrapolation_value` to extrapolate the input image + values. + box_indices: A 1-D tensor of shape `[num_boxes]` with int32 values in `[0, + batch)`. The value of `box_ind[i]` specifies the image that the `i`-th box + refers to. + crop_size: A 1-D tensor of 2 elements, `size = [crop_height, crop_width]`. + All cropped image patches are resized to this size. The aspect ratio of + the image content is not preserved. Both `crop_height` and `crop_width` + need to be positive. + method: An optional string specifying the sampling method for resizing. It + can be either `"bilinear"` or `"nearest"` and default to `"bilinear"`. + Currently two sampling methods are supported: Bilinear and Nearest + Neighbor. + extrapolation_value: An optional `float`. Defaults to `0`. Value used for + extrapolation, when applicable. + name: A name for the operation (optional). + + Returns: + A 4-D tensor of shape `[num_boxes, crop_height, crop_width, depth]`. + """ + return gen_image_ops.crop_and_resize( + image, boxes, box_indices, crop_size, method, extrapolation_value, name) + + +crop_and_resize_deprecation = deprecation.deprecated_args( + None, 'box_ind is deprecated, use box_indices instead', 'box_ind') +tf_export(v1=['image.crop_and_resize'])( + crop_and_resize_deprecation(gen_image_ops.crop_and_resize)) diff --git a/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt index f25fb6541e..dcf80e3342 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt @@ -38,7 +38,7 @@ tf_module { } member_method { name: "crop_and_resize" - argspec: "args=[\'image\', \'boxes\', \'box_ind\', \'crop_size\', \'method\', \'extrapolation_value\', \'name\'], varargs=None, keywords=None, defaults=[\'bilinear\', \'0\', \'None\'], " + argspec: "args=[\'image\', \'boxes\', \'box_indices\', \'crop_size\', \'method\', \'extrapolation_value\', \'name\'], varargs=None, keywords=None, defaults=[\'bilinear\', \'0\', \'None\'], " } member_method { name: "crop_to_bounding_box" @@ -86,7 +86,7 @@ tf_module { } member_method { name: "extract_image_patches" - argspec: "args=[\'images\', \'ksizes\', \'strides\', \'rates\', \'padding\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + argspec: "args=[\'images\', \'sizes\', \'strides\', \'rates\', \'padding\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "extract_jpeg_shape" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 9b2abb9d2a..1074ba5702 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -31,6 +31,15 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # Maps from a function name to a dictionary that describes how to # map from an old argument keyword to the new argument keyword. self.function_keyword_renames = { + "tf.image.crop_and_resize": { + "box_ind": "box_indices", + }, + "tf.image.extract_image_patches": { + "ksizes": "sizes", + }, + "tf.extract_image_patches": { + "ksizes": "sizes", + }, "tf.expand_dims": { "dim": "axis", }, -- GitLab From a3650434746cba6b78d9846fbde3b7f31f6a33c8 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Tue, 20 Nov 2018 11:00:02 -0800 Subject: [PATCH 115/672] [tf.data] Enable `tf.data.experimental.Optional` as a dataset component. This change introduces `DatasetStructure` as a `Structure` subclass for representing the structure of a `Dataset` value, and changes the representation of "legacy structures" for non-Tensor components to use the new class. Previously, a nested `Dataset` was represented by a `_NestedDatasetComponent` that appeared at the same position in `Dataset.output_types`, `Dataset.output_shapes`, and `Dataset.output_classes`. After this change, we allow a `Structure` object to substitute for `_NestedDatasetComponent`. Thus `DatasetStructure` becomes the direct replacement for `_NestedDatasetComponent`, and `OptionalStructure` can be used in the same position to represent an `Optional` as a component of a dataset element. PiperOrigin-RevId: 222273133 --- tensorflow/python/data/experimental/ops/BUILD | 2 +- .../python/data/experimental/ops/grouping.py | 16 +- tensorflow/python/data/kernel_tests/BUILD | 4 + .../data/kernel_tests/dataset_ops_test.py | 61 ++++ tensorflow/python/data/ops/dataset_ops.py | 260 +++++++----------- tensorflow/python/data/ops/optional_ops.py | 12 +- tensorflow/python/data/util/structure.py | 26 +- tensorflow/python/data/util/structure_test.py | 9 +- 8 files changed, 202 insertions(+), 188 deletions(-) diff --git a/tensorflow/python/data/experimental/ops/BUILD b/tensorflow/python/data/experimental/ops/BUILD index 170fda90b6..b6c1376b6a 100644 --- a/tensorflow/python/data/experimental/ops/BUILD +++ b/tensorflow/python/data/experimental/ops/BUILD @@ -165,7 +165,7 @@ py_library( "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/util:nest", - "//tensorflow/python/data/util:sparse", + "//tensorflow/python/data/util:structure", ], ) diff --git a/tensorflow/python/data/experimental/ops/grouping.py b/tensorflow/python/data/experimental/ops/grouping.py index 80ca7104d8..db10ea3b7f 100644 --- a/tensorflow/python/data/experimental/ops/grouping.py +++ b/tensorflow/python/data/experimental/ops/grouping.py @@ -21,6 +21,7 @@ import numpy as np from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest +from tensorflow.python.data.util import structure from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -448,7 +449,10 @@ class _GroupByWindowDataset(dataset_ops.UnaryDataset): def _make_reduce_func(self, reduce_func, input_dataset): """Make wrapping defun for reduce_func.""" - nested_dataset = dataset_ops._NestedDatasetComponent(input_dataset) # pylint: disable=protected-access + nested_dataset = dataset_ops.DatasetStructure( + structure.Structure._from_legacy_structure( # pylint: disable=protected-access + input_dataset.output_types, input_dataset.output_shapes, + input_dataset.output_classes)) wrapped_func = dataset_ops.StructuredFunctionWrapper( reduce_func, self._transformation_name(), @@ -456,11 +460,13 @@ class _GroupByWindowDataset(dataset_ops.UnaryDataset): input_shapes=(tensor_shape.scalar(), nested_dataset), input_types=(dtypes.int64, nested_dataset)) if not isinstance( - wrapped_func.output_classes, dataset_ops._NestedDatasetComponent): # pylint: disable=protected-access + wrapped_func.output_structure, dataset_ops.DatasetStructure): raise TypeError("`reduce_func` must return a `Dataset` object.") - self._output_classes = wrapped_func.output_classes.output_classes - self._output_types = wrapped_func.output_types.output_types - self._output_shapes = wrapped_func.output_shapes.output_shapes + # pylint: disable=protected-access + element_structure = wrapped_func.output_structure._element_structure + self._output_classes = element_structure._to_legacy_output_classes() + self._output_types = element_structure._to_legacy_output_types() + self._output_shapes = element_structure._to_legacy_output_shapes() self._reduce_func = wrapped_func.function @property diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index 21eed2b070..fa1f6d701a 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -117,8 +117,12 @@ tf_py_test( "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", "//tensorflow/python:sparse_tensor", + "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:optional_ops", + "//tensorflow/python/data/util:structure", ], ) diff --git a/tensorflow/python/data/kernel_tests/dataset_ops_test.py b/tensorflow/python/data/kernel_tests/dataset_ops_test.py index a5324af4d0..1f22a37c2e 100644 --- a/tensorflow/python/data/kernel_tests/dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_ops_test.py @@ -24,10 +24,14 @@ import numpy as np from tensorflow.core.framework import graph_pb2 from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.ops import optional_ops from tensorflow.python.data.ops import readers from tensorflow.python.data.util import nest +from tensorflow.python.data.util import structure +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import tensor_shape from tensorflow.python.platform import test @@ -249,6 +253,63 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertTrue(ds.options().experimental_autotune) self.assertTrue(ds.options().experimental_filter_fusion) + # pylint: disable=g-long-lambda + @parameterized.named_parameters( + ("Tensor", lambda: constant_op.constant(37.0), + structure.TensorStructure(dtypes.float32, [])), + ("SparseTensor", lambda: sparse_tensor.SparseTensor( + indices=[[0]], values=constant_op.constant([0], dtype=dtypes.int32), + dense_shape=[1]), + structure.SparseTensorStructure(dtypes.int32, [1])), + ("Nest", lambda: { + "a": constant_op.constant(37.0), + "b": (constant_op.constant(["Foo"]), constant_op.constant("Bar"))}, + structure.NestedStructure({ + "a": structure.TensorStructure(dtypes.float32, []), + "b": (structure.TensorStructure(dtypes.string, [1]), + structure.TensorStructure(dtypes.string, []))})), + ("Dataset", lambda: dataset_ops.Dataset.from_tensor_slices( + constant_op.constant([1, 2, 3])), + dataset_ops.DatasetStructure( + structure.TensorStructure(dtypes.int32, []))), + ("Optional", lambda: optional_ops.Optional.from_value(37.0), + optional_ops.OptionalStructure( + structure.TensorStructure(dtypes.float32, []))), + ) + def testDatasetStructure(self, tf_value_fn, expected_element_structure): + dataset = dataset_ops.Dataset.from_tensors(0).map(lambda _: tf_value_fn()) + dataset_structure = structure.Structure.from_value(dataset) + self.assertIsInstance(dataset_structure, dataset_ops.DatasetStructure) + + # TODO(b/110122868): Add a public API to `tf.data.Dataset` for accessing + # the element structure. + self.assertTrue(expected_element_structure.is_compatible_with( + dataset_structure._element_structure)) + self.assertTrue(dataset_structure._element_structure.is_compatible_with( + expected_element_structure)) + + self.assertEqual([dtypes.variant], dataset_structure._flat_types) + self.assertEqual([tensor_shape.scalar()], dataset_structure._flat_shapes) + + # Assert that the `Dataset` survives a round-trip via _from_tensor_list() + # and _to_tensor_list(). + round_trip_dataset = dataset_structure._from_tensor_list( + dataset_structure._to_tensor_list(dataset)) + + value = tf_value_fn() + + if isinstance(value, dataset_ops.Dataset): + self.assertDatasetsEqual(value, dataset.flat_map(lambda x: x)) + elif isinstance(value, optional_ops.Optional): + self.assertDatasetProduces( + round_trip_dataset.map(lambda opt: opt.get_value()), + [self.evaluate(value.get_value())], + requires_initialization=True) + else: + self.assertDatasetProduces( + round_trip_dataset, [self.evaluate(tf_value_fn())], + requires_initialization=True) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 4a11619112..5c0cfe994d 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -31,6 +31,7 @@ from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.util import nest from tensorflow.python.data.util import random_seed from tensorflow.python.data.util import sparse +from tensorflow.python.data.util import structure as structure_lib from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -1868,57 +1869,6 @@ class SparseTensorSliceDataset(DatasetSource): return (dtypes.int64, self._sparse_tensor.dtype, dtypes.int64) -class _NestedDatasetComponent(object): - """The structure of a `Dataset` nested in a component of another `Dataset`. - - A `StructuredFunctionWrapper` around a function that returns a `Dataset` as - one of its components will have a `NestedDatasetComponent` in the - corresponding position in the `output_classes`, `output_shapes`, and - `output_types` properties. - - TODO(b/110122868): Add this class, or something equivalent, to the public API. - We are considering revising the public API for accessing Dataset structure - (`output_classes` etc.) based on experience with nested datasets and other - custom component types. - """ - - def __init__(self, - dataset=None, - output_shapes=None, - output_types=None, - output_classes=None): - if dataset is None: - if (output_classes is None or output_shapes is None or - output_types is None): - raise ValueError( - "Either `dataset`, or all of `output_classes`, " - "`output_shapes`, and `output_types` must be specified.") - self._output_classes = output_classes - self._output_shapes = output_shapes - self._output_types = output_types - else: - if not (output_classes is None and output_shapes is None and - output_types is None): - raise ValueError( - "Either `dataset`, or all of `output_classes`, " - "`output_shapes`, and `output_types` must be specified.") - self._output_classes = dataset.output_classes - self._output_shapes = dataset.output_shapes - self._output_types = dataset.output_types - - @property - def output_classes(self): - return self._output_classes - - @property - def output_shapes(self): - return self._output_shapes - - @property - def output_types(self): - return self._output_types - - class _VariantDataset(DatasetV2): """A Dataset wrapper around a `tf.variant`-typed function argument.""" @@ -1935,15 +1885,73 @@ class _VariantDataset(DatasetV2): @property def output_classes(self): - return self._structure.output_classes + return self._structure._to_legacy_output_classes() # pylint: disable=protected-access @property def output_shapes(self): - return self._structure.output_shapes + return self._structure._to_legacy_output_shapes() # pylint: disable=protected-access @property def output_types(self): - return self._structure.output_types + return self._structure._to_legacy_output_types() # pylint: disable=protected-access + + +class DatasetStructure(structure_lib.Structure): + """Represents a `Dataset` of structured values.""" + + def __init__(self, element_structure): + self._element_structure = element_structure + + @property + def _flat_shapes(self): + return [tensor_shape.scalar()] + + @property + def _flat_types(self): + return [dtypes.variant] + + def is_compatible_with(self, other): + # pylint: disable=protected-access + return (isinstance(other, DatasetStructure) and + self._element_structure.is_compatible_with( + other._element_structure)) + + def _to_tensor_list(self, value): + return [value._as_variant_tensor()] # pylint: disable=protected-access + + def _from_tensor_list(self, flat_value): + if (len(flat_value) != 1 or flat_value[0].dtype != dtypes.variant or + not flat_value[0].shape.is_compatible_with(tensor_shape.scalar())): + raise ValueError( + "DatasetStructure corresponds to a single tf.variant scalar.") + return self._from_compatible_tensor_list(flat_value) + + def _from_compatible_tensor_list(self, flat_value): + # pylint: disable=protected-access + return _VariantDataset(flat_value[0], self._element_structure) + + @staticmethod + def from_value(value): + # TODO(b/110122868): We can simplify this when a `Dataset` object has a + # `Structure`-valued property. + element_structure = structure_lib.Structure._from_legacy_structure( + value.output_types, value.output_shapes, value.output_classes) + return DatasetStructure(element_structure) + + def _to_legacy_output_types(self): + return self + + def _to_legacy_output_shapes(self): + return self + + def _to_legacy_output_classes(self): + return self + + +# pylint: disable=protected-access +structure_lib.Structure._register_custom_converter(DatasetV2, + DatasetStructure.from_value) +# pylint: enable=protected-access class StructuredFunctionWrapper(object): @@ -2001,6 +2009,9 @@ class StructuredFunctionWrapper(object): self._input_types = dataset.output_types self._input_classes = dataset.output_classes + self._input_structure = structure_lib.Structure._from_legacy_structure( # pylint: disable=protected-access + self._input_types, self._input_shapes, self._input_classes) + self._transformation_name = transformation_name readable_transformation_name = transformation_name.replace( ".", "_")[:-2] if len(transformation_name) > 2 else "" @@ -2008,35 +2019,18 @@ class StructuredFunctionWrapper(object): readable_transformation_name, function_utils.get_func_name(func), str(ops.uid()) - ]) if defun_kwargs is None: defun_kwargs = {} @function.Defun( - *self._defun_args(), func_name=self._func_name, **defun_kwargs) + *self._input_structure._flat_types, func_name=self._func_name, # pylint: disable=protected-access + **defun_kwargs) def tf_data_structured_function_wrapper(*args): """Wrapper for passing nested structures to and from tf.data functions.""" - flat_args = [] - for arg, arg_class, arg_shape, arg_type in zip( - args, - nest.flatten(self._input_classes), - nest.flatten(self._input_shapes), - nest.flatten(self._input_types)): - # TODO(b/110122868): Add a registration mechanism for new component - # types. - if arg_class is sparse_tensor_lib.SparseTensor: - arg = sparse.deserialize_sparse_tensors( - arg, arg_type, arg_shape, arg_class) - arg.indices.set_shape([None, arg_shape.ndims]) - arg.dense_shape.set_shape([arg_shape.ndims]) - elif isinstance(arg_class, _NestedDatasetComponent): - arg = _VariantDataset(arg, arg_class) - else: - arg.set_shape(arg_shape) - flat_args.append(arg) - nested_args = nest.pack_sequence_as(self._input_classes, flat_args) + # pylint: disable=protected-access + nested_args = self._input_structure._from_compatible_tensor_list(args) if not _should_unpack_args(nested_args): nested_args = (nested_args,) @@ -2054,50 +2048,14 @@ class StructuredFunctionWrapper(object): if isinstance(ret, list): ret = tuple(ret) - # Convert any `SparseTensorValue`s to `SparseTensor`s and all other - # values to tensors. - flat_ret = [] - flat_classes = [] - flat_shapes = [] - flat_types = [] - for t in nest.flatten(ret): - # TODO(b/110122868): Add a registration mechanism for new component - # types. - if sparse_tensor_lib.is_sparse(t): - t = sparse_tensor_lib.SparseTensor.from_value(t) - flat_ret.append(sparse.serialize_sparse_tensors(t)) - flat_classes.append(sparse_tensor_lib.SparseTensor) - flat_shapes.append(t.get_shape()) - flat_types.append(t.dtype) - elif isinstance(t, DatasetV2): - flat_ret.append(t._as_variant_tensor()) # pylint: disable=protected-access - component = _NestedDatasetComponent(t) - flat_classes.append(component) - flat_shapes.append(component) - flat_types.append(component) - if t.options() != Options(): - warnings.warn("Encountered a nested dataset with non-default " - "options. These options will not be propagated to " - "the outer dataset.") - else: - try: - t = ops.convert_to_tensor(t) - except (ValueError, TypeError): - raise TypeError("Unsupported return value from function passed to " - "%s: %s." % (transformation_name, t)) - flat_ret.append(t) - flat_classes.append(ops.Tensor) - flat_shapes.append(t.get_shape()) - flat_types.append(t.dtype) - - ret = nest.pack_sequence_as(ret, flat_ret) - self._output_classes = nest.pack_sequence_as(ret, flat_classes) - self._output_shapes = nest.pack_sequence_as(ret, flat_shapes) - self._output_types = nest.pack_sequence_as(ret, flat_types) + try: + self._output_structure = structure_lib.Structure.from_value(ret) + except (ValueError, TypeError): + raise TypeError("Unsupported return value from function passed to " + "%s: %s." % (transformation_name, ret)) _warn_if_collections(transformation_name) - - return flat_ret + return self._output_structure._to_tensor_list(ret) self._function = tf_data_structured_function_wrapper if add_to_graph: @@ -2108,32 +2066,21 @@ class StructuredFunctionWrapper(object): # in case (e.g.) we need to rerun the function. self._function._create_definition_if_needed() # pylint: disable=protected-access - def _defun_args(self): - """Returns a flat list of `tf.DType` for the input element structure.""" - ret = [] - for input_type, input_class in zip(nest.flatten(self._input_types), - nest.flatten(self._input_classes)): - # TODO(b/110122868): Add a registration mechanism for new component types. - if input_class is sparse_tensor_lib.SparseTensor: - ret.append(dtypes.variant) - elif isinstance(input_class, _NestedDatasetComponent): - ret.append(dtypes.variant) - else: - assert isinstance(input_type, dtypes.DType) - ret.append(input_type) - return ret + @property + def output_structure(self): + return self._output_structure @property def output_classes(self): - return self._output_classes + return self._output_structure._to_legacy_output_classes() # pylint: disable=protected-access @property def output_shapes(self): - return self._output_shapes + return self._output_structure._to_legacy_output_shapes() # pylint: disable=protected-access @property def output_types(self): - return self._output_types + return self._output_structure._to_legacy_output_types() # pylint: disable=protected-access @property def function(self): @@ -2156,30 +2103,12 @@ def flat_structure(dataset): A dictionary of keyword arguments that can be passed to many Dataset op constructors. """ - output_classes = [] - output_shapes = [] - output_types = [] - for output_class, output_shape, output_type in zip( - nest.flatten(dataset.output_classes), nest.flatten(dataset.output_shapes), - nest.flatten(dataset.output_types)): - if isinstance(output_class, _NestedDatasetComponent): - output_classes.append(output_class.output_classes) - output_shapes.append(output_shape.output_shapes) - output_types.append(output_type.output_types) - else: - output_classes.append(output_class) - output_shapes.append(output_shape) - output_types.append(output_type) - - output_classes = nest.pack_sequence_as(dataset.output_classes, output_classes) - output_shapes = nest.pack_sequence_as(dataset.output_shapes, output_shapes) - output_types = nest.pack_sequence_as(dataset.output_types, output_types) - + # pylint: disable=protected-access + structure = structure_lib.Structure._from_legacy_structure( + dataset.output_types, dataset.output_shapes, dataset.output_classes) return { - "output_shapes": - nest.flatten(sparse.as_dense_shapes(output_shapes, output_classes)), - "output_types": - nest.flatten(sparse.as_dense_types(output_types, output_classes)), + "output_shapes": structure._flat_shapes, + "output_types": structure._flat_types, } @@ -2902,11 +2831,13 @@ class FlatMapDataset(UnaryDataset): wrapped_func = StructuredFunctionWrapper( map_func, self._transformation_name(), dataset=input_dataset) - if not isinstance(wrapped_func.output_classes, _NestedDatasetComponent): + if not isinstance(wrapped_func.output_structure, DatasetStructure): raise TypeError("`map_func` must return a `Dataset` object.") - self._output_classes = wrapped_func.output_classes.output_classes - self._output_types = wrapped_func.output_types.output_types - self._output_shapes = wrapped_func.output_shapes.output_shapes + # pylint: disable=protected-access + element_structure = wrapped_func.output_structure._element_structure + self._output_classes = element_structure._to_legacy_output_classes() + self._output_types = element_structure._to_legacy_output_types() + self._output_shapes = element_structure._to_legacy_output_shapes() self._map_func = wrapped_func.function def _as_variant_tensor(self): @@ -3048,10 +2979,9 @@ class WindowDataset(UnaryDataset): self._output_classes = nest.pack_sequence_as( input_dataset.output_classes, [ - _NestedDatasetComponent( # pylint: disable=protected-access - output_classes=output_class, - output_shapes=output_shape, - output_types=output_type) + DatasetStructure( + structure_lib.Structure._from_legacy_structure( # pylint: disable=protected-access + output_type, output_shape, output_class)) for output_class, output_shape, output_type in zip( nest.flatten(input_dataset.output_classes), nest.flatten(input_dataset.output_shapes), diff --git a/tensorflow/python/data/ops/optional_ops.py b/tensorflow/python/data/ops/optional_ops.py index 91cf883ce9..4113b7ed31 100644 --- a/tensorflow/python/data/ops/optional_ops.py +++ b/tensorflow/python/data/ops/optional_ops.py @@ -183,19 +183,13 @@ class OptionalStructure(structure.Structure): return OptionalStructure(value.value_structure) def _to_legacy_output_types(self): - raise NotImplementedError("The `output_types` property is not supported on " - "structured objects containing an `Optional`. " - "Use the corresponding `structure` property.") + return self def _to_legacy_output_shapes(self): - raise NotImplementedError("The `output_shapes` property is not supported on" - " structured objects containing an `Optional`. " - "Use the corresponding `structure` property.") + return self def _to_legacy_output_classes(self): - raise NotImplementedError("The `output_classes` property is not supported " - "on structured objects containing an `Optional`. " - "Use the corresponding `structure` property.") + return self # pylint: disable=protected-access diff --git a/tensorflow/python/data/util/structure.py b/tensorflow/python/data/util/structure.py index 9a3118297d..3cf67b0745 100644 --- a/tensorflow/python/data/util/structure.py +++ b/tensorflow/python/data/util/structure.py @@ -208,14 +208,16 @@ class Structure(object): flat_ret = [] for flat_type, flat_shape, flat_class in zip(flat_types, flat_shapes, flat_classes): - if issubclass(flat_class, sparse_tensor_lib.SparseTensor): + if isinstance(flat_class, Structure): + flat_ret.append(flat_class) + elif issubclass(flat_class, sparse_tensor_lib.SparseTensor): flat_ret.append(SparseTensorStructure(flat_type, flat_shape)) elif issubclass(flat_class, ops.Tensor): flat_ret.append(TensorStructure(flat_type, flat_shape)) else: # NOTE(mrry): Since legacy structures produced by iterators only - # comprise Tensors, SparseTensors, and nests, we do not need to support - # all structure types here. + # comprise Tensors, SparseTensors, and nests, we do not need to + # support all structure types here. raise TypeError( "Could not build a structure for output class %r" % flat_type) @@ -381,6 +383,13 @@ class TensorStructure(Structure): return self._from_compatible_tensor_list(flat_value) def _from_compatible_tensor_list(self, flat_value): + # TODO(b/112266545): It would be cleaner to create a new `ensure_shape()` + # op here and return that, instead of mutating the input's shape using + # `Tensor.set_shape()`. However, that would add extra ops on the arguments + # of each `tf.data` function, which could impact performance. When this + # bug is resolved, we should be able to add the `ensure_shape()` ops and + # optimize them away using contextual shape information. + flat_value[0].set_shape(self._shape) return flat_value[0] @staticmethod @@ -406,7 +415,11 @@ class SparseTensorStructure(Structure): @property def _flat_shapes(self): - return [tensor_shape.vector(3)] + # NOTE(mrry): The default flat shape of a boxed `SparseTensor` is `(3,)`, + # but a `SparseTensorStructure` can also represent a batch of boxed + # `SparseTensor` objects with shape `(?, 3)` (and batches of batches, etc.), + # so the flat shape must be unknown. + return [tensor_shape.unknown_shape(None)] @property def _flat_types(self): @@ -428,8 +441,11 @@ class SparseTensorStructure(Structure): return self._from_compatible_tensor_list(flat_value) def _from_compatible_tensor_list(self, flat_value): - return sparse_ops.deserialize_sparse( + ret = sparse_ops.deserialize_sparse( flat_value[0], dtype=self._dtype, rank=self._dense_shape.ndims) + ret.indices.set_shape([None, self._dense_shape.ndims]) + ret.dense_shape.set_shape([self._dense_shape.ndims]) + return ret @staticmethod def from_value(value): diff --git a/tensorflow/python/data/util/structure_test.py b/tensorflow/python/data/util/structure_test.py index 630a0c912b..65a41a50f1 100644 --- a/tensorflow/python/data/util/structure_test.py +++ b/tensorflow/python/data/util/structure_test.py @@ -44,7 +44,7 @@ class StructureTest(test.TestCase, parameterized.TestCase): [dtypes.float32], [[]]), (lambda: sparse_tensor.SparseTensor( indices=[[3, 4]], values=[-1], dense_shape=[4, 5]), - structure.SparseTensorStructure, [dtypes.variant], [[3]]), + structure.SparseTensorStructure, [dtypes.variant], [None]), (lambda: (constant_op.constant(37.0), constant_op.constant([1, 2, 3])), structure.NestedStructure, [dtypes.float32, dtypes.int32], [[], [3]]), (lambda: { @@ -58,14 +58,17 @@ class StructureTest(test.TestCase, parameterized.TestCase): sparse_tensor.SparseTensor( indices=[[3, 4]], values=[-1], dense_shape=[4, 5])) }, structure.NestedStructure, - [dtypes.float32, dtypes.variant, dtypes.variant], [[], [3], [3]])) + [dtypes.float32, dtypes.variant, dtypes.variant], [[], None, None])) def testFlatStructure(self, value_fn, expected_structure, expected_types, expected_shapes): value = value_fn() s = structure.Structure.from_value(value) self.assertIsInstance(s, expected_structure) self.assertEqual(expected_types, s._flat_types) - self.assertEqual(expected_shapes, s._flat_shapes) + for expected, actual in zip(expected_shapes, s._flat_shapes): + self.assertTrue(actual.is_compatible_with(expected)) + self.assertTrue( + tensor_shape.as_shape(expected).is_compatible_with(actual)) @parameterized.parameters( (lambda: constant_op.constant(37.0), lambda: [ -- GitLab From 231d94406b9bb4c85e43ae15b2df391a439d6ccc Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 11:02:05 -0800 Subject: [PATCH 116/672] Update docstring for CategoricalAccuracy. PiperOrigin-RevId: 222273525 --- tensorflow/python/keras/metrics.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 7848be33f1..030bf4768c 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -760,6 +760,9 @@ class CategoricalAccuracy(MeanMetricWrapper): ultimately returned as `categorical accuracy`: an idempotent operation that simply divides `total` by `count`. + `y_pred` and `y_true` should be passed in as vectors of probabilities, rather + than as labels. If necessary, use `tf.one_hot` to expand `y_true` as a vector. + If `sample_weight` is `None`, weights default to 1. Use `sample_weight` of 0 to mask values. """ -- GitLab From 02c1056b0d35e53dc8173a8bd1b70196cf9ea0c4 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 20 Nov 2018 11:02:23 -0800 Subject: [PATCH 117/672] Rename random.set_random_seed to random.set_seed for TF 2.0 API. PiperOrigin-RevId: 222273633 --- tensorflow/python/framework/random_seed.py | 103 +++++++++++++++++- .../api/golden/v2/tensorflow.random.pbtxt | 2 +- tensorflow/tools/compatibility/renames_v2.py | 20 +++- 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/framework/random_seed.py b/tensorflow/python/framework/random_seed.py index 0d20693429..6b7f56a92c 100644 --- a/tensorflow/python/framework/random_seed.py +++ b/tensorflow/python/framework/random_seed.py @@ -82,8 +82,7 @@ def get_seed(op_seed): return seeds -@tf_export('random.set_random_seed', - v1=['random.set_random_seed', 'set_random_seed']) +@tf_export(v1=['random.set_random_seed', 'set_random_seed']) def set_random_seed(seed): """Sets the graph-level random seed. @@ -183,3 +182,103 @@ def set_random_seed(seed): context.set_global_seed(seed) else: ops.get_default_graph().seed = seed + + +@tf_export('random.set_seed', v1=[]) +def set_seed(seed): + """Sets the graph-level random seed. + + Operations that rely on a random seed actually derive it from two seeds: + the graph-level and operation-level seeds. This sets the graph-level seed. + + Its interactions with operation-level seeds is as follows: + + 1. If neither the graph-level nor the operation seed is set: + A random seed is used for this op. + 2. If the graph-level seed is set, but the operation seed is not: + The system deterministically picks an operation seed in conjunction + with the graph-level seed so that it gets a unique random sequence. + 3. If the graph-level seed is not set, but the operation seed is set: + A default graph-level seed and the specified operation seed are used to + determine the random sequence. + 4. If both the graph-level and the operation seed are set: + Both seeds are used in conjunction to determine the random sequence. + + To illustrate the user-visible effects, consider these examples: + + To generate different sequences across sessions, set neither + graph-level nor op-level seeds: + + ```python + a = tf.random_uniform([1]) + b = tf.random_normal([1]) + + print("Session 1") + with tf.Session() as sess1: + print(sess1.run(a)) # generates 'A1' + print(sess1.run(a)) # generates 'A2' + print(sess1.run(b)) # generates 'B1' + print(sess1.run(b)) # generates 'B2' + + print("Session 2") + with tf.Session() as sess2: + print(sess2.run(a)) # generates 'A3' + print(sess2.run(a)) # generates 'A4' + print(sess2.run(b)) # generates 'B3' + print(sess2.run(b)) # generates 'B4' + ``` + + To generate the same repeatable sequence for an op across sessions, set the + seed for the op: + + ```python + a = tf.random_uniform([1], seed=1) + b = tf.random_normal([1]) + + # Repeatedly running this block with the same graph will generate the same + # sequence of values for 'a', but different sequences of values for 'b'. + print("Session 1") + with tf.Session() as sess1: + print(sess1.run(a)) # generates 'A1' + print(sess1.run(a)) # generates 'A2' + print(sess1.run(b)) # generates 'B1' + print(sess1.run(b)) # generates 'B2' + + print("Session 2") + with tf.Session() as sess2: + print(sess2.run(a)) # generates 'A1' + print(sess2.run(a)) # generates 'A2' + print(sess2.run(b)) # generates 'B3' + print(sess2.run(b)) # generates 'B4' + ``` + + To make the random sequences generated by all ops be repeatable across + sessions, set a graph-level seed: + + ```python + tf.random.set_seed(1234) + a = tf.random_uniform([1]) + b = tf.random_normal([1]) + + # Repeatedly running this block with the same graph will generate the same + # sequences of 'a' and 'b'. + print("Session 1") + with tf.Session() as sess1: + print(sess1.run(a)) # generates 'A1' + print(sess1.run(a)) # generates 'A2' + print(sess1.run(b)) # generates 'B1' + print(sess1.run(b)) # generates 'B2' + + print("Session 2") + with tf.Session() as sess2: + print(sess2.run(a)) # generates 'A1' + print(sess2.run(a)) # generates 'A2' + print(sess2.run(b)) # generates 'B1' + print(sess2.run(b)) # generates 'B2' + ``` + + Args: + seed: integer. + """ + # TODO(go/tf2-random): change doc, update to match design doc + set_random_seed(seed) diff --git a/tensorflow/tools/api/golden/v2/tensorflow.random.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.random.pbtxt index ce8d277ec8..de5cb6b717 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.random.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.random.pbtxt @@ -29,7 +29,7 @@ tf_module { argspec: "args=[\'shape\', \'lam\', \'dtype\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\', \'None\'], " } member_method { - name: "set_random_seed" + name: "set_seed" argspec: "args=[\'seed\'], varargs=None, keywords=None, defaults=None" } member_method { diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 55a2804c80..f002418020 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -39,6 +39,7 @@ renames = { 'tf.GRAPH_DEF_VERSION': 'tf.version.GRAPH_DEF_VERSION', 'tf.GRAPH_DEF_VERSION_MIN_CONSUMER': 'tf.version.GRAPH_DEF_VERSION_MIN_CONSUMER', 'tf.GRAPH_DEF_VERSION_MIN_PRODUCER': 'tf.version.GRAPH_DEF_VERSION_MIN_PRODUCER', + 'tf.GraphKeys': 'tf.compat.v1.GraphKeys', 'tf.IdentityReader': 'tf.compat.v1.IdentityReader', 'tf.InteractiveSession': 'tf.compat.v1.InteractiveSession', 'tf.LMDBReader': 'tf.compat.v1.LMDBReader', @@ -198,7 +199,9 @@ renames = { 'tf.image.resize_area': 'tf.compat.v1.image.resize_area', 'tf.image.resize_bicubic': 'tf.compat.v1.image.resize_bicubic', 'tf.image.resize_bilinear': 'tf.compat.v1.image.resize_bilinear', + 'tf.image.resize_images': 'tf.compat.v1.image.resize_images', 'tf.image.resize_nearest_neighbor': 'tf.compat.v1.image.resize_nearest_neighbor', + 'tf.image.transpose_image': 'tf.compat.v1.image.transpose_image', 'tf.initialize_all_tables': 'tf.compat.v1.initialize_all_tables', 'tf.initialize_all_variables': 'tf.compat.v1.initialize_all_variables', 'tf.initialize_local_variables': 'tf.compat.v1.initialize_local_variables', @@ -354,6 +357,7 @@ renames = { 'tf.quantized_concat': 'tf.quantization.quantized_concat', 'tf.random.get_seed': 'tf.compat.v1.random.get_seed', 'tf.random.multinomial': 'tf.compat.v1.random.multinomial', + 'tf.random.set_random_seed': 'tf.compat.v1.random.set_random_seed', 'tf.random.stateless_multinomial': 'tf.compat.v1.random.stateless_multinomial', 'tf.random_crop': 'tf.image.random_crop', 'tf.random_gamma': 'tf.random.gamma', @@ -437,7 +441,7 @@ renames = { 'tf.serialize_many_sparse': 'tf.io.serialize_many_sparse', 'tf.serialize_sparse': 'tf.io.serialize_sparse', 'tf.serialize_tensor': 'tf.io.serialize_tensor', - 'tf.set_random_seed': 'tf.random.set_random_seed', + 'tf.set_random_seed': 'tf.compat.v1.set_random_seed', 'tf.setdiff1d': 'tf.compat.v1.setdiff1d', 'tf.sets.set_difference': 'tf.sets.difference', 'tf.sets.set_intersection': 'tf.sets.intersection', @@ -449,6 +453,7 @@ renames = { 'tf.sparse.merge': 'tf.compat.v1.sparse.merge', 'tf.sparse.placeholder': 'tf.compat.v1.sparse.placeholder', 'tf.sparse.reduce_max_sparse': 'tf.compat.v1.sparse.reduce_max_sparse', + 'tf.sparse.reduce_sum_sparse': 'tf.compat.v1.sparse.reduce_sum_sparse', 'tf.sparse_add': 'tf.compat.v1.sparse_add', 'tf.sparse_fill_empty_rows': 'tf.sparse.fill_empty_rows', 'tf.sparse_mask': 'tf.sparse.mask', @@ -459,8 +464,8 @@ renames = { 'tf.sparse_placeholder': 'tf.compat.v1.sparse_placeholder', 'tf.sparse_reduce_max': 'tf.compat.v1.sparse_reduce_max', 'tf.sparse_reduce_max_sparse': 'tf.compat.v1.sparse_reduce_max_sparse', - 'tf.sparse_reduce_sum': 'tf.sparse.reduce_sum', - 'tf.sparse_reduce_sum_sparse': 'tf.sparse.reduce_sum_sparse', + 'tf.sparse_reduce_sum': 'tf.compat.v1.sparse_reduce_sum', + 'tf.sparse_reduce_sum_sparse': 'tf.compat.v1.sparse_reduce_sum_sparse', 'tf.sparse_reorder': 'tf.sparse.reorder', 'tf.sparse_reset_shape': 'tf.sparse.reset_shape', 'tf.sparse_reshape': 'tf.sparse.reshape', @@ -496,6 +501,15 @@ renames = { 'tf.string_to_hash_bucket_fast': 'tf.strings.to_hash_bucket_fast', 'tf.string_to_hash_bucket_strong': 'tf.strings.to_hash_bucket_strong', 'tf.string_to_number': 'tf.strings.to_number', + 'tf.summary.audio': 'tf.compat.v1.summary.audio', + 'tf.summary.get_summary_description': 'tf.compat.v1.summary.get_summary_description', + 'tf.summary.histogram': 'tf.compat.v1.summary.histogram', + 'tf.summary.image': 'tf.compat.v1.summary.image', + 'tf.summary.merge': 'tf.compat.v1.summary.merge', + 'tf.summary.merge_all': 'tf.compat.v1.summary.merge_all', + 'tf.summary.scalar': 'tf.compat.v1.summary.scalar', + 'tf.summary.tensor_summary': 'tf.compat.v1.summary.tensor_summary', + 'tf.summary.text': 'tf.compat.v1.summary.text', 'tf.svd': 'tf.linalg.svd', 'tf.tables_initializer': 'tf.compat.v1.tables_initializer', 'tf.test.compute_gradient': 'tf.compat.v1.test.compute_gradient', -- GitLab From a96a27e92faa3e908c2a5952d5f8f0dfcb6fa4d2 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 11:23:36 -0800 Subject: [PATCH 118/672] TFTRT: split log for adding TRT node to two lines --- .../contrib/tensorrt/convert/convert_graph.cc | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 69c8be8b57..5038e74fdd 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -970,16 +970,9 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { &graph, alloc.get(), &engine_nodes); // If status is ok, we successfully added the node to the graph and can // remove segment ops. Otherwise graph is not modified. - string msg = StrCat("Adding TensorRT node ", engine.engine_name, " for segment ", - i, ", composed of ", + string msg = StrCat("Added TensorRT node ", engine.engine_name, " for segment ", + i, " consisting ", converted_segments.at(i).first.size(), " nodes"); - if (VLOG_IS_ON(1)) { - StrAppend(&msg, " ("); - for (const string& node_name : converted_segments.at(i).first) { - StrAppend(&msg, node_name, ", "); - } - StrAppend(&msg, ")"); - } if (status.ok()) { LOG(INFO) << msg << " succeeded."; for (auto node_name : converted_segments.at(i).first) { @@ -987,8 +980,13 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { } } else { // Graph is not modified. - LOG(WARNING) << msg << " failed: " << status << ". Skipping..."; + LOG(WARNING) << msg << " failed: " << status << ". Fallback to TF..."; + } + msg = "Segment consists of nodes: "; + for (const string& node_name : converted_segments.at(i).first) { + StrAppend(&msg, node_name, ", "); } + VLOG(1) << msg; } cudaSetDevice(old_cuda_device); graph.ToGraphDef(params.output_graph_def); -- GitLab From 5708ff3b7535cc22c054afe66d98beb71211603b Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 11:25:54 -0800 Subject: [PATCH 119/672] TFTRT: fix alignment --- tensorflow/contrib/tensorrt/convert/convert_graph.cc | 2 +- tensorflow/contrib/tensorrt/segment/segment.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 5038e74fdd..d688ebd7b4 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -877,7 +877,7 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { [](const Edge* edge) { return true; }, OutputEdgeValidator(), segment_options, &initial_segments)); LOG(INFO) << "Number of TensorRT candidate segments: " - << initial_segments.size(); + << initial_segments.size(); // Get the EngineInfo for each segment. std::unordered_map node_map; diff --git a/tensorflow/contrib/tensorrt/segment/segment.cc b/tensorflow/contrib/tensorrt/segment/segment.cc index 9ee7b76e30..ab44718256 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.cc +++ b/tensorflow/contrib/tensorrt/segment/segment.cc @@ -442,7 +442,8 @@ tensorflow::Status SegmentGraph( msg += elem + ", "; } LOG(INFO) << msg << "(For more information see " - << "https://docs.nvidia.com/deeplearning/dgx/integrate-tf-trt/index.html#support-ops)."; + << "https://docs.nvidia.com/deeplearning" + << "/dgx/integrate-tf-trt/index.html#support-ops)."; // The segmentation algorithm below visits nodes in reverse topological order // and attempts to merge nodes along output edges. That means that subgraphs -- GitLab From d1fec4590b803a51765706d9d7a35c0a1e917ac1 Mon Sep 17 00:00:00 2001 From: Saurabh Saxena Date: Tue, 20 Nov 2018 11:03:44 -0800 Subject: [PATCH 120/672] Support calling AddN on nested TensorLists. Disable SimplifyAggregation optimizer when aggregation variants. PiperOrigin-RevId: 222273920 --- .../optimizers/arithmetic_optimizer.cc | 4 ++- tensorflow/core/kernels/list_kernels.h | 15 +++++++-- .../kernel_tests/control_flow_ops_py_test.py | 14 ++++++++ .../python/kernel_tests/list_ops_test.py | 33 ++++++++++++++++++- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc index cf294cd20b..566701ec2a 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc @@ -2309,7 +2309,9 @@ class SimplifyAggregation : public ArithmeticOptimizerStage { ~SimplifyAggregation() override = default; bool IsSupported(const NodeDef* node) const override { - return IsAggregate(*node) && NumNonControlInputs(*node) > 0; + return IsAggregate(*node) && NumNonControlInputs(*node) > 0 && + GetDataTypeFromAttr(*node, "T") != + DT_VARIANT; // TODO(b/119787146): Enable for variants. } Status TrySimplify(NodeDef* node, string* simplified_node_name) override { diff --git a/tensorflow/core/kernels/list_kernels.h b/tensorflow/core/kernels/list_kernels.h index c2591f5314..75d91aff49 100644 --- a/tensorflow/core/kernels/list_kernels.h +++ b/tensorflow/core/kernels/list_kernels.h @@ -374,8 +374,12 @@ Status TensorListBinaryAdd(OpKernelContext* c, const TensorList& a, b_tensor.shape().DebugString(), " in position ", i); } Tensor out_tensor; - TF_RETURN_IF_ERROR( - c->allocate_temp(a_tensor.dtype(), a_tensor.shape(), &out_tensor)); + AllocatorAttributes attr; + if (a_tensor.dtype() == DT_VARIANT) { + attr.set_on_host(true); + } + TF_RETURN_IF_ERROR(c->allocate_temp(a_tensor.dtype(), a_tensor.shape(), + &out_tensor, attr)); out->tensors.push_back(out_tensor); switch (out_tensor.dtype()) { #define DTYPE_CASE(dtype) \ @@ -387,6 +391,13 @@ Status TensorListBinaryAdd(OpKernelContext* c, const TensorList& a, TF_CALL_NUMBER_TYPES(DTYPE_CASE) #undef DTYPE_CASE + case DataTypeToEnum::value: { + Variant* v_out = &(out_tensor.scalar()()); + TF_RETURN_IF_ERROR(BinaryOpVariants( + c, ADD_VARIANT_BINARY_OP, a_tensor.scalar()(), + b_tensor.scalar()(), v_out)); + break; + } default: return errors::InvalidArgument("Trying to add unsupported dtype ", out_tensor.dtype()); diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 0d6d2cc6da..3394df20d8 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -435,6 +435,20 @@ class ControlFlowTest(test.TestCase): self.assertEqual(1.0, control_flow_ops.cond(rv, case, lambda: t).eval()) + def testCondWithTensorArrayGrad(self): + with self.cached_session() as sess: + with ops.device(test.gpu_device_name()): + pred = array_ops.placeholder(dtypes.bool, []) + x = constant_op.constant([1.0, 2.0, 3.0]) + y = control_flow_ops.cond( + pred, lambda: functional_ops.map_fn(lambda z: z * 2.0, x), + lambda: constant_op.constant([1.0, 1.0, 1.0])) + g = gradients_impl.gradients(y, x)[0] + + self.assertAllEqual(sess.run(g, {pred: True}), [2.0, 2.0, 2.0]) + # TODO(b/119791601): Enable this. + # self.assertAllEqual(sess.run(g, {pred: False}), [0.0, 0.0, 0.0]) + @test_util.disable_control_flow_v2("b/113293074") def testCondIndexedSlicesDifferentTypes(self): with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/list_ops_test.py b/tensorflow/python/kernel_tests/list_ops_test.py index 2bc8ba463b..09cb5cf0ba 100644 --- a/tensorflow/python/kernel_tests/list_ops_test.py +++ b/tensorflow/python/kernel_tests/list_ops_test.py @@ -29,8 +29,8 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops -from tensorflow.python.framework import test_util from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gradients_impl @@ -834,6 +834,37 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertAllEqual(result[:2], [-1, 5]) self.assertIs(result[2], t) + def testAddN(self): + l1 = list_ops.tensor_list_from_tensor([1.0, 2.0], element_shape=[]) + l2 = list_ops.tensor_list_from_tensor([3.0, 4.0], element_shape=[]) + l3 = list_ops.tensor_list_from_tensor([5.0, 6.0], element_shape=[]) + result = math_ops.add_n((l1, l2, l3)) + result_t = list_ops.tensor_list_stack(result, element_dtype=dtypes.float32) + self.assertAllEqual(self.evaluate(result_t), [9., 12.]) + + def testAddNNestedList(self): + l1 = list_ops.tensor_list_from_tensor([1.0, 2.0], element_shape=[]) + l2 = list_ops.tensor_list_from_tensor([3.0, 4.0], element_shape=[]) + l3 = list_ops.tensor_list_from_tensor([5.0, 6.0], element_shape=[]) + l4 = list_ops.tensor_list_from_tensor([7.0, 8.0], element_shape=[]) + a = list_ops.empty_tensor_list( + element_dtype=dtypes.variant, element_shape=[]) + a = list_ops.tensor_list_push_back(a, l1) + a = list_ops.tensor_list_push_back(a, l2) + b = list_ops.empty_tensor_list( + element_dtype=dtypes.variant, element_shape=[]) + b = list_ops.tensor_list_push_back(b, l3) + b = list_ops.tensor_list_push_back(b, l4) + result = math_ops.add_n((a, b)) + result_0 = list_ops.tensor_list_stack( + list_ops.tensor_list_get_item(result, 0, element_dtype=dtypes.variant), + element_dtype=dtypes.float32) + result_1 = list_ops.tensor_list_stack( + list_ops.tensor_list_get_item(result, 1, element_dtype=dtypes.variant), + element_dtype=dtypes.float32) + self.assertAllEqual(self.evaluate(result_0), [6., 8.]) + self.assertAllEqual(self.evaluate(result_1), [10., 12.]) + if __name__ == "__main__": test.main() -- GitLab From b07a00ab431cced4f51984e824e474df07ba6d57 Mon Sep 17 00:00:00 2001 From: Peter Ma Date: Tue, 20 Nov 2018 11:13:22 -0800 Subject: [PATCH 121/672] Fix one typo. PiperOrigin-RevId: 222275519 --- tensorflow/core/protobuf/rewriter_config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/protobuf/rewriter_config.proto b/tensorflow/core/protobuf/rewriter_config.proto index d68f273536..515d673828 100644 --- a/tensorflow/core/protobuf/rewriter_config.proto +++ b/tensorflow/core/protobuf/rewriter_config.proto @@ -38,7 +38,7 @@ message RewriterConfig { } // Enum controlling the number of times to run optimizers. The default is to - // run them once. + // run them twice. enum NumIterationsType { DEFAULT_NUM_ITERS = 0; ONE = 1; -- GitLab From 3478a4e928431b45cec68c781cf2b0cbd94015fd Mon Sep 17 00:00:00 2001 From: Zhenyu Tan Date: Tue, 20 Nov 2018 11:13:30 -0800 Subject: [PATCH 122/672] Internal Cleanup. PiperOrigin-RevId: 222275534 --- tensorflow/python/ops/array_ops.py | 70 +++++- tensorflow/python/ops/control_flow_ops.py | 226 +++++++++++++++++- .../tools/api/golden/v2/tensorflow.pbtxt | 6 +- .../tools/compatibility/tf_upgrade_v2.py | 6 + 4 files changed, 302 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 85a2c9192d..ed050d740e 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -1507,7 +1507,75 @@ def split(value, num_or_size_splits, axis=0, num=None, name="split"): value=value, size_splits=size_splits, axis=axis, num_split=num, name=name) -@tf_export("transpose") +@tf_export("transpose", v1=[]) +def transpose_v2(a, perm=None, conjugate=False, name="transpose"): + """Transposes `a`. Permutes the dimensions according to `perm`. + + The returned tensor's dimension i will correspond to the input dimension + `perm[i]`. If `perm` is not given, it is set to (n-1...0), where n is + the rank of the input tensor. Hence by default, this operation performs a + regular matrix transpose on 2-D input Tensors. If conjugate is True and + `a.dtype` is either `complex64` or `complex128` then the values of `a` + are conjugated and transposed. + + @compatibility(numpy) + In `numpy` transposes are memory-efficient constant time operations as they + simply return a new view of the same data with adjusted `strides`. + + TensorFlow does not support strides, so `transpose` returns a new tensor with + the items permuted. + @end_compatibility + + For example: + + ```python + x = tf.constant([[1, 2, 3], [4, 5, 6]]) + tf.transpose(x) # [[1, 4] + # [2, 5] + # [3, 6]] + + # Equivalently + tf.transpose(x, perm=[1, 0]) # [[1, 4] + # [2, 5] + # [3, 6]] + + # If x is complex, setting conjugate=True gives the conjugate transpose + x = tf.constant([[1 + 1j, 2 + 2j, 3 + 3j], + [4 + 4j, 5 + 5j, 6 + 6j]]) + tf.transpose(x, conjugate=True) # [[1 - 1j, 4 - 4j], + # [2 - 2j, 5 - 5j], + # [3 - 3j, 6 - 6j]] + + # 'perm' is more useful for n-dimensional tensors, for n > 2 + x = tf.constant([[[ 1, 2, 3], + [ 4, 5, 6]], + [[ 7, 8, 9], + [10, 11, 12]]]) + + # Take the transpose of the matrices in dimension-0 + # (this common operation has a shorthand `linalg.transpose`) + tf.transpose(x, perm=[0, 2, 1]) # [[[1, 4], + # [2, 5], + # [3, 6]], + # [[7, 10], + # [8, 11], + # [9, 12]]] + ``` + + Args: + a: A `Tensor`. + perm: A permutation of the dimensions of `a`. + conjugate: Optional bool. Setting it to `True` is mathematically equivalent + to tf.conj(tf.transpose(input)). + name: A name for the operation (optional). + + Returns: + A transposed `Tensor`. + """ + return transpose(a=a, perm=perm, name=name, conjugate=conjugate) + + +@tf_export(v1=["transpose"]) def transpose(a, perm=None, name="transpose", conjugate=False): """Transposes `a`. Permutes the dimensions according to `perm`. diff --git a/tensorflow/python/ops/control_flow_ops.py b/tensorflow/python/ops/control_flow_ops.py index eab9b3f993..4417632e69 100644 --- a/tensorflow/python/ops/control_flow_ops.py +++ b/tensorflow/python/ops/control_flow_ops.py @@ -3136,7 +3136,193 @@ class WhileContext(ControlFlowContext): # pylint: disable=redefined-outer-name -@tf_export("while_loop") +@tf_export("while_loop", v1=[]) +def while_loop_v2(cond, + body, + loop_vars, + shape_invariants=None, + parallel_iterations=10, + back_prop=True, + swap_memory=False, + maximum_iterations=None, + return_same_structure=False, + name=None): + """Repeat `body` while the condition `cond` is true. + + `cond` is a callable returning a boolean scalar tensor. `body` is a callable + returning a (possibly nested) tuple, namedtuple or list of tensors of the same + arity (length and structure) and types as `loop_vars`. `loop_vars` is a + (possibly nested) tuple, namedtuple or list of tensors that is passed to both + `cond` and `body`. `cond` and `body` both take as many arguments as there are + `loop_vars`. + + In addition to regular Tensors or IndexedSlices, the body may accept and + return TensorArray objects. The flows of the TensorArray objects will + be appropriately forwarded between loops and during gradient calculations. + + Note that `while_loop` calls `cond` and `body` *exactly once* (inside the + call to `while_loop`, and not at all during `Session.run()`). `while_loop` + stitches together the graph fragments created during the `cond` and `body` + calls with some additional graph nodes to create the graph flow that + repeats `body` until `cond` returns false. + + For correctness, `tf.while_loop()` strictly enforces shape invariants for + the loop variables. A shape invariant is a (possibly partial) shape that + is unchanged across the iterations of the loop. An error will be raised + if the shape of a loop variable after an iteration is determined to be more + general than or incompatible with its shape invariant. For example, a shape + of [11, None] is more general than a shape of [11, 17], and [11, 21] is not + compatible with [11, 17]. By default (if the argument `shape_invariants` is + not specified), it is assumed that the initial shape of each tensor in + `loop_vars` is the same in every iteration. The `shape_invariants` argument + allows the caller to specify a less specific shape invariant for each loop + variable, which is needed if the shape varies between iterations. The + `tf.Tensor.set_shape` + function may also be used in the `body` function to indicate that + the output loop variable has a particular shape. The shape invariant for + SparseTensor and IndexedSlices are treated specially as follows: + + a) If a loop variable is a SparseTensor, the shape invariant must be + TensorShape([r]) where r is the rank of the dense tensor represented + by the sparse tensor. It means the shapes of the three tensors of the + SparseTensor are ([None], [None, r], [r]). NOTE: The shape invariant here + is the shape of the SparseTensor.dense_shape property. It must be the shape of + a vector. + + b) If a loop variable is an IndexedSlices, the shape invariant must be + a shape invariant of the values tensor of the IndexedSlices. It means + the shapes of the three tensors of the IndexedSlices are (shape, [shape[0]], + [shape.ndims]). + + `while_loop` implements non-strict semantics, enabling multiple iterations + to run in parallel. The maximum number of parallel iterations can be + controlled by `parallel_iterations`, which gives users some control over + memory consumption and execution order. For correct programs, `while_loop` + should return the same result for any parallel_iterations > 0. + + For training, TensorFlow stores the tensors that are produced in the + forward inference and are needed in back propagation. These tensors are a + main source of memory consumption and often cause OOM errors when training + on GPUs. When the flag swap_memory is true, we swap out these tensors from + GPU to CPU. This for example allows us to train RNN models with very long + sequences and large batches. + + Args: + cond: A callable that represents the termination condition of the loop. + body: A callable that represents the loop body. + loop_vars: A (possibly nested) tuple, namedtuple or list of numpy array, + `Tensor`, and `TensorArray` objects. + shape_invariants: The shape invariants for the loop variables. + parallel_iterations: The number of iterations allowed to run in parallel. It + must be a positive integer. + back_prop: Whether backprop is enabled for this while loop. + swap_memory: Whether GPU-CPU memory swap is enabled for this loop. + maximum_iterations: Optional maximum number of iterations of the while loop + to run. If provided, the `cond` output is AND-ed with an additional + condition ensuring the number of iterations executed is no greater than + `maximum_iterations`. + return_same_structure: If True, output has same structure as `loop_vars`. If + eager execution is enabled, this is ignored (and always treated as True). + name: Optional name prefix for the returned tensors. + + Returns: + The output tensors for the loop variables after the loop. + If `return_same_structure` is True, the return value has the same + structure as `loop_vars`. + If `return_same_structure` is False, the return value is a Tensor, + TensorArray or IndexedSlice if the length of `loop_vars` is 1, or a list + otherwise. + + Raises: + TypeError: if `cond` or `body` is not callable. + ValueError: if `loop_vars` is empty. + + Example: + + ```python + i = tf.constant(0) + c = lambda i: tf.less(i, 10) + b = lambda i: tf.add(i, 1) + r = tf.while_loop(c, b, [i]) + ``` + + Example with nesting and a namedtuple: + + ```python + import collections + Pair = collections.namedtuple('Pair', 'j, k') + ijk_0 = (tf.constant(0), Pair(tf.constant(1), tf.constant(2))) + c = lambda i, p: i < 10 + b = lambda i, p: (i + 1, Pair((p.j + p.k), (p.j - p.k))) + ijk_final = tf.while_loop(c, b, ijk_0) + ``` + + Example using shape_invariants: + + ```python + i0 = tf.constant(0) + m0 = tf.ones([2, 2]) + c = lambda i, m: i < 10 + b = lambda i, m: [i+1, tf.concat([m, m], axis=0)] + tf.while_loop( + c, b, loop_vars=[i0, m0], + shape_invariants=[i0.get_shape(), tf.TensorShape([None, 2])]) + ``` + + Example which demonstrates non-strict semantics: In the following + example, the final value of the counter `i` does not depend on `x`. So + the `while_loop` can increment the counter parallel to updates of `x`. + However, because the loop counter at one loop iteration depends + on the value at the previous iteration, the loop counter itself cannot + be incremented in parallel. Hence if we just want the final value of the + counter (which we print on the line `print(sess.run(i))`), then + `x` will never be incremented, but the counter will be updated on a + single thread. Conversely, if we want the value of the output (which we + print on the line `print(sess.run(out).shape)`), then the counter may be + incremented on its own thread, while `x` can be incremented in + parallel on a separate thread. In the extreme case, it is conceivable + that the thread incrementing the counter runs until completion before + `x` is incremented even a single time. The only thing that can never + happen is that the thread updating `x` can never get ahead of the + counter thread because the thread incrementing `x` depends on the value + of the counter. + + ```python + import tensorflow as tf + + n = 10000 + x = tf.constant(list(range(n))) + c = lambda i, x: i < n + b = lambda i, x: (tf.Print(i + 1, [i]), tf.Print(x + 1, [i], "x:")) + i, out = tf.while_loop(c, b, (0, x)) + with tf.Session() as sess: + print(sess.run(i)) # prints [0] ... [9999] + + # The following line may increment the counter and x in parallel. + # The counter thread may get ahead of the other thread, but not the + # other way around. So you may see things like + # [9996] x:[9987] + # meaning that the counter thread is on iteration 9996, + # while the other thread is on iteration 9987 + print(sess.run(out).shape) + ``` + + """ + return while_loop( + cond=cond, + body=body, + loop_vars=loop_vars, + shape_invariants=shape_invariants, + parallel_iterations=parallel_iterations, + back_prop=back_prop, + swap_memory=swap_memory, + name=name, + maximum_iterations=maximum_iterations, + return_same_structure=return_same_structure) + + +# pylint: disable=redefined-outer-name +@tf_export(v1=["while_loop"]) def while_loop(cond, body, loop_vars, @@ -3536,7 +3722,43 @@ def group(*inputs, **kwargs): return no_op(name=name) -@tf_export("tuple") +@tf_export("tuple", v1=[]) +def tuple_v2(tensors, control_inputs=None, name=None): + """Group tensors together. + + This creates a tuple of tensors with the same values as the `tensors` + argument, except that the value of each tensor is only returned after the + values of all tensors have been computed. + + `control_inputs` contains additional ops that have to finish before this op + finishes, but whose outputs are not returned. + + This can be used as a "join" mechanism for parallel computations: all the + argument tensors can be computed in parallel, but the values of any tensor + returned by `tuple` are only available after all the parallel computations + are done. + + See also `tf.group` and + `tf.control_dependencies`. + + Args: + tensors: A list of `Tensor`s or `IndexedSlices`, some entries can be `None`. + control_inputs: List of additional ops to finish before returning. + name: (optional) A name to use as a `name_scope` for the operation. + + Returns: + Same as `tensors`. + + Raises: + ValueError: If `tensors` does not contain any `Tensor` or `IndexedSlices`. + TypeError: If `control_inputs` is not a list of `Operation` or `Tensor` + objects. + + """ + return tuple(tensors=tensors, name=name, control_inputs=control_inputs) # pylint: disable=redefined-builtin + + +@tf_export(v1=["tuple"]) def tuple(tensors, name=None, control_inputs=None): # pylint: disable=redefined-builtin """Group tensors together. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index b03c8c212d..6adce4b3fd 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -1110,7 +1110,7 @@ tf_module { } member_method { name: "transpose" - argspec: "args=[\'a\', \'perm\', \'name\', \'conjugate\'], varargs=None, keywords=None, defaults=[\'None\', \'transpose\', \'False\'], " + argspec: "args=[\'a\', \'perm\', \'conjugate\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'transpose\'], " } member_method { name: "truediv" @@ -1130,7 +1130,7 @@ tf_module { } member_method { name: "tuple" - argspec: "args=[\'tensors\', \'name\', \'control_inputs\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + argspec: "args=[\'tensors\', \'control_inputs\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "unique" @@ -1162,7 +1162,7 @@ tf_module { } member_method { name: "while_loop" - argspec: "args=[\'cond\', \'body\', \'loop_vars\', \'shape_invariants\', \'parallel_iterations\', \'back_prop\', \'swap_memory\', \'name\', \'maximum_iterations\', \'return_same_structure\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'True\', \'False\', \'None\', \'None\', \'False\'], " + argspec: "args=[\'cond\', \'body\', \'loop_vars\', \'shape_invariants\', \'parallel_iterations\', \'back_prop\', \'swap_memory\', \'maximum_iterations\', \'return_same_structure\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'True\', \'False\', \'None\', \'False\', \'None\'], " } member_method { name: "zeros" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 1074ba5702..3cef1f1602 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -219,6 +219,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "data", "indices", "segment_ids", "name", "num_segments" ], "tf.strings.length": ["input", "name", "unit"], + "tf.transpose": ["a", "perm", "name", "conjugate"], + "tf.tuple": ["tensors", "name", "control_inputs"], + "tf.while_loop": ["cond", "body", "loop_vars", "shape_invariants", + "parallel_iterations", "back_prop", "swap_memory", + "name", "maximum_iterations", + "return_same_structure"], } # Specially handled functions. -- GitLab From 97a16c7b0237b4da9276981515d13a38b0de8019 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Tue, 20 Nov 2018 11:14:45 -0800 Subject: [PATCH 123/672] [tf.data] Propagate private threadpool size parameter during iterator creation so that it is (actually) used as the maximum degree of parallelism for autotuning. PiperOrigin-RevId: 222275729 --- .../experimental/threadpool_dataset_op.cc | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc b/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc index ab21dfc6bc..7bd393f0f4 100644 --- a/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc +++ b/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc @@ -187,20 +187,15 @@ class ThreadPoolDatasetOp : public UnaryDatasetOpKernel { : DatasetIterator(params) {} Status Initialize(IteratorContext* ctx) override { - return dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_); + return dataset()->input_->MakeIterator( + IteratorContext(CreateParams(ctx)), prefix(), &input_impl_); } Status GetNextInternal(IteratorContext* ctx, std::vector* out_tensors, bool* end_of_sequence) override { - ThreadPoolResource* pool = dataset()->threadpool_; - IteratorContext::Params params(ctx); - params.runner = [pool](std::function c) { - pool->Schedule(std::move(c)); - }; - params.runner_threadpool_size = pool->NumThreads(); - IteratorContext iter_ctx(params); - return input_impl_->GetNext(&iter_ctx, out_tensors, end_of_sequence); + return input_impl_->GetNext(IteratorContext(CreateParams(ctx)), + out_tensors, end_of_sequence); } protected: @@ -211,6 +206,16 @@ class ThreadPoolDatasetOp : public UnaryDatasetOpKernel { } private: + IteratorContext::Params CreateParams(IteratorContext* ctx) { + ThreadPoolResource* pool = dataset()->threadpool_; + IteratorContext::Params params(ctx); + params.runner = [pool](std::function c) { + pool->Schedule(std::move(c)); + }; + params.runner_threadpool_size = pool->NumThreads(); + return params; + } + std::unique_ptr input_impl_; }; -- GitLab From 3c28434fe21b5feb29973632f393a27b0b5afd84 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 11:49:27 -0800 Subject: [PATCH 124/672] TFTRT: use StrCat and StrAppend in the log --- tensorflow/contrib/tensorrt/segment/segment.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tensorflow/contrib/tensorrt/segment/segment.cc b/tensorflow/contrib/tensorrt/segment/segment.cc index ab44718256..917ff41fbf 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.cc +++ b/tensorflow/contrib/tensorrt/segment/segment.cc @@ -33,6 +33,7 @@ namespace tensorflow { namespace tensorrt { namespace segment { using ::tensorflow::strings::StrAppend; +using ::tensorflow::strings::StrCat; // A simple graph representation to mirror tensorflow::Graph. This structure // helps saving memory since segmenter modifies the graph in place, preventing @@ -433,13 +434,12 @@ tensorflow::Status SegmentGraph( } node_segments.emplace_back(node); } - string msg = "There are " - + std::to_string(num_unsupported_ops) - + " unsupported ops of " - + std::to_string(unsupported_ops.size()) - + " different types in the graph: "; + string msg = StrCat("There are ", num_unsupported_ops, + " ops of ", unsupported_ops.size(), + " different types in the graph that", + " are not converted to TensorRT: "); for (const auto& elem: unsupported_ops) { - msg += elem + ", "; + StrAppend(&msg, elem, ", "); } LOG(INFO) << msg << "(For more information see " << "https://docs.nvidia.com/deeplearning" -- GitLab From a51e09caf77453c4713686888082dae7b6cfa5f8 Mon Sep 17 00:00:00 2001 From: Tom Hennigan Date: Tue, 20 Nov 2018 11:21:15 -0800 Subject: [PATCH 125/672] Log when a new FuncGraph is created. PiperOrigin-RevId: 222276868 --- tensorflow/python/eager/function.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index e863cf57bc..609a340915 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -48,6 +48,7 @@ from tensorflow.python.ops import custom_gradient from tensorflow.python.ops import functional_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import resource_variable_ops +from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import compat from tensorflow.python.util import nest from tensorflow.python.util import tf_decorator @@ -66,6 +67,11 @@ WHITELIST_FUNCTION_ATTRIBUTE_REGEX = [ BACKWARD_FUNCTION_ATTRIBUTE_NAME ] +CacheKey = collections.namedtuple("CacheKey", [ + "input_signature", "parent_graph", "device_functions", "colocation_stack", + "uses_xla" +]) + def _parse_func_attrs(attributes): """Convert the keyword arguments into function_def attributes. @@ -927,17 +933,17 @@ class PolymorphicFunction(object): """Computes the cache key given inputs and execution context.""" if self._input_signature is None: inputs = (args, kwargs) if kwargs else args - cache_key = pywrap_tensorflow.TFE_Py_EncodeArg(inputs) + input_signature = pywrap_tensorflow.TFE_Py_EncodeArg(inputs) else: del args, kwargs - cache_key = self._flat_input_signature + input_signature = self._flat_input_signature ctx = context.context() with ops.init_scope(): # The graph, or whether we're executing eagerly, should be a part of the # cache key so we don't improperly capture tensors such as variables. executing_eagerly = ctx.executing_eagerly() - execution_context = executing_eagerly or ops.get_default_graph() + parent_graph = None if executing_eagerly else ops.get_default_graph() # pylint: disable=protected-access default_graph = ops.get_default_graph() @@ -966,8 +972,8 @@ class PolymorphicFunction(object): else: device_functions = () # pylint: enable=protected-access - return (cache_key, execution_context, device_functions, colocation_stack, - uses_xla) + return CacheKey(input_signature, parent_graph, device_functions, + colocation_stack, uses_xla) def _canonicalize_function_inputs(self, *args, **kwargs): """Canonicalizes `args` and `kwargs`. @@ -1083,6 +1089,9 @@ class PolymorphicFunction(object): "must be hashable.") if graph_function is None: + logging.vlog(1, + "Creating new FuncGraph for Python function %r (key: %r)", + self._python_function.__name__, cache_key) if self._input_signature is None: arglen = len(args) else: -- GitLab From dadd38ede6fa5a039a14e01714da9eff2dd00459 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Tue, 20 Nov 2018 11:22:33 -0800 Subject: [PATCH 126/672] Add tensor_name field in VirtualScheduler CreateSendRecv So that we can compare ChannelCostEstimator estimation with measured RecvTensor time in StepStats. PiperOrigin-RevId: 222277076 --- .../core/grappler/costs/virtual_scheduler.cc | 21 ++++++++++++------- .../core/grappler/costs/virtual_scheduler.h | 3 ++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tensorflow/core/grappler/costs/virtual_scheduler.cc b/tensorflow/core/grappler/costs/virtual_scheduler.cc index b9b240e72c..ae5200b359 100644 --- a/tensorflow/core/grappler/costs/virtual_scheduler.cc +++ b/tensorflow/core/grappler/costs/virtual_scheduler.cc @@ -469,8 +469,8 @@ Status VirtualScheduler::Init() { } else { // Different device, no cached copy; transfer input_node to the // curr_node's device. - auto send_and_recv = - CreateSendRecv(input_node, curr_node, input_node_name); + auto send_and_recv = CreateSendRecv(input_node, curr_node, input_node, + input_node_name); // Note that CreateSendRecv() already connected input/output between // _Send and _Recv ops. const auto* send = send_and_recv.first; @@ -608,7 +608,8 @@ string VirtualScheduler::ChannelDeviceName(const NodeDef* from, } std::pair VirtualScheduler::CreateSendRecv( - const NodeDef* from, const NodeDef* to, const string& input_name) { + const NodeDef* from, const NodeDef* to, const NodeDef* input_node, + const string& input_name) { CHECK(!initialized_) << "CreateSendRecv is called after Init()."; // Connect "from" node to "to" node with _Send and _Recv such that @@ -639,10 +640,14 @@ std::pair VirtualScheduler::CreateSendRecv( send->set_device(ChannelDeviceName(from, to)); auto& send_attr = *(send->mutable_attr()); send_attr[kAttrInputSrc].set_s(input_name); - // Use input_name as tensor_name. - send_attr[kAttrTensorName].set_s(input_name); send_attr[kAttrSrcDevice].set_s(DeviceName(from)); send_attr[kAttrDstDevice].set_s(DeviceName(to)); + // GraphDef generated by AutoGrappler has tensor_name field when removing + // _Send/_Recv nodes. + if (input_node->attr().count(kAttrTensorName)) { + send_attr[kAttrTensorName].set_s( + input_node->attr().at(kAttrTensorName).s()); + } // _Recv op. auto* recv = new NodeDef(); @@ -652,8 +657,10 @@ std::pair VirtualScheduler::CreateSendRecv( recv->set_device(DeviceName(to)); auto& recv_attr = *(recv->mutable_attr()); recv_attr[kAttrInputSrc].set_s(input_name); - // Use input_name as tensor_name. - recv_attr[kAttrTensorName].set_s(input_name); + if (input_node->attr().count(kAttrTensorName)) { + recv_attr[kAttrTensorName].set_s( + input_node->attr().at(kAttrTensorName).s()); + } // NodeState for _Send op. auto& send_node_state = GetNodeStateOrCreateIt(send); diff --git a/tensorflow/core/grappler/costs/virtual_scheduler.h b/tensorflow/core/grappler/costs/virtual_scheduler.h index 92e0a88782..6a835f32d1 100644 --- a/tensorflow/core/grappler/costs/virtual_scheduler.h +++ b/tensorflow/core/grappler/costs/virtual_scheduler.h @@ -317,7 +317,8 @@ class VirtualScheduler { void MaybeUpdateInputOutput(const NodeDef* node); NodeState& GetNodeStateOrCreateIt(const NodeDef* node); std::pair CreateSendRecv( - const NodeDef* from, const NodeDef* to, const string& input_name); + const NodeDef* from, const NodeDef* to, const NodeDef* input_node, + const string& input_name); string DeviceName(const NodeDef* node) const; string SanitizedDeviceName(const NodeDef* node) const; string ChannelDeviceName(const NodeDef* from, const NodeDef* to) const; -- GitLab From a0b8cee815100b805a24fedfa12b28139d24e7fe Mon Sep 17 00:00:00 2001 From: Yanhui Liang Date: Tue, 20 Nov 2018 11:24:30 -0800 Subject: [PATCH 127/672] Remove `seed2` arg in sample_distorted_bounding_box op for TF 2.0. PiperOrigin-RevId: 222277431 --- tensorflow/python/ops/image_ops_impl.py | 110 +++++++++++++++++- .../api/golden/v2/tensorflow.image.pbtxt | 2 +- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index c4b5db9418..1618b79504 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -24,6 +24,7 @@ from tensorflow.python.compat import compat from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import random_seed from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops @@ -1965,7 +1966,114 @@ def total_variation(images, name=None): return tot_var -@tf_export('image.sample_distorted_bounding_box') +@tf_export('image.sample_distorted_bounding_box', v1=[]) +def sample_distorted_bounding_box_v2(image_size, + bounding_boxes, + seed=0, + min_object_covered=0.1, + aspect_ratio_range=None, + area_range=None, + max_attempts=None, + use_image_if_no_bounding_boxes=None, + name=None): + """Generate a single randomly distorted bounding box for an image. + + Bounding box annotations are often supplied in addition to ground-truth labels + in image recognition or object localization tasks. A common technique for + training such a system is to randomly distort an image while preserving + its content, i.e. *data augmentation*. This Op outputs a randomly distorted + localization of an object, i.e. bounding box, given an `image_size`, + `bounding_boxes` and a series of constraints. + + The output of this Op is a single bounding box that may be used to crop the + original image. The output is returned as 3 tensors: `begin`, `size` and + `bboxes`. The first 2 tensors can be fed directly into `tf.slice` to crop the + image. The latter may be supplied to `tf.image.draw_bounding_boxes` to + visualize what the bounding box looks like. + + Bounding boxes are supplied and returned as `[y_min, x_min, y_max, x_max]`. + The bounding box coordinates are floats in `[0.0, 1.0]` relative to the width + and height of the underlying image. + + For example, + + ```python + # Generate a single distorted bounding box. + begin, size, bbox_for_draw = tf.image.sample_distorted_bounding_box( + tf.shape(image), + bounding_boxes=bounding_boxes, + min_object_covered=0.1) + + # Draw the bounding box in an image summary. + image_with_box = tf.image.draw_bounding_boxes(tf.expand_dims(image, 0), + bbox_for_draw) + tf.summary.image('images_with_box', image_with_box) + + # Employ the bounding box to distort the image. + distorted_image = tf.slice(image, begin, size) + ``` + + Note that if no bounding box information is available, setting + `use_image_if_no_bounding_boxes = true` will assume there is a single implicit + bounding box covering the whole image. If `use_image_if_no_bounding_boxes` is + false and no bounding boxes are supplied, an error is raised. + + Args: + image_size: A `Tensor`. Must be one of the following types: `uint8`, `int8`, + `int16`, `int32`, `int64`. + 1-D, containing `[height, width, channels]`. + bounding_boxes: A `Tensor` of type `float32`. + 3-D with shape `[batch, N, 4]` describing the N bounding boxes + associated with the image. + seed: An optional `int`. Defaults to `0`. + If either `seed` or `seed2` are set to non-zero, the random number + generator is seeded by the given `seed`. Otherwise, it is seeded by a + random seed. + min_object_covered: A Tensor of type `float32`. Defaults to `0.1`. + The cropped area of the image must contain at least this + fraction of any bounding box supplied. The value of this parameter should + be non-negative. In the case of 0, the cropped area does not need to + overlap any of the bounding boxes supplied. + aspect_ratio_range: An optional list of `floats`. Defaults to `[0.75, + 1.33]`. + The cropped area of the image must have an aspect `ratio = + width / height` within this range. + area_range: An optional list of `floats`. Defaults to `[0.05, 1]`. + The cropped area of the image must contain a fraction of the + supplied image within this range. + max_attempts: An optional `int`. Defaults to `100`. + Number of attempts at generating a cropped region of the image + of the specified constraints. After `max_attempts` failures, return the + entire image. + use_image_if_no_bounding_boxes: An optional `bool`. Defaults to `False`. + Controls behavior if no bounding boxes supplied. + If true, assume an implicit bounding box covering the whole input. If + false, raise an error. + name: A name for the operation (optional). + + Returns: + A tuple of `Tensor` objects (begin, size, bboxes). + + begin: A `Tensor`. Has the same type as `image_size`. 1-D, containing + `[offset_height, offset_width, 0]`. Provide as input to + `tf.slice`. + size: A `Tensor`. Has the same type as `image_size`. 1-D, containing + `[target_height, target_width, -1]`. Provide as input to + `tf.slice`. + bboxes: A `Tensor` of type `float32`. 3-D with shape `[1, 1, 4]` containing + the distorted bounding box. + Provide as input to `tf.image.draw_bounding_boxes`. + """ + seed1, seed2 = random_seed.get_seed(seed) if seed else (0, 0) + return sample_distorted_bounding_box( + image_size, bounding_boxes, seed1, seed2, min_object_covered, + aspect_ratio_range, area_range, max_attempts, + use_image_if_no_bounding_boxes, name) + + +@tf_export(v1=['image.sample_distorted_bounding_box']) +@deprecation.deprecated(date=None, instructions='`seed2` arg is deprecated.' + 'Use sample_distorted_bounding_box_v2 instead.') def sample_distorted_bounding_box(image_size, bounding_boxes, seed=None, diff --git a/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt index dcf80e3342..3c6ed1cfb8 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.image.pbtxt @@ -206,7 +206,7 @@ tf_module { } member_method { name: "sample_distorted_bounding_box" - argspec: "args=[\'image_size\', \'bounding_boxes\', \'seed\', \'seed2\', \'min_object_covered\', \'aspect_ratio_range\', \'area_range\', \'max_attempts\', \'use_image_if_no_bounding_boxes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'0.1\', \'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'image_size\', \'bounding_boxes\', \'seed\', \'min_object_covered\', \'aspect_ratio_range\', \'area_range\', \'max_attempts\', \'use_image_if_no_bounding_boxes\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'0.1\', \'None\', \'None\', \'None\', \'None\', \'None\'], " } member_method { name: "sobel_edges" -- GitLab From 541ca6d17420e6f421e38e9d86204699a519eac9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 11:24:53 -0800 Subject: [PATCH 128/672] Multi-label quantile regression PiperOrigin-RevId: 222277514 --- .../estimator_batch/estimator.py | 54 ++++-- .../estimator_batch/estimator_test.py | 159 +++++++++++++++++- .../boosted_trees/python/utils/losses.py | 4 +- 3 files changed, 198 insertions(+), 19 deletions(-) diff --git a/tensorflow/contrib/boosted_trees/estimator_batch/estimator.py b/tensorflow/contrib/boosted_trees/estimator_batch/estimator.py index 99ecded653..a178820841 100644 --- a/tensorflow/contrib/boosted_trees/estimator_batch/estimator.py +++ b/tensorflow/contrib/boosted_trees/estimator_batch/estimator.py @@ -428,6 +428,7 @@ class GradientBoostedDecisionTreeQuantileRegressor(estimator.Estimator): learner_config, examples_per_layer, quantiles, + label_dimension=1, num_trees=None, feature_columns=None, weight_column_name=None, @@ -448,6 +449,10 @@ class GradientBoostedDecisionTreeQuantileRegressor(estimator.Estimator): layer. It can also be a function that computes the number of examples based on the depth of the layer that's being built. quantiles: a list of quantiles for the loss, each between 0 and 1. + label_dimension: Dimension of regression label. This is the size + of the last dimension of the labels `Tensor` (typically, this has shape + `[batch_size, label_dimension]`). When label_dimension>1, it is + recommended to use multiclass strategy diagonal hessian or full hessian. num_trees: An int, number of trees to build. feature_columns: A list of feature columns. weight_column_name: Name of the column for weights, or None if not @@ -489,9 +494,11 @@ class GradientBoostedDecisionTreeQuantileRegressor(estimator.Estimator): loss_fn=functools.partial( losses.per_example_quantile_regression_loss, quantile=quantile), link_fn=array_ops.identity, - logit_dimension=1) + logit_dimension=label_dimension) return head + learner_config.num_classes = max(2, label_dimension) + super(GradientBoostedDecisionTreeQuantileRegressor, self).__init__( model_fn=model.model_builder, params={ @@ -548,6 +555,7 @@ def core_multiclass_head( # Core..QuantileRegressor directly, def core_quantile_regression_head( quantiles, + label_dimension=1, weight_column=None, loss_reduction=core_losses.Reduction.SUM_OVER_NONZERO_WEIGHTS): """Core head for quantile regression problems.""" @@ -562,7 +570,7 @@ def core_quantile_regression_head( # pylint:disable=protected-access head_fn = core_head_lib._regression_head( - label_dimension=1, + label_dimension=label_dimension, loss_fn=loss_fn, loss_reduction=loss_reduction, weight_column=weight_column) @@ -747,6 +755,7 @@ class CoreGradientBoostedDecisionTreeQuantileRegressor( learner_config, examples_per_layer, quantiles, + label_dimension=1, num_trees=None, feature_columns=None, weight_column_name=None, @@ -766,6 +775,10 @@ class CoreGradientBoostedDecisionTreeQuantileRegressor( layer. It can also be a function that computes the number of examples based on the depth of the layer that's being built. quantiles: a list of quantiles for the loss, each between 0 and 1. + label_dimension: Dimension of regression label. This is the size + of the last dimension of the labels `Tensor` (typically, this has shape + `[batch_size, label_dimension]`). When label_dimension>1, it is + recommended to use multiclass strategy diagonal hessian or full hessian. num_trees: An int, number of trees to build. feature_columns: A list of feature columns. weight_column_name: Name of the column for weights, or None if not @@ -799,18 +812,31 @@ class CoreGradientBoostedDecisionTreeQuantileRegressor( mode=mode, config=config, params={ - 'head': core_quantile_regression_head(quantiles[0]), - 'feature_columns': feature_columns, - 'learner_config': learner_config, - 'num_trees': num_trees, - 'weight_column_name': weight_column_name, - 'examples_per_layer': examples_per_layer, - 'center_bias': center_bias, - 'logits_modifier_function': logits_modifier_function, - 'use_core_libs': True, - 'output_leaf_index': output_leaf_index, - 'override_global_step_value': None, - 'num_quantiles': num_quantiles, + 'head': + core_quantile_regression_head( + quantiles[0], label_dimension=label_dimension), + 'feature_columns': + feature_columns, + 'learner_config': + learner_config, + 'num_trees': + num_trees, + 'weight_column_name': + weight_column_name, + 'examples_per_layer': + examples_per_layer, + 'center_bias': + center_bias, + 'logits_modifier_function': + logits_modifier_function, + 'use_core_libs': + True, + 'output_leaf_index': + output_leaf_index, + 'override_global_step_value': + None, + 'num_quantiles': + num_quantiles, }, output_type=model.ModelBuilderOutputType.ESTIMATOR_SPEC) diff --git a/tensorflow/contrib/boosted_trees/estimator_batch/estimator_test.py b/tensorflow/contrib/boosted_trees/estimator_batch/estimator_test.py index 7863b5a4f8..ee052ac603 100644 --- a/tensorflow/contrib/boosted_trees/estimator_batch/estimator_test.py +++ b/tensorflow/contrib/boosted_trees/estimator_batch/estimator_test.py @@ -81,7 +81,7 @@ def _infer_ranking_train_input_fn(): _QUANTILE_REGRESSION_SIZE = 1000 -def _quantile_regression_input_fns(): +def _quantile_regression_input_fns(two_dimension=False): # The data generation is taken from # http://scikit-learn.org/stable/auto_examples/ensemble/plot_gradient_boosting_quantile.html np.random.seed(1) @@ -90,20 +90,28 @@ def _quantile_regression_input_fns(): """The function to predict.""" return x * np.sin(x) + def g(x): + """The function to predict.""" + return x * np.cos(x) + # Training data. x = np.atleast_2d(np.random.uniform(0, 10.0, size=_QUANTILE_REGRESSION_SIZE)).T x = x.astype(np.float32) # Labels. - y = f(x).ravel() + if not two_dimension: + y = f(x).ravel() + else: + y = np.column_stack((f(x).ravel(), g(x).ravel())) # Add random noise. dy = 1.5 + 1.0 * np.random.random(y.shape) noise = np.random.normal(0, dy) y += noise y_original = y.astype(np.float32) - y = y.reshape(_QUANTILE_REGRESSION_SIZE, 1) + if not two_dimension: + y = y.reshape(_QUANTILE_REGRESSION_SIZE, 1) train_input_fn = numpy_io.numpy_input_fn( x=x, @@ -439,6 +447,78 @@ class BoostedTreeEstimatorTest(test_util.TensorFlowTestCase): self.assertTrue(frac_above_lower >= 0.92) self.assertTrue(frac_above_lower <= 0.98) + # Multi-dimensional quantile regression. + def testQuantileRegressionMultiDimLabel(self): + learner_config = learner_pb2.LearnerConfig() + learner_config.num_classes = 2 + learner_config.constraints.max_tree_depth = 3 + learner_config.growing_mode = learner_pb2.LearnerConfig.WHOLE_TREE + learner_config.constraints.min_node_weight = 1 / _QUANTILE_REGRESSION_SIZE + learner_config.regularization.l2 = 1.0 / _QUANTILE_REGRESSION_SIZE + learner_config.regularization.l1 = 1.0 / _QUANTILE_REGRESSION_SIZE + learner_config.regularization.tree_complexity = ( + 1.0 / _QUANTILE_REGRESSION_SIZE) + + train_input_fn, test_input_fn, y = _quantile_regression_input_fns( + two_dimension=True) + + # 95% percentile. + model_upper = estimator.GradientBoostedDecisionTreeQuantileRegressor( + quantiles=[0.95], + learner_config=learner_config, + label_dimension=2, + num_trees=100, + examples_per_layer=_QUANTILE_REGRESSION_SIZE, + center_bias=False) + + model_upper.fit(input_fn=train_input_fn, steps=1000) + result_iter = model_upper.predict(input_fn=test_input_fn) + upper = [] + for prediction_dict in result_iter: + upper.append(prediction_dict["scores"]) + + count_below_upper = np.count_nonzero(upper > y, axis=0) + count_both_below_upper = np.count_nonzero(np.prod(upper > y, axis=1)) + frac_below_upper_0 = round(1. * count_below_upper[0] / len(y), 3) + frac_below_upper_1 = round(1. * count_below_upper[1] / len(y), 3) + frac_both_below_upper = round(1. * count_both_below_upper / len(y), 3) + # +/- 3% + self.assertTrue(frac_below_upper_0 >= 0.92) + self.assertTrue(frac_below_upper_0 <= 0.98) + self.assertTrue(frac_below_upper_1 >= 0.92) + self.assertTrue(frac_below_upper_1 <= 0.98) + self.assertTrue(frac_both_below_upper >= 0.92) + self.assertTrue(frac_both_below_upper <= 0.98) + + train_input_fn, test_input_fn, _ = _quantile_regression_input_fns( + two_dimension=True) + model_lower = estimator.GradientBoostedDecisionTreeQuantileRegressor( + quantiles=[0.05], + learner_config=learner_config, + label_dimension=2, + num_trees=100, + examples_per_layer=_QUANTILE_REGRESSION_SIZE, + center_bias=False) + + model_lower.fit(input_fn=train_input_fn, steps=1000) + result_iter = model_lower.predict(input_fn=test_input_fn) + lower = [] + for prediction_dict in result_iter: + lower.append(prediction_dict["scores"]) + + count_above_lower = np.count_nonzero(lower < y, axis=0) + count_both_aboce_lower = np.count_nonzero(np.prod(lower < y, axis=1)) + frac_above_lower_0 = round(1. * count_above_lower[0] / len(y), 3) + frac_above_lower_1 = round(1. * count_above_lower[1] / len(y), 3) + frac_both_above_lower = round(1. * count_both_aboce_lower / len(y), 3) + # +/- 3% + self.assertTrue(frac_above_lower_0 >= 0.92) + self.assertTrue(frac_above_lower_0 <= 0.98) + self.assertTrue(frac_above_lower_1 >= 0.92) + self.assertTrue(frac_above_lower_1 <= 0.98) + self.assertTrue(frac_both_above_lower >= 0.92) + self.assertTrue(frac_both_above_lower <= 0.98) + class CoreGradientBoostedDecisionTreeEstimators(test_util.TensorFlowTestCase): @@ -685,6 +765,79 @@ class CoreGradientBoostedDecisionTreeEstimators(test_util.TensorFlowTestCase): self.assertTrue(frac_above_lower >= 0.92) self.assertTrue(frac_above_lower <= 0.98) + # Multi-dimensional quantile regression. + def testQuantileRegressionMultiDimLabel(self): + learner_config = learner_pb2.LearnerConfig() + learner_config.num_classes = 2 + learner_config.constraints.max_tree_depth = 3 + learner_config.growing_mode = learner_pb2.LearnerConfig.WHOLE_TREE + learner_config.constraints.min_node_weight = 1 / _QUANTILE_REGRESSION_SIZE + learner_config.regularization.l2 = 1.0 / _QUANTILE_REGRESSION_SIZE + learner_config.regularization.l1 = 1.0 / _QUANTILE_REGRESSION_SIZE + learner_config.regularization.tree_complexity = ( + 1.0 / _QUANTILE_REGRESSION_SIZE) + + train_input_fn, test_input_fn, y = _quantile_regression_input_fns( + two_dimension=True) + y = y.reshape(_QUANTILE_REGRESSION_SIZE, 2) + + # 95% percentile. + model_upper = estimator.CoreGradientBoostedDecisionTreeQuantileRegressor( + quantiles=[0.95], + learner_config=learner_config, + num_trees=100, + label_dimension=2, + examples_per_layer=_QUANTILE_REGRESSION_SIZE, + center_bias=False) + + model_upper.train(input_fn=train_input_fn, steps=1000) + result_iter = model_upper.predict(input_fn=test_input_fn) + upper = [] + for prediction_dict in result_iter: + upper.append(prediction_dict["predictions"]) + + count_below_upper = np.count_nonzero(upper > y, axis=0) + count_both_below_upper = np.count_nonzero(np.prod(upper > y, axis=1)) + frac_below_upper_0 = round(1. * count_below_upper[0] / len(y), 3) + frac_below_upper_1 = round(1. * count_below_upper[1] / len(y), 3) + frac_both_below_upper = round(1. * count_both_below_upper / len(y), 3) + # +/- 3% + self.assertTrue(frac_below_upper_0 >= 0.92) + self.assertTrue(frac_below_upper_0 <= 0.98) + self.assertTrue(frac_below_upper_1 >= 0.92) + self.assertTrue(frac_below_upper_1 <= 0.98) + self.assertTrue(frac_both_below_upper >= 0.92) + self.assertTrue(frac_both_below_upper <= 0.98) + + train_input_fn, test_input_fn, _ = _quantile_regression_input_fns( + two_dimension=True) + model_lower = estimator.CoreGradientBoostedDecisionTreeQuantileRegressor( + quantiles=[0.05], + learner_config=learner_config, + num_trees=100, + label_dimension=2, + examples_per_layer=_QUANTILE_REGRESSION_SIZE, + center_bias=False) + + model_lower.train(input_fn=train_input_fn, steps=1000) + result_iter = model_lower.predict(input_fn=test_input_fn) + lower = [] + for prediction_dict in result_iter: + lower.append(prediction_dict["predictions"]) + + count_above_lower = np.count_nonzero(lower < y, axis=0) + count_both_aboce_lower = np.count_nonzero(np.prod(lower < y, axis=1)) + frac_above_lower_0 = round(1. * count_above_lower[0] / len(y), 3) + frac_above_lower_1 = round(1. * count_above_lower[1] / len(y), 3) + frac_both_above_lower = round(1. * count_both_aboce_lower / len(y), 3) + # +/- 3% + self.assertTrue(frac_above_lower_0 >= 0.92) + self.assertTrue(frac_above_lower_0 <= 0.98) + self.assertTrue(frac_above_lower_1 >= 0.92) + self.assertTrue(frac_above_lower_1 <= 0.98) + self.assertTrue(frac_both_above_lower >= 0.92) + self.assertTrue(frac_both_above_lower <= 0.98) + if __name__ == "__main__": googletest.main() diff --git a/tensorflow/contrib/boosted_trees/python/utils/losses.py b/tensorflow/contrib/boosted_trees/python/utils/losses.py index f8da20a54c..7a99dccdd1 100644 --- a/tensorflow/contrib/boosted_trees/python/utils/losses.py +++ b/tensorflow/contrib/boosted_trees/python/utils/losses.py @@ -65,9 +65,9 @@ def per_example_quantile_regression_loss(labels, weights, predictions, below is this loss but squared in the region where the loss value < 1. Args: - labels: Rank 2 (N, 1) tensor of per-example labels. + labels: Rank 2 (N, D) tensor of per-example labels. weights: Rank 2 (N, 1) tensor of per-example weights. - predictions: Rank 2 (N, 1) tensor of per-example predictions. + predictions: Rank 2 (N, D) tensor of per-example predictions. quantile: The quantile to use. Returns: -- GitLab From 51f54a7a95cd4bef139967f12fe6ce67b8e63c83 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 20 Nov 2018 11:25:44 -0800 Subject: [PATCH 129/672] Remove FilteredFunctionPassManager; NFC PiperOrigin-RevId: 222277666 --- .../compiler/xla/service/cpu/compiler_functor.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/tensorflow/compiler/xla/service/cpu/compiler_functor.cc b/tensorflow/compiler/xla/service/cpu/compiler_functor.cc index 2852fc8666..796a7cf94d 100644 --- a/tensorflow/compiler/xla/service/cpu/compiler_functor.cc +++ b/tensorflow/compiler/xla/service/cpu/compiler_functor.cc @@ -61,17 +61,6 @@ Disabling these as a starting point. // TODO(b/64227304) Creating a custom pass pipeline will replace this. namespace { - -// TODO(sanjoy): remove this class. -class FilteredFunctionPassManager : public llvm::legacy::FunctionPassManager { - public: - explicit FilteredFunctionPassManager(llvm::Module* m) - : llvm::legacy::FunctionPassManager(m) {} - void add(llvm::Pass* p) override { - llvm::legacy::FunctionPassManager::add(p); - } -}; - class FilteredPassManager : public llvm::legacy::PassManager { public: explicit FilteredPassManager(bool disable_expensive_passes) @@ -94,7 +83,7 @@ class FilteredPassManager : public llvm::legacy::PassManager { std::unique_ptr CompilerFunctor::operator()( llvm::Module& module) const { FilteredPassManager module_passes(disable_expensive_passes_); - FilteredFunctionPassManager function_passes(&module); + llvm::legacy::FunctionPassManager function_passes(&module); VLOG(2) << "IR before optimizations"; XLA_VLOG_LINES(2, llvm_ir::DumpModuleToString(module)); -- GitLab From 8aeab3d5e13d2b4e4db3e4720d017d70a38c8394 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 11:33:19 -0800 Subject: [PATCH 130/672] This CL allows subclass models to work with float64 datasets. PiperOrigin-RevId: 222279047 --- tensorflow/python/keras/BUILD | 1 + tensorflow/python/keras/engine/training.py | 7 ++++++- .../python/keras/engine/training_dataset_test.py | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index adfa2260c6..37dcc9eb04 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -728,6 +728,7 @@ py_test( ":keras", "//tensorflow/python:client_testlib", "//third_party/py/numpy", + "@absl_py//absl/testing:parameterized", ], ) diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index d926b53189..ce01777b2d 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -1227,7 +1227,10 @@ class Model(Network): # to match the value shapes. if not self.inputs: is_build_called = True - self._set_inputs(x) + cast_inputs = x + if training_utils.has_tensors(x): + cast_inputs = training_utils.cast_if_floating_dtype(x) + self._set_inputs(cast_inputs) else: dict_inputs = isinstance(self.inputs, dict) if dict_inputs and context.executing_eagerly(): @@ -1243,6 +1246,8 @@ class Model(Network): if not self._is_compiled: # On-the-fly compilation of the model. # We need to use `y` to set the model targets. + if training_utils.has_tensors(y): + y = training_utils.cast_if_floating_dtype(y) if isinstance(y, (list, tuple)): if not all(isinstance(v, np.ndarray) or tensor_util.is_tensor(v) for v in y): diff --git a/tensorflow/python/keras/engine/training_dataset_test.py b/tensorflow/python/keras/engine/training_dataset_test.py index e8b884e935..2e6bec6c62 100644 --- a/tensorflow/python/keras/engine/training_dataset_test.py +++ b/tensorflow/python/keras/engine/training_dataset_test.py @@ -20,6 +20,8 @@ from __future__ import print_function import logging +from absl.testing import parameterized + import numpy as np from tensorflow.python import keras @@ -33,11 +35,18 @@ from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training.rmsprop import RMSPropOptimizer -class TestTrainingWithDatasetIterators(test.TestCase): +class TestTrainingWithDatasetIterators(test.TestCase, parameterized.TestCase): + @parameterized.parameters( + {'model': 'functional'}, + {'model': 'subclass'}, + ) @tf_test_util.run_in_graph_and_eager_modes - def test_training_and_eval_methods_on_iterators_single_io(self): - model = testing_utils.get_small_functional_mlp(1, 4, input_dim=3) + def test_training_and_eval_methods_on_iterators_single_io(self, model): + if model == 'functional': + model = testing_utils.get_small_functional_mlp(1, 4, input_dim=3) + elif model == 'subclass': + model = testing_utils.get_small_sequential_mlp(1, 4) optimizer = RMSPropOptimizer(learning_rate=0.001) loss = 'mse' metrics = ['mae', metrics_module.CategoricalAccuracy()] -- GitLab From 06d5348a3da499ecfb3745ec48cc1a8411fcf674 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 11:40:12 -0800 Subject: [PATCH 131/672] Add Jacobian API to GradientTape. PiperOrigin-RevId: 222280321 --- tensorflow/python/eager/BUILD | 1 + tensorflow/python/eager/backprop.py | 109 ++++++++++++++++++ tensorflow/python/eager/backprop_test.py | 76 ++++++++++++ .../golden/v1/tensorflow.-gradient-tape.pbtxt | 4 + .../golden/v2/tensorflow.-gradient-tape.pbtxt | 4 + 5 files changed, 194 insertions(+) diff --git a/tensorflow/python/eager/BUILD b/tensorflow/python/eager/BUILD index 55728b19ab..d3457ed241 100644 --- a/tensorflow/python/eager/BUILD +++ b/tensorflow/python/eager/BUILD @@ -341,6 +341,7 @@ py_library( "//tensorflow/python/eager:context", "//tensorflow/python/eager:execute", "//tensorflow/python/eager:tape", + "//tensorflow/python/ops/parallel_for:control_flow_ops", "@six_archive//:six", ], ) diff --git a/tensorflow/python/eager/backprop.py b/tensorflow/python/eager/backprop.py index 5b6b42155f..84b61f47c1 100644 --- a/tensorflow/python/eager/backprop.py +++ b/tensorflow/python/eager/backprop.py @@ -42,9 +42,20 @@ from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import nest from tensorflow.python.util import tf_contextlib from tensorflow.python.util import tf_inspect +from tensorflow.python.util.lazy_loader import LazyLoader from tensorflow.python.util.tf_export import tf_export +# Note that we need to lazy load the following two modules to avoid creating +# circular dependencies. +# TODO(b/119775953): fix the circular dependencies. +pfor_ops = LazyLoader( + "pfor_ops", globals(), + "tensorflow.python.ops.parallel_for.control_flow_ops") + +function = LazyLoader("function", globals(), + "tensorflow.python.eager.function") + _op_attr_type_cache = {} @@ -937,3 +948,101 @@ class GradientTape(object): grad = nest.pack_sequence_as(sources, flat_grad) return grad + + def jacobian(self, + target, + sources, + unconnected_gradients=UnconnectedGradients.NONE, + experimental_use_pfor=True): + """Computes the jacobian using operations recorded in context of this tape. + + See http://en.wikipedia.org/wiki/jacobian_matrix_and_determinant for the + definition of a Jacobian. + + Example usage: + + with tf.GradientTape() as g: + x = tf.constant([1.0, 2.0]) + g.watch(x) + y = x * x + jacobian = g.jacobian(y, x) + # jacobian value is [[2., 0.], [0., 4.]] + + Args: + target: Tensor to be differentiated. + sources: a list or nested structure of Tensors or Variables. `target` + will be differentiated against elements in `sources`. + unconnected_gradients: a value which can either hold 'none' or 'zero' and + alters the value which will be returned if the target and sources are + unconnected. The possible values and effects are detailed in + 'UnconnectedGradients' and it defaults to 'none'. + experimental_use_pfor: If true, vectorizes the jacobian computation. Else + falls back to a sequential while_loop. Vectorization can sometimes fail + or lead to excessive memory usage. This option can be used to disable + vectorization in such cases. + + Returns: + a list or nested structure of Tensors (or IndexedSlices, or None), + one for each element in `sources`. Returned structure is the same as + the structure of `sources`. + + Raises: + RuntimeError: If called on a non-persistent tape with eager execution + enabled and without enabling experimental_use_pfor. + ValueError: If vectorization of jacobian computation fails. + """ + flat_sources = nest.flatten(sources) + target_static_shape = target.shape + target_shape = array_ops.shape(target) + # Note that we push and pop the tape here and below. This is needed since we + # need gradients through the enclosed operations. + self._push_tape() + target = array_ops.reshape(target, [-1]) + self._pop_tape() + + def loop_fn(i): + self._push_tape() + y = array_ops.gather(target, i) + self._pop_tape() + grad = self.gradient(y, flat_sources, + unconnected_gradients=unconnected_gradients) + return grad + + try: + target_size = int(target.shape[0]) + except TypeError: + target_size = array_ops.shape(target)[0] + + if experimental_use_pfor: + def f(): + return pfor_ops.pfor(loop_fn, target_size) + if context.executing_eagerly(): + f = function.defun(f) + try: + output = f() + except ValueError as err: + # TODO(agarwal): Fold this error message into err. + logging.error("Encountered an exception while vectorizing the jacobian " + "computation. Vectorization can be disabled by setting " + "experimental_use_pfor to False.") + raise err + else: + if context.executing_eagerly(): + if not self._persistent: + raise RuntimeError( + "GradientTape must be created with persistent=True" + " to compute the jacobian with eager execution enabled and with " + " experimental_use_pfor set to False.") + output = pfor_ops.for_loop( + loop_fn, [target.dtype] * len(flat_sources), target_size) + + for i, out in enumerate(output): + if out is not None: + new_shape = array_ops.concat( + [target_shape, array_ops.shape(out)[1:]], axis=0) + out = array_ops.reshape(out, new_shape) + if context.executing_eagerly(): + out.set_shape(target_static_shape.concatenate(flat_sources[i].shape)) + output[i] = out + + return nest.pack_sequence_as(sources, output) diff --git a/tensorflow/python/eager/backprop_test.py b/tensorflow/python/eager/backprop_test.py index d9f2a95828..237b7f304e 100644 --- a/tensorflow/python/eager/backprop_test.py +++ b/tensorflow/python/eager/backprop_test.py @@ -1227,5 +1227,81 @@ class BackpropTest(test.TestCase): self.assertAllEqual(da[0], tf_da[0].eval()) +@test_util.run_all_in_graph_and_eager_modes +class JacobianTest(test.TestCase): + + def _jacobian(self, experimental_use_pfor): + persistent = context.executing_eagerly and not experimental_use_pfor + with backprop.GradientTape(persistent=persistent) as g: + x = constant_op.constant([1., 2.]) + y = constant_op.constant([3., 4.]) + g.watch(x) + g.watch(y) + z = x * x * y + jacobian = g.jacobian(z, [x, y], + experimental_use_pfor=experimental_use_pfor) + answer = [array_ops.diag(2 * x * y), array_ops.diag(x * x)] + return jacobian, answer + + def testPfor(self): + jacobian, answer = self._jacobian(experimental_use_pfor=True) + for j, a in zip(jacobian, answer): + self.assertAllEqual(a, j) + + def testWhileLoop(self): + jacobian, answer = self._jacobian(experimental_use_pfor=False) + for j, a in zip(jacobian, answer): + self.assertAllEqual(a, j) + + def testPforDefun(self): + + @function.defun + def _f(): + return self._jacobian(experimental_use_pfor=True) + + jacobian, answer = _f() + for j, a in zip(jacobian, answer): + self.assertAllEqual(a, j) + + def testWhileLoopDefun(self): + + @function.defun + def _f(): + return self._jacobian(experimental_use_pfor=False) + + jacobian, answer = _f() + for j, a in zip(jacobian, answer): + self.assertAllEqual(a, j) + + def testPersistentTape(self): + if not context.executing_eagerly(): + return + with backprop.GradientTape() as g: + x = constant_op.constant([1.0, 2.0]) + g.watch(x) + y = x * x + with self.assertRaisesRegexp(RuntimeError, 'persistent'): + g.jacobian(y, x, experimental_use_pfor=False) + + def testPforException(self): + var = variables.Variable([1.]) + + @custom_gradient.custom_gradient + def op(x): + def grad(_): + # Note that we perform a stateful operation here that will not be + # compatible with parallel for construct. + with ops.control_dependencies( + [var.assign(random_ops.random_uniform([1]))]): + return constant_op.constant(1.) + return x, grad + + with backprop.GradientTape() as g: + x = constant_op.constant([1., 2.]) + g.watch(x) + y = op(x) + with self.assertRaisesRegexp(ValueError, 'No converter'): + g.jacobian(y, x, experimental_use_pfor=True) + if __name__ == '__main__': test.main() diff --git a/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt index 0a16d6ab92..50af42f4fc 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt @@ -10,6 +10,10 @@ tf_class { name: "gradient" argspec: "args=[\'self\', \'target\', \'sources\', \'output_gradients\', \'unconnected_gradients\'], varargs=None, keywords=None, defaults=[\'None\', \'UnconnectedGradients.NONE\'], " } + member_method { + name: "jacobian" + argspec: "args=[\'self\', \'target\', \'sources\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + } member_method { name: "reset" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt index 0a16d6ab92..50af42f4fc 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt @@ -10,6 +10,10 @@ tf_class { name: "gradient" argspec: "args=[\'self\', \'target\', \'sources\', \'output_gradients\', \'unconnected_gradients\'], varargs=None, keywords=None, defaults=[\'None\', \'UnconnectedGradients.NONE\'], " } + member_method { + name: "jacobian" + argspec: "args=[\'self\', \'target\', \'sources\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + } member_method { name: "reset" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" -- GitLab From 619b3f452923780de3a6164d5d692ee9343adeec Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Tue, 20 Nov 2018 11:41:25 -0800 Subject: [PATCH 132/672] Minor update to the unified LSTM. The activation function (callable) can be passed into defun function, since its is not tensor, it does not change the signature for the generated underlying functions. PiperOrigin-RevId: 222280524 --- .../python/keras/layers/unified_rnn_test.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/keras/layers/unified_rnn_test.py b/tensorflow/python/keras/layers/unified_rnn_test.py index 015a079a0d..a16d0f383a 100644 --- a/tensorflow/python/keras/layers/unified_rnn_test.py +++ b/tensorflow/python/keras/layers/unified_rnn_test.py @@ -174,6 +174,8 @@ class UnifiedLSTM(RNN): def __init__(self, units, + activation='tanh', + recurrent_activation='hard_sigmoid', kernel_initializer='glorot_uniform', recurrent_initializer='orthogonal', bias_initializer='zeros', @@ -196,7 +198,8 @@ class UnifiedLSTM(RNN): cell_spec = collections.namedtuple('cell', ['state_size', 'output_size']) self.cell = cell_spec( state_size=(self.units, self.units), output_size=self.units) - + self.activation = activations.get(activation) + self.recurrent_activation = activations.get(recurrent_activation) self.kernel_initializer = initializers.get(kernel_initializer) self.recurrent_initializer = initializers.get(recurrent_initializer) self.bias_initializer = initializers.get(bias_initializer) @@ -292,7 +295,8 @@ class UnifiedLSTM(RNN): outputs, [new_h, new_c], runtime = normal_lstm( inputs, initial_state[0], initial_state[1], self.kernel, - self.recurrent_kernel, self.bias, self.units) + self.recurrent_kernel, self.bias, self.units, self.activation, + self.recurrent_activation) function.register(cudnn_lstm, inputs, initial_state[0], initial_state[1], self.kernel, self.recurrent_kernel, self.bias, self.units) @@ -385,7 +389,8 @@ def _is_multiple_state(state_size): 'experimental_api_implements': 'lstm', 'experimental_api_preferred_device': 'CPU' }) -def normal_lstm(inputs, init_h, init_c, kernel, recurrent_kernel, bias, units): +def normal_lstm(inputs, init_h, init_c, kernel, recurrent_kernel, bias, units, + activation, recurrent_activation): input_shape = K.int_shape(inputs) timesteps = input_shape[1] @@ -405,12 +410,12 @@ def normal_lstm(inputs, init_h, init_c, kernel, recurrent_kernel, bias, units): z2 = z[:, 2 * units:3 * units] z3 = z[:, 3 * units:] - i = activations.get('hard_sigmoid')(z0) - f = activations.get('hard_sigmoid')(z1) - c = f * c_tm1 + i * activations.get('tanh')(z2) - o = activations.get('hard_sigmoid')(z3) + i = recurrent_activation(z0) + f = recurrent_activation(z1) + c = f * c_tm1 + i * activation(z2) + o = recurrent_activation(z3) - h = o * activations.get('tanh')(c) + h = o * activation(c) return h, [h, c] _, outputs, new_states = K.rnn( -- GitLab From e808d6d895502c0fb97f8fc1eb4e60b10ff2b8c5 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 11:47:20 -0800 Subject: [PATCH 133/672] Copied sort_ops.py and sort_ops_test.py from contrib/framework/python/ops to python/ops and adjusted them. PiperOrigin-RevId: 222281467 --- tensorflow/contrib/framework/BUILD | 15 +- .../contrib/framework/python/ops/sort_ops.py | 172 +-------------- tensorflow/python/BUILD | 28 +++ tensorflow/python/ops/sort_ops.py | 197 ++++++++++++++++++ .../python/ops/sort_ops_test.py | 6 +- tensorflow/python/ops/standard_ops.py | 1 + .../tools/api/golden/v1/tensorflow.pbtxt | 8 + .../tools/api/golden/v2/tensorflow.pbtxt | 8 + .../tools/compatibility/tf_upgrade_v2.py | 2 + 9 files changed, 250 insertions(+), 187 deletions(-) create mode 100644 tensorflow/python/ops/sort_ops.py rename tensorflow/{contrib/framework => }/python/ops/sort_ops_test.py (96%) diff --git a/tensorflow/contrib/framework/BUILD b/tensorflow/contrib/framework/BUILD index cd747df4d6..53efae1e10 100644 --- a/tensorflow/contrib/framework/BUILD +++ b/tensorflow/contrib/framework/BUILD @@ -66,6 +66,7 @@ tf_custom_op_py_library( "//tensorflow/python:resource_variable_ops", "//tensorflow/python:script_ops", "//tensorflow/python:smart_cond", + "//tensorflow/python:sort_ops", "//tensorflow/python:sparse_tensor", "//tensorflow/python:state_ops", "//tensorflow/python:state_ops_gen", @@ -311,17 +312,3 @@ py_test( "//third_party/py/numpy", ], ) - -py_test( - name = "sort_ops_test", - size = "medium", - srcs = ["python/ops/sort_ops_test.py"], - srcs_version = "PY2AND3", - deps = [ - ":framework_py", - "//tensorflow/python:array_ops", - "//tensorflow/python:client_testlib", - "//tensorflow/python:random_ops", - "//third_party/py/numpy", - ], -) diff --git a/tensorflow/contrib/framework/python/ops/sort_ops.py b/tensorflow/contrib/framework/python/ops/sort_ops.py index 1921a77c1e..42184a4e55 100644 --- a/tensorflow/contrib/framework/python/ops/sort_ops.py +++ b/tensorflow/contrib/framework/python/ops/sort_ops.py @@ -22,173 +22,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import numpy as np +from tensorflow.python.ops import sort_ops -from tensorflow.python.framework import constant_op -from tensorflow.python.framework import ops as framework_ops -from tensorflow.python.framework import tensor_util -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import math_ops -from tensorflow.python.ops import nn_ops - - -def sort(values, axis=-1, direction='ASCENDING', name=None): - """Sorts a tensor. - - Args: - values: 1-D or higher numeric `Tensor`. - axis: The axis along which to sort. The default is -1, which sorts the last - axis. - direction: The direction in which to sort the values (`'ASCENDING'` or - `'DESCENDING'`). - name: Optional name for the operation. - - Returns: - A `Tensor` with the same dtype and shape as `values`, with the elements - sorted along the given `axis`. - - Raises: - ValueError: If axis is not a constant scalar, or the direction is invalid. - """ - with framework_ops.name_scope(name, 'sort'): - return _sort_or_argsort(values, axis, direction, return_argsort=False) - - -def argsort(values, axis=-1, direction='ASCENDING', stable=False, name=None): - """Returns the indices of a tensor that give its sorted order along an axis. - - For a 1D tensor, `tf.gather(values, tf.argsort(values))` is equivalent to - `tf.sort(values)`. For higher dimensions, the output has the same shape as - `values`, but along the given axis, values represent the index of the sorted - element in that slice of the tensor at the given position. - - Args: - values: 1-D or higher numeric `Tensor`. - axis: The axis along which to sort. The default is -1, which sorts the last - axis. - direction: The direction in which to sort the values (`'ASCENDING'` or - `'DESCENDING'`). - stable: If True, equal elements in the original tensor will not be - re-ordered in the returned order. Unstable sort is not yet implemented, - but will eventually be the default for performance reasons. If you - require a stable order, pass `stable=True` for forwards compatibility. - name: Optional name for the operation. - - Returns: - An int32 `Tensor` with the same shape as `values`. The indices that would - sort each slice of the given `values` along the given `axis`. - - Raises: - ValueError: If axis is not a constant scalar, or the direction is invalid. - """ - del stable # Unused. - with framework_ops.name_scope(name, 'argsort'): - return _sort_or_argsort(values, axis, direction, return_argsort=True) - - -def _sort_or_argsort(values, axis, direction, return_argsort): - """Internal sort/argsort implementation. - - Args: - values: The input values. - axis: The axis along which to sort. - direction: 'ASCENDING' or 'DESCENDING'. - return_argsort: Whether to return the argsort result. - - Returns: - Either the sorted values, or the indices of the sorted values in the - original tensor. See the `sort` and `argsort` docstrings. - - Raises: - ValueError: If axis is not a constant scalar, or the direction is invalid. - """ - if direction not in _SORT_IMPL: - raise ValueError('%s should be one of %s' % - (direction, ', '.join(sorted(_SORT_IMPL.keys())))) - # Axis must be an integer, not a Tensor. - axis = framework_ops.convert_to_tensor(axis, name='axis') - axis_static = tensor_util.constant_value(axis) - if axis.shape.ndims != 0 or axis_static is None: - raise ValueError('axis must be a constant scalar') - axis_static = int(axis_static) # Avoids NumPy casting error - - values = framework_ops.convert_to_tensor(values, name='values') - - return _SORT_IMPL[direction](values, axis_static, return_argsort) - - -def _descending_sort(values, axis, return_argsort=False): - """Sorts values in reverse using `top_k`. - - Args: - values: Tensor of numeric values. - axis: Index of the axis which values should be sorted along. - return_argsort: If False, return the sorted values. If True, return the - indices that would sort the values. - - Returns: - The sorted values. - """ - k = array_ops.shape(values)[axis] - rank = array_ops.rank(values) - static_rank = values.shape.ndims - # Fast path: sorting the last axis. - if axis == -1 or axis + 1 == values.get_shape().ndims: - top_k_input = values - transposition = None - else: - # Otherwise, transpose the array. Swap axes `axis` and `rank - 1`. - if axis < 0: - # Calculate the actual axis index if counting from the end. Use the static - # rank if available, or else make the axis back into a tensor. - axis += static_rank or rank - if static_rank is not None: - # Prefer to calculate the transposition array in NumPy and make it a - # constant. - transposition = constant_op.constant( - np.r_[ - # Axes up to axis are unchanged. - np.arange(axis), - # Swap axis and rank - 1. - [static_rank - 1], - # Axes in [axis + 1, rank - 1) are unchanged. - np.arange(axis + 1, static_rank - 1), - # Swap axis and rank - 1. - [axis]], - name='transposition') - else: - # Generate the transposition array from the tensors. - transposition = array_ops.concat( - [ - # Axes up to axis are unchanged. - math_ops.range(axis), - # Swap axis and rank - 1. - [rank - 1], - # Axes in [axis + 1, rank - 1) are unchanged. - math_ops.range(axis + 1, rank - 1), - # Swap axis and rank - 1. - [axis] - ], - axis=0) - top_k_input = array_ops.transpose(values, transposition) - - values, indices = nn_ops.top_k(top_k_input, k) - return_value = indices if return_argsort else values - if transposition is not None: - # transposition contains a single cycle of length 2 (swapping 2 elements), - # so it is an involution (it is its own inverse). - return_value = array_ops.transpose(return_value, transposition) - return return_value - - -def _ascending_sort(values, axis, return_argsort=False): - # Negate the values to get the ascending order from descending sort. - values_or_indices = _descending_sort(-values, axis, return_argsort) - # If not argsort, negate the values again. - return values_or_indices if return_argsort else -values_or_indices - - -_SORT_IMPL = { - 'ASCENDING': _ascending_sort, - 'DESCENDING': _descending_sort, -} +sort = sort_ops.sort +argsort = sort_ops.argsort diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 1010678533..3def23bc44 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -2843,6 +2843,33 @@ py_test( ], ) +py_library( + name = "sort_ops", + srcs = ["ops/sort_ops.py"], + srcs_version = "PY2AND3", + deps = [ + ":array_ops", + ":framework", + ":math_ops", + ":nn_ops", + "//third_party/py/numpy", + ], +) + +py_test( + name = "sort_ops_test", + srcs = ["ops/sort_ops_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":array_ops", + ":client_testlib", + ":framework", + ":random_ops", + ":sort_ops", + "//third_party/py/numpy", + ], +) + py_library( name = "spectral_ops_test_util", srcs = ["ops/spectral_ops_test_util.py"], @@ -2957,6 +2984,7 @@ py_library( ":random_ops", ":script_ops", ":session_ops", + ":sort_ops", ":sparse_grad", ":sparse_ops", ":special_math_ops", diff --git a/tensorflow/python/ops/sort_ops.py b/tensorflow/python/ops/sort_ops.py new file mode 100644 index 0000000000..c3e23d701e --- /dev/null +++ b/tensorflow/python/ops/sort_ops.py @@ -0,0 +1,197 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Support for sorting tensors. + +@@argsort +@@sort +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import ops as framework_ops +from tensorflow.python.framework import tensor_util +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import nn_ops +from tensorflow.python.util.tf_export import tf_export + + +@tf_export('sort') +def sort(values, axis=-1, direction='ASCENDING', name=None): + """Sorts a tensor. + + Args: + values: 1-D or higher numeric `Tensor`. + axis: The axis along which to sort. The default is -1, which sorts the last + axis. + direction: The direction in which to sort the values (`'ASCENDING'` or + `'DESCENDING'`). + name: Optional name for the operation. + + Returns: + A `Tensor` with the same dtype and shape as `values`, with the elements + sorted along the given `axis`. + + Raises: + ValueError: If axis is not a constant scalar, or the direction is invalid. + """ + with framework_ops.name_scope(name, 'sort'): + return _sort_or_argsort(values, axis, direction, return_argsort=False) + + +@tf_export('argsort') +def argsort(values, axis=-1, direction='ASCENDING', stable=False, name=None): + """Returns the indices of a tensor that give its sorted order along an axis. + + For a 1D tensor, `tf.gather(values, tf.argsort(values))` is equivalent to + `tf.sort(values)`. For higher dimensions, the output has the same shape as + `values`, but along the given axis, values represent the index of the sorted + element in that slice of the tensor at the given position. + + Args: + values: 1-D or higher numeric `Tensor`. + axis: The axis along which to sort. The default is -1, which sorts the last + axis. + direction: The direction in which to sort the values (`'ASCENDING'` or + `'DESCENDING'`). + stable: If True, equal elements in the original tensor will not be + re-ordered in the returned order. Unstable sort is not yet implemented, + but will eventually be the default for performance reasons. If you require + a stable order, pass `stable=True` for forwards compatibility. + name: Optional name for the operation. + + Returns: + An int32 `Tensor` with the same shape as `values`. The indices that would + sort each slice of the given `values` along the given `axis`. + + Raises: + ValueError: If axis is not a constant scalar, or the direction is invalid. + """ + del stable # Unused. + with framework_ops.name_scope(name, 'argsort'): + return _sort_or_argsort(values, axis, direction, return_argsort=True) + + +def _sort_or_argsort(values, axis, direction, return_argsort): + """Internal sort/argsort implementation. + + Args: + values: The input values. + axis: The axis along which to sort. + direction: 'ASCENDING' or 'DESCENDING'. + return_argsort: Whether to return the argsort result. + + Returns: + Either the sorted values, or the indices of the sorted values in the + original tensor. See the `sort` and `argsort` docstrings. + + Raises: + ValueError: If axis is not a constant scalar, or the direction is invalid. + """ + if direction not in _SORT_IMPL: + raise ValueError('%s should be one of %s' % (direction, ', '.join( + sorted(_SORT_IMPL.keys())))) + # Axis must be an integer, not a Tensor. + axis = framework_ops.convert_to_tensor(axis, name='axis') + axis_static = tensor_util.constant_value(axis) + if axis.shape.ndims != 0 or axis_static is None: + raise ValueError('axis must be a constant scalar') + axis_static = int(axis_static) # Avoids NumPy casting error + + values = framework_ops.convert_to_tensor(values, name='values') + + return _SORT_IMPL[direction](values, axis_static, return_argsort) + + +def _descending_sort(values, axis, return_argsort=False): + """Sorts values in reverse using `top_k`. + + Args: + values: Tensor of numeric values. + axis: Index of the axis which values should be sorted along. + return_argsort: If False, return the sorted values. If True, return the + indices that would sort the values. + + Returns: + The sorted values. + """ + k = array_ops.shape(values)[axis] + rank = array_ops.rank(values) + static_rank = values.shape.ndims + # Fast path: sorting the last axis. + if axis == -1 or axis + 1 == values.get_shape().ndims: + top_k_input = values + transposition = None + else: + # Otherwise, transpose the array. Swap axes `axis` and `rank - 1`. + if axis < 0: + # Calculate the actual axis index if counting from the end. Use the static + # rank if available, or else make the axis back into a tensor. + axis += static_rank or rank + if static_rank is not None: + # Prefer to calculate the transposition array in NumPy and make it a + # constant. + transposition = constant_op.constant( + np.r_[ + # Axes up to axis are unchanged. + np.arange(axis), + # Swap axis and rank - 1. + [static_rank - 1], + # Axes in [axis + 1, rank - 1) are unchanged. + np.arange(axis + 1, static_rank - 1), + # Swap axis and rank - 1. + [axis]], + name='transposition') + else: + # Generate the transposition array from the tensors. + transposition = array_ops.concat( + [ + # Axes up to axis are unchanged. + math_ops.range(axis), + # Swap axis and rank - 1. + [rank - 1], + # Axes in [axis + 1, rank - 1) are unchanged. + math_ops.range(axis + 1, rank - 1), + # Swap axis and rank - 1. + [axis] + ], + axis=0) + top_k_input = array_ops.transpose(values, transposition) + + values, indices = nn_ops.top_k(top_k_input, k) + return_value = indices if return_argsort else values + if transposition is not None: + # transposition contains a single cycle of length 2 (swapping 2 elements), + # so it is an involution (it is its own inverse). + return_value = array_ops.transpose(return_value, transposition) + return return_value + + +def _ascending_sort(values, axis, return_argsort=False): + # Negate the values to get the ascending order from descending sort. + values_or_indices = _descending_sort(-values, axis, return_argsort) + # If not argsort, negate the values again. + return values_or_indices if return_argsort else -values_or_indices + + +_SORT_IMPL = { + 'ASCENDING': _ascending_sort, + 'DESCENDING': _descending_sort, +} diff --git a/tensorflow/contrib/framework/python/ops/sort_ops_test.py b/tensorflow/python/ops/sort_ops_test.py similarity index 96% rename from tensorflow/contrib/framework/python/ops/sort_ops_test.py rename to tensorflow/python/ops/sort_ops_test.py index 791b32cd1e..8a92f49266 100644 --- a/tensorflow/contrib/framework/python/ops/sort_ops_test.py +++ b/tensorflow/python/ops/sort_ops_test.py @@ -20,7 +20,6 @@ from __future__ import print_function import numpy as np -from tensorflow.contrib.framework.python.ops import sort_ops from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors @@ -28,6 +27,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops +from tensorflow.python.ops import sort_ops from tensorflow.python.platform import test @@ -88,9 +88,7 @@ class SortTest(test.TestCase): self.assertAllEqual( np.sort(arr, axis=0)[::-1], sort_ops.sort( - constant_op.constant(arr), - axis=0, - direction='DESCENDING').eval()) + constant_op.constant(arr), axis=0, direction='DESCENDING').eval()) def testSort_staticallyKnownRank_constantTransposition(self): # The transposition array should be a constant if the rank of "values" is diff --git a/tensorflow/python/ops/standard_ops.py b/tensorflow/python/ops/standard_ops.py index 03e491a315..c614d072ba 100644 --- a/tensorflow/python/ops/standard_ops.py +++ b/tensorflow/python/ops/standard_ops.py @@ -72,6 +72,7 @@ from tensorflow.python.ops.partitioned_variables import * from tensorflow.python.ops.random_ops import * from tensorflow.python.ops.script_ops import py_func from tensorflow.python.ops.session_ops import * +from tensorflow.python.ops.sort_ops import * from tensorflow.python.ops.sparse_ops import * from tensorflow.python.ops.state_ops import assign from tensorflow.python.ops.state_ops import assign_add diff --git a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt index 6a45bc7b7f..367f506b21 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt @@ -700,6 +700,10 @@ tf_module { name: "argmin" argspec: "args=[\'input\', \'axis\', \'name\', \'dimension\', \'output_type\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \"\"], " } + member_method { + name: "argsort" + argspec: "args=[\'values\', \'axis\', \'direction\', \'stable\', \'name\'], varargs=None, keywords=None, defaults=[\'-1\', \'ASCENDING\', \'False\', \'None\'], " + } member_method { name: "as_dtype" argspec: "args=[\'type_value\'], varargs=None, keywords=None, defaults=None" @@ -1956,6 +1960,10 @@ tf_module { name: "slice" argspec: "args=[\'input_\', \'begin\', \'size\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "sort" + argspec: "args=[\'values\', \'axis\', \'direction\', \'name\'], varargs=None, keywords=None, defaults=[\'-1\', \'ASCENDING\', \'None\'], " + } member_method { name: "space_to_batch" argspec: "args=[\'input\', \'paddings\', \'block_size\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 6adce4b3fd..1711348ec3 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -452,6 +452,10 @@ tf_module { name: "argmin" argspec: "args=[\'input\', \'axis\', \'output_type\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \"\", \'None\'], " } + member_method { + name: "argsort" + argspec: "args=[\'values\', \'axis\', \'direction\', \'stable\', \'name\'], varargs=None, keywords=None, defaults=[\'-1\', \'ASCENDING\', \'False\', \'None\'], " + } member_method { name: "as_dtype" argspec: "args=[\'type_value\'], varargs=None, keywords=None, defaults=None" @@ -1036,6 +1040,10 @@ tf_module { name: "slice" argspec: "args=[\'input_\', \'begin\', \'size\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "sort" + argspec: "args=[\'values\', \'axis\', \'direction\', \'name\'], varargs=None, keywords=None, defaults=[\'-1\', \'ASCENDING\', \'None\'], " + } member_method { name: "space_to_batch_nd" argspec: "args=[\'input\', \'block_shape\', \'paddings\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 3cef1f1602..c60c6a4b32 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -153,6 +153,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.contrib.data.sloppy_interleave": "tf.compat.v1.contrib.data.sloppy_interleave", "tf.contrib.data.unbatch": "tf.data.experimental.unbatch", "tf.contrib.data.unique": "tf.data.experimental.unique", + "tf.contrib.framework.sort": "tf.sort", + "tf.contrib.framework.argsort": "tf.argsort", "tf.quantize_v2": "tf.quantization.quantize", "tf.sparse_concat": "tf.sparse.concat", "tf.sparse_split": "tf.sparse.split", -- GitLab From bf8544fccf8d4f909600b1840758680f411deaa7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 11:48:08 -0800 Subject: [PATCH 134/672] Switch some code to the new tf.distribute.Strategy API. PiperOrigin-RevId: 222281620 --- .../collective_all_reduce_strategy_test.py | 2 +- .../python/cross_device_ops_test.py | 2 +- .../python/estimator_integration_test.py | 4 +- .../python/estimator_training_test.py | 4 +- .../python/keras_optimizer_v2_test.py | 4 +- .../distribute/python/mirrored_strategy.py | 4 +- .../python/mirrored_strategy_multigpu_test.py | 133 +++++++++--------- .../distribute/python/one_device_strategy.py | 6 +- .../python/one_device_strategy_test.py | 2 +- .../python/parameter_server_strategy_test.py | 6 +- .../distribute/python/strategy_test_lib.py | 7 +- .../contrib/distribute/python/tpu_strategy.py | 6 +- .../contrib/optimizer_v2/optimizer_v2.py | 17 +-- .../distribute/distribute_coordinator.py | 22 +-- .../distribute/distribute_coordinator_test.py | 67 +++++---- .../python/distribute/estimator_training.py | 4 +- tensorflow/python/distribute/values.py | 10 +- tensorflow/python/eager/tape.py | 4 +- .../keras/engine/training_distributed.py | 16 +-- tensorflow/python/training/distribute_test.py | 4 +- .../python/training/monitored_session_test.py | 32 ++--- tensorflow/python/training/optimizer.py | 16 ++- 22 files changed, 183 insertions(+), 189 deletions(-) diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py index a47eef94e9..eb2b859aa5 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py @@ -249,7 +249,7 @@ class CollectiveAllReduceStrategyTestBase( expected_values): distribution, master_target, config = self._get_test_object( task_type, task_id, num_gpus) - devices = distribution.worker_devices + devices = distribution.extended.worker_devices with ops.Graph().as_default(), \ self.cached_session(config=config, diff --git a/tensorflow/contrib/distribute/python/cross_device_ops_test.py b/tensorflow/contrib/distribute/python/cross_device_ops_test.py index 00672a4401..a0f7cf182c 100644 --- a/tensorflow/contrib/distribute/python/cross_device_ops_test.py +++ b/tensorflow/contrib/distribute/python/cross_device_ops_test.py @@ -119,7 +119,7 @@ class CrossDeviceOpsTestBase(test.TestCase, parameterized.TestCase): sess.run(list(left._index.values())), list(right._index.values())) def _testReductionAndBroadcast(self, cross_device_ops, distribution): - devices = distribution.worker_devices + devices = distribution.extended.worker_devices values = [constant_op.constant(float(d)) for d in range(len(devices))] per_replica = _make_per_replica(values, devices) diff --git a/tensorflow/contrib/distribute/python/estimator_integration_test.py b/tensorflow/contrib/distribute/python/estimator_integration_test.py index 264dca6f38..e17085628b 100644 --- a/tensorflow/contrib/distribute/python/estimator_integration_test.py +++ b/tensorflow/contrib/distribute/python/estimator_integration_test.py @@ -77,12 +77,12 @@ class DNNLinearCombinedClassifierIntegrationTest(test.TestCase, train_input_fn = self.dataset_input_fn( x={'x': data}, y=data, - batch_size=batch_size // len(distribution.worker_devices), + batch_size=batch_size // distribution.num_replicas_in_sync, shuffle=True) eval_input_fn = self.dataset_input_fn( x={'x': data}, y=data, - batch_size=batch_size // len(distribution.worker_devices), + batch_size=batch_size // distribution.num_replicas_in_sync, shuffle=False) predict_input_fn = numpy_io.numpy_input_fn( x={'x': data}, batch_size=batch_size, shuffle=False) diff --git a/tensorflow/contrib/distribute/python/estimator_training_test.py b/tensorflow/contrib/distribute/python/estimator_training_test.py index 3e7d5df4c4..202e92d1e7 100644 --- a/tensorflow/contrib/distribute/python/estimator_training_test.py +++ b/tensorflow/contrib/distribute/python/estimator_training_test.py @@ -204,10 +204,10 @@ class DistributeCoordinatorIntegrationTest(test.TestCase, train_input_fn = self.dataset_input_fn( x={"x": DATA}, y=DATA, - batch_size=BATCH_SIZE // len(train_distribute.worker_devices), + batch_size=BATCH_SIZE // train_distribute.num_replicas_in_sync, shuffle=True) if eval_distribute: - eval_batch_size = BATCH_SIZE // len(eval_distribute.worker_devices) + eval_batch_size = BATCH_SIZE // eval_distribute.num_replicas_in_sync else: eval_batch_size = BATCH_SIZE eval_input_fn = self.dataset_input_fn( diff --git a/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py b/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py index 0d7e11c3b6..fba06283ce 100644 --- a/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py +++ b/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py @@ -83,11 +83,11 @@ class KerasOptimizerV2IntegrationTest(test.TestCase, parameterized.TestCase): train_input_fn = self.dataset_input_fn( x={'x': data}, y=data, - batch_size=batch_size // len(distribution.worker_devices)) + batch_size=batch_size // distribution.num_replicas_in_sync) eval_input_fn = self.dataset_input_fn( x={'x': data}, y=data, - batch_size=batch_size // len(distribution.worker_devices)) + batch_size=batch_size // distribution.num_replicas_in_sync) predict_input_fn = numpy_io.numpy_input_fn( x={'x': data}, batch_size=batch_size, shuffle=False) diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy.py b/tensorflow/contrib/distribute/python/mirrored_strategy.py index f7432162cb..a2ab95487a 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy.py @@ -742,7 +742,7 @@ class CoreMirroredExtended(distribute_lib.DistributionStrategyExtended): self.coord = coord self.distribution = dist self.device = device - self.replica_id = dist.worker_devices.index(device) + self.replica_id = dist.extended.worker_devices.index(device) self.variable_creator_fn = variable_creator_fn # State needed to run and return the results of `fn`. self.main_fn = fn @@ -944,4 +944,4 @@ class MirroredReplicaContext(distribute_lib.ReplicaContext): def devices(self): distribute_lib.require_replica_context(self) replica_id = tensor_util.constant_value(self._replica_id_in_sync_group) - return [self._distribution_strategy.worker_devices[replica_id]] + return [self._distribution_strategy.extended.worker_devices[replica_id]] diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py index 9fd4cca319..d20ac144bf 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py @@ -90,11 +90,11 @@ class MirroredTwoDeviceDistributionTest(strategy_test_lib.DistributionTestBase, return list(range(replica_id)) with distribution.scope(), self.assertRaises(AssertionError): - distribution.call_for_each_replica(run_fn) + distribution.extended.call_for_each_replica(run_fn) def testReduceToCpu(self, distribution): with distribution.scope(): - result = distribution.call_for_each_replica(_replica_id) + result = distribution.extended.call_for_each_replica(_replica_id) reduced = distribution.reduce( reduce_util.ReduceOp.SUM, result, @@ -114,7 +114,7 @@ class MirroredTwoDeviceDistributionTest(strategy_test_lib.DistributionTestBase, expected_num_input_pipelines=1, expected_input_pipeline_id=0) iterator = distribution.make_input_fn_iterator(input_fn) - self._test_input_fn_iterator(iterator, distribution.worker_devices, + self._test_input_fn_iterator(iterator, distribution.extended.worker_devices, expected_values) def testGlobalStepUpdate(self, distribution): @@ -150,7 +150,7 @@ class MirroredOneDeviceDistributionTest( mode=["graph", "eager"])) def testReduceToMultipleDestinations(self, distribution): with distribution.scope(): - reduced = distribution.reduce( + reduced = distribution.extended.reduce_to( reduce_util.ReduceOp.SUM, 1.0, destinations=["/device:CPU:0", "/device:GPU:0"]) @@ -204,7 +204,7 @@ class MirroredStrategyVariableCreatorStackTest( with context.graph_mode(), \ distribution.scope(), \ variable_scope.variable_creator_scope(main_thread_creator): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) result = distribution.unwrap(result) expected = ["main_thread:thread_0", "main_thread:thread_1"] self.assertEqual(expected, result) @@ -221,13 +221,13 @@ class MirroredStrategyVariableCreationTest(test.TestCase): def model_fn(): # This variable should be created only once across the threads because of # special variable_creator functions used by - # `distribution.call_for_each_replica`. + # `distribution.extended.call_for_each_replica`. v = variable_scope.variable(1.0, name="foo") ds_context.get_replica_context().merge_call(lambda _: _) return v with distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertIsInstance(result, values.MirroredVariable) self.assertEqual("foo:0", result.name) @@ -238,7 +238,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): return v with distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertIsInstance(result, values.MirroredVariable) # Default name of "Variable" will be used. self.assertEqual("Variable:0", result.name) @@ -252,7 +252,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): return vs with distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) for i, v in enumerate(result): self.assertIsInstance(v, values.MirroredVariable) self.assertEqual("foo" + str(i) + ":0", v.name) @@ -268,7 +268,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): return vs with distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) for v in result: self.assertIsInstance(v, values.MirroredVariable) self.assertEqual(4, len(result)) @@ -285,7 +285,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): return v with distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertIsInstance(result, values.MirroredVariable) # The resulting mirrored variable will use the name from the first device. self.assertEqual("foo_0:0", result.name) @@ -316,7 +316,8 @@ class MirroredStrategyVariableCreationTest(test.TestCase): features = iterator.get_next() with distribution.scope(): - result = distribution.call_for_each_replica(model_fn, args=(features,)) + result = distribution.extended.call_for_each_replica( + model_fn, args=(features,)) suffixes = ["", "_1", "_2"] for (kernel, bias), suffix in zip(result, suffixes): self.assertIsInstance(kernel, values.MirroredVariable) @@ -348,7 +349,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): v = variable_scope.variable(1.0, name="var-main0") self.assertEqual("var-main0:0", v.name) - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertEqual(4, len(result)) v0, v1, v2, v3 = result self.assertIsInstance(v0, values.MirroredVariable) @@ -385,7 +386,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): v = variable_scope.get_variable("var-main0", [1]) self.assertEqual("main/var-main0:0", v.name) - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertEqual(4, len(result)) v0, v1, v2, v3 = result self.assertIsInstance(v0, values.MirroredVariable) @@ -418,15 +419,15 @@ class MirroredStrategyVariableCreationTest(test.TestCase): devices = ["/device:GPU:0", "/device:CPU:0"] with distribution.scope(): - v0, v1 = distribution.call_for_each_replica(create_fn) + v0, v1 = distribution.extended.call_for_each_replica(create_fn) self.evaluate(v0.initializer) self.assertEqual(2.0, self.evaluate(v0.get(devices[0]))) self.assertEqual(2.0, self.evaluate(v0.get(devices[1]))) - self.assertEqual(2.0, self.evaluate(distribution.read_var(v0))) + self.assertEqual(2.0, self.evaluate(distribution.extended.read_var(v0))) self.evaluate(v1.initializer) self.assertEqual(3.0, self.evaluate(v1.get(devices[0]))) self.assertEqual(3.0, self.evaluate(v1.get(devices[1]))) - self.assertEqual(3.0, self.evaluate(distribution.read_var(v1))) + self.assertEqual(3.0, self.evaluate(distribution.extended.read_var(v1))) def replica_id_plus_one(): return math_ops.cast(_replica_id() + 1, dtype=dtypes.float32) @@ -437,7 +438,8 @@ class MirroredStrategyVariableCreationTest(test.TestCase): update1 = v1.assign_add(7.0 * replica_id_plus_one()) return update0, update1 - update0a, update1a = distribution.call_for_each_replica(update_member_fn) + update0a, update1a = distribution.extended.call_for_each_replica( + update_member_fn) # Update "sync on read" variable. self.evaluate(distribution.group(update0a)) @@ -446,7 +448,8 @@ class MirroredStrategyVariableCreationTest(test.TestCase): # so device[1] can end up with a different value. self.assertEqual(2.0 + 2*5.0, self.evaluate(v0.get(devices[1]))) # Always reads from device 0. - self.assertEqual(2.0 + 5.0, self.evaluate(distribution.read_var(v0))) + self.assertEqual(2.0 + 5.0, self.evaluate( + distribution.extended.read_var(v0))) # Update "sync on write" variable. self.evaluate(distribution.group(update1a)) @@ -454,7 +457,8 @@ class MirroredStrategyVariableCreationTest(test.TestCase): # Writes are synchronized for v1, only the argument to assign_add on # device[0] is used. self.assertEqual(3.0 + 7.0, self.evaluate(v1.get(devices[1]))) - self.assertEqual(3.0 + 7.0, self.evaluate(distribution.read_var(v1))) + self.assertEqual(3.0 + 7.0, self.evaluate( + distribution.extended.read_var(v1))) # Update using state_ops.assign_add global function. def update_state_ops_fn(): @@ -462,7 +466,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): update1 = state_ops.assign_add(v1, 13.0 * replica_id_plus_one()) return update0, update1 - update0b, update1b = distribution.call_for_each_replica( + update0b, update1b = distribution.extended.call_for_each_replica( update_state_ops_fn) self.evaluate(distribution.group(update0b)) @@ -470,14 +474,14 @@ class MirroredStrategyVariableCreationTest(test.TestCase): self.assertEqual(2.0 + 5.0 + 11.0, self.evaluate(v0.get(devices[0]))) self.assertEqual(2.0 + 2*5.0 + 2*11.0, self.evaluate(v0.get(devices[1]))) self.assertEqual(2.0 + 5.0 + 11.0, self.evaluate( - distribution.read_var(v0))) + distribution.extended.read_var(v0))) # Update "sync on write" variable. self.evaluate(distribution.group(update1b)) self.assertEqual(3.0 + 7.0 + 13.0, self.evaluate(v1.get(devices[0]))) self.assertEqual(3.0 + 7.0 + 13.0, self.evaluate(v1.get(devices[1]))) self.assertEqual(3.0 + 7.0 + 13.0, self.evaluate( - distribution.read_var(v1))) + distribution.extended.read_var(v1))) def testNoneSynchronizationWithGetVariable(self, distribution): with distribution.scope(): @@ -540,7 +544,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): "/device:GPU:0": "bar" }) with self.assertRaises(RuntimeError): - _ = distribution.call_for_each_replica(model_fn, args=(names,)) + _ = distribution.extended.call_for_each_replica(model_fn, args=(names,)) def testReplicaLocalVariable(self, distribution): all_v_sum = {} @@ -575,7 +579,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): with distribution.scope(): # Create "sum" and "mean" versions of ReplicaLocalVariables. ret_ops, ret_v_sum, ret_v_mean, regrouped_sum, regrouped_mean = ( - distribution.call_for_each_replica(model_fn)) + distribution.extended.call_for_each_replica(model_fn)) # Should see the same wrapping instance in all replicas. self.assertIs(all_v_sum[0], ret_v_sum) self.assertIs(all_v_mean[0], ret_v_mean) @@ -609,9 +613,9 @@ class MirroredStrategyVariableCreationTest(test.TestCase): # applying the reduction across all replicas (whether you use # read_var(), get(), or nothing). self.assertEqual(expected_sum, self.evaluate( - distribution.read_var(ret_v_sum))) + distribution.extended.read_var(ret_v_sum))) self.assertEqual(expected_mean, self.evaluate( - distribution.read_var(ret_v_mean))) + distribution.extended.read_var(ret_v_mean))) self.assertEqual(expected_sum, self.evaluate(ret_v_sum.get())) self.assertEqual(expected_mean, self.evaluate(ret_v_mean.get())) self.assertEqual(expected_sum, self.evaluate(ret_v_sum)) @@ -631,7 +635,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): return outputs with context.graph_mode(), distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) # Two variables are created by the RNN layer. self.assertEqual(2, len(result)) for v in result: @@ -652,7 +656,7 @@ class MirroredStrategyVariableCreationTest(test.TestCase): return var.assign(value) with distribution.scope(): - ret_v_sum = distribution.call_for_each_replica(model_fn) + ret_v_sum = distribution.extended.call_for_each_replica(model_fn) # Initialize variables. self.evaluate(variables.global_variables_initializer()) @@ -663,7 +667,8 @@ class MirroredStrategyVariableCreationTest(test.TestCase): self.assertEqual(2.0, self.evaluate(ret_v_sum)) # Apply updates. - update_ops = distribution.update(ret_v_sum, update, 5.0, grouped=False) + update_ops = distribution.extended.update( + ret_v_sum, update, args=(5.0,), group=False) self.evaluate(update_ops) # Assert that the aggregated value of the replica local vars is the sum # of the individual values after running the update ops. @@ -691,7 +696,7 @@ class MirroredStrategyNameScopeTest(test.TestCase): with context.graph_mode(), distribution.scope(): with ops.name_scope("main"): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertEqual(2, len(result)) for v, name in zip(result, ["a", "b"]): self.assertIsInstance(v, values.DistributedValues) @@ -708,7 +713,7 @@ class MirroredStrategyNameScopeTest(test.TestCase): return a, b with context.graph_mode(), distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertEqual(2, len(result)) for v, name in zip(result, ["a", "b"]): self.assertIsInstance(v, values.DistributedValues) @@ -734,7 +739,7 @@ class MirroredStrategyNameScopeTest(test.TestCase): with context.graph_mode(), distribution.scope(): with ops.name_scope("main"): a = variable_scope.variable(1.0, name="a") - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) result_b = result[0] result_c = result[1] self.assertIsInstance(result_b, values.DistributedValues) @@ -763,7 +768,7 @@ class MirroredStrategyNameScopeTest(test.TestCase): with context.graph_mode(), distribution.scope(): with ops.name_scope("main"): a = variable_scope.get_variable("a", [1]) - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) result_b = result[0] result_c = result[1] self.assertIsInstance(result_b, values.DistributedValues) @@ -805,7 +810,7 @@ class MirroredThreeDeviceDistributionTest( return v with distribution.scope(): - result = distribution.call_for_each_replica(model_fn) + result = distribution.extended.call_for_each_replica(model_fn) self.assertIsInstance(result, values.MirroredVariable) self.assertEqual("foo:0", result.name) @@ -828,7 +833,7 @@ class MirroredVariableUpdateTest(test.TestCase): return v with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) @@ -839,7 +844,7 @@ class MirroredVariableUpdateTest(test.TestCase): ValueError, "You must specify an aggregation method to update a " "MirroredVariable in Replica Context."): self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) def testAssignMirroredVarReplicaContextWithSum(self, distribution): # Test that we don't reduce a non-per-replica value with the "sum" @@ -850,7 +855,7 @@ class MirroredVariableUpdateTest(test.TestCase): return v with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) @@ -861,14 +866,14 @@ class MirroredVariableUpdateTest(test.TestCase): ValueError, "A non-DistributedValues value 5.0 cannot be reduced " "with the given reduce op ReduceOp.SUM."): self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) def testAssignMirroredVarCrossDeviceContext(self, distribution): def var_fn(): return variable_scope.variable(1.0, name="foo") with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(1.0, self.evaluate(mirrored_var)) @@ -881,7 +886,7 @@ class MirroredVariableUpdateTest(test.TestCase): 1.0, name="foo", aggregation=variable_scope.VariableAggregation.MEAN) with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(1.0, self.evaluate(mirrored_var)) @@ -893,7 +898,7 @@ class MirroredVariableUpdateTest(test.TestCase): return mirrored_var.assign(value) self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) self.assertEqual(0.5, self.evaluate(mirrored_var)) def testAssignMirroredVarReplicaContextWithSingleValue(self, distribution): @@ -902,7 +907,7 @@ class MirroredVariableUpdateTest(test.TestCase): 1.0, name="foo", aggregation=variable_scope.VariableAggregation.MEAN) with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(1.0, self.evaluate(mirrored_var)) @@ -911,7 +916,7 @@ class MirroredVariableUpdateTest(test.TestCase): return mirrored_var.assign(5.0) self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) self.assertEqual(5.0, self.evaluate(mirrored_var)) def testAssignAddMirroredVarCrossDeviceContext(self, distribution): @@ -919,7 +924,7 @@ class MirroredVariableUpdateTest(test.TestCase): return variable_scope.variable(1.0, name="foo") with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(1.0, self.evaluate(mirrored_var)) @@ -942,7 +947,7 @@ class MirroredVariableUpdateTest(test.TestCase): 1.0, name="foo", aggregation=variable_scope.VariableAggregation.MEAN) with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(1.0, self.evaluate(mirrored_var)) @@ -954,7 +959,7 @@ class MirroredVariableUpdateTest(test.TestCase): return mirrored_var.assign_add(value) self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) self.assertEqual(1.5, self.evaluate(mirrored_var)) def testAssignAddMirroredVarReplicaContextWithSingleValue(self, distribution): @@ -963,7 +968,7 @@ class MirroredVariableUpdateTest(test.TestCase): 1.0, name="foo", aggregation=variable_scope.VariableAggregation.MEAN) with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(1.0, self.evaluate(mirrored_var)) @@ -972,7 +977,7 @@ class MirroredVariableUpdateTest(test.TestCase): return mirrored_var.assign_add(5.0) self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) self.assertEqual(6.0, self.evaluate(mirrored_var)) def testAssignSubMirroredVarCrossDeviceContext(self, distribution): @@ -980,7 +985,7 @@ class MirroredVariableUpdateTest(test.TestCase): return variable_scope.variable(5.0, name="foo") with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(5.0, self.evaluate(mirrored_var)) @@ -995,7 +1000,7 @@ class MirroredVariableUpdateTest(test.TestCase): 5.0, name="foo", aggregation=variable_scope.VariableAggregation.MEAN) with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(5.0, self.evaluate(mirrored_var)) @@ -1007,7 +1012,7 @@ class MirroredVariableUpdateTest(test.TestCase): return mirrored_var.assign_sub(value) self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) self.assertEqual(4.5, self.evaluate(mirrored_var)) def testAssignSubMirroredVarReplicaContextWithSingleValue(self, distribution): @@ -1016,7 +1021,7 @@ class MirroredVariableUpdateTest(test.TestCase): 5.0, name="foo", aggregation=variable_scope.VariableAggregation.MEAN) with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.evaluate(variables.global_variables_initializer()) self.assertEqual(5.0, self.evaluate(mirrored_var)) @@ -1025,7 +1030,7 @@ class MirroredVariableUpdateTest(test.TestCase): return mirrored_var.assign_sub(1.0) self.evaluate(distribution.unwrap( - distribution.call_for_each_replica(model_fn))) + distribution.extended.call_for_each_replica(model_fn))) self.assertEqual(4.0, self.evaluate(mirrored_var)) @@ -1045,7 +1050,7 @@ class MirroredAndReplicaLocalVariableInitializerTest(test.TestCase): return v with distribution.scope(): - mirrored_var = distribution.call_for_each_replica(var_fn) + mirrored_var = distribution.extended.call_for_each_replica(var_fn) self.assertIsInstance(mirrored_var, values.MirroredVariable) self.assertFalse(self.evaluate(mirrored_var.is_initialized())) self.evaluate(mirrored_var.initializer) @@ -1064,7 +1069,8 @@ class MirroredAndReplicaLocalVariableInitializerTest(test.TestCase): return v_sum with distribution.scope(): - replica_local_var = distribution.call_for_each_replica(model_fn) + replica_local_var = distribution.extended.call_for_each_replica( + model_fn) self.assertTrue(isinstance(replica_local_var, values.ReplicaLocalVariable)) self.assertFalse(self.evaluate(replica_local_var.is_initialized())) @@ -1088,7 +1094,7 @@ class ReplicaLocalVariableAssignTest(test.TestCase): return v_sum with distribution.scope(): - replica_local_var = distribution.call_for_each_replica(model_fn) + replica_local_var = distribution.extended.call_for_each_replica(model_fn) self.assertTrue(isinstance(replica_local_var, values.ReplicaLocalVariable)) self.evaluate(variables.global_variables_initializer()) @@ -1116,7 +1122,7 @@ class ReplicaLocalVariableAssignTest(test.TestCase): return v_sum with distribution.scope(): - replica_local_var = distribution.call_for_each_replica(model_fn) + replica_local_var = distribution.extended.call_for_each_replica(model_fn) self.assertTrue(isinstance(replica_local_var, values.ReplicaLocalVariable)) self.evaluate(variables.global_variables_initializer()) @@ -1181,7 +1187,7 @@ class MirroredStrategyDefunTest(test.TestCase): mock_model = MockModel(two_variables) self.evaluate(variables.global_variables_initializer()) - result = distribution.call_for_each_replica( + result = distribution.extended.call_for_each_replica( model_fn, args=[mock_model] + inputs) for device in devices: device_result = values.select_device(device, result) @@ -1194,8 +1200,9 @@ class MirroredStrategyDefunTest(test.TestCase): # call_for_each has one trace per device. To check that the expected set # of variables was accessed on each trace, we first retrieve each # device-specific graph function. - per_replica_graph_functions = distribution.call_for_each_replica( - defun.get_concrete_function, args=[mock_model] + inputs) + per_replica_graph_functions = ( + distribution.extended.call_for_each_replica( + defun.get_concrete_function, args=[mock_model] + inputs)) for device in devices: graph_function = per_replica_graph_functions.get(device=device) self.assertEqual(set(mock_model.variables), @@ -1281,7 +1288,7 @@ class MirroredStrategyDefunTest(test.TestCase): gradients_fn = backprop.implicit_grad(loss_fn) gradients_fn = optimizer_lib.get_filtered_grad_fn(gradients_fn) - grads_and_vars = distribution.call_for_each_replica( + grads_and_vars = distribution.extended.call_for_each_replica( gradients_fn, args=(None,)) optimizer = gradient_descent.GradientDescentOptimizer(0.25) @@ -1361,7 +1368,7 @@ class MultiWorkerMirroredStrategyTest( expected_input_pipeline_id=None) iterator = distribution.make_input_fn_iterator(input_fn) self._test_input_fn_iterator( - iterator, distribution.worker_devices, expected_values, sess) + iterator, distribution.extended.worker_devices, expected_values, sess) class MultiWorkerMirroredStrategyTestWithChief( diff --git a/tensorflow/contrib/distribute/python/one_device_strategy.py b/tensorflow/contrib/distribute/python/one_device_strategy.py index 2f6d38547c..f881c234ac 100644 --- a/tensorflow/contrib/distribute/python/one_device_strategy.py +++ b/tensorflow/contrib/distribute/python/one_device_strategy.py @@ -204,10 +204,6 @@ class _OneDeviceReplicaContext(distribute_lib.ReplicaContext): distribution_strategy, replica_id_in_sync_group=constant_op.constant(0, dtypes.int32)) - @property - def device(self): - raise RuntimeError("Use .devices instead") - @property def devices(self): - return [self._distribution_strategy.worker_devices[0]] + return [self._distribution_strategy.extended.worker_devices[0]] diff --git a/tensorflow/contrib/distribute/python/one_device_strategy_test.py b/tensorflow/contrib/distribute/python/one_device_strategy_test.py index b0a2ba3415..d46cd6f529 100644 --- a/tensorflow/contrib/distribute/python/one_device_strategy_test.py +++ b/tensorflow/contrib/distribute/python/one_device_strategy_test.py @@ -55,7 +55,7 @@ class OneDeviceStrategyTest(strategy_test_lib.DistributionTestBase): expected_input_pipeline_id=0) iterator = d.make_input_fn_iterator(input_fn) self._test_input_fn_iterator( - iterator, d.worker_devices, expected_values) + iterator, d.extended.worker_devices, expected_values) if __name__ == "__main__": diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py index b4c098aa57..1ada6a6ba4 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py @@ -522,7 +522,7 @@ class ParameterServerStrategyTestBase( expected_values): distribution, master_target, config = self._get_test_objects( task_type, task_id, num_gpus) - devices = distribution.worker_devices + devices = distribution.extended.worker_devices with ops.Graph().as_default(), \ self.cached_session(config=config, @@ -698,9 +698,9 @@ class ParameterServerStrategyWithChiefTest(ParameterServerStrategyTestBase, v = variable_scope.get_variable('v', initializer=10.0) _ = v * v v, = tape.watched_variables() - w = distribution.value_container(v) + w = distribution.extended.value_container(v) self.assertIs(values.AggregatingVariable, type(w)) - distribution.call_for_each_replica(f) + distribution.extended.call_for_each_replica(f) if __name__ == '__main__': diff --git a/tensorflow/contrib/distribute/python/strategy_test_lib.py b/tensorflow/contrib/distribute/python/strategy_test_lib.py index de0abc6f04..5a8e8ed0dd 100644 --- a/tensorflow/contrib/distribute/python/strategy_test_lib.py +++ b/tensorflow/contrib/distribute/python/strategy_test_lib.py @@ -191,17 +191,18 @@ class DistributionTestBase(test.TestCase): def _test_replica_id(self, d): with d.scope(): - expected_devices = [False] * len(d.worker_devices) + expected_devices = [False] * len(d.extended.worker_devices) def mark_devices_fn(): replica_id = self.evaluate( ds_context.get_replica_context().replica_id_in_sync_group) - self.assertLess(replica_id, len(d.worker_devices)) + self.assertLess(replica_id, len(d.extended.worker_devices)) self.assertFalse(expected_devices[replica_id]) expected_devices[replica_id] = True d.call_for_each_replica(mark_devices_fn) - self.assertAllEqual(expected_devices, [True] * len(d.worker_devices)) + self.assertAllEqual(expected_devices, + [True] * len(d.extended.worker_devices)) def _test_call_and_merge_exceptions(self, dist): with dist.scope(): diff --git a/tensorflow/contrib/distribute/python/tpu_strategy.py b/tensorflow/contrib/distribute/python/tpu_strategy.py index 314dcc5e01..478e3accd7 100644 --- a/tensorflow/contrib/distribute/python/tpu_strategy.py +++ b/tensorflow/contrib/distribute/python/tpu_strategy.py @@ -556,13 +556,9 @@ class _TPUReplicaContext(distribute_lib.ReplicaContext): # TODO(b/118385803): properly initialize replica_id, instead of always 0 replica_id_in_sync_group=constant_op.constant(0, dtypes.int32)) - @property - def device(self): - raise RuntimeError("Use .devices instead") - @property def devices(self): distribute_lib.require_replica_context(self) ds = self._distribution_strategy replica_id = tensor_util.constant_value(self._replica_id_in_sync_group) - return [ds.worker_devices[replica_id]] + return [ds.extended.worker_devices[replica_id]] diff --git a/tensorflow/contrib/optimizer_v2/optimizer_v2.py b/tensorflow/contrib/optimizer_v2/optimizer_v2.py index d6dedc2774..a72db5e12f 100644 --- a/tensorflow/contrib/optimizer_v2/optimizer_v2.py +++ b/tensorflow/contrib/optimizer_v2/optimizer_v2.py @@ -447,7 +447,7 @@ class _OptimizerV2State(object): if v is None: if colocate_with is None: colocate_with = self._non_slot_devices - with self._distribution.colocate_vars_with(colocate_with): + with self._distribution.extended.colocate_vars_with(colocate_with): # TODO(josh11b): Use get_variable() except for the legacy Adam use case. v = variable_scope.variable(initial_value, name=name, trainable=False) self._non_slot_dict[name] = v @@ -928,7 +928,7 @@ class OptimizerV2(optimizer_v1.Optimizer): def _distributed_apply(self, distribution, grads_and_vars, global_step, name): """`apply_gradients` for use with a `DistributionStrategy`.""" - reduced_grads = distribution.batch_reduce( + reduced_grads = distribution.extended.batch_reduce_to( ds_reduce_util.ReduceOp.SUM, grads_and_vars) var_list = [v for _, v in grads_and_vars] grads_and_vars = zip(reduced_grads, var_list) @@ -945,7 +945,7 @@ class OptimizerV2(optimizer_v1.Optimizer): with ops.name_scope(name, self._name) as name: per_graph_state = self._get_or_create_state(var_list=unwrapped_var_list) # Include the current value of any dynamic hyper parameters in `state`. - non_slot_devices = distribution.non_slot_devices(var_list) + non_slot_devices = distribution.extended.non_slot_devices(var_list) state = per_graph_state._copy_with_dynamic_hyper( # pylint: disable=protected-access self._hyper, distribution, non_slot_devices) @@ -990,7 +990,8 @@ class OptimizerV2(optimizer_v1.Optimizer): # Use the processors to update the variables. update_ops = [] for grad, var in grads_and_vars: - update_ops.extend(distribution.update(var, update, grad, grouped=False)) + update_ops.extend(distribution.extended.update( + var, update, args=(grad,), group=False)) # Give the child class a chance to do something after applying # gradients @@ -1002,8 +1003,8 @@ class OptimizerV2(optimizer_v1.Optimizer): update_ops = control_flow_ops.group(update_ops) with ops.control_dependencies([update_ops]): - finish_updates = distribution.update_non_slot( - non_slot_devices, finish, grouped=False) + finish_updates = distribution.extended.update_non_slot( + non_slot_devices, finish, group=False) # We said grouped=False, which means finish_updates is always a list. # It will be [None] when finish() returns None. if finish_updates == [None]: @@ -1018,8 +1019,8 @@ class OptimizerV2(optimizer_v1.Optimizer): def update_global_step(global_step, name): return global_step.assign_add(1, read_value=False, name=name) - apply_updates = distribution.update(global_step, update_global_step, - name) + apply_updates = distribution.extended.update( + global_step, update_global_step, args=(name,)) # Add the training op to the TRAIN_OP graph collection in graph mode. if not eager_execution: diff --git a/tensorflow/python/distribute/distribute_coordinator.py b/tensorflow/python/distribute/distribute_coordinator.py index 07d291e037..c0f9b8a1fd 100644 --- a/tensorflow/python/distribute/distribute_coordinator.py +++ b/tensorflow/python/distribute/distribute_coordinator.py @@ -245,7 +245,7 @@ class _WorkerContext(object): else: session_config = self._session_config - if not self._strategy or self._strategy.should_init: + if not self._strategy or self._strategy.extended.experimental_should_init: logging.info("Creating chief session creator with config: %r", config) return monitored_session.ChiefSessionCreator( scaffold, @@ -306,19 +306,19 @@ class _WorkerContext(object): return self._num_workers @property - def should_init(self): + def experimental_should_init(self): """Whether to run init ops.""" - return self._strategy.should_init + return self._strategy.extended.experimental_should_init @property def should_checkpoint(self): """Whether to save checkpoint.""" - return self._strategy.should_checkpoint + return self._strategy.extended.should_checkpoint @property def should_save_summary(self): """Whether to save summaries.""" - return self._strategy.should_save_summary + return self._strategy.extended.should_save_summary def _run_single_worker(worker_fn, @@ -632,10 +632,10 @@ def run_distribute_coordinator(worker_fn, The `strategy` object is expected to be a DistributionStrategy object which has implemented methods needed by distributed coordinator such as `configure(session_config, cluster_spec, task_type, task_id)` which configures - the strategy object for a specific task and `should_init` property which - instructs the distribute coordinator whether to run init ops for a task. The - distribute coordinator will make a copy of the `strategy` object, call its - `configure` method and pass it to `worker_fn` as an argument. + the strategy object for a specific task and `experimental_should_init` + property which instructs the distribute coordinator whether to run init ops + for a task. The distribute coordinator will make a copy of the `strategy` + object, call its `configure` method and pass it to `worker_fn` as an argument. The `worker_fn` defines the training logic and is called under a its own worker context which can be accessed to via `get_current_worker_context`. A @@ -758,7 +758,7 @@ def run_distribute_coordinator(worker_fn, # The client must know the cluster but servers in the cluster don't have to # know the client. if task_type in [_TaskType.CLIENT, None]: - if strategy.between_graph: + if strategy.extended.experimental_between_graph: return _run_between_graph_client(worker_fn, strategy, eval_fn, eval_strategy, cluster_spec, session_config, rpc_layer) @@ -804,7 +804,7 @@ def run_distribute_coordinator(worker_fn, environment=environment) if task_type in [_TaskType.CHIEF, _TaskType.WORKER]: - if strategy.between_graph: + if strategy.extended.experimental_between_graph: # All jobs run `worker_fn` if between-graph. _run_single_worker(worker_fn, strategy, cluster_spec, task_type, task_id, session_config, rpc_layer) diff --git a/tensorflow/python/distribute/distribute_coordinator_test.py b/tensorflow/python/distribute/distribute_coordinator_test.py index 0c1ee8c87e..f2cb950aad 100644 --- a/tensorflow/python/distribute/distribute_coordinator_test.py +++ b/tensorflow/python/distribute/distribute_coordinator_test.py @@ -79,46 +79,53 @@ def _strip_protocol(target): return target -class MockStrategy(object): +class MockExtended(object): def __init__(self, between_graph=False, should_init=None, should_checkpoint=None, should_save_summary=None): - self._between_graph = between_graph - self._should_init = should_init - self._should_checkpoint = should_checkpoint - self._should_save_summary = should_save_summary + self.experimental_between_graph = between_graph + self.experimental_should_init = should_init + self.should_checkpoint = should_checkpoint + self.should_save_summary = should_save_summary - @property - def between_graph(self): - return self._between_graph + +class MockStrategy(object): + + def __init__(self, + between_graph=False, + should_init=None, + should_checkpoint=None, + should_save_summary=None): + self.extended = MockExtended(between_graph, should_init, should_checkpoint, + should_save_summary) def configure(self, session_config=None, cluster_spec=None, task_type=None, task_id=None): - if self._should_init is None: + if self.extended.experimental_should_init is None: if task_id == 0: - self._should_init = True + self.extended.experimental_should_init = True else: - self._should_init = False - if self._should_checkpoint is None: + self.extended.experimental_should_init = False + if self.extended.should_checkpoint is None: if task_id == 0: - self._should_checkpoint = True + self.extended.should_checkpoint = True else: - self._should_checkpoint = False - if self._should_save_summary is None: + self.extended.should_checkpoint = False + if self.extended.should_save_summary is None: if task_id == 0: - self._should_save_summary = True + self.extended.should_save_summary = True else: - self._should_save_summary = False + self.extended.should_save_summary = False if session_config: if (cluster_spec and task_type and task_id is not None and - self._between_graph): + self.extended.experimental_between_graph): session_config.intra_op_parallelism_threads += 1 if task_type in ["chief", "worker"]: session_config.device_filters.extend( @@ -127,18 +134,6 @@ class MockStrategy(object): session_config.inter_op_parallelism_threads += 1 session_config.device_filters.append("/job:somejob") - @property - def should_init(self): - return self._should_init - - @property - def should_checkpoint(self): - return self._should_checkpoint - - @property - def should_save_summary(self): - return self._should_save_summary - class MockServer(object): @@ -373,9 +368,12 @@ class DistributeCoordinatorTestBase(test.TestCase): context = distribute_coordinator_context.get_current_worker_context() self.assertTrue(context is not None) - self.assertEqual(context._strategy.should_init, strategy.should_init) - self.assertEqual(context.should_checkpoint, strategy.should_checkpoint) - self.assertEqual(context.should_save_summary, strategy.should_save_summary) + self.assertEqual(context._strategy.extended.experimental_should_init, + strategy.extended.experimental_should_init) + self.assertEqual(context.should_checkpoint, + strategy.extended.should_checkpoint) + self.assertEqual(context.should_save_summary, + strategy.extended.should_save_summary) task_type = str(context.task_type) task_id = context.task_id or 0 @@ -385,7 +383,8 @@ class DistributeCoordinatorTestBase(test.TestCase): while len(self._strategy_property[task_type]) <= task_id: self._strategy_property[task_type].append(None) self._strategy_property[task_type][task_id] = ( - context._strategy.should_init, context.should_checkpoint, + context._strategy.extended.experimental_should_init, + context.should_checkpoint, context.should_save_summary) def _run_mock_std_server(self, diff --git a/tensorflow/python/distribute/estimator_training.py b/tensorflow/python/distribute/estimator_training.py index 227b00fb3e..549fa8fb8a 100644 --- a/tensorflow/python/distribute/estimator_training.py +++ b/tensorflow/python/distribute/estimator_training.py @@ -308,7 +308,7 @@ def estimator_train(estimator, train_distributed_fn, hooks): raise ValueError('Only `STANDALONE_CLIENT` mode is supported when you call ' '`estimator.train`') - if estimator._config._train_distribute.between_graph: + if estimator._config._train_distribute.extended.experimental_between_graph: # TODO(yuefengz): remove this limitation once we figure out how to merge # return values from `_worker_fn`s. raise ValueError('`Estimator.train` API is not supported for %s with ' @@ -356,7 +356,7 @@ def estimator_evaluate(estimator, evaluate_distributed_fn, hooks): raise ValueError('Only `STANDALONE_CLIENT` mode is supported when you call ' '`Estimator.train`') - if estimator._config._eval_distribute.between_graph: + if estimator._config._eval_distribute.extended.experimental_between_graph: # TODO(yuefengz): remove this limitation once we figure out how to merge # return values from `_worker_fn`s. raise ValueError('`Estimator.evaluate` API is not supported for %s with ' diff --git a/tensorflow/python/distribute/values.py b/tensorflow/python/distribute/values.py index 33ca27c63b..5f69323bff 100644 --- a/tensorflow/python/distribute/values.py +++ b/tensorflow/python/distribute/values.py @@ -1608,11 +1608,11 @@ class MultiStepContext(object): """A context object that can be used to capture things when running steps. This context object is useful when running multiple steps at a time using the - `run_steps_on_dataset` API. For e.g. it allows the user's step function to - specify which outputs to emit at what frequency. Currently it supports - capturing output from the last step, as well as capturing non tensor outputs. - In the future it will be augmented to support other use cases such as output - each N steps. + `experimental_run_steps_on_iterator` API. For e.g. it allows the user's step + function to specify which outputs to emit at what frequency. Currently it + supports capturing output from the last step, as well as capturing non tensor + outputs. In the future it will be augmented to support other use cases such + as output each N steps. """ def __init__(self): diff --git a/tensorflow/python/eager/tape.py b/tensorflow/python/eager/tape.py index 1326f09713..e501b403a3 100644 --- a/tensorflow/python/eager/tape.py +++ b/tensorflow/python/eager/tape.py @@ -63,7 +63,7 @@ def watch_variable(tape, variable): """Marks this variable to be watched by the given tape.""" strategy = distribution_strategy_context.get_distribution_strategy() if distribution_strategy_context.get_replica_context(): - variables = [strategy.value_container(variable)] + variables = [strategy.extended.value_container(variable)] else: variables = strategy.unwrap(variable) for var in variables: @@ -78,7 +78,7 @@ def variable_accessed(variable): """ strategy = distribution_strategy_context.get_distribution_strategy() if distribution_strategy_context.get_replica_context(): - variables = [strategy.value_container(variable)] + variables = [strategy.extended.value_container(variable)] else: variables = strategy.unwrap(variable) for var in variables: diff --git a/tensorflow/python/keras/engine/training_distributed.py b/tensorflow/python/keras/engine/training_distributed.py index 878451d4cf..53261fdd26 100644 --- a/tensorflow/python/keras/engine/training_distributed.py +++ b/tensorflow/python/keras/engine/training_distributed.py @@ -109,7 +109,7 @@ def experimental_fit_loop(model, mode=_Mode.TRAIN) (grouped_inputs, grouped_outputs, grouped_updates, - grouped_session_args) = current_strategy.call_for_each_replica( + grouped_session_args) = current_strategy.extended.call_for_each_replica( _per_device_fit_function, args=(model._grouped_model_train,)) (all_inputs, all_outputs, all_updates, all_session_args) = distributed_training_utils.unwrap_values( @@ -152,7 +152,7 @@ def experimental_fit_loop(model, name='steps_per_run') with current_strategy.scope(): - ctx = current_strategy.run_steps_on_dataset( + ctx = current_strategy.extended.experimental_run_steps_on_iterator( step_fn, iterator, iterations=steps_per_run, initial_loop_values=initial_loop_values) @@ -300,7 +300,7 @@ def experimental_test_loop(model, mode=_Mode.TEST) (grouped_inputs, grouped_outputs, grouped_updates, - grouped_session_args) = current_strategy.call_for_each_replica( + grouped_session_args) = current_strategy.extended.call_for_each_replica( _per_device_eval_function, args=(model._grouped_model_test,)) (all_inputs, all_outputs, all_updates, @@ -335,7 +335,7 @@ def experimental_test_loop(model, with current_strategy.scope(): # TODO(priyag): Use steps_per_run when we use new metrics as they will # allow handling metric computation at each step using variables. - ctx = current_strategy.run_steps_on_dataset( + ctx = current_strategy.extended.experimental_run_steps_on_iterator( step_fn, iterator, iterations=1, initial_loop_values=initial_loop_values) @@ -414,7 +414,7 @@ def experimental_predict_loop(model, iterator, verbose=0, steps=None): mode=_Mode.PREDICT) (grouped_inputs, grouped_outputs, grouped_updates, - grouped_session_args) = current_strategy.call_for_each_replica( + grouped_session_args) = current_strategy.extended.call_for_each_replica( _per_device_predict_function, args=(model._grouped_model_predict,)) (all_inputs, all_outputs, all_updates, @@ -445,7 +445,7 @@ def experimental_predict_loop(model, iterator, verbose=0, steps=None): with current_strategy.scope(): # TODO(priyag, sourabhbajaj): Support steps_per_run if/when we add outfeed. - ctx = current_strategy.run_steps_on_dataset( + ctx = current_strategy.extended.experimental_run_steps_on_iterator( step_fn, iterator, iterations=1, initial_loop_values=initial_loop_values) @@ -528,7 +528,7 @@ def clone_model_on_replicas(model, strategy, make_callback_model=False, inputs=None, targets=None, mode=None): """Create a cloned model on each replica.""" with strategy.scope(): - grouped_model = strategy.call_for_each_replica( + grouped_model = strategy.extended.call_for_each_replica( _clone_and_build_model, args=(model, inputs, targets)) if mode is _Mode.TRAIN: model._grouped_model_train = grouped_model @@ -583,7 +583,7 @@ def _get_execution_function(model, mode): # Create train ops on each of the devices when we call # `_per_device_fit_function`. (grouped_inputs, grouped_outputs, grouped_updates, - grouped_session_args) = strategy.call_for_each_replica( + grouped_session_args) = strategy.extended.call_for_each_replica( _per_device_function, args=(model._grouped_model,)) if mode == 'train': diff --git a/tensorflow/python/training/distribute_test.py b/tensorflow/python/training/distribute_test.py index ad4d50c548..4758e3d3d4 100644 --- a/tensorflow/python/training/distribute_test.py +++ b/tensorflow/python/training/distribute_test.py @@ -92,9 +92,9 @@ class TestStrategyTest(test.TestCase): variable_scope.variable(1.0, name="bar")) with self.assertRaises(RuntimeError): - dist.call_for_each_replica(run_fn) + dist.extended.call_for_each_replica(run_fn) with dist.scope(): - dist.call_for_each_replica(run_fn) + dist.extended.call_for_each_replica(run_fn) _assert_in_default_state(self) def testScope(self): diff --git a/tensorflow/python/training/monitored_session_test.py b/tensorflow/python/training/monitored_session_test.py index ebe2f15a55..2ceb387ec3 100644 --- a/tensorflow/python/training/monitored_session_test.py +++ b/tensorflow/python/training/monitored_session_test.py @@ -382,6 +382,16 @@ class MonitoredTrainingSessionTest(test.TestCase): self.assertEqual(0, session.run(gstep)) +class MockExtended(object): + + def __init__(self, between_graph, should_init, should_checkpoint, + should_save_summary): + self.experimental_between_graph = between_graph + self.experimental_should_init = should_init + self.should_checkpoint = should_checkpoint + self.should_save_summary = should_save_summary + + class MockStrategy(object): def __init__(self, @@ -389,26 +399,8 @@ class MockStrategy(object): should_init=True, should_checkpoint=None, should_save_summary=None): - self._between_graph = between_graph - self._should_init = should_init - self._should_checkpoint = should_checkpoint - self._should_save_summary = should_save_summary - - @property - def between_graph(self): - return self._between_graph - - @property - def should_init(self): - return self._should_init - - @property - def should_checkpoint(self): - return self._should_checkpoint - - @property - def should_save_summary(self): - return self._should_save_summary + self.extended = MockExtended(between_graph, should_init, should_checkpoint, + should_save_summary) class MonitoredTrainingSessionWithDistributeCoordinatorTest(test.TestCase): diff --git a/tensorflow/python/training/optimizer.py b/tensorflow/python/training/optimizer.py index 6fca4ca7d4..8cd5311b31 100644 --- a/tensorflow/python/training/optimizer.py +++ b/tensorflow/python/training/optimizer.py @@ -660,7 +660,7 @@ class Optimizer( replicas. If `global_step` was not None, that operation also increments `global_step` """ - reduced_grads = distribution.batch_reduce( + reduced_grads = distribution.extended.batch_reduce_to( ds_reduce_util.ReduceOp.SUM, grads_and_vars) var_list = [v for _, v in grads_and_vars] grads_and_vars = zip(reduced_grads, var_list) @@ -695,21 +695,23 @@ class Optimizer( update_ops = [ op for grad, var in grads_and_vars - for op in distribution.update(var, update, grad, grouped=False) + for op in distribution.extended.update( + var, update, args=(grad,), group=False) ] def finish(self, update_ops): return self._finish(update_ops, "update") - non_slot_devices = distribution.non_slot_devices(var_list) - finish_updates = distribution.update_non_slot( - non_slot_devices, finish, self, update_ops, grouped=False) + non_slot_devices = distribution.extended.non_slot_devices(var_list) + finish_updates = distribution.extended.update_non_slot( + non_slot_devices, finish, args=(self, update_ops), group=False) if global_step is None: apply_updates = distribution.group(finish_updates, name=name) else: with ops.control_dependencies(finish_updates): - apply_updates = distribution.update( - global_step, state_ops.assign_add, 1, name=name) + apply_updates = distribution.extended.update( + global_step, state_ops.assign_add, args=(1,), + kwargs={"name": name}) if not context.executing_eagerly(): if isinstance(apply_updates, ops.Tensor): -- GitLab From a8ae0f47e56d778b69278f7eef971c3b6b605bf9 Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Tue, 20 Nov 2018 11:52:19 -0800 Subject: [PATCH 135/672] Minor error message improvement for incompatible type conversion. PiperOrigin-RevId: 222282332 --- tensorflow/python/eager/pywrap_tensor.cc | 4 ++-- tensorflow/python/eager/pywrap_tfe_src.cc | 6 ++++-- tensorflow/python/eager/tensor_test.py | 8 ++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/eager/pywrap_tensor.cc b/tensorflow/python/eager/pywrap_tensor.cc index 55f0896e3b..ed19047f09 100644 --- a/tensorflow/python/eager/pywrap_tensor.cc +++ b/tensorflow/python/eager/pywrap_tensor.cc @@ -439,8 +439,8 @@ int EagerTensor_init(EagerTensor* self, PyObject* args, PyObject* kwds) { PyErr_SetString( PyExc_TypeError, tensorflow::strings::StrCat( - "Cannot convert value ", TFE_GetPythonString(value_str.get()), - " to EagerTensor with requested dtype: ", + "Cannot convert provided value to EagerTensor. Provided value: ", + TFE_GetPythonString(value_str.get()), " Requested dtype: ", tensorflow::DataTypeString( static_cast(desired_dtype))) .c_str()); diff --git a/tensorflow/python/eager/pywrap_tfe_src.cc b/tensorflow/python/eager/pywrap_tfe_src.cc index f074b73a9f..9ce500bc08 100644 --- a/tensorflow/python/eager/pywrap_tfe_src.cc +++ b/tensorflow/python/eager/pywrap_tfe_src.cc @@ -2303,8 +2303,10 @@ bool ConvertToTensor( PyErr_SetString( PyExc_TypeError, tensorflow::strings::StrCat( - "Cannot convert value ", TFE_GetPythonString(input_str.get()), - " to EagerTensor with requested dtype: ", desired_dtype) + "Cannot convert provided value to EagerTensor. Provided value: ", + TFE_GetPythonString(input_str.get()), " Requested dtype: ", + tensorflow::DataTypeString( + static_cast(desired_dtype))) .c_str()); return false; } diff --git a/tensorflow/python/eager/tensor_test.py b/tensorflow/python/eager/tensor_test.py index d0500a413d..8c9d5dabe7 100644 --- a/tensorflow/python/eager/tensor_test.py +++ b/tensorflow/python/eager/tensor_test.py @@ -323,6 +323,14 @@ class TFETensorTest(test_util.TensorFlowTestCase): def testConvertToTensorAllowsOverflow(self): _ = ops.convert_to_tensor(123456789, dtype=dtypes.uint8) + def testEagerTensorError(self): + with self.assertRaisesRegexp( + TypeError, + "Cannot convert provided value to EagerTensor. " + "Provided value.*Requested dtype.*"): + _ = ops.convert_to_tensor(1., dtype=dtypes.int32) + + class TFETensorUtilTest(test_util.TensorFlowTestCase): -- GitLab From 2cbeb0cb762d31e69d4dd1adba9008c27441a1e5 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 20 Nov 2018 11:59:09 -0800 Subject: [PATCH 136/672] Enable iota in HLO evaluator for all integral and floating point types. PiperOrigin-RevId: 222283442 --- .../xla/service/hlo_evaluator_typed_visitor.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h b/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h index 332fa874c3..f975ba63bb 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h +++ b/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h @@ -2543,12 +2543,14 @@ class HloEvaluatorTypedVisitor : public DfsHloVisitorWithDefault { template ::value || - std::is_same::value || - std::is_same::value>::type* = nullptr> + std::is_integral::value || + std::is_floating_point::value>::type* = nullptr> Status HandleIota(HloInstruction* instruction) { auto* iota = Cast(instruction); - std::vector data(iota->shape().dimensions(iota->iota_dimension())); + // Avoid using std::vector since std::vector does not convert to + // absl::Span. + absl::InlinedVector data( + iota->shape().dimensions(iota->iota_dimension())); std::iota(data.begin(), data.end(), 0); auto result = LiteralUtil::CreateR1(data); @@ -2565,9 +2567,8 @@ class HloEvaluatorTypedVisitor : public DfsHloVisitorWithDefault { } template ::value || - std::is_same::value || - std::is_same::value)>::type* = nullptr> + !(std::is_integral::value || + std::is_floating_point::value)>::type* = nullptr> Status HandleIota(HloInstruction* iota) { return InvalidArgument("Unsupported type for iota"); } -- GitLab From 7aeef997590ef434a71db1546eec173ff29640ea Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 20 Nov 2018 11:59:30 -0800 Subject: [PATCH 137/672] Fix profiler after subgraph refactor and remove commented tensors_. PiperOrigin-RevId: 222283502 --- tensorflow/lite/core/subgraph.h | 8 ++++++++ tensorflow/lite/interpreter.cc | 8 ++++++++ tensorflow/lite/interpreter.h | 13 ++----------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/tensorflow/lite/core/subgraph.h b/tensorflow/lite/core/subgraph.h index 9783747ff6..120c307ef2 100644 --- a/tensorflow/lite/core/subgraph.h +++ b/tensorflow/lite/core/subgraph.h @@ -21,6 +21,7 @@ limitations under the License. #include "tensorflow/lite/allocation.h" #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/memory_planner.h" +#include "tensorflow/lite/profiling/profiler.h" #include "tensorflow/lite/util.h" namespace tflite { @@ -242,6 +243,10 @@ class Subgraph { // WARNING: This is an experimental API and subject to change. TfLiteStatus ResetVariableTensors(); + void SetProfiler(profiling::Profiler* profiler) { profiler_ = profiler; } + + profiling::Profiler* GetProfiler() { return profiler_; } + private: // Prevent 'context_' from accessing functions that are only available to // delegated kernels. @@ -470,6 +475,9 @@ class Subgraph { // External contexts (kTfLiteMaxExternalContexts). TfLiteExternalContext** external_contexts_; + + // Profiler for this interpreter instance. + profiling::Profiler* profiler_ = nullptr; }; } // namespace tflite diff --git a/tensorflow/lite/interpreter.cc b/tensorflow/lite/interpreter.cc index 4f4a999210..078c2306c4 100644 --- a/tensorflow/lite/interpreter.cc +++ b/tensorflow/lite/interpreter.cc @@ -190,4 +190,12 @@ TfLiteStatus Interpreter::GetBufferHandle(int tensor_index, return kTfLiteOk; } +void Interpreter::SetProfiler(profiling::Profiler* profiler) { + for (auto& subgraph : subgraphs_) subgraph.SetProfiler(profiler); +} + +profiling::Profiler* Interpreter::GetProfiler() { + return primary_subgraph().GetProfiler(); +} + } // namespace tflite diff --git a/tensorflow/lite/interpreter.h b/tensorflow/lite/interpreter.h index d89affff45..7da4a2cbfa 100644 --- a/tensorflow/lite/interpreter.h +++ b/tensorflow/lite/interpreter.h @@ -380,9 +380,9 @@ class Interpreter { TfLiteBufferHandle* buffer_handle, TfLiteDelegate** delegate); - void SetProfiler(profiling::Profiler* profiler) { profiler_ = profiler; } + void SetProfiler(profiling::Profiler* profiler); - profiling::Profiler* GetProfiler() { return profiler_; } + profiling::Profiler* GetProfiler(); // The default capacity of `tensors_` vector. static constexpr int kTensorsReservedCapacity = 128; @@ -434,12 +434,6 @@ class Interpreter { return subgraphs_.front(); // Safe as subgraphs_ always has 1 entry. } - // Tensors needed by the interpreter. Use `AddTensors` to add more blank - // tensor entries. Note, `tensors_.data()` needs to be synchronized to the - // `context_` whenever this std::vector is reallocated. Currently this - // only happens in `AddTensors()`. - // std::vector tensors_; - // Set the value of an external context. static void SetExternalContext(struct TfLiteContext* context, TfLiteExternalContextType type, @@ -472,9 +466,6 @@ class Interpreter { bool allow_buffer_handle_output_ = false; - // Profiler for this interpreter instance. - profiling::Profiler* profiler_ = nullptr; - // List of active external contexts. TfLiteExternalContext* external_contexts_[kTfLiteMaxExternalContexts]; -- GitLab From 9947625c3f1c3d43f12125b7af1cdbdd8bea7ff2 Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Tue, 20 Nov 2018 12:00:43 -0800 Subject: [PATCH 138/672] Add new method to expose all the function names in the registry. Also refactor the ReachableFunctions so that it does not rely on the ToProto() method for all the functionDefs. PiperOrigin-RevId: 222283700 --- tensorflow/core/framework/function.cc | 20 +++++++++++++++----- tensorflow/core/framework/function.h | 3 +++ tensorflow/core/framework/function_test.cc | 11 +++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/tensorflow/core/framework/function.cc b/tensorflow/core/framework/function.cc index 838f899911..6809c27197 100644 --- a/tensorflow/core/framework/function.cc +++ b/tensorflow/core/framework/function.cc @@ -1241,6 +1241,16 @@ const FunctionDef* FunctionLibraryDefinition::GetAttrImpl( } } +std::vector FunctionLibraryDefinition::ListFunctionNames() const { + std::vector function_names; + tf_shared_lock l(mu_); + function_names.reserve(function_defs_.size()); + for (const auto& it : function_defs_) { + function_names.emplace_back(it.first); + } + return function_names; +} + FunctionDefLibrary FunctionLibraryDefinition::ToProto() const { FunctionDefLibrary lib; tf_shared_lock l(mu_); @@ -1357,12 +1367,12 @@ absl::flat_hash_set ReachableFunctions( if (!grad_func_name.empty()) add_to_func_queue(grad_func_name); } - const FunctionDefLibrary library_proto = flib.ToProto(); - for (const auto& it : library_proto.function()) { - const auto attr_it = it.attr().find(kExperimentalApiImplements); - if (attr_it != it.attr().end()) { + for (const auto& func_name : flib.ListFunctionNames()) { + const auto& func_def = flib.Find(func_name); + const auto attr_it = func_def->attr().find(kExperimentalApiImplements); + if (attr_it != func_def->attr().end()) { if (reachable_api_interface.contains(attr_it->second.s())) { - reachable_funcs.insert(it.signature().name()); + reachable_funcs.insert(func_name); } } } diff --git a/tensorflow/core/framework/function.h b/tensorflow/core/framework/function.h index 6792cf1653..9cf4b0f4cd 100644 --- a/tensorflow/core/framework/function.h +++ b/tensorflow/core/framework/function.h @@ -407,6 +407,9 @@ class FunctionLibraryDefinition : public OpRegistryInterface { return function_defs_.size(); } + // Returns all the function names in the FunctionLibraryDefinition. + std::vector ListFunctionNames() const LOCKS_EXCLUDED(mu_); + const OpRegistryInterface* default_registry() const { return default_registry_; } diff --git a/tensorflow/core/framework/function_test.cc b/tensorflow/core/framework/function_test.cc index f57a79b167..75d45fa2c8 100644 --- a/tensorflow/core/framework/function_test.cc +++ b/tensorflow/core/framework/function_test.cc @@ -1213,6 +1213,17 @@ TEST(FunctionLibraryDefinitionTest, ToProto) { EXPECT_EQ(f3->DebugString(), f4->DebugString()); } +TEST(FunctionLibraryDefinitionTest, FunctionNames) { + FunctionDefLibrary proto; + *proto.add_function() = test::function::XTimesTwo(); + *proto.add_function() = test::function::WXPlusB(); + const FunctionLibraryDefinition lib_def(OpRegistry::Global(), proto); + + const std::vector function_names = lib_def.ListFunctionNames(); + const std::vector expected = {"XTimesTwo", "WXPlusB"}; + EXPECT_EQ(function_names, expected); +} + TEST(FunctionLibraryDefinitionTest, GetAttr_FuncNoAttr) { FunctionDefLibrary proto; *proto.add_function() = test::function::XTimesTwo(); -- GitLab From 08d0de579e94c78bf5561bf312939e38d78c7d32 Mon Sep 17 00:00:00 2001 From: Dimitris Vardoulakis Date: Tue, 20 Nov 2018 12:31:09 -0800 Subject: [PATCH 139/672] [TF:XLA] Remove no-op return in literal.cc. PiperOrigin-RevId: 222288471 --- tensorflow/compiler/xla/literal.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/compiler/xla/literal.cc b/tensorflow/compiler/xla/literal.cc index fcc59f6d21..36ad7c6486 100644 --- a/tensorflow/compiler/xla/literal.cc +++ b/tensorflow/compiler/xla/literal.cc @@ -1123,7 +1123,6 @@ void DenseArrayToStringHelper(const LiteralBase& literal, } } pieces->push_back(brace_to_string("}")); - return; } }; -- GitLab From 0b0767e77f0e5bdc3a625de56cfed8a57d951e98 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 13:07:36 -0800 Subject: [PATCH 140/672] Automated rollback of commit e510289890c19b4ebab990e101d918b4c37029a7 PiperOrigin-RevId: 222294175 --- tensorflow/lite/toco/import_tensorflow.cc | 5 ++++- tensorflow/lite/toco/import_tensorflow_test.cc | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index c51031b4e5..4c3a0717e7 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -219,7 +219,10 @@ tensorflow::Status ImportShape( // allocation code gets a bit confused. It seems that the code expects an // empty shape for zero-sized shapes, so we will do just that, except for the // [0] case. - if (zero_sized_shape && input_dims_only_sizes.size() > 1) { + // TODO(b/119325030): In order to correctly import the "scalar" shapes the + // following test must include "&& input_dims_only_sizes.size() > 1", but + // that seems to slow everything down a lot. + if (zero_sized_shape) { shape->mutable_dims()->clear(); if (input_flat_size != nullptr) *input_flat_size = 0; return tensorflow::Status::OK(); diff --git a/tensorflow/lite/toco/import_tensorflow_test.cc b/tensorflow/lite/toco/import_tensorflow_test.cc index 07b52d3970..0be358b1f7 100644 --- a/tensorflow/lite/toco/import_tensorflow_test.cc +++ b/tensorflow/lite/toco/import_tensorflow_test.cc @@ -190,7 +190,9 @@ TEST_P(ShapeImportTest, ShapeIsOneDimZero) { EXPECT_TRUE(ImportNode(node, &model).ok()); const auto& array = model.GetArray("Node1"); - EXPECT_THAT(array.shape().dims(), ::testing::ElementsAre(0)); + // We would like to have [0] shapes actually import correctly, but + // for some reason that slows everything down. + EXPECT_THAT(array.shape().dims(), ::testing::ElementsAre()); } TEST_P(ShapeImportTest, ShapeElementTooLarge) { -- GitLab From 5c4efd94603671df138d8df6bf1c9b51b8259270 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 13:19:32 -0800 Subject: [PATCH 141/672] Fix a convolution test's name PiperOrigin-RevId: 222295785 --- tensorflow/compiler/xla/tests/convolution_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/compiler/xla/tests/convolution_test.cc b/tensorflow/compiler/xla/tests/convolution_test.cc index a5e9cfd0cc..b52d30fd66 100644 --- a/tensorflow/compiler/xla/tests/convolution_test.cc +++ b/tensorflow/compiler/xla/tests/convolution_test.cc @@ -1282,7 +1282,7 @@ TYPED_TEST(Convolve2D_1x4x4x1024_3x3x1x1024_Depthwise_Valid, Types) { } template -class Convolve2D_1x2x2x6_2x2x1x12_Grouped_Valid : public ConvolutionTest { +class Convolve2D_1x2x2x6_2x2x2x12_Grouped_Valid : public ConvolutionTest { public: void RunTest() { XlaBuilder builder(TestName()); @@ -1341,8 +1341,8 @@ class Convolve2D_1x2x2x6_2x2x1x12_Grouped_Valid : public ConvolutionTest { } }; -TYPED_TEST_CASE(Convolve2D_1x2x2x6_2x2x1x12_Grouped_Valid, TestTypes); -TYPED_TEST(Convolve2D_1x2x2x6_2x2x1x12_Grouped_Valid, Types) { +TYPED_TEST_CASE(Convolve2D_1x2x2x6_2x2x2x12_Grouped_Valid, TestTypes); +TYPED_TEST(Convolve2D_1x2x2x6_2x2x2x12_Grouped_Valid, Types) { this->RunTest(); } -- GitLab From 760ef2cc7ec0d28b34e4544efb6433315f8fc99d Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 13:34:35 -0800 Subject: [PATCH 142/672] Allow intermediate string tensors PiperOrigin-RevId: 222298206 --- tensorflow/lite/toco/BUILD | 46 ++++++ tensorflow/lite/toco/export_tensorflow.cc | 21 ++- tensorflow/lite/toco/toco.cc | 82 +--------- tensorflow/lite/toco/toco_convert.cc | 108 ++++++++++++++ tensorflow/lite/toco/toco_convert.h | 34 +++++ tensorflow/lite/toco/toco_convert_test.cc | 173 ++++++++++++++++++++++ tensorflow/lite/toco/toco_tooling.cc | 6 +- tensorflow/lite/toco/tooling_util.cc | 8 + 8 files changed, 390 insertions(+), 88 deletions(-) create mode 100644 tensorflow/lite/toco/toco_convert.cc create mode 100644 tensorflow/lite/toco/toco_convert.h create mode 100644 tensorflow/lite/toco/toco_convert_test.cc diff --git a/tensorflow/lite/toco/BUILD b/tensorflow/lite/toco/BUILD index 1430287444..82aa1f557e 100644 --- a/tensorflow/lite/toco/BUILD +++ b/tensorflow/lite/toco/BUILD @@ -395,6 +395,28 @@ tf_cc_test( # :toco is the main public command-line tool exposing the functionality # of the :toco_tooling library. +cc_library( + name = "toco_convert", + srcs = ["toco_convert.cc"], + hdrs = ["toco_convert.h"], + visibility = ["//visibility:public"], + deps = [ + ":model", + ":model_cmdline_flags", + ":model_flags_proto_cc", + ":toco_cmdline_flags", + ":toco_flags_proto_cc", + ":toco_port", + ":toco_tooling", + ":types_proto_cc", + "@com_google_absl//absl/strings", + "//tensorflow/core:lib", + # We cannot embed the core:ops dependency directly into :toco_tooling as + # it can conflict with downstream deps when toco is used as a library. + "//tensorflow/core:ops", + ], +) + tf_cc_binary( name = "toco", srcs = ["toco.cc"], @@ -404,6 +426,7 @@ tf_cc_binary( ":model_cmdline_flags", ":model_flags_proto_cc", ":toco_cmdline_flags", + ":toco_convert", ":toco_flags_proto_cc", ":toco_port", ":toco_tooling", @@ -416,6 +439,29 @@ tf_cc_binary( ], ) +tf_cc_test( + name = "toco_convert_test", + srcs = ["toco_convert_test.cc"], + visibility = ["//visibility:public"], + deps = [ + ":model", + ":model_cmdline_flags", + ":model_flags_proto_cc", + ":toco_cmdline_flags", + ":toco_convert", + ":toco_flags_proto_cc", + ":toco_port", + ":toco_tooling", + ":types_proto_cc", + "@com_google_googletest//:gtest_main", + "@com_google_absl//absl/strings", + "//tensorflow/core:lib", + # We cannot embed the core:ops dependency directly into :toco_tooling as + # it can conflict with downstream deps when toco is used as a library. + "//tensorflow/core:ops", + ], +) + tf_cc_test( name = "toco_port_test", srcs = ["toco_port_test.cc"], diff --git a/tensorflow/lite/toco/export_tensorflow.cc b/tensorflow/lite/toco/export_tensorflow.cc index 1752745aae..bdc3a5b0fb 100644 --- a/tensorflow/lite/toco/export_tensorflow.cc +++ b/tensorflow/lite/toco/export_tensorflow.cc @@ -48,7 +48,8 @@ using tensorflow::TensorProto; namespace toco { namespace { -tensorflow::DataType GetTensorFlowDataType(ArrayDataType data_type) { +tensorflow::DataType GetTensorFlowDataType(ArrayDataType data_type, + const string& error_location) { switch (data_type) { case ArrayDataType::kBool: return tensorflow::DT_BOOL; @@ -66,14 +67,21 @@ tensorflow::DataType GetTensorFlowDataType(ArrayDataType data_type) { return tensorflow::DT_COMPLEX64; default: case ArrayDataType::kNone: - LOG(FATAL) << "Unsupported data type: " << static_cast(data_type); + LOG(FATAL) << "Unsupported data type '" << ArrayDataTypeName(data_type) + << "' in " << error_location; return tensorflow::DT_INVALID; } } +tensorflow::DataType GetTensorFlowDataTypeForOp(ArrayDataType data_type, + const string& op_name) { + return GetTensorFlowDataType(data_type, "op '" + op_name + "'"); +} + tensorflow::DataType GetTensorFlowDataType(const Model& model, const string& array_name) { - return GetTensorFlowDataType(model.GetArray(array_name).data_type); + return GetTensorFlowDataType(model.GetArray(array_name).data_type, + "array '" + array_name + "'"); } // TensorFlow sometimes forbids what it calls "legacy scalars", @@ -1285,7 +1293,7 @@ void ConvertRangeOperator(const Model& model, const RangeOperator& src_op, *range_op->add_input() = src_op.inputs[1]; *range_op->add_input() = src_op.inputs[2]; (*range_op->mutable_attr())["Tidx"].set_type( - GetTensorFlowDataType(src_op.dtype)); + GetTensorFlowDataTypeForOp(src_op.dtype, /*op_name=*/src_op.outputs[0])); } void ConvertPackOperator(const Model& model, const PackOperator& src_op, @@ -1298,7 +1306,8 @@ void ConvertPackOperator(const Model& model, const PackOperator& src_op, } (*pack_op->mutable_attr())["axis"].set_i(src_op.axis); (*pack_op->mutable_attr())["N"].set_i(src_op.inputs.size()); - (*pack_op->mutable_attr())["T"].set_type(GetTensorFlowDataType(src_op.dtype)); + (*pack_op->mutable_attr())["T"].set_type( + GetTensorFlowDataTypeForOp(src_op.dtype, src_op.outputs[0])); } void ConvertFillOperator(const Model& model, const FillOperator& src_op, @@ -1887,7 +1896,7 @@ void ConvertRandomUniformOperator(const Model& model, GetTensorFlowDataType(model, src_op.inputs[0]); (*new_op->mutable_attr())["T"].set_type(shape_type); (*new_op->mutable_attr())["dtype"].set_type( - GetTensorFlowDataType(src_op.dtype)); + GetTensorFlowDataTypeForOp(src_op.dtype, src_op.outputs[0])); (*new_op->mutable_attr())["seed"].set_i(src_op.seed); (*new_op->mutable_attr())["seed2"].set_i(src_op.seed2); } diff --git a/tensorflow/lite/toco/toco.cc b/tensorflow/lite/toco/toco.cc index 9740015850..4a3d6a5848 100644 --- a/tensorflow/lite/toco/toco.cc +++ b/tensorflow/lite/toco/toco.cc @@ -16,87 +16,9 @@ limitations under the License. #include #include -#include "absl/strings/string_view.h" -#include "tensorflow/lite/toco/model.h" #include "tensorflow/lite/toco/model_cmdline_flags.h" -#include "tensorflow/lite/toco/model_flags.pb.h" #include "tensorflow/lite/toco/toco_cmdline_flags.h" -#include "tensorflow/lite/toco/toco_flags.pb.h" -#include "tensorflow/lite/toco/toco_port.h" -#include "tensorflow/lite/toco/toco_tooling.h" -#include "tensorflow/lite/toco/toco_types.h" -#include "tensorflow/core/lib/core/errors.h" -#include "tensorflow/core/platform/logging.h" - -namespace toco { -namespace { - -// Checks the permissions of the output file to ensure it is writeable. -void CheckOutputFilePermissions(const Arg& output_file) { - QCHECK(output_file.specified()) << "Missing required flag --output_file.\n"; - QCHECK(port::file::Writable(output_file.value()).ok()) - << "Specified output_file is not writable: " << output_file.value() - << ".\n"; -} - -// Checks the permissions of the frozen model file. -void CheckFrozenModelPermissions(const Arg& input_file) { - QCHECK(input_file.specified()) << "Missing required flag --input_file.\n"; - QCHECK(port::file::Exists(input_file.value(), port::file::Defaults()).ok()) - << "Specified input_file does not exist: " << input_file.value() << ".\n"; - QCHECK(port::file::Readable(input_file.value(), port::file::Defaults()).ok()) - << "Specified input_file exists, but is not readable: " - << input_file.value() << ".\n"; -} - -// Reads the contents of the GraphDef from either the frozen graph file or the -// SavedModel directory. If it reads the SavedModel directory, it updates the -// ModelFlags and TocoFlags accordingly. -void ReadInputData(const ParsedTocoFlags& parsed_toco_flags, - const ParsedModelFlags& parsed_model_flags, - TocoFlags* toco_flags, ModelFlags* model_flags, - string* graph_def_contents) { - port::CheckInitGoogleIsDone("InitGoogle is not done yet.\n"); - - // Ensure savedmodel_directory is not set. - QCHECK(!parsed_toco_flags.savedmodel_directory.specified()) - << "Use `tensorflow/lite/python/tflite_convert` script with " - << "SavedModel directories.\n"; - - // Checks the input file permissions and reads the contents. - CheckFrozenModelPermissions(parsed_toco_flags.input_file); - CHECK(port::file::GetContents(parsed_toco_flags.input_file.value(), - graph_def_contents, port::file::Defaults()) - .ok()); -} - -tensorflow::Status ToolMain(const ParsedTocoFlags& parsed_toco_flags, - const ParsedModelFlags& parsed_model_flags) { - ModelFlags model_flags; - ReadModelFlagsFromCommandLineFlags(parsed_model_flags, &model_flags); - - TocoFlags toco_flags; - ReadTocoFlagsFromCommandLineFlags(parsed_toco_flags, &toco_flags); - - string graph_def_contents; - ReadInputData(parsed_toco_flags, parsed_model_flags, &toco_flags, - &model_flags, &graph_def_contents); - CheckOutputFilePermissions(parsed_toco_flags.output_file); - - std::unique_ptr model = - Import(toco_flags, model_flags, graph_def_contents); - Transform(toco_flags, model.get()); - string output_file_contents; - TF_RETURN_IF_ERROR(Export(toco_flags, *model, toco_flags.allow_custom_ops(), - &output_file_contents)); - TF_RETURN_IF_ERROR( - port::file::SetContents(parsed_toco_flags.output_file.value(), - output_file_contents, port::file::Defaults())); - return tensorflow::Status(); -} - -} // namespace -} // namespace toco +#include "tensorflow/lite/toco/toco_convert.h" int main(int argc, char** argv) { toco::string msg; @@ -126,6 +48,6 @@ int main(int argc, char** argv) { return 1; } toco::port::InitGoogle(argv[0], effective_argc, &effective_argv, true); - auto status = toco::ToolMain(parsed_toco_flags, parsed_model_flags); + auto status = toco::Convert(parsed_toco_flags, parsed_model_flags); return status.ok() ? 0 : -1; } diff --git a/tensorflow/lite/toco/toco_convert.cc b/tensorflow/lite/toco/toco_convert.cc new file mode 100644 index 0000000000..28e7b10ecd --- /dev/null +++ b/tensorflow/lite/toco/toco_convert.cc @@ -0,0 +1,108 @@ +/* Copyright 2017 The TensorFlow Authors. 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. +==============================================================================*/ +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "tensorflow/lite/toco/model.h" +#include "tensorflow/lite/toco/model_cmdline_flags.h" +#include "tensorflow/lite/toco/model_flags.pb.h" +#include "tensorflow/lite/toco/toco_cmdline_flags.h" +#include "tensorflow/lite/toco/toco_flags.pb.h" +#include "tensorflow/lite/toco/toco_port.h" +#include "tensorflow/lite/toco/toco_tooling.h" +#include "tensorflow/lite/toco/toco_types.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/platform/logging.h" + +namespace toco { +namespace { + +// Checks the permissions of the output file to ensure it is writeable. +void CheckOutputFilePermissions(const Arg& output_file) { + QCHECK(output_file.specified()) << "Missing required flag --output_file.\n"; + QCHECK(port::file::Writable(output_file.value()).ok()) + << "Specified output_file is not writable: " << output_file.value() + << ".\n"; +} + +// Checks the permissions of the frozen model file. +void CheckFrozenModelPermissions(const Arg& input_file) { + QCHECK(input_file.specified()) << "Missing required flag --input_file.\n"; + QCHECK(port::file::Exists(input_file.value(), port::file::Defaults()).ok()) + << "Specified input_file does not exist: " << input_file.value() << ".\n"; + QCHECK(port::file::Readable(input_file.value(), port::file::Defaults()).ok()) + << "Specified input_file exists, but is not readable: " + << input_file.value() << ".\n"; +} + +// Reads the contents of the GraphDef from either the frozen graph file or the +// SavedModel directory. If it reads the SavedModel directory, it updates the +// ModelFlags and TocoFlags accordingly. +void ReadInputData(const ParsedTocoFlags& parsed_toco_flags, + const ParsedModelFlags& parsed_model_flags, + TocoFlags* toco_flags, ModelFlags* model_flags, + string* graph_def_contents) { + port::CheckInitGoogleIsDone("InitGoogle is not done yet.\n"); + + // Ensure savedmodel_directory is not set. + QCHECK(!parsed_toco_flags.savedmodel_directory.specified()) + << "Use `tensorflow/lite/python/tflite_convert` script with " + << "SavedModel directories.\n"; + + // Checks the input file permissions and reads the contents. + CheckFrozenModelPermissions(parsed_toco_flags.input_file); + CHECK(port::file::GetContents(parsed_toco_flags.input_file.value(), + graph_def_contents, port::file::Defaults()) + .ok()); +} +} // namespace + +tensorflow::Status Convert(const string& graph_def_contents, + const TocoFlags& toco_flags, + const ModelFlags& model_flags, + string* output_file_contents) { + std::unique_ptr model = + Import(toco_flags, model_flags, graph_def_contents); + Transform(toco_flags, model.get()); + return Export(toco_flags, *model, toco_flags.allow_custom_ops(), + output_file_contents); +} + +tensorflow::Status Convert(const ParsedTocoFlags& parsed_toco_flags, + const ParsedModelFlags& parsed_model_flags) { + ModelFlags model_flags; + ReadModelFlagsFromCommandLineFlags(parsed_model_flags, &model_flags); + + TocoFlags toco_flags; + ReadTocoFlagsFromCommandLineFlags(parsed_toco_flags, &toco_flags); + + string graph_def_contents; + ReadInputData(parsed_toco_flags, parsed_model_flags, &toco_flags, + &model_flags, &graph_def_contents); + CheckOutputFilePermissions(parsed_toco_flags.output_file); + + string output_file_contents; + TF_RETURN_IF_ERROR(Convert(graph_def_contents, toco_flags, model_flags, + &output_file_contents)); + + TF_RETURN_IF_ERROR( + port::file::SetContents(parsed_toco_flags.output_file.value(), + output_file_contents, port::file::Defaults())); + return tensorflow::Status(); +} + +} // namespace toco diff --git a/tensorflow/lite/toco/toco_convert.h b/tensorflow/lite/toco/toco_convert.h new file mode 100644 index 0000000000..ebbd336d3f --- /dev/null +++ b/tensorflow/lite/toco/toco_convert.h @@ -0,0 +1,34 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#ifndef TENSORFLOW_LITE_TOCO_TOCO_CONVERT_H_ +#define TENSORFLOW_LITE_TOCO_TOCO_CONVERT_H_ + +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/lite/toco/args.h" +#include "tensorflow/lite/toco/model_flags.pb.h" +#include "tensorflow/lite/toco/toco_flags.pb.h" + +namespace toco { + +tensorflow::Status Convert(const string& graph_def_contents, + const TocoFlags& toco_flags, + const ModelFlags& model_flags, + string* output_file_contents); + +tensorflow::Status Convert(const ParsedTocoFlags& parsed_toco_flags, + const ParsedModelFlags& parsed_model_flags); +} // namespace toco + +#endif // TENSORFLOW_LITE_TOCO_TOCO_CONVERT_H_ diff --git a/tensorflow/lite/toco/toco_convert_test.cc b/tensorflow/lite/toco/toco_convert_test.cc new file mode 100644 index 0000000000..c3c440db94 --- /dev/null +++ b/tensorflow/lite/toco/toco_convert_test.cc @@ -0,0 +1,173 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#include "tensorflow/lite/toco/toco_convert.h" +#include +#include + +namespace toco { +namespace { + +TEST(TocoTest, MissingInputFile) { + ParsedTocoFlags toco_flags; + ParsedModelFlags model_flags; + EXPECT_DEATH(Convert(toco_flags, model_flags).ok(), + "Missing required flag --input_file"); +} + +TEST(TocoTest, BadInputFormat) { + TocoFlags toco_flags; + ModelFlags model_flags; + + string input; + string output; + + EXPECT_DEATH(Convert(input, toco_flags, model_flags, &output).ok(), + "Unhandled input_format='FILE_FORMAT_UNKNOWN'"); +} + +TEST(TocoTest, MissingOuputArrays) { + TocoFlags toco_flags; + ModelFlags model_flags; + + toco_flags.set_input_format(TENSORFLOW_GRAPHDEF); + string input; + string output; + + EXPECT_DEATH(Convert(input, toco_flags, model_flags, &output).ok(), + "This model does not define output arrays, so a --output_arrays " + "flag must be given on the command-line"); +} + +TEST(TocoTest, BadOutputArray) { + TocoFlags toco_flags; + ModelFlags model_flags; + + toco_flags.set_input_format(TENSORFLOW_GRAPHDEF); + model_flags.add_output_arrays("output1"); + string input; + string output; + + EXPECT_DEATH(Convert(input, toco_flags, model_flags, &output).ok(), + "Specified output array .output1. is not produced by any op " + "in this graph. Is it a typo. To silence this message, pass " + "this flag: allow_nonexistent_arrays"); +} + +TEST(TocoTest, BadOutputFormat) { + TocoFlags toco_flags; + ModelFlags model_flags; + + toco_flags.set_input_format(TENSORFLOW_GRAPHDEF); + model_flags.add_output_arrays("output1"); + string input = R"GraphDef( + node { + name: "output1" + input: "input1" + input: "input2" + op: "Sub" + attr { key: "T" value { type: DT_FLOAT } } + } + )GraphDef"; + + string output; + + EXPECT_DEATH(Convert(input, toco_flags, model_flags, &output).ok(), + "Unhandled output_format='FILE_FORMAT_UNKNOWN'"); +} + +TEST(TocoTest, SimpleFloatModel) { + TocoFlags toco_flags; + ModelFlags model_flags; + + toco_flags.set_input_format(TENSORFLOW_GRAPHDEF); + toco_flags.set_output_format(TENSORFLOW_GRAPHDEF); + + // Inputs are automatically selected (but that might not be a good idea). + model_flags.add_output_arrays("output1"); + string input = R"GraphDef( + node { + name: "input1" + op: "Placeholder" + attr { key: "dtype" value { type: DT_INT64 } } + } + node { + name: "input2" + op: "Placeholder" + attr { key: "dtype" value { type: DT_INT64 } } + } + node { + name: "output1" + input: "input1" + input: "input2" + op: "Sub" + attr { key: "T" value { type: DT_FLOAT } } + } + )GraphDef"; + + string output; + EXPECT_TRUE(Convert(input, toco_flags, model_flags, &output).ok()); + EXPECT_TRUE(!output.empty()); +} + +TEST(TocoTest, TransientStringTensors) { + TocoFlags toco_flags; + ModelFlags model_flags; + + toco_flags.set_input_format(TENSORFLOW_GRAPHDEF); + + // We need to do a couple of things to trigger the transient array + // initialization code: output format must support memory planning, and the + // input array must have a shape. + toco_flags.set_output_format(TFLITE); + + model_flags.add_output_arrays("output1"); + string input = R"GraphDef( + node { + name: "input1" + op: "Placeholder" + attr { key: "dtype" value { type: DT_STRING } } + attr { key: "shape" value { shape { dim { size:1 }}}} + } + node { + name: "indices1" + op: "Placeholder" + attr { key: "dtype" value { type: DT_INT64 } } + } + node { + name: "intermediate1" + op: "Gather" + input: "input1" + input: "indices1" + attr { key: "Tparams" value { type: DT_STRING } } + attr { key: "Tindices" value { type: DT_INT64 } } + } + node { + name: "output1" + op: "Gather" + input: "intermediate1" + input: "indices2" + attr { key: "Tparams" value { type: DT_STRING } } + attr { key: "Tindices" value { type: DT_INT64 } } + } + )GraphDef"; + + string output; + + EXPECT_TRUE(Convert(input, toco_flags, model_flags, &output).ok()); + EXPECT_TRUE(!output.empty()); +} + +} // namespace +} // namespace toco diff --git a/tensorflow/lite/toco/toco_tooling.cc b/tensorflow/lite/toco/toco_tooling.cc index 5f96e833fb..d8b111d037 100644 --- a/tensorflow/lite/toco/toco_tooling.cc +++ b/tensorflow/lite/toco/toco_tooling.cc @@ -210,7 +210,8 @@ std::unique_ptr Import(const TocoFlags& toco_flags, CheckInvariants(*model); break; default: - LOG(FATAL) << "Unhandled input_format"; + LOG(FATAL) << "Unhandled input_format='" + << FileFormat_Name(toco_flags.input_format()) << "'"; } LogDump(kLogLevelModelChanged, "AT IMPORT", *model); @@ -424,7 +425,8 @@ tensorflow::Status Export(const TocoFlags& toco_flags, const Model& model, DumpGraphviz(model, output_file_contents); break; default: - LOG(FATAL) << "Unhandled output_format"; + LOG(FATAL) << "Unhandled output_format='" + << FileFormat_Name(toco_flags.output_format()) << "'"; } return tensorflow::Status(); } diff --git a/tensorflow/lite/toco/tooling_util.cc b/tensorflow/lite/toco/tooling_util.cc index cff387782f..084169548e 100644 --- a/tensorflow/lite/toco/tooling_util.cc +++ b/tensorflow/lite/toco/tooling_util.cc @@ -1770,6 +1770,14 @@ bool IsAllocatableTransientArray(const Model& model, const string& array_name) { if (!array->has_shape()) { return false; } + + // The size of string tensors is rarely known ahead of time, so all transient + // tensors of this type will need to be dynamically allocated. + if (array->final_data_type == ArrayDataType::kString || + array->data_type == ArrayDataType::kString) { + return false; + } + return true; } -- GitLab From ca4a34eb9e8333f216eccb0adff0e6e9186b9510 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 20 Nov 2018 13:39:02 -0800 Subject: [PATCH 143/672] [TF:XLA] Bump open source llvm revision to r347298 PiperOrigin-RevId: 222299016 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 14a5d0a25c..101d0e4c7a 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -472,11 +472,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "llvm", build_file = clean_dep("//third_party/llvm:llvm.autogenerated.BUILD"), - sha256 = "286465fc41ade5c1c44e4a6dce9681106664fcdd12264dc9be63fc22bbee3c9c", - strip_prefix = "llvm-0478924a3727c74fd482d07eed45a8347540576e", + sha256 = "7b4f705c532ee2aafb6e8b9013ad22ec8bb1823a153cd2d6ddb6b7faef818874", + strip_prefix = "llvm-9ad322c7dfd4385be9a515d734f70700f192ebae", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/0478924a3727c74fd482d07eed45a8347540576e.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/0478924a3727c74fd482d07eed45a8347540576e.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/9ad322c7dfd4385be9a515d734f70700f192ebae.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/9ad322c7dfd4385be9a515d734f70700f192ebae.tar.gz", ], ) -- GitLab From 1e904bd524771c851421860de39091976ef8616e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 13:41:02 -0800 Subject: [PATCH 144/672] This CL allows sparse losses to work in Keras even if they take a different dtype for the labels than the model outputs produce. PiperOrigin-RevId: 222299347 --- tensorflow/python/keras/engine/training.py | 6 +++- .../keras/engine/training_dataset_test.py | 34 ++++++++++++------- tensorflow/python/keras/losses.py | 7 ++++ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index ce01777b2d..56f069c057 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -693,11 +693,15 @@ class Model(Network): target = None if target is None or K.is_placeholder(target): if target is None: + target_dtype = losses.LABEL_DTYPES_FOR_LOSSES.get( + self.loss_functions[i], + K.dtype(self.outputs[i])) + target = K.placeholder( ndim=len(shape), name=name + '_target', sparse=K.is_sparse(self.outputs[i]), - dtype=K.dtype(self.outputs[i])) + dtype=target_dtype) self._feed_targets.append(target) self._feed_outputs.append(self.outputs[i]) self._feed_output_names.append(name) diff --git a/tensorflow/python/keras/engine/training_dataset_test.py b/tensorflow/python/keras/engine/training_dataset_test.py index 2e6bec6c62..e79e5842a1 100644 --- a/tensorflow/python/keras/engine/training_dataset_test.py +++ b/tensorflow/python/keras/engine/training_dataset_test.py @@ -30,6 +30,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.keras import metrics as metrics_module from tensorflow.python.keras import testing_utils +from tensorflow.python.ops.losses import losses_impl from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training.rmsprop import RMSPropOptimizer @@ -146,7 +147,7 @@ class TestTrainingWithDatasetIterators(test.TestCase, parameterized.TestCase): 'dataset iterator ran out of data') -class TestTrainingWithDataset(test.TestCase): +class TestTrainingWithDataset(test.TestCase, parameterized.TestCase): @tf_test_util.run_in_graph_and_eager_modes def test_calling_model_on_same_dataset(self): @@ -249,20 +250,29 @@ class TestTrainingWithDataset(test.TestCase): model.evaluate(dataset, steps=2, verbose=1) model.predict(dataset, steps=2) + @parameterized.parameters( + {'model': 'functional'}, + {'model': 'subclass'}, + ) @tf_test_util.run_in_graph_and_eager_modes - def test_dataset_with_sparse_labels(self): - model = testing_utils.get_small_functional_mlp(1, 4, input_dim=3) - optimizer = RMSPropOptimizer(learning_rate=0.001) - loss = 'sparse_categorical_crossentropy' - model.compile(optimizer, loss) + def test_dataset_with_sparse_labels(self, model): + if model == 'functional': + model = testing_utils.get_small_functional_mlp(1, 4, input_dim=3) + elif model == 'subclass': + model = testing_utils.get_small_sequential_mlp(1, 4) - inputs = np.zeros((10, 3)) - targets = np.random.randint(0, 4, size=10, dtype=np.int32) - dataset = dataset_ops.Dataset.from_tensor_slices((inputs, targets)) - dataset = dataset.repeat(100) - dataset = dataset.batch(10) + for loss in ['sparse_categorical_crossentropy', + losses_impl.sparse_softmax_cross_entropy]: + optimizer = RMSPropOptimizer(learning_rate=0.001) + model.compile(optimizer, loss) - model.fit(dataset, epochs=1, steps_per_epoch=2, verbose=1) + inputs = np.zeros((10, 3), dtype=np.float32) + targets = np.random.randint(0, 4, size=10, dtype=np.int32) + dataset = dataset_ops.Dataset.from_tensor_slices((inputs, targets)) + dataset = dataset.repeat(100) + dataset = dataset.batch(10) + + model.fit(dataset, epochs=1, steps_per_epoch=2, verbose=1) def test_dataset_input_shape_validation(self): with self.cached_session(): diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index 9f548bfe04..f871ee409e 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -26,6 +26,7 @@ from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn +from tensorflow.python.ops.losses import losses_impl from tensorflow.python.util.tf_export import tf_export @@ -197,3 +198,9 @@ def get(identifier): else: raise ValueError('Could not interpret ' 'loss function identifier:', identifier) + + +LABEL_DTYPES_FOR_LOSSES = { + losses_impl.sparse_softmax_cross_entropy: 'int32', + sparse_categorical_crossentropy: 'int32' +} -- GitLab From 813449805cf8cba7f3fbff7c7b77fa2f1f0ee2bb Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 20 Nov 2018 13:49:58 -0800 Subject: [PATCH 145/672] Add uint64 support to Merge and Switch. XLA's auto-clustering sometimes creates uint64 Merge ops. For symmetry I also added support for uint64 Switches even though I don't strictly need them. PiperOrigin-RevId: 222300834 --- tensorflow/core/kernels/control_flow_ops.cc | 3 +++ .../python/kernel_tests/control_flow_ops_py_test.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/tensorflow/core/kernels/control_flow_ops.cc b/tensorflow/core/kernels/control_flow_ops.cc index 382c9d5e50..1587eb5114 100644 --- a/tensorflow/core/kernels/control_flow_ops.cc +++ b/tensorflow/core/kernels/control_flow_ops.cc @@ -71,11 +71,13 @@ TF_CALL_ALL_TYPES(REGISTER_CPU_SWITCH); TF_CALL_ALL_TYPES(REGISTER_CPU_REF_SWITCH); TF_CALL_QUANTIZED_TYPES(REGISTER_CPU_SWITCH); TF_CALL_QUANTIZED_TYPES(REGISTER_CPU_REF_SWITCH); +REGISTER_CPU_SWITCH(uint64); TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_SWITCH); TF_CALL_QUANTIZED_TYPES(REGISTER_GPU_SWITCH); TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_REF_SWITCH); TF_CALL_QUANTIZED_TYPES(REGISTER_GPU_REF_SWITCH); +REGISTER_GPU_SWITCH(uint64); #undef REGISTER_CPU_SWITCH #undef REGISTER_CPU_REF_SWITCH @@ -263,6 +265,7 @@ TF_CALL_QUANTIZED_TYPES(REGISTER_GPU_KERNEL); TF_CALL_QUANTIZED_TYPES(REGISTER_GPU_REF_KERNEL); REGISTER_GPU_KERNEL(bool); REGISTER_GPU_REF_KERNEL(bool); +REGISTER_GPU_KERNEL(uint64); #undef REGISTER_GPU_KERNEL #undef REGISTER_GPU_REF_KERNEL diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 3394df20d8..3b8f917282 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -3360,6 +3360,14 @@ class ControlFlowTest(test.TestCase): result = control_flow_ops.ref_merge([v_f, v_t]) sess.run(result) + def testUInt64SwitchMerge(self): + with self.cached_session(force_gpu=test.is_gpu_available()) as sess: + constant_uint64 = constant_op.constant(np.array([42]), dtypes.uint64) + cond = constant_op.constant(True, dtypes.bool) + v_f, v_t = control_flow_ops.switch(constant_uint64, cond) + result = control_flow_ops.merge([v_f, v_t]) + sess.run(result) + def testQIntArgAndRet(self): @function.Defun(dtypes.qint8) -- GitLab From 7ee43ac030645fc3aa41fc61047e3164c53c99b1 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 11:52:25 -0800 Subject: [PATCH 146/672] TFTRT: fix wording in logs --- tensorflow/contrib/tensorrt/convert/convert_graph.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index d688ebd7b4..1e0ea5f7e2 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -970,8 +970,8 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { &graph, alloc.get(), &engine_nodes); // If status is ok, we successfully added the node to the graph and can // remove segment ops. Otherwise graph is not modified. - string msg = StrCat("Added TensorRT node ", engine.engine_name, " for segment ", - i, " consisting ", + string msg = StrCat("TensorRT node ", engine.engine_name, " added for segment ", + i, " consisting of ", converted_segments.at(i).first.size(), " nodes"); if (status.ok()) { LOG(INFO) << msg << " succeeded."; -- GitLab From f32501accfbbc5e76f182a20df93e4154737a11e Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 13:10:12 -0800 Subject: [PATCH 147/672] TFTRT: rename my_trt_op_ to TRTEngineOp_ in tests --- .../tensorrt/python/trt_convert_test.py | 6 ++-- tensorflow/contrib/tensorrt/test/base_test.py | 32 +++++++++---------- .../tensorrt/test/batch_matmul_test.py | 6 ++-- .../tensorrt/test/biasadd_matmul_test.py | 2 +- .../binary_tensor_weight_broadcast_test.py | 2 +- .../tensorrt/test/concatenation_test.py | 2 +- .../tensorrt/test/const_broadcast_test.py | 2 +- .../tensorrt/test/memory_alignment_test.py | 2 +- .../multi_connection_neighbor_engine_test.py | 2 +- .../tensorrt/test/neighboring_engine_test.py | 4 +-- .../contrib/tensorrt/test/rank_two_test.py | 4 +-- .../tensorrt/test/reshape_transpose_test.py | 6 ++-- .../test/tf_trt_integration_test_base.py | 6 ++-- .../contrib/tensorrt/test/unary_test.py | 4 +-- .../tensorrt/test/vgg_block_nchw_test.py | 2 +- .../contrib/tensorrt/test/vgg_block_test.py | 2 +- 16 files changed, 42 insertions(+), 42 deletions(-) diff --git a/tensorflow/contrib/tensorrt/python/trt_convert_test.py b/tensorflow/contrib/tensorrt/python/trt_convert_test.py index aa82f4207f..7f1045c199 100644 --- a/tensorflow/contrib/tensorrt/python/trt_convert_test.py +++ b/tensorflow/contrib/tensorrt/python/trt_convert_test.py @@ -162,7 +162,7 @@ class TrtConvertTest(test_util.TensorFlowTestCase): node_name_to_op = {node.name: node.op for node in graph_def.node} self.assertEqual({ "input": "Placeholder", - "my_trt_op_0": "TRTEngineOp", + "TRTEngineOp_0": "TRTEngineOp", "output": "Identity" }, node_name_to_op) @@ -189,10 +189,10 @@ class TrtConvertTest(test_util.TensorFlowTestCase): execute_engine_test_value = ("done" if expect_engine_is_run else "") execute_native_segment_test_value = ("" if expect_engine_is_run else "done") self.assertEqual(execute_engine_test_value, - trt_convert.get_test_value("my_trt_op_0:ExecuteTrtEngine")) + trt_convert.get_test_value("TRTEngineOp_0:ExecuteTrtEngine")) self.assertEqual( execute_native_segment_test_value, - trt_convert.get_test_value("my_trt_op_0:ExecuteNativeSegment")) + trt_convert.get_test_value("TRTEngineOp_0:ExecuteNativeSegment")) def testCreateInferenceGraph_MinimumSegmentSize(self): if not trt_convert.is_tensorrt_enabled(): diff --git a/tensorflow/contrib/tensorrt/test/base_test.py b/tensorflow/contrib/tensorrt/test/base_test.py index 18096e0ff1..5caa61c6fe 100644 --- a/tensorflow/contrib/tensorrt/test/base_test.py +++ b/tensorflow/contrib/tensorrt/test/base_test.py @@ -75,9 +75,9 @@ class SimpleSingleEngineTest(trt_test.TfTrtIntegrationTestBase): """Return the expected engines to build.""" # TODO(aaroey): LayoutOptimizer adds additional nodes to the graph which # breaks the connection check, fix it. - # - my_trt_op_0 should have ["weights", "conv", "bias", "bias_add", + # - TRTEngineOp_0 should have ["weights", "conv", "bias", "bias_add", # "relu", "identity", "max_pool"] - return ["my_trt_op_0"] + return ["TRTEngineOp_0"] class SimpleMultiEnginesTest(trt_test.TfTrtIntegrationTestBase): @@ -131,10 +131,10 @@ class SimpleMultiEnginesTest(trt_test.TfTrtIntegrationTestBase): """Return the expected engines to build.""" # TODO(aaroey): LayoutOptimizer adds additional nodes to the graph which # breaks the connection check, fix it. - # - my_trt_op_0 should have ["mul", "sub", "div1", "mul1", "add1", + # - TRTEngineOp_0 should have ["mul", "sub", "div1", "mul1", "add1", # "add", "sub1"]; - # - my_trt_op_1 should have ["weights","conv", "div"] - return ["my_trt_op_0", "my_trt_op_1"] + # - TRTEngineOp_1 should have ["weights","conv", "div"] + return ["TRTEngineOp_0", "TRTEngineOp_1"] def ShouldRunTest(self, run_params): # TODO(aaroey): LayoutOptimizer adds Transpose(Const, Const) to the graph @@ -153,7 +153,7 @@ class PartiallyConvertedTestA(trt_test.TfTrtIntegrationTestBase): """Setup method.""" super(PartiallyConvertedTestA, self).setUp() # Let it fail to build the second engine. - trt_convert.add_test_value("my_trt_op_1:CreateTRTNode", "fail") + trt_convert.add_test_value("TRTEngineOp_1:CreateTRTNode", "fail") def GetParams(self): """Create a graph containing two segment.""" @@ -190,7 +190,7 @@ class PartiallyConvertedTestA(trt_test.TfTrtIntegrationTestBase): """Return the expected engines to build.""" return { # Only the first engine is built. - "my_trt_op_0": ["c0", "c1", "add0", "add1", "mul0", "mul1"] + "TRTEngineOp_0": ["c0", "c1", "add0", "add1", "mul0", "mul1"] } def ShouldRunTest(self, run_params): @@ -207,13 +207,13 @@ class PartiallyConvertedTestB(PartiallyConvertedTestA): super(PartiallyConvertedTestB, self).setUp() # Let it fail to build the first engine. trt_convert.clear_test_values("") - trt_convert.add_test_value("my_trt_op_0:CreateTRTNode", "fail") + trt_convert.add_test_value("TRTEngineOp_0:CreateTRTNode", "fail") def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { # Only the second engine is built. - "my_trt_op_1": ["c2", "c3", "add2", "add3", "mul2", "mul3"] + "TRTEngineOp_1": ["c2", "c3", "add2", "add3", "mul2", "mul3"] } @@ -257,8 +257,8 @@ class ConstInputTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": ["add", "add1", "mul"], - "my_trt_op_1": ["add2", "add3", "mul1"] + "TRTEngineOp_0": ["add", "add1", "mul"], + "TRTEngineOp_1": ["add2", "add3", "mul1"] } @@ -289,7 +289,7 @@ class ConstDataInputSingleEngineTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return {"my_trt_op_0": ["c", "add", "add1", "mul"]} + return {"TRTEngineOp_0": ["c", "add", "add1", "mul"]} class ConstDataInputMultipleEnginesTest(trt_test.TfTrtIntegrationTestBase): @@ -324,12 +324,12 @@ class ConstDataInputMultipleEnginesTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": ["add2", "add3", "mul1"], + "TRTEngineOp_0": ["add2", "add3", "mul1"], # Why segment ["add", "add1", "mul"] was assigned segment id 1 # instead of 0: the parent node of this segment is actually const # node 'c', but it's removed later since it's const output of the # segment which is not allowed. - "my_trt_op_1": ["add", "add1", "mul"] + "TRTEngineOp_1": ["add", "add1", "mul"] } @@ -373,8 +373,8 @@ class ControlDependencyTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": ["c1", "add", "add1", "mul"], - "my_trt_op_1": ["c2", "add2", "add3", "mul1"] + "TRTEngineOp_0": ["c1", "add", "add1", "mul"], + "TRTEngineOp_1": ["c2", "add2", "add3", "mul1"] } diff --git a/tensorflow/contrib/tensorrt/test/batch_matmul_test.py b/tensorflow/contrib/tensorrt/test/batch_matmul_test.py index 4b88808178..f42308ecb7 100644 --- a/tensorflow/contrib/tensorrt/test/batch_matmul_test.py +++ b/tensorflow/contrib/tensorrt/test/batch_matmul_test.py @@ -79,12 +79,12 @@ class BatchMatMulTest(trt_test.TfTrtIntegrationTestBase): """Return the expected engines to build.""" if (run_params.dynamic_engine and not trt_test.IsQuantizationMode(run_params.precision_mode)): - return ["my_trt_op_0", "my_trt_op_1"] - return ["my_trt_op_1"] + return ["TRTEngineOp_0", "TRTEngineOp_1"] + return ["TRTEngineOp_1"] def ExpectedEnginesToRun(self, run_params): """Return the expected engines to run.""" - return ["my_trt_op_1"] + return ["TRTEngineOp_1"] def ShouldRunTest(self, run_params): """Whether to run the test.""" diff --git a/tensorflow/contrib/tensorrt/test/biasadd_matmul_test.py b/tensorflow/contrib/tensorrt/test/biasadd_matmul_test.py index 6546ef6477..053b38ff1c 100644 --- a/tensorflow/contrib/tensorrt/test/biasadd_matmul_test.py +++ b/tensorflow/contrib/tensorrt/test/biasadd_matmul_test.py @@ -128,7 +128,7 @@ class BiasaddMatMulTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0"] + return ["TRTEngineOp_0"] def ShouldRunTest(self, run_params): """Whether to run the test.""" diff --git a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py index b53cb3c091..e8b5a8ff62 100644 --- a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py +++ b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py @@ -70,7 +70,7 @@ class BinaryTensorWeightBroadcastTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_%d" % i for i in range(16)] + return ["TRTEngineOp_%d" % i for i in range(16)] if __name__ == "__main__": diff --git a/tensorflow/contrib/tensorrt/test/concatenation_test.py b/tensorflow/contrib/tensorrt/test/concatenation_test.py index 465cb02296..c3576f81d9 100644 --- a/tensorflow/contrib/tensorrt/test/concatenation_test.py +++ b/tensorflow/contrib/tensorrt/test/concatenation_test.py @@ -79,7 +79,7 @@ class ConcatenationTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0"] + return ["TRTEngineOp_0"] if __name__ == "__main__": diff --git a/tensorflow/contrib/tensorrt/test/const_broadcast_test.py b/tensorflow/contrib/tensorrt/test/const_broadcast_test.py index e32f047866..c1c883312d 100644 --- a/tensorflow/contrib/tensorrt/test/const_broadcast_test.py +++ b/tensorflow/contrib/tensorrt/test/const_broadcast_test.py @@ -64,7 +64,7 @@ class ConstBroadcastTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ['my_trt_op_0'] + return ['TRTEngineOp_0'] def ExpectedAbsoluteTolerance(self, run_params): """The absolute tolerance to compare floating point results.""" diff --git a/tensorflow/contrib/tensorrt/test/memory_alignment_test.py b/tensorflow/contrib/tensorrt/test/memory_alignment_test.py index bc7c90081f..104bac43a0 100644 --- a/tensorflow/contrib/tensorrt/test/memory_alignment_test.py +++ b/tensorflow/contrib/tensorrt/test/memory_alignment_test.py @@ -68,7 +68,7 @@ class MemoryAlignmentTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0"] + return ["TRTEngineOp_0"] def ExpectedAbsoluteTolerance(self, run_params): """The absolute tolerance to compare floating point results.""" diff --git a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py index 11be4feaf7..f09c7b70bc 100644 --- a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py +++ b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py @@ -83,7 +83,7 @@ class MultiConnectionNeighborEngineTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0", "my_trt_op_1"] + return ["TRTEngineOp_0", "TRTEngineOp_1"] if __name__ == "__main__": diff --git a/tensorflow/contrib/tensorrt/test/neighboring_engine_test.py b/tensorflow/contrib/tensorrt/test/neighboring_engine_test.py index eddeafa38b..3e1e4b088b 100644 --- a/tensorflow/contrib/tensorrt/test/neighboring_engine_test.py +++ b/tensorflow/contrib/tensorrt/test/neighboring_engine_test.py @@ -66,8 +66,8 @@ class NeighboringEngineTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": ["bias", "mul", "sub"], - "my_trt_op_1": ["weights", "conv"] + "TRTEngineOp_0": ["bias", "mul", "sub"], + "TRTEngineOp_1": ["weights", "conv"] } diff --git a/tensorflow/contrib/tensorrt/test/rank_two_test.py b/tensorflow/contrib/tensorrt/test/rank_two_test.py index 74a4a05925..0cd733dca1 100644 --- a/tensorflow/contrib/tensorrt/test/rank_two_test.py +++ b/tensorflow/contrib/tensorrt/test/rank_two_test.py @@ -68,11 +68,11 @@ class RankTwoTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": [ + "TRTEngineOp_0": [ "add0_1", "add0_2", "add0_3", "c0_1", "c0_2", "c0_3", "abs0_1", "abs0_2" ], - "my_trt_op_1": [ + "TRTEngineOp_1": [ "add", "add1_1", "add1_2", "add1_3", "c1_1", "c1_2", "c1_3", "abs1_1", "abs1_2", "reciprocal0", "reciprocal1" ], diff --git a/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py b/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py index bbc724ab18..419e52b768 100644 --- a/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py +++ b/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py @@ -79,7 +79,7 @@ class ReshapeTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": ["reshape-%d" % i for i in range(7)] + + "TRTEngineOp_0": ["reshape-%d" % i for i in range(7)] + ["reshape-%d/shape" % i for i in range(7)] } @@ -117,7 +117,7 @@ class TransposeTest(trt_test.TfTrtIntegrationTestBase): # Note: by default Grappler will run the TRT optimizer twice. At the # first time it will group the two transpose ops below to same segment # then fail the conversion due to the expected batch dimension problem. - # At the second time, since the input of bridge op is my_trt_op_0, it + # At the second time, since the input of bridge op is TRTEngineOp_0, it # will fail to do shape inference which then cause conversion to fail. # TODO(laigd): support shape inference, make TRT optimizer run only # once, and fix this. @@ -136,7 +136,7 @@ class TransposeTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return { - "my_trt_op_0": [ + "TRTEngineOp_0": [ "transpose-1", "transpose-1/perm", "transposeback", "transposeback/perm" ] diff --git a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py index c3cff28574..da22c8371b 100644 --- a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py +++ b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py @@ -217,9 +217,9 @@ class TfTrtIntegrationTestBase(test_util.TensorFlowTestCase): def _PrepareRun(self, graph_state): """Set up necessary testing environment before calling sess.run().""" # Clear test values added by TRTEngineOp. - trt_convert.clear_test_values("my_trt_op_.*:ExecuteTrtEngine") - trt_convert.clear_test_values("my_trt_op_.*:ExecuteCalibration") - trt_convert.clear_test_values("my_trt_op_.*:ExecuteNativeSegment") + trt_convert.clear_test_values("TRTEngineOp_.*:ExecuteTrtEngine") + trt_convert.clear_test_values("TRTEngineOp_.*:ExecuteCalibration") + trt_convert.clear_test_values("TRTEngineOp_.*:ExecuteNativeSegment") def _GetGPUOptions(self): gpu_options = config_pb2.GPUOptions() diff --git a/tensorflow/contrib/tensorrt/test/unary_test.py b/tensorflow/contrib/tensorrt/test/unary_test.py index 8736bfb644..9fc50e0595 100644 --- a/tensorflow/contrib/tensorrt/test/unary_test.py +++ b/tensorflow/contrib/tensorrt/test/unary_test.py @@ -107,8 +107,8 @@ class UnaryTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" return [ - "my_trt_op_0", "my_trt_op_1", "my_trt_op_2", "my_trt_op_3", - "my_trt_op_4" + "TRTEngineOp_0", "TRTEngineOp_1", "TRTEngineOp_2", "TRTEngineOp_3", + "TRTEngineOp_4" ] diff --git a/tensorflow/contrib/tensorrt/test/vgg_block_nchw_test.py b/tensorflow/contrib/tensorrt/test/vgg_block_nchw_test.py index b0271a04b3..b29626d2c2 100644 --- a/tensorflow/contrib/tensorrt/test/vgg_block_nchw_test.py +++ b/tensorflow/contrib/tensorrt/test/vgg_block_nchw_test.py @@ -76,7 +76,7 @@ class VGGBlockNCHWTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0"] + return ["TRTEngineOp_0"] if __name__ == "__main__": diff --git a/tensorflow/contrib/tensorrt/test/vgg_block_test.py b/tensorflow/contrib/tensorrt/test/vgg_block_test.py index d7c165784b..9b0b189626 100644 --- a/tensorflow/contrib/tensorrt/test/vgg_block_test.py +++ b/tensorflow/contrib/tensorrt/test/vgg_block_test.py @@ -67,7 +67,7 @@ class VGGBlockTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - return ["my_trt_op_0"] + return ["TRTEngineOp_0"] if __name__ == "__main__": -- GitLab From d4127586167c47679cee38c61bc44b7055d90be8 Mon Sep 17 00:00:00 2001 From: Tom Hennigan Date: Tue, 20 Nov 2018 14:07:16 -0800 Subject: [PATCH 148/672] Fix vlog of non-functions (e.g. callable objects). PiperOrigin-RevId: 222303881 --- tensorflow/python/eager/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index 609a340915..bc92a0c974 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -1091,7 +1091,7 @@ class PolymorphicFunction(object): if graph_function is None: logging.vlog(1, "Creating new FuncGraph for Python function %r (key: %r)", - self._python_function.__name__, cache_key) + self._python_function, cache_key) if self._input_signature is None: arglen = len(args) else: -- GitLab From 95fbc0e4db095ec6e947d1bb20319441cc31e505 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 14:12:53 -0800 Subject: [PATCH 149/672] TFTRT: fix alignment --- tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc index cff6be9759..8037d47040 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc @@ -492,7 +492,7 @@ TRTEngineOp::EngineCtxPair& TRTEngineOp::GetEngine(int batch_size, TrtUniquePtrType engine; bool convert_successfully = false; LOG(INFO) << "Building a new TensorRT engine for " << name() - << " with batch size " << batch_size; + << " with batch size " << batch_size; // Up to this point, calibrator_ can never be empty, since otherwise it // means calibration_mode_ is true and this path won't get executed. auto status = convert::ConvertGraphDefToEngine( @@ -568,7 +568,7 @@ tensorflow::Status TRTEngineOp::AllocateCalibrationResources( cres->thr_.reset(new std::thread([cres, label, segment_graph, shapes, platform_gpu_id, workspace_size_bytes]() { LOG(INFO) << "Starting calibration thread on device " << platform_gpu_id - << ", Calibration Resource @ " << cres; + << ", Calibration Resource @ " << cres; auto err = cudaSetDevice(platform_gpu_id); if (err != cudaSuccess) { // TODO(aaroey): should return error here. -- GitLab From fd46ffb7bd04d0959294a09ae8a9d2cbd74a48ca Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Tue, 20 Nov 2018 14:13:20 -0800 Subject: [PATCH 150/672] Automated rollback of commit a3650434746cba6b78d9846fbde3b7f31f6a33c8 PiperOrigin-RevId: 222304840 --- tensorflow/python/data/experimental/ops/BUILD | 2 +- .../python/data/experimental/ops/grouping.py | 16 +- tensorflow/python/data/kernel_tests/BUILD | 4 - .../data/kernel_tests/dataset_ops_test.py | 61 ---- tensorflow/python/data/ops/dataset_ops.py | 260 +++++++++++------- tensorflow/python/data/ops/optional_ops.py | 12 +- tensorflow/python/data/util/structure.py | 26 +- tensorflow/python/data/util/structure_test.py | 9 +- 8 files changed, 188 insertions(+), 202 deletions(-) diff --git a/tensorflow/python/data/experimental/ops/BUILD b/tensorflow/python/data/experimental/ops/BUILD index b6c1376b6a..170fda90b6 100644 --- a/tensorflow/python/data/experimental/ops/BUILD +++ b/tensorflow/python/data/experimental/ops/BUILD @@ -165,7 +165,7 @@ py_library( "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/util:nest", - "//tensorflow/python/data/util:structure", + "//tensorflow/python/data/util:sparse", ], ) diff --git a/tensorflow/python/data/experimental/ops/grouping.py b/tensorflow/python/data/experimental/ops/grouping.py index db10ea3b7f..80ca7104d8 100644 --- a/tensorflow/python/data/experimental/ops/grouping.py +++ b/tensorflow/python/data/experimental/ops/grouping.py @@ -21,7 +21,6 @@ import numpy as np from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest -from tensorflow.python.data.util import structure from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -449,10 +448,7 @@ class _GroupByWindowDataset(dataset_ops.UnaryDataset): def _make_reduce_func(self, reduce_func, input_dataset): """Make wrapping defun for reduce_func.""" - nested_dataset = dataset_ops.DatasetStructure( - structure.Structure._from_legacy_structure( # pylint: disable=protected-access - input_dataset.output_types, input_dataset.output_shapes, - input_dataset.output_classes)) + nested_dataset = dataset_ops._NestedDatasetComponent(input_dataset) # pylint: disable=protected-access wrapped_func = dataset_ops.StructuredFunctionWrapper( reduce_func, self._transformation_name(), @@ -460,13 +456,11 @@ class _GroupByWindowDataset(dataset_ops.UnaryDataset): input_shapes=(tensor_shape.scalar(), nested_dataset), input_types=(dtypes.int64, nested_dataset)) if not isinstance( - wrapped_func.output_structure, dataset_ops.DatasetStructure): + wrapped_func.output_classes, dataset_ops._NestedDatasetComponent): # pylint: disable=protected-access raise TypeError("`reduce_func` must return a `Dataset` object.") - # pylint: disable=protected-access - element_structure = wrapped_func.output_structure._element_structure - self._output_classes = element_structure._to_legacy_output_classes() - self._output_types = element_structure._to_legacy_output_types() - self._output_shapes = element_structure._to_legacy_output_shapes() + self._output_classes = wrapped_func.output_classes.output_classes + self._output_types = wrapped_func.output_types.output_types + self._output_shapes = wrapped_func.output_shapes.output_shapes self._reduce_func = wrapped_func.function @property diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index fa1f6d701a..21eed2b070 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -117,12 +117,8 @@ tf_py_test( "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/python:client_testlib", - "//tensorflow/python:constant_op", "//tensorflow/python:sparse_tensor", - "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/ops:optional_ops", - "//tensorflow/python/data/util:structure", ], ) diff --git a/tensorflow/python/data/kernel_tests/dataset_ops_test.py b/tensorflow/python/data/kernel_tests/dataset_ops_test.py index 1f22a37c2e..a5324af4d0 100644 --- a/tensorflow/python/data/kernel_tests/dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_ops_test.py @@ -24,14 +24,10 @@ import numpy as np from tensorflow.core.framework import graph_pb2 from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import optional_ops from tensorflow.python.data.ops import readers from tensorflow.python.data.util import nest -from tensorflow.python.data.util import structure -from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor -from tensorflow.python.framework import tensor_shape from tensorflow.python.platform import test @@ -253,63 +249,6 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertTrue(ds.options().experimental_autotune) self.assertTrue(ds.options().experimental_filter_fusion) - # pylint: disable=g-long-lambda - @parameterized.named_parameters( - ("Tensor", lambda: constant_op.constant(37.0), - structure.TensorStructure(dtypes.float32, [])), - ("SparseTensor", lambda: sparse_tensor.SparseTensor( - indices=[[0]], values=constant_op.constant([0], dtype=dtypes.int32), - dense_shape=[1]), - structure.SparseTensorStructure(dtypes.int32, [1])), - ("Nest", lambda: { - "a": constant_op.constant(37.0), - "b": (constant_op.constant(["Foo"]), constant_op.constant("Bar"))}, - structure.NestedStructure({ - "a": structure.TensorStructure(dtypes.float32, []), - "b": (structure.TensorStructure(dtypes.string, [1]), - structure.TensorStructure(dtypes.string, []))})), - ("Dataset", lambda: dataset_ops.Dataset.from_tensor_slices( - constant_op.constant([1, 2, 3])), - dataset_ops.DatasetStructure( - structure.TensorStructure(dtypes.int32, []))), - ("Optional", lambda: optional_ops.Optional.from_value(37.0), - optional_ops.OptionalStructure( - structure.TensorStructure(dtypes.float32, []))), - ) - def testDatasetStructure(self, tf_value_fn, expected_element_structure): - dataset = dataset_ops.Dataset.from_tensors(0).map(lambda _: tf_value_fn()) - dataset_structure = structure.Structure.from_value(dataset) - self.assertIsInstance(dataset_structure, dataset_ops.DatasetStructure) - - # TODO(b/110122868): Add a public API to `tf.data.Dataset` for accessing - # the element structure. - self.assertTrue(expected_element_structure.is_compatible_with( - dataset_structure._element_structure)) - self.assertTrue(dataset_structure._element_structure.is_compatible_with( - expected_element_structure)) - - self.assertEqual([dtypes.variant], dataset_structure._flat_types) - self.assertEqual([tensor_shape.scalar()], dataset_structure._flat_shapes) - - # Assert that the `Dataset` survives a round-trip via _from_tensor_list() - # and _to_tensor_list(). - round_trip_dataset = dataset_structure._from_tensor_list( - dataset_structure._to_tensor_list(dataset)) - - value = tf_value_fn() - - if isinstance(value, dataset_ops.Dataset): - self.assertDatasetsEqual(value, dataset.flat_map(lambda x: x)) - elif isinstance(value, optional_ops.Optional): - self.assertDatasetProduces( - round_trip_dataset.map(lambda opt: opt.get_value()), - [self.evaluate(value.get_value())], - requires_initialization=True) - else: - self.assertDatasetProduces( - round_trip_dataset, [self.evaluate(tf_value_fn())], - requires_initialization=True) - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 5c0cfe994d..4a11619112 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -31,7 +31,6 @@ from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.util import nest from tensorflow.python.data.util import random_seed from tensorflow.python.data.util import sparse -from tensorflow.python.data.util import structure as structure_lib from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -1869,6 +1868,57 @@ class SparseTensorSliceDataset(DatasetSource): return (dtypes.int64, self._sparse_tensor.dtype, dtypes.int64) +class _NestedDatasetComponent(object): + """The structure of a `Dataset` nested in a component of another `Dataset`. + + A `StructuredFunctionWrapper` around a function that returns a `Dataset` as + one of its components will have a `NestedDatasetComponent` in the + corresponding position in the `output_classes`, `output_shapes`, and + `output_types` properties. + + TODO(b/110122868): Add this class, or something equivalent, to the public API. + We are considering revising the public API for accessing Dataset structure + (`output_classes` etc.) based on experience with nested datasets and other + custom component types. + """ + + def __init__(self, + dataset=None, + output_shapes=None, + output_types=None, + output_classes=None): + if dataset is None: + if (output_classes is None or output_shapes is None or + output_types is None): + raise ValueError( + "Either `dataset`, or all of `output_classes`, " + "`output_shapes`, and `output_types` must be specified.") + self._output_classes = output_classes + self._output_shapes = output_shapes + self._output_types = output_types + else: + if not (output_classes is None and output_shapes is None and + output_types is None): + raise ValueError( + "Either `dataset`, or all of `output_classes`, " + "`output_shapes`, and `output_types` must be specified.") + self._output_classes = dataset.output_classes + self._output_shapes = dataset.output_shapes + self._output_types = dataset.output_types + + @property + def output_classes(self): + return self._output_classes + + @property + def output_shapes(self): + return self._output_shapes + + @property + def output_types(self): + return self._output_types + + class _VariantDataset(DatasetV2): """A Dataset wrapper around a `tf.variant`-typed function argument.""" @@ -1885,73 +1935,15 @@ class _VariantDataset(DatasetV2): @property def output_classes(self): - return self._structure._to_legacy_output_classes() # pylint: disable=protected-access + return self._structure.output_classes @property def output_shapes(self): - return self._structure._to_legacy_output_shapes() # pylint: disable=protected-access + return self._structure.output_shapes @property def output_types(self): - return self._structure._to_legacy_output_types() # pylint: disable=protected-access - - -class DatasetStructure(structure_lib.Structure): - """Represents a `Dataset` of structured values.""" - - def __init__(self, element_structure): - self._element_structure = element_structure - - @property - def _flat_shapes(self): - return [tensor_shape.scalar()] - - @property - def _flat_types(self): - return [dtypes.variant] - - def is_compatible_with(self, other): - # pylint: disable=protected-access - return (isinstance(other, DatasetStructure) and - self._element_structure.is_compatible_with( - other._element_structure)) - - def _to_tensor_list(self, value): - return [value._as_variant_tensor()] # pylint: disable=protected-access - - def _from_tensor_list(self, flat_value): - if (len(flat_value) != 1 or flat_value[0].dtype != dtypes.variant or - not flat_value[0].shape.is_compatible_with(tensor_shape.scalar())): - raise ValueError( - "DatasetStructure corresponds to a single tf.variant scalar.") - return self._from_compatible_tensor_list(flat_value) - - def _from_compatible_tensor_list(self, flat_value): - # pylint: disable=protected-access - return _VariantDataset(flat_value[0], self._element_structure) - - @staticmethod - def from_value(value): - # TODO(b/110122868): We can simplify this when a `Dataset` object has a - # `Structure`-valued property. - element_structure = structure_lib.Structure._from_legacy_structure( - value.output_types, value.output_shapes, value.output_classes) - return DatasetStructure(element_structure) - - def _to_legacy_output_types(self): - return self - - def _to_legacy_output_shapes(self): - return self - - def _to_legacy_output_classes(self): - return self - - -# pylint: disable=protected-access -structure_lib.Structure._register_custom_converter(DatasetV2, - DatasetStructure.from_value) -# pylint: enable=protected-access + return self._structure.output_types class StructuredFunctionWrapper(object): @@ -2009,9 +2001,6 @@ class StructuredFunctionWrapper(object): self._input_types = dataset.output_types self._input_classes = dataset.output_classes - self._input_structure = structure_lib.Structure._from_legacy_structure( # pylint: disable=protected-access - self._input_types, self._input_shapes, self._input_classes) - self._transformation_name = transformation_name readable_transformation_name = transformation_name.replace( ".", "_")[:-2] if len(transformation_name) > 2 else "" @@ -2019,18 +2008,35 @@ class StructuredFunctionWrapper(object): readable_transformation_name, function_utils.get_func_name(func), str(ops.uid()) + ]) if defun_kwargs is None: defun_kwargs = {} @function.Defun( - *self._input_structure._flat_types, func_name=self._func_name, # pylint: disable=protected-access - **defun_kwargs) + *self._defun_args(), func_name=self._func_name, **defun_kwargs) def tf_data_structured_function_wrapper(*args): """Wrapper for passing nested structures to and from tf.data functions.""" - # pylint: disable=protected-access - nested_args = self._input_structure._from_compatible_tensor_list(args) + flat_args = [] + for arg, arg_class, arg_shape, arg_type in zip( + args, + nest.flatten(self._input_classes), + nest.flatten(self._input_shapes), + nest.flatten(self._input_types)): + # TODO(b/110122868): Add a registration mechanism for new component + # types. + if arg_class is sparse_tensor_lib.SparseTensor: + arg = sparse.deserialize_sparse_tensors( + arg, arg_type, arg_shape, arg_class) + arg.indices.set_shape([None, arg_shape.ndims]) + arg.dense_shape.set_shape([arg_shape.ndims]) + elif isinstance(arg_class, _NestedDatasetComponent): + arg = _VariantDataset(arg, arg_class) + else: + arg.set_shape(arg_shape) + flat_args.append(arg) + nested_args = nest.pack_sequence_as(self._input_classes, flat_args) if not _should_unpack_args(nested_args): nested_args = (nested_args,) @@ -2048,14 +2054,50 @@ class StructuredFunctionWrapper(object): if isinstance(ret, list): ret = tuple(ret) - try: - self._output_structure = structure_lib.Structure.from_value(ret) - except (ValueError, TypeError): - raise TypeError("Unsupported return value from function passed to " - "%s: %s." % (transformation_name, ret)) + # Convert any `SparseTensorValue`s to `SparseTensor`s and all other + # values to tensors. + flat_ret = [] + flat_classes = [] + flat_shapes = [] + flat_types = [] + for t in nest.flatten(ret): + # TODO(b/110122868): Add a registration mechanism for new component + # types. + if sparse_tensor_lib.is_sparse(t): + t = sparse_tensor_lib.SparseTensor.from_value(t) + flat_ret.append(sparse.serialize_sparse_tensors(t)) + flat_classes.append(sparse_tensor_lib.SparseTensor) + flat_shapes.append(t.get_shape()) + flat_types.append(t.dtype) + elif isinstance(t, DatasetV2): + flat_ret.append(t._as_variant_tensor()) # pylint: disable=protected-access + component = _NestedDatasetComponent(t) + flat_classes.append(component) + flat_shapes.append(component) + flat_types.append(component) + if t.options() != Options(): + warnings.warn("Encountered a nested dataset with non-default " + "options. These options will not be propagated to " + "the outer dataset.") + else: + try: + t = ops.convert_to_tensor(t) + except (ValueError, TypeError): + raise TypeError("Unsupported return value from function passed to " + "%s: %s." % (transformation_name, t)) + flat_ret.append(t) + flat_classes.append(ops.Tensor) + flat_shapes.append(t.get_shape()) + flat_types.append(t.dtype) + + ret = nest.pack_sequence_as(ret, flat_ret) + self._output_classes = nest.pack_sequence_as(ret, flat_classes) + self._output_shapes = nest.pack_sequence_as(ret, flat_shapes) + self._output_types = nest.pack_sequence_as(ret, flat_types) _warn_if_collections(transformation_name) - return self._output_structure._to_tensor_list(ret) + + return flat_ret self._function = tf_data_structured_function_wrapper if add_to_graph: @@ -2066,21 +2108,32 @@ class StructuredFunctionWrapper(object): # in case (e.g.) we need to rerun the function. self._function._create_definition_if_needed() # pylint: disable=protected-access - @property - def output_structure(self): - return self._output_structure + def _defun_args(self): + """Returns a flat list of `tf.DType` for the input element structure.""" + ret = [] + for input_type, input_class in zip(nest.flatten(self._input_types), + nest.flatten(self._input_classes)): + # TODO(b/110122868): Add a registration mechanism for new component types. + if input_class is sparse_tensor_lib.SparseTensor: + ret.append(dtypes.variant) + elif isinstance(input_class, _NestedDatasetComponent): + ret.append(dtypes.variant) + else: + assert isinstance(input_type, dtypes.DType) + ret.append(input_type) + return ret @property def output_classes(self): - return self._output_structure._to_legacy_output_classes() # pylint: disable=protected-access + return self._output_classes @property def output_shapes(self): - return self._output_structure._to_legacy_output_shapes() # pylint: disable=protected-access + return self._output_shapes @property def output_types(self): - return self._output_structure._to_legacy_output_types() # pylint: disable=protected-access + return self._output_types @property def function(self): @@ -2103,12 +2156,30 @@ def flat_structure(dataset): A dictionary of keyword arguments that can be passed to many Dataset op constructors. """ - # pylint: disable=protected-access - structure = structure_lib.Structure._from_legacy_structure( - dataset.output_types, dataset.output_shapes, dataset.output_classes) + output_classes = [] + output_shapes = [] + output_types = [] + for output_class, output_shape, output_type in zip( + nest.flatten(dataset.output_classes), nest.flatten(dataset.output_shapes), + nest.flatten(dataset.output_types)): + if isinstance(output_class, _NestedDatasetComponent): + output_classes.append(output_class.output_classes) + output_shapes.append(output_shape.output_shapes) + output_types.append(output_type.output_types) + else: + output_classes.append(output_class) + output_shapes.append(output_shape) + output_types.append(output_type) + + output_classes = nest.pack_sequence_as(dataset.output_classes, output_classes) + output_shapes = nest.pack_sequence_as(dataset.output_shapes, output_shapes) + output_types = nest.pack_sequence_as(dataset.output_types, output_types) + return { - "output_shapes": structure._flat_shapes, - "output_types": structure._flat_types, + "output_shapes": + nest.flatten(sparse.as_dense_shapes(output_shapes, output_classes)), + "output_types": + nest.flatten(sparse.as_dense_types(output_types, output_classes)), } @@ -2831,13 +2902,11 @@ class FlatMapDataset(UnaryDataset): wrapped_func = StructuredFunctionWrapper( map_func, self._transformation_name(), dataset=input_dataset) - if not isinstance(wrapped_func.output_structure, DatasetStructure): + if not isinstance(wrapped_func.output_classes, _NestedDatasetComponent): raise TypeError("`map_func` must return a `Dataset` object.") - # pylint: disable=protected-access - element_structure = wrapped_func.output_structure._element_structure - self._output_classes = element_structure._to_legacy_output_classes() - self._output_types = element_structure._to_legacy_output_types() - self._output_shapes = element_structure._to_legacy_output_shapes() + self._output_classes = wrapped_func.output_classes.output_classes + self._output_types = wrapped_func.output_types.output_types + self._output_shapes = wrapped_func.output_shapes.output_shapes self._map_func = wrapped_func.function def _as_variant_tensor(self): @@ -2979,9 +3048,10 @@ class WindowDataset(UnaryDataset): self._output_classes = nest.pack_sequence_as( input_dataset.output_classes, [ - DatasetStructure( - structure_lib.Structure._from_legacy_structure( # pylint: disable=protected-access - output_type, output_shape, output_class)) + _NestedDatasetComponent( # pylint: disable=protected-access + output_classes=output_class, + output_shapes=output_shape, + output_types=output_type) for output_class, output_shape, output_type in zip( nest.flatten(input_dataset.output_classes), nest.flatten(input_dataset.output_shapes), diff --git a/tensorflow/python/data/ops/optional_ops.py b/tensorflow/python/data/ops/optional_ops.py index 4113b7ed31..91cf883ce9 100644 --- a/tensorflow/python/data/ops/optional_ops.py +++ b/tensorflow/python/data/ops/optional_ops.py @@ -183,13 +183,19 @@ class OptionalStructure(structure.Structure): return OptionalStructure(value.value_structure) def _to_legacy_output_types(self): - return self + raise NotImplementedError("The `output_types` property is not supported on " + "structured objects containing an `Optional`. " + "Use the corresponding `structure` property.") def _to_legacy_output_shapes(self): - return self + raise NotImplementedError("The `output_shapes` property is not supported on" + " structured objects containing an `Optional`. " + "Use the corresponding `structure` property.") def _to_legacy_output_classes(self): - return self + raise NotImplementedError("The `output_classes` property is not supported " + "on structured objects containing an `Optional`. " + "Use the corresponding `structure` property.") # pylint: disable=protected-access diff --git a/tensorflow/python/data/util/structure.py b/tensorflow/python/data/util/structure.py index 3cf67b0745..9a3118297d 100644 --- a/tensorflow/python/data/util/structure.py +++ b/tensorflow/python/data/util/structure.py @@ -208,16 +208,14 @@ class Structure(object): flat_ret = [] for flat_type, flat_shape, flat_class in zip(flat_types, flat_shapes, flat_classes): - if isinstance(flat_class, Structure): - flat_ret.append(flat_class) - elif issubclass(flat_class, sparse_tensor_lib.SparseTensor): + if issubclass(flat_class, sparse_tensor_lib.SparseTensor): flat_ret.append(SparseTensorStructure(flat_type, flat_shape)) elif issubclass(flat_class, ops.Tensor): flat_ret.append(TensorStructure(flat_type, flat_shape)) else: # NOTE(mrry): Since legacy structures produced by iterators only - # comprise Tensors, SparseTensors, and nests, we do not need to - # support all structure types here. + # comprise Tensors, SparseTensors, and nests, we do not need to support + # all structure types here. raise TypeError( "Could not build a structure for output class %r" % flat_type) @@ -383,13 +381,6 @@ class TensorStructure(Structure): return self._from_compatible_tensor_list(flat_value) def _from_compatible_tensor_list(self, flat_value): - # TODO(b/112266545): It would be cleaner to create a new `ensure_shape()` - # op here and return that, instead of mutating the input's shape using - # `Tensor.set_shape()`. However, that would add extra ops on the arguments - # of each `tf.data` function, which could impact performance. When this - # bug is resolved, we should be able to add the `ensure_shape()` ops and - # optimize them away using contextual shape information. - flat_value[0].set_shape(self._shape) return flat_value[0] @staticmethod @@ -415,11 +406,7 @@ class SparseTensorStructure(Structure): @property def _flat_shapes(self): - # NOTE(mrry): The default flat shape of a boxed `SparseTensor` is `(3,)`, - # but a `SparseTensorStructure` can also represent a batch of boxed - # `SparseTensor` objects with shape `(?, 3)` (and batches of batches, etc.), - # so the flat shape must be unknown. - return [tensor_shape.unknown_shape(None)] + return [tensor_shape.vector(3)] @property def _flat_types(self): @@ -441,11 +428,8 @@ class SparseTensorStructure(Structure): return self._from_compatible_tensor_list(flat_value) def _from_compatible_tensor_list(self, flat_value): - ret = sparse_ops.deserialize_sparse( + return sparse_ops.deserialize_sparse( flat_value[0], dtype=self._dtype, rank=self._dense_shape.ndims) - ret.indices.set_shape([None, self._dense_shape.ndims]) - ret.dense_shape.set_shape([self._dense_shape.ndims]) - return ret @staticmethod def from_value(value): diff --git a/tensorflow/python/data/util/structure_test.py b/tensorflow/python/data/util/structure_test.py index 65a41a50f1..630a0c912b 100644 --- a/tensorflow/python/data/util/structure_test.py +++ b/tensorflow/python/data/util/structure_test.py @@ -44,7 +44,7 @@ class StructureTest(test.TestCase, parameterized.TestCase): [dtypes.float32], [[]]), (lambda: sparse_tensor.SparseTensor( indices=[[3, 4]], values=[-1], dense_shape=[4, 5]), - structure.SparseTensorStructure, [dtypes.variant], [None]), + structure.SparseTensorStructure, [dtypes.variant], [[3]]), (lambda: (constant_op.constant(37.0), constant_op.constant([1, 2, 3])), structure.NestedStructure, [dtypes.float32, dtypes.int32], [[], [3]]), (lambda: { @@ -58,17 +58,14 @@ class StructureTest(test.TestCase, parameterized.TestCase): sparse_tensor.SparseTensor( indices=[[3, 4]], values=[-1], dense_shape=[4, 5])) }, structure.NestedStructure, - [dtypes.float32, dtypes.variant, dtypes.variant], [[], None, None])) + [dtypes.float32, dtypes.variant, dtypes.variant], [[], [3], [3]])) def testFlatStructure(self, value_fn, expected_structure, expected_types, expected_shapes): value = value_fn() s = structure.Structure.from_value(value) self.assertIsInstance(s, expected_structure) self.assertEqual(expected_types, s._flat_types) - for expected, actual in zip(expected_shapes, s._flat_shapes): - self.assertTrue(actual.is_compatible_with(expected)) - self.assertTrue( - tensor_shape.as_shape(expected).is_compatible_with(actual)) + self.assertEqual(expected_shapes, s._flat_shapes) @parameterized.parameters( (lambda: constant_op.constant(37.0), lambda: [ -- GitLab From b64c750d37d6d59d853e0f75e89fdae498dffb03 Mon Sep 17 00:00:00 2001 From: Sami Kama Date: Tue, 20 Nov 2018 14:24:48 -0800 Subject: [PATCH 151/672] Revert buildifier changes and exclude nccl kernels for windows builds --- tensorflow/core/BUILD | 114 +++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 3237c34a99..41d3f6eab8 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -1349,63 +1349,63 @@ cc_library( name = "all_kernels_statically_linked", visibility = ["//visibility:private"], deps = [ - "//tensorflow/core/kernels:array", - "//tensorflow/core/kernels:audio", - "//tensorflow/core/kernels:batch_kernels", - "//tensorflow/core/kernels:bincount_op", - "//tensorflow/core/kernels:boosted_trees_ops", - "//tensorflow/core/kernels:candidate_sampler_ops", - "//tensorflow/core/kernels:checkpoint_ops", - "//tensorflow/core/kernels:collective_ops", - "//tensorflow/core/kernels:control_flow_ops", - "//tensorflow/core/kernels:ctc_ops", - "//tensorflow/core/kernels:cudnn_rnn_kernels", - "//tensorflow/core/kernels:data_flow", - "//tensorflow/core/kernels:dataset_ops", - "//tensorflow/core/kernels:decode_proto_op", - "//tensorflow/core/kernels:encode_proto_op", - "//tensorflow/core/kernels:fake_quant_ops", - "//tensorflow/core/kernels:function_ops", - "//tensorflow/core/kernels:functional_ops", - "//tensorflow/core/kernels:grappler", - "//tensorflow/core/kernels:histogram_op", - "//tensorflow/core/kernels:image", - "//tensorflow/core/kernels:io", - "//tensorflow/core/kernels:linalg", - "//tensorflow/core/kernels:list_kernels", - "//tensorflow/core/kernels:lookup", - "//tensorflow/core/kernels:logging", - "//tensorflow/core/kernels:manip", - "//tensorflow/core/kernels:math", - "//tensorflow/core/kernels:multinomial_op", - "//tensorflow/core/kernels:nn", - "//tensorflow/core/kernels:parameterized_truncated_normal_op", - "//tensorflow/core/kernels:parsing", - "//tensorflow/core/kernels:partitioned_function_ops", - "//tensorflow/core/kernels:ragged_ops", - "//tensorflow/core/kernels:random_ops", - "//tensorflow/core/kernels:random_poisson_op", - "//tensorflow/core/kernels:remote_fused_graph_ops", - "//tensorflow/core/kernels:required", - "//tensorflow/core/kernels:resource_variable_ops", - "//tensorflow/core/kernels:rpc_op", - "//tensorflow/core/kernels:scoped_allocator_ops", - "//tensorflow/core/kernels:sdca_ops", - "//tensorflow/core/kernels:searchsorted_op", - "//tensorflow/core/kernels:set_kernels", - "//tensorflow/core/kernels:sparse", - "//tensorflow/core/kernels:state", - "//tensorflow/core/kernels:stateless_random_ops", - "//tensorflow/core/kernels:string", - "//tensorflow/core/kernels:summary_kernels", - "//tensorflow/core/kernels:training_ops", - "//tensorflow/core/kernels:word2vec_kernels", - ] + tf_additional_cloud_kernel_deps() + - select({ - "//tensorflow:no_nccl_support": [], - "//tensorflow:with_cuda_support_windows_override": [], - "//conditions:default": ["//tensorflow/core/kernels:nccl_kernels"], - }) + if_not_windows([ + "//tensorflow/core/kernels:array", + "//tensorflow/core/kernels:audio", + "//tensorflow/core/kernels:batch_kernels", + "//tensorflow/core/kernels:bincount_op", + "//tensorflow/core/kernels:boosted_trees_ops", + "//tensorflow/core/kernels:candidate_sampler_ops", + "//tensorflow/core/kernels:checkpoint_ops", + "//tensorflow/core/kernels:collective_ops", + "//tensorflow/core/kernels:control_flow_ops", + "//tensorflow/core/kernels:ctc_ops", + "//tensorflow/core/kernels:cudnn_rnn_kernels", + "//tensorflow/core/kernels:data_flow", + "//tensorflow/core/kernels:dataset_ops", + "//tensorflow/core/kernels:decode_proto_op", + "//tensorflow/core/kernels:encode_proto_op", + "//tensorflow/core/kernels:fake_quant_ops", + "//tensorflow/core/kernels:function_ops", + "//tensorflow/core/kernels:functional_ops", + "//tensorflow/core/kernels:grappler", + "//tensorflow/core/kernels:histogram_op", + "//tensorflow/core/kernels:image", + "//tensorflow/core/kernels:io", + "//tensorflow/core/kernels:linalg", + "//tensorflow/core/kernels:list_kernels", + "//tensorflow/core/kernels:lookup", + "//tensorflow/core/kernels:logging", + "//tensorflow/core/kernels:manip", + "//tensorflow/core/kernels:math", + "//tensorflow/core/kernels:multinomial_op", + "//tensorflow/core/kernels:nn", + "//tensorflow/core/kernels:parameterized_truncated_normal_op", + "//tensorflow/core/kernels:parsing", + "//tensorflow/core/kernels:partitioned_function_ops", + "//tensorflow/core/kernels:ragged_ops", + "//tensorflow/core/kernels:random_ops", + "//tensorflow/core/kernels:random_poisson_op", + "//tensorflow/core/kernels:remote_fused_graph_ops", + "//tensorflow/core/kernels:required", + "//tensorflow/core/kernels:resource_variable_ops", + "//tensorflow/core/kernels:rpc_op", + "//tensorflow/core/kernels:scoped_allocator_ops", + "//tensorflow/core/kernels:sdca_ops", + "//tensorflow/core/kernels:searchsorted_op", + "//tensorflow/core/kernels:set_kernels", + "//tensorflow/core/kernels:sparse", + "//tensorflow/core/kernels:state", + "//tensorflow/core/kernels:stateless_random_ops", + "//tensorflow/core/kernels:string", + "//tensorflow/core/kernels:summary_kernels", + "//tensorflow/core/kernels:training_ops", + "//tensorflow/core/kernels:word2vec_kernels", + ] + tf_additional_cloud_kernel_deps() + + select({ + "//tensorflow:no_nccl_support": [], + "//tensorflow:windows": [], + "//conditions:default": ["//tensorflow/core/kernels:nccl_kernels"], + }) + if_not_windows([ "//tensorflow/core/kernels:fact_op", "//tensorflow/core/kernels:array_not_windows", "//tensorflow/core/kernels:math_not_windows", -- GitLab From baad4e65fc8c4e5313e70bfd9fe0240cd0972842 Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Tue, 20 Nov 2018 14:21:31 -0800 Subject: [PATCH 152/672] Remove some `num_gpus` and `auto_shard_dataset` from CoreMirroredStrategy. PiperOrigin-RevId: 222306139 --- .../python/cross_device_ops_test.py | 16 ++-- .../python/estimator_training_test.py | 8 +- .../distribute/python/mirrored_strategy.py | 94 ++++++------------- .../python/mirrored_strategy_multigpu_test.py | 32 ++++--- 4 files changed, 62 insertions(+), 88 deletions(-) diff --git a/tensorflow/contrib/distribute/python/cross_device_ops_test.py b/tensorflow/contrib/distribute/python/cross_device_ops_test.py index a0f7cf182c..40410b90be 100644 --- a/tensorflow/contrib/distribute/python/cross_device_ops_test.py +++ b/tensorflow/contrib/distribute/python/cross_device_ops_test.py @@ -381,27 +381,31 @@ class MultiWorkerCrossDeviceOpsTest(multi_worker_test_base.MultiWorkerTestBase, distribution=[ combinations.NamedDistribution( "MirroredCPU", - lambda: mirrored_strategy.MirroredStrategy(num_gpus=0), + lambda: mirrored_strategy.MirroredStrategy(num_gpus_per_worker=0), required_gpus=0), combinations.NamedDistribution( "Mirrored1GPU", - lambda: mirrored_strategy.MirroredStrategy(num_gpus=1), + lambda: mirrored_strategy.MirroredStrategy(num_gpus_per_worker=1), required_gpus=1), combinations.NamedDistribution( "Mirrored2GPUs", - lambda: mirrored_strategy.MirroredStrategy(num_gpus=2), + lambda: mirrored_strategy.MirroredStrategy(num_gpus_per_worker=2), required_gpus=2), + # pylint: disable=g-long-lambda combinations.NamedDistribution( "CoreMirroredCPU", - lambda: mirrored_strategy.CoreMirroredStrategy(num_gpus=0), + lambda: mirrored_strategy.CoreMirroredStrategy( + num_gpus_per_worker=0), required_gpus=0), combinations.NamedDistribution( "CoreMirrored1GPU", - lambda: mirrored_strategy.CoreMirroredStrategy(num_gpus=1), + lambda: mirrored_strategy.CoreMirroredStrategy( + num_gpus_per_worker=1), required_gpus=1), combinations.NamedDistribution( "CoreMirrored2GPUs", - lambda: mirrored_strategy.CoreMirroredStrategy(num_gpus=2), + lambda: mirrored_strategy.CoreMirroredStrategy( + num_gpus_per_worker=2), required_gpus=2), ], mode=["graph"]) diff --git a/tensorflow/contrib/distribute/python/estimator_training_test.py b/tensorflow/contrib/distribute/python/estimator_training_test.py index 202e92d1e7..0f35657a80 100644 --- a/tensorflow/contrib/distribute/python/estimator_training_test.py +++ b/tensorflow/contrib/distribute/python/estimator_training_test.py @@ -522,7 +522,7 @@ class RunConfigTest(test.TestCase): run_config_lib.RunConfig( experimental_distribute=DistributeConfig( train_distribute=mirrored_strategy.CoreMirroredStrategy( - num_gpus=2))) + num_gpus_per_worker=2))) def test_should_run_distribute_coordinator(self): """Tests that should_run_distribute_coordinator return a correct value.""" @@ -546,11 +546,11 @@ class RunConfigTest(test.TestCase): config_with_train_distribute = run_config_lib.RunConfig( experimental_distribute=DistributeConfig( train_distribute=mirrored_strategy.CoreMirroredStrategy( - num_gpus=2))) + num_gpus_per_worker=2))) config_with_eval_distribute = run_config_lib.RunConfig( experimental_distribute=DistributeConfig( eval_distribute=mirrored_strategy.CoreMirroredStrategy( - num_gpus=2))) + num_gpus_per_worker=2))) self.assertTrue( dc_training.should_run_distribute_coordinator( config_with_train_distribute)) @@ -564,7 +564,7 @@ class RunConfigTest(test.TestCase): config = run_config_lib.RunConfig( experimental_distribute=DistributeConfig( train_distribute=mirrored_strategy.CoreMirroredStrategy( - num_gpus=2))) + num_gpus_per_worker=2))) self.assertFalse(dc_training.should_run_distribute_coordinator(config)) def test_init_run_config_duplicate_distribute(self): diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy.py b/tensorflow/contrib/distribute/python/mirrored_strategy.py index a2ab95487a..d671d1d562 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy.py @@ -303,58 +303,21 @@ class CoreMirroredStrategy(distribute_lib.DistributionStrategy): This strategy uses one replica per device and sync replication for its multi-GPU version. - When `cluster_spec` is given by the `configure` method., it turns into the - mulit-worker version that works on multiple workers with in-graph replication. - Note: `configure` will be called by higher-level APIs if running in - distributed environment. - - There are several important concepts for distributed TensorFlow, e.g. - `client`, `job`, 'task', `cluster`, `in-graph replication` and - 'synchronous training' and they have already been defined in the - [TensorFlow's documentation](https://www.tensorflow.org/deploy/distributed). - The distribution strategy inherits these concepts as well and in addition to - that we also clarify several more concepts: - - * **In-graph replication**: the `client` creates a single `tf.Graph` that - specifies tasks for devices on all workers. The `client` then creates a - client session which will talk to the `master` service of a `worker`. Then - the `master` will partition the graph and distribute the work to all - participating workers. - * **Worker**: A `worker` is a TensorFlow `task` that usually maps to one - physical machine. We will have multiple `worker`s with different `task` - index. They all do similar things except for one worker checkpointing model - variables, writing summaries, etc. in addition to its ordinary work. - - The multi-worker version of this class maps one replica to one device on a - worker. It mirrors all model variables on all replicas. For example, if you - have two `worker`s and each `worker` has 4 GPUs, it will create 8 copies of - the model variables on these 8 GPUs. Then like in MirroredStrategy, each - replica performs their computation with their own copy of variables unless in - cross-replica model where variable or tensor reduction happens. + The multi-worker version will be added in the fture. Args: devices: a list of device strings. - num_gpus: number of GPUs. For local training, either specify `devices` or - `num_gpus`. In distributed training, this must be specified as number of - GPUs on each worker. - num_gpus_per_worker: number of GPUs per worker. This is the same as - `num_gpus` and only one of `num_gpus` and `num_gpus_per_worker` can be - specified. + num_gpus_per_worker: number of GPUs per worker. cross_device_ops: optional, a descedant of `CrossDeviceOps`. If this is not - set, the `configure` method will try to find the best one. - auto_shard_dataset: whether to auto-shard the dataset when there are - multiple workers. + set, nccl will be use by default. """ def __init__(self, devices=None, - num_gpus=None, num_gpus_per_worker=None, - cross_device_ops=None, - auto_shard_dataset=False): - extended = CoreMirroredExtended( - self, devices, num_gpus, num_gpus_per_worker, - cross_device_ops, auto_shard_dataset) + cross_device_ops=None): + extended = CoreMirroredExtended(self, devices, num_gpus_per_worker, + cross_device_ops) super(CoreMirroredStrategy, self).__init__(extended) @@ -364,21 +327,12 @@ class CoreMirroredExtended(distribute_lib.DistributionStrategyExtended): def __init__(self, container_strategy, devices=None, - num_gpus=None, num_gpus_per_worker=None, - cross_device_ops=None, - auto_shard_dataset=False): + cross_device_ops=None): super(CoreMirroredExtended, self).__init__(container_strategy) self._cross_device_ops = cross_device_ops - self._auto_shard_dataset = auto_shard_dataset # Remember num GPUs which might be needed by `configure` method. - if num_gpus is not None and num_gpus_per_worker is not None: - raise ValueError( - "You cannot specify both `num_gpus` and `num_gpus_per_worker`.") - if num_gpus is not None: - self._num_gpus = num_gpus - else: - self._num_gpus = num_gpus_per_worker + self._num_gpus = num_gpus_per_worker self._initialize_local(self._num_gpus, devices) @@ -493,8 +447,9 @@ class CoreMirroredExtended(distribute_lib.DistributionStrategyExtended): def _distribute_dataset(self, dataset_fn): if self._cluster_spec: return values.MultiWorkerDataset( - partial(self._call_dataset_fn, dataset_fn), self._worker_devices, - auto_shard=self._auto_shard_dataset) + partial(self._call_dataset_fn, dataset_fn), + self._worker_devices, + auto_shard=False) else: return values.PerReplicaDataset( self._call_dataset_fn(dataset_fn), self._devices) @@ -873,26 +828,29 @@ class MirroredStrategy(distribute_lib.DistributionStrategy): auto_shard_dataset=False, cross_tower_ops=None): assert not (cross_device_ops and cross_tower_ops) - extended = MirroredExtended( - self, devices, num_gpus, num_gpus_per_worker, - cross_device_ops or cross_tower_ops, auto_shard_dataset) + if num_gpus is not None and num_gpus_per_worker is not None: + raise ValueError( + "You cannot specify both `num_gpus` and `num_gpus_per_worker`.") + if num_gpus is None: + num_gpus = num_gpus_per_worker + extended = MirroredExtended(self, devices, num_gpus, + cross_device_ops or cross_tower_ops, + auto_shard_dataset) super(MirroredStrategy, self).__init__(extended) class MirroredExtended(CoreMirroredExtended): """Implementation of (contrib) MirroredStrategy.""" - # pylint: disable=useless-super-delegation def __init__(self, container_strategy, devices=None, - num_gpus=None, num_gpus_per_worker=None, cross_device_ops=None, auto_shard_dataset=False): super(MirroredExtended, self).__init__( - container_strategy, devices, num_gpus, num_gpus_per_worker, - cross_device_ops, auto_shard_dataset) + container_strategy, devices, num_gpus_per_worker, cross_device_ops) + self._auto_shard_dataset = auto_shard_dataset def _make_dataset_iterator(self, dataset): """Make iterator from dataset without splitting the batch. @@ -912,6 +870,16 @@ class MirroredExtended(CoreMirroredExtended): worker_device_pairs = [("/job:localhost", self._devices)] return values.DatasetIterator(dataset, worker_device_pairs) + def _distribute_dataset(self, dataset_fn): + if self._cluster_spec: + return values.MultiWorkerDataset( + partial(self._call_dataset_fn, dataset_fn), + self._worker_devices, + auto_shard=self._auto_shard_dataset) + else: + return values.PerReplicaDataset( + self._call_dataset_fn(dataset_fn), self._devices) + class MirroredReplicaContext(distribute_lib.ReplicaContext): """ReplicaContext used in MirroredStrategy.call_for_each_replica(). diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py index d20ac144bf..1027da857d 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py @@ -1304,21 +1304,23 @@ class MirroredStrategyDefunTest(test.TestCase): self.assertAllEqual([0.5], updated_var_values[1]) -@combinations.generate(combinations.combine( - distribution=[ - combinations.NamedDistribution( - "Mirrored", - # pylint: disable=g-long-lambda - lambda: mirrored_strategy.CoreMirroredStrategy( - num_gpus=context.num_gpus()), - required_gpus=1), - combinations.NamedDistribution( - "CoreMirrored", - # pylint: disable=g-long-lambda - lambda: mirrored_strategy.CoreMirroredStrategy( - num_gpus=context.num_gpus()), - required_gpus=1)], - mode=["graph"])) +@combinations.generate( + combinations.combine( + distribution=[ + combinations.NamedDistribution( + "Mirrored", + # pylint: disable=g-long-lambda + lambda: mirrored_strategy.CoreMirroredStrategy( + num_gpus_per_worker=context.num_gpus()), + required_gpus=1), + combinations.NamedDistribution( + "CoreMirrored", + # pylint: disable=g-long-lambda + lambda: mirrored_strategy.CoreMirroredStrategy( + num_gpus_per_worker=context.num_gpus()), + required_gpus=1) + ], + mode=["graph"])) class MultiWorkerMirroredStrategyTest( multi_worker_test_base.MultiWorkerTestBase, strategy_test_lib.DistributionTestBase): -- GitLab From 81493f17e8538691f7affae4458f5e4b2c1d74ce Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Tue, 20 Nov 2018 14:21:42 -0800 Subject: [PATCH 153/672] Allow TFE_Execute to be invoked in a new thread. Returns an TFE_ExecuteOpOnThreadResult which can be waited upon. PiperOrigin-RevId: 222306168 --- tensorflow/c/BUILD | 4 + tensorflow/c/c_api_experimental.cc | 54 +++++++- tensorflow/c/c_api_experimental.h | 19 +++ tensorflow/c/c_api_experimental_test.cc | 123 ++++++++++++++++++ .../core/common_runtime/eager/context.h | 2 + 5 files changed, 200 insertions(+), 2 deletions(-) diff --git a/tensorflow/c/BUILD b/tensorflow/c/BUILD index 84238ffc1f..71089a87c7 100644 --- a/tensorflow/c/BUILD +++ b/tensorflow/c/BUILD @@ -121,6 +121,7 @@ tf_cuda_library( ":c_api", ":c_api_internal", "//tensorflow/c/eager:c_api", + "//tensorflow/c/eager:c_api_internal", "//tensorflow/compiler/jit:flags", "//tensorflow/contrib/tpu:all_ops", "//tensorflow/core:core_cpu", @@ -274,8 +275,11 @@ tf_cc_test( # the shared library must be able to use core:framework. # linkstatic = tf_kernel_tests_linkstatic(), deps = [ + ":c_api", ":c_api_experimental", ":c_test_util", + "//tensorflow/c/eager:c_api", + "//tensorflow/c/eager:c_api_test_util", "//tensorflow/core:lib", "//tensorflow/core:protos_all_cc", "//tensorflow/core:test", diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc index f160f204de..069de45e33 100644 --- a/tensorflow/c/c_api_experimental.cc +++ b/tensorflow/c/c_api_experimental.cc @@ -15,7 +15,10 @@ limitations under the License. #include "tensorflow/c/c_api_experimental.h" +#include "tensorflow/c/c_api.h" #include "tensorflow/c/c_api_internal.h" +#include "tensorflow/c/eager/c_api.h" +#include "tensorflow/c/eager/c_api_internal.h" #include "tensorflow/compiler/jit/flags.h" #include "tensorflow/core/common_runtime/eager/attr_builder.h" #include "tensorflow/core/framework/tensor.pb.h" @@ -8740,8 +8743,55 @@ void TFE_TensorHandlePrintDebugString(TFE_TensorHandle* handle) { TF_DeleteStatus(status); } -TF_CAPI_EXPORT extern void TF_MakeInternalErrorStatus(TF_Status* status, - const char* errMsg) { +struct TFE_ExecuteOpNotification { + TFE_ExecuteOpNotification() : status(TF_NewStatus(), TF_DeleteStatus) {} + tensorflow::Notification n; + std::unique_ptr thread; + std::unique_ptr status; +}; + +TFE_ExecuteOpNotification* TFE_ExecuteOpInNewThread(TFE_Op* op, + TFE_TensorHandle** retvals, + int* num_retvals, + TF_Status* status) { + TFE_ExecuteOpNotification* n = new TFE_ExecuteOpNotification; + + n->thread.reset(op->operation.EagerContext()->TFEnv()->StartThread( + tensorflow::ThreadOptions(), "ExecuteOpThread", + [op, retvals, num_retvals, n]() { + TFE_Execute(op, retvals, num_retvals, n->status.get()); + n->n.Notify(); + })); + + return n; +} + +void TFE_ExecuteOpNotificationWaitAndDelete( + TFE_ExecuteOpNotification* notification, TF_Status* status) { + if (notification == nullptr) { + status->status = tensorflow::errors::InvalidArgument( + "Passed in notification is a nullptr."); + + return; + } + if (notification->thread == nullptr) { + status->status = tensorflow::errors::InvalidArgument( + "Passed in notification didn't start a thread correctly. Cleaning up " + "this notification. Please re-execute the operation to get a new " + "notification."); + + delete notification; + return; + } + + notification->n.WaitForNotification(); + + status->status = notification->status->status; + + delete notification; +} + +void TF_MakeInternalErrorStatus(TF_Status* status, const char* errMsg) { status->status = tensorflow::errors::Internal(errMsg); } diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h index 25c03df518..728445e8fd 100644 --- a/tensorflow/c/c_api_experimental.h +++ b/tensorflow/c/c_api_experimental.h @@ -180,6 +180,25 @@ TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_DequeueVariantTensor( TF_CAPI_EXPORT extern void TFE_TensorHandlePrintDebugString( TFE_TensorHandle* handle); +typedef struct TFE_ExecuteOpNotification TFE_ExecuteOpNotification; + +// Allows invoking a kernel asynchronously, and explicitly returns a +// notification that can be waited upon. This always executes the kernel in a +// new thread. +// 1. `retvals` and `num_retvals` can only be consumed after +// `TFE_ExecuteOp` returns successfully. They shouldn't be used +// if the return is unsuccessful +// 2. These new APIs cannot be used together with the TFE context level async +// support. +TF_CAPI_EXPORT extern TFE_ExecuteOpNotification* TFE_ExecuteOpInNewThread( + TFE_Op* op, TFE_TensorHandle** retvals, int* num_retvals, + TF_Status* status); + +// Waits to complete the op execution, and cleans up the notification. +// Errors reported by op execution are set in `status`. +TF_CAPI_EXPORT extern void TFE_ExecuteOpNotificationWaitAndDelete( + TFE_ExecuteOpNotification* notification, TF_Status* status); + TF_CAPI_EXPORT extern void TF_MakeInternalErrorStatus(TF_Status* status, const char* errMsg); diff --git a/tensorflow/c/c_api_experimental_test.cc b/tensorflow/c/c_api_experimental_test.cc index 881dbaf35a..daa7701b7f 100644 --- a/tensorflow/c/c_api_experimental_test.cc +++ b/tensorflow/c/c_api_experimental_test.cc @@ -15,6 +15,8 @@ limitations under the License. #include "tensorflow/c/c_api_experimental.h" #include "tensorflow/c/c_test_util.h" +#include "tensorflow/c/eager/c_api.h" +#include "tensorflow/c/eager/c_api_test_util.h" #include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/platform/env.h" #include "tensorflow/core/platform/logging.h" @@ -173,5 +175,126 @@ TEST(CAPI_EXPERIMENTAL, IsStateful) { EXPECT_EQ(id, 0); } +TEST(CAPI_EXPERIMENTAL, TFE_ExecuteOpInNewThreadTest_Simple) { + TF_Status* status = TF_NewStatus(); + TFE_ContextOptions* opts = TFE_NewContextOptions(); + TFE_Context* ctx = TFE_NewContext(opts, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_DeleteContextOptions(opts); + + TFE_TensorHandle* m = TestMatrixTensorHandle(); + + TFE_Op* matmul_op = MatMulOp(ctx, m, m); + + TFE_TensorHandle* retvals[1] = {nullptr}; + int num_retvals = 1; + + auto* r = + TFE_ExecuteOpInNewThread(matmul_op, &retvals[0], &num_retvals, status); + + TFE_ExecuteOpNotificationWaitAndDelete(r, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TF_Tensor* t = TFE_TensorHandleResolve(retvals[0], status); + ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + float product[4] = {0}; + EXPECT_EQ(sizeof(product), TF_TensorByteSize(t)); + memcpy(&product[0], TF_TensorData(t), TF_TensorByteSize(t)); + TF_DeleteTensor(t); + EXPECT_EQ(7, product[0]); + EXPECT_EQ(10, product[1]); + EXPECT_EQ(15, product[2]); + EXPECT_EQ(22, product[3]); + + TFE_DeleteOp(matmul_op); + TFE_DeleteTensorHandle(m); + + TFE_DeleteTensorHandle(retvals[0]); + TFE_DeleteContext(ctx); + TF_DeleteStatus(status); +} + +// Perform a send/recv test. Recv blocks, so they need to be executed +// asynchronously. +TEST(CAPI_EXPERIMENTAL, TFE_ExecuteOpInNewThreadTest_Blocking) { + TF_Status* status = TF_NewStatus(); + TFE_ContextOptions* opts = TFE_NewContextOptions(); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_Context* ctx = TFE_NewContext(opts, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_DeleteContextOptions(opts); + + // Returns a 2x2 float32 Tensor on the CPU, with data 1., 2., 3., 4. + TFE_TensorHandle* m = TestMatrixTensorHandle(); + + // Build a send op. + TFE_Op* send_op = TFE_NewOp(ctx, "_Send", status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_OpAddInput(send_op, m, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + string tensor_name = "Tensor"; + TFE_OpSetAttrType(send_op, "T", TF_FLOAT); + TFE_OpSetAttrString(send_op, "tensor_name", tensor_name.c_str(), + tensor_name.size()); + string send_device = "/job:localhost/replica:0/task:0/device:CPU:0"; + TFE_OpSetAttrString(send_op, "send_device", send_device.c_str(), + send_device.size()); + TFE_OpSetAttrInt(send_op, "send_device_incarnation", 1234); + string recv_device = "/job:localhost/replica:0/task:0/device:CPU:0"; + TFE_OpSetAttrString(send_op, "recv_device", recv_device.c_str(), + recv_device.size()); + TFE_OpSetAttrBool(send_op, "client_terminated", true); + + // Build a recv op. + TFE_Op* recv_op = TFE_NewOp(ctx, "_Recv", status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TFE_OpSetAttrType(recv_op, "tensor_type", TF_FLOAT); + TFE_OpSetAttrString(recv_op, "tensor_name", tensor_name.c_str(), + tensor_name.size()); + TFE_OpSetAttrString(recv_op, "send_device", send_device.c_str(), + send_device.size()); + TFE_OpSetAttrInt(recv_op, "send_device_incarnation", 1234); + TFE_OpSetAttrString(recv_op, "recv_device", recv_device.c_str(), + recv_device.size()); + TFE_OpSetAttrBool(recv_op, "client_terminated", true); + + TFE_TensorHandle* send_retvals; + int send_num_retvals = 0; + auto* send_result = TFE_ExecuteOpInNewThread(send_op, &send_retvals, + &send_num_retvals, status); + + TFE_TensorHandle* recv_retvals[1] = {nullptr}; + int recv_num_retvals = 1; + auto* recv_result = TFE_ExecuteOpInNewThread(recv_op, &recv_retvals[0], + &recv_num_retvals, status); + + TFE_ExecuteOpNotificationWaitAndDelete(send_result, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_ExecuteOpNotificationWaitAndDelete(recv_result, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TF_Tensor* t = TFE_TensorHandleResolve(recv_retvals[0], status); + ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + float product[4] = {0}; + EXPECT_EQ(sizeof(product), TF_TensorByteSize(t)); + memcpy(&product[0], TF_TensorData(t), TF_TensorByteSize(t)); + TF_DeleteTensor(t); + EXPECT_EQ(1, product[0]); + EXPECT_EQ(2, product[1]); + EXPECT_EQ(3, product[2]); + EXPECT_EQ(4, product[3]); + + TFE_DeleteOp(send_op); + TFE_DeleteOp(recv_op); + TFE_DeleteTensorHandle(m); + + TFE_DeleteTensorHandle(recv_retvals[0]); + TFE_DeleteContext(ctx); + TF_DeleteStatus(status); +} + } // namespace } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/eager/context.h b/tensorflow/core/common_runtime/eager/context.h index 4de807bde3..51109f8f1a 100644 --- a/tensorflow/core/common_runtime/eager/context.h +++ b/tensorflow/core/common_runtime/eager/context.h @@ -206,6 +206,8 @@ class EagerContext { bool UseSendTensorRPC() { return use_send_tensor_rpc_; } bool PinSmallOpsToCPU() { return pin_small_ops_to_cpu_; } + tensorflow::Env* TFEnv() const { return env_; } + private: void InitDeviceMapAndAsync(); Status MaybeRegisterFunctionRemotely(const FunctionDef& fdef); -- GitLab From 178b4349ae1710869c625ec843213584253faeb1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 14:43:22 -0800 Subject: [PATCH 154/672] Adds string deserialization support for V2 Optimizers PiperOrigin-RevId: 222309566 --- tensorflow/python/keras/BUILD | 2 + .../python/keras/optimizer_v2/adamax.py | 14 +++---- .../python/keras/optimizer_v2/adamax_test.py | 28 ++++++------- .../python/keras/optimizer_v2/rmsprop.py | 32 +++++++-------- .../python/keras/optimizer_v2/rmsprop_test.py | 16 ++++---- tensorflow/python/keras/optimizers.py | 39 ++++++++++++++----- tensorflow/python/keras/optimizers_test.py | 38 ++++++++++++++++++ 7 files changed, 114 insertions(+), 55 deletions(-) diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index 37dcc9eb04..81ef941ba6 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -266,6 +266,7 @@ py_test( name = "optimizers_test", size = "medium", srcs = ["optimizers_test.py"], + shard_count = 2, srcs_version = "PY2AND3", tags = ["notsan"], deps = [ @@ -273,6 +274,7 @@ py_test( "//tensorflow/python:client_testlib", "//tensorflow/python:training", "//third_party/py/numpy", + "@absl_py//absl/testing:parameterized", ], ) diff --git a/tensorflow/python/keras/optimizer_v2/adamax.py b/tensorflow/python/keras/optimizer_v2/adamax.py index 6712427f91..7530e629d1 100644 --- a/tensorflow/python/keras/optimizer_v2/adamax.py +++ b/tensorflow/python/keras/optimizer_v2/adamax.py @@ -13,7 +13,7 @@ # limitations under the License. # ============================================================================== -"""AdaMax for TensorFlow.""" +"""Adamax for TensorFlow.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -27,8 +27,8 @@ from tensorflow.python.ops import resource_variable_ops from tensorflow.python.training import training_ops -class AdaMax(adam.Adam): - """Optimizer that implements the AdaMax algorithm. +class Adamax(adam.Adam): + """Optimizer that implements the Adamax algorithm. It is a variant of Adam based on the infinity norm. Default parameters follow those provided in the paper. @@ -44,8 +44,8 @@ class AdaMax(adam.Adam): beta_1=0.9, beta_2=0.999, epsilon=1e-7, - name='AdaMax'): - """Construct a new AdaMax optimizer. + name='Adamax'): + """Construct a new Adamax optimizer. Initialization: @@ -86,10 +86,10 @@ class AdaMax(adam.Adam): rate for the exponentially weighted infinity norm. epsilon: A small constant for numerical stability. name: Optional name for the operations created when applying gradients. - Defaults to "AdaMax". + Defaults to "Adamax". """ # pylint: disable=useless-super-delegation - super(AdaMax, self).__init__(learning_rate, beta_1, beta_2, epsilon, name) + super(Adamax, self).__init__(learning_rate, beta_1, beta_2, epsilon, name) # pylint: enable=useless-super-delegation def _resource_apply_dense(self, grad, var): diff --git a/tensorflow/python/keras/optimizer_v2/adamax_test.py b/tensorflow/python/keras/optimizer_v2/adamax_test.py index 23eb718429..c6b45ccbe9 100644 --- a/tensorflow/python/keras/optimizer_v2/adamax_test.py +++ b/tensorflow/python/keras/optimizer_v2/adamax_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for AdaMax.""" +"""Tests for Adamax.""" from __future__ import absolute_import from __future__ import division @@ -76,7 +76,7 @@ def get_beta_accumulators(opt, dtype): return beta_1_power -class AdaMaxOptimizerTest(test.TestCase): +class AdamaxOptimizerTest(test.TestCase): def doTestSparse(self, use_resource=False): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: @@ -100,7 +100,7 @@ class AdaMaxOptimizerTest(test.TestCase): grads1 = ops.IndexedSlices( constant_op.constant(grads1_np), constant_op.constant(grads1_np_indices), constant_op.constant([3])) - opt = adamax.AdaMax() + opt = adamax.Adamax() update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() @@ -110,7 +110,7 @@ class AdaMaxOptimizerTest(test.TestCase): beta1_power = get_beta_accumulators(opt, dtype) - # Run 3 steps of AdaMax + # Run 3 steps of Adamax for t in range(1, 4): self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) update.run() @@ -135,7 +135,7 @@ class AdaMaxOptimizerTest(test.TestCase): var = variables.Variable([[1.0], [2.0]]) indices = constant_op.constant([0, 1], dtype=index_dtype) gathered_sum = math_ops.reduce_sum(array_ops.gather(var, indices)) - optimizer = adamax.AdaMax(3.0) + optimizer = adamax.Adamax(3.0) minimize_op = optimizer.minimize(gathered_sum, var_list=[var]) variables.global_variables_initializer().run() minimize_op.run() @@ -157,9 +157,9 @@ class AdaMaxOptimizerTest(test.TestCase): [0.2], shape=[1, 1], dtype=dtype), constant_op.constant([1]), constant_op.constant([2, 1])) - repeated_update = adamax.AdaMax().apply_gradients( + repeated_update = adamax.Adamax().apply_gradients( [(grad_repeated_index, repeated_index_update_var)]) - aggregated_update = adamax.AdaMax().apply_gradients( + aggregated_update = adamax.Adamax().apply_gradients( [(grad_aggregated, aggregated_update_var)]) variables.global_variables_initializer().run() self.assertAllClose(aggregated_update_var.eval(), @@ -189,7 +189,7 @@ class AdaMaxOptimizerTest(test.TestCase): grads0 = constant_op.constant(grads0_np) grads1 = constant_op.constant(grads1_np) - opt = adamax.AdaMax() + opt = adamax.Adamax() update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) if not context.executing_eagerly(): @@ -198,7 +198,7 @@ class AdaMaxOptimizerTest(test.TestCase): self.assertAllClose([1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 4.0], self.evaluate(var1)) - # Run 3 steps of AdaMax + # Run 3 steps of Adamax for t in range(1, 4): if not context.executing_eagerly(): self.evaluate(update) @@ -232,7 +232,7 @@ class AdaMaxOptimizerTest(test.TestCase): var1 = variables.Variable(var1_np) grads0 = constant_op.constant(grads0_np) grads1 = constant_op.constant(grads1_np) - opt = adamax.AdaMax(constant_op.constant(0.001)) + opt = adamax.Adamax(constant_op.constant(0.001)) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() @@ -242,7 +242,7 @@ class AdaMaxOptimizerTest(test.TestCase): beta1_power = get_beta_accumulators(opt, dtype) - # Run 3 steps of AdaMax + # Run 3 steps of Adamax for t in range(1, 4): self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) update.run() @@ -268,7 +268,7 @@ class AdaMaxOptimizerTest(test.TestCase): var1 = variables.Variable(var1_np) grads0 = constant_op.constant(grads0_np) grads1 = constant_op.constant(grads1_np) - opt = adamax.AdaMax() + opt = adamax.Adamax() update1 = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) update2 = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() @@ -279,7 +279,7 @@ class AdaMaxOptimizerTest(test.TestCase): self.assertAllClose([1.0, 2.0], var0.eval()) self.assertAllClose([3.0, 4.0], var1.eval()) - # Run 3 steps of intertwined AdaMax1 and AdaMax2. + # Run 3 steps of intertwined Adamax1 and Adamax2. for t in range(1, 4): self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) if t % 2 == 0: @@ -298,7 +298,7 @@ class AdaMaxOptimizerTest(test.TestCase): with context.eager_mode(): v1 = resource_variable_ops.ResourceVariable(1.) v2 = resource_variable_ops.ResourceVariable(1.) - opt = adamax.AdaMax(1.) + opt = adamax.Adamax(1.) opt.minimize(lambda: v1 + v2, var_list=[v1, v2]) # There should be iteration, hyper variables, and two unique slot # variables for v1 and v2 respectively. diff --git a/tensorflow/python/keras/optimizer_v2/rmsprop.py b/tensorflow/python/keras/optimizer_v2/rmsprop.py index e34397c06d..eae5620349 100644 --- a/tensorflow/python/keras/optimizer_v2/rmsprop.py +++ b/tensorflow/python/keras/optimizer_v2/rmsprop.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""RMSProp for TensorFlow.""" +"""RMSprop for TensorFlow.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -23,8 +23,8 @@ from tensorflow.python.ops import math_ops from tensorflow.python.training import training_ops -class RMSProp(optimizer_v2.OptimizerV2): - r"""Optimizer that implements the RMSProp algorithm. +class RMSprop(optimizer_v2.OptimizerV2): + r"""Optimizer that implements the RMSprop algorithm. A detailed description of rmsprop. @@ -36,7 +36,7 @@ class RMSProp(optimizer_v2.OptimizerV2): mean_square_t + \epsilon}$$ $$variable_t := variable_{t-1} - mom_t - This implementation of RMSProp uses plain momentum, not Nesterov momentum. + This implementation of RMSprop uses plain momentum, not Nesterov momentum. The centered version additionally maintains a moving average of the gradients, and uses that average to estimate the variance: @@ -58,8 +58,8 @@ class RMSProp(optimizer_v2.OptimizerV2): momentum=0.0, epsilon=1e-7, centered=False, - name="RMSProp"): - """Construct a new RMSProp optimizer. + name="RMSprop"): + """Construct a new RMSprop optimizer. Note that in the dense implementation of this algorithm, variables and their corresponding accumulators (momentum, gradient moving average, square @@ -83,16 +83,13 @@ class RMSProp(optimizer_v2.OptimizerV2): True may help with training, but is slightly more expensive in terms of computation and memory. Defaults to False. name: Optional name prefix for the operations created when applying - gradients. Defaults to "RMSProp". - - @compatibility(eager) - When eager execution is enabled, `learning_rate`, `decay`, `momentum`, and - `epsilon` can each be a callable that takes no arguments and returns the - actual value to use. This can be useful for changing these values across - different invocations of optimizer functions. - @end_compatibility + gradients. Defaults to "RMSprop". @compatibility(eager) When eager + execution is enabled, `learning_rate`, `decay`, `momentum`, and + `epsilon` can each be a callable that takes no arguments and returns the + actual value to use. This can be useful for changing these values across + different invocations of optimizer functions. @end_compatibility """ - super(RMSProp, self).__init__(name) + super(RMSprop, self).__init__(name) self._set_hyper("learning_rate", learning_rate) self._set_hyper("rho", rho) @@ -182,7 +179,7 @@ class RMSProp(optimizer_v2.OptimizerV2): use_locking=self._use_locking) def get_config(self): - config = super(RMSProp, self).get_config() + config = super(RMSprop, self).get_config() config.update({ "learning_rate": self._serialize_hyperparameter("learning_rate"), "rho": self._serialize_hyperparameter("rho"), @@ -191,3 +188,6 @@ class RMSProp(optimizer_v2.OptimizerV2): "centered": self._centered, }) return config + + +RMSProp = RMSprop diff --git a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py index 8d7afa54cc..2ac090724e 100644 --- a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py +++ b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py @@ -52,7 +52,7 @@ _TESTPARAMS = [ ] -class RMSPropOptimizerTest(test.TestCase): +class RMSpropOptimizerTest(test.TestCase): def _rmsprop_update_numpy(self, var, g, mg, rms, mom, lr, rho, momentum, epsilon, centered): @@ -98,7 +98,7 @@ class RMSPropOptimizerTest(test.TestCase): var1 = resource_variable_ops.ResourceVariable(var1_np, dtype=dtype) grads0 = constant_op.constant(grads0_np, dtype=dtype) grads1 = constant_op.constant(grads1_np, dtype=dtype) - opt = rmsprop.RMSProp( + opt = rmsprop.RMSprop( learning_rate=learning_rate, rho=rho, momentum=momentum, @@ -135,7 +135,7 @@ class RMSPropOptimizerTest(test.TestCase): self.assertAllClose([1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 4.0], self.evaluate(var1)) - # Run 4 steps of RMSProp + # Run 4 steps of RMSprop for _ in range(1, 5): update.run() @@ -164,7 +164,7 @@ class RMSPropOptimizerTest(test.TestCase): x = constant_op.constant([[4.0], [5.0]], dtype=dtype) pred = math_ops.matmul(embedding_ops.embedding_lookup([var0], [0]), x) loss = pred * pred - sgd_op = rmsprop.RMSProp( + sgd_op = rmsprop.RMSprop( learning_rate=1.0, rho=0.0, momentum=0.0, @@ -188,7 +188,7 @@ class RMSPropOptimizerTest(test.TestCase): x = constant_op.constant([[4.0], [5.0]], dtype=dtype) pred = math_ops.matmul(embedding_ops.embedding_lookup([var0], [0]), x) loss = pred * pred - sgd_op = rmsprop.RMSProp( + sgd_op = rmsprop.RMSprop( learning_rate=1.0, rho=0.0, momentum=0.0, @@ -224,7 +224,7 @@ class RMSPropOptimizerTest(test.TestCase): grads1 = ops.IndexedSlices( constant_op.constant(grads1_np), constant_op.constant(grads1_np_indices), constant_op.constant([1])) - opt = rmsprop.RMSProp( + opt = rmsprop.RMSprop( learning_rate=learning_rate, rho=rho, momentum=momentum, @@ -261,7 +261,7 @@ class RMSPropOptimizerTest(test.TestCase): self.assertAllClose([1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 4.0], self.evaluate(var1)) - # Run 4 steps of RMSProp + # Run 4 steps of RMSprop for _ in range(1, 5): update.run() @@ -295,7 +295,7 @@ class RMSPropOptimizerTest(test.TestCase): rho = lambda: 0.9 momentum = lambda: 0.0 epsilon = lambda: 1.0 - opt = rmsprop.RMSProp(learning_rate, rho, momentum, epsilon) + opt = rmsprop.RMSprop(learning_rate, rho, momentum, epsilon) # Fetch params to validate initial values self.assertAllClose([1.0, 2.0], self.evaluate(var0)) diff --git a/tensorflow/python/keras/optimizers.py b/tensorflow/python/keras/optimizers.py index 09dd708b93..9c8020dc05 100644 --- a/tensorflow/python/keras/optimizers.py +++ b/tensorflow/python/keras/optimizers.py @@ -22,8 +22,16 @@ from __future__ import print_function import six from six.moves import zip # pylint: disable=redefined-builtin +from tensorflow.python import tf2 from tensorflow.python.keras import backend as K +from tensorflow.python.keras.optimizer_v2 import adadelta as adadelta_v2 +from tensorflow.python.keras.optimizer_v2 import adagrad as adagrad_v2 +from tensorflow.python.keras.optimizer_v2 import adam as adam_v2 +from tensorflow.python.keras.optimizer_v2 import adamax as adamax_v2 +from tensorflow.python.keras.optimizer_v2 import gradient_descent as gradient_descent_v2 +from tensorflow.python.keras.optimizer_v2 import nadam as nadam_v2 from tensorflow.python.keras.optimizer_v2 import optimizer_v2 +from tensorflow.python.keras.optimizer_v2 import rmsprop as rmsprop_v2 from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object from tensorflow.python.ops import clip_ops @@ -796,16 +804,27 @@ def deserialize(config, custom_objects=None): Returns: A Keras Optimizer instance. """ - all_classes = { - 'sgd': SGD, - 'rmsprop': RMSprop, - 'adagrad': Adagrad, - 'adadelta': Adadelta, - 'adam': Adam, - 'adamax': Adamax, - 'nadam': Nadam, - 'tfoptimizer': TFOptimizer, - } + if tf2.enabled(): + all_classes = { + 'adadelta': adadelta_v2.Adadelta, + 'adagrad': adagrad_v2.Adagrad, + 'adam': adam_v2.Adam, + 'adamax': adamax_v2.Adamax, + 'nadam': nadam_v2.Nadam, + 'rmsprop': rmsprop_v2.RMSprop, + 'sgd': gradient_descent_v2.SGD + } + else: + all_classes = { + 'adadelta': Adadelta, + 'adagrad': Adagrad, + 'adam': Adam, + 'adamax': Adamax, + 'nadam': Nadam, + 'rmsprop': RMSprop, + 'sgd': SGD, + 'tfoptimizer': TFOptimizer + } # Make deserialization case-insensitive for built-in optimizers. if config['class_name'].lower() in all_classes: config['class_name'] = config['class_name'].lower() diff --git a/tensorflow/python/keras/optimizers_test.py b/tensorflow/python/keras/optimizers_test.py index 9664f09fff..46bb0274c6 100644 --- a/tensorflow/python/keras/optimizers_test.py +++ b/tensorflow/python/keras/optimizers_test.py @@ -19,11 +19,14 @@ from __future__ import division from __future__ import print_function import gc +import os import weakref +from absl.testing import parameterized import numpy as np from tensorflow.python import keras +from tensorflow.python import tf2 from tensorflow.python.eager import context from tensorflow.python.framework import ops from tensorflow.python.framework import test_util @@ -208,5 +211,40 @@ class KerasOptimizersTest(test.TestCase): _ = keras.optimizers.Adam(clipnorm=-2.0) +@test_util.run_all_in_graph_and_eager_modes +class KerasV2OptimizersTest(test.TestCase, parameterized.TestCase): + + @parameterized.named_parameters( + ('adadelta_tf2', 'adadelta', True), ('adadelta_tf1', 'adadelta', False), + ('adagrad_tf2', 'adagrad', True), ('adagrad_tf1', 'adagrad', False), + ('adam_tf2', 'adam', True), ('adam_tf1', 'adam', False), + ('adamax_tf2', 'adamax', True), ('adamax_tf1', 'adamax', False), + ('sgd_tf2', 'sgd', True), ('sgd_tf1', 'sgd', False), + ('nadam_tf2', 'nadam', True), ('nadam_tf1', 'nadam', False), + ('rmsprop_tf2', 'rmsprop', True), ('rmsprop_tf1', 'rmsprop', False)) + def test_load_from_string(self, optimizer_string, tf2mode): + old_mode = os.environ.get('TF2_BEHAVIOR', None) + if tf2mode: + os.environ['TF2_BEHAVIOR'] = 'enabled' + else: + if 'TF2_BEHAVIOR' in os.environ: + del os.environ['TF2_BEHAVIOR'] + + # Sanity check. + self.assertEqual(tf2.enabled(), tf2mode) + + model = keras.models.Sequential() + model.add(keras.layers.Dense(1, input_shape=(10,))) + model.compile(optimizer_string, 'binary_crossentropy') + + self.assertEqual(optimizer_string, + model.optimizer.__class__.__name__.lower()) + + model.fit(np.ones((10, 10), 'float32'), np.ones((10, 1), 'float32')) + + if old_mode is not None: + os.environ['TF2_BEHAVIOR'] = old_mode + + if __name__ == '__main__': test.main() -- GitLab From cfb6e1634ecb89ca32ee60ce394c119fabe5d61c Mon Sep 17 00:00:00 2001 From: Kay Zhu Date: Tue, 20 Nov 2018 14:53:45 -0800 Subject: [PATCH 155/672] [TF2XLA] In Resampler, correctly handle out of boundary samples by returning 0 in the forward pass. PiperOrigin-RevId: 222311168 --- .../compiler/tests/resampler_ops_test.py | 53 +++++++++++++++++- .../compiler/tf2xla/kernels/resampler_ops.cc | 56 +++++++++++++++++-- 2 files changed, 102 insertions(+), 7 deletions(-) diff --git a/tensorflow/compiler/tests/resampler_ops_test.py b/tensorflow/compiler/tests/resampler_ops_test.py index f87ac3360c..d8ca0eab27 100644 --- a/tensorflow/compiler/tests/resampler_ops_test.py +++ b/tensorflow/compiler/tests/resampler_ops_test.py @@ -63,8 +63,8 @@ class ResamplerOpsTest(xla_test.XLATestCase): def testSimple(self): for dtype in self.float_types: input_shape = [1, 2, 2, 1] - input_rgb_data = [0, 5, 13, 54] - input_np = np.array(input_rgb_data, dtype=dtype).reshape(input_shape) + input_data = [0, 5, 13, 54] + input_np = np.array(input_data, dtype=dtype).reshape(input_shape) warp_shape = [1, 2] warp_data = [0.7, 0.6] @@ -151,6 +151,55 @@ class ResamplerOpsTest(xla_test.XLATestCase): expected_grad_data, expected_grad_warp) + def testOutOfBoundWarps(self): + # (x, y) are both less than 0. + for dtype in self.float_types: + input_shape = [1, 2, 2, 1] + input_data = [10, 5, 13, 54] + input_np = np.array(input_data, dtype=dtype).reshape(input_shape) + + warp_shape = [1, 2, 2] + warp_data = [-1, -1, 0.7, 0.6] + warp_np = np.array(warp_data, dtype=dtype).reshape(warp_shape) + expected = [[[0.0], [27.62]]] + self._assertForwardOpMatchesExpected(input_np, warp_np, expected) + + # One of (x, y) is less than 0. + for dtype in self.float_types: + input_shape = [1, 2, 2, 1] + input_data = [10, 5, 13, 54] + input_np = np.array(input_data, dtype=dtype).reshape(input_shape) + + warp_shape = [1, 2, 2] + warp_data = [-1, 0.1, 0.7, 0.6] + warp_np = np.array(warp_data, dtype=dtype).reshape(warp_shape) + expected = [[[0.0], [27.62]]] + self._assertForwardOpMatchesExpected(input_np, warp_np, expected) + + # Both of (x, y) are greater than image size. + for dtype in self.float_types: + input_shape = [1, 2, 2, 1] + input_data = [10, 5, 13, 54] + input_np = np.array(input_data, dtype=dtype).reshape(input_shape) + + warp_shape = [1, 2, 2] + warp_data = [-0.1, 0.1, 1.2, 2.1] + warp_np = np.array(warp_data, dtype=dtype).reshape(warp_shape) + expected = [[[0.0], [0.0]]] + self._assertForwardOpMatchesExpected(input_np, warp_np, expected) + + # One of (x, y) is greater than image size. + for dtype in self.float_types: + input_shape = [1, 2, 2, 1] + input_data = [10, 5, 13, 54] + input_np = np.array(input_data, dtype=dtype).reshape(input_shape) + + warp_shape = [1, 2, 2] + warp_data = [0.1, -0.1, 1.2, 0.1] + warp_np = np.array(warp_data, dtype=dtype).reshape(warp_shape) + expected = [[[0.0], [0.0]]] + self._assertForwardOpMatchesExpected(input_np, warp_np, expected) + if __name__ == '__main__': test.main() diff --git a/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc b/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc index 847704608f..8a8f33c8f3 100644 --- a/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc @@ -44,9 +44,6 @@ namespace { using xla::XlaOp; -// TODO(b/112295522): note that sampling from image boundary is not currently -// being handled properly. - // Calculates the bilinear weight tensor, given basis ratio (px, py) of the // sampling position: // W = [(1-px)*(1-py), px*(1-py), (1-px)*py, px*py] @@ -421,12 +418,13 @@ class ResamplerOp : public XlaOpKernel { OP_REQUIRES(ctx, warp_shape.dim_size(last_warp_dim) == 2, errors::InvalidArgument( "the last dimension of warp must be exactly size 2.")); + xla::PrimitiveType warp_type = ctx->input_xla_type(1); XlaOp data = ctx->Input("data"); XlaOp warp = ctx->Input("warp"); // Find the coordinates of the top left corner for the 2x2 region to be - // sampled from. The dimensions are (batch, dim_0, ... dim_n, 2) where the + // sampled from. The dimensions are [batch, dim_0, ... dim_n, 2] where the // last dimension of size 2 in turn is [x, y]. XlaOp top_left = xla::ConvertElementType(warp, xla::U32); @@ -457,10 +455,56 @@ class ResamplerOp : public XlaOpKernel { dot_dims.add_lhs_contracting_dimensions(warp_shape.dims() - 1); dot_dims.add_rhs_contracting_dimensions(warp_shape.dims() - 1); + // The dimension is [batch, dim_0, ...dim_n, data_channels]. auto blended_pixels = xla::DotGeneral(weights, neighbors_data, dot_dims, /*precision_config=*/nullptr); - ctx->SetOutput(0, blended_pixels); + // Handle out of boundary cases by constructing a predicate mask array based + // on the in-bound condition, and output 0 for the blended pixel value if + // out-bound. The dimension is the same as top_left: [batch, dim_0, + // ...dim_n, 2] where the last dimension of size 2 is the [x, y] coordinate. + + auto is_ge_zero = xla::Ge(warp, xla::ZerosLike(warp)); + + auto is_lt_image_size = xla::Lt( + warp, + xla::ConvertElementType( + xla::ConstantR1( + ctx->builder(), + {/*width=*/static_cast(data_shape.dim_size(2) - 1), + /*height=*/static_cast(data_shape.dim_size(1) - 1)}), + warp_type), + /*broadcast_dimensions=*/{warp_shape.dims() - 1}); + + auto is_in_bound_x_y = xla::And(is_ge_zero, is_lt_image_size); + // Reduce along last dimension. The resulting dimension is: + // [batch, dim_0, ...dim_n]. + auto is_in_bound = xla::Reduce( + is_in_bound_x_y, xla::ConstantR0(ctx->builder(), true), + xla::CreateScalarAndComputation(xla::PrimitiveType::PRED, + ctx->builder()), + {last_warp_dim}); + + // Broadcast 'is_in_bound' to the same dimension as 'blended_pixels', which + // is the dimension of the result: + // [batch, dim_0, ...dim_n, data_channels]. + auto warp_dims = warp_shape.dim_sizes(); + std::vector result_dims(warp_dims.begin(), warp_dims.end() - 1); + result_dims.push_back(data_channels); + xla::Shape broadcasted_shape = + xla::ShapeUtil::MakeShape(xla::PrimitiveType::PRED, result_dims); + + std::vector broadcasted_dims(warp_dims.size() - 1); + std::iota(broadcasted_dims.begin(), broadcasted_dims.end(), 0); + auto broadcasted_is_in_bound = + xla::BroadcastInDim(is_in_bound, broadcasted_shape, broadcasted_dims); + + // Set out of bound samples to zero. + auto zeros = + xla::Broadcast(xla::Zero(ctx->builder(), data_type), result_dims); + auto result = xla::Select(broadcasted_is_in_bound, blended_pixels, zeros); + + ctx->SetOutput(0, result); } }; @@ -473,6 +517,8 @@ class ResamplerGradOp : public XlaOpKernel { OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &output_dtype)); } + // TODO(b/112295522): note that sampling from image boundary is not currently + // being handled properly. void Compile(XlaOpKernelContext* ctx) override { TensorShape data_shape_tf = ctx->InputShape("data"); OP_REQUIRES(ctx, data_shape_tf.dims() == 4, -- GitLab From bf4acd8775e93dfc54250e2414cc3971a29a1de1 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 15:01:36 -0800 Subject: [PATCH 156/672] TFTRT: include log in VLOG_IS_ON(1) --- tensorflow/contrib/tensorrt/convert/convert_graph.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 1e0ea5f7e2..bc82b3c0f0 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -982,11 +982,13 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { // Graph is not modified. LOG(WARNING) << msg << " failed: " << status << ". Fallback to TF..."; } - msg = "Segment consists of nodes: "; - for (const string& node_name : converted_segments.at(i).first) { - StrAppend(&msg, node_name, ", "); + if (VLOG_IS_ON(1)) { + msg = "Segment consists of nodes: "; + for (const string& node_name : converted_segments.at(i).first) { + StrAppend(&msg, node_name, ", "); + } + VLOG(1) << msg; } - VLOG(1) << msg; } cudaSetDevice(old_cuda_device); graph.ToGraphDef(params.output_graph_def); -- GitLab From 0e4fced6195fb73f1c3091d8bfd2c341102f347e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 14:57:06 -0800 Subject: [PATCH 157/672] Fixed/improved ragged.from_sparse() precondition logic for enforcing that the input sparse tensor is statically known to be of rank 2. PiperOrigin-RevId: 222311695 --- .../python/ops/ragged/ragged_conversion_ops.py | 11 ++++++++--- .../ops/ragged/ragged_from_sparse_op_test.py | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/ops/ragged/ragged_conversion_ops.py b/tensorflow/python/ops/ragged/ragged_conversion_ops.py index 0385be02d4..83212e49cf 100644 --- a/tensorflow/python/ops/ragged/ragged_conversion_ops.py +++ b/tensorflow/python/ops/ragged/ragged_conversion_ops.py @@ -361,9 +361,14 @@ def from_sparse(st_input, name=None): st_input = sparse_tensor.convert_to_tensor_or_sparse_tensor( st_input, name='rt_input') - if (st_input.dense_shape.shape.ndims != 2 and - st_input.indices.shape.ndims is None or - st_input.indices.shape.dims[1].value != 2): + static_rank_from_dense_shape = ( + None if st_input.dense_shape.shape.ndims is None + else st_input.dense_shape.shape.dims[0].value) + static_rank_from_indices = ( + None if st_input.indices.shape.ndims is None + else st_input.indices.shape.dims[1].value) + + if static_rank_from_dense_shape != 2 and static_rank_from_indices != 2: raise ValueError('rank(st_input) must be 2') with ops.control_dependencies( diff --git a/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py b/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py index ff19ddedeb..77418ff20d 100644 --- a/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py @@ -64,6 +64,20 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): self.assertRaisesRegexp(ValueError, r'rank\(st_input\) must be 2', ragged.from_sparse, st3) + def testGoodPartialSparseTensorRank(self): + st1 = sparse_tensor.SparseTensor( + indices=[[0, 0]], + values=[0], + dense_shape=array_ops.placeholder(dtypes.int64)) + st2 = sparse_tensor.SparseTensor( + indices=array_ops.placeholder(dtypes.int64), + values=[0], + dense_shape=[4, 3]) + + # Shouldn't throw ValueError + ragged.from_sparse(st1) + ragged.from_sparse(st2) + def testNonRaggedSparseTensor(self): # "index_suffix" means the value of the innermost dimension of the index # (i.e., indices[i][-1]). -- GitLab From fcc79c953348a95c611ed8a05dcf27349597bf34 Mon Sep 17 00:00:00 2001 From: Yu-Cheng Ling Date: Tue, 20 Nov 2018 15:23:38 -0800 Subject: [PATCH 158/672] Changing subgraphs to vector of unique_ptrs. PiperOrigin-RevId: 222316187 --- tensorflow/lite/core/subgraph.h | 3 --- tensorflow/lite/interpreter.cc | 8 ++++---- tensorflow/lite/interpreter.h | 6 +++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tensorflow/lite/core/subgraph.h b/tensorflow/lite/core/subgraph.h index 120c307ef2..e85d6df974 100644 --- a/tensorflow/lite/core/subgraph.h +++ b/tensorflow/lite/core/subgraph.h @@ -57,7 +57,6 @@ class Subgraph { // interpreter. TfLiteStatus SetVariables(std::vector variables); - // Adds a node with the given parameters and returns the index of the new // node in `node_index` (optionally). Interpreter will take ownership of // `builtin_data` and destroy it with `free`. Ownership of 'init_data' @@ -167,7 +166,6 @@ class Subgraph { return &nodes_and_registration_[node_index]; } - // Change the dimensionality of a given tensor. Note, this is only acceptable // for tensor indices that are inputs. // Returns status of failure or success. @@ -227,7 +225,6 @@ class Subgraph { return kTfLiteOk; } - // The default capacity of `tensors_` vector. static constexpr int kTensorsReservedCapacity = 128; // The capacity headroom of `tensors_` vector before calling ops' diff --git a/tensorflow/lite/interpreter.cc b/tensorflow/lite/interpreter.cc index 078c2306c4..326aff5ce4 100644 --- a/tensorflow/lite/interpreter.cc +++ b/tensorflow/lite/interpreter.cc @@ -35,7 +35,7 @@ namespace tflite { Interpreter::Interpreter(ErrorReporter* error_reporter) : error_reporter_(error_reporter ? error_reporter : DefaultErrorReporter()) { - subgraphs_.emplace_back(error_reporter_, external_contexts_); + subgraphs_.emplace_back(new Subgraph(error_reporter_, external_contexts_)); context_ = primary_subgraph().context(); // Reserve some space for the tensors to avoid excessive resizing. @@ -136,7 +136,7 @@ void Interpreter::UseNNAPI(bool enable) { primary_subgraph().UseNNAPI(enable); } void Interpreter::SetNumThreads(int num_threads) { for (auto& subgraph : subgraphs_) { - subgraph.context()->recommended_num_threads = num_threads; + subgraph->context()->recommended_num_threads = num_threads; } for (int i = 0; i < kTfLiteMaxExternalContexts; ++i) { @@ -149,7 +149,7 @@ void Interpreter::SetNumThreads(int num_threads) { void Interpreter::SetAllowFp16PrecisionForFp32(bool allow) { for (auto& subgraph : subgraphs_) { - subgraph.context()->allow_fp32_relax_to_fp16 = allow; + subgraph->context()->allow_fp32_relax_to_fp16 = allow; } } @@ -191,7 +191,7 @@ TfLiteStatus Interpreter::GetBufferHandle(int tensor_index, } void Interpreter::SetProfiler(profiling::Profiler* profiler) { - for (auto& subgraph : subgraphs_) subgraph.SetProfiler(profiler); + for (auto& subgraph : subgraphs_) subgraph->SetProfiler(profiler); } profiling::Profiler* Interpreter::GetProfiler() { diff --git a/tensorflow/lite/interpreter.h b/tensorflow/lite/interpreter.h index 7da4a2cbfa..405cf640b9 100644 --- a/tensorflow/lite/interpreter.h +++ b/tensorflow/lite/interpreter.h @@ -427,11 +427,11 @@ class Interpreter { friend class InterpreterTest; Subgraph& primary_subgraph() { - return subgraphs_.front(); // Safe as subgraphs_ always has 1 entry. + return *subgraphs_.front(); // Safe as subgraphs_ always has 1 entry. } const Subgraph& primary_subgraph() const { - return subgraphs_.front(); // Safe as subgraphs_ always has 1 entry. + return *subgraphs_.front(); // Safe as subgraphs_ always has 1 entry. } // Set the value of an external context. @@ -470,7 +470,7 @@ class Interpreter { TfLiteExternalContext* external_contexts_[kTfLiteMaxExternalContexts]; // Subgraphs - std::vector subgraphs_; + std::vector> subgraphs_; }; } // namespace tflite -- GitLab From 095b54be3fa6dc206d7151d65c901e4273fd5b08 Mon Sep 17 00:00:00 2001 From: Guangda Lai Date: Tue, 20 Nov 2018 15:38:53 -0800 Subject: [PATCH 159/672] PR #22788: TFTRT User provided INT8 quantization scales Please approve this CL. It will be submitted automatically, and its GitHub pull request will be marked as merged. Imported from GitHub PR #22788 TF-TRT now supports the following quantization nodes: - QuantizeAndDequantizeV2 - QuantizeAndDequantizeV3 - FakeQuantWithMinMaxVars - FakeQuantWithMinMaxArgs When these nodes are converted: 1. Their quantization ranges are extracted and stored 2. The nodes are removed 3. The ranges are applied to the relevant tensors This enables a path for TF-TRT to deploy models trained with quantization in the loop, for example those trained with tf.contrib.quantize. trt.create_inference_graph() has a new boolean argument, `use_calibration`. If we are in INT8 mode and use_calibration=True, create_inference_graph will return a calibration graph just like it did previously. The calibrator will not override ranges provided via quantization nodes. If we are in INT8 mode and use_calibration=False, a warning will be issued for every tensor which does not have a calibration range. Since TRT may fuse some operations, users may not always need to provide a value for these tensors. If a tensor that TRT needs is missing, the conversion will fail. This PR also adds support for Relu6 nodes, and fixes a bug with not renaming tensors. Current Issues/Considerations: - If a model was trained with quantization nodes in places where TRT will not quantize (i.e. due to op fusion), then accuracy may drop dramatically. The solution is to figure out which ops will be fused by TRT and avoid placing quantization nodes between those ops. Another option is to place clip ops with each quantization node, so that if the tensor is not quantized it will still be clipped to be in the expected range - this will impact performace negatively. - TRT does not have documentation for op fusion yet. - TRT only supports symmetric quantization. Ranges are converted to symmetric ranges using `max(abs(min_range), abs(max_range))`. - Since the tensors which are inputs and outputs to the TRTEngine are renamed to "TensorRTInputPH_{X}", "TensorRTOutputPH_{X}", if these tensors are missing ranges the warnings will not make sense to users. - MatMul and BiasAdd are not fused, requiring users to provide a range between these ops. Copybara import of the project: - 58f69a5899c8a902956b876c3fa8baab6e60e7c7 Allows user to specify int8 scales via TF nodes. by Trevor Morris - abda4224e8d6b8e227a579a481e9f0ebe5fdb346 Add FakeQuantWithMinMaxArgs by Trevor Morris - 6e07831307ebad7f154052cc387da22b6169a4d1 Add more checks on quantize node inputs. by Trevor Morris - 9dda56272f87cc1ebd66eeaa6e8f3cf0421fe4fe Fix merge conflicts by Trevor Morris - 08159b275a5e66e5713ab25befcd7b2034d631bb Improve use_calibration arg documentation by Trevor Morris - f60e430827c759755922cdaea80ae6af954cb934 Quantization-aware training full test on MNIST by Trevor Morris - de0ed5a2bf01342d4c23357d3abf39eb68bb0b2a Add quantization mnist test to BUILD by Trevor Morris - da089db8e6c868f7fab11e45cbea182daccdb393 Fixes for @aaroey's review. by Trevor Morris - 481c4904c6cdc129827c6b9c625cbd899fd3a555 Merge branch 'master' of https://github.com/tensorflow/te... by Guangda Lai <31743510+aaroey@users.noreply.github.com> - cdccbc859f1fc7e5041d61f378934ab1125e7ccc Fix some formatting/compilation issues by Guangda Lai <31743510+aaroey@users.noreply.github.com> - 218a89386fb8c00c0bf1de7f1ce6ec69a3991130 Merge cdccbc859f1fc7e5041d61f378934ab1125e7ccc into 38b3d... by Trevor Morris COPYBARA_INTEGRATE_REVIEW=https://github.com/tensorflow/tensorflow/pull/22788 from trevor-m:tmorris_tftrt_int8prequantize cdccbc859f1fc7e5041d61f378934ab1125e7ccc PiperOrigin-RevId: 222318529 --- tensorflow/contrib/tensorrt/BUILD | 29 ++ .../contrib/tensorrt/convert/convert_graph.cc | 144 +++--- .../contrib/tensorrt/convert/convert_graph.h | 10 +- .../tensorrt/convert/convert_graph_test.cc | 43 +- .../contrib/tensorrt/convert/convert_nodes.cc | 420 +++++++++++++++++- .../contrib/tensorrt/convert/convert_nodes.h | 58 ++- .../tensorrt/convert/convert_nodes_test.cc | 293 +++++++++++- .../tensorrt/convert/trt_optimization_pass.cc | 10 + .../tensorrt/convert/trt_optimization_pass.h | 4 +- .../contrib/tensorrt/kernels/trt_engine_op.cc | 14 +- .../contrib/tensorrt/kernels/trt_engine_op.h | 4 + .../contrib/tensorrt/ops/trt_engine_op.cc | 3 +- .../contrib/tensorrt/python/trt_convert.py | 25 +- tensorflow/contrib/tensorrt/test/base_test.py | 4 +- .../tensorrt/test/quantization_mnist_test.py | 290 ++++++++++++ .../tensorrt/test/quantization_test.py | 144 ++++++ .../contrib/tensorrt/test/testdata/checkpoint | 3 + .../model.ckpt-46900.data-00000-of-00001 | Bin 0 -> 686728 bytes .../test/testdata/model.ckpt-46900.index | Bin 0 -> 652 bytes .../test/tf_trt_integration_test_base.py | 51 ++- .../grappler/optimizers/layout_optimizer.cc | 4 + 21 files changed, 1421 insertions(+), 132 deletions(-) create mode 100644 tensorflow/contrib/tensorrt/test/quantization_mnist_test.py create mode 100644 tensorflow/contrib/tensorrt/test/quantization_test.py create mode 100644 tensorflow/contrib/tensorrt/test/testdata/checkpoint create mode 100644 tensorflow/contrib/tensorrt/test/testdata/model.ckpt-46900.data-00000-of-00001 create mode 100644 tensorflow/contrib/tensorrt/test/testdata/model.ckpt-46900.index diff --git a/tensorflow/contrib/tensorrt/BUILD b/tensorflow/contrib/tensorrt/BUILD index 20bcd2447e..784acce444 100644 --- a/tensorflow/contrib/tensorrt/BUILD +++ b/tensorflow/contrib/tensorrt/BUILD @@ -29,6 +29,10 @@ load( "if_tensorrt", ) +exports_files(glob([ + "test/testdata/*", +])) + tf_cuda_cc_test( name = "tensorrt_test_cc", size = "small", @@ -491,6 +495,7 @@ cuda_py_tests( "test/memory_alignment_test.py", "test/multi_connection_neighbor_engine_test.py", "test/neighboring_engine_test.py", + "test/quantization_test.py", "test/rank_two_test.py", "test/reshape_transpose_test.py", "test/vgg_block_nchw_test.py", @@ -527,6 +532,30 @@ cuda_py_tests( ], ) +cuda_py_test( + name = "quantization_mnist_test", + srcs = ["test/quantization_mnist_test.py"], + additional_deps = [ + ":tf_trt_integration_test_base", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python/keras:keras", + "//tensorflow/python/estimator:estimator", + ], + data = [ + "test/testdata/checkpoint", + "test/testdata/model.ckpt-46900.data-00000-of-00001", + "test/testdata/model.ckpt-46900.index", + ], + tags = [ + "no_cuda_on_cpu_tap", + "no_pip", + "no_tap", # It is not able to download the mnist data. + "no_windows", + "nomac", + ], +) + cc_library( name = "utils", srcs = ["convert/utils.cc"], diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index f95ffe4100..21f505b7fe 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -82,60 +82,73 @@ std::vector GetLoadedTensorRTVersion() { } TrtCandidateSelector::TrtCandidateSelector( - const grappler::GraphProperties& graph_properties) - : graph_properties_(graph_properties) {} + const grappler::GraphProperties& graph_properties, int precision_mode) + : graph_properties_(graph_properties), precision_mode_(precision_mode) {} Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node) { // TODO(laigd): move this set to TrtNodeValidator where it should belong. // LINT.IfChange static const std::set candidate_ops = { - "Identity", - "Snapshot", - "Const", - "Conv2D", - "MaxPool", - "BiasAdd", - "Relu", - "Add", - "Mul", - "Sub", - "Rsqrt", - "Pad", - "Mean", - "AvgPool", - "ConcatV2", - "DepthwiseConv2dNative", - "FusedBatchNorm", - "FusedBatchNormV2", - "Div", - "RealDiv", - "Rsqrt", - "Reciprocal", - "Exp", - "Log", - "Sqrt", - "Abs", - "Neg", - "Transpose", - "Reshape", - "MatMul", - "BatchMatMul", - "Softmax", - "Minimum", - "Maximum", - "TopKV2", - "Sum", - "Prod", - "Max", - "Min", + "Identity", + "Snapshot", + "Const", + "Conv2D", + "MaxPool", + "BiasAdd", + "Relu", + "Add", + "Mul", + "Sub", + "Rsqrt", + "Pad", + "Mean", + "AvgPool", + "ConcatV2", + "DepthwiseConv2dNative", + "FusedBatchNorm", + "FusedBatchNormV2", + "Div", + "RealDiv", + "Rsqrt", + "Reciprocal", + "Exp", + "Log", + "Sqrt", + "Abs", + "Neg", + "Transpose", + "Reshape", + "MatMul", + "BatchMatMul", + "Softmax", + "Minimum", + "Maximum", + "TopKV2", + "Sum", + "Prod", + "Max", + "Min", + "Relu6", }; - // LINT.ThenChange(//tensorflow/contrib/tensorrt/convert/convert_nodes.cc) - const bool is_supported_op_type = + bool is_supported_op_type = (candidate_ops.count(node->type_string()) || PluginFactoryTensorRT::GetInstance()->IsPlugin(node->type_string())); + static const std::set quantize_ops = { + "QuantizeAndDequantizeV2", + "QuantizeAndDequantizeV3", + "FakeQuantWithMinMaxVars", + "FakeQuantWithMinMaxArgs", + }; + // In INT8 mode, we will always apply the quantization ranges provided by + // these ops to the relevant tensors. This happens regardless of the value of + // use_calibration. + if (precision_mode_ == INT8MODE && quantize_ops.count(node->type_string())) { + is_supported_op_type = true; + } + // LINT.ThenChange(//tensorflow/contrib/tensorrt/convert/convert_nodes.cc) if (!is_supported_op_type) { return errors::Unimplemented("Op type ", node->type_string(), - " is not supported."); + " is not supported"); } std::vector input_edges; @@ -220,7 +233,8 @@ tensorflow::Status ConvertGraphDefToTensorRT( const std::vector& output_names, size_t max_batch_size, size_t max_workspace_size_bytes, tensorflow::GraphDef* new_graph_def, int precision_mode, int minimum_segment_size, bool is_dyn_op, - int max_cached_engines, std::vector cached_engine_batches) { + int max_cached_engines, std::vector cached_engine_batches, + bool use_calibration) { // Create GrapplerItem. tensorflow::grappler::GrapplerItem item; item.fetch = output_names; @@ -287,6 +301,7 @@ tensorflow::Status ConvertGraphDefToTensorRT( list->add_i(batch); } } + parameters["use_calibration"].set_b(use_calibration); // Run optimizer. tensorflow::grappler::MetaOptimizer meta_opt(nullptr, config_proto); @@ -566,27 +581,30 @@ tensorflow::Status CreateTRTNode(const std::vector& infos, int pos, } } } + + const bool calibrate_int8 = + (info.precision_mode == INT8MODE && info.use_calibration); + // Build the engine and get its serialized representation. string segment_string; - if (info.engine_type == EngineInfo::EngineType::TRTStatic || - info.precision_mode == INT8MODE) { + if (info.engine_type == EngineInfo::EngineType::TRTStatic || calibrate_int8) { // Create static engine for fp32/fp16 mode, and test validity of the engine - // for int8 mode. We don't want engine to fail at the calibration time. - // So we are constructing a FP32 engine here to check its validity, and if - // it is a valid engine then we put the serialized graphdef to the op. - // Otherwise we skip node creation for this engine. + // for int8 calibration mode. We don't want engine to fail at the + // calibration time. So we are constructing a FP32 engine here to check its + // validity, and if it is a valid engine then we put the serialized graphdef + // to the op. Otherwise we skip node creation for this engine. Logger trt_logger; TrtUniquePtrType engine; // TODO(sami): What happens if 1st dim is not batch? TF_RETURN_IF_ERROR(ConvertGraphDefToEngine( - info.segment_graph_def, - info.precision_mode == INT8MODE ? FP32MODE : info.precision_mode, + info.segment_graph_def, calibrate_int8 ? FP32MODE : info.precision_mode, max_batch_size, info.max_workspace_size_bytes, input_shapes, &trt_logger, alloc, /*calibrator=*/nullptr, &engine, + info.use_calibration, /*convert_successfully=*/nullptr)); TrtUniquePtrType engine_data(engine->serialize()); segment_string = string((const char*)engine_data->data(), engine_data->size()); - if (info.precision_mode == INT8MODE) { + if (calibrate_int8) { // See above comment about why not putting this inside the 'else' branch. segment_string = info.segment_graph_def.SerializeAsString(); } @@ -598,7 +616,7 @@ tensorflow::Status CreateTRTNode(const std::vector& infos, int pos, // conversion. string prec_string; TF_RETURN_IF_ERROR(GetPrecisionModeName(info.precision_mode, &prec_string)); - if (info.precision_mode == INT8MODE && + if (info.precision_mode == INT8MODE && calibrate_int8 && !TRTResourceManager::instance()->getManager("TRTCalibration")) { LOG(ERROR) << "Failed to construct calibration storage"; } @@ -634,6 +652,7 @@ tensorflow::Status CreateTRTNode(const std::vector& infos, int pos, .Attr("cached_engine_batches", {max_batch_size}) .Attr("workspace_size_bytes", info.max_workspace_size_bytes) .Attr("precision_mode", prec_string) + .Attr("use_calibration", info.use_calibration) .Attr("OutT", out_types) .Finalize(&trt_node); if (!status.ok()) { @@ -866,7 +885,8 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { } segment_options.minimum_segment_size = params.minimum_segment_size; tensorflow::tensorrt::segment::SegmentNodesVector initial_segments; - TrtCandidateSelector candidate_selector(*params.graph_properties); + TrtCandidateSelector candidate_selector(*params.graph_properties, + params.precision_mode); TF_RETURN_IF_ERROR(tensorrt::segment::SegmentGraph( &graph, std::bind(&TrtCandidateSelector::IsTensorRTCandidate, &candidate_selector, @@ -904,10 +924,14 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { continue; } curr_engine.precision_mode = params.precision_mode; - curr_engine.engine_type = - (params.is_dyn_op || params.precision_mode == INT8MODE - ? EngineInfo::EngineType::TRTDynamic - : EngineInfo::EngineType::TRTStatic); + if (params.use_calibration && params.precision_mode != INT8MODE) { + return errors::InvalidArgument( + "Calibration with FP32 or FP16 is not supported."); + } + curr_engine.engine_type = ((params.is_dyn_op || params.use_calibration) + ? EngineInfo::EngineType::TRTDynamic + : EngineInfo::EngineType::TRTStatic); + curr_engine.use_calibration = params.use_calibration; curr_engine.cached_engine_batches = params.cached_engine_batches; curr_engine.maximum_cached_engines = params.max_cached_engines; StrAppend(&curr_engine.engine_name, "my_trt_op_", t); diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.h b/tensorflow/contrib/tensorrt/convert/convert_graph.h index 1c9d82105a..1f39f56f63 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.h +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.h @@ -35,7 +35,8 @@ namespace convert { // supported by TRT. class TrtCandidateSelector { public: - TrtCandidateSelector(const grappler::GraphProperties& graph_properties); + TrtCandidateSelector(const grappler::GraphProperties& graph_properties, + int precision_mode); // Returns OK iff 'node' is a TF-TRT conversion candidate, which will be added // to TRT subgraph and later converted into TRT engine. @@ -49,6 +50,9 @@ class TrtCandidateSelector { // GraphProperties of the graph whose nodes are to be validated by // IsTensorRTCandidate(). const grappler::GraphProperties& graph_properties_; + + // Quantization ops are only converted when using quantized precisions. + const int precision_mode_; }; struct ConversionParams { @@ -63,6 +67,7 @@ struct ConversionParams { cluster(nullptr), is_dyn_op(false), fixed_input_size(true), + use_calibration(true), max_cached_engines(1) {} const tensorflow::GraphDef* input_graph_def; const std::vector* output_names; @@ -76,6 +81,7 @@ struct ConversionParams { bool is_dyn_op; // Whether to create engine on conversion or execution time bool fixed_input_size; // Assume non-batch ranks of input tensors are fixed int max_cached_engines; // maximum number of cached engines + bool use_calibration; std::vector cached_engine_batches; // list of cached engines }; @@ -95,7 +101,7 @@ tensorflow::Status ConvertGraphDefToTensorRT( size_t max_workspace_size_bytes, tensorflow::GraphDef* new_graph_def, int precision_mode = 1, int minimum_segment_size = 3, bool is_dyn_op = false, int max_cached_engines = 1, - std::vector cached_engine_batches = {}); + std::vector cached_engine_batches = {}, bool use_calibration = true); // Method to call from optimization pass tensorflow::Status ConvertAfterShapes(ConversionParams& params); diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc b/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc index f10729987f..2d2bfeb192 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph_test.cc @@ -85,27 +85,42 @@ TEST(TrtCandidateSelector, Basics) { ops::MatMul(s.WithOpName("matmul_with_incompatible_input"), incompatible_feed, const_2); + // Quantize ops. + auto quantize_attrs = ops::FakeQuantWithMinMaxArgs::Min(-6.0f).Max(6.0f); + auto quantize = ops::FakeQuantWithMinMaxArgs(s.WithOpName("quantize"), feed, + quantize_attrs); + + // Get GrapplerItem and GraphProperties. grappler::GrapplerItem item; TF_EXPECT_OK(s.ToGraphDef(&item.graph)); Tensor feed_tensor(DT_FLOAT, input_shape); item.feed.push_back(std::make_pair("feed", feed_tensor)); - grappler::GraphProperties graph_properties(item); TF_EXPECT_OK(graph_properties.InferStatically(true)); - TrtCandidateSelector selector(graph_properties); - TF_EXPECT_OK(selector.IsTensorRTCandidate(matmul.operation.node())); - ExpectStatus( - selector.IsTensorRTCandidate(incompatible_matmul.operation.node()), - error::INVALID_ARGUMENT, - "transpose_a is not supported for TensorRT FullyConnected " - "(op: MatMul), at: incompatible_matmul"); - ExpectStatus(selector.IsTensorRTCandidate(unsupported_op.operation.node()), - error::UNIMPLEMENTED, "Op type Sin is not supported"); - ExpectStatus(selector.IsTensorRTCandidate( - matmul_with_incompatible_input.operation.node()), - error::INTERNAL, - "Failed to convert input with index 0 to a TRT_TensorOrWeights"); + for (const int precision_mode : {FP32MODE, INT8MODE}) { + TrtCandidateSelector selector(graph_properties, precision_mode); + TF_EXPECT_OK(selector.IsTensorRTCandidate(matmul.operation.node())); + ExpectStatus( + selector.IsTensorRTCandidate(incompatible_matmul.operation.node()), + error::INVALID_ARGUMENT, + "transpose_a is not supported for TensorRT FullyConnected " + "(op: MatMul), at: incompatible_matmul"); + ExpectStatus(selector.IsTensorRTCandidate(unsupported_op.operation.node()), + error::UNIMPLEMENTED, "Op type Sin is not supported"); + ExpectStatus( + selector.IsTensorRTCandidate( + matmul_with_incompatible_input.operation.node()), + error::INTERNAL, + "Failed to convert input with index 0 to a TRT_TensorOrWeights"); + if (precision_mode == INT8MODE) { + TF_EXPECT_OK(selector.IsTensorRTCandidate(quantize.operation.node())); + } else { + ExpectStatus(selector.IsTensorRTCandidate(quantize.operation.node()), + error::UNIMPLEMENTED, + "Op type FakeQuantWithMinMaxArgs is not supported"); + } + } } class FakeCluster : public grappler::Cluster { diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index af9bbbfdfd..27c20204bb 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -449,7 +449,9 @@ class TRT_TensorOrWeights::SimpleITensor : public nvinfer1::ITensor { void setLocation(nvinfer1::TensorLocation location) override {} #if NV_TENSORRT_MAJOR >= 5 - bool setDynamicRange(float min, float max) override {} + bool setDynamicRange(float min, float max) override { return true; } + + float getDynamicRange() const override { return 0; } #endif private: @@ -810,8 +812,11 @@ Status TrtNodeValidator::ConvertConstToWeights( return status; } -Converter::Converter(nvinfer1::INetworkDefinition* trt_network, bool is_fp16) - : trt_network_(trt_network), is_fp16_(is_fp16) { +Converter::Converter(nvinfer1::INetworkDefinition* trt_network, + int precision_mode, bool use_calibration) + : trt_network_(trt_network), + precision_mode_(precision_mode), + use_calibration_(use_calibration) { this->RegisterOpConverters(); } @@ -836,13 +841,18 @@ Status Converter::ConvertNode(const NodeDef& node_def) { TRT_TensorOrWeights& output = outputs[i]; string output_name = node_def.name(); if (i != 0) output_name = StrCat(output_name, ":", i); - // We need to check the name before setting it. For Identity op where the - // output is the input, if its input is one of the engine input, setting - // the name here will overwrite engine input bindings which will cause - // runtime error. + // We need to check the name before setting it. If the input is one of the + // engine input, setting the name here will overwrite engine input + // bindings which will cause runtime error. if (output.is_tensor()) { const char* tensor_name = output.tensor()->getName(); - if (tensor_name == nullptr || std::strlen(tensor_name) == 0) { + if (!tensorflow::str_util::StartsWith(tensor_name, kInputPHName)) { + // TRT initializes tensor names as "(Unnamed ITensor* N)". We rename + // them to match their corresponding TensorFlow name. + // Note: ITensors that we create internally within TF-TRT which are + // not inputs or outputs of a node will not be renamed. This is a + // potential cause of confusion if an error message or warning + // mentions the unnamed tensor. output.tensor()->setName(output_name.c_str()); } } @@ -954,6 +964,7 @@ Status Converter::TransposeTensor(nvinfer1::ITensor* input_tensor, nvinfer1::IShuffleLayer* layer = this->network()->addShuffle(*input_tensor); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Transpose"); + MarkQuantizationRangesAsInferrable(input_tensor, layer->getOutput(0)); nvinfer1::Permutation permutation; for (int32_t i = 0; i < dims.nbDims; ++i) { @@ -976,6 +987,38 @@ Status Converter::TransposeTensor(nvinfer1::ITensor* input_tensor, return tensorflow::Status::OK(); } +Status Converter::GetWeightRange(const TRT_ShapedWeights& weights, + float* out_min, float* out_max) const { + switch (weights.type_) { + case DataType::DT_FLOAT: { + auto inp = static_cast(weights.GetValues()); + auto result = std::minmax_element(inp, inp + weights.count()); + *out_min = *result.first; + *out_max = *result.second; + break; + } + case DataType::DT_HALF: { + auto inp = static_cast(weights.GetValues()); + auto result = std::minmax_element(inp, inp + weights.count()); + *out_min = Eigen::half_impl::half_to_float(*result.first); + *out_max = Eigen::half_impl::half_to_float(*result.second); + break; + } + case DataType::DT_INT32: { + auto inp = static_cast(weights.GetValues()); + auto result = std::minmax_element(inp, inp + weights.count()); + *out_min = static_cast(*result.first); + *out_max = static_cast(*result.second); + break; + } + default: + return errors::Unimplemented( + "Data type not supported for GetWeightRange: ", + DataTypeString(weights.type_)); + } + return Status::OK(); +} + Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, const nvinfer1::Dims& dims, const nvinfer1::ITensor** tensor) { @@ -1002,6 +1045,8 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, *const_cast(input.tensor())); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Reshape"); layer->setReshapeDimensions(dims); + MarkQuantizationRangesAsInferrable( + const_cast(input.tensor()), layer->getOutput(0)); *tensor = layer->getOutput(0); } } else { @@ -1009,10 +1054,123 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, this->network()->addConstant(dims, input.weights().GetTrtWeights()); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, "TF-TRT Internal Reshape"); *tensor = layer->getOutput(0); + if (precision_mode() == INT8MODE && !use_calibration()) { + // If we are in int8 mode and not calibrating, we need to explicitly set a + // quantization range for the output tensor of the IConstantLayer. Here we + // set the range to [min(weights), max(weights)]. + float min_range = 0.0f; + float max_range = 0.0f; + TF_RETURN_IF_ERROR( + GetWeightRange(input.weights(), &min_range, &max_range)); + // Avoid setting range to 0 because TRT will throw an error. If the + // weights are zero then the range doesn't matter: using 127.0f should + // ensure the quantized weight will be exactly zero. + if (min_range == 0.0f && max_range == 0.0f) { + min_range = -127.0f; + max_range = 127.0f; + } + ProvideQuantizationRange(const_cast(*tensor), + min_range, max_range); + } } return tensorflow::Status::OK(); } +void Converter::MarkQuantizationRangesAsInferrable(nvinfer1::ITensor* input, + nvinfer1::ITensor* output) { + quantization_infer_.push_back({input, output}); + quantization_infer_.push_back({output, input}); +} + +void Converter::ProvideQuantizationRange(nvinfer1::ITensor* tensor, + float min_range, float max_range) { + float symmetric_range = std::max(std::abs(min_range), std::abs(max_range)); + quantization_ranges_[tensor] = symmetric_range; +} + +void Converter::MaybeApplyQuantizationRanges() { + if (precision_mode() != INT8MODE) return; + + // Infer ranges across marked ops. + PropagateQuantizationRanges(); + // Apply ranges. +#if NV_TENSORRT_MAJOR >= 5 + for (auto pair : quantization_ranges_) { + nvinfer1::ITensor* tensor = pair.first; + const float range = pair.second; + VLOG(1) << "Setting range for: " << tensor->getName() << ": " << range; + // TODO(laigd): if 'tensor' already has a range set which doesn't match + // 'range', it should report error. + tensor->setDynamicRange(-range, range); + } +#endif + + // Warn user about tensors that are missing ranges. If TRT fuses some layers + // then these tensors may not actually be required, which is why this is + // just a warning. If we are still missing ranges even after fusion, + // Builder::buildCudaEngine() will return nullptr and we will catch the + // error at that point. + if (!use_calibration()) { + // Get all tensors from network + std::set all_tensors; + for (int i = 0; i < this->network()->getNbLayers(); i++) { + nvinfer1::ILayer* layer = this->network()->getLayer(i); + for (int j = 0; j < layer->getNbInputs(); j++) { + all_tensors.insert(layer->getInput(j)); + } + for (int j = 0; j < layer->getNbOutputs(); j++) { + all_tensors.insert(layer->getOutput(j)); + } + } + // Find tensors with no ranges + for (auto tensor : all_tensors) { + if (!quantization_ranges_.count(tensor)) { + // Note: there may be some warnings for "(Unnamed ITensor* N)". These + // are tensors which are created internally by TF-TRT. The ranges for + // these unnamed ITensors are always inferred from user provided ranges, + // thus there will also be a warning for the range(s) the user missed. + LOG(WARNING) << "Quantization range was not found for " + << tensor->getName() << ". " + << "This is okay if TensorRT does not need the range " + << "(e.g. due to node fusion)."; + } + } + } +} + +void Converter::PropagateQuantizationRanges() { + // Propagate ranges across edges in quantization_infer_ until no new + // information is added. + // Note: this function modifies quantization_infer_, it might be better to + // modify a copy instead if we for some reason need quantization_infer_ + // later. + bool information_added = true; + while (information_added) { + information_added = false; + for (auto it = quantization_infer_.begin(); + it != quantization_infer_.end();) { + auto input_tensor_range = quantization_ranges_.find(it->first); + auto output_tensor_range = quantization_ranges_.find(it->second); + if (input_tensor_range != quantization_ranges_.end() && + output_tensor_range == quantization_ranges_.end()) { + // Input has range but output doesn't: copy range + // TODO(laigd): consider reporting error if it a different range is + // already set. + quantization_ranges_[it->second] = input_tensor_range->second; + information_added = true; + VLOG(1) << "Copy quantization range: " << it->first->getName() << " -> " + << it->second->getName(); + } + // We can remove edges when the output range is known + if (quantization_ranges_.find(it->second) != quantization_ranges_.end()) { + it = quantization_infer_.erase(it); + } else { + ++it; + } + } + } +} + Status Converter::GetInputs(const tensorflow::NodeDef& node_def, std::vector* inputs) const { for (auto const& input_name : node_def.input()) { @@ -1247,7 +1405,7 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, } } - if (params->converter->is_fp16()) { + if (params->converter->precision_mode() == FP16MODE) { weights = ConvertFP32ToFP16(params->weight_store, weights); } @@ -1264,6 +1422,10 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, *const_cast(tensor), nvinfer1::UnaryOperation::kNEG); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); + // Since quantization ranges are symmetric, the same range as the input + // will work for the negation of the input. + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), layer->getOutput(0)); tensor = layer->getOutput(0); } else { TRT_ShapedWeights neg_weights = @@ -1275,6 +1437,25 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, } } else if (node_def.op() == "Div" || node_def.op() == "RealDiv") { if (swapped_inputs) { + // We need to infer the quantization range for this intermediate tensor. + // + // x -> [Recip] -> 1/x -> [Scale] -> s/x + // ^ + // need range for this + // + // We have the quantization scales for x and s/x - can we divide the scale + // for s/x by s? Only if it is a scalar. + // + // Because of this issue, fall back to BinaryTensorOpTensor if we are + // doing INT8 with no calibration. There is most likely no performance + // penalty by falling back here. + if (params->converter->precision_mode() == INT8MODE && + !params->converter->use_calibration()) { + return errors::Unimplemented( + "Intermediate quantization range cannot be determined without" + " calibration. Falling back to BinaryTensorOpTensor for ", + node_def.op(), ", at ", node_def.name()); + } scale_weights = weights; nvinfer1::IUnaryLayer* layer = params->converter->network()->addUnary( *const_cast(tensor), @@ -1350,7 +1531,7 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) { return tensorflow::errors::Internal( "Conv2D expects kernel of dimension 4, at: " + node_def.name()); } - if (params->converter->is_fp16()) { + if (params->converter->precision_mode() == FP16MODE) { weights_rsck = ConvertFP32ToFP16(params->weight_store, inputs.at(1).weights()); } @@ -1397,6 +1578,8 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) { nvinfer1::DimsHW(padding[0].first, padding[1].first), nvinfer1::DimsHW(padding[0].second, padding[1].second)); TFTRT_RETURN_ERROR_IF_NULLPTR(pad_layer, node_def.name()); + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), pad_layer->getOutput(0)); padding = {{0, 0}, {0, 0}}; tensor = pad_layer->getOutput(0); VLOG(2) << "TENSOR after: " << DebugString(tensor->getDimensions()); @@ -1741,6 +1924,8 @@ tensorflow::Status ConvertPool(OpConverterParams* params) { nvinfer1::DimsHW(padding[0].first, padding[1].first), nvinfer1::DimsHW(padding[0].second, padding[1].second)); TFTRT_RETURN_ERROR_IF_NULLPTR(pad_layer, node_def.name()); + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), pad_layer->getOutput(0)); padding = {{0, 0}, {0, 0}}; tensor = pad_layer->getOutput(0); } @@ -1748,6 +1933,11 @@ tensorflow::Status ConvertPool(OpConverterParams* params) { nvinfer1::IPoolingLayer* layer = params->converter->network()->addPooling( *const_cast(tensor), type, ksize); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); + // TODO(tmorris): Average pooling may not be entirely safe to infer + // quantization range through (at least forwards - backwards should be fine). + // Max pooling is okay. + params->converter->MarkQuantizationRangesAsInferrable( + const_cast(tensor), layer->getOutput(0)); layer->setStride(stride); layer->setPadding({padding[0].first, padding[1].first}); @@ -1776,6 +1966,148 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { return tensorflow::Status::OK(); } +Status ConvertQuantize(OpConverterParams* params) { + const auto& inputs = params->inputs; + const auto& node_def = params->node_def; + if ((inputs.size() == 0) || + (node_def.op() == "FakeQuantWithMinMaxArgs" && inputs.size() != 1) || + (node_def.op() == "FakeQuantWithMinMaxVars" && inputs.size() != 3) || + (node_def.op() == "QuantizeAndDequantizeV2" && inputs.size() != 3) || + (node_def.op() == "QuantizeAndDequantizeV3" && inputs.size() != 4)) { + return errors::InvalidArgument("Invalid number of inputs for ", + node_def.op(), ", at ", node_def.name()); + } + if (inputs.at(0).is_weights()) { + // TensorRT will automatically quantize weights, so we will ignore ranges + // for weights. + params->outputs->push_back(inputs.at(0)); + return Status::OK(); + } + float min_range = 0.0f; + float max_range = 0.0f; + if (node_def.op() == "FakeQuantWithMinMaxArgs") { + // Get ranges via node attributes. + TFAttrs attrs(node_def); + if (attrs.count("min") == 0 || attrs.count("max") == 0) { + return errors::InvalidArgument("Min or max attribute not found for ", + node_def.op(), " at ", node_def.name()); + } + min_range = attrs.get("min"); + max_range = attrs.get("max"); + } else if (node_def.op() == "FakeQuantWithMinMaxVars" || + node_def.op() == "QuantizeAndDequantizeV2" || + node_def.op() == "QuantizeAndDequantizeV3") { + // Get ranges via inputs. + if (!inputs.at(1).is_weights() || !inputs.at(2).is_weights()) { + return errors::InvalidArgument("Min and max inputs for ", node_def.op(), + " must be weights not tensors, at ", + node_def.name()); + } + auto get_weights_value = [&inputs](int index) { + auto raw_weights = static_cast( + const_cast(inputs.at(index).weights().GetValues())); + return raw_weights[0]; + }; + min_range = get_weights_value(1); + max_range = get_weights_value(2); + } else { + return errors::InvalidArgument("Unknown quantization op ", node_def.op(), + ", at ", node_def.name()); + } + if (params->validation_only) return Status::OK(); + + // Store ranges for tensor + params->converter->ProvideQuantizationRange( + const_cast(inputs.at(0).tensor()), min_range, + max_range); + // Sometimes, TRT may not quantize a tensor, either because it chooses to + // execute a higher precision kernel or because of op fusion. In these cases, + // accuracy will suffer if the model was trained to expect quantization at + // that tensor. We should consider adding a clip(tensor, min_range, max_range) + // operation here to ensure that any arbitrarily placed quantize node will + // execute as expected. However, this will negatively affect performance. If + // users train their models in a way which models inference as close as + // possible (i.e. not quantizing in place where fusion will occur), then there + // is no problem with the current implementation. + params->outputs->push_back(inputs.at(0)); + return Status::OK(); +} + +// TODO(pdavoodi): we should update relu6 implementation once TensorRT supports +// Relu6 natively. +tensorflow::Status ConvertRelu6(OpConverterParams* params) { + const auto& inputs = params->inputs; + const auto& node_def = params->node_def; + if (inputs.size() != 1) { + return tensorflow::errors::InvalidArgument( + "Invalid number of inputs for Relu6, at ", node_def.name()); + } + if (inputs.at(0).is_weights()) { + return tensorflow::errors::Unimplemented( + "Relu6 is only implemented for tensors, not weights, at ", + node_def.name()); + } + if (params->validation_only) return Status::OK(); + // *************************************************************************** + // TensorRT does not implement Relu6 natively. This function converts Relu6 op + // to available TensorRT ops: Relu6(x) = min(Relu(x), 6) + // *************************************************************************** + + // Input Tensor + const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); + + // Relu operation i.e. Relu(x) = max(0, x) + nvinfer1::IActivationLayer* relu_layer = + params->converter->network()->addActivation( + *const_cast(tensor), + nvinfer1::ActivationType::kRELU); + TFTRT_RETURN_ERROR_IF_NULLPTR(relu_layer, node_def.name()); + + // Large range of relu is problematic during quantization in INT8 precision + // mode. Setting dynamic range of relu = [0.f, 6.0f] helps with quantization. + // TRT only uses dynamic ranges in INT8 precision mode, + // and this does not affect the FP32 path. + params->converter->ProvideQuantizationRange(relu_layer->getOutput(0), 0.0f, + 6.0f); + + // Create a constant layer to store the floating point weight i.e. 6.0f This + // tensor will be broadcasted uniformly during elementwise `min` operation. + // The constant has to have the same rank as the input in order for TRT to + // broadcast + nvinfer1::Dims dims; + dims.nbDims = relu_layer->getOutput(0)->getDimensions().nbDims; + for (int i = 0; i < dims.nbDims; i++) { + dims.d[i] = 1; + } + TRT_ShapedWeights weights = params->weight_store->GetTempWeights( + tensorflow::DataType::DT_FLOAT, dims); + auto weights_ptr = + static_cast(const_cast(weights.GetValues())); + weights_ptr[0] = 6.0f; + nvinfer1::IConstantLayer* const6_layer = + params->converter->network()->addConstant(dims, weights.GetTrtWeights()); + TFTRT_RETURN_ERROR_IF_NULLPTR(const6_layer, node_def.name()); + params->converter->ProvideQuantizationRange(const6_layer->getOutput(0), 0.0f, + 6.0f); + + // ElementWise Min Operation + // Min op is a nop for INT8 execution path, as the input tensor + // to this layer will only have values in range [0.f, 6.0f]. + const nvinfer1::ITensor* tensor_l = relu_layer->getOutput(0); + const nvinfer1::ITensor* tensor_r = const6_layer->getOutput(0); + nvinfer1::IElementWiseLayer* relu6_layer = + params->converter->network()->addElementWise( + *const_cast(tensor_l), + *const_cast(tensor_r), + nvinfer1::ElementWiseOperation::kMIN); + TFTRT_RETURN_ERROR_IF_NULLPTR(relu6_layer, node_def.name()); + nvinfer1::ITensor* output_tensor = relu6_layer->getOutput(0); + params->converter->ProvideQuantizationRange(output_tensor, 0.0f, 6.0f); + + params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); + return Status::OK(); +} + tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; @@ -1786,7 +2118,8 @@ tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { } if (params->validation_only) return Status::OK(); - const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); + nvinfer1::ITensor* tensor = + const_cast(inputs.at(0).tensor()); const nvinfer1::Dims original_dims = tensor->getDimensions(); TFAttrs attrs(node_def); const string data_format = attrs.get("data_format"); @@ -1811,9 +2144,11 @@ tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { // TODO(laigd): this doesn't match what the TRT doc says, fix the doc? if (channel_index != 0 || original_dims.nbDims != 3) { nvinfer1::IShuffleLayer* shuffle_layer = - params->converter->network()->addShuffle( - *const_cast(tensor)); + params->converter->network()->addShuffle(*tensor); TFTRT_RETURN_ERROR_IF_NULLPTR(shuffle_layer, node_def.name()); + params->converter->MarkQuantizationRangesAsInferrable( + tensor, shuffle_layer->getOutput(0)); + // NOTE(laigd): for some reason we need to apply the reshape // unconditionally. The default shape has nbDims==-1 and it seems the // behavior is undefined in some cases. @@ -1832,7 +2167,7 @@ tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { } TRT_ShapedWeights weights = inputs.at(1).weights(); - if (params->converter->is_fp16()) { + if (params->converter->precision_mode() == FP16MODE) { weights = ConvertFP32ToFP16(params->weight_store, weights); } nvinfer1::ScaleMode mode = nvinfer1::ScaleMode::kCHANNEL; @@ -1842,8 +2177,8 @@ tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { TRT_ShapedWeights empty_weights(weights.type_); nvinfer1::IScaleLayer* layer = params->converter->network()->addScale( - *const_cast(tensor), mode, weights.GetTrtWeights(), - empty_weights.GetTrtWeights(), empty_weights.GetTrtWeights()); + *tensor, mode, weights.GetTrtWeights(), empty_weights.GetTrtWeights(), + empty_weights.GetTrtWeights()); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); nvinfer1::ITensor* output_tensor = layer->getOutput(0); @@ -1867,6 +2202,8 @@ tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { if (channel_index != 0) { shuffle_layer->setSecondTranspose(permutation); } + params->converter->MarkQuantizationRangesAsInferrable( + output_tensor, shuffle_layer->getOutput(0)); output_tensor = shuffle_layer->getOutput(0); } @@ -2025,6 +2362,9 @@ tensorflow::Status ConvertConst(OpConverterParams* params) { } tensorflow::Status ConvertIdentity(OpConverterParams* params) { + // TODO(tmorris): TRT's Identity layer does not get optimized away as of TRT + // 5.0, however once we know that it does it would be nice to use that + // instead. params->outputs->push_back(params->inputs.at(0)); return tensorflow::Status::OK(); } @@ -2046,6 +2386,13 @@ tensorflow::Status ConvertBinary(OpConverterParams* params) { node_def.name()); } + // TODO(tmorris): TRT plans to deprecate IScaleLayer and will replace it with + // IElementwiseLayer. At that point, we can remove BinaryTensorOpWeight. For + // now, the performance will be slightly better with IScaleLayer because it + // can be fused in more situations. However, most of the benefits of + // IScaleLayer are when the layer performs both a shift and a scale, which we + // don't do except for convolutions. + // // Try to convert into Scale layer first (for better performance) // Since scale layer supports restricted broadcast policy and op types, we // allow failure and try to handle it through Elementwise op @@ -2088,6 +2435,20 @@ tensorflow::Status ConvertUnary(OpConverterParams* params) { nvinfer1::IUnaryLayer* layer; if (node_def.op() == "Rsqrt") { + // We will need a quantization range for intermediate tensor if not using + // calibration. + // + // x -> [Sqrt] -> sqrt(x) -> [Recip] -> 1/sqrt(x) + // ^ + // need range here + if (params->converter->precision_mode() == INT8MODE && + !params->converter->use_calibration()) { + return errors::Unimplemented( + "Intermediate quantization range cannot be determined without" + " calibration for Rsqrt, consider replacing with " + "Sqrt -> FakeQuant -> Reciprocal ops, at ", + node_def.name()); + } layer = params->converter->network()->addUnary( *const_cast(tensor), nvinfer1::UnaryOperation::kSQRT); @@ -2647,6 +3008,8 @@ tensorflow::Status ConvertSoftmax(OpConverterParams* params) { layer->setAxes(1 << (nbDims - 1)); nvinfer1::ITensor* output_tensor = layer->getOutput(0); + // Quantization range for SoftMax is always (0, 1) + params->converter->ProvideQuantizationRange(output_tensor, 0.0f, 1.0f); params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); return tensorflow::Status::OK(); } @@ -2694,6 +3057,13 @@ void TrtNodeValidator::RegisterOpValidators() { op_validators_["Transpose"] = ConvertTranspose; op_validators_["Reshape"] = ConvertReshape; op_validators_["MatMul"] = ConvertMatMul; + + op_validators_["Relu6"] = ConvertRelu6; + + op_validators_["QuantizeAndDequantizeV2"] = ConvertQuantize; + op_validators_["QuantizeAndDequantizeV3"] = ConvertQuantize; + op_validators_["FakeQuantWithMinMaxVars"] = ConvertQuantize; + op_validators_["FakeQuantWithMinMaxArgs"] = ConvertQuantize; } void Converter::RegisterOpConverters() { @@ -2744,6 +3114,11 @@ void Converter::RegisterOpConverters() { op_registry_["MatMul"] = ConvertMatMul; op_registry_["BatchMatMul"] = ConvertBatchMatMul; op_registry_["TopKV2"] = ConvertTopK; + op_registry_["Relu6"] = ConvertRelu6; + op_registry_["QuantizeAndDequantizeV2"] = ConvertQuantize; + op_registry_["QuantizeAndDequantizeV3"] = ConvertQuantize; + op_registry_["FakeQuantWithMinMaxVars"] = ConvertQuantize; + op_registry_["FakeQuantWithMinMaxArgs"] = ConvertQuantize; plugin_converter_ = ConvertPlugin; } @@ -2754,7 +3129,7 @@ tensorflow::Status ConvertGraphDefToEngine( const std::vector& input_shapes, Logger* logger, nvinfer1::IGpuAllocator* allocator, TRTInt8Calibrator* calibrator, - TrtUniquePtrType* engine, + TrtUniquePtrType* engine, bool use_calibration, bool* convert_successfully) { engine->reset(); if (convert_successfully) *convert_successfully = false; @@ -2769,7 +3144,11 @@ tensorflow::Status ConvertGraphDefToEngine( builder->setHalf2Mode(true); } else if (precision_mode == INT8MODE) { builder->setInt8Mode(true); - builder->setInt8Calibrator(calibrator); + if (use_calibration) { + builder->setInt8Calibrator(calibrator); + } else { + builder->setInt8Calibrator(nullptr); + } } // Create the network. @@ -2782,7 +3161,7 @@ tensorflow::Status ConvertGraphDefToEngine( // Build the network VLOG(1) << "Starting engine conversion "; - Converter converter(trt_network.get(), precision_mode == FP16MODE); + Converter converter(trt_network.get(), precision_mode, use_calibration); std::vector> output_tensors; // Graph nodes are already topologically sorted during construction for (const auto& node_def : gdef.node()) { @@ -2838,6 +3217,9 @@ tensorflow::Status ConvertGraphDefToEngine( TF_RETURN_IF_ERROR(converter.RenameAndMarkOutputTensors(output_tensors)); if (convert_successfully) *convert_successfully = true; + // Apply user provided quantization ranges to tensors + converter.MaybeApplyQuantizationRanges(); + // Build the engine. VLOG(1) << "Starting engine creation"; engine->reset(builder->buildCudaEngine(*converter.network())); diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.h b/tensorflow/contrib/tensorrt/convert/convert_nodes.h index 5cc28b33e7..50100a142f 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.h +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.h @@ -92,7 +92,8 @@ struct EngineInfo { EngineInfo() : engine_type(EngineType::TRTStatic), max_workspace_size_bytes(0), - precision_mode(FP32MODE) {} + precision_mode(FP32MODE), + use_calibration(true) {} string engine_name; string device; @@ -109,6 +110,7 @@ struct EngineInfo { int maximum_cached_engines; std::vector cached_engine_batches; int precision_mode; + bool use_calibration; }; // Constructs a graphdef from the segment in the given graph. Adds placeholder @@ -145,7 +147,7 @@ tensorflow::Status ConvertGraphDefToEngine( const std::vector& input_shapes, Logger* logger, nvinfer1::IGpuAllocator* allocator, TRTInt8Calibrator* calibrator, - TrtUniquePtrType* engine, + TrtUniquePtrType* engine, bool use_calibration, bool* convert_successfully); // Helper class for the segmenter to determine whether an output edge from the @@ -392,7 +394,8 @@ class TrtNodeValidator { // Class to convert TF nodes to TRT network. class Converter { public: - Converter(nvinfer1::INetworkDefinition* trt_network, bool is_fp16); + Converter(nvinfer1::INetworkDefinition* trt_network, int precision_mode, + bool use_calibration); ////////////////////////////////////////////////////////////////////////////// // Methods used by the TRT engine builder to build a TRT network from a TF @@ -422,8 +425,27 @@ class Converter { // to add TRT layers. nvinfer1::INetworkDefinition* network() { return trt_network_; } - // Is the converter operating in fp16 mode? - bool is_fp16() const { return is_fp16_; } + // What precision are we targeting? + int precision_mode() const { return precision_mode_; } + + // Calibration will be or was previously performed on this network? + bool use_calibration() const { return use_calibration_; } + + // This should be called on the inputs and outputs of any layer we create + // where we know that the quantization range does not change during that + // operation. (e.g. Reshape, Transpose, Identity, MaxPool). + void MarkQuantizationRangesAsInferrable(nvinfer1::ITensor* input, + nvinfer1::ITensor* output); + + // This function should be called when we know the quantization range of a + // tensor, either from a quantize/dequantize node or when the output is a + // fixed range (e.g. SoftMax, Relu6, Sigmoid). + void ProvideQuantizationRange(nvinfer1::ITensor* tensor, float min_range, + float max_range); + + // Should be called when full TRT network has been constructed and before + // building the engine. + void MaybeApplyQuantizationRanges(); // Below are helper methods for op converters to add different layers to the // TRT network. @@ -457,6 +479,12 @@ class Converter { void RegisterOpConverters(); + void PropagateQuantizationRanges(); + + // Gets the min and max value in a TRT_ShapedWeights + Status GetWeightRange(const TRT_ShapedWeights& weights, float* out_min, + float* out_max) const; + // Registered op converters by op type. std::unordered_map op_registry_; @@ -472,7 +500,25 @@ class Converter { // Store the weights added during construction of trt_network_. TrtWeightStore weight_store_; - const bool is_fp16_; + // During conversion, this table is populated with quantization ranges per + // tensor. MaybeApplyQuantizationRanges() will use this table to set the TRT + // quantization ranges. Since TRT only supports symmetric ranges, we will + // store the range as a single float = max(abs(min_range), abs(max_range)). + // Range refers to the floating point values, e.g. min_range = 0.0f, max_range + // = 6.0f for Relu6. + std::unordered_map quantization_ranges_; + + // Edges where quantization ranges can be inferred (copied) across ops - from + // first tensor to second tensor. PropagateQuantizationRanges() will propagate + // known ranges from quantization_ranges_ across these edges, adding the new + // ranges to quantization_ranges_ so that they can be applied in + // MaybeApplyQuantizationRanges(). + std::vector> + quantization_infer_; + + const int precision_mode_; + + const bool use_calibration_; // Batch size of inputs to trt_network_ added by AddInputTensor(). During // network construction it will update this, use it to verify the batch diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 862754f3d2..b46a7c6c8a 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -35,6 +35,7 @@ limitations under the License. #include "tensorflow/core/grappler/costs/graph_properties.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/test.h" #include "tensorflow/core/protobuf/config.pb.h" // NOLINT #include "tensorflow/core/public/session.h" @@ -49,6 +50,7 @@ namespace tensorflow { namespace tensorrt { namespace convert { +using ::tensorflow::strings::StrCat; using ::testing::ElementsAre; // TODO(laigd): put this into some test utils file. @@ -135,11 +137,12 @@ void ValidateWeights(const TRT_ShapedWeights& weights, // Fake ITensor implementation for testing purposes. class FakeITensor : public nvinfer1::ITensor { public: - FakeITensor() {} + FakeITensor() : dynamic_range_(0.0f) {} - FakeITensor(const nvinfer1::Dims& dims) : dims_(dims) {} + FakeITensor(const nvinfer1::Dims& dims) : dims_(dims), dynamic_range_(0.0f) {} - FakeITensor(const std::vector& dims) : dims_(GetTestDims(dims)) {} + FakeITensor(const std::vector& dims) + : dims_(GetTestDims(dims)), dynamic_range_(0.0f) {} void setName(const char* name) override { name_ = name; } @@ -168,7 +171,12 @@ class FakeITensor : public nvinfer1::ITensor { } #if NV_TENSORRT_MAJOR >= 5 - bool setDynamicRange(float min, float max) override {} + bool setDynamicRange(float min, float max) override { + dynamic_range_ = std::max(std::abs(min), std::abs(max)); + return true; + } + + float getDynamicRange() const override { return dynamic_range_; } #endif private: @@ -176,6 +184,7 @@ class FakeITensor : public nvinfer1::ITensor { nvinfer1::Dims dims_; nvinfer1::DataType type_; nvinfer1::TensorLocation location_; + float dynamic_range_; }; TEST(TRT_ShapedWeights_Test, Basic) { @@ -425,7 +434,9 @@ class ConverterTest : public ::testing::Test { ConverterTest() { builder_.reset(nvinfer1::createInferBuilder(logger_)); network_.reset(builder_->createNetwork()); - converter_.reset(new Converter(network_.get(), /*fp16=*/false)); + converter_.reset(new Converter(network_.get(), + /*precision_mode=*/FP32MODE, + /*use_calibration=*/false)); weight_store_ = &converter_->weight_store_; } @@ -452,8 +463,21 @@ class ConverterTest : public ::testing::Test { return converter_->GetInputs(node_def, inputs); } + Status GetWeightRange(const TRT_ShapedWeights& weights, float* out_min, + float* out_max) const { + return converter_->GetWeightRange(weights, out_min, out_max); + } + + void PropagateQuantizationRanges() { + converter_->PropagateQuantizationRanges(); + } + int batch_size() const { return converter_->batch_size_; } + std::unordered_map& quantization_ranges() { + return converter_->quantization_ranges_; + } + private: Logger logger_; // These members are ordered in a way such that the destruction order is: @@ -676,6 +700,88 @@ TEST_F(ConverterTest, AddAndGetTensorOrWeights) { "tensor/weights my_tensor already exist"); } +template +void TestGetWeightRange(ConverterTest* test, TrtWeightStore* weight_store) { + TRT_ShapedWeights weights = + weight_store->GetTempWeights(DataTypeToEnum::v(), GetTestDims({2, 3})); + const std::vector values = {T(3), T(1), T(2), T(6), T(5), T(4)}; + memcpy(const_cast(weights.GetValues()), values.data(), + weights.size_bytes()); + + float out_min = 0.0f; + float out_max = 0.0f; + TF_EXPECT_OK(test->GetWeightRange(weights, &out_min, &out_max)); + EXPECT_EQ(1.0f, out_min); + EXPECT_EQ(6.0f, out_max); +} + +TEST_F(ConverterTest, GetWeightRange) { + TestGetWeightRange(this, weight_store_); + TestGetWeightRange(this, weight_store_); + TestGetWeightRange(this, weight_store_); +} + +TEST_F(ConverterTest, ProvideQuantizationRange) { + FakeITensor fake_tensor; + // Assymetric range + converter_->ProvideQuantizationRange(&fake_tensor, 0.0f, 6.0f); + EXPECT_EQ(6.0f, quantization_ranges()[&fake_tensor]); + converter_->ProvideQuantizationRange(&fake_tensor, 1.0f, 6.0f); + EXPECT_EQ(6.0f, quantization_ranges()[&fake_tensor]); + converter_->ProvideQuantizationRange(&fake_tensor, -8.0f, 6.0f); + EXPECT_EQ(8.0f, quantization_ranges()[&fake_tensor]); + converter_->ProvideQuantizationRange(&fake_tensor, -8.123f, -6.123f); + EXPECT_EQ(8.123f, quantization_ranges()[&fake_tensor]); + // Symmetric range + converter_->ProvideQuantizationRange(&fake_tensor, -6.123f, 6.123f); + EXPECT_EQ(6.123f, quantization_ranges()[&fake_tensor]); +} + +TEST_F(ConverterTest, MaybeApplyQuantizationRanges) { + // input -> infer1 -> infer2 -> infer3 + FakeITensor input, infer_1, infer_2, infer_3; + FakeITensor not_infer; + Converter int8_converter(/*trt_network=*/nullptr, INT8MODE, + /*use_calibration=*/true); + int8_converter.ProvideQuantizationRange(&input, -5.0f, 5.0f); + int8_converter.ProvideQuantizationRange(¬_infer, -100.0f, 100.0f); + int8_converter.MarkQuantizationRangesAsInferrable(&input, &infer_1); + int8_converter.MarkQuantizationRangesAsInferrable(&infer_1, &infer_2); + int8_converter.MarkQuantizationRangesAsInferrable(&infer_2, &infer_3); + + // Input range should be inferred along the chain and applied to tensors. + int8_converter.MaybeApplyQuantizationRanges(); +#if NV_TENSORRT_MAJOR >= 5 + EXPECT_EQ(input.getDynamicRange(), 5.0f); + EXPECT_EQ(infer_1.getDynamicRange(), 5.0f); + EXPECT_EQ(infer_2.getDynamicRange(), 5.0f); + EXPECT_EQ(infer_3.getDynamicRange(), 5.0f); + EXPECT_EQ(not_infer.getDynamicRange(), 100.0f); +#endif +} + +TEST_F(ConverterTest, PropagateQuantizationRanges) { + // infer0 <-> infer1 <-> infer2 <-> infer3 + // | + // infer4 <-> infer5 + FakeITensor infer[6]; + FakeITensor not_infer; + converter_->ProvideQuantizationRange(&infer[4], -5.0f, 5.0f); + converter_->MarkQuantizationRangesAsInferrable(&infer[0], &infer[1]); + converter_->MarkQuantizationRangesAsInferrable(&infer[1], &infer[2]); + converter_->MarkQuantizationRangesAsInferrable(&infer[3], &infer[2]); + converter_->MarkQuantizationRangesAsInferrable(&infer[4], &infer[1]); + converter_->MarkQuantizationRangesAsInferrable(&infer[4], &infer[5]); + + // Input range should be inferred along the chain. + PropagateQuantizationRanges(); + auto ranges = quantization_ranges(); + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(5.0f, ranges[&infer[i]]); + } + EXPECT_EQ(ranges.count(¬_infer), 0); +} + // Class to test various op converters, using both a TrtNodeValidator and // Converter. class OpConverterTest : public ::testing::Test { @@ -704,7 +810,9 @@ class OpConverterTest : public ::testing::Test { // Reset the validator and converter. validator_.reset(new TrtNodeValidator); - converter_.reset(new Converter(network_.get(), /*fp16=*/false)); + converter_.reset(new Converter(network_.get(), + /*precision_mode=*/FP32MODE, + /*use_calibration=*/false)); // Reset other related artifacts. scope_ = Scope::NewRootScope(); @@ -847,6 +955,11 @@ class OpConverterTest : public ::testing::Test { } } + // Expose quantization_ranges_ for tests + std::unordered_map& quantization_ranges() { + return converter_->quantization_ranges_; + } + std::unique_ptr converter_; std::unique_ptr validator_; @@ -856,6 +969,11 @@ class OpConverterTest : public ::testing::Test { TrtUniquePtrType network_; TrtUniquePtrType engine_; cudaStream_t stream_; + // Used to create placeholders with shape and data type information. The + // created placeholders will be used as inputs to the node to be verified, + // thus we need the shape and data type information to get a non-empty + // GraphProperties. + // TODO(laigd): consider use this Scope to create the NodeDef to verify. Scope scope_; std::unordered_map validator_inputs_; }; @@ -1233,6 +1351,169 @@ TEST_F(OpConverterTest, ConvertBiasAdd) { // TestConvertBiasAdd(this); } +TEST_F(OpConverterTest, ConvertQuantize) { + for (const string& op : + {"FakeQuantWithMinMaxArgs", "FakeQuantWithMinMaxVars", + "QuantizeAndDequantizeV2", "QuantizeAndDequantizeV3"}) { + // Input list is empty, should fail. + NodeDef node_def = MakeNodeDef("my_quantize", op, {}); + RunValidationAndConversion( + node_def, error::INVALID_ARGUMENT, + StrCat("Invalid number of inputs for ", op, ", at my_quantize") + .c_str()); + } + { + // FakeQuantWithMinMaxArgs attributes are empty, should fail. + NodeDef node_def = + MakeNodeDef("my_quantize", "FakeQuantWithMinMaxArgs", {"input"}); + AddTestTensor("input", {1, 2, 3}); + RunValidationAndConversion( + node_def, error::INVALID_ARGUMENT, + "Min or max attribute not found for FakeQuantWithMinMaxArgs " + "at my_quantize"); + } + { + // FakeQuantWithMinMaxArgs ranges set via attributes, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto quantize_attrs = ops::FakeQuantWithMinMaxArgs::Min(-6.0f).Max(6.0f); + auto quantize = ops::FakeQuantWithMinMaxArgs(s.WithOpName("my_quantize"), + input, quantize_attrs); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(1, ranges.count(output.tensor())); + EXPECT_EQ(6.0f, ranges[output.tensor()]); + } + { + // FakeQuantWithMinMaxVars ranges set via inputs, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto quantize = ops::FakeQuantWithMinMaxVars( + s.WithOpName("my_quantize"), input, weights_min, weights_max); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + AddTestWeights("weights_min", {1}, {-6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(1, ranges.count(output.tensor())); + EXPECT_EQ(6.0f, ranges[output.tensor()]); + } + { + // QuantizeAndDequantizeV2 ranges set via inputs, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto quantize = ops::QuantizeAndDequantizeV2( + s.WithOpName("my_quantize"), input, weights_min, weights_max); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + AddTestWeights("weights_min", {1}, {-6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(1, ranges.count(output.tensor())); + EXPECT_EQ(6.0f, ranges[output.tensor()]); + } + { + // QuantizeAndDequantizeV2 Range inputs are tensors, should fail. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto quantize = ops::QuantizeAndDequantizeV2( + s.WithOpName("my_quantize"), input, weights_min, weights_max); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + AddTestTensor("weights_min", {1}); + AddTestTensor("weights_max", {1}); + RunValidationAndConversion( + node_def, error::INVALID_ARGUMENT, + "Min and max inputs for QuantizeAndDequantizeV2 must be weights not " + "tensors, at my_quantize"); + } + { + // QuantizeAndDequantizeV3 ranges set via inputs, ok. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto weights_min = ops::Placeholder(s.WithOpName("weights_min"), DT_FLOAT); + auto weights_max = ops::Placeholder(s.WithOpName("weights_max"), DT_FLOAT); + auto num_bits = ops::Placeholder(s.WithOpName("num_bits"), DT_INT32); + auto quantize = ops::QuantizeAndDequantizeV3( + s.WithOpName("my_quantize"), input, weights_min, weights_max, num_bits); + const NodeDef& node_def = quantize.operation.node()->def(); + AddTestTensor("input", {1, 2, 3}); + AddTestWeights("weights_min", {1}, {-6.0f}); + AddTestWeights("weights_max", {1}, {6.0f}); + AddTestWeights("num_bits", {1}, {8}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_quantize", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(1, ranges.count(output.tensor())); + EXPECT_EQ(6.0f, ranges[output.tensor()]); + } +} + +TEST_F(OpConverterTest, ConvertRelu6) { + { + // Input list is empty, should fail. + NodeDef node_def = MakeNodeDef("my_relu6", "Relu6", {}); + RunValidationAndConversion( + node_def, error::INVALID_ARGUMENT, + "Invalid number of inputs for Relu6, at my_relu6"); + } + + // Get the NodeDef for Relu6. + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto relu6 = ops::Relu6(s.WithOpName("my_relu6"), input); + const NodeDef node_def = relu6.operation.node()->def(); + { + // Input is weights, should fail. + Reset(); + AddTestWeights("input", {1}, {1.0f}); + RunValidationAndConversion( + node_def, error::UNIMPLEMENTED, + "Relu6 is only implemented for tensors, not weights, at my_relu6"); + } + { + // Clip tensor values and set quantization ranges, ok. + Reset(); + AddTestTensor("input", {1, 2, 3}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_relu6", &output)); + EXPECT_TRUE(output.is_tensor()); + auto ranges = quantization_ranges(); + EXPECT_EQ(ranges[output.tensor()], 6.0f); + + std::vector output_data(6); + BuildAndRun("input", {-100, -1, 0, 3, 5, 9}, "my_relu6", &output_data); + EXPECT_THAT(output_data, ElementsAre(0, 0, 0, 3, 5, 6)); + } +} + } // namespace convert } // namespace tensorrt } // namespace tensorflow diff --git a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc index b30d94b028..4ac7e21d34 100644 --- a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc +++ b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.cc @@ -67,6 +67,9 @@ tensorflow::Status TRTOptimizationPass::Init( TF_RETURN_IF_ERROR(GetPrecisionMode( Uppercase(params.at("precision_mode").s()), &precision_mode_)); } + if (params.count("use_calibration")) { + use_calibration_ = params.at("use_calibration").b(); + } return tensorflow::Status::OK(); } @@ -222,6 +225,12 @@ tensorflow::Status TRTOptimizationPass::Optimize( TF_RETURN_IF_ERROR(static_graph_properties.InferStatically(true)); tensorflow::tensorrt::convert::ConversionParams cp; + if (use_calibration_ && precision_mode_ != INT8MODE) { + LOG(ERROR) << "Calibration with FP32 or FP16 is not implemented. " + << "Falling back to use_calibration = False."; + use_calibration_ = false; + } + std::vector nodes_to_preserve; for (const auto& n : item.NodesToPreserve()) { auto tokens = str_util::Split(n, ":"); @@ -250,6 +259,7 @@ tensorflow::Status TRTOptimizationPass::Optimize( cp.is_dyn_op = is_dynamic_op_; cp.cached_engine_batches = batches_; cp.max_cached_engines = max_cached_batches_; + cp.use_calibration = use_calibration_; auto status = tensorflow::tensorrt::convert::ConvertAfterShapes(cp); VLOG(1) << "Returning from " << name_; return status; diff --git a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h index 71b51d1368..3e8dc0978e 100644 --- a/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h +++ b/tensorflow/contrib/tensorrt/convert/trt_optimization_pass.h @@ -38,7 +38,8 @@ class TRTOptimizationPass : public tensorflow::grappler::CustomGraphOptimizer { maximum_batch_size_(-1), is_dynamic_op_(false), max_cached_batches_(1), - max_workspace_size_bytes_(256LL << 20) { + max_workspace_size_bytes_(256LL << 20), + use_calibration_(true) { VLOG(1) << "Constructing " << name_; } @@ -67,6 +68,7 @@ class TRTOptimizationPass : public tensorflow::grappler::CustomGraphOptimizer { std::vector batches_; int max_cached_batches_; int64_t max_workspace_size_bytes_; + bool use_calibration_; }; } // namespace convert diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc index 019446813a..1e907e0d2a 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc @@ -124,8 +124,10 @@ TRTEngineOp::TRTEngineOp(OpKernelConstruction* context) OP_REQUIRES_OK(context, context->GetAttr("segment_funcdef_name", &funcdef_name_)); OP_REQUIRES_OK(context, GetPrecisionMode(precision_string, &precision_mode_)); - calibration_mode_ = - (precision_mode_ == INT8MODE && calibration_data.size() == 0); + OP_REQUIRES_OK(context, + context->GetAttr("use_calibration", &use_calibration_)); + calibration_mode_ = (use_calibration_ && precision_mode_ == INT8MODE && + calibration_data.size() == 0); if (calibration_data.size()) { calibrator_.reset(new TRTInt8Calibrator(calibration_data)); calibration_data.resize(0); @@ -308,7 +310,7 @@ bool TRTEngineOp::ExecuteTrtEngine( std::vector buffers(num_binding); for (int i = 0; i < ctx->num_inputs(); i++) { const string input_name = StrCat(kInputPHName, i); - const size_t binding_index = + const int binding_index = trt_engine_ptr->getBindingIndex(input_name.c_str()); if (binding_index == -1) { LOG(ERROR) << "Input node not found, at " << input_name; @@ -345,7 +347,7 @@ bool TRTEngineOp::ExecuteTrtEngine( for (int i = 0; i < ctx->num_outputs(); i++) { // Create an output tensor const string output_name = StrCat(kOutputPHName, i); - const size_t binding_index = + const int binding_index = trt_engine_ptr->getBindingIndex(output_name.c_str()); Tensor* output_tensor = nullptr; @@ -497,7 +499,8 @@ TRTEngineOp::EngineCtxPair& TRTEngineOp::GetEngine(int batch_size, // means calibration_mode_ is true and this path won't get executed. auto status = convert::ConvertGraphDefToEngine( segment_graph_, precision_mode_, batch_size, workspace_size_, shapes, - &logger, allocator, calibrator_.get(), &engine, &convert_successfully); + &logger, allocator, calibrator_.get(), &engine, use_calibration_, + &convert_successfully); if (!status.ok()) { if (convert_successfully) { // This means it fail to build the engine even when the network is built @@ -586,6 +589,7 @@ tensorflow::Status TRTEngineOp::AllocateCalibrationResources( *segment_graph, INT8MODE, cres->calibrator_->getBatchSize(), workspace_size_bytes, shapes, &cres->logger_, cres->allocator_.get(), cres->calibrator_.get(), &cres->engine_, + /*use_calibration=*/true, /*convert_successfully=*/nullptr); if (!s.ok()) { LOG(ERROR) << "Calibration failed: " << s; diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h index 8fe0675891..b545f497f3 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h @@ -130,6 +130,10 @@ class TRTEngineOp : public AsyncOpKernel { // The finalized calibrator for inference. std::unique_ptr calibrator_; + + // If true, create calibration graph for INT8 mode. Otherwise, we are using + // user-provided quantization ranges. + bool use_calibration_; }; } // namespace tensorrt diff --git a/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc b/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc index e0c7b62723..ce04e5806e 100644 --- a/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc @@ -39,8 +39,9 @@ REGISTER_OP("TRTEngineOp") .Attr("cached_engine_batches: list(int) = []") .Attr("max_cached_engines_count: int = 1") .Attr("workspace_size_bytes: int") - .Attr("precision_mode: {'FP32', 'FP16', 'INT8', 'INT8CALIB'}") + .Attr("precision_mode: {'FP32', 'FP16', 'INT8'}") .Attr("calibration_data: string = ''") + .Attr("use_calibration: bool = true") .Input("in_tensor: InT") .Output("out_tensor: OutT"); // TODO(jie): TF requires concrete output shape for concrete input shapes. diff --git a/tensorflow/contrib/tensorrt/python/trt_convert.py b/tensorflow/contrib/tensorrt/python/trt_convert.py index 0e59fdd1fe..74a2c2392a 100644 --- a/tensorflow/contrib/tensorrt/python/trt_convert.py +++ b/tensorflow/contrib/tensorrt/python/trt_convert.py @@ -70,7 +70,8 @@ def get_tensorrt_rewriter_config(rewriter_config=None, minimum_segment_size=3, is_dynamic_op=False, maximum_cached_engines=1, - cached_engine_batch_sizes=None): + cached_engine_batch_sizes=None, + use_calibration=True): """Returns a RewriterConfig proto for TRT transformation. Args: @@ -95,6 +96,15 @@ def get_tensorrt_rewriter_config(rewriter_config=None, use this list to determine the batch sizes of the cached engines, instead of making the decision on the fly. This is useful when we know the most common batch size(s) the application is going to generate. + use_calibration: this argument is ignored if precision_mode is not INT8. if + set to True, a calibration graph will be created to calibrate the missing + ranges. The calibration graph must be converted to an inference graph + using calib_graph_to_infer_graph() after running calibration. if set to + False, quantization nodes will be expected for every tensor in the graph + (exlcuding those which will be fused). If a range is missing, an error + will occur. Please note that accuracy may be negatively affected if there + is a mismatch between which tensors TRT quantizes and which tensors were + trained with fake quantization. Returns: A RewriterConfig proto which sets a TensorRTOptimizer to run Grappler. @@ -141,6 +151,7 @@ def get_tensorrt_rewriter_config(rewriter_config=None, "maximum_cached_engines items.") optimizer.parameter_map["cached_engine_batches"].list.i.extend( cached_engine_batch_sizes) + optimizer.parameter_map["use_calibration"].b = use_calibration return rewriter_config_with_trt @@ -153,6 +164,7 @@ def create_inference_graph(input_graph_def, is_dynamic_op=False, maximum_cached_engines=1, cached_engine_batch_sizes=None, + use_calibration=True, input_saved_model_dir=None, input_saved_model_tags=None, output_saved_model_dir=None, @@ -184,6 +196,15 @@ def create_inference_graph(input_graph_def, use this list to determine the batch sizes of the cached engines, instead of making the decision on the fly. This is useful when we know the most common batch size(s) the application is going to generate. + use_calibration: this argument is ignored if precision_mode is not INT8. if + set to True, a calibration graph will be created to calibrate the missing + ranges. The calibration graph must be converted to an inference graph + using calib_graph_to_infer_graph() after running calibration. if set to + False, quantization nodes will be expected for every tensor in the graph + (exlcuding those which will be fused). If a range is missing, an error + will occur. Please note that accuracy may be negatively affected if there + is a mismatch between which tensors TRT quantizes and which tensors were + trained with fake quantization. input_saved_model_dir: the directory to load the SavedModel which contains the input graph to transforms. Used only when input_graph_def is None. input_saved_model_tags: list of tags to load the SavedModel. @@ -333,7 +354,7 @@ def create_inference_graph(input_graph_def, rewriter_config_with_trt = get_tensorrt_rewriter_config( rewriter_config, max_batch_size, max_workspace_size_bytes, precision_mode, minimum_segment_size, is_dynamic_op, maximum_cached_engines, - cached_engine_batch_sizes) + cached_engine_batch_sizes, use_calibration) session_config_with_trt.graph_options.rewrite_options.CopyFrom( rewriter_config_with_trt) diff --git a/tensorflow/contrib/tensorrt/test/base_test.py b/tensorflow/contrib/tensorrt/test/base_test.py index 18096e0ff1..7e826fb7e1 100644 --- a/tensorflow/contrib/tensorrt/test/base_test.py +++ b/tensorflow/contrib/tensorrt/test/base_test.py @@ -197,7 +197,9 @@ class PartiallyConvertedTestA(trt_test.TfTrtIntegrationTestBase): """Whether to run the test.""" # Disable the test in fp16 mode since multiple matmul and add ops together # can cause overflow. - return run_params.precision_mode != "FP16" + return ((run_params.precision_mode != "FP16") and + not (trt_test.IsQuantizationMode(run_params.precision_mode) and + not run_params.use_calibration)) class PartiallyConvertedTestB(PartiallyConvertedTestA): diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py new file mode 100644 index 0000000000..e7d6ec4ad3 --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/quantization_mnist_test.py @@ -0,0 +1,290 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Script to test TF-TRT INT8 conversion without calibration on Mnist model.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.contrib.tensorrt.python import trt_convert +# pylint: disable=unused-import +from tensorflow.contrib.tensorrt.python.ops import trt_engine_op +# pylint: enable=unused-import +from tensorflow.core.protobuf import config_pb2 +from tensorflow.python import data +from tensorflow.python import keras +from tensorflow.python.estimator.estimator import Estimator +from tensorflow.python.estimator.model_fn import EstimatorSpec +from tensorflow.python.estimator.model_fn import ModeKeys +from tensorflow.python.estimator.run_config import RunConfig +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import graph_util +from tensorflow.python.framework import importer +from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util +from tensorflow.python.keras.datasets import mnist +from tensorflow.python.layers import layers +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import gen_array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import metrics +from tensorflow.python.ops import nn +from tensorflow.python.ops import variable_scope +from tensorflow.python.ops.losses import losses +from tensorflow.python.platform import test +from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.summary import summary +from tensorflow.python.training import saver +from tensorflow.python.training.adam import AdamOptimizer +from tensorflow.python.training.checkpoint_management import latest_checkpoint +from tensorflow.python.training.training_util import get_global_step + +INPUT_NODE_NAME = 'input' +OUTPUT_NODE_NAME = 'output' + + +class QuantizationAwareTrainingMNISTTest(test_util.TensorFlowTestCase): + + def _BuildGraph(self, x): + + def _Quantize(x, r): + x = gen_array_ops.quantize_and_dequantize_v2(x, -r, r) + return x + + def _DenseLayer(x, num_inputs, num_outputs, quantization_range, name): + """Dense layer with quantized outputs. + + Args: + x: input to the dense layer + num_inputs: number of input columns of x + num_outputs: number of output columns + quantization_range: the min/max range for quantization + name: name of the variable scope + + Returns: + The output of the layer. + """ + with variable_scope.variable_scope(name): + kernel = variable_scope.get_variable( + 'kernel', + shape=[num_inputs, num_outputs], + dtype=dtypes.float32, + initializer=keras.initializers.glorot_uniform()) + bias = variable_scope.get_variable( + 'bias', + shape=[num_outputs], + dtype=dtypes.float32, + initializer=keras.initializers.zeros()) + x = math_ops.matmul(x, kernel) + x = _Quantize(x, quantization_range) + x = nn.bias_add(x, bias) + x = _Quantize(x, quantization_range) + return x + + x = _Quantize(x, 1) + # Conv + Bias + Relu6 + x = layers.conv2d(x, filters=32, kernel_size=3, use_bias=True) + x = nn.relu6(x) + # Conv + Bias + Relu6 + x = layers.conv2d(x, filters=64, kernel_size=3, use_bias=True) + x = nn.relu6(x) + # Reduce + x = math_ops.reduce_mean(x, [1, 2]) + x = _Quantize(x, 6) + # FC1 + x = _DenseLayer(x, 64, 512, 6, name='dense') + x = nn.relu6(x) + # FC2 + x = _DenseLayer(x, 512, 10, 25, name='dense_1') + x = array_ops.identity(x, name=OUTPUT_NODE_NAME) + return x + + def _GetGraphDef(self, use_trt, max_batch_size, model_dir): + """Get the frozen mnist GraphDef. + + Args: + use_trt: whether use TF-TRT to convert the graph. + max_batch_size: the max batch size to apply during TF-TRT conversion. + model_dir: the model directory to load the checkpoints. + + Returns: + The frozen mnist GraphDef. + """ + graph = ops.Graph() + with self.session(graph=graph) as sess: + with graph.device('/GPU:0'): + x = array_ops.placeholder( + shape=(None, 28, 28, 1), dtype=dtypes.float32, name=INPUT_NODE_NAME) + self._BuildGraph(x) + # Load weights + mnist_saver = saver.Saver() + checkpoint_file = latest_checkpoint(model_dir) + mnist_saver.restore(sess, checkpoint_file) + # Freeze + graph_def = graph_util.convert_variables_to_constants( + sess, sess.graph_def, output_node_names=[OUTPUT_NODE_NAME]) + # Convert with TF-TRT + if use_trt: + logging.info('Number of nodes before TF-TRT conversion: %d', + len(graph_def.node)) + graph_def = trt_convert.create_inference_graph( + graph_def, + outputs=[OUTPUT_NODE_NAME], + max_batch_size=max_batch_size, + precision_mode='INT8', + max_workspace_size_bytes=4096 << 19, + minimum_segment_size=2, + use_calibration=False, + ) + logging.info('Number of nodes after TF-TRT conversion: %d', + len(graph_def.node)) + num_engines = len( + [1 for n in graph_def.node if str(n.op) == 'TRTEngineOp']) + self.assertEqual(1, num_engines) + return graph_def + + def _Run(self, is_training, use_trt, batch_size, num_epochs, model_dir): + """Train or evaluate the model. + + Args: + is_training: whether to train or evaluate the model. In training mode, + quantization will be simulated where the quantize_and_dequantize_v2 are + placed. + use_trt: if true, use TRT INT8 mode for evaluation, which will perform + real quantization. Otherwise use native TensorFlow which will perform + simulated quantization. Ignored if is_training is True. + batch_size: batch size. + num_epochs: how many epochs to train. Ignored if is_training is False. + model_dir: where to save or load checkpoint. + + Returns: + The Estimator evaluation result. + """ + # Get dataset + train_data, test_data = mnist.load_data() + + def _PreprocessFn(x, y): + x = math_ops.cast(x, dtypes.float32) + x = array_ops.expand_dims(x, axis=2) + x = 2.0 * (x / 255.0) - 1.0 + y = math_ops.cast(y, dtypes.int32) + return x, y + + def _EvalInputFn(): + mnist_x, mnist_y = test_data + dataset = data.Dataset.from_tensor_slices((mnist_x, mnist_y)) + dataset = dataset.apply( + data.experimental.map_and_batch( + map_func=_PreprocessFn, + batch_size=batch_size, + num_parallel_calls=8)) + dataset = dataset.repeat(count=1) + iterator = dataset.make_one_shot_iterator() + features, labels = iterator.get_next() + return features, labels + + def _TrainInputFn(): + mnist_x, mnist_y = train_data + dataset = data.Dataset.from_tensor_slices((mnist_x, mnist_y)) + dataset = dataset.shuffle(2 * len(mnist_x)) + dataset = dataset.apply( + data.experimental.map_and_batch( + map_func=_PreprocessFn, + batch_size=batch_size, + num_parallel_calls=8)) + dataset = dataset.repeat(count=num_epochs) + iterator = dataset.make_one_shot_iterator() + features, labels = iterator.get_next() + return features, labels + + def _ModelFn(features, labels, mode): + if is_training: + logits_out = self._BuildGraph(features) + else: + graph_def = self._GetGraphDef(use_trt, batch_size, model_dir) + logits_out = importer.import_graph_def( + graph_def, + input_map={INPUT_NODE_NAME: features}, + return_elements=[OUTPUT_NODE_NAME + ':0'], + name='')[0] + + loss = losses.sparse_softmax_cross_entropy( + labels=labels, logits=logits_out) + summary.scalar('loss', loss) + + classes_out = math_ops.argmax(logits_out, axis=1, name='classes_out') + accuracy = metrics.accuracy( + labels=labels, predictions=classes_out, name='acc_op') + summary.scalar('accuracy', accuracy[1]) + + if mode == ModeKeys.EVAL: + return EstimatorSpec( + mode, loss=loss, eval_metric_ops={'accuracy': accuracy}) + elif mode == ModeKeys.TRAIN: + optimizer = AdamOptimizer(learning_rate=1e-2) + train_op = optimizer.minimize(loss, global_step=get_global_step()) + return EstimatorSpec(mode, loss=loss, train_op=train_op) + + config_proto = config_pb2.ConfigProto() + config_proto.gpu_options.allow_growth = True + estimator = Estimator( + model_fn=_ModelFn, + model_dir=model_dir if is_training else None, + config=RunConfig(session_config=config_proto)) + + if is_training: + estimator.train(_TrainInputFn) + results = estimator.evaluate(_EvalInputFn) + logging.info('accuracy: %s', str(results['accuracy'])) + return results + + # To generate the checkpoint, set a different model_dir and call self._Run() + # by setting is_training=True and num_epochs=1000, e.g.: + # model_dir = '/tmp/quantization_mnist' + # self._Run( + # is_training=True, + # use_trt=False, + # batch_size=128, + # num_epochs=100, + # model_dir=model_dir) + def testEval(self): + if not trt_convert.is_tensorrt_enabled(): + return + model_dir = test.test_src_dir_path('contrib/tensorrt/test/testdata') + + accuracy_tf_native = self._Run( + is_training=False, + use_trt=False, + batch_size=128, + num_epochs=None, + model_dir=model_dir)['accuracy'] + logging.info('accuracy_tf_native: %f', accuracy_tf_native) + self.assertAllClose(accuracy_tf_native, 0.9662) + + if trt_convert.get_linked_tensorrt_version()[0] < 5: + return + + accuracy_tf_trt = self._Run( + is_training=False, + use_trt=True, + batch_size=128, + num_epochs=None, + model_dir=model_dir)['accuracy'] + logging.info('accuracy_tf_trt: %f', accuracy_tf_trt) + self.assertAllClose(accuracy_tf_trt, 0.9677) + + +if __name__ == '__main__': + test.main() diff --git a/tensorflow/contrib/tensorrt/test/quantization_test.py b/tensorflow/contrib/tensorrt/test/quantization_test.py new file mode 100644 index 0000000000..28353273ed --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/quantization_test.py @@ -0,0 +1,144 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Model script to test TF-TensorRT integration.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.contrib.tensorrt.python import trt_convert +from tensorflow.contrib.tensorrt.test import tf_trt_integration_test_base as trt_test +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import gen_array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.platform import test + + +def _GetParams(add_quantization_nodes, dtype=dtypes.float32): + input_name = "input" + input_dims = [8, 8] + output_name = "output" + + def _Quantize(x, r): + if add_quantization_nodes: + x = gen_array_ops.fake_quant_with_min_max_vars(x, -r, r) + return x + + g = ops.Graph() + with g.as_default(): + x = array_ops.placeholder( + dtype=dtype, shape=[None] + input_dims[1:], name=input_name) + x = _Quantize(x, 10.0) + x = x + 5 + x = _Quantize(x, 15.0) + x = x - 5 + x = _Quantize(x, 10.0) + x = x * 0.1 + x = _Quantize(x, 1.0) + w = constant_op.constant(np.ones((8, 1)), dtype=dtypes.float32) + x = math_ops.matmul(x, w) + x = _Quantize(x, 10.0) + x = array_ops.identity(x, name=output_name) + + return trt_test.TfTrtIntegrationTestParams( + gdef=g.as_graph_def(), + input_names=[input_name], + input_dims=[input_dims], + output_names=[output_name], + expected_output_dims=[(8, 1)]) + + +class QuantizationMissingAllRangesTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Create a graph containing single segment with no quantization ranges.""" + return _GetParams(add_quantization_nodes=False) + + def ShouldRunTest(self, run_params): + if trt_convert.get_linked_tensorrt_version()[0] < 5: + return False + # Only test static engine mode, with or without calibration. + return (trt_test.IsQuantizationMode(run_params.precision_mode) and + not run_params.use_optimizer and not run_params.dynamic_engine) + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + if run_params.use_calibration: + # In static engine mode with calibration, it should build a calibration + # engine. + return ["my_trt_op_0"] + # In static engine mode without calibration, the engine building will fail + # since no quantization ranges are set, which results in no TRT nodes. + return [] + + +class QuantizationWithRangesTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Create a graph containing single segment with no quantization ranges.""" + return _GetParams(add_quantization_nodes=True) + + def ShouldRunTest(self, run_params): + if trt_convert.get_linked_tensorrt_version()[0] < 5: + return False + # Test static/dynamic engine with/without calibration. + return (trt_test.IsQuantizationMode(run_params.precision_mode) and + not run_params.use_optimizer) + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + return ["my_trt_op_0"] + + def ExpectedAbsoluteTolerance(self, run_params): + """The absolute tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + + def ExpectedRelativeTolerance(self, run_params): + """The relative tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + + +class NonQuantizedPrecisionsWithRangesTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Create a graph containing single segment with no quantization ranges.""" + return _GetParams(add_quantization_nodes=True) + + def ShouldRunTest(self, run_params): + # Only test FP32/FP16 mode. + return not trt_test.IsQuantizationMode(run_params.precision_mode) + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + # The fake quant ops are not supported in FP32/FP16 mode, and will split the + # graph into three TRT segments. + return ["my_trt_op_0", "my_trt_op_1", "my_trt_op_2", "my_trt_op_3"] + + def ExpectedAbsoluteTolerance(self, run_params): + """The absolute tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + + def ExpectedRelativeTolerance(self, run_params): + """The relative tolerance to compare floating point results.""" + return 1.e-05 if run_params.precision_mode == "FP32" else 1.e-01 + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/contrib/tensorrt/test/testdata/checkpoint b/tensorflow/contrib/tensorrt/test/testdata/checkpoint new file mode 100644 index 0000000000..a603e1aec9 --- /dev/null +++ b/tensorflow/contrib/tensorrt/test/testdata/checkpoint @@ -0,0 +1,3 @@ +model_checkpoint_path: "model.ckpt-46900" +all_model_checkpoint_paths: "model.ckpt-0" +all_model_checkpoint_paths: "model.ckpt-46900" diff --git a/tensorflow/contrib/tensorrt/test/testdata/model.ckpt-46900.data-00000-of-00001 b/tensorflow/contrib/tensorrt/test/testdata/model.ckpt-46900.data-00000-of-00001 new file mode 100644 index 0000000000000000000000000000000000000000..88a998f184b275121e1e76eb51d2310da149f10a GIT binary patch literal 686728 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

n|U(L*sXt#p& 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

(u53Zi|>OUYUFmuAY)@+~zxZ#1~s# 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 kmi}G5*R6iv-W%pe_iH$@?Ay6RVqaQxx1E+b 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 F0{~I{!JYsB literal 0 HcmV?d00001 diff --git a/tensorflow/contrib/tensorrt/test/testdata/model.ckpt-46900.index b/tensorflow/contrib/tensorrt/test/testdata/model.ckpt-46900.index new file mode 100644 index 0000000000000000000000000000000000000000..537976571337508ab1798d33646c51d62a146ecc GIT binary patch literal 652 zcmaFOHiLnIje}8&iGz`Wn>#7BB+)RwAiq4dh=WmxL4(C~S+$@Q3p=k-yr}2_1r`k! z(^q#&7Bg@QCFkdr8KvkaWhNGLFbc5xp;aA-6znmW$Aki*R?tnZkTm@6v9(!t0m ztxz&qF+_k#INnfFf`N%qBA}zWW2OTm9LvBZnv$AV zoGN(QhgFD~qk%=C;|Z@ugMjI}C*iCN{IW`d)q?5_Us%;8!oGXB^D~LE<_k)(wD2)H zN`$;~X<}oO61~m9$#|YO*<=czMneOKsQ|ZvC=aWYV3d&(1A`c=k_77c{dB~nipQ* GetOpsFormatAgnostic() { "Exit", "Exp", "Expm1", + "FakeQuantWithMinMaxVars", + "FakeQuantWithMinMaxArgs", "Fill", "Floor", "FloorDiv", @@ -161,6 +163,8 @@ std::set GetOpsFormatAgnostic() { "PreventGradient", "Prod", "Polygamma", + "QuantizeAndDequantizeV2", + "QuantizeAndDequantizeV3", "Pow", "Real", "RealDiv", -- GitLab From e16716d94c0c6cde419129827c37a8f61bd8b023 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 20 Nov 2018 15:39:19 -0800 Subject: [PATCH 160/672] Remove unused lambda captures This fixes the lambda capture <> is not used compiler warning. PiperOrigin-RevId: 222318600 --- .../image/kernels/adjust_hsv_in_yiq_op.cc | 2 +- tensorflow/core/kernels/adjust_hue_op.cc | 4 ++-- tensorflow/core/kernels/barrier_ops.cc | 2 +- tensorflow/core/kernels/deep_conv2d.cc | 19 +++++++++---------- tensorflow/core/kernels/tensor_array_ops.cc | 6 +++--- .../internal/optimized/optimized_ops.h | 1 - .../internal/reference/reference_ops.h | 1 - 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.cc b/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.cc index 478b716d88..108da04494 100644 --- a/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.cc +++ b/tensorflow/contrib/image/kernels/adjust_hsv_in_yiq_op.cc @@ -115,7 +115,7 @@ class AdjustHsvInYiqOp : public AdjustHsvInYiqOpBase { *context->device()->tensorflow_cpu_worker_threads(); Shard(worker_threads.num_threads, worker_threads.workers, channel_count, kCostPerChannel, - [channel_count, &input_data, &output_data, &tranformation_matrix]( + [&input_data, &output_data, &tranformation_matrix]( int64 start_channel, int64 end_channel) { // Applying projection matrix to input RGB vectors. const float* p = input_data.data() + start_channel * kChannelSize; diff --git a/tensorflow/core/kernels/adjust_hue_op.cc b/tensorflow/core/kernels/adjust_hue_op.cc index 6079aa749d..52dec94305 100644 --- a/tensorflow/core/kernels/adjust_hue_op.cc +++ b/tensorflow/core/kernels/adjust_hue_op.cc @@ -216,8 +216,8 @@ class AdjustHueOp : public AdjustHueOpBase { *context->device()->tensorflow_cpu_worker_threads(); Shard(worker_threads.num_threads, worker_threads.workers, channel_count, kCostPerChannel, - [channel_count, &input_data, &output_data, delta_h]( - int64 start_channel, int64 end_channel) { + [&input_data, &output_data, delta_h](int64 start_channel, + int64 end_channel) { const float* p = input_data.data() + start_channel * kChannelSize; float* q = output_data.data() + start_channel * kChannelSize; for (int i = start_channel; i < end_channel; i++) { diff --git a/tensorflow/core/kernels/barrier_ops.cc b/tensorflow/core/kernels/barrier_ops.cc index 944564dfba..aa91235822 100644 --- a/tensorflow/core/kernels/barrier_ops.cc +++ b/tensorflow/core/kernels/barrier_ops.cc @@ -180,7 +180,7 @@ class Barrier : public ResourceBase { // SQSS is closed, nothing is left in the incomplete set, // the queue is not already marked as closed, and (most // importantly), the queue has entries in it. - [this, ctx, callback, component_index]() { + [this, ctx, callback]() { if (!ctx->status().ok()) { callback(); return; diff --git a/tensorflow/core/kernels/deep_conv2d.cc b/tensorflow/core/kernels/deep_conv2d.cc index f9c8f16cb9..8736639881 100644 --- a/tensorflow/core/kernels/deep_conv2d.cc +++ b/tensorflow/core/kernels/deep_conv2d.cc @@ -434,10 +434,9 @@ struct TransformFilters { tile_spatial_size, base_filter_spatial_size, transform_matrix); auto shard = [&ctx, &args, &transform, &base_filter_rows, &base_filter_cols, - &num_filters_transform, &in_depth, &out_depth, - &filter_shards_row, &filter_shards_col, &tile_spatial_size, - &filter_in, &transform_matrix, - &filter_out](int64 start, int64 limit) { + &num_filters_transform, &in_depth, &filter_shards_row, + &filter_shards_col, &tile_spatial_size, &filter_in, + &transform_matrix, &filter_out](int64 start, int64 limit) { // Allocate buffer for pre-processed filter: // [base_filter_rows, base_filter_cols, num_filters_transform, in_depth] // @@ -533,9 +532,9 @@ struct PackFilters { const int64 out_depth = args.out_depth; const int64 num_filters = filter_shards_row * filter_shards_col * out_depth; - auto shard = [&ctx, &packed_filters, &filter_transform_data, - &tile_spatial_size, &in_depth, &out_depth, &filter_shards_row, - &filter_shards_col, &num_filters](int64 start, int64 limit) { + auto shard = [&ctx, &packed_filters, &filter_transform_data, &in_depth, + &out_depth, &filter_shards_row, &filter_shards_col, + &num_filters](int64 start, int64 limit) { const int64 filter_coord_stride = num_filters * in_depth; for (int64 i = start; i < limit; ++i) { // Allocate filter buffer [out_depth, shard_rows, shard_cols, in_depth]. @@ -1004,9 +1003,9 @@ struct DeepConv2D { out_tile_spatial_size, tile_spatial_size, output_transform_matrix); auto shard = [&ctx, &args, &transform, &packed_filters, &in_depth, - out_depth, tile_rows, tile_cols, out_tile_rows, out_tile_cols, - filter_shards_row, filter_shards_col, tile_spatial_size, - &input, &tile_transform_matrix, &output_transform_matrix, + out_depth, out_tile_rows, out_tile_cols, filter_shards_row, + filter_shards_col, tile_spatial_size, &input, + &tile_transform_matrix, &output_transform_matrix, &output](int64 batch_start, int64 batch_limit) { const int64 row_tiles = (args.out_rows + out_tile_rows - 1) / out_tile_rows + diff --git a/tensorflow/core/kernels/tensor_array_ops.cc b/tensorflow/core/kernels/tensor_array_ops.cc index a97a71b344..aa85f546a8 100644 --- a/tensorflow/core/kernels/tensor_array_ops.cc +++ b/tensorflow/core/kernels/tensor_array_ops.cc @@ -352,9 +352,9 @@ class TensorArrayGradOp : public TensorArrayCreationOp { } const auto key = strings::StrCat(output_handle(0), output_handle(1)); - auto creator = [this, key, tensor_array, array_size, marked_size, - element_shape, shape_to_prepend, tensor_array_output_handle, - output_handle](TensorArray** ret) -> Status { + auto creator = [key, tensor_array, array_size, marked_size, element_shape, + shape_to_prepend, + tensor_array_output_handle](TensorArray** ret) -> Status { *ret = new TensorArray( key, tensor_array->ElemType(), *tensor_array_output_handle, array_size, element_shape, tensor_array->HasIdenticalElementShapes(), diff --git a/tensorflow/lite/kernels/internal/optimized/optimized_ops.h b/tensorflow/lite/kernels/internal/optimized/optimized_ops.h index 4ff875091e..e2329c79c7 100644 --- a/tensorflow/lite/kernels/internal/optimized/optimized_ops.h +++ b/tensorflow/lite/kernels/internal/optimized/optimized_ops.h @@ -4293,7 +4293,6 @@ inline void LogSoftmax(const SoftmaxParams& params, using FixedPointScaledDiff = gemmlowp::FixedPoint; using FixedPointAccum = gemmlowp::FixedPoint; - using FixedPoint0 = gemmlowp::FixedPoint; const int trailing_dim = input_shape.DimensionsCount() - 1; const int outer_size = diff --git a/tensorflow/lite/kernels/internal/reference/reference_ops.h b/tensorflow/lite/kernels/internal/reference/reference_ops.h index fd37865c3e..920f154049 100644 --- a/tensorflow/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/lite/kernels/internal/reference/reference_ops.h @@ -2736,7 +2736,6 @@ inline void LogSoftmax(const SoftmaxParams& params, using FixedPointScaledDiff = gemmlowp::FixedPoint; using FixedPointAccum = gemmlowp::FixedPoint; - using FixedPoint0 = gemmlowp::FixedPoint; const int trailing_dim = input_shape.DimensionsCount() - 1; const int outer_size = -- GitLab From f93cdcb3cd1dac7769ac393dbcbab801a304480b Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Tue, 20 Nov 2018 15:53:51 -0800 Subject: [PATCH 161/672] Replace use of tf.gradients with GradientTape in _FusedBatchNormGradGrad Fixes #23794 PiperOrigin-RevId: 222320612 --- tensorflow/python/ops/nn_grad.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/ops/nn_grad.py b/tensorflow/python/ops/nn_grad.py index 902653befc..34404edc9a 100644 --- a/tensorflow/python/ops/nn_grad.py +++ b/tensorflow/python/ops/nn_grad.py @@ -18,13 +18,13 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.eager import backprop from tensorflow.python.eager import context from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_nn_ops -from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn_ops @@ -948,10 +948,14 @@ def _FusedBatchNormGradGrad(op, *grad): grad_grad_x = grad[0] grad_grad_scale = grad[1] grad_grad_offset = grad[2] - grad_x, grad_scale, grad_offset = _BatchNormGrad( - grad_y, x, scale, pop_mean, pop_var, epsilon, data_format, is_training) - grad_initial = [grad_grad_x, grad_grad_scale, grad_grad_offset] - grad_grad_y, grad_x, grad_scale = gradients_impl.gradients( + with backprop.GradientTape() as tape: + tape.watch(grad_y) + tape.watch(x) + tape.watch(scale) + grad_x, grad_scale, grad_offset = _BatchNormGrad( + grad_y, x, scale, pop_mean, pop_var, epsilon, data_format, is_training) + grad_initial = [grad_grad_x, grad_grad_scale, grad_grad_offset] + grad_grad_y, grad_x, grad_scale = tape.gradient( [grad_x, grad_scale, grad_offset], [grad_y, x, scale], grad_initial) return grad_grad_y, grad_x, grad_scale, None, None -- GitLab From 03e9335993127eb9d6c18a86e83611583cdd5eba Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 15:54:07 -0800 Subject: [PATCH 162/672] Test to show how strided_slice fails sometimes. PiperOrigin-RevId: 222320648 --- tensorflow/lite/build_def.bzl | 1 + tensorflow/lite/testing/generate_examples.py | 26 +++++++++++++++++++ .../testing/generated_examples_zip_test.cc | 3 +++ 3 files changed, 30 insertions(+) diff --git a/tensorflow/lite/build_def.bzl b/tensorflow/lite/build_def.bzl index 8255211d27..fcd7255910 100644 --- a/tensorflow/lite/build_def.bzl +++ b/tensorflow/lite/build_def.bzl @@ -297,6 +297,7 @@ def generated_test_models(): "squeeze", "strided_slice", "strided_slice_1d_exhaustive", + "strided_slice_buggy", "sub", "tile", "topk", diff --git a/tensorflow/lite/testing/generate_examples.py b/tensorflow/lite/testing/generate_examples.py index 9b0f59f9da..b7e549cc5c 100644 --- a/tensorflow/lite/testing/generate_examples.py +++ b/tensorflow/lite/testing/generate_examples.py @@ -2520,6 +2520,32 @@ def make_strided_slice_1d_exhaustive_tests(zip_path): _make_strided_slice_tests(zip_path, test_parameters) +def make_strided_slice_buggy_tests(zip_path): + """Make a set of tests to show strided_slice yields incorrect results.""" + + test_parameters = [{ + "unused_iteration_counter": [1], + }] + + def build_graph(parameters): + """Build the strided_slice op testing graph.""" + del parameters + input_values = tf.placeholder(dtype=tf.float32, shape=[4, 2]) + data = tf.constant([[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], + [12, 13, 14, 15]], tf.float32) + return [input_values], [input_values + data[:, :2]] + + def build_inputs(parameters, sess, inputs, outputs): + del parameters + input_values = np.zeros([4, 2], dtype=np.float32) + return [input_values], sess.run( + outputs, feed_dict={inputs[0]: input_values}) + + make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) + + def make_lstm_tests(zip_path): """Make a set of tests to do basic Lstm cell.""" diff --git a/tensorflow/lite/testing/generated_examples_zip_test.cc b/tensorflow/lite/testing/generated_examples_zip_test.cc index 6f31daa5fb..91a4851fb0 100644 --- a/tensorflow/lite/testing/generated_examples_zip_test.cc +++ b/tensorflow/lite/testing/generated_examples_zip_test.cc @@ -102,6 +102,9 @@ std::map kBrokenTests = { {R"(^\/add.*dtype=tf\.int64)", "119126484"}, {R"(^\/floor_div.*dtype=tf\.int64)", "119126484"}, {R"(^\/squared_difference.*dtype=tf\.int64)", "119126484"}, + + // Strided Slice chooses the wrong dimension. + {R"(^\/strided_slice_buggy)", "119786029"}, }; // Allows test data to be unarchived into a temporary directory and makes -- GitLab From 285bfa4f5231d18f0c4ef0169a79d1e71e1a601f Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Tue, 20 Nov 2018 16:15:53 -0800 Subject: [PATCH 163/672] Add V2 precision, recall metrics. PiperOrigin-RevId: 222323900 --- tensorflow/python/keras/metrics.py | 120 ++++++++++++ tensorflow/python/keras/metrics_test.py | 244 ++++++++++++++++++++++++ 2 files changed, 364 insertions(+) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 030bf4768c..0793585047 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -977,6 +977,126 @@ class TruePositives(_ConfusionMatrixConditionCount): dtype=dtype) +class Precision(Metric): + """Computes the precision of the predictions with respect to the labels. + + The metric creates two local variables, `true_positives` and `false_positives` + that are used to compute the precision. This value is ultimately returned as + `precision`, an idempotent operation that simply divides `true_positives` + by the sum of `true_positives` and `false_positives`. + + If `sample_weight` is `None`, weights default to 1. + Use `sample_weight` of 0 to mask values. + """ + + def __init__(self, thresholds=None, name=None, dtype=None): + """Creates a `Precision` instance. + + Args: + thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float + threshold values in [0, 1]. A threshold is compared with prediction + values to determine the truth value of predictions (i.e., above the + threshold is `true`, below is `false`). One metric value is generated + for each threshold value. + name: (Optional) string name of the metric instance. + dtype: (Optional) data type of the metric result. + """ + super(Precision, self).__init__(name=name, dtype=dtype) + self.thresholds = [0.5] if thresholds is None else thresholds + self.tp = self.add_weight( + 'true_positives', + shape=(len(self.thresholds),), + initializer=init_ops.zeros_initializer) + self.fp = self.add_weight( + 'false_positives', + shape=(len(self.thresholds),), + initializer=init_ops.zeros_initializer) + + def update_state(self, y_true, y_pred, sample_weight=None): + """Accumulates true positive and false positive statistics. + + Args: + y_true: The ground truth values. + y_pred: The predicted values. + sample_weight: Optional weighting of each example. Defaults to 1. Can be a + `Tensor` whose rank is either 0, or the same rank as `y_true`, and must + be broadcastable to `y_true`. + + Returns: + Update op. + """ + return _update_confusion_matrix_variables({ + _ConfusionMatrix.TRUE_POSITIVES: self.tp, + _ConfusionMatrix.FALSE_POSITIVES: self.fp + }, y_true, y_pred, self.thresholds, sample_weight) + + def result(self): + return array_ops.where( + math_ops.greater(self.tp + self.fp, 0), + math_ops.div(self.tp, self.tp + self.fp), + array_ops.zeros_like(self.thresholds)) + + +class Recall(Metric): + """Computes the recall of the predictions with respect to the labels. + + This metric creates two local variables, `true_positives` and + `false_negatives`, that are used to compute the recall. This value is + ultimately returned as `recall`, an idempotent operation that simply divides + `true_positives` by the sum of `true_positives` and `false_negatives`. + + If `sample_weight` is `None`, weights default to 1. + Use `sample_weight` of 0 to mask values. + """ + + def __init__(self, thresholds=None, name=None, dtype=None): + """Creates a `Recall` instance. + + Args: + thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float + threshold values in [0, 1]. A threshold is compared with prediction + values to determine the truth value of predictions (i.e., above the + threshold is `true`, below is `false`). One metric value is generated + for each threshold value. + name: (Optional) string name of the metric instance. + dtype: (Optional) data type of the metric result. + """ + super(Recall, self).__init__(name=name, dtype=dtype) + self.thresholds = [0.5] if thresholds is None else thresholds + self.tp = self.add_weight( + 'true_positives', + shape=(len(self.thresholds),), + initializer=init_ops.zeros_initializer) + self.fn = self.add_weight( + 'false_negatives', + shape=(len(self.thresholds),), + initializer=init_ops.zeros_initializer) + + def update_state(self, y_true, y_pred, sample_weight=None): + """Accumulates true positive and false negative statistics. + + Args: + y_true: The ground truth values. + y_pred: The predicted values. + sample_weight: Optional weighting of each example. Defaults to 1. Can be a + `Tensor` whose rank is either 0, or the same rank as `y_true`, and must + be broadcastable to `y_true`. + + Returns: + Update op. + """ + return _update_confusion_matrix_variables({ + _ConfusionMatrix.TRUE_POSITIVES: self.tp, + _ConfusionMatrix.FALSE_NEGATIVES: self.fn + }, y_true, y_pred, self.thresholds, sample_weight) + + def result(self): + return array_ops.where( + math_ops.greater(self.tp + self.fn, 0), + math_ops.div(self.tp, self.tp + self.fn), + array_ops.zeros_like(self.thresholds)) + + @tf_export('keras.metrics.binary_accuracy') def binary_accuracy(y_true, y_pred, threshold=0.5): threshold = math_ops.cast(threshold, y_pred.dtype) diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index c6a49c3c3e..535802a64a 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -32,6 +32,7 @@ from tensorflow.python.keras import metrics from tensorflow.python.keras.engine.training import Model from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops +from tensorflow.python.ops import random_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -733,5 +734,248 @@ class TruePositivesTest(test.TestCase): self.assertAllClose([222., 111., 37.], self.evaluate(result)) +@test_util.run_all_in_graph_and_eager_modes +class PrecisionTest(test.TestCase): + + def test_config(self): + p_obj = metrics.Precision(name='my_precision', thresholds=[0.4, 0.9]) + self.assertEqual(p_obj.name, 'my_precision') + self.assertLen(p_obj.variables, 2) + self.assertEqual([v.name for v in p_obj.variables], + ['true_positives:0', 'false_positives:0']) + self.assertEqual(p_obj.thresholds, [0.4, 0.9]) + + def test_value_is_idempotent(self): + p_obj = metrics.Precision(thresholds=[0.3, 0.72]) + y_pred = random_ops.random_uniform(shape=(10, 3)) + y_true = random_ops.random_uniform(shape=(10, 3)) + update_op = p_obj.update_state(y_true, y_pred) + self.evaluate(variables.variables_initializer(p_obj.variables)) + + # Run several updates. + for _ in range(10): + self.evaluate(update_op) + + # Then verify idempotency. + initial_precision = self.evaluate(p_obj.result()) + for _ in range(10): + self.assertArrayNear(initial_precision, self.evaluate(p_obj.result()), + 1e-3) + + def test_unweighted(self): + p_obj = metrics.Precision() + y_pred = constant_op.constant([1, 0, 1, 0], shape=(1, 4)) + y_true = constant_op.constant([0, 1, 1, 0], shape=(1, 4)) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj(y_true, y_pred) + self.assertAlmostEqual(0.5, self.evaluate(result)) + + def test_unweighted_all_incorrect(self): + p_obj = metrics.Precision(thresholds=[0.5]) + inputs = np.random.randint(0, 2, size=(100, 1)) + y_pred = constant_op.constant(inputs) + y_true = constant_op.constant(1 - inputs) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj(y_true, y_pred) + self.assertAlmostEqual(0, self.evaluate(result)) + + def test_weighted(self): + p_obj = metrics.Precision() + y_pred = constant_op.constant([[1, 0, 1, 0], [1, 0, 1, 0]]) + y_true = constant_op.constant([[0, 1, 1, 0], [1, 0, 0, 1]]) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj( + y_true, + y_pred, + sample_weight=constant_op.constant([[1, 2, 3, 4], [4, 3, 2, 1]])) + weighted_tp = 3.0 + 4.0 + weighted_positives = (1.0 + 3.0) + (4.0 + 2.0) + expected_precision = weighted_tp / weighted_positives + self.assertAlmostEqual(expected_precision, self.evaluate(result)) + + def test_div_by_zero(self): + p_obj = metrics.Precision() + y_pred = constant_op.constant([0, 0, 0, 0]) + y_true = constant_op.constant([0, 0, 0, 0]) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj(y_true, y_pred) + self.assertEqual(0, self.evaluate(result)) + + def test_unweighted_with_threshold(self): + p_obj = metrics.Precision(thresholds=[0.5, 0.7]) + y_pred = constant_op.constant([1, 0, 0.6, 0], shape=(1, 4)) + y_true = constant_op.constant([0, 1, 1, 0], shape=(1, 4)) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj(y_true, y_pred) + self.assertArrayNear([0.5, 0.], self.evaluate(result), 0) + + def test_weighted_with_threshold(self): + p_obj = metrics.Precision(thresholds=[0.5, 1.1]) + y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) + y_pred = constant_op.constant([[1, 0], [0.6, 0]], + shape=(2, 2), + dtype=dtypes.float32) + weights = constant_op.constant([[4, 0], [3, 1]], + shape=(2, 2), + dtype=dtypes.float32) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj(y_true, y_pred, sample_weight=weights) + weighted_tp = 0 + 3. + weighted_positives = (0 + 3.) + (4. + 0.) + expected_precision = weighted_tp / weighted_positives + self.assertArrayNear([expected_precision, 0], self.evaluate(result), 1e-3) + + def test_extreme_thresholds(self): + p_obj = metrics.Precision(thresholds=[-1.0, 2.0]) # beyond values range + y_pred = math_ops.cast( + constant_op.constant([1, 0, 1, 0], shape=(1, 4)), dtype=dtypes.float32) + y_true = math_ops.cast( + constant_op.constant([0, 1, 1, 1], shape=(1, 4)), dtype=dtypes.float32) + self.evaluate(variables.variables_initializer(p_obj.variables)) + result = p_obj(y_true, y_pred) + self.assertArrayNear([0.75, 0.], self.evaluate(result), 0) + + def test_multiple_updates(self): + p_obj = metrics.Precision(thresholds=[0.5, 1.1]) + y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) + y_pred = constant_op.constant([[1, 0], [0.6, 0]], + shape=(2, 2), + dtype=dtypes.float32) + weights = constant_op.constant([[4, 0], [3, 1]], + shape=(2, 2), + dtype=dtypes.float32) + self.evaluate(variables.variables_initializer(p_obj.variables)) + update_op = p_obj.update_state(y_true, y_pred, sample_weight=weights) + for _ in range(2): + self.evaluate(update_op) + + weighted_tp = (0 + 3.) + (0 + 3.) + weighted_positives = ((0 + 3.) + (4. + 0.)) + ((0 + 3.) + (4. + 0.)) + expected_precision = weighted_tp / weighted_positives + self.assertArrayNear([expected_precision, 0], self.evaluate(p_obj.result()), + 1e-3) + + +@test_util.run_all_in_graph_and_eager_modes +class RecallTest(test.TestCase): + + def test_config(self): + r_obj = metrics.Recall(name='my_recall', thresholds=[0.4, 0.9]) + self.assertEqual(r_obj.name, 'my_recall') + self.assertLen(r_obj.variables, 2) + self.assertEqual([v.name for v in r_obj.variables], + ['true_positives:0', 'false_negatives:0']) + self.assertEqual(r_obj.thresholds, [0.4, 0.9]) + + def test_value_is_idempotent(self): + r_obj = metrics.Recall(thresholds=[0.3, 0.72]) + y_pred = random_ops.random_uniform(shape=(10, 3)) + y_true = random_ops.random_uniform(shape=(10, 3)) + update_op = r_obj.update_state(y_true, y_pred) + self.evaluate(variables.variables_initializer(r_obj.variables)) + + # Run several updates. + for _ in range(10): + self.evaluate(update_op) + + # Then verify idempotency. + initial_recall = self.evaluate(r_obj.result()) + for _ in range(10): + self.assertArrayNear(initial_recall, self.evaluate(r_obj.result()), 1e-3) + + def test_unweighted(self): + r_obj = metrics.Recall() + y_pred = constant_op.constant([1, 0, 1, 0], shape=(1, 4)) + y_true = constant_op.constant([0, 1, 1, 0], shape=(1, 4)) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj(y_true, y_pred) + self.assertAlmostEqual(0.5, self.evaluate(result)) + + def test_unweighted_all_incorrect(self): + r_obj = metrics.Recall(thresholds=[0.5]) + inputs = np.random.randint(0, 2, size=(100, 1)) + y_pred = constant_op.constant(inputs) + y_true = constant_op.constant(1 - inputs) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj(y_true, y_pred) + self.assertAlmostEqual(0, self.evaluate(result)) + + def test_weighted(self): + r_obj = metrics.Recall() + y_pred = constant_op.constant([[1, 0, 1, 0], [0, 1, 0, 1]]) + y_true = constant_op.constant([[0, 1, 1, 0], [1, 0, 0, 1]]) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj( + y_true, + y_pred, + sample_weight=constant_op.constant([[1, 2, 3, 4], [4, 3, 2, 1]])) + weighted_tp = 3.0 + 1.0 + weighted_t = (2.0 + 3.0) + (4.0 + 1.0) + expected_recall = weighted_tp / weighted_t + self.assertAlmostEqual(expected_recall, self.evaluate(result)) + + def test_div_by_zero(self): + r_obj = metrics.Recall() + y_pred = constant_op.constant([0, 0, 0, 0]) + y_true = constant_op.constant([0, 0, 0, 0]) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj(y_true, y_pred) + self.assertEqual(0, self.evaluate(result)) + + def test_unweighted_with_threshold(self): + r_obj = metrics.Recall(thresholds=[0.5, 0.7]) + y_pred = constant_op.constant([1, 0, 0.6, 0], shape=(1, 4)) + y_true = constant_op.constant([0, 1, 1, 0], shape=(1, 4)) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj(y_true, y_pred) + self.assertArrayNear([0.5, 0.], self.evaluate(result), 0) + + def test_weighted_with_threshold(self): + r_obj = metrics.Recall(thresholds=[0.5, 1.1]) + y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) + y_pred = constant_op.constant([[1, 0], [0.6, 0]], + shape=(2, 2), + dtype=dtypes.float32) + weights = constant_op.constant([[1, 4], [3, 2]], + shape=(2, 2), + dtype=dtypes.float32) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj(y_true, y_pred, sample_weight=weights) + weighted_tp = 0 + 3. + weighted_positives = (0 + 3.) + (4. + 0.) + expected_recall = weighted_tp / weighted_positives + self.assertArrayNear([expected_recall, 0], self.evaluate(result), 1e-3) + + def test_extreme_thresholds(self): + r_obj = metrics.Recall(thresholds=[-1.0, 2.0]) # beyond values range + y_pred = math_ops.cast( + constant_op.constant([1, 0, 1, 0], shape=(1, 4)), dtype=dtypes.float32) + y_true = math_ops.cast( + constant_op.constant([0, 1, 1, 1], shape=(1, 4)), dtype=dtypes.float32) + self.evaluate(variables.variables_initializer(r_obj.variables)) + result = r_obj(y_true, y_pred) + self.assertArrayNear([1.0, 0.], self.evaluate(result), 0) + + def test_multiple_updates(self): + r_obj = metrics.Recall(thresholds=[0.5, 1.1]) + y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) + y_pred = constant_op.constant([[1, 0], [0.6, 0]], + shape=(2, 2), + dtype=dtypes.float32) + weights = constant_op.constant([[1, 4], [3, 2]], + shape=(2, 2), + dtype=dtypes.float32) + self.evaluate(variables.variables_initializer(r_obj.variables)) + update_op = r_obj.update_state(y_true, y_pred, sample_weight=weights) + for _ in range(2): + self.evaluate(update_op) + + weighted_tp = (0 + 3.) + (0 + 3.) + weighted_positives = ((0 + 3.) + (4. + 0.)) + ((0 + 3.) + (4. + 0.)) + expected_recall = weighted_tp / weighted_positives + self.assertArrayNear([expected_recall, 0], self.evaluate(r_obj.result()), + 1e-3) + + if __name__ == '__main__': test.main() -- GitLab From 0fee95f2a98f047f074d6c16c1841f0f94834fcf Mon Sep 17 00:00:00 2001 From: Guangda Lai Date: Tue, 20 Nov 2018 16:28:50 -0800 Subject: [PATCH 164/672] Fix conversion for binary operations and add corresponding test. Main changes include: 1. reenable SimpleMultiEnginesTest, and fix the graph so that binary ops "mul" and "div" don't broadcast on batch dimension, also fix the rewriter config to disable LayoutOptimizer (by calling OptimizerDisabledRewriterConfig() in base class) 2. rewrite TensorRTGetBroadcastShape() to GetTrtBroadcastShape(), make it a member function of the converter and add corresponding tests. 3. implement RECIP computation for LambdaFactory::unary 4. consolidate ConverBinary() and related methods (BinaryTensorOpWeight, BinaryTensorOpTensor) and add corresponding tests. PiperOrigin-RevId: 222325662 --- .../contrib/tensorrt/convert/convert_nodes.cc | 413 ++++++------ .../contrib/tensorrt/convert/convert_nodes.h | 7 + .../tensorrt/convert/convert_nodes_test.cc | 610 +++++++++++++++--- tensorflow/contrib/tensorrt/test/base_test.py | 51 +- .../test/tf_trt_integration_test_base.py | 6 + 5 files changed, 785 insertions(+), 302 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 27c20204bb..631c2575c0 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -202,6 +202,21 @@ string DebugString(const nvinfer1::DimensionType type) { } } +string DebugString(const nvinfer1::DataType trt_dtype) { + switch (trt_dtype) { + case nvinfer1::DataType::kFLOAT: + return "kFLOAT"; + case nvinfer1::DataType::kHALF: + return "kHALF"; + case nvinfer1::DataType::kINT8: + return "kINT8"; + case nvinfer1::DataType::kINT32: + return "kINT32"; + default: + return "Invalid TRT data type"; + } +} + string DebugString(const nvinfer1::Dims& dims) { string out = StrCat("nvinfer1::Dims(nbDims=", dims.nbDims, ", d="); for (int i = 0; i < dims.nbDims; ++i) { @@ -222,16 +237,15 @@ string DebugString(const nvinfer1::Permutation& permutation, int len) { string DebugString(const nvinfer1::ITensor& tensor) { return StrCat("nvinfer1::ITensor(@", reinterpret_cast(&tensor), - ", shape=", DebugString(tensor.getDimensions()), ")"); + ", name=", tensor.getName(), + ", dtype=", DebugString(tensor.getType()), + ", dims=", DebugString(tensor.getDimensions()), ")"); } -// Return whether or not the broadcast is feasible; -bool TensorRTGetBroadcastShape(const nvinfer1::Dims& operand_l, - const bool operand_l_is_tensor, - const nvinfer1::Dims& operand_r, - const bool operand_r_is_tensor, - nvinfer1::Dims* operand_l_new_shape, - nvinfer1::Dims* operand_r_new_shape) { +Status Converter::GetTrtBroadcastShape( + const TRT_TensorOrWeights& operand_l, const TRT_TensorOrWeights& operand_r, + nvinfer1::Dims* operand_l_new_dims, + nvinfer1::Dims* operand_r_new_dims) const { // *************************************************************************** // TensorRT Elementwise op supports broadcast but requires both tensor to be // of Identical rank @@ -256,52 +270,59 @@ bool TensorRTGetBroadcastShape(const nvinfer1::Dims& operand_l, // -> T: 1 1 1 -1 3 5 1 // -> W: 1 1 1 1 3 5 1 // *************************************************************************** - const int max_nb_dims = nvinfer1::Dims::MAX_DIMS + 1; - const size_t element_size = sizeof(operand_l.d[0]); - - // fill in dimensions - int l_s[max_nb_dims]; - std::fill(l_s, l_s + max_nb_dims, 1); - int l_d = operand_l_is_tensor ? operand_l.nbDims + 1 : operand_l.nbDims; - int r_s[max_nb_dims]; - std::fill(r_s, r_s + max_nb_dims, 1); - int r_d = operand_r_is_tensor ? operand_r.nbDims + 1 : operand_r.nbDims; - - int max_d = std::max(l_d, r_d); - std::memcpy(l_s + max_d - operand_l.nbDims, operand_l.d, - operand_l.nbDims * element_size); - std::memcpy(r_s + max_d - operand_r.nbDims, operand_r.d, - operand_r.nbDims * element_size); - - // set -1 for batch dimension, since batch size is not supposed to be - // broadcasted - if (operand_l_is_tensor) { - if (max_d != l_d) { // if broadcast beyond batch dimension, fail - return false; - } - l_s[0] = -1; - } - if (operand_r_is_tensor) { - if (max_d != r_d) { // if broadcast beyond batch dimension, fail - return false; - } - r_s[0] = -1; + if (!operand_l.is_tensor() && !operand_r.is_tensor()) { + return errors::InvalidArgument( + "Broadcasting requires at least one of the operands be tensors"); } - // compare broadcast feasibility - for (int i = max_d - 1; i >= 0; i--) { - if ((l_s[i] != r_s[i]) && (l_s[i] != 1) && (r_s[i] != 1)) { - return false; + const int max_nb_dims = nvinfer1::Dims::MAX_DIMS + 1; + auto compute_output_dims = + [max_nb_dims](const TRT_TensorOrWeights& input, int broadcast_num_dims, + int* output_dims_array, nvinfer1::Dims* output_dims) { + const nvinfer1::Dims input_dims = input.GetTrtDims(); + std::fill(output_dims_array, output_dims_array + max_nb_dims, 1); + std::copy(input_dims.d, input_dims.d + input_dims.nbDims, + output_dims_array + broadcast_num_dims - input_dims.nbDims); + if (input.is_tensor()) { + const int true_input_dims = input_dims.nbDims + 1; + if (true_input_dims < broadcast_num_dims) { + return errors::InvalidArgument( + "Broadcasting beyond batch dimension is not supported ", + "(tensor #dims ", true_input_dims, " vs broadcast #dims ", + broadcast_num_dims, ")"); + } + // Set the batch dimension to -1, since batch size is not supposed to + // be broadcasted. + output_dims_array[0] = -1; + } + // Copy to output dimensions (stripping the batch dimension). + output_dims->nbDims = broadcast_num_dims - 1; + std::copy(output_dims_array + 1, output_dims_array + broadcast_num_dims, + output_dims->d); + return Status::OK(); + }; + + // Compute the output dimensions. + const int broadcast_num_dims = + std::max(operand_l.GetTrtDims().nbDims + (operand_l.is_tensor() ? 1 : 0), + operand_r.GetTrtDims().nbDims + (operand_r.is_tensor() ? 1 : 0)); + int output_l[max_nb_dims], output_r[max_nb_dims]; + TF_RETURN_IF_ERROR(compute_output_dims(operand_l, broadcast_num_dims, + output_l, operand_l_new_dims)); + TF_RETURN_IF_ERROR(compute_output_dims(operand_r, broadcast_num_dims, + output_r, operand_r_new_dims)); + + // Compare broadcast feasibility + for (int i = 0; i < broadcast_num_dims; ++i) { + if ((output_l[i] != output_r[i]) && (output_l[i] != 1) && + (output_r[i] != 1)) { + return errors::InvalidArgument( + "Infeasible broadcast scheme (", "batch_dim: ", output_l[0], ", ", + DebugString(*operand_l_new_dims), " vs ", "batch_dim: ", output_r[0], + ", ", DebugString(*operand_r_new_dims), ")"); } } - - // output new TensorRT Dimension (stripping the batch dimension) - operand_l_new_shape->nbDims = max_d - 1; - std::memcpy(operand_l_new_shape->d, l_s + 1, (max_d - 1) * element_size); - operand_r_new_shape->nbDims = max_d - 1; - std::memcpy(operand_r_new_shape->d, r_s + 1, (max_d - 1) * element_size); - - return true; + return Status::OK(); } inline bool DimsEqual(const nvinfer1::Dims& dim_l, @@ -515,8 +536,7 @@ nvinfer1::Dims TRT_TensorOrWeights::GetTrtDims() const { string TRT_TensorOrWeights::DebugString() const { string output = "TRT_TensorOrWeights(type="; if (is_tensor()) { - StrAppend(&output, "tensor @", reinterpret_cast(tensor()), - ", shape=", convert::DebugString(tensor()->getDimensions()), + StrAppend(&output, "tensor=", convert::DebugString(*tensor()), ", batch_size=", batch_size_); } else { StrAppend(&output, "weights=", weights_.DebugString()); @@ -779,8 +799,9 @@ Status TrtNodeValidator::ValidateNode( Status status = ConvertToTensorOrWeights( *pair.first, pair.second, graph_properties, &tensor_or_weights); if (!status.ok()) { - return errors::Internal("Failed to convert input with index ", i, - " to a TRT_TensorOrWeights"); + return errors::Internal( + "Failed to convert input with index ", i, + " to a TRT_TensorOrWeights: ", status.error_message()); } inputs.push_back(tensor_or_weights); } @@ -1033,8 +1054,9 @@ Status Converter::PrepareTensorForShape(const TRT_TensorOrWeights& input, } if (can_check_shapes && TrtDimsNumElements(input.GetTrtDims()) != TrtDimsNumElements(dims)) { - return tensorflow::errors::InvalidArgument( - "Reshape shapes are not compatible."); + return errors::InvalidArgument("Reshape shapes are not compatible (", + DebugString(input.GetTrtDims()), " vs ", + DebugString(dims), ")"); } if (input.is_tensor()) { @@ -1227,12 +1249,11 @@ TRT_ShapedWeights ConvertFP32ToFP16(TrtWeightStore* store, } // **************************************************************************** -// Constant folding functions -// TODO(jie): once optimizer kicks in, we should have done constant folding -// there. +// Constant folding functions for weights. +// TODO(laigd): we should probably use eigen directly. // ***************************************************************************** struct LambdaFactory { - enum class OP_CATEGORY : int { RSQRT = 0, NEG, ADD, MUL, SUB, RECIP }; + enum class OP_CATEGORY : int { RSQRT = 0, NEG, RECIP }; OP_CATEGORY op; template @@ -1247,7 +1268,7 @@ struct LambdaFactory { case OP_CATEGORY::RECIP: return [](T t) -> T { return 1.0 / t; }; default: - VLOG(2) << "Not supported op for unary: " << static_cast(op); + LOG(ERROR) << "Not supported op for unary: " << static_cast(op); return nullptr; } } @@ -1258,15 +1279,18 @@ std::function LambdaFactory::unary() { switch (op) { case OP_CATEGORY::RSQRT: { VLOG(2) << "RSQRT GETS DONE"; - return [](Eigen::half t) -> Eigen::half { + return [](Eigen::half t) { return Eigen::half(1.0 / sqrt(static_cast(t))); }; } case OP_CATEGORY::NEG: - return [](Eigen::half t) -> Eigen::half { return -t; }; - // TODO(aaroey): can we support RECIP? + return [](Eigen::half t) { return -t; }; + case OP_CATEGORY::RECIP: + return [](Eigen::half t) { + return Eigen::half(1.0 / static_cast(t)); + }; default: - VLOG(2) << "Not supported op for unary: " << static_cast(op); + LOG(ERROR) << "Not supported op for unary: " << static_cast(op); return nullptr; } } @@ -1298,50 +1322,48 @@ tensorflow::Status UnaryCompute(const TRT_ShapedWeights& iweights, return tensorflow::Status::OK(); } +// If swapped_inputs is false, 'tensor' is the left operand and 'weights' is the +// right operand. If swapped_inputs is true, those two are swapped. +// // TODO(jie): broadcast is needed yet not implemented. -// Only implemented channel wise for the time being -tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, - const nvinfer1::ITensor* tensor, - TRT_ShapedWeights weights, - bool swapped_inputs) { +// Only implemented channel wise for the time being. +Status BinaryTensorOpWeight(OpConverterParams* params, + const nvinfer1::ITensor* tensor, + TRT_ShapedWeights weights, bool swapped_inputs) { + static const std::unordered_set supported_ops = {"Sub", "Add", "Mul", + "Div", "RealDiv"}; const auto& node_def = params->node_def; - // tensor is the left operand while weights is the right operand; - // when swapped_inputs set to true, those two are swapped. - // TODO(aaroey): use a set. - if (node_def.op() != "Sub" && node_def.op() != "Add" && - node_def.op() != "Mul" && node_def.op() != "Div" && - node_def.op() != "RealDiv") { - return tensorflow::errors::Unimplemented( - "op not supported: " + node_def.op() + ", at: " + node_def.name()); + if (!supported_ops.count(node_def.op())) { + return errors::Unimplemented(node_def.op(), " is not supported, at ", + node_def.name()); } - // Check type consistency - nvinfer1::DataType ttype; - TF_RETURN_IF_ERROR(ConvertDType(weights.type_, &ttype)); + // Check type consistency. + nvinfer1::DataType trt_dtype; + TF_RETURN_IF_ERROR(ConvertDType(weights.type_, &trt_dtype)); - // Check scale mode + // Check scale mode. auto dims_w = weights.shape_; - auto dims_t = tensor->getDimensions(); + const auto dims_t = tensor->getDimensions(); // TODO(jie): addScale checks for input tensor dimension if (dims_t.nbDims != 3) { - return tensorflow::errors::InvalidArgument( - "addScale requires tensor with rank 3, " + node_def.name()); + return errors::InvalidArgument("addScale requires tensor with rank 3, at ", + node_def.name()); } - // default to element-wise + // Default to element-wise auto scale_mode = nvinfer1::ScaleMode::kELEMENTWISE; // TODO(jie): maybe use a permutation instead to support more cases; - bool permutation_flag = false; + bool need_to_permute = false; if (weights.count() == 1) { - VLOG(2) << "UNIFORM"; scale_mode = nvinfer1::ScaleMode::kUNIFORM; } else { - // no broadcasting on Batch dimension; - VLOG(2) << "WEIGHTS DIM: " << dims_w.nbDims - << " tensor DIM: " << dims_t.nbDims; + VLOG(2) << "weights dims: " << DebugString(dims_w) + << "; tensor dims: " << DebugString(dims_t); + // Make sure no broadcasting on batch dimension. if (dims_w.nbDims == dims_t.nbDims + 1) { if (dims_w.d[0] == 1) { for (int i = 1; i < dims_w.nbDims; i++) { @@ -1349,72 +1371,70 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, } dims_w.nbDims--; } else { - return tensorflow::errors::InvalidArgument( - "Binary op cannot operate on batch, " + node_def.name()); + return errors::InvalidArgument("Binary op cannot operate on batch, at ", + node_def.name()); } } if (dims_w.nbDims == dims_t.nbDims && dims_w.d[0] == dims_t.d[0]) { scale_mode = nvinfer1::ScaleMode::kELEMENTWISE; - // default is element; + // Default is element-wise for (int i = 1; i < dims_w.nbDims; i++) { if (dims_w.d[i] != dims_t.d[i]) { - // if dimension does not match, switch back to channel; - VLOG(2) << "channel"; + // If dimension does not match, switch back to per-channel scale_mode = nvinfer1::ScaleMode::kCHANNEL; break; } } - // if channel as candidate, validate it + // If the mode is per-channel, since channel dimension is assumed to be + // the third to last dimension, we need to make sure all other dimensions + // have size 1. if (scale_mode == nvinfer1::ScaleMode::kCHANNEL) { for (int i = 1; i < dims_w.nbDims; i++) { if (dims_w.d[i] != 1) - return tensorflow::errors::InvalidArgument( - "Weight shape not compatible at, " + node_def.name()); + return errors::InvalidArgument( + "Weight dims not compatible for channel-wise broadcast at ", + node_def.name()); } - } else { - VLOG(2) << "elementwise"; } } else if (dims_w.nbDims == 1 && dims_w.d[0] == dims_t.d[dims_t.nbDims - 1]) { - // channel wise and broadcast required; - permutation_flag = true; + // Channel wise and broadcast required. We compare the last dimension of + // the tensor shape because of tensorflow default broadcasting rules. + need_to_permute = true; scale_mode = nvinfer1::ScaleMode::kCHANNEL; } else { - return tensorflow::errors::InvalidArgument( - "Weight shape not compatible at, " + node_def.name()); + return errors::InvalidArgument("Weight dims not compatible at ", + node_def.name()); } } + // TODO(laigd): we should add validation_only support in TransposeTensor() and + // PrepareTensorForShape(). + if (params->validation_only) return Status::OK(); - // transpose last dimension + // Transpose last dimension. std::vector permutation(dims_t.nbDims + 1); - if (permutation_flag) { - if (scale_mode == nvinfer1::ScaleMode::kCHANNEL && dims_t.nbDims > 1) { - // we swap the last dimension into channel for trt. - // because of tensorflow default broadcasting rules. - for (int i = 0; i < static_cast(permutation.size()); i++) { - permutation[i] = i; - } - permutation[1] = dims_t.nbDims; - permutation[dims_t.nbDims] = 1; - TF_RETURN_IF_ERROR(params->converter->TransposeTensor( - const_cast(tensor), permutation, &tensor)); - } else { - return tensorflow::errors::InvalidArgument( - "Transpose cannot be applied, " + node_def.name()); - } + if (need_to_permute) { + // We swap the last dimension into channel for trt, because of tensorflow + // default broadcasting rules. + for (int i = 0; i < static_cast(permutation.size()); i++) { + permutation[i] = i; + } + permutation[1] = dims_t.nbDims; + permutation[dims_t.nbDims] = 1; + TF_RETURN_IF_ERROR(params->converter->TransposeTensor( + const_cast(tensor), permutation, &tensor)); } if (params->converter->precision_mode() == FP16MODE) { weights = ConvertFP32ToFP16(params->weight_store, weights); } - // prepare weights + // Prepare weights TRT_ShapedWeights shift_weights(weights.type_); TRT_ShapedWeights scale_weights(weights.type_); TRT_ShapedWeights power_weights(weights.type_); - // Maybe I should do a switch if (node_def.op() == "Sub") { if (swapped_inputs) { shift_weights = weights; @@ -1475,8 +1495,8 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, } else if (node_def.op() == "Add") { shift_weights = weights; } else { - return tensorflow::errors::Unimplemented("Binary op not supported: " + - node_def.op()); + // This should not happen. + return errors::Unimplemented("Binary op not supported at ", node_def.op()); } nvinfer1::IScaleLayer* layer = params->converter->network()->addScale( @@ -1486,8 +1506,8 @@ tensorflow::Status BinaryTensorOpWeight(OpConverterParams* params, TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); const nvinfer1::ITensor* output_tensor = layer->getOutput(0); - // transpose back dimension - if (permutation_flag) { + // Transpose back dimension + if (need_to_permute) { TF_RETURN_IF_ERROR(params->converter->TransposeTensor( const_cast(output_tensor), permutation, &output_tensor)); @@ -1621,9 +1641,9 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, params->node_def.name()); } -tensorflow::Status BinaryTensorOpTensor(OpConverterParams* params, - const TRT_TensorOrWeights& operand_l, - const TRT_TensorOrWeights& operand_r) { +Status BinaryTensorOpTensor(OpConverterParams* params, + const TRT_TensorOrWeights& operand_l, + const TRT_TensorOrWeights& operand_r) { const auto& node_def = params->node_def; static const std::unordered_map ops{ {"Add", nvinfer1::ElementWiseOperation::kSUM}, @@ -1634,50 +1654,52 @@ tensorflow::Status BinaryTensorOpTensor(OpConverterParams* params, {"Minimum", nvinfer1::ElementWiseOperation::kMIN}, {"Maximum", nvinfer1::ElementWiseOperation::kMAX}, }; + auto op_pair = ops.find(node_def.op()); + if (op_pair == ops.end()) { + return errors::Unimplemented("Binary op ", node_def.op(), + " not supported at: ", node_def.name()); + } - const nvinfer1::ITensor* tensor_l; - const nvinfer1::ITensor* tensor_r; - - nvinfer1::Dims dim_l; - nvinfer1::Dims dim_r; - - if (!TensorRTGetBroadcastShape(operand_l.GetTrtDims(), operand_l.is_tensor(), - operand_r.GetTrtDims(), operand_r.is_tensor(), - &dim_l, &dim_r)) { - return tensorflow::errors::InvalidArgument( - "Binary op broadcast scheme not supported by TensorRT op: " + - node_def.op() + ", at: " + node_def.name()); + nvinfer1::Dims broadcasted_dims_l, broadcasted_dims_r; + Status status = params->converter->GetTrtBroadcastShape( + operand_l, operand_r, &broadcasted_dims_l, &broadcasted_dims_r); + if (!status.ok()) { + return errors::InvalidArgument( + "Unsupported binary op broadcast scheme for op ", node_def.name(), ": ", + status.error_message()); } + if (params->validation_only) return Status::OK(); - TF_RETURN_IF_ERROR( - params->converter->PrepareTensorForShape(operand_l, dim_l, &tensor_l)); - TF_RETURN_IF_ERROR( - params->converter->PrepareTensorForShape(operand_r, dim_r, &tensor_r)); + const nvinfer1::ITensor* tensor_l = nullptr; + const nvinfer1::ITensor* tensor_r = nullptr; + status = params->converter->PrepareTensorForShape( + operand_l, broadcasted_dims_l, &tensor_l); + if (status.ok()) { + status = params->converter->PrepareTensorForShape( + operand_r, broadcasted_dims_r, &tensor_r); + } + if (!status.ok()) { + return errors::Internal("Failed to convert binary op ", node_def.name(), + ": ", status.error_message()); + } - // get trt type & shape + // Check type consistency. TFAttrs attrs(node_def); - // maybe this part has to be moved into the block of rsqrt later nvinfer1::DataType dtype = attrs.get("T"); + TFTRT_CHECK_EQ_TYPE(tensor_l->getType(), dtype) + << DebugString(tensor_l->getType()) << " vs " << DebugString(dtype); + TFTRT_CHECK_EQ_TYPE(tensor_r->getType(), dtype) + << DebugString(tensor_r->getType()) << " vs " << DebugString(dtype); - // check type consistency - TFTRT_CHECK_EQ_TYPE(tensor_l->getType(), dtype); - TFTRT_CHECK_EQ_TYPE(tensor_r->getType(), dtype); - auto op_pair = ops.find(node_def.op()); - if (op_pair == ops.end()) { - return tensorflow::errors::Unimplemented( - "binary op: ", node_def.op(), " not supported at: ", node_def.name()); - } - + // Add ElementWise layer. nvinfer1::IElementWiseLayer* layer = params->converter->network()->addElementWise( - // TODO(aaroey): will tensor_l/tensor_r get modified? *const_cast(tensor_l), *const_cast(tensor_r), op_pair->second); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); - nvinfer1::ITensor* output_tensor = layer->getOutput(0); - // pass the output + // Pass the output params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); return tensorflow::Status::OK(); } @@ -2135,9 +2157,9 @@ tensorflow::Status ConvertBiasAdd(OpConverterParams* params) { } permutation.order[0] = channel_index; permutation.order[channel_index] = 0; + VLOG(1) << "ConvertBiasAdd permutation: " + << DebugString(permutation, original_dims.nbDims); } - VLOG(1) << "ConvertBiasAdd permutation: " - << DebugString(permutation, original_dims.nbDims); // TensorRT addScale requires input to be of rank 3, we need to apply // transpose as well as reshape. @@ -2369,18 +2391,17 @@ tensorflow::Status ConvertIdentity(OpConverterParams* params) { return tensorflow::Status::OK(); } -tensorflow::Status ConvertBinary(OpConverterParams* params) { +Status ConvertBinary(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; if (inputs.size() != 2) { - return tensorflow::errors::FailedPrecondition( - "Binary ops require two tensor input, at ", node_def.name()); + return errors::InvalidArgument("Binary ops require two inputs, at ", + node_def.name()); } // Constant folding should have been done by TensorFlow - if (inputs.at(0).is_weights() && inputs.at(1).is_weights()) { - return tensorflow::errors::Unimplemented( + return errors::Unimplemented( "Constant folding is falled back to TensorFlow, binary op received " "both input as constant at: ", node_def.name()); @@ -2393,11 +2414,11 @@ tensorflow::Status ConvertBinary(OpConverterParams* params) { // IScaleLayer are when the layer performs both a shift and a scale, which we // don't do except for convolutions. // - // Try to convert into Scale layer first (for better performance) + // Try to convert into Scale layer first (for better performance). // Since scale layer supports restricted broadcast policy and op types, we // allow failure and try to handle it through Elementwise op - // (BinaryTensorOpTensor) - Status status = tensorflow::Status::OK(); + // (BinaryTensorOpTensor). + Status status = Status::OK(); if (inputs.at(0).is_tensor() && inputs.at(1).is_weights()) { status = BinaryTensorOpWeight(params, inputs.at(0).tensor(), inputs.at(1).weights(), false); @@ -2405,7 +2426,10 @@ tensorflow::Status ConvertBinary(OpConverterParams* params) { status = BinaryTensorOpWeight(params, inputs.at(1).tensor(), inputs.at(0).weights(), true); } + // If both input are tensors, or one of them is weights but the conversion + // above failed, try the conversion using BinaryTensorOpTensor. if ((inputs.at(0).is_tensor() && inputs.at(1).is_tensor()) || !status.ok()) { + if (!status.ok()) VLOG(1) << status; status = BinaryTensorOpTensor(params, inputs.at(0), inputs.at(1)); } return status; @@ -3050,48 +3074,49 @@ tensorflow::Status ConvertTopK(OpConverterParams* params) { return tensorflow::Status::OK(); } -void TrtNodeValidator::RegisterOpValidators() { +static void RegisterValidatableOpConverters( + std::unordered_map* registration) { // TODO(laigd): support all op types. - op_validators_["BiasAdd"] = ConvertBiasAdd; - op_validators_["Const"] = ConvertConst; - op_validators_["Transpose"] = ConvertTranspose; - op_validators_["Reshape"] = ConvertReshape; - op_validators_["MatMul"] = ConvertMatMul; + (*registration)["BiasAdd"] = ConvertBiasAdd; + (*registration)["Const"] = ConvertConst; + (*registration)["Transpose"] = ConvertTranspose; + (*registration)["Reshape"] = ConvertReshape; + (*registration)["MatMul"] = ConvertMatMul; + (*registration)["Relu6"] = ConvertRelu6; - op_validators_["Relu6"] = ConvertRelu6; + for (auto quantization_op_type : + {"QuantizeAndDequantizeV2", "QuantizeAndDequantizeV3", + "FakeQuantWithMinMaxVars", "FakeQuantWithMinMaxArgs"}) { + (*registration)[quantization_op_type] = ConvertQuantize; + } + for (auto binary_op_type : + {"Add", "Mul", "Sub", "Div", "RealDiv", "Maximum", "Minimum"}) { + (*registration)[binary_op_type] = ConvertBinary; + } +} - op_validators_["QuantizeAndDequantizeV2"] = ConvertQuantize; - op_validators_["QuantizeAndDequantizeV3"] = ConvertQuantize; - op_validators_["FakeQuantWithMinMaxVars"] = ConvertQuantize; - op_validators_["FakeQuantWithMinMaxArgs"] = ConvertQuantize; +void TrtNodeValidator::RegisterOpValidators() { + RegisterValidatableOpConverters(&op_validators_); } void Converter::RegisterOpConverters() { - // vgg_16 slim implementation + RegisterValidatableOpConverters(&op_registry_); + op_registry_["Conv2D"] = ConvertConv2D; op_registry_["DepthwiseConv2dNative"] = ConvertConv2DDepthwise; op_registry_["Relu"] = ConvertActivation; op_registry_["MaxPool"] = ConvertPool; op_registry_["AvgPool"] = ConvertPool; - op_registry_["BiasAdd"] = ConvertBiasAdd; - op_registry_["Const"] = ConvertConst; // TODO(ben,jie): this is a temp hack. op_registry_["Identity"] = ConvertIdentity; // Identity should be removed op_registry_["Snapshot"] = ConvertIdentity; // Snapshot should be removed - // resnet_50_v1 slim implementation - op_registry_["Add"] = ConvertBinary; - op_registry_["Mul"] = ConvertBinary; - op_registry_["Sub"] = ConvertBinary; op_registry_["Pad"] = ConvertPad; op_registry_["ConcatV2"] = ConvertConcat; op_registry_["FusedBatchNorm"] = ConvertFusedBatchNorm; op_registry_["FusedBatchNormV2"] = ConvertFusedBatchNorm; - op_registry_["Div"] = ConvertBinary; - op_registry_["RealDiv"] = ConvertBinary; - op_registry_["Rsqrt"] = ConvertUnary; op_registry_["Reciprocal"] = ConvertUnary; op_registry_["Exp"] = ConvertUnary; @@ -3100,18 +3125,12 @@ void Converter::RegisterOpConverters() { op_registry_["Abs"] = ConvertUnary; op_registry_["Neg"] = ConvertUnary; - op_registry_["Transpose"] = ConvertTranspose; - op_registry_["Reshape"] = ConvertReshape; - op_registry_["Sum"] = ConvertReduce; op_registry_["Prod"] = ConvertReduce; op_registry_["Max"] = ConvertReduce; op_registry_["Min"] = ConvertReduce; op_registry_["Mean"] = ConvertReduce; - op_registry_["Maximum"] = ConvertBinary; - op_registry_["Minimum"] = ConvertBinary; op_registry_["Softmax"] = ConvertSoftmax; - op_registry_["MatMul"] = ConvertMatMul; op_registry_["BatchMatMul"] = ConvertBatchMatMul; op_registry_["TopKV2"] = ConvertTopK; op_registry_["Relu6"] = ConvertRelu6; diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.h b/tensorflow/contrib/tensorrt/convert/convert_nodes.h index 50100a142f..54e19b7395 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.h +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.h @@ -462,6 +462,13 @@ class Converter { const nvinfer1::Dims& dims, const nvinfer1::ITensor** tensor); + // Return OK if the broadcast scheme is supported and compute the shapes after + // broadcasting. + Status GetTrtBroadcastShape(const TRT_TensorOrWeights& operand_l, + const TRT_TensorOrWeights& operand_r, + nvinfer1::Dims* operand_l_new_dims, + nvinfer1::Dims* operand_r_new_dims) const; + private: // Verify the provided batch_size is consistent with batch_size_ and update it // if necessary. diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index b46a7c6c8a..603c4f7b5e 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -52,6 +52,7 @@ namespace convert { using ::tensorflow::strings::StrCat; using ::testing::ElementsAre; +using ::testing::ElementsAreArray; // TODO(laigd): put this into some test utils file. void ExpectStatus(Status status, error::Code code = error::OK, @@ -73,6 +74,32 @@ nvinfer1::Dims GetTestDims(const std::vector& d) { return dims; } +nvinfer1::DataType TfDataTypeToTrt(DataType tf_dtype) { + switch (tf_dtype) { + case DT_FLOAT: + return nvinfer1::DataType::kFLOAT; + case DT_HALF: + return nvinfer1::DataType::kHALF; + case DT_INT32: + return nvinfer1::DataType::kINT32; + default: + QCHECK(false) << "Unexpected data type " << DataTypeString(tf_dtype); + } +} + +DataType TrtDataTypeToTf(nvinfer1::DataType trt_dtype) { + switch (trt_dtype) { + case nvinfer1::DataType::kFLOAT: + return DT_FLOAT; + case nvinfer1::DataType::kHALF: + return DT_HALF; + case nvinfer1::DataType::kINT32: + return DT_INT32; + default: + QCHECK(false) << "Unexpected data type " << static_cast(trt_dtype); + } +} + NodeDef MakeNodeDef(const string& name, const string& op, const std::vector& inputs) { NodeDef node_def; @@ -115,6 +142,15 @@ bool TrtDimsEqualsArray(const std::vector& lhs, return TrtDimsEquals(GetTestDims(lhs), rhs); } +// TODO(laigd): define a parameterized matcher that can compare against the +// vector. +void ExpectTrtDimsEqualsArray(const std::vector& lhs, + const nvinfer1::Dims& rhs) { + EXPECT_TRUE(TrtDimsEqualsArray(lhs, rhs)) + << "expected: " << DebugString(GetTestDims(lhs)) << "\n" + << " actual: " << DebugString(rhs); +} + bool TrtShapedWeightsEquals(const TRT_ShapedWeights& lhs, const TRT_ShapedWeights& rhs) { return TrtDimsEquals(lhs.shape_, rhs.shape_) && lhs.type_ == rhs.type_ && @@ -125,8 +161,7 @@ template void ValidateWeights(const TRT_ShapedWeights& weights, const std::vector& expected_dims, const std::vector& expected_value) { - EXPECT_TRUE(TrtDimsEqualsArray(expected_dims, weights.shape_)) - << weights.DebugString(); + ExpectTrtDimsEqualsArray(expected_dims, weights.shape_); ASSERT_EQ(expected_value.size(), weights.count()) << weights.DebugString(); const T* actual_values = static_cast(weights.GetValues()); for (int i = 0; i < expected_value.size(); ++i) { @@ -276,9 +311,7 @@ TEST(TRT_TensorOrWeights_Test, Basic) { EXPECT_EQ(1, ptr->batch_size()); } EXPECT_EQ(&itensor, ptr->tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({1}, ptr->GetTrtDims())) - << "- expected: " << DebugString(dims) - << "\n vs\n- actual: " << DebugString(ptr->GetTrtDims()); + ExpectTrtDimsEqualsArray({1}, ptr->GetTrtDims()); } } } @@ -297,9 +330,7 @@ TEST(TRT_TensorOrWeights_Test, Basic) { EXPECT_EQ(false, ptr->is_weights()); EXPECT_EQ(1, ptr->batch_size()); EXPECT_NE(nullptr, ptr->tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({1}, ptr->GetTrtDims())) - << "- expected: " << DebugString(dims) - << "\n vs\n- actual: " << DebugString(ptr->GetTrtDims()); + ExpectTrtDimsEqualsArray({1}, ptr->GetTrtDims()); } } // Test constructor with TRT_ShapedWeights argument. @@ -316,9 +347,7 @@ TEST(TRT_TensorOrWeights_Test, Basic) { nvinfer1::Dims dims; dims.nbDims = 0; - EXPECT_TRUE(TrtDimsEqualsArray({}, ptr->GetTrtDims())) - << "- expected: " << DebugString(dims) - << "\n vs\n- actual: " << DebugString(ptr->GetTrtDims()); + ExpectTrtDimsEqualsArray({}, ptr->GetTrtDims()); } } } @@ -395,9 +424,7 @@ TEST_F(ValidatorTest, ConvertToTensorOrWeights) { EXPECT_EQ(true, output.is_tensor()); EXPECT_EQ(batch_size, output.batch_size()); EXPECT_NE(nullptr, output.tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({non_batch_dim}, output.GetTrtDims())) - << "- expected: {" << non_batch_dim << "} \n vs\n" - << "- actual: " << DebugString(output.GetTrtDims()); + ExpectTrtDimsEqualsArray({non_batch_dim}, output.GetTrtDims()); } } @@ -548,9 +575,9 @@ TEST_F(ConverterTest, AddAndGetInputs) { EXPECT_EQ(nvinfer1::DataType::kFLOAT, inputs[0].tensor()->getType()); EXPECT_EQ(nvinfer1::DataType::kINT32, inputs[2].tensor()->getType()); EXPECT_EQ(nvinfer1::DataType::kHALF, inputs[3].tensor()->getType()); - EXPECT_TRUE(TrtDimsEqualsArray({1}, inputs[0].tensor()->getDimensions())); - EXPECT_TRUE(TrtDimsEqualsArray({2, 3}, inputs[2].tensor()->getDimensions())); - EXPECT_TRUE(TrtDimsEqualsArray({5, 3}, inputs[3].tensor()->getDimensions())); + ExpectTrtDimsEqualsArray({1}, inputs[0].tensor()->getDimensions()); + ExpectTrtDimsEqualsArray({2, 3}, inputs[2].tensor()->getDimensions()); + ExpectTrtDimsEqualsArray({5, 3}, inputs[3].tensor()->getDimensions()); } TEST_F(ConverterTest, RenameAndMarkOutputTensors) { @@ -596,7 +623,7 @@ TEST_F(ConverterTest, RenameAndMarkOutputTensors) { {{"my_op", "my_output"}, {"my_op:1", "my_output_1"}})); EXPECT_EQ(2, output_tensors.size()); for (auto output_tensor : output_tensors) { - EXPECT_TRUE(TrtDimsEqualsArray({2, 1}, output_tensor->getDimensions())); + ExpectTrtDimsEqualsArray({2, 1}, output_tensor->getDimensions()); } EXPECT_EQ("my_output", string(output_tensors[0]->getName())); EXPECT_EQ("my_output_1", string(output_tensors[1]->getName())); @@ -621,8 +648,7 @@ TEST_F(ConverterTest, TransposeTensor) { // OK. TF_EXPECT_OK( converter_->TransposeTensor(input_tensor, {0, 3, 1, 2}, &output_tensor)); - EXPECT_TRUE(TrtDimsEqualsArray({5, 2, 3}, output_tensor->getDimensions())) - << DebugString(*output_tensor); + ExpectTrtDimsEqualsArray({5, 2, 3}, output_tensor->getDimensions()); } TEST_F(ConverterTest, PrepareTensorForShape_Tensor) { @@ -634,7 +660,7 @@ TEST_F(ConverterTest, PrepareTensorForShape_Tensor) { // Shape size doesn't match. ExpectStatus(converter_->PrepareTensorForShape(tw, GetTestDims({2, 3, 6}), &output_tensor), - error::INVALID_ARGUMENT, "Reshape shapes are not compatible."); + error::INVALID_ARGUMENT, "Reshape shapes are not compatible"); // TODO(aaroey): we should check the case where uninferred dimensions are not // an exact divisor of input dim ensions, e.g. for dims {-1, 7}. @@ -642,14 +668,12 @@ TEST_F(ConverterTest, PrepareTensorForShape_Tensor) { // Infer shape, ok. TF_EXPECT_OK(converter_->PrepareTensorForShape(tw, GetTestDims({-1, 2}), &output_tensor)); - EXPECT_TRUE(TrtDimsEqualsArray({15, 2}, output_tensor->getDimensions())) - << DebugString(*output_tensor); + ExpectTrtDimsEqualsArray({15, 2}, output_tensor->getDimensions()); // Regular shape. TF_EXPECT_OK(converter_->PrepareTensorForShape(tw, GetTestDims({10, 3}), &output_tensor)); - EXPECT_TRUE(TrtDimsEqualsArray({10, 3}, output_tensor->getDimensions())) - << DebugString(*output_tensor); + ExpectTrtDimsEqualsArray({10, 3}, output_tensor->getDimensions()); } TEST_F(ConverterTest, PrepareTensorForShape_Weights) { @@ -659,8 +683,7 @@ TEST_F(ConverterTest, PrepareTensorForShape_Weights) { const nvinfer1::ITensor* output_tensor = nullptr; TF_EXPECT_OK(converter_->PrepareTensorForShape(tw, GetTestDims({10, 3}), &output_tensor)); - EXPECT_TRUE(TrtDimsEqualsArray({10, 3}, output_tensor->getDimensions())) - << DebugString(*output_tensor); + ExpectTrtDimsEqualsArray({10, 3}, output_tensor->getDimensions()); } TEST_F(ConverterTest, MaybeUpdateBatchSize) { @@ -782,6 +805,96 @@ TEST_F(ConverterTest, PropagateQuantizationRanges) { EXPECT_EQ(ranges.count(¬_infer), 0); } +TEST_F(ConverterTest, GetTrtBroadcastShape) { + const bool kIsTensor = true; + const bool kIsNotTensor = false; + auto symmetric_test = [this](const std::vector& operand_1_shape, + const std::vector& operand_2_shape, + const bool operand_1_is_tensor, + const bool operand_2_is_tensor, + const std::vector& expected_operand_1_shape, + const std::vector& expected_operand_2_shape, + error::Code expected_code = error::OK, + const char* expected_error_msg_substr = nullptr, + const int operand_1_batch_size = -1, + const int operand_2_batch_size = -1) { + auto create_tensor_or_weights = [](const std::vector& shape, + bool is_tensor, int batch_size = -1) { + if (is_tensor) { + return TRT_TensorOrWeights{nvinfer1::DataType::kFLOAT, + GetTestDims(shape), batch_size}; + } + TRT_ShapedWeights weights; + weights.shape_ = GetTestDims(shape); + return TRT_TensorOrWeights(weights); + }; + + nvinfer1::Dims operand_1_new_dims, operand_2_new_dims; + TRT_TensorOrWeights operand_1 = create_tensor_or_weights( + operand_1_shape, operand_1_is_tensor, operand_1_batch_size); + TRT_TensorOrWeights operand_2 = create_tensor_or_weights( + operand_2_shape, operand_2_is_tensor, operand_2_batch_size); + + // operand_1 broadcast operand_2 + ExpectStatus( + this->converter_->GetTrtBroadcastShape( + operand_1, operand_2, &operand_1_new_dims, &operand_2_new_dims), + expected_code, expected_error_msg_substr); + if (expected_code == error::OK) { + ExpectTrtDimsEqualsArray(expected_operand_1_shape, operand_1_new_dims); + ExpectTrtDimsEqualsArray(expected_operand_2_shape, operand_2_new_dims); + } + // operand_2 broadcast operand_1 + ExpectStatus( + this->converter_->GetTrtBroadcastShape( + operand_2, operand_1, &operand_2_new_dims, &operand_1_new_dims), + expected_code, expected_error_msg_substr); + if (expected_code == error::OK) { + ExpectTrtDimsEqualsArray(expected_operand_1_shape, operand_1_new_dims); + ExpectTrtDimsEqualsArray(expected_operand_2_shape, operand_2_new_dims); + } + }; + + // Both inputs are weights. + symmetric_test( + {1}, {1}, kIsNotTensor, kIsNotTensor, {}, {}, error::INVALID_ARGUMENT, + "Broadcasting requires at least one of the operands be tensors"); + + // One tensor and one weights. + symmetric_test({1, 1, 1}, {2}, kIsTensor, kIsNotTensor, {1, 1, 1}, {1, 1, 2}); + symmetric_test({1, 1, 2}, {2}, kIsTensor, kIsNotTensor, {1, 1, 2}, {1, 1, 2}); + symmetric_test({1, 3, 2}, {1}, kIsTensor, kIsNotTensor, {1, 3, 2}, {1, 1, 1}); + symmetric_test({1, 1, 1}, {2, 3}, kIsTensor, kIsNotTensor, {1, 1, 1}, + {1, 2, 3}); + symmetric_test({1, 1, 1}, {2, 3, 4}, kIsTensor, kIsNotTensor, {1, 1, 1}, + {2, 3, 4}); + symmetric_test({1, 1, 1}, {1, 2, 3, 4}, kIsTensor, kIsNotTensor, {1, 1, 1}, + {2, 3, 4}); + symmetric_test({1, 3, 4}, {1, 2, 1, 4}, kIsTensor, kIsNotTensor, {1, 3, 4}, + {2, 1, 4}); + symmetric_test({1, 1, 1}, {2, 1, 1, 1}, kIsTensor, kIsNotTensor, {}, {}, + error::INVALID_ARGUMENT, "Infeasible broadcast scheme"); + symmetric_test({1, 1, 1}, {2, 1, 1, 1}, kIsTensor, kIsNotTensor, {}, {}, + error::INVALID_ARGUMENT, "Infeasible broadcast scheme", + /*operand_1_batch_size=*/2); + symmetric_test({1, 1, 1}, {1, 1, 1, 1, 1}, kIsTensor, kIsNotTensor, {}, {}, + error::INVALID_ARGUMENT, + "Broadcasting beyond batch dimension is not supported " + "(tensor #dims 4 vs broadcast #dims 5)"); + + // Both inputs are tensors. + symmetric_test({1, 1, 1}, {1, 1}, kIsTensor, kIsTensor, {}, {}, + error::INVALID_ARGUMENT, + "Broadcasting beyond batch dimension is not supported " + "(tensor #dims 3 vs broadcast #dims 4)"); + symmetric_test({1, 3, 4}, {2, 1, 4}, kIsTensor, kIsTensor, {1, 3, 4}, + {2, 1, 4}); + symmetric_test({1, 1, 1}, {1, 1, 1, 1}, kIsTensor, kIsTensor, {}, {}, + error::INVALID_ARGUMENT, + "Broadcasting beyond batch dimension is not supported " + "(tensor #dims 4 vs broadcast #dims 5)"); +} + // Class to test various op converters, using both a TrtNodeValidator and // Converter. class OpConverterTest : public ::testing::Test { @@ -820,8 +933,11 @@ class OpConverterTest : public ::testing::Test { } // TODO(laigd): test fp16 and int8 support. - void BuildAndRun(const char* input_name, const std::vector& input_data, - const char* output_name, std::vector* output_data) { + template + void BuildAndRun( + const std::vector>>& + input_data, + const char* output_name, std::vector* output_data) { // Mark the output tensor as TRT engine output. TF_EXPECT_OK(converter_->RenameAndMarkOutputTensors( {{string(output_name), string(output_name)}})); @@ -832,25 +948,33 @@ class OpConverterTest : public ::testing::Test { CHECK_NOTNULL(engine_.get()); // Execute the TRT engine. - const int input_size = input_data.size() * sizeof(float); - const int output_size = output_data->size() * sizeof(float); - const int input_index = engine_->getBindingIndex(input_name); - const int output_index = engine_->getBindingIndex(output_name); + ASSERT_LE(input_data.size() + 1, 3); + void* buffers[3]; + for (const auto name_and_data : input_data) { + const int input_size = name_and_data.second.size() * sizeof(T); + const int input_index = engine_->getBindingIndex(name_and_data.first); + ASSERT_EQ(0, cudaMalloc(&buffers[input_index], input_size)); + ASSERT_EQ( + 0, cudaMemcpyAsync(buffers[input_index], name_and_data.second.data(), + input_size, cudaMemcpyHostToDevice, stream_)); + } - ASSERT_EQ(engine_->getNbBindings(), 2); - void* buffers[2]; - ASSERT_EQ(0, cudaMalloc(&buffers[input_index], input_size)); + const int output_size = output_data->size() * sizeof(T); + const int output_index = engine_->getBindingIndex(output_name); ASSERT_EQ(0, cudaMalloc(&buffers[output_index], output_size)); - ASSERT_EQ(0, cudaMemcpyAsync(buffers[input_index], input_data.data(), - input_size, cudaMemcpyHostToDevice, stream_)); + + ASSERT_EQ(engine_->getNbBindings(), input_data.size() + 1); + TrtUniquePtrType execution_context( engine_->createExecutionContext()); execution_context->enqueue(/*batchSize=*/1, buffers, stream_, nullptr); ASSERT_EQ(0, cudaMemcpyAsync(output_data->data(), buffers[output_index], output_size, cudaMemcpyDeviceToHost, stream_)); cudaStreamSynchronize(stream_); - ASSERT_EQ(0, cudaFree(buffers[input_index])); - ASSERT_EQ(0, cudaFree(buffers[output_index])); + + for (int i = 0; i < input_data.size() + 1; ++i) { + ASSERT_EQ(0, cudaFree(buffers[i])); + } } bool HasStaticShape(const nvinfer1::Dims& dims) const { @@ -865,18 +989,7 @@ class OpConverterTest : public ::testing::Test { void AddTestTensor( const char* name, const std::vector& dims, int batch_size = 1, nvinfer1::DataType trt_dtype = nvinfer1::DataType::kFLOAT) { - DataType tf_dtype = DT_FLOAT; - switch (trt_dtype) { - case nvinfer1::DataType::kFLOAT: - tf_dtype = DT_FLOAT; - break; - case nvinfer1::DataType::kINT32: - tf_dtype = DT_INT32; - break; - default: - ASSERT_TRUE(false) << "Unexpected data type " - << static_cast(trt_dtype); - } + DataType tf_dtype = TrtDataTypeToTf(trt_dtype); ops::Placeholder::Attrs attrs; TF_EXPECT_OK(TensorShapeUtils::MakeShape(dims, &attrs.shape_)); attrs.shape_.InsertDim(0, batch_size); @@ -1097,15 +1210,15 @@ TEST_F(OpConverterTest, ConvertTranspose) { Reset(); AddTestTensor("input", {1, 2, 3}); AddTestWeights("weights", {4}, {0, 3, 1, 2}); - RunConversion(node_def); + RunValidationAndConversion(node_def); TRT_TensorOrWeights output; TF_EXPECT_OK(GetTensorOrWeights("my_transpose", &output)); EXPECT_TRUE(output.is_tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({3, 1, 2}, output.tensor()->getDimensions())) - << output.DebugString(); + ExpectTrtDimsEqualsArray({3, 1, 2}, output.tensor()->getDimensions()); std::vector output_data(6); - BuildAndRun("input", {1, 2, 3, 4, 5, 6}, "my_transpose", &output_data); + BuildAndRun({{"input", {1, 2, 3, 4, 5, 6}}}, "my_transpose", + &output_data); EXPECT_THAT(output_data, ElementsAre(1, 4, 2, 5, 3, 6)); } } @@ -1187,15 +1300,15 @@ TEST_F(OpConverterTest, ConvertReshape) { Reset(); AddTestTensor("input", ok_params[i].tensor_dims, ok_params[i].batch_size); AddTestWeights("weights", {4}, ok_params[i].shape); - RunConversion(node_def); + RunValidationAndConversion(node_def); TRT_TensorOrWeights output; TF_EXPECT_OK(GetTensorOrWeights("my_reshape", &output)); EXPECT_TRUE(output.is_tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({1, 3, 2}, output.tensor()->getDimensions())) - << output.DebugString(); + ExpectTrtDimsEqualsArray({1, 3, 2}, output.tensor()->getDimensions()); std::vector output_data(6); - BuildAndRun("input", {1, 2, 3, 4, 5, 6}, "my_reshape", &output_data); + BuildAndRun({{"input", {1, 2, 3, 4, 5, 6}}}, "my_reshape", + &output_data); EXPECT_THAT(output_data, ElementsAre(1, 2, 3, 4, 5, 6)); } } @@ -1250,15 +1363,14 @@ TEST_F(OpConverterTest, ConvertMatMul) { get_matmul_nodedef(DT_FLOAT, /*transpose_a=*/false, transpose_b); AddTestTensor("input", {2}, /*batch_size=*/1); AddTestWeights("weights", {2, 2}, {0, 1, 2, 3}); - RunConversion(node_def); + RunValidationAndConversion(node_def); TRT_TensorOrWeights output; TF_EXPECT_OK(GetTensorOrWeights("my_matmul", &output)); EXPECT_TRUE(output.is_tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({2}, output.tensor()->getDimensions())) - << output.DebugString(); + ExpectTrtDimsEqualsArray({2}, output.tensor()->getDimensions()); std::vector output_data(2); - BuildAndRun("input", {0, 1}, "my_matmul", &output_data); + BuildAndRun({{"input", {0, 1}}}, "my_matmul", &output_data); if (transpose_b) { EXPECT_THAT(output_data, ElementsAre(1, 3)); } else { @@ -1294,12 +1406,15 @@ void TestConvertBiasAdd(OpConverterTest* test) { dims_array[0] = 2; dims_array[trt_input_rank - 1] = 3; } - test->AddTestTensor("input", dims_array, /*batch_size=*/1); + test->AddTestTensor("input", dims_array, /*batch_size=*/1, + TfDataTypeToTrt(dtype)); // Add bias weights. const int channel_size = (data_format == "NHWC" ? 3 : 2); std::vector bias(channel_size); - std::iota(bias.begin(), bias.end(), 1); // bias will be {1, 2, 3, ...} + for (int i = 0; i < channel_size; ++i) { + bias[i] = CType(i + 1); // bias will be {1, 2, 3, ...} + } test->AddTestWeights("weights", {channel_size}, bias); // Run the conversion. @@ -1307,28 +1422,29 @@ void TestConvertBiasAdd(OpConverterTest* test) { TRT_TensorOrWeights output; TF_EXPECT_OK(test->GetTensorOrWeights("my_biasadd", &output)); EXPECT_TRUE(output.is_tensor()); - EXPECT_TRUE( - TrtDimsEqualsArray(dims_array, output.tensor()->getDimensions())) - << output.DebugString(); + ExpectTrtDimsEqualsArray(dims_array, output.tensor()->getDimensions()); // Build and run the engine. const int num_input = TrtDimsNumElements(GetTestDims(dims_array)); ASSERT_EQ(trt_input_rank > 1 ? 6 : (data_format == "NHWC" ? 3 : 2), num_input); std::vector output_data(num_input); - test->BuildAndRun("input", std::vector(num_input, CType(0)), - "my_biasadd", &output_data); + test->BuildAndRun( + {{"input", std::vector(num_input, CType(0))}}, "my_biasadd", + &output_data); if (trt_input_rank == 1) { if (data_format == "NHWC") { - EXPECT_THAT(output_data, ElementsAre(1, 2, 3)); + EXPECT_THAT(output_data, ElementsAre(CType(1), CType(2), CType(3))); } else { - EXPECT_THAT(output_data, ElementsAre(1, 2)); + EXPECT_THAT(output_data, ElementsAre(CType(1), CType(2))); } } else { if (data_format == "NHWC") { - EXPECT_THAT(output_data, ElementsAre(1, 2, 3, 1, 2, 3)); + EXPECT_THAT(output_data, ElementsAre(CType(1), CType(2), CType(3), + CType(1), CType(2), CType(3))); } else { - EXPECT_THAT(output_data, ElementsAre(1, 1, 1, 2, 2, 2)); + EXPECT_THAT(output_data, ElementsAre(CType(1), CType(1), CType(1), + CType(2), CType(2), CType(2))); } } } @@ -1344,11 +1460,344 @@ TEST_F(OpConverterTest, ConvertBiasAdd) { "Input expects tensor and weights, at my_biasadd"); } - // OK. + // OK. Note that kINT32 is not supported by IScaleLayer, so we don't test + // DT_INT32 type here. TestConvertBiasAdd(this); - // TODO(laigd): uncomment this after cl/220663893 is submitted. - // TestConvertBiasAdd(this); - // TestConvertBiasAdd(this); + TestConvertBiasAdd(this); +} + +template +NodeDef GetBinaryOpNodeDef(const string& input_name_l, + const string& input_name_r, DataType dtype) { + Scope s = Scope::NewRootScope(); + auto input_l = ops::Placeholder(s.WithOpName(input_name_l), dtype); + auto input_r = ops::Placeholder(s.WithOpName(input_name_r), dtype); + auto op = OpType(s.WithOpName("my_binary"), input_l, input_r); + return op.operation.node()->def(); +} + +void CheckAddedLayers(OpConverterTest* test, bool expect_scale_layer) { + bool element_wise_layer_found = false; + bool scale_layer_found = false; + for (int i = 0; i < test->converter_->network()->getNbLayers(); i++) { + nvinfer1::ILayer* layer = test->converter_->network()->getLayer(i); + if (dynamic_cast(layer)) { + scale_layer_found = true; + } else if (dynamic_cast(layer)) { + element_wise_layer_found = true; + } + } + EXPECT_EQ(expect_scale_layer, scale_layer_found); + EXPECT_NE(expect_scale_layer, element_wise_layer_found); +} + +template +void TestBinaryTensorOpWeightNoBroadcast(OpConverterTest* test) { + typedef typename EnumToDataType::Type CType; + for (auto swap_inputs : {false, true}) { + test->Reset(); + NodeDef node_def; + if (swap_inputs) { + node_def = GetBinaryOpNodeDef("weights", "input", dtype); + } else { + node_def = GetBinaryOpNodeDef("input", "weights", dtype); + } + + const std::vector operand1{CType(3), CType(7.5)}; + const std::vector operand2{CType(2), CType(3)}; + + // It requires the dims to be at least of rank 3 to apply an IScaleLayer. + test->AddTestTensor("input", /*dims=*/{1, 1, 2}, /*batch_size=*/1, + TfDataTypeToTrt(dtype)); + test->AddTestWeights("weights", /*dims=*/{1, 1, 2}, + /*values=*/swap_inputs ? operand1 : operand2); + test->RunValidationAndConversion(node_def); + + // Make sure it does use BinaryTensorOpWeight, not BinaryTensorOpTensor. + CheckAddedLayers(test, /*expect_scale_layer=*/true); + + // Check the dims of the output ITensor. + TRT_TensorOrWeights output; + TF_EXPECT_OK(test->GetTensorOrWeights("my_binary", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray({1, 1, 2}, output.tensor()->getDimensions()); + + std::vector output_data(2); + test->BuildAndRun( + {{"input", + /*input_data=*/swap_inputs ? operand2 : operand1}}, + "my_binary", &output_data); + if (node_def.op() == "Add") { + EXPECT_THAT(output_data, ElementsAre(CType(5), CType(10.5))); + } else if (node_def.op() == "Sub") { + EXPECT_THAT(output_data, ElementsAre(CType(1), CType(4.5))); + } else if (node_def.op() == "Mul") { + EXPECT_THAT(output_data, ElementsAre(CType(6), CType(22.5))); + } else if (node_def.op() == "Div") { + EXPECT_THAT(output_data, ElementsAre(CType(1.5), CType(2.5))); + } else if (node_def.op() == "RealDiv") { + EXPECT_THAT(output_data, ElementsAre(CType(1.5), CType(2.5))); + } else { + ASSERT_TRUE(false); + } + } +} + +template +void TestBinaryTensorOpWeightWithChannelWiseBroadcast(OpConverterTest* test) { + typedef typename EnumToDataType::Type CType; + const NodeDef node_def = + GetBinaryOpNodeDef("input", "weights", dtype); + const std::vector input{CType(1), CType(2), CType(3), CType(4)}; + const std::vector weights{CType(10), CType(20)}; + // There are two types of valid dim pairs which requires channel-wise + // broadcasting: + // - input dims (X Y Z) vs weights dims (X 1 1) + // - input dims (X Y Z) vs weights dims (Z) + // Here X=Z=2 and Y=1. + for (auto weights_dims : std::vector>{{2, 1, 1}, {2}}) { + test->Reset(); + test->AddTestTensor("input", /*dims=*/{2, 1, 2}, /*batch_size=*/1, + TfDataTypeToTrt(dtype)); + test->AddTestWeights("weights", weights_dims, weights); + test->RunValidationAndConversion(node_def); + + // Make sure it does use BinaryTensorOpWeight, not BinaryTensorOpTensor. + CheckAddedLayers(test, /*expect_scale_layer=*/true); + + // Check the dims of the output ITensor. + TRT_TensorOrWeights output; + TF_EXPECT_OK(test->GetTensorOrWeights("my_binary", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray({2, 1, 2}, output.tensor()->getDimensions()); + + std::vector output_data(4); + test->BuildAndRun({{"input", input}}, "my_binary", &output_data); + if (weights_dims.size() == 1) { + EXPECT_THAT(output_data, + ElementsAre(CType(11), CType(22), CType(13), CType(24))); + } else { + EXPECT_THAT(output_data, + ElementsAre(CType(11), CType(12), CType(23), CType(24))); + } + } +} + +template +void TestBinaryTensorOpWeightWithUniformlyBroadcast(OpConverterTest* test) { + typedef typename EnumToDataType::Type CType; + const NodeDef node_def = + GetBinaryOpNodeDef("input", "weights", dtype); + const std::vector input{CType(1), CType(2), CType(3), CType(4)}; + const std::vector weights{CType(10)}; + test->Reset(); + test->AddTestTensor("input", /*dims=*/{2, 1, 2}, /*batch_size=*/1, + TfDataTypeToTrt(dtype)); + test->AddTestWeights("weights", {1, 1, 1, 1}, weights); + test->RunValidationAndConversion(node_def); + + // Make sure it does use BinaryTensorOpWeight, not BinaryTensorOpTensor. + CheckAddedLayers(test, /*expect_scale_layer=*/true); + + // Check the dims of the output ITensor. + TRT_TensorOrWeights output; + TF_EXPECT_OK(test->GetTensorOrWeights("my_binary", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray({2, 1, 2}, output.tensor()->getDimensions()); + + std::vector output_data(4); + test->BuildAndRun({{"input", input}}, "my_binary", &output_data); + EXPECT_THAT(output_data, + ElementsAre(CType(11), CType(12), CType(13), CType(14))); +} + +template +void TestBinaryTensorOpWeightFallback(OpConverterTest* test, + const std::vector& input_dims, + const std::vector& weights_dims, + error::Code code = error::OK, + const char* error_msg_substr = nullptr, + const int input_batch_size = 1) { + const DataType dtype = DT_FLOAT; + typedef typename EnumToDataType::Type CType; + const size_t num_inputs = TrtDimsNumElements(GetTestDims(input_dims)); + const size_t num_weights = TrtDimsNumElements(GetTestDims(weights_dims)); + + test->Reset(); + const NodeDef node_def = + GetBinaryOpNodeDef("input", "weights", dtype); + test->AddTestTensor("input", /*dims=*/input_dims, input_batch_size, + TfDataTypeToTrt(dtype)); + test->AddTestWeights( + "weights", /*dims=*/weights_dims, + /*values=*/std::vector(num_weights, CType(1))); + test->RunValidationAndConversion(node_def, code, error_msg_substr); + if (code != error::OK) return; + + // Make sure it does use BinaryTensorOpTensor, not BinaryTensorOpWeight. + CheckAddedLayers(test, /*expect_scale_layer=*/false); + + TRT_TensorOrWeights output; + TF_EXPECT_OK(test->GetTensorOrWeights("my_binary", &output)); + EXPECT_TRUE(output.is_tensor()); + + // Check the dims of the output ITensor. + std::vector expected_output_dims = input_dims; + for (int i = expected_output_dims.size() - 1, j = weights_dims.size() - 1; + i >= 0 && j >= 0; --i, --j) { + if (expected_output_dims[i] == 1) { + expected_output_dims[i] = weights_dims[j]; + } + } + ExpectTrtDimsEqualsArray(expected_output_dims, + output.tensor()->getDimensions()); + + // Check the result of running the engine. + const int expected_num_outputs = + TrtDimsNumElements(GetTestDims(expected_output_dims)); + std::vector output_data(expected_num_outputs); + test->BuildAndRun( + {{"input", + /*input_data=*/std::vector(num_inputs, CType(2))}}, + "my_binary", &output_data); + if (node_def.op() == "Add") { + EXPECT_THAT(output_data, ElementsAreArray(std::vector( + expected_num_outputs, CType(3)))); + } else if (node_def.op() == "Minimum") { + EXPECT_THAT(output_data, ElementsAreArray(std::vector( + expected_num_outputs, CType(1)))); + } else { + ASSERT_TRUE(false); + } +} + +template +void TestBinaryTensorOpTensor(OpConverterTest* test) { + typedef typename EnumToDataType::Type CType; + test->Reset(); + const NodeDef node_def = + GetBinaryOpNodeDef("input1", "input2", dtype); + test->AddTestTensor("input1", /*dims=*/{1, 2}, /*batch_size=*/1, + TfDataTypeToTrt(dtype)); + test->AddTestTensor("input2", /*dims=*/{2, 1}, /*batch_size=*/1, + TfDataTypeToTrt(dtype)); + test->RunValidationAndConversion(node_def); + + // Make sure it does use BinaryTensorOpTensor, not BinaryTensorOpWeight. + CheckAddedLayers(test, /*expect_scale_layer=*/false); + + // Check output dims. + TRT_TensorOrWeights output; + TF_EXPECT_OK(test->GetTensorOrWeights("my_binary", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray({2, 2}, output.tensor()->getDimensions()); + + std::vector output_data(4); + // After broadcasting first input becomes {3, 6, 3, 6} and second input + // becomes {2, 3, 2, 3}. + test->BuildAndRun( + {{"input1", {CType(3), CType(6)}}, {"input2", {CType(2), CType(3)}}}, + "my_binary", &output_data); + if (node_def.op() == "Add") { + EXPECT_THAT(output_data, + ElementsAre(CType(5), CType(8), CType(6), CType(9))); + } else if (node_def.op() == "Sub") { + EXPECT_THAT(output_data, + ElementsAre(CType(1), CType(4), CType(0), CType(3))); + } else if (node_def.op() == "Mul") { + EXPECT_THAT(output_data, + ElementsAre(CType(6), CType(12), CType(9), CType(18))); + } else if (node_def.op() == "Div") { + EXPECT_THAT(output_data, + ElementsAre(CType(1.5), CType(3), CType(1), CType(2))); + } else if (node_def.op() == "RealDiv") { + EXPECT_THAT(output_data, + ElementsAre(CType(1.5), CType(3), CType(1), CType(2))); + } else if (node_def.op() == "Minimum") { + EXPECT_THAT(output_data, + ElementsAre(CType(2), CType(2), CType(3), CType(3))); + } else if (node_def.op() == "Maximum") { + EXPECT_THAT(output_data, + ElementsAre(CType(3), CType(6), CType(3), CType(6))); + } else { + ASSERT_TRUE(false); + } +} + +TEST_F(OpConverterTest, ConvertBinary) { + // Input size doesn't match, should fail. + for (size_t num_inputs = 0; num_inputs < 2; ++num_inputs) { + Reset(); + NodeDef node_def = MakeNodeDef("my_add", "Add", {num_inputs, "input"}); + AddTestTensor("input", {1}, /*batch_size=*/1, nvinfer1::DataType::kFLOAT); + RunValidationAndConversion(node_def, error::INVALID_ARGUMENT, + "Binary ops require two inputs, at my_add"); + } + { + // Both inputs are weights. + Reset(); + NodeDef node_def = MakeNodeDef("my_add", "Add", {"weights1", "weights2"}); + AddTestWeights("weights1", {1}, {1}); + AddTestWeights("weights2", {1}, {1}); + RunValidationAndConversion( + node_def, error::UNIMPLEMENTED, + "Constant folding is falled back to TensorFlow, binary op received " + "both input as constant at: my_add"); + } + + // Test BinaryTensorOpWeight() without broadcasting. + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); +#if 0 + // TODO(b/119560144): it doesn't support FP16 constants and the following test + // will fail. + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); + TestBinaryTensorOpWeightNoBroadcast(this); +#endif + + // Test BinaryTensorOpWeight() with channel-wise broadcasting. + TestBinaryTensorOpWeightWithChannelWiseBroadcast(this); + + // Test BinaryTensorOpWeight() with uniformly broadcasting. + TestBinaryTensorOpWeightWithUniformlyBroadcast(this); + + // Test BinaryTensorOpWeight() falling back to BinaryTensorOpTensor(). + // Unsupported op. + TestBinaryTensorOpWeightFallback(this, {1, 1, 1}, {1}); + // Rank of input tensor dimension <3. + TestBinaryTensorOpWeightFallback(this, {1, 1}, {1}); + // Broadcast on batch dimension, should fail. + TestBinaryTensorOpWeightFallback( + this, {1, 1, 1}, {2, 1, 1, 1}, error::INVALID_ARGUMENT, + "Unsupported binary op broadcast scheme for op my_binary", + /*input_batch_size=*/2); + // Incompatible dims with per-channel mode. + TestBinaryTensorOpWeightFallback(this, {1, 1, 1}, {1, 2, 1}); + // Incompatible dims. + TestBinaryTensorOpWeightFallback(this, {1, 2, 1}, {2}); + + // Test BinaryTensorOpTensor() with broadcasting. + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); + TestBinaryTensorOpTensor(this); } TEST_F(OpConverterTest, ConvertQuantize) { @@ -1509,7 +1958,8 @@ TEST_F(OpConverterTest, ConvertRelu6) { EXPECT_EQ(ranges[output.tensor()], 6.0f); std::vector output_data(6); - BuildAndRun("input", {-100, -1, 0, 3, 5, 9}, "my_relu6", &output_data); + BuildAndRun({{"input", {-100, -1, 0, 3, 5, 9}}}, "my_relu6", + &output_data); EXPECT_THAT(output_data, ElementsAre(0, 0, 0, 3, 5, 6)); } } diff --git a/tensorflow/contrib/tensorrt/test/base_test.py b/tensorflow/contrib/tensorrt/test/base_test.py index 7e826fb7e1..b325d76edf 100644 --- a/tensorflow/contrib/tensorrt/test/base_test.py +++ b/tensorflow/contrib/tensorrt/test/base_test.py @@ -56,8 +56,9 @@ class SimpleSingleEngineTest(trt_test.TfTrtIntegrationTestBase): strides=[1, 2, 2, 1], padding="SAME", name="conv") - bias = constant_op.constant( - [4., 1.5, 2., 3., 5., 7.], name="bias", dtype=dtype) + bias = constant_op.constant([4., 1.5, 2., 3., 5., 7.], + name="bias", + dtype=dtype) added = nn.bias_add(conv, bias, name="bias_add") relu = nn.relu(added, "relu") identity = array_ops.identity(relu, "identity") @@ -73,11 +74,12 @@ class SimpleSingleEngineTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - # TODO(aaroey): LayoutOptimizer adds additional nodes to the graph which - # breaks the connection check, fix it. - # - my_trt_op_0 should have ["weights", "conv", "bias", "bias_add", - # "relu", "identity", "max_pool"] - return ["my_trt_op_0"] + return { + "my_trt_op_0": [ + "weights", "conv", "bias", "bias_add", "relu", "identity", + "max_pool" + ] + } class SimpleMultiEnginesTest(trt_test.TfTrtIntegrationTestBase): @@ -92,7 +94,7 @@ class SimpleMultiEnginesTest(trt_test.TfTrtIntegrationTestBase): g = ops.Graph() with g.as_default(): inp = array_ops.placeholder( - dtype=dtype, shape=[None] + input_dims[1:], name=input_name) + dtype=dtype, shape=input_dims, name=input_name) with g.device("/GPU:0"): conv_filter = constant_op.constant( [[[[1., 0.5, 4., 6., 0.5, 1.], [1., 0.5, 1., 1., 0.5, 1.]]]], @@ -105,10 +107,10 @@ class SimpleMultiEnginesTest(trt_test.TfTrtIntegrationTestBase): padding="SAME", name="conv") c1 = constant_op.constant( - np.random.randn(input_dims[0], 12, 12, 6), dtype=dtype, name="c1") + np.random.randn(12, 12, 6), dtype=dtype, name="c1") p = math_ops.mul(conv, c1, name="mul") c2 = constant_op.constant( - np.random.randn(input_dims[0], 12, 12, 6), dtype=dtype, name="c2") + np.random.randn(12, 12, 6), dtype=dtype, name="c2") q = math_ops.div(conv, c2, name="div") edge = self.trt_incompatible_op(q, name="incompatible") @@ -129,22 +131,21 @@ class SimpleMultiEnginesTest(trt_test.TfTrtIntegrationTestBase): def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" - # TODO(aaroey): LayoutOptimizer adds additional nodes to the graph which - # breaks the connection check, fix it. - # - my_trt_op_0 should have ["mul", "sub", "div1", "mul1", "add1", - # "add", "sub1"]; - # - my_trt_op_1 should have ["weights","conv", "div"] - return ["my_trt_op_0", "my_trt_op_1"] + return { + "my_trt_op_0": [ + "add", "add1", "c1", "div1", "mul", "mul1", "sub", "sub1" + ], + "my_trt_op_1": ["c2", "conv", "div", "weights"] + } - def ShouldRunTest(self, run_params): - # TODO(aaroey): LayoutOptimizer adds Transpose(Const, Const) to the graph - # which breaks the conversion. We should fix it as: - # - Detect the invalid NodeDef earlier before adding them to segment - # - Let it able to change the RewriterConfig when calling - # create_inference_graph(). - # It will be good to add debugging feature for Grappler to print the graph - # after running each optimizer. - return False + def GetConversionParams(self, run_params): + """Return a ConversionParams for test.""" + return super( + SimpleMultiEnginesTest, self + ).GetConversionParams(run_params)._replace( + # Disable layout optimizer, since it'll add Transpose(Const, Const) to + # the graph and breaks the conversion check. + rewriter_config=trt_test.OptimizerDisabledRewriterConfig()) class PartiallyConvertedTestA(trt_test.TfTrtIntegrationTestBase): diff --git a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py index 0d23eeae1a..80eb8552fd 100644 --- a/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py +++ b/tensorflow/contrib/tensorrt/test/tf_trt_integration_test_base.py @@ -70,6 +70,8 @@ class GraphState(object): def OptimizerDisabledRewriterConfig(): """Returns a RewriterConfig with all default Grappler optimizers disabled.""" rewriter_config = rewriter_config_pb2.RewriterConfig() + + # Turn off all default Grappler optimizers. off = rewriter_config_pb2.RewriterConfig.OFF rewriter_config.layout_optimizer = off rewriter_config.constant_folding = off @@ -86,6 +88,10 @@ def OptimizerDisabledRewriterConfig(): rewriter_config_pb2.RewriterConfig.NO_MEM_OPT) rewriter_config.pin_to_host_optimization = off rewriter_config.auto_parallel.enable = False + + # Run only once for each enabled optimizer. + rewriter_config.meta_optimizer_iterations = ( + rewriter_config_pb2.RewriterConfig.ONE) return rewriter_config -- GitLab From dc45615483758ffc5889d7cb61537634ce925c78 Mon Sep 17 00:00:00 2001 From: Zhenyu Tan Date: Tue, 20 Nov 2018 16:33:58 -0800 Subject: [PATCH 165/672] Internal Cleanup. PiperOrigin-RevId: 222326402 --- tensorflow/python/ops/linalg_ops.py | 73 ++++++++++++++++++- .../api/golden/v2/tensorflow.linalg.pbtxt | 2 +- .../tools/api/golden/v2/tensorflow.pbtxt | 2 +- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/ops/linalg_ops.py b/tensorflow/python/ops/linalg_ops.py index bbccc7e036..1a9e7112b4 100644 --- a/tensorflow/python/ops/linalg_ops.py +++ b/tensorflow/python/ops/linalg_ops.py @@ -423,7 +423,78 @@ def svd(tensor, full_matrices=False, compute_uv=True, name=None): # pylint: disable=redefined-builtin -@tf_export('norm', 'linalg.norm') +@tf_export('norm', 'linalg.norm', v1=[]) +def norm_v2(tensor, + ord='euclidean', + axis=None, + keepdims=None, + name=None): + r"""Computes the norm of vectors, matrices, and tensors. + + This function can compute several different vector norms (the 1-norm, the + Euclidean or 2-norm, the inf-norm, and in general the p-norm for p > 0) and + matrix norms (Frobenius, 1-norm, 2-norm and inf-norm). + + Args: + tensor: `Tensor` of types `float32`, `float64`, `complex64`, `complex128` + ord: Order of the norm. Supported values are 'fro', 'euclidean', + `1`, `2`, `np.inf` and any positive real number yielding the corresponding + p-norm. Default is 'euclidean' which is equivalent to Frobenius norm if + `tensor` is a matrix and equivalent to 2-norm for vectors. + Some restrictions apply: + a) The Frobenius norm `fro` is not defined for vectors, + b) If axis is a 2-tuple (matrix norm), only 'euclidean', 'fro', `1`, + `2`, `np.inf` are supported. + See the description of `axis` on how to compute norms for a batch of + vectors or matrices stored in a tensor. + axis: If `axis` is `None` (the default), the input is considered a vector + and a single vector norm is computed over the entire set of values in the + tensor, i.e. `norm(tensor, ord=ord)` is equivalent to + `norm(reshape(tensor, [-1]), ord=ord)`. + If `axis` is a Python integer, the input is considered a batch of vectors, + and `axis` determines the axis in `tensor` over which to compute vector + norms. + If `axis` is a 2-tuple of Python integers it is considered a batch of + matrices and `axis` determines the axes in `tensor` over which to compute + a matrix norm. + Negative indices are supported. Example: If you are passing a tensor that + can be either a matrix or a batch of matrices at runtime, pass + `axis=[-2,-1]` instead of `axis=None` to make sure that matrix norms are + computed. + keepdims: If True, the axis indicated in `axis` are kept with size 1. + Otherwise, the dimensions in `axis` are removed from the output shape. + name: The name of the op. + + Returns: + output: A `Tensor` of the same type as tensor, containing the vector or + matrix norms. If `keepdims` is True then the rank of output is equal to + the rank of `tensor`. Otherwise, if `axis` is none the output is a scalar, + if `axis` is an integer, the rank of `output` is one less than the rank + of `tensor`, if `axis` is a 2-tuple the rank of `output` is two less + than the rank of `tensor`. + + Raises: + ValueError: If `ord` or `axis` is invalid. + + @compatibility(numpy) + Mostly equivalent to numpy.linalg.norm. + Not supported: ord <= 0, 2-norm for matrices, nuclear norm. + Other differences: + a) If axis is `None`, treats the flattened `tensor` as a vector + regardless of rank. + b) Explicitly supports 'euclidean' norm as the default, including for + higher order tensors. + @end_compatibility + """ + return norm(tensor=tensor, + ord=ord, + axis=axis, + keepdims=keepdims, + name=name) + + +# pylint: disable=redefined-builtin +@tf_export(v1=['norm', 'linalg.norm']) @deprecation.deprecated_args( None, 'keep_dims is deprecated, use keepdims instead', 'keep_dims') def norm(tensor, diff --git a/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt index 1a4098d121..d8259aa775 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt @@ -142,7 +142,7 @@ tf_module { } member_method { name: "norm" - argspec: "args=[\'tensor\', \'ord\', \'axis\', \'keepdims\', \'name\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'euclidean\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'tensor\', \'ord\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'euclidean\', \'None\', \'None\', \'None\'], " } member_method { name: "qr" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 1711348ec3..ec2d72290e 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -854,7 +854,7 @@ tf_module { } member_method { name: "norm" - argspec: "args=[\'tensor\', \'ord\', \'axis\', \'keepdims\', \'name\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'euclidean\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'tensor\', \'ord\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'euclidean\', \'None\', \'None\', \'None\'], " } member_method { name: "not_equal" -- GitLab From 4da08f347b444fa60b2327a15449a37740871224 Mon Sep 17 00:00:00 2001 From: Zhenyu Tan Date: Tue, 20 Nov 2018 16:54:28 -0800 Subject: [PATCH 166/672] Implement Keras V2 FTRL optimization. PiperOrigin-RevId: 222329163 --- tensorflow/python/keras/optimizer_v2/BUILD | 20 + tensorflow/python/keras/optimizer_v2/ftrl.py | 207 +++++++++ .../python/keras/optimizer_v2/ftrl_test.py | 426 ++++++++++++++++++ 3 files changed, 653 insertions(+) create mode 100644 tensorflow/python/keras/optimizer_v2/ftrl.py create mode 100644 tensorflow/python/keras/optimizer_v2/ftrl_test.py diff --git a/tensorflow/python/keras/optimizer_v2/BUILD b/tensorflow/python/keras/optimizer_v2/BUILD index 7defc7d308..6b805781f0 100644 --- a/tensorflow/python/keras/optimizer_v2/BUILD +++ b/tensorflow/python/keras/optimizer_v2/BUILD @@ -17,6 +17,7 @@ py_library( "adagrad.py", "adam.py", "adamax.py", + "ftrl.py", "gradient_descent.py", "nadam.py", "optimizer_v2.py", @@ -112,6 +113,25 @@ cuda_py_test( shard_count = 4, ) +cuda_py_test( + name = "ftrl_test", + size = "medium", + srcs = ["ftrl_test.py"], + additional_deps = [ + ":optimizer_v2", + "//tensorflow/python:client_testlib", + "//tensorflow/python:embedding_ops", + "//tensorflow/python:platform_test", + "//tensorflow/python:framework", + "//tensorflow/python:math_ops", + "//tensorflow/python:resource_variable_ops", + "//tensorflow/python:resources", + "//tensorflow/python:variables", + "//tensorflow/python/eager:context", + ], + shard_count = 4, +) + cuda_py_test( name = "gradient_descent_test", size = "medium", diff --git a/tensorflow/python/keras/optimizer_v2/ftrl.py b/tensorflow/python/keras/optimizer_v2/ftrl.py new file mode 100644 index 0000000000..2faf65eab3 --- /dev/null +++ b/tensorflow/python/keras/optimizer_v2/ftrl.py @@ -0,0 +1,207 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Ftrl-proximal for TensorFlow.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.keras.optimizer_v2 import optimizer_v2 +from tensorflow.python.ops import init_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.training import training_ops + + +class Ftrl(optimizer_v2.OptimizerV2): + """Optimizer that implements the FTRL algorithm. + + See this [paper]( + https://www.eecs.tufts.edu/~dsculley/papers/ad-click-prediction.pdf). + This version has support for both online L2 (the L2 penalty given in the paper + above) and shrinkage-type L2 (which is the addition of an L2 penalty to the + loss function). + """ + + def __init__(self, + learning_rate, + learning_rate_power=-0.5, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0, + name='Ftrl', + l2_shrinkage_regularization_strength=0.0): + r"""Construct a new FTRL optimizer. + + Args: + learning_rate: A float value or a constant float `Tensor`. + learning_rate_power: A float value, must be less or equal to zero. + Controls how the learning rate decreases during training. Use zero for + a fixed learning rate. + initial_accumulator_value: The starting value for accumulators. + Only zero or positive values are allowed. + l1_regularization_strength: A float value, must be greater than or + equal to zero. + l2_regularization_strength: A float value, must be greater than or + equal to zero. + name: Optional name prefix for the operations created when applying + gradients. Defaults to "Ftrl". + l2_shrinkage_regularization_strength: A float value, must be greater than + or equal to zero. This differs from L2 above in that the L2 above is a + stabilization penalty, whereas this L2 shrinkage is a magnitude penalty. + The FTRL formulation can be written as: + w_{t+1} = argmin_w(\hat{g}_{1:t}w + L1*||w||_1 + L2*||w||_2^2), where + \hat{g} = g + (2*L2_shrinkage*w), and g is the gradient of the loss + function w.r.t. the weights w. + Specifically, in the absence of L1 regularization, it is equivalent to + the following update rule: + w_{t+1} = w_t - lr_t / (1 + 2*L2*lr_t) * g_t - + 2*L2_shrinkage*lr_t / (1 + 2*L2*lr_t) * w_t + where lr_t is the learning rate at t. + When input is sparse shrinkage will only happen on the active weights. + + Raises: + ValueError: If one of the arguments is invalid. + + References + See [paper] + (https://www.eecs.tufts.edu/~dsculley/papers/ad-click-prediction.pdf) + """ + super(Ftrl, self).__init__(name) + + if initial_accumulator_value < 0.0: + raise ValueError( + 'initial_accumulator_value %f needs to be positive or zero' % + initial_accumulator_value) + if learning_rate_power > 0.0: + raise ValueError('learning_rate_power %f needs to be negative or zero' % + learning_rate_power) + if l1_regularization_strength < 0.0: + raise ValueError( + 'l1_regularization_strength %f needs to be positive or zero' % + l1_regularization_strength) + if l2_regularization_strength < 0.0: + raise ValueError( + 'l2_regularization_strength %f needs to be positive or zero' % + l2_regularization_strength) + if l2_shrinkage_regularization_strength < 0.0: + raise ValueError( + 'l2_shrinkage_regularization_strength %f needs to be positive' + ' or zero' % l2_shrinkage_regularization_strength) + + self._set_hyper('learning_rate', learning_rate) + self._set_hyper('learning_rate_power', learning_rate_power) + self._set_hyper('l1_regularization_strength', l1_regularization_strength) + self._set_hyper('l2_regularization_strength', l2_regularization_strength) + self._initial_accumulator_value = initial_accumulator_value + self._l2_shrinkage_regularization_strength = ( + l2_shrinkage_regularization_strength) + + def _create_slots(self, var_list): + # Create the "accum" and "linear" slots. + for var in var_list: + dtype = var.dtype.base_dtype + init = init_ops.constant_initializer( + self._initial_accumulator_value, dtype=dtype) + self.add_slot(var, 'accumulator', init) + self.add_slot(var, 'linear') + + def _resource_apply_dense(self, grad, var): + var_dtype = var.dtype.base_dtype + learning_rate = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) + learning_rate_power = math_ops.cast( + self._get_hyper('learning_rate_power'), var_dtype) + l1_regularization_strength = math_ops.cast( + self._get_hyper('l1_regularization_strength'), var_dtype) + l2_regularization_strength = math_ops.cast( + self._get_hyper('l2_regularization_strength'), var_dtype) + accum = self.get_slot(var, 'accumulator') + linear = self.get_slot(var, 'linear') + if self._l2_shrinkage_regularization_strength <= 0.0: + return training_ops.resource_apply_ftrl( + var.handle, + accum.handle, + linear.handle, + grad, + learning_rate, + l1_regularization_strength, + l2_regularization_strength, + learning_rate_power, + use_locking=self._use_locking) + else: + return training_ops.resource_apply_ftrl_v2( + var.handle, + accum.handle, + linear.handle, + grad, + learning_rate, + l1_regularization_strength, + l2_regularization_strength, + math_ops.cast(self._l2_shrinkage_regularization_strength, var_dtype), + learning_rate_power, + use_locking=self._use_locking) + + def _resource_apply_sparse(self, grad, var, indices): + var_dtype = var.dtype.base_dtype + learning_rate = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) + learning_rate_power = math_ops.cast( + self._get_hyper('learning_rate_power'), var_dtype) + l1_regularization_strength = math_ops.cast( + self._get_hyper('l1_regularization_strength'), var_dtype) + l2_regularization_strength = math_ops.cast( + self._get_hyper('l2_regularization_strength'), var_dtype) + accum = self.get_slot(var, 'accumulator') + linear = self.get_slot(var, 'linear') + if self._l2_shrinkage_regularization_strength <= 0.0: + return training_ops.resource_sparse_apply_ftrl( + var.handle, + accum.handle, + linear.handle, + grad, + indices, + learning_rate, + l1_regularization_strength, + l2_regularization_strength, + learning_rate_power, + use_locking=self._use_locking) + else: + return training_ops.resource_sparse_apply_ftrl_v2( + var.handle, + accum.handle, + linear.handle, + grad, + indices, + learning_rate, + l1_regularization_strength, + l2_regularization_strength, + math_ops.cast(self._l2_shrinkage_regularization_strength, var_dtype), + learning_rate_power, + use_locking=self._use_locking) + + def get_config(self): + config = super(Ftrl, self).get_config() + config.update({ + 'learning_rate': + self._serialize_hyperparameter('learning_rate'), + 'initial_accumulator_value': + self._initial_accumulator_value, + 'learning_rate_power': + self._serialize_hyperparameter('learning_rate_power'), + 'l1_regularization_strength': + self._serializer_hyperparameter('l1_regularization_strength'), + 'l2_regularization_strength': + self._serializer_hyperparameter('l2_regularization_strength'), + 'l2_shrinkage_regularization_strength': + self._l2_shrinkage_regularization_strength, + }) + return config diff --git a/tensorflow/python/keras/optimizer_v2/ftrl_test.py b/tensorflow/python/keras/optimizer_v2/ftrl_test.py new file mode 100644 index 0000000000..c14cf75c26 --- /dev/null +++ b/tensorflow/python/keras/optimizer_v2/ftrl_test.py @@ -0,0 +1,426 @@ +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== +"""Functional tests for Ftrl operations.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.keras.optimizer_v2 import ftrl +from tensorflow.python.ops import embedding_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import resource_variable_ops +from tensorflow.python.ops import variables +from tensorflow.python.platform import test +from tensorflow.python.training import adagrad +from tensorflow.python.training import gradient_descent + + +class FtrlOptimizerTest(test.TestCase): + + def doTestFtrlwithoutRegularization(self, use_resource=False): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + if use_resource: + var0 = resource_variable_ops.ResourceVariable([0.0, 0.0], dtype=dtype) + var1 = resource_variable_ops.ResourceVariable([0.0, 0.0], dtype=dtype) + else: + var0 = variables.Variable([0.0, 0.0], dtype=dtype) + var1 = variables.Variable([0.0, 0.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.02], dtype=dtype) + opt = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllClose([0.0, 0.0], v0_val) + self.assertAllClose([0.0, 0.0], v1_val) + + # Run 3 steps FTRL + for _ in range(3): + update.run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType( + np.array([-2.60260963, -4.29698515]), v0_val) + self.assertAllCloseAccordingToType( + np.array([-0.28432083, -0.56694895]), v1_val) + + def testFtrlWithoutRegularization(self): + self.doTestFtrlwithoutRegularization(use_resource=False) + + def testResourceFtrlWithoutRegularization(self): + self.doTestFtrlwithoutRegularization(use_resource=True) + + def testFtrlwithoutRegularization2(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + var0 = variables.Variable([1.0, 2.0], dtype=dtype) + var1 = variables.Variable([4.0, 3.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.02], dtype=dtype) + + opt = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) + self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) + + # Run 3 steps FTRL + for _ in range(3): + update.run() + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType( + np.array([-2.55607247, -3.98729396]), v0_val) + self.assertAllCloseAccordingToType( + np.array([-0.28232238, -0.56096673]), v1_val) + + def testMinimizeSparseResourceVariable(self): + for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: + with self.cached_session(): + var0 = resource_variable_ops.ResourceVariable([[1.0, 2.0]], dtype=dtype) + x = constant_op.constant([[4.0], [5.0]], dtype=dtype) + pred = math_ops.matmul(embedding_ops.embedding_lookup([var0], [0]), x) + loss = pred * pred + sgd_op = ftrl.Ftrl(1.0).minimize(loss, var_list=[var0]) + variables.global_variables_initializer().run() + # Fetch params to validate initial values + self.assertAllCloseAccordingToType([[1.0, 2.0]], self.evaluate(var0)) + # Run 1 step of sgd + sgd_op.run() + # Validate updated params + self.assertAllCloseAccordingToType([[0, 1]], + self.evaluate(var0), + atol=0.01) + + def testFtrlWithL1(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + var0 = variables.Variable([1.0, 2.0], dtype=dtype) + var1 = variables.Variable([4.0, 3.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.02], dtype=dtype) + + opt = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.001, + l2_regularization_strength=0.0) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) + self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) + + # Run 10 steps FTRL + for _ in range(10): + update.run() + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType( + np.array([-7.66718769, -10.91273689]), v0_val) + self.assertAllCloseAccordingToType( + np.array([-0.93460727, -1.86147261]), v1_val) + + def testFtrlWithL1_L2(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + var0 = variables.Variable([1.0, 2.0], dtype=dtype) + var1 = variables.Variable([4.0, 3.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.02], dtype=dtype) + + opt = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.001, + l2_regularization_strength=2.0) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) + self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) + + # Run 10 steps FTRL + for _ in range(10): + update.run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType( + np.array([-0.24059935, -0.46829352]), v0_val) + self.assertAllCloseAccordingToType( + np.array([-0.02406147, -0.04830509]), v1_val) + + def testFtrlWithL1_L2_L2Shrinkage(self): + """Test the new FTRL op with support for l2 shrinkage. + + The addition of this parameter which places a constant pressure on weights + towards the origin causes the gradient descent trajectory to differ. The + weights will tend to have smaller magnitudes with this parameter set. + """ + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + var0 = variables.Variable([1.0, 2.0], dtype=dtype) + var1 = variables.Variable([4.0, 3.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.02], dtype=dtype) + + opt = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.001, + l2_regularization_strength=2.0, + l2_shrinkage_regularization_strength=0.1) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) + self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) + + # Run 10 steps FTRL + for _ in range(10): + update.run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType( + np.array([-0.22578995, -0.44345796]), v0_val) + self.assertAllCloseAccordingToType( + np.array([-0.14378493, -0.13229476]), v1_val) + + def testFtrlWithL1_L2_L2ShrinkageSparse(self): + """Tests the new FTRL op with support for l2 shrinkage on sparse grads.""" + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + var0 = variables.Variable([[1.0], [2.0]], dtype=dtype) + var1 = variables.Variable([[4.0], [3.0]], dtype=dtype) + grads0 = ops.IndexedSlices( + constant_op.constant([0.1], shape=[1, 1], dtype=dtype), + constant_op.constant([0]), constant_op.constant([2, 1])) + grads1 = ops.IndexedSlices( + constant_op.constant([0.02], shape=[1, 1], dtype=dtype), + constant_op.constant([1]), constant_op.constant([2, 1])) + + opt = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.001, + l2_regularization_strength=2.0, + l2_shrinkage_regularization_strength=0.1) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([[1.0], [2.0]], v0_val) + self.assertAllCloseAccordingToType([[4.0], [3.0]], v1_val) + + # Run 10 steps FTRL + for _ in range(10): + update.run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([[-0.22578995], [2.]], v0_val) + self.assertAllCloseAccordingToType([[4.], [-0.13229476]], v1_val) + + def testFtrlWithL2ShrinkageDoesNotChangeLrSchedule(self): + """Verifies that l2 shrinkage in FTRL does not change lr schedule.""" + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session() as sess: + var0 = variables.Variable([1.0, 2.0], dtype=dtype) + var1 = variables.Variable([1.0, 2.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.1, 0.2], dtype=dtype) + + opt0 = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.001, + l2_regularization_strength=2.0, + l2_shrinkage_regularization_strength=0.1) + opt1 = ftrl.Ftrl( + 3.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.001, + l2_regularization_strength=2.0) + update0 = opt0.apply_gradients([(grads0, var0)]) + update1 = opt1.apply_gradients([(grads1, var1)]) + variables.global_variables_initializer().run() + + v0_val, v1_val = sess.run([var0, var1]) + self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) + self.assertAllCloseAccordingToType([1.0, 2.0], v1_val) + + # Run 10 steps FTRL + for _ in range(10): + update0.run() + update1.run() + + v0_val, v1_val = sess.run([var0, var1]) + # var0 is experiencing L2 shrinkage so it should be smaller than var1 + # in magnitude. + self.assertTrue((v0_val**2 < v1_val**2).all()) + accum0 = sess.run(opt0.get_slot(var0, "accumulator")) + accum1 = sess.run(opt1.get_slot(var1, "accumulator")) + # L2 shrinkage should not change how we update grad accumulator. + self.assertAllCloseAccordingToType(accum0, accum1) + + def applyOptimizer(self, opt, dtype, steps=5, is_sparse=False): + if is_sparse: + var0 = variables.Variable([[0.0], [0.0]], dtype=dtype) + var1 = variables.Variable([[0.0], [0.0]], dtype=dtype) + grads0 = ops.IndexedSlices( + constant_op.constant([0.1], shape=[1, 1], dtype=dtype), + constant_op.constant([0]), constant_op.constant([2, 1])) + grads1 = ops.IndexedSlices( + constant_op.constant([0.02], shape=[1, 1], dtype=dtype), + constant_op.constant([1]), constant_op.constant([2, 1])) + else: + var0 = variables.Variable([0.0, 0.0], dtype=dtype) + var1 = variables.Variable([0.0, 0.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.2], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.02], dtype=dtype) + + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + sess = ops.get_default_session() + v0_val, v1_val = sess.run([var0, var1]) + if is_sparse: + self.assertAllCloseAccordingToType([[0.0], [0.0]], v0_val) + self.assertAllCloseAccordingToType([[0.0], [0.0]], v1_val) + else: + self.assertAllCloseAccordingToType([0.0, 0.0], v0_val) + self.assertAllCloseAccordingToType([0.0, 0.0], v1_val) + + # Run Ftrl for a few steps + for _ in range(steps): + update.run() + + v0_val, v1_val = sess.run([var0, var1]) + return v0_val, v1_val + + # When variables are initialized with Zero, FTRL-Proximal has two properties: + # 1. Without L1&L2 but with fixed learning rate, FTRL-Proximal is identical + # with GradientDescent. + # 2. Without L1&L2 but with adaptive learning rate, FTRL-Proximal is identical + # with Adagrad. + # So, basing on these two properties, we test if our implementation of + # FTRL-Proximal performs same updates as Adagrad or GradientDescent. + def testEquivAdagradwithoutRegularization(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session(): + val0, val1 = self.applyOptimizer( + ftrl.Ftrl( + 3.0, + # Adagrad learning rate + learning_rate_power=-0.5, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0), + dtype) + + with self.cached_session(): + val2, val3 = self.applyOptimizer( + adagrad.AdagradOptimizer(3.0, initial_accumulator_value=0.1), dtype) + + self.assertAllCloseAccordingToType(val0, val2) + self.assertAllCloseAccordingToType(val1, val3) + + def testEquivSparseAdagradwithoutRegularization(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session(): + val0, val1 = self.applyOptimizer( + ftrl.Ftrl( + 3.0, + # Adagrad learning rate + learning_rate_power=-0.5, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0), + dtype, + is_sparse=True) + + with self.cached_session(): + val2, val3 = self.applyOptimizer( + adagrad.AdagradOptimizer(3.0, initial_accumulator_value=0.1), + dtype, + is_sparse=True) + + self.assertAllCloseAccordingToType(val0, val2) + self.assertAllCloseAccordingToType(val1, val3) + + def testEquivSparseGradientDescentwithoutRegularization(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session(): + val0, val1 = self.applyOptimizer( + ftrl.Ftrl( + 3.0, + # Fixed learning rate + learning_rate_power=-0.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0), + dtype, + is_sparse=True) + + with self.cached_session(): + val2, val3 = self.applyOptimizer( + gradient_descent.GradientDescentOptimizer(3.0), + dtype, + is_sparse=True) + + self.assertAllCloseAccordingToType(val0, val2) + self.assertAllCloseAccordingToType(val1, val3) + + def testEquivGradientDescentwithoutRegularization(self): + for dtype in [dtypes.half, dtypes.float32]: + with self.cached_session(): + val0, val1 = self.applyOptimizer( + ftrl.Ftrl( + 3.0, + # Fixed learning rate + learning_rate_power=-0.0, + initial_accumulator_value=0.1, + l1_regularization_strength=0.0, + l2_regularization_strength=0.0), + dtype) + + with self.cached_session(): + val2, val3 = self.applyOptimizer( + gradient_descent.GradientDescentOptimizer(3.0), dtype) + + self.assertAllCloseAccordingToType(val0, val2) + self.assertAllCloseAccordingToType(val1, val3) + + +if __name__ == "__main__": + test.main() -- GitLab From 0dbafc2eb5b3e5fdfcdb10d69e44c09d61373a08 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 20 Nov 2018 17:05:54 -0800 Subject: [PATCH 167/672] Don't auto-cluster ops producing or consuming DT_VARIANT. PiperOrigin-RevId: 222330733 --- tensorflow/cc/BUILD | 1 + .../compiler/jit/mark_for_compilation_pass.cc | 37 +++++++-- .../jit/mark_for_compilation_pass_test.cc | 76 +++++++++++++++++++ 3 files changed, 106 insertions(+), 8 deletions(-) diff --git a/tensorflow/cc/BUILD b/tensorflow/cc/BUILD index 83353b79f7..a09becc49b 100644 --- a/tensorflow/cc/BUILD +++ b/tensorflow/cc/BUILD @@ -489,6 +489,7 @@ tf_gen_op_wrappers_cc( "image_ops", "io_ops", "linalg_ops", + "list_ops", "logging_ops", "lookup_ops", "manip_ops", diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass.cc b/tensorflow/compiler/jit/mark_for_compilation_pass.cc index 60b962d2e8..25796435a5 100644 --- a/tensorflow/compiler/jit/mark_for_compilation_pass.cc +++ b/tensorflow/compiler/jit/mark_for_compilation_pass.cc @@ -72,6 +72,11 @@ struct OperationFilter { // to resort to a dummy implementation. Currently Assert and CheckNumerics ops // have dummy XLA implementations. bool allow_dummy_ops; + + // Whether ops that produce or consume DT_VARIANT values are allowed. We + // don't auto-cluster these ops because we don't yet support live-in or + // live-out DT_VARIANT values. + bool allow_ops_producing_or_consuming_variant; }; bool IsDummyImplOp(absl::string_view op_name) { @@ -84,6 +89,12 @@ bool IsStatefulRandomOp(absl::string_view op_name) { op_name == "TruncatedNormal"; } +bool OpProducesOrConsumesVariant(const Node& node) { + auto is_variant = [](DataType dtype) { return dtype == DT_VARIANT; }; + return absl::c_any_of(node.input_types(), is_variant) || + absl::c_any_of(node.output_types(), is_variant); +} + bool HasXLAKernel(const Node& node, const DeviceType& jit_device_type) { // There is a SymbolicGradient kernel on the XLA_JIT device, but the gradient // is really a kind of function call and will be handled by @@ -246,6 +257,10 @@ bool IsCompilableCall(const NodeDef& call_def, if (!op_filter.allow_dummy_ops && IsDummyImplOp(node->type_string())) { return false; } + if (!op_filter.allow_ops_producing_or_consuming_variant && + OpProducesOrConsumesVariant(*node)) { + return false; + } if (!HasXLAKernel(*node, jit_device_type) && !IsCompilableCall(node->def(), jit_device_type, op_filter, depth + 1, lib_runtime)) { @@ -470,16 +485,15 @@ Status FindCompilationCandidates( XlaOpRegistry::GetCompilationDevice(device_type.type(), ®istration)); DeviceType jit_device_type(registration->compilation_device_name); + bool always_auto_cluster = registration->autoclustering_policy == + XlaOpRegistry::AutoclusteringPolicy::kAlways; + OperationFilter op_filter; op_filter.allow_resource_ops = registration->compile_resource_ops; - op_filter.allow_stateful_rng_ops = - (registration->autoclustering_policy == - XlaOpRegistry::AutoclusteringPolicy::kAlways); - op_filter.allow_control_trigger = - (registration->autoclustering_policy == - XlaOpRegistry::AutoclusteringPolicy::kAlways); - op_filter.allow_dummy_ops = (registration->autoclustering_policy == - XlaOpRegistry::AutoclusteringPolicy::kAlways); + op_filter.allow_stateful_rng_ops = always_auto_cluster; + op_filter.allow_control_trigger = always_auto_cluster; + op_filter.allow_dummy_ops = always_auto_cluster; + op_filter.allow_ops_producing_or_consuming_variant = always_auto_cluster; if (!HasXLAKernel(*node, jit_device_type) && !IsCompilableCall(node->def(), jit_device_type, op_filter, 0, @@ -503,6 +517,12 @@ Status FindCompilationCandidates( << node->type_string() << ")"; continue; } + if (!op_filter.allow_ops_producing_or_consuming_variant && + OpProducesOrConsumesVariant(*node)) { + VLOG(2) << "Rejecting " << node->name() + << ": produces or consumes DT_VARIANT"; + continue; + } if (!op_filter.allow_resource_ops && (HasResourceOutput(*node) || IsNonResourceVarResourceOp(*node))) { @@ -639,6 +659,7 @@ bool IsCompilable(FunctionLibraryRuntime* flr, const NodeDef& ndef) { op_filter.allow_stateful_rng_ops = true; op_filter.allow_control_trigger = true; op_filter.allow_dummy_ops = true; + op_filter.allow_ops_producing_or_consuming_variant = true; return IsCompilableCall(ndef, jit_device_type, op_filter, 0, flr); } diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc b/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc index 24d78c0772..bf2c5508ea 100644 --- a/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc +++ b/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc @@ -22,6 +22,7 @@ limitations under the License. #include "tensorflow/cc/ops/array_ops.h" #include "tensorflow/cc/ops/control_flow_ops_internal.h" #include "tensorflow/cc/ops/function_ops.h" +#include "tensorflow/cc/ops/list_ops.h" #include "tensorflow/cc/ops/resource_variable_ops.h" #include "tensorflow/cc/ops/sendrecv_ops.h" #include "tensorflow/cc/ops/standard_ops.h" @@ -1147,5 +1148,80 @@ TEST(XlaCompilationTest, DontAutoClusterDummyOps) { EXPECT_EQ(clusters["test/check"], ""); } +TEST(XlaCompilationTest, DontAutoClusterOpsProducingVariant) { + Scope root = Scope::NewRootScope().ExitOnError(); + Output a = ops::Placeholder(root.WithOpName("test/a"), DT_INT64); + Output b = ops::Placeholder(root.WithOpName("test/b"), DT_INT64); + + Output cast_a = ops::Cast(root.WithOpName("test/cast_a"), a, DT_INT32); + Output cast_b = ops::Cast(root.WithOpName("test/cast_b"), b, DT_INT32); + + Output tensor_list_reserve = ops::TensorListReserve( + root.WithOpName("test/tensor_list_reserve"), cast_a, cast_b, DT_FLOAT); + + std::unique_ptr graph(new Graph(OpRegistry::Global())); + TF_ASSERT_OK(root.ToGraph(graph.get())); + + TF_ASSERT_OK(MarkForCompilationPassTestHelper::MarkForCompilation(&graph)); + + std::unordered_map clusters = GetClusters(*graph); + EXPECT_EQ(clusters["test/tensor_list_reserve"], ""); +} + +TEST(XlaCompilationTest, DontAutoClusterOpsConsumingVariant) { + Scope root = Scope::NewRootScope().ExitOnError(); + Output dummy_input = + ops::Placeholder(root.WithOpName("test/dummy_input"), DT_INT64); + Output variant_input = + ops::Placeholder(root.WithOpName("test/variant_input"), DT_VARIANT); + + // Create one more node so that we don't avoid creating a cluster solely + // because it would be trivial. + Output dummy_cast = + ops::Cast(root.WithOpName("test/dummy_cast"), dummy_input, DT_INT32); + + Output tensor_list_element_shape = ops::TensorListElementShape( + root.WithOpName("test/tensor_list_element_shape"), variant_input, + DT_INT32); + + root.graph()->AddControlEdge(dummy_cast.node(), + tensor_list_element_shape.node()); + + std::unique_ptr graph(new Graph(OpRegistry::Global())); + TF_ASSERT_OK(root.ToGraph(graph.get())); + + TF_ASSERT_OK(MarkForCompilationPassTestHelper::MarkForCompilation(&graph)); + + std::unordered_map clusters = GetClusters(*graph); + EXPECT_EQ(clusters["test/tensor_list_element_shape"], ""); +} + +TEST(XlaCompilationTest, ClusterOpsProducingVariantIfOnXlaDevice) { + Scope root = Scope::NewRootScope().ExitOnError(); + Output a = ops::Placeholder(root.WithOpName("test/a"), DT_INT64); + Output b = ops::Placeholder(root.WithOpName("test/b"), DT_INT64); + + Output cast_a = ops::Cast(root.WithOpName("test/cast_a"), a, DT_INT32); + Output cast_b = ops::Cast(root.WithOpName("test/cast_b"), b, DT_INT32); + + Output tensor_list_reserve = ops::TensorListReserve( + root.WithOpName("test/tensor_list_reserve"), cast_a, cast_b, DT_FLOAT); + + std::unique_ptr graph(new Graph(OpRegistry::Global())); + TF_ASSERT_OK(root.ToGraph(graph.get())); + + string xla_cpu_device = "/job:worker/replica:0/task:0/device:XLA_CPU:0"; + for (Node* n : graph->nodes()) { + if (absl::StartsWith(n->name(), /*prefix=*/"test/")) { + n->set_assigned_device_name(xla_cpu_device); + } + } + + TF_ASSERT_OK(MarkForCompilationPassTestHelper::MarkForCompilation(&graph)); + + std::unordered_map clusters = GetClusters(*graph); + EXPECT_NE(clusters["test/tensor_list_reserve"], ""); +} + } // namespace } // namespace tensorflow -- GitLab From d26d2aa067455fa6ba2b013fb133f158ed488aab Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 17:08:18 -0800 Subject: [PATCH 168/672] Allow installation of custom delegates during initialization PiperOrigin-RevId: 222331040 --- .../lite/tools/benchmark/benchmark_tflite_model.cc | 9 +++++---- tensorflow/lite/tools/benchmark/benchmark_tflite_model.h | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tensorflow/lite/tools/benchmark/benchmark_tflite_model.cc b/tensorflow/lite/tools/benchmark/benchmark_tflite_model.cc index 777d9dde7d..7768b75f76 100644 --- a/tensorflow/lite/tools/benchmark/benchmark_tflite_model.cc +++ b/tensorflow/lite/tools/benchmark/benchmark_tflite_model.cc @@ -181,7 +181,9 @@ bool PopulateInputLayerInfo( return true; } -BenchmarkParams GetDefaultParams() { +} // namespace + +BenchmarkParams BenchmarkTfLiteModel::DefaultParams() { BenchmarkParams default_params = BenchmarkModel::DefaultParams(); default_params.AddParam("graph", BenchmarkParam::Create("")); default_params.AddParam("input_layer", @@ -192,10 +194,8 @@ BenchmarkParams GetDefaultParams() { return default_params; } -} // namespace - BenchmarkTfLiteModel::BenchmarkTfLiteModel() - : BenchmarkTfLiteModel(GetDefaultParams()) {} + : BenchmarkTfLiteModel(DefaultParams()) {} BenchmarkTfLiteModel::BenchmarkTfLiteModel(BenchmarkParams params) : BenchmarkModel(std::move(params)) { @@ -319,6 +319,7 @@ void BenchmarkTfLiteModel::Init() { bool use_nnapi = params_.Get("use_nnapi"); interpreter->UseNNAPI(use_nnapi); + ApplyDelegates(); auto interpreter_inputs = interpreter->inputs(); diff --git a/tensorflow/lite/tools/benchmark/benchmark_tflite_model.h b/tensorflow/lite/tools/benchmark/benchmark_tflite_model.h index 401ab5427d..83599e644d 100644 --- a/tensorflow/lite/tools/benchmark/benchmark_tflite_model.h +++ b/tensorflow/lite/tools/benchmark/benchmark_tflite_model.h @@ -77,11 +77,16 @@ class BenchmarkTfLiteModel : public BenchmarkModel { }; protected: + static BenchmarkParams DefaultParams(); void PrepareInputsAndOutputs() override; - private: + // Allows installation of custom delegates during initialization + virtual void ApplyDelegates() {} + std::unique_ptr model; std::unique_ptr interpreter; + + private: std::vector inputs; ProfilingListener profiling_listener_; GemmlowpProfilingListener gemmlowp_profiling_listener_; -- GitLab From b3e007394680801113f492fa1f5a9784e8502f19 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 17:12:09 -0800 Subject: [PATCH 169/672] Add parallel_iterations argument to pfor and jacobian functions to control the amount of parallelism. PiperOrigin-RevId: 222331433 --- .../ops/parallel_for/control_flow_ops.py | 108 +++++++++++++++--- .../ops/parallel_for/control_flow_ops_test.py | 34 +++++- .../python/ops/parallel_for/gradients.py | 25 ++-- .../python/ops/parallel_for/gradients_test.py | 13 +++ 4 files changed, 155 insertions(+), 25 deletions(-) diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops.py b/tensorflow/python/ops/parallel_for/control_flow_ops.py index ead7ae5478..3c818f3d6c 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops.py @@ -19,14 +19,16 @@ from __future__ import print_function from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import math_ops from tensorflow.python.ops import tensor_array_ops from tensorflow.python.ops.parallel_for.pfor import PFor from tensorflow.python.util import nest -def for_loop(loop_fn, loop_fn_dtypes, iters): +def for_loop(loop_fn, loop_fn_dtypes, iters, parallel_iterations=None): """Runs `loop_fn` `iters` times and stacks the outputs. @@ -39,6 +41,8 @@ def for_loop(loop_fn, loop_fn_dtypes, iters): objects. The shape of these outputs should not depend on the input. loop_fn_dtypes: dtypes for the outputs of loop_fn. iters: Number of iterations for which to run loop_fn. + parallel_iterations: The number of iterations that can be dispatched in + parallel. This knob can be used to control the total memory usage. Returns: Returns a nested structure of stacked output tensor objects with the same @@ -66,11 +70,16 @@ def for_loop(loop_fn, loop_fn_dtypes, iters): outputs.append(ta) return tuple([i + 1] + outputs) + if parallel_iterations is not None: + extra_args = {"parallel_iterations": parallel_iterations} + else: + extra_args = {} ta_list = control_flow_ops.while_loop( - lambda i, *ta: i < iters, while_body, [0] + [ - tensor_array_ops.TensorArray(dtype, iters) - for dtype in flat_loop_fn_dtypes - ])[1:] + lambda i, *ta: i < iters, + while_body, + [0] + [tensor_array_ops.TensorArray(dtype, iters) + for dtype in flat_loop_fn_dtypes], + **extra_args)[1:] # TODO(rachelim): enable this for sparse tensors @@ -79,7 +88,15 @@ def for_loop(loop_fn, loop_fn_dtypes, iters): return nest.pack_sequence_as(loop_fn_dtypes, output) -def pfor(loop_fn, iters): +def _flatten_first_two_dims(x): + """Flattens the first two dimensions of x into a single dimension.""" + old_shape = array_ops.shape(x) + new_shape = array_ops.concat([[old_shape[0] * old_shape[1]], old_shape[2:]], + axis=0) + return array_ops.reshape(x, new_shape) + + +def pfor(loop_fn, iters, parallel_iterations=None): """Equivalent to running `loop_fn` `iters` times and stacking the outputs. `pfor` has functionality similar to `for_loop`, i.e. running `loop_fn` `iters` @@ -99,8 +116,8 @@ def pfor(loop_fn, iters): reads, etc). - Conversion works only on a limited set of kernels for which a converter has been registered. - - loop_fn cannot currently contain control flow operations like - tf.while_loop or tf.cond. + - loop_fn has limited support for control flow operations. tf.cond in + particular is not supported. - `loop_fn` should return nested structure of Tensors or Operations. However if an Operation is returned, it should have zero outputs. - The shape and dtype of `loop_fn` outputs should not depend on the input @@ -109,12 +126,21 @@ def pfor(loop_fn, iters): Args: loop_fn: A function that takes an int32 scalar tf.Tensor object representing the iteration number, and returns a possibly nested structure of Tensor or - Operation objects. + Operation objects. Note that if setting `parallel_iterations` argument to + something other than None, `loop_fn` may be called more than once during + graph construction. So it may need to avoid mutating global state. iters: Number of iterations for which to run loop_fn. + parallel_iterations: A knob to control how many iterations are vectorized + and dispatched in parallel. The default value of None corresponds to + vectorizing all the iterations. If `parallel_iterations` is smaller than + `iters`, then chunks of at most that many iterations are dispatched in + sequence. This knob can be used to control the total memory usage. Returns: Returns a nested structure of stacked tensor objects with the same nested structure as the output of `loop_fn`. + Raises: + ValueError: If parallel_iterations is not None and not an integer > 1. """ existing_ops = set(ops.get_default_graph().get_operations()) with ops.name_scope("loop_body"): @@ -122,9 +148,61 @@ def pfor(loop_fn, iters): loop_fn_outputs = loop_fn(loop_var) new_ops = set(ops.get_default_graph().get_operations()) - existing_ops iters = ops.convert_to_tensor(iters) - with ops.name_scope("pfor"): - converter = PFor(loop_var, iters, new_ops) - outputs = [] - for loop_fn_output in nest.flatten(loop_fn_outputs): - outputs.append(converter.convert(loop_fn_output)) - return nest.pack_sequence_as(loop_fn_outputs, outputs) + if parallel_iterations is not None: + if parallel_iterations < 1: + raise ValueError("parallel_iterations must be None or a positive integer") + if parallel_iterations == 1: + raise ValueError("Found parallel_iterations == 1. Use for_loop instead.") + iters_value = tensor_util.constant_value(iters) + if iters_value is not None and iters_value < parallel_iterations: + parallel_iterations = None + if parallel_iterations is None: + with ops.name_scope("pfor"): + converter = PFor(loop_var, iters, new_ops) + outputs = [] + for loop_fn_output in nest.flatten(loop_fn_outputs): + outputs.append(converter.convert(loop_fn_output)) + return nest.pack_sequence_as(loop_fn_outputs, outputs) + else: + num_tiled_iterations = iters // parallel_iterations + num_remaining_iterations = iters % parallel_iterations + # TODO(agarwal): Avoid calling loop_fn twice. Generate the loop body inside + # a tf.function and extract the graph from there to vectorize it. + with ops.name_scope("pfor_untiled"): + converter = PFor(loop_var, num_remaining_iterations, new_ops) + remaining_outputs = [] + flattened_loop_fn_outputs = nest.flatten(loop_fn_outputs) + for loop_fn_output in flattened_loop_fn_outputs: + remaining_outputs.append(converter.convert(loop_fn_output)) + + with ops.name_scope("pfor_tiled"): + loop_fn_dtypes = [ops.convert_to_tensor(x).dtype + for x in flattened_loop_fn_outputs] + + def tiled_loop_body(j): + offset = j * parallel_iterations + num_remaining_iterations + + def tiled_loop_fn(i): + return nest.flatten(loop_fn(i + offset)) + + return pfor(tiled_loop_fn, parallel_iterations) + + tiled_outputs = for_loop(tiled_loop_body, loop_fn_dtypes, + num_tiled_iterations, parallel_iterations=1) + tiled_outputs = [_flatten_first_two_dims(y) for y in tiled_outputs] + + with ops.name_scope("pfor"): + iters_value = tensor_util.constant_value(iters) + if iters_value is None or iters_value % parallel_iterations: + outputs = control_flow_ops.cond( + math_ops.equal(num_remaining_iterations, 0), + lambda: tiled_outputs, + lambda: [array_ops.concat([x, y], axis=0) + for x, y in zip(remaining_outputs, tiled_outputs)]) + else: + outputs = tiled_outputs + return nest.pack_sequence_as(loop_fn_outputs, nest.flatten(outputs)) + + + + diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py index 7d13014687..4470c0b958 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py @@ -73,9 +73,13 @@ class PForTest(test.TestCase): else: self.assertAllEqual(outputs[i + n], outputs[i]) - def _test_loop_fn(self, loop_fn, iters, loop_fn_dtypes=dtypes.float32): - t1 = pfor_control_flow_ops.pfor(loop_fn, iters=iters) - t2 = pfor_control_flow_ops.for_loop(loop_fn, loop_fn_dtypes, iters=iters) + def _test_loop_fn(self, loop_fn, iters, + loop_fn_dtypes=dtypes.float32, + parallel_iterations=None): + t1 = pfor_control_flow_ops.pfor(loop_fn, iters=iters, + parallel_iterations=parallel_iterations) + t2 = pfor_control_flow_ops.for_loop(loop_fn, loop_fn_dtypes, iters=iters, + parallel_iterations=parallel_iterations) self.run_and_assert_equal(t1, t2) def test_op_conversion_fallback_to_while_loop(self): @@ -96,6 +100,30 @@ class PForTest(test.TestCase): loop_fn, 3, loop_fn_dtypes=[dtypes.float32, dtypes.int32]) flags.FLAGS.op_conversion_fallback_to_while_loop = False + def test_parallel_iterations(self): + for parallel_iterations in [2, 3, 8, 10]: + x = random_ops.random_uniform([8, 3]) + + # pylint: disable=cell-var-from-loop + def loop_fn(i): + return array_ops.gather(x, i) + # pylint: enable=cell-var-from-loop + + self._test_loop_fn(loop_fn, 8, parallel_iterations=parallel_iterations) + self._test_loop_fn(loop_fn, 4 * constant_op.constant(2), + parallel_iterations=parallel_iterations) + + def test_parallel_iterations_zero(self): + with self.assertRaisesRegexp(ValueError, "positive integer"): + pfor_control_flow_ops.pfor(lambda i: 1, 8, parallel_iterations=0) + with self.assertRaisesRegexp(TypeError, "positive integer"): + pfor_control_flow_ops.for_loop(lambda i: 1, dtypes.int32, 8, + parallel_iterations=0) + + def test_parallel_iterations_one(self): + with self.assertRaisesRegexp(ValueError, "Use for_loop instead"): + pfor_control_flow_ops.pfor(lambda i: 1, 8, parallel_iterations=1) + class ArrayTest(PForTest): diff --git a/tensorflow/python/ops/parallel_for/gradients.py b/tensorflow/python/ops/parallel_for/gradients.py index 1f026b3660..3ba1bde347 100644 --- a/tensorflow/python/ops/parallel_for/gradients.py +++ b/tensorflow/python/ops/parallel_for/gradients.py @@ -25,7 +25,7 @@ from tensorflow.python.ops.parallel_for import control_flow_ops from tensorflow.python.util import nest -def jacobian(output, inputs, use_pfor=True): +def jacobian(output, inputs, use_pfor=True, parallel_iterations=None): """Computes jacobian of `output` w.r.t. `inputs`. Args: @@ -33,6 +33,8 @@ def jacobian(output, inputs, use_pfor=True): inputs: A tensor or a nested structure of tensor objects. use_pfor: If true, uses pfor for computing the jacobian. Else uses tf.while_loop. + parallel_iterations: A knob to control how many iterations and dispatched in + parallel. This knob can be used to control the total memory usage. Returns: A tensor or a nested strucutre of tensors with the same structure as @@ -56,10 +58,14 @@ def jacobian(output, inputs, use_pfor=True): output_size = array_ops.shape(output)[0] if use_pfor: - pfor_outputs = control_flow_ops.pfor(loop_fn, output_size) + pfor_outputs = control_flow_ops.pfor( + loop_fn, output_size, parallel_iterations=parallel_iterations) else: pfor_outputs = control_flow_ops.for_loop( - loop_fn, [output.dtype] * len(flat_inputs), output_size) + loop_fn, + [output.dtype] * len(flat_inputs), + output_size, + parallel_iterations=parallel_iterations) for i, out in enumerate(pfor_outputs): if out is not None: @@ -72,7 +78,7 @@ def jacobian(output, inputs, use_pfor=True): return nest.pack_sequence_as(inputs, pfor_outputs) -def batch_jacobian(output, inp, use_pfor=True): +def batch_jacobian(output, inp, use_pfor=True, parallel_iterations=None): """Computes and stacks jacobians of `output[i,...]` w.r.t. `input[i,...]`. e.g. @@ -87,6 +93,8 @@ def batch_jacobian(output, inp, use_pfor=True): inp: A tensor with shape [b, x1, ..., x_m] use_pfor: If true, uses pfor for computing the Jacobian. Else uses a tf.while_loop. + parallel_iterations: A knob to control how many iterations and dispatched in + parallel. This knob can be used to control the total memory usage. Returns: A tensor `t` with shape [b, y_1, ..., y_n, x1, ..., x_m] where `t[i, ...]` @@ -118,10 +126,13 @@ def batch_jacobian(output, inp, use_pfor=True): return gradient_ops.gradients(y, inp)[0] if use_pfor: - pfor_output = control_flow_ops.pfor(loop_fn, output_row_size) + pfor_output = control_flow_ops.pfor(loop_fn, output_row_size, + parallel_iterations=parallel_iterations) else: - pfor_output = control_flow_ops.for_loop(loop_fn, output.dtype, - output_row_size) + pfor_output = control_flow_ops.for_loop( + loop_fn, output.dtype, + output_row_size, + parallel_iterations=parallel_iterations) if pfor_output is None: return None pfor_output = array_ops.reshape(pfor_output, diff --git a/tensorflow/python/ops/parallel_for/gradients_test.py b/tensorflow/python/ops/parallel_for/gradients_test.py index b2be24e110..545c482df8 100644 --- a/tensorflow/python/ops/parallel_for/gradients_test.py +++ b/tensorflow/python/ops/parallel_for/gradients_test.py @@ -416,6 +416,12 @@ class GradientsTest(test.TestCase): self.assertAllClose(ans, pfor_value) self.assertAllClose(ans, while_value) + def test_jacobian_parallel_iterations(self): + x = constant_op.constant([[1., 2], [3, 4]]) + y = math_ops.matmul(x, x) + self.assertAllClose(gradients.jacobian(y, x, parallel_iterations=2), + gradients.jacobian(y, x, parallel_iterations=3)) + def test_batch_jacobian_bad_shapes(self): x = random_ops.random_uniform([2, 2]) y = random_ops.random_uniform([3, 2]) @@ -459,6 +465,13 @@ class GradientsTest(test.TestCase): self.assertAllClose(ans, pfor_value) self.assertAllClose(ans, while_value) + def test_batch_jacobian_parallel_iterations(self): + x = constant_op.constant([[1., 2], [3, 4]]) + w = constant_op.constant([[1., 2, 3, 4], [5, 6, 7, 8]]) + y = math_ops.matmul(x, w) + self.assertAllClose(gradients.batch_jacobian(y, x, parallel_iterations=2), + gradients.batch_jacobian(y, x, parallel_iterations=3)) + def test_fc_batch_jacobian(self): pfor_jacobian, while_jacobian = create_fc_batch_jacobian(8, 4, 2) self.run_and_assert_equal(pfor_jacobian, while_jacobian) -- GitLab From afca7030074c869313fcf75cd84fc7ec3dc99fec Mon Sep 17 00:00:00 2001 From: Karim Nosir Date: Tue, 20 Nov 2018 17:19:16 -0800 Subject: [PATCH 170/672] Add MirrorPad op to the schema. PiperOrigin-RevId: 222332230 --- tensorflow/lite/builtin_ops.h | 1 + tensorflow/lite/c/builtin_op_data.h | 10 ++ .../lite/core/api/flatbuffer_conversions.cc | 13 ++ .../writer/option_writer_generator.cc | 2 + tensorflow/lite/nnapi_delegate.cc | 1 + tensorflow/lite/schema/schema.fbs | 13 ++ tensorflow/lite/schema/schema_generated.h | 170 +++++++++++++++++- 7 files changed, 204 insertions(+), 6 deletions(-) diff --git a/tensorflow/lite/builtin_ops.h b/tensorflow/lite/builtin_ops.h index a3843deb00..2300ff4ed2 100644 --- a/tensorflow/lite/builtin_ops.h +++ b/tensorflow/lite/builtin_ops.h @@ -125,6 +125,7 @@ typedef enum { kTfLiteBuiltinResizeNearestNeighbor = 97, kTfLiteBuiltinLeakyRelu = 98, kTfLiteBuiltinSquaredDifference = 99, + kTfLiteBuiltinMirrorPad = 100, } TfLiteBuiltinOperator; #ifdef __cplusplus diff --git a/tensorflow/lite/c/builtin_op_data.h b/tensorflow/lite/c/builtin_op_data.h index 5a2f1fa4b1..33aaac3c80 100644 --- a/tensorflow/lite/c/builtin_op_data.h +++ b/tensorflow/lite/c/builtin_op_data.h @@ -35,11 +35,21 @@ typedef enum { kTfLitePaddingValid, } TfLitePadding; +typedef enum { + kTfLiteMirrorPaddingUnknown = 0, + kTfLiteMirrorPaddingReflect, + kTfLiteMirrorPaddingSymmetric, +} TfLiteMirrorPaddingMode; + typedef struct { int width; int height; } TfLitePaddingValues; +typedef struct { + TfLiteMirrorPaddingMode mode; +} TfLiteMirrorPaddingParams; + // Possible fused activation functions. // TODO(aselle): rename to TfLiteActivation typedef enum { diff --git a/tensorflow/lite/core/api/flatbuffer_conversions.cc b/tensorflow/lite/core/api/flatbuffer_conversions.cc index 3b592a6e0b..aa9b372398 100644 --- a/tensorflow/lite/core/api/flatbuffer_conversions.cc +++ b/tensorflow/lite/core/api/flatbuffer_conversions.cc @@ -629,6 +629,19 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } + case BuiltinOperator_MIRROR_PAD: { + TfLiteMirrorPaddingParams* params = + allocator->AllocatePOD(); + auto* mirror_pad_params = op->builtin_options_as_MirrorPadOptions(); + if (mirror_pad_params != nullptr) { + params->mode = + mirror_pad_params->mode() == tflite::MirrorPadMode_REFLECT + ? TfLiteMirrorPaddingMode::kTfLiteMirrorPaddingReflect + : TfLiteMirrorPaddingMode::kTfLiteMirrorPaddingSymmetric; + } + *builtin_data = reinterpret_cast(params); + break; + } // Below are the ops with no builtin_data strcture. case BuiltinOperator_BATCH_TO_SPACE_ND: diff --git a/tensorflow/lite/experimental/writer/option_writer_generator.cc b/tensorflow/lite/experimental/writer/option_writer_generator.cc index 26d4a91c71..b44750e8b2 100644 --- a/tensorflow/lite/experimental/writer/option_writer_generator.cc +++ b/tensorflow/lite/experimental/writer/option_writer_generator.cc @@ -67,6 +67,7 @@ static const char* param_structs[] = {"TfLiteConvParams", "TfLitePackParams", "TfLiteOneHotParams", "TfLiteLeakyReluParams", + "TfLiteMirrorPaddingParams", nullptr}; } // namespace @@ -153,6 +154,7 @@ class OpOptionData { op_to_option_["BIDIRECTIONAL_SEQUENCE_RNN"] = "SequenceRNNOptions"; op_to_option_["UNIDIRECTIONAL_SEQUENCE_RNN"] = "SequenceRNNOptions"; op_to_option_["UNIDIRECTIONAL_SEQUENCE_RNN"] = "SequenceRNNOptions"; + op_to_option_["MIRROR_PAD"] = ""; // TODO(karimnosseir): MirrorPadOptions. // Manually specified mappings between ops and options (none) op_to_option_["EMBEDDING_LOOKUP"] = ""; // TODO(aselle): maybe something else. diff --git a/tensorflow/lite/nnapi_delegate.cc b/tensorflow/lite/nnapi_delegate.cc index 292dedf1c9..58288a8dd4 100644 --- a/tensorflow/lite/nnapi_delegate.cc +++ b/tensorflow/lite/nnapi_delegate.cc @@ -683,6 +683,7 @@ TfLiteStatus AddOpsAndParams( case tflite::BuiltinOperator_RANGE: case tflite::BuiltinOperator_LEAKY_RELU: case tflite::BuiltinOperator_SQUARED_DIFFERENCE: + case tflite::BuiltinOperator_MIRROR_PAD: logError("Op code %d is currently not delegated to NNAPI", builtin); return kTfLiteError; break; diff --git a/tensorflow/lite/schema/schema.fbs b/tensorflow/lite/schema/schema.fbs index e40a0409f9..652871d013 100644 --- a/tensorflow/lite/schema/schema.fbs +++ b/tensorflow/lite/schema/schema.fbs @@ -202,6 +202,7 @@ enum BuiltinOperator : byte { RESIZE_NEAREST_NEIGHBOR = 97, LEAKY_RELU = 98, SQUARED_DIFFERENCE = 99, + MIRROR_PAD = 100, } // Options for the builtin operators. @@ -282,6 +283,7 @@ union BuiltinOptions { ResizeNearestNeighborOptions, LeakyReluOptions, SquaredDifferenceOptions, + MirrorPadOptions, } enum Padding : byte { SAME, VALID } @@ -669,6 +671,17 @@ table LeakyReluOptions { table SquaredDifferenceOptions { } +enum MirrorPadMode : byte { + // Doesn't include borders. + REFLECT = 0, + // Includes borders. + SYMMETRIC = 1, +} + +table MirrorPadOptions { + mode:MirrorPadMode; +} + // An OperatorCode can be an enum value (BuiltinOperator) if the operator is a // builtin, or a string if the operator is custom. table OperatorCode { diff --git a/tensorflow/lite/schema/schema_generated.h b/tensorflow/lite/schema/schema_generated.h index e93cb3d81d..1464c75613 100755 --- a/tensorflow/lite/schema/schema_generated.h +++ b/tensorflow/lite/schema/schema_generated.h @@ -259,6 +259,9 @@ struct LeakyReluOptionsT; struct SquaredDifferenceOptions; struct SquaredDifferenceOptionsT; +struct MirrorPadOptions; +struct MirrorPadOptionsT; + struct OperatorCode; struct OperatorCodeT; @@ -508,11 +511,12 @@ enum BuiltinOperator { BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97, BuiltinOperator_LEAKY_RELU = 98, BuiltinOperator_SQUARED_DIFFERENCE = 99, + BuiltinOperator_MIRROR_PAD = 100, BuiltinOperator_MIN = BuiltinOperator_ADD, - BuiltinOperator_MAX = BuiltinOperator_SQUARED_DIFFERENCE + BuiltinOperator_MAX = BuiltinOperator_MIRROR_PAD }; -inline const BuiltinOperator (&EnumValuesBuiltinOperator())[99] { +inline const BuiltinOperator (&EnumValuesBuiltinOperator())[100] { static const BuiltinOperator values[] = { BuiltinOperator_ADD, BuiltinOperator_AVERAGE_POOL_2D, @@ -612,7 +616,8 @@ inline const BuiltinOperator (&EnumValuesBuiltinOperator())[99] { BuiltinOperator_RANGE, BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, BuiltinOperator_LEAKY_RELU, - BuiltinOperator_SQUARED_DIFFERENCE + BuiltinOperator_SQUARED_DIFFERENCE, + BuiltinOperator_MIRROR_PAD }; return values; } @@ -719,6 +724,7 @@ inline const char * const *EnumNamesBuiltinOperator() { "RESIZE_NEAREST_NEIGHBOR", "LEAKY_RELU", "SQUARED_DIFFERENCE", + "MIRROR_PAD", nullptr }; return names; @@ -807,11 +813,12 @@ enum BuiltinOptions { BuiltinOptions_ResizeNearestNeighborOptions = 74, BuiltinOptions_LeakyReluOptions = 75, BuiltinOptions_SquaredDifferenceOptions = 76, + BuiltinOptions_MirrorPadOptions = 77, BuiltinOptions_MIN = BuiltinOptions_NONE, - BuiltinOptions_MAX = BuiltinOptions_SquaredDifferenceOptions + BuiltinOptions_MAX = BuiltinOptions_MirrorPadOptions }; -inline const BuiltinOptions (&EnumValuesBuiltinOptions())[77] { +inline const BuiltinOptions (&EnumValuesBuiltinOptions())[78] { static const BuiltinOptions values[] = { BuiltinOptions_NONE, BuiltinOptions_Conv2DOptions, @@ -889,7 +896,8 @@ inline const BuiltinOptions (&EnumValuesBuiltinOptions())[77] { BuiltinOptions_RangeOptions, BuiltinOptions_ResizeNearestNeighborOptions, BuiltinOptions_LeakyReluOptions, - BuiltinOptions_SquaredDifferenceOptions + BuiltinOptions_SquaredDifferenceOptions, + BuiltinOptions_MirrorPadOptions }; return values; } @@ -973,6 +981,7 @@ inline const char * const *EnumNamesBuiltinOptions() { "ResizeNearestNeighborOptions", "LeakyReluOptions", "SquaredDifferenceOptions", + "MirrorPadOptions", nullptr }; return names; @@ -1291,6 +1300,10 @@ template<> struct BuiltinOptionsTraits { static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions; }; +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions; +}; + struct BuiltinOptionsUnion { BuiltinOptions type; void *value; @@ -1930,6 +1943,14 @@ struct BuiltinOptionsUnion { return type == BuiltinOptions_SquaredDifferenceOptions ? reinterpret_cast(value) : nullptr; } + MirrorPadOptionsT *AsMirrorPadOptions() { + return type == BuiltinOptions_MirrorPadOptions ? + reinterpret_cast(value) : nullptr; + } + const MirrorPadOptionsT *AsMirrorPadOptions() const { + return type == BuiltinOptions_MirrorPadOptions ? + reinterpret_cast(value) : nullptr; + } }; bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type); @@ -2127,6 +2148,35 @@ inline const char *EnumNameCombinerType(CombinerType e) { return EnumNamesCombinerType()[index]; } +enum MirrorPadMode { + MirrorPadMode_REFLECT = 0, + MirrorPadMode_SYMMETRIC = 1, + MirrorPadMode_MIN = MirrorPadMode_REFLECT, + MirrorPadMode_MAX = MirrorPadMode_SYMMETRIC +}; + +inline const MirrorPadMode (&EnumValuesMirrorPadMode())[2] { + static const MirrorPadMode values[] = { + MirrorPadMode_REFLECT, + MirrorPadMode_SYMMETRIC + }; + return values; +} + +inline const char * const *EnumNamesMirrorPadMode() { + static const char * const names[] = { + "REFLECT", + "SYMMETRIC", + nullptr + }; + return names; +} + +inline const char *EnumNameMirrorPadMode(MirrorPadMode e) { + const size_t index = static_cast(e); + return EnumNamesMirrorPadMode()[index]; +} + enum CustomOptionsFormat { CustomOptionsFormat_FLEXBUFFERS = 0, CustomOptionsFormat_MIN = CustomOptionsFormat_FLEXBUFFERS, @@ -6769,6 +6819,60 @@ inline flatbuffers::Offset CreateSquaredDifferenceOpti flatbuffers::Offset CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb, const SquaredDifferenceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +struct MirrorPadOptionsT : public flatbuffers::NativeTable { + typedef MirrorPadOptions TableType; + MirrorPadMode mode; + MirrorPadOptionsT() + : mode(MirrorPadMode_REFLECT) { + } +}; + +struct MirrorPadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MirrorPadOptionsT NativeTableType; + enum { + VT_MODE = 4 + }; + MirrorPadMode mode() const { + return static_cast(GetField(VT_MODE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_MODE) && + verifier.EndTable(); + } + MirrorPadOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MirrorPadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MirrorPadOptionsBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_mode(MirrorPadMode mode) { + fbb_.AddElement(MirrorPadOptions::VT_MODE, static_cast(mode), 0); + } + explicit MirrorPadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + MirrorPadOptionsBuilder &operator=(const MirrorPadOptionsBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMirrorPadOptions( + flatbuffers::FlatBufferBuilder &_fbb, + MirrorPadMode mode = MirrorPadMode_REFLECT) { + MirrorPadOptionsBuilder builder_(_fbb); + builder_.add_mode(mode); + return builder_.Finish(); +} + +flatbuffers::Offset CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + struct OperatorCodeT : public flatbuffers::NativeTable { typedef OperatorCode TableType; BuiltinOperator builtin_code; @@ -7130,6 +7234,9 @@ struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const SquaredDifferenceOptions *builtin_options_as_SquaredDifferenceOptions() const { return builtin_options_type() == BuiltinOptions_SquaredDifferenceOptions ? static_cast(builtin_options()) : nullptr; } + const MirrorPadOptions *builtin_options_as_MirrorPadOptions() const { + return builtin_options_type() == BuiltinOptions_MirrorPadOptions ? static_cast(builtin_options()) : nullptr; + } const flatbuffers::Vector *custom_options() const { return GetPointer *>(VT_CUSTOM_OPTIONS); } @@ -7465,6 +7572,10 @@ template<> inline const SquaredDifferenceOptions *Operator::builtin_options_as inline const MirrorPadOptions *Operator::builtin_options_as() const { + return builtin_options_as_MirrorPadOptions(); +} + struct OperatorBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; @@ -10005,6 +10116,32 @@ inline flatbuffers::Offset CreateSquaredDifferenceOpti _fbb); } +inline MirrorPadOptionsT *MirrorPadOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new MirrorPadOptionsT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void MirrorPadOptions::UnPackTo(MirrorPadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = mode(); _o->mode = _e; }; +} + +inline flatbuffers::Offset MirrorPadOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMirrorPadOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MirrorPadOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _mode = _o->mode; + return tflite::CreateMirrorPadOptions( + _fbb, + _mode); +} + inline OperatorCodeT *OperatorCode::UnPack(const flatbuffers::resolver_function_t *_resolver) const { auto _o = new OperatorCodeT(); UnPackTo(_o, _resolver); @@ -10567,6 +10704,10 @@ inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *ob auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } default: return false; } } @@ -10889,6 +11030,10 @@ inline void *BuiltinOptionsUnion::UnPack(const void *obj, BuiltinOptions type, c auto ptr = reinterpret_cast(obj); return ptr->UnPack(resolver); } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } default: return nullptr; } } @@ -11199,6 +11344,10 @@ inline flatbuffers::Offset BuiltinOptionsUnion::Pack(flatbuffers::FlatBuff auto ptr = reinterpret_cast(value); return CreateSquaredDifferenceOptions(_fbb, ptr, _rehasher).Union(); } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(value); + return CreateMirrorPadOptions(_fbb, ptr, _rehasher).Union(); + } default: return 0; } } @@ -11509,6 +11658,10 @@ inline BuiltinOptionsUnion::BuiltinOptionsUnion(const BuiltinOptionsUnion &u) FL value = new SquaredDifferenceOptionsT(*reinterpret_cast(u.value)); break; } + case BuiltinOptions_MirrorPadOptions: { + value = new MirrorPadOptionsT(*reinterpret_cast(u.value)); + break; + } default: break; } @@ -11896,6 +12049,11 @@ inline void BuiltinOptionsUnion::Reset() { delete ptr; break; } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } default: break; } value = nullptr; -- GitLab From 785cac6c8d43dadca123403f2212987a6230fd84 Mon Sep 17 00:00:00 2001 From: Jared Duke Date: Tue, 20 Nov 2018 17:22:34 -0800 Subject: [PATCH 171/672] Update tf_ops_compatibility Alphabetize the list, and include the following ops: * Fill * FloorDiv * FloorMod * LeakyRelu * Range * ResizeNearestNeighbor PiperOrigin-RevId: 222332617 --- tensorflow/lite/g3doc/tf_ops_compatibility.md | 216 ++++++++++++------ 1 file changed, 143 insertions(+), 73 deletions(-) diff --git a/tensorflow/lite/g3doc/tf_ops_compatibility.md b/tensorflow/lite/g3doc/tf_ops_compatibility.md index 5a7bc2deeb..2864c6aaf4 100644 --- a/tensorflow/lite/g3doc/tf_ops_compatibility.md +++ b/tensorflow/lite/g3doc/tf_ops_compatibility.md @@ -1,4 +1,3 @@ - # TensorFlow Lite & TensorFlow Compatibility Guide TensorFlow Lite supports a number of TensorFlow operations used in common @@ -155,6 +154,30 @@ Options { } ``` +**ARG_MAX** + +``` +Inputs { + 0: a tensor + 1: a tensor +} +Outputs { + 0: A tensor of indices of maximum values. +} +``` + +**ARG_MIN** + +``` +Inputs { + 0: a tensor + 1: a tensor +} +Outputs { + 0: A tensor of indices of minium values. +} +``` + **AVERAGE_POOL_2D** ``` @@ -281,6 +304,18 @@ Outputs { } ``` +**FILL** + +``` +Inputs { + 0: a 1D tensor + 1: a 0D (scalar) tensor +} +Outputs { + 0: A tensor of shape `tensor 0` filled with the value in `tensor 1`. +} +``` + **FLOOR** ``` @@ -292,6 +327,30 @@ outputs: { } ``` +**FLOOR_DIV** + +``` +Inputs { + 0: a tensor + 1: a tensor +} +Outputs { + 0: result of computing element-wise floor of `tensor 0` divided by `tensor 1`. +} +``` + +**FLOOR_MOD** + +``` +Inputs { + 0: a tensor + 1: a tensor +} +Outputs { + 0: result of computing element-wise floor of `tensor 0` modulo `tensor 1`. +} +``` + **FULLY_CONNECTED** ``` @@ -393,6 +452,20 @@ Options { } ``` +**LEAKY_RELU** + +``` +Inputs { + 0: a tensor +} +Outputs { + 0: a tensor equivalent to max(input, input * alpha) +} +Options { + alpha +} +``` + **LESS** ``` @@ -436,6 +509,18 @@ Options { } ``` +**LOGICAL_OR** + +``` +Inputs { + 0: a list of tensors. + 1: a list of tensors. +} +Outputs { + 0: A tensor of logical_or output tensors. +} +``` + **LOGISTIC** ``` @@ -513,6 +598,18 @@ Outputs { } ``` +**PACK** + +``` +Inputs { + 0: a list of tensors. + 1: an integer. +} +Outputs { + 0: A tensor of stacked tensors. +} +``` + **PAD** ``` @@ -554,6 +651,35 @@ Outputs { } ``` +**POW** + +``` +Inputs { + 0: a tensor + 1: a tensor +} +Outputs { + 0: elementwise pow of the input tensors +} +``` + +**RANGE** + +``` +Inputs { + 0: a 0D (scalar) tensor + 1: a 0D (scalar) tensor + 2: a 0D (scalar) tensor +} +Outputs { + 0: A 1D tensor of type `dtype` defined by a sequence where `tensor 0` is the + start, `tensor 1` is the limit, and `tensor 2` is the delta. +} +Options { + dtype +} +``` + **RELU** ``` @@ -602,6 +728,22 @@ Options { } ``` +**RESIZE_NEAREST_NEIGHBOR** + +``` +Inputs { + 0: a 4D tensor + 1: a 1D tensor with 2 elements +} +Outputs { + 0: A tensor of type `tensor 0` resized according to `tensor 1` heigh/width values + using nearest neighbors interpolation. +} +Options { + align_corners +} +``` + **RSQRT** ``` @@ -796,66 +938,6 @@ Outputs { } ``` -**POW** - -``` -Inputs { - 0: a tensor - 1: a tensor -} -Outputs { - 0: elementwise pow of the input tensors -} -``` - -**ARG_MAX** - -``` -Inputs { - 0: a tensor - 1: a tensor -} -Outputs { - 0: A tensor of indices of maximum values. -} -``` - -**ARG_MIN** - -``` -Inputs { - 0: a tensor - 1: a tensor -} -Outputs { - 0: A tensor of indices of minium values. -} -``` - -**PACK** - -``` -Inputs { - 0: a list of tensors. - 1: an integer. -} -Outputs { - 0: A tensor of stacked tensors. -} -``` - -**LOGICAL_OR** - -``` -Inputs { - 0: a list of tensors. - 1: a list of tensors. -} -Outputs { - 0: A tensor of logical_or output tensors. -} -``` - **UNPACK** ``` @@ -869,18 +951,6 @@ Outputs { } ``` -**FLOOR_DIV** - -``` -Inputs { - 0: a list of tensors. - 1: a list of tensors. -} -Outputs { - 0: A tensor of floor_div output tensors. -} -``` - **ZEROS_LIKE** ``` -- GitLab From 3e3f71b3e4ac9872895f6ddc7482f97b7b22448c Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 20 Nov 2018 17:24:25 -0800 Subject: [PATCH 172/672] Make deprecated Split function use new one rather than the other way This helps avoid a compiler warning since the deprecated function is no longer being used in the header. PiperOrigin-RevId: 222332803 --- tensorflow/core/util/sparse/sparse_tensor.h | 50 ++++++--------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/tensorflow/core/util/sparse/sparse_tensor.h b/tensorflow/core/util/sparse/sparse_tensor.h index b9ca8ab395..89c163aa51 100644 --- a/tensorflow/core/util/sparse/sparse_tensor.h +++ b/tensorflow/core/util/sparse/sparse_tensor.h @@ -238,15 +238,6 @@ class SparseTensor { static Status Split(const SparseTensor& tensor, const int split_dim, const int num_split, std::vector* result); - template - ABSL_DEPRECATED( - "Use the form of Split() that takes an output pointer and returns a " - "status instead.") - static std::vector Split(const SparseTensor& tensor, - const int split_dim, - const int num_split, - Status* status = nullptr); - // Slice() will slice the input SparseTensor into a SparseTensor based on // specified start and size. Both start and size are 1-D array with each // element of the array representing one dimension. The start is the start @@ -578,10 +569,9 @@ SparseTensor SparseTensor::Concat( } template -std::vector SparseTensor::Split(const SparseTensor& input_tensor, - const int split_dim, - const int num_split, - Status* status /* = nullptr */) { +Status SparseTensor::Split(const SparseTensor& input_tensor, + const int split_dim, const int num_split, + std::vector* result) { std::vector output_indices; std::vector output_values; std::vector output_shapes; @@ -601,17 +591,15 @@ std::vector SparseTensor::Split(const SparseTensor& input_tensor, const int split_dim_size = input_tensor.shape()[split_dim]; const int split_size = split_dim_size / num_split; - if (!(num_split > 0 && num_split <= split_dim_size) && status != nullptr) { - *status = Status(error::INVALID_ARGUMENT, - strings::StrCat("num_split must be in the interval (0, ", - split_dim_size, "]")); - return {}; + if (!(num_split > 0 && num_split <= split_dim_size)) { + return Status(error::INVALID_ARGUMENT, + strings::StrCat("num_split must be in the interval (0, ", + split_dim_size, "]")); } if (!(split_dim >= 0 && split_dim < num_dim)) { - *status = Status( + return Status( error::INVALID_ARGUMENT, strings::StrCat("num_dim must be in the interval [0, ", num_dim, ")")); - return {}; } const int residual = split_dim_size % num_split; @@ -649,28 +637,18 @@ std::vector SparseTensor::Split(const SparseTensor& input_tensor, } } - std::vector output_tensors; - output_tensors.reserve(num_split); + result->clear(); + result->reserve(num_split); for (int i = 0; i < num_split; ++i) { SparseTensor tensor; Status create_status = Create(output_indices[i], output_values[i], output_shapes[i], &tensor); - if (!create_status.ok() && status != nullptr) { - *status = create_status; - return {}; + if (!create_status.ok()) { + return create_status; } - output_tensors.push_back(std::move(tensor)); + result->push_back(std::move(tensor)); } - return output_tensors; -} - -template -Status SparseTensor::Split(const SparseTensor& input_tensor, - const int split_dim, const int num_split, - std::vector* result) { - Status status; - *result = Split(input_tensor, split_dim, num_split, &status); - return status; + return Status::OK(); } template -- GitLab From 96b0d298df643ea835a8e2aa7265cb365409205d Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Tue, 20 Nov 2018 17:28:20 -0800 Subject: [PATCH 173/672] Add performance test for LSTM that with grappler swap the implementation. PiperOrigin-RevId: 222333112 --- .../python/keras/layers/unified_rnn_test.py | 190 ++++++++++++++++-- 1 file changed, 176 insertions(+), 14 deletions(-) diff --git a/tensorflow/python/keras/layers/unified_rnn_test.py b/tensorflow/python/keras/layers/unified_rnn_test.py index a16d0f383a..22d29f191b 100644 --- a/tensorflow/python/keras/layers/unified_rnn_test.py +++ b/tensorflow/python/keras/layers/unified_rnn_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function import collections +import time from tensorflow.core.protobuf import config_pb2 from tensorflow.core.protobuf import rewriter_config_pb2 @@ -37,6 +38,7 @@ from tensorflow.python.keras import regularizers from tensorflow.python.keras import testing_utils from tensorflow.python.keras.engine.base_layer import \ InputSpec +from tensorflow.python.keras.layers.cudnn_recurrent import CuDNNLSTM from tensorflow.python.keras.layers.recurrent import RNN from tensorflow.python.keras.utils import tf_utils from tensorflow.python.ops import array_ops @@ -47,20 +49,22 @@ from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables from tensorflow.python.ops.losses import losses from tensorflow.python.platform import test +from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import gradient_descent class RNNTest(test.TestCase): - def test_unifiedRNN(self): + def setUp(self): rewrites = rewriter_config_pb2.RewriterConfig() rewrites.function_optimization = rewriter_config_pb2.RewriterConfig.OFF customer_optimizer = rewrites.custom_optimizers.add() customer_optimizer.name = 'ExperimentalImplementationSelector' rewrites.min_graph_nodes = -1 graph_options = config_pb2.GraphOptions(rewrite_options=rewrites) - config = config_pb2.ConfigProto(graph_options=graph_options) + self.config = config_pb2.ConfigProto(graph_options=graph_options) + def test_unifiedRNN(self): input_shape = 10 rnn_state_size = 8 output_shape = 8 @@ -68,13 +72,13 @@ class RNNTest(test.TestCase): batch = 100 epoch = 1 - with ops.Graph().as_default(), session.Session(config=config) as sess: + with ops.Graph().as_default(), session.Session(config=self.config) as sess: (x_train, y_train), _ = testing_utils.get_test_data( train_samples=batch, test_samples=0, input_shape=(timestep, input_shape), num_classes=output_shape) - y_train = keras.utils.to_categorical(y_train) + y_train = keras.utils.to_categorical(y_train, output_shape) layer = UnifiedLSTM(rnn_state_size) @@ -104,18 +108,36 @@ class RNNTest(test.TestCase): self.assertNotEqual(existing_loss, loss_value) existing_loss = loss_value + def test_keras_model_with_lstm(self): + input_shape = 10 + rnn_state_size = 8 + output_shape = 8 + timestep = 4 + batch = 100 + epoch = 10 + + (x_train, y_train), _ = testing_utils.get_test_data( + train_samples=batch, + test_samples=0, + input_shape=(timestep, input_shape), + num_classes=output_shape) + y_train = keras.utils.to_categorical(y_train, output_shape) + + K.set_session(session.Session(config=self.config)) + layer = UnifiedLSTM(rnn_state_size) + + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs, unused_runtime = layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('rmsprop', loss='mse') + model.fit(x_train, y_train, epochs=epoch) + def test_unifiedRNN_with_cond(self): # This test is to demonstrate the graph rewrite of grappler plugin under # the condition that the function returns different number of internal # states. - rewrites = rewriter_config_pb2.RewriterConfig() - rewrites.function_optimization = rewriter_config_pb2.RewriterConfig.OFF - customer_optimizer = rewrites.custom_optimizers.add() - customer_optimizer.name = 'ExperimentalImplementationSelector' - rewrites.min_graph_nodes = -1 - graph_options = config_pb2.GraphOptions(rewrite_options=rewrites) - config = config_pb2.ConfigProto(graph_options=graph_options) - input_shape = 10 rnn_state_size = 8 output_shape = 8 @@ -123,13 +145,13 @@ class RNNTest(test.TestCase): batch = 100 epoch = 1 - with ops.Graph().as_default(), session.Session(config=config) as sess: + with ops.Graph().as_default(), session.Session(config=self.config) as sess: (x_train, y_train), _ = testing_utils.get_test_data( train_samples=batch, test_samples=0, input_shape=(timestep, input_shape), num_classes=output_shape) - y_train = keras.utils.to_categorical(y_train) + y_train = keras.utils.to_categorical(y_train, output_shape) layer = UnifiedLSTM(rnn_state_size) @@ -169,6 +191,146 @@ class RNNTest(test.TestCase): self.assertNotEqual(existing_loss, loss_value) existing_loss = loss_value + def _time_performance_run_cudnn_lstm(self, test_config, x_train, y_train): + # Get the performance number for standard Cudnn LSTM + input_shape = test_config['input_shape'] + rnn_state_size = test_config['rnn_state_size'] + timestep = test_config['timestep'] + epoch = test_config['epoch'] + warmup_epoch = test_config['warmup_epoch'] + + ops.reset_default_graph() + with self.test_session(use_gpu=True): + cudnn_lstm_layer = CuDNNLSTM(rnn_state_size) + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs = cudnn_lstm_layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('sgd', 'mse') + + total_duration = 0 + for i in range(epoch): + start_time = time.time() + model.fit(x_train, y_train) + end_time = time.time() + if i >= warmup_epoch: + duration_per_epoch = end_time - start_time + total_duration += duration_per_epoch + logging.vlog(2, '%s: Time consumed for epoch %d is: %s', + 'CuDNN LSTM', i, duration_per_epoch) + logging.info('Average performance for %s per epoch is: %s', + 'CuDNN LSTM', (total_duration / epoch)) + return total_duration / epoch + + def _time_performance_run_unifed_lstm_gpu( + self, test_config, x_train, y_train): + # Get performance number for Unified_LSTM with grappler swap the impl + input_shape = test_config['input_shape'] + rnn_state_size = test_config['rnn_state_size'] + timestep = test_config['timestep'] + epoch = test_config['epoch'] + warmup_epoch = test_config['warmup_epoch'] + + ops.reset_default_graph() + K.set_session(session.Session(config=self.config)) + layer = UnifiedLSTM(rnn_state_size) + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs, _ = layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('sgd', 'mse') + + total_duration = 0 + for i in range(epoch): + start_time = time.time() + model.fit(x_train, y_train) + end_time = time.time() + if i >= warmup_epoch: + duration_per_epoch = end_time - start_time + total_duration += duration_per_epoch + logging.vlog(2, '%s: Time consumed for epoch %d is: %s', + 'Unified LSTM', i, duration_per_epoch) + logging.info('Average performance for %s per epoch is: %s', + 'Unified LSTM', (total_duration / epoch)) + return total_duration / epoch + + def _time_performance_run_normal_lstm( + self, test_config, x_train, y_train): + # Get performance number for standard LSTM on GPU. + input_shape = test_config['input_shape'] + rnn_state_size = test_config['rnn_state_size'] + timestep = test_config['timestep'] + epoch = test_config['epoch'] + warmup_epoch = test_config['warmup_epoch'] + + ops.reset_default_graph() + with self.test_session(use_gpu=True): + layer = keras.layers.LSTM(rnn_state_size) + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs = layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('sgd', 'mse') + + total_duration = 0 + for i in range(epoch): + start_time = time.time() + model.fit(x_train, y_train) + end_time = time.time() + if i >= warmup_epoch: + duration_per_epoch = end_time - start_time + total_duration += duration_per_epoch + logging.vlog(2, '%s: Time consumed for epoch %d is: %s', + 'Normal LSTM', i, duration_per_epoch) + logging.info('Average performance for %s per epoch is: %s', + 'Normal LSTM', (total_duration / epoch)) + return total_duration / epoch + + def test_performance_with_standard_cudnn_impl(self): + if not test.is_gpu_available(): + self.skipTest('performance test will only run on GPU') + + test_config = { + 'input_shape': 128, + 'rnn_state_size': 64, + 'output_shape': 64, + 'timestep': 50, + 'epoch': 20, + # The performance for warmup epoch is ignored. + 'warmup_epoch': 1, + } + batch = 64 + (x_train, y_train), _ = testing_utils.get_test_data( + train_samples=batch, + test_samples=0, + input_shape=(test_config['timestep'], test_config['input_shape']), + num_classes=test_config['output_shape']) + y_train = keras.utils.to_categorical(y_train, test_config['output_shape']) + + cudnn_duration = self._time_performance_run_cudnn_lstm( + test_config, x_train, y_train) + unified_lstm_gpu_duration = self._time_performance_run_unifed_lstm_gpu( + test_config, x_train, y_train) + normal_lstm_duration = self._time_performance_run_normal_lstm( + test_config, x_train, y_train) + + cudnn_vs_unified = cudnn_duration / unified_lstm_gpu_duration + unified_vs_normal = normal_lstm_duration / unified_lstm_gpu_duration + # Assert the performance diff should be within 80% of the native cudnn impl. + self.assertGreaterEqual( + cudnn_vs_unified, 0.80, + 'Expect the performance of Unified LSTM is within 80% of CuDNN LSTM, ' + 'but got {}'.format(cudnn_vs_unified * 100)) + # Assert the performance diff between CPU impl and GPU impl should be more + # than 5 times. + self.assertGreaterEqual( + unified_vs_normal, 5, + 'Expect the performance of Unified LSTM is more than 5 times of normal ' + 'LSTM, but got {}'.format(unified_vs_normal)) + class UnifiedLSTM(RNN): -- GitLab From a102a6a71844e194f3946f6318768c5367f1f16b Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 20 Nov 2018 17:33:45 -0800 Subject: [PATCH 174/672] Add use_gpu, force_gpu & force_gpu helpers in test_util In order to make tests compatible for V2 behavior we should avoid using sessions and instead use device contexts. To support the different desired behaviors we add 3 helpers in test_util and covert a few tests to make use of them. PiperOrigin-RevId: 222333755 --- tensorflow/compiler/tests/rmsprop_test.py | 4 +- tensorflow/python/framework/test_util.py | 21 + .../python/keras/engine/training_gpu_test.py | 2 +- .../python/keras/optimizer_v2/rmsprop_test.py | 21 +- .../python/kernel_tests/array_ops_test.py | 13 +- .../python/kernel_tests/bitcast_op_test.py | 3 +- .../compare_and_bitpack_op_test.py | 3 +- .../kernel_tests/determinant_op_test.py | 3 +- .../kernel_tests/dynamic_stitch_op_test.py | 15 +- .../extract_image_patches_op_test.py | 3 +- .../extract_volume_patches_op_test.py | 3 +- .../matrix_exponential_op_test.py | 3 +- .../kernel_tests/matrix_logarithm_op_test.py | 3 +- .../python/kernel_tests/numerics_test.py | 7 +- .../python/kernel_tests/scatter_ops_test.py | 9 +- .../kernel_tests/spacetodepth_op_test.py | 18 +- .../python/kernel_tests/unstack_op_test.py | 24 +- .../python/kernel_tests/zero_division_test.py | 3 +- tensorflow/python/ops/nn_test.py | 673 +++++++++--------- tensorflow/python/training/rmsprop_test.py | 37 +- 20 files changed, 449 insertions(+), 419 deletions(-) diff --git a/tensorflow/compiler/tests/rmsprop_test.py b/tensorflow/compiler/tests/rmsprop_test.py index 5138a4a2a9..dc3e90b4af 100644 --- a/tensorflow/compiler/tests/rmsprop_test.py +++ b/tensorflow/compiler/tests/rmsprop_test.py @@ -76,7 +76,7 @@ class RmspropTest(xla_test.XLATestCase): rms_opt = rmsprop.RMSPropOptimizer(learning_rate, centered=centered) rms_update = rms_opt.apply_gradients( zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) mg0 = rms_opt.get_slot(var0, "mg") self.assertEqual(mg0 is not None, centered) @@ -97,7 +97,7 @@ class RmspropTest(xla_test.XLATestCase): # Run 3 steps of RMSProp for _ in range(3): - rms_update.run() + self.evaluate(rms_update) var0_np, mg0_np, rms0_np, mom0_np = self._rmsprop_update_numpy( var0_np, diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index 897122746b..bf0ebaea99 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -1062,6 +1062,27 @@ def device(use_gpu): yield +@contextlib.contextmanager +def use_gpu(): + """Uses gpu when requested and available.""" + with device(use_gpu=True): + yield + + +@contextlib.contextmanager +def force_gpu(): + """Force the gpu to be used.""" + with ops.device("/device:GPU:0"): + yield + + +@contextlib.contextmanager +def force_cpu(): + """Force the cpu to be used.""" + with ops.device("/device:CPU:0"): + yield + + class CapturedWrites(object): """A utility class to load the captured writes made to a stream.""" diff --git a/tensorflow/python/keras/engine/training_gpu_test.py b/tensorflow/python/keras/engine/training_gpu_test.py index 596d085f3f..45dcfe4399 100644 --- a/tensorflow/python/keras/engine/training_gpu_test.py +++ b/tensorflow/python/keras/engine/training_gpu_test.py @@ -69,7 +69,7 @@ class TrainingGPUTest(test.TestCase): return simple_model if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): + with test_util.use_gpu(): losses_to_test = ['sparse_categorical_crossentropy', 'categorical_crossentropy', 'binary_crossentropy'] diff --git a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py index 2ac090724e..62b64d5cf9 100644 --- a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py +++ b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py @@ -28,6 +28,7 @@ from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.keras.optimizer_v2 import rmsprop from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops @@ -87,7 +88,7 @@ class RMSpropOptimizerTest(test.TestCase): def testDense(self): for (dtype, learning_rate, rho, momentum, epsilon, centered) in _TESTPARAMS: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): # Initialize variables for numpy implementation. var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) grads0_np = np.array([0.1, 0.2], dtype=dtype.as_numpy_dtype) @@ -106,7 +107,7 @@ class RMSpropOptimizerTest(test.TestCase): centered=centered) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) if centered: mg0 = opt.get_slot(var0, "mg") @@ -137,7 +138,7 @@ class RMSpropOptimizerTest(test.TestCase): # Run 4 steps of RMSprop for _ in range(1, 5): - update.run() + self.evaluate(update) var0_np, mg0_np, rms0_np, mom0_np = self._rmsprop_update_numpy( var0_np, grads0_np, mg0_np, rms0_np, mom0_np, learning_rate, rho, @@ -171,11 +172,11 @@ class RMSpropOptimizerTest(test.TestCase): epsilon=0.0, centered=False).minimize( loss, var_list=[var0]) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) # Fetch params to validate initial values self.assertAllCloseAccordingToType([[1.0, 2.0]], self.evaluate(var0)) # Run 1 step of sgd - sgd_op.run() + self.evaluate(sgd_op) # Validate updated params self.assertAllCloseAccordingToType([[0., 1.]], self.evaluate(var0), @@ -195,11 +196,11 @@ class RMSpropOptimizerTest(test.TestCase): epsilon=1.0, centered=True).minimize( loss, var_list=[var0]) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) # Fetch params to validate initial values self.assertAllCloseAccordingToType([[1.0, 2.0]], self.evaluate(var0)) # Run 1 step of sgd - sgd_op.run() + self.evaluate(sgd_op) # Validate updated params self.assertAllCloseAccordingToType([[-111, -138]], self.evaluate(var0), @@ -207,7 +208,7 @@ class RMSpropOptimizerTest(test.TestCase): def testSparse(self): for (dtype, learning_rate, rho, momentum, epsilon, centered) in _TESTPARAMS: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): # Initialize variables for numpy implementation. var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) grads0_np = np.array([0.1], dtype=dtype.as_numpy_dtype) @@ -231,7 +232,7 @@ class RMSpropOptimizerTest(test.TestCase): epsilon=epsilon, centered=centered) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) if centered: mg0 = opt.get_slot(var0, "mg") @@ -263,7 +264,7 @@ class RMSpropOptimizerTest(test.TestCase): # Run 4 steps of RMSprop for _ in range(1, 5): - update.run() + self.evaluate(update) var0_np, mg0_np, rms0_np, mom0_np = self._sparse_rmsprop_update_numpy( var0_np, grads0_np_indices, grads0_np, mg0_np, rms0_np, mom0_np, diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py index b9d9d54c98..afc158f697 100644 --- a/tensorflow/python/kernel_tests/array_ops_test.py +++ b/tensorflow/python/kernel_tests/array_ops_test.py @@ -556,7 +556,8 @@ class StridedSliceTest(test_util.TensorFlowTestCase): def testInt64GPU(self): if not test_util.is_gpu_available(): self.skipTest("No GPU available") - with self.session(use_gpu=True, force_gpu=True): + + with test_util.force_gpu(): x = constant_op.constant([1., 2., 3.]) begin = constant_op.constant([2], dtype=dtypes.int64) end = constant_op.constant([3], dtype=dtypes.int64) @@ -1187,18 +1188,18 @@ class IdentityTest(test_util.TensorFlowTestCase): self.assertAllEqual(x.numpy(), y.numpy()) self.assertTrue(device in y.device.lower()) - with ops.device("gpu:0"): + with test_util.force_gpu(): a = constant_op.constant([[2], [3]], dtype=dtypes.float32) - with ops.device("gpu:0"): + with test_util.force_gpu(): b = array_ops.identity(a) _test(a, b, "gpu") - with ops.device("cpu:0"): + with test_util.force_cpu(): c = array_ops.identity(b) _test(b, c, "cpu") - with ops.device("cpu:0"): + with test_util.force_cpu(): d = array_ops.identity(c) _test(c, d, "cpu") - with ops.device("gpu:0"): + with test_util.force_gpu(): e = array_ops.identity(d) _test(d, e, "gpu") diff --git a/tensorflow/python/kernel_tests/bitcast_op_test.py b/tensorflow/python/kernel_tests/bitcast_op_test.py index 4dcf218d7c..5ceffcfeda 100644 --- a/tensorflow/python/kernel_tests/bitcast_op_test.py +++ b/tensorflow/python/kernel_tests/bitcast_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test @@ -28,7 +29,7 @@ from tensorflow.python.platform import test class BitcastTest(test.TestCase): def _testBitcast(self, x, datatype, shape): - with self.session(use_gpu=True): + with test_util.use_gpu(): tf_ans = array_ops.bitcast(x, datatype) out = self.evaluate(tf_ans) buff_after = memoryview(out).tobytes() diff --git a/tensorflow/python/kernel_tests/compare_and_bitpack_op_test.py b/tensorflow/python/kernel_tests/compare_and_bitpack_op_test.py index e1928c5a1c..215ea97f36 100644 --- a/tensorflow/python/kernel_tests/compare_and_bitpack_op_test.py +++ b/tensorflow/python/kernel_tests/compare_and_bitpack_op_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -30,7 +31,7 @@ class CompareAndBitpackTest(test.TestCase): x, threshold, truth, expected_err_re=None): - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): ans = math_ops.compare_and_bitpack(x, threshold) if expected_err_re is None: tf_ans = self.evaluate(ans) diff --git a/tensorflow/python/kernel_tests/determinant_op_test.py b/tensorflow/python/kernel_tests/determinant_op_test.py index 78c1d74da0..602ceb6ebd 100644 --- a/tensorflow/python/kernel_tests/determinant_op_test.py +++ b/tensorflow/python/kernel_tests/determinant_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_linalg_ops from tensorflow.python.ops import linalg_ops @@ -62,7 +63,7 @@ class DeterminantOpTest(test.TestCase): atol=5e-5) def _compareDeterminant(self, matrix_x): - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): self._compareDeterminantBase(matrix_x, linalg_ops.matrix_determinant(matrix_x)) self._compareLogDeterminantBase( diff --git a/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py b/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py index c0b0e3f193..3d063c4e0e 100644 --- a/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py +++ b/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import math_ops @@ -36,7 +37,7 @@ class DynamicStitchTestBase(object): self.stitch_op = stitch_op def testScalar(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): indices = [constant_op.constant(0), constant_op.constant(1)] data = [constant_op.constant(40), constant_op.constant(60)] for step in -1, 1: @@ -47,7 +48,7 @@ class DynamicStitchTestBase(object): self.assertEqual([2], stitched_t.get_shape().as_list()) def testShapeInferenceForScalarWithNonConstantIndices(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): indices = [ array_ops.placeholder(dtype=dtypes.int32), constant_op.constant(1) @@ -61,7 +62,7 @@ class DynamicStitchTestBase(object): self.assertEqual([None], stitched_t.get_shape().as_list()) def testSimpleOneDimensional(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): # Test various datatypes in the simple case to ensure that the op was # registered under those types. dtypes_to_test = [ @@ -84,7 +85,7 @@ class DynamicStitchTestBase(object): self.assertEqual([8], stitched_t.get_shape().as_list()) def testOneListOneDimensional(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): indices = [constant_op.constant([1, 6, 2, 3, 5, 0, 4, 7])] data = [constant_op.constant([10, 60, 20, 30, 50, 0, 40, 70])] stitched_t = self.stitch_op(indices, data) @@ -94,7 +95,7 @@ class DynamicStitchTestBase(object): self.assertEqual([8], stitched_t.get_shape().as_list()) def testSimpleTwoDimensional(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): indices = [ constant_op.constant([0, 4, 7]), constant_op.constant([1, 6]), @@ -113,7 +114,7 @@ class DynamicStitchTestBase(object): self.assertEqual([8, 2], stitched_t.get_shape().as_list()) def testZeroSizeTensor(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): indices = [ constant_op.constant([0, 4, 7]), constant_op.constant([1, 6]), @@ -222,7 +223,7 @@ class ParallelDynamicStitchTest(DynamicStitchTestBase, test.TestCase): DynamicStitchTestBase.__init__(self, data_flow_ops.parallel_dynamic_stitch) def testScalar(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): indices = [constant_op.constant(0), constant_op.constant(1)] data = [constant_op.constant(40.0), constant_op.constant(60.0)] for step in -1, 1: diff --git a/tensorflow/python/kernel_tests/extract_image_patches_op_test.py b/tensorflow/python/kernel_tests/extract_image_patches_op_test.py index 4fe51e94e1..bb3c0ae806 100644 --- a/tensorflow/python/kernel_tests/extract_image_patches_op_test.py +++ b/tensorflow/python/kernel_tests/extract_image_patches_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test @@ -43,7 +44,7 @@ class ExtractImagePatches(test.TestCase): strides = [1] + strides + [1] rates = [1] + rates + [1] - with self.session(use_gpu=True): + with test_util.use_gpu(): out_tensor = array_ops.extract_image_patches( constant_op.constant(image), ksizes=ksizes, diff --git a/tensorflow/python/kernel_tests/extract_volume_patches_op_test.py b/tensorflow/python/kernel_tests/extract_volume_patches_op_test.py index d99823d517..88f7df8fbb 100644 --- a/tensorflow/python/kernel_tests/extract_volume_patches_op_test.py +++ b/tensorflow/python/kernel_tests/extract_volume_patches_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test @@ -45,7 +46,7 @@ class ExtractVolumePatches(test.TestCase): ksizes = [1] + ksizes + [1] strides = [1] + strides + [1] - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): out_tensor = array_ops.extract_volume_patches( constant_op.constant(image), ksizes=ksizes, diff --git a/tensorflow/python/kernel_tests/matrix_exponential_op_test.py b/tensorflow/python/kernel_tests/matrix_exponential_op_test.py index 7fe6cd4141..d41b449a1f 100644 --- a/tensorflow/python/kernel_tests/matrix_exponential_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_exponential_op_test.py @@ -25,6 +25,7 @@ import numpy as np from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import random_ops @@ -50,7 +51,7 @@ class ExponentialOpTest(test.TestCase): def _verifyExponential(self, x, np_type): inp = x.astype(np_type) - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): tf_ans = linalg_impl.matrix_exponential(inp) if x.size == 0: np_ans = np.empty(x.shape, dtype=np_type) diff --git a/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py b/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py index 102502ae0d..81c0b5a772 100644 --- a/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py @@ -25,6 +25,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_linalg_ops from tensorflow.python.ops import math_ops @@ -39,7 +40,7 @@ class LogarithmOpTest(test.TestCase): def _verifyLogarithm(self, x, np_type): inp = x.astype(np_type) - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): # Verify that expm(logm(A)) == A. tf_ans = linalg_impl.matrix_exponential( gen_linalg_ops.matrix_logarithm(inp)) diff --git a/tensorflow/python/kernel_tests/numerics_test.py b/tensorflow/python/kernel_tests/numerics_test.py index d25d97349d..e3210dcddc 100644 --- a/tensorflow/python/kernel_tests/numerics_test.py +++ b/tensorflow/python/kernel_tests/numerics_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops @@ -35,7 +36,7 @@ class VerifyTensorAllFiniteTest(test.TestCase): def testVerifyTensorAllFiniteSucceeds(self): x_shape = [5, 4] x = np.random.random_sample(x_shape).astype(np.float32) - with self.session(use_gpu=True): + with test_util.use_gpu(): t = constant_op.constant(x, shape=x_shape, dtype=dtypes.float32) t_verified = numerics.verify_tensor_all_finite(t, "Input is not a number.") @@ -48,7 +49,7 @@ class VerifyTensorAllFiniteTest(test.TestCase): # Test NaN. x[0] = np.nan - with self.session(use_gpu=True): + with test_util.use_gpu(): with self.assertRaisesOpError(my_msg): t = constant_op.constant(x, shape=x_shape, dtype=dtypes.float32) t_verified = numerics.verify_tensor_all_finite(t, my_msg) @@ -56,7 +57,7 @@ class VerifyTensorAllFiniteTest(test.TestCase): # Test Inf. x[0] = np.inf - with self.session(use_gpu=True): + with test_util.use_gpu(): with self.assertRaisesOpError(my_msg): t = constant_op.constant(x, shape=x_shape, dtype=dtypes.float32) t_verified = numerics.verify_tensor_all_finite(t, my_msg) diff --git a/tensorflow/python/kernel_tests/scatter_ops_test.py b/tensorflow/python/kernel_tests/scatter_ops_test.py index 1c7006ac0b..a4daad7adc 100644 --- a/tensorflow/python/kernel_tests/scatter_ops_test.py +++ b/tensorflow/python/kernel_tests/scatter_ops_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -320,19 +321,19 @@ class ScatterTest(test.TestCase): updates = np.array([-3, -4, -5]).astype(np.float32) # With GPU, the code ignores indices that are out of range. # We don't test the implementation; just test there's no failures. - with self.cached_session(force_gpu=True): + with test_util.force_gpu(): ref = variables.Variable(params) ref.initializer.run() # Indices all in range, no problem. indices = np.array([2, 0, 5]) - op(ref, indices, updates).eval() + self.evaluate(op(ref, indices, updates)) # Indicies out of range should not fail. indices = np.array([-1, 0, 5]) - op(ref, indices, updates).eval() + self.evaluate(op(ref, indices, updates)) indices = np.array([2, 0, 6]) - op(ref, indices, updates).eval() + self.evaluate(op(ref, indices, updates)) if __name__ == '__main__': diff --git a/tensorflow/python/kernel_tests/spacetodepth_op_test.py b/tensorflow/python/kernel_tests/spacetodepth_op_test.py index c32b4ff42d..8ac98a198c 100644 --- a/tensorflow/python/kernel_tests/spacetodepth_op_test.py +++ b/tensorflow/python/kernel_tests/spacetodepth_op_test.py @@ -36,21 +36,22 @@ class SpaceToDepthTest(test.TestCase): def _testOne(self, inputs, block_size, outputs, dtype=dtypes.float32): input_nhwc = math_ops.cast(inputs, dtype) - with self.session(use_gpu=False): + with test_util.force_cpu(): # test NHWC (default) on CPU x_tf = array_ops.space_to_depth(input_nhwc, block_size) - self.assertAllEqual(x_tf.eval(), outputs) - if test.is_gpu_available(): - with self.session(force_gpu=True): + self.assertAllEqual(self.evaluate(x_tf), outputs) + + if test_util.is_gpu_available(): + with test_util.force_gpu(): # test NHWC (default) on GPU x_tf = array_ops.space_to_depth(input_nhwc, block_size) - self.assertAllEqual(x_tf.eval(), outputs) + self.assertAllEqual(self.evaluate(x_tf), outputs) # test NCHW on GPU input_nchw = test_util.NHWCToNCHW(input_nhwc) output_nchw = array_ops.space_to_depth( input_nchw, block_size, data_format="NCHW") output_nhwc = test_util.NCHWToNHWC(output_nchw) - self.assertAllEqual(output_nhwc.eval(), outputs) + self.assertAllEqual(self.evaluate(output_nhwc), outputs) def testBasic(self): x_np = [[[[1], [2]], [[3], [4]]]] @@ -134,13 +135,14 @@ class SpaceToDepthTest(test.TestCase): input_nhwc = array_ops.ones([batch_size, 4, 6, 3]) x_out = array_ops.ones([batch_size, 2, 3, 12]) - with self.session(use_gpu=False): + with test_util.force_cpu(): # test NHWC (default) on CPU x_tf = array_ops.space_to_depth(input_nhwc, block_size) self.assertAllEqual(x_tf.shape, x_out.shape) self.evaluate(x_tf) + if test.is_gpu_available(): - with self.session(use_gpu=True): + with test_util.use_gpu(): # test NHWC (default) on GPU x_tf = array_ops.space_to_depth(input_nhwc, block_size) self.assertAllEqual(x_tf.shape, x_out.shape) diff --git a/tensorflow/python/kernel_tests/unstack_op_test.py b/tensorflow/python/kernel_tests/unstack_op_test.py index 6aea42990a..d314e1eaf9 100644 --- a/tensorflow/python/kernel_tests/unstack_op_test.py +++ b/tensorflow/python/kernel_tests/unstack_op_test.py @@ -41,7 +41,7 @@ class UnstackOpTest(test.TestCase): def testSimple(self): np.random.seed(7) - with self.session(use_gpu=True): + with test_util.use_gpu(): for shape in (2,), (3,), (2, 3), (3, 2), (4, 3, 2): for dtype in [ np.bool, np.float16, np.float32, np.float64, np.int32, np.int64 @@ -53,14 +53,15 @@ class UnstackOpTest(test.TestCase): cs = array_ops.unstack(x, num=shape[0]) self.assertEqual(type(cs), list) self.assertEqual(len(cs), shape[0]) - cs = [c.eval() for c in cs] + cs = [self.evaluate(c) for c in cs] self.assertAllEqual(cs, data) def testSimpleGpu(self): if not test_util.is_gpu_available(): self.skipTest('No GPU available') + np.random.seed(7) - with self.session(use_gpu=True, force_gpu=True): + with test_util.force_gpu(): for shape in (2,), (3,), (2, 3), (3, 2), (4, 3, 2): for dtype in [np.float16, np.float32, np.float64, np.int32, np.int64]: data = np.random.randn(*shape).astype(dtype) @@ -70,7 +71,7 @@ class UnstackOpTest(test.TestCase): cs = array_ops.unstack(x, num=shape[0]) self.assertEqual(type(cs), list) self.assertEqual(len(cs), shape[0]) - cs = [c.eval() for c in cs] + cs = [self.evaluate(c) for c in cs] self.assertAllEqual(cs, data) def testGradientsAxis0(self): @@ -131,15 +132,13 @@ class UnstackOpTest(test.TestCase): for j in range(-i, i): expected = np_split_squeeze(a, j) - with self.cached_session() as sess: - actual_unstack = sess.run(array_ops.unstack(a, axis=j)) + actual_unstack = self.evaluate(array_ops.unstack(a, axis=j)) self.assertAllEqual(expected, actual_unstack) def testAxis0Default(self): - with self.cached_session() as sess: - a = constant_op.constant([[1, 2, 3], [4, 5, 6]], name='a') - unstacked = sess.run(array_ops.unstack(a)) + a = constant_op.constant([[1, 2, 3], [4, 5, 6]], name='a') + unstacked = self.evaluate(array_ops.unstack(a)) self.assertEqual(len(unstacked), 2) self.assertAllEqual(unstacked[0], [1, 2, 3]) @@ -156,10 +155,9 @@ class UnstackOpTest(test.TestCase): array_ops.unstack(a, axis=-3) def testZeroLengthDim(self): - with self.cached_session(): - x = array_ops.zeros(shape=(0, 1, 2)) - y = array_ops.unstack(x, axis=1)[0].eval() - self.assertEqual(y.shape, (0, 2)) + x = array_ops.zeros(shape=(0, 1, 2)) + y = self.evaluate(array_ops.unstack(x, axis=1)[0]) + self.assertEqual(y.shape, (0, 2)) if __name__ == '__main__': diff --git a/tensorflow/python/kernel_tests/zero_division_test.py b/tensorflow/python/kernel_tests/zero_division_test.py index 73ab382e53..7c82f9320a 100644 --- a/tensorflow/python/kernel_tests/zero_division_test.py +++ b/tensorflow/python/kernel_tests/zero_division_test.py @@ -21,13 +21,14 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class ZeroDivisionTest(test.TestCase): def testZeros(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): for dtype in dtypes.uint8, dtypes.int16, dtypes.int32, dtypes.int64: zero = constant_op.constant(0, dtype=dtype) one = constant_op.constant(1, dtype=dtype) diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index 14cc1c6b5a..96b9d6fc0d 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -53,31 +53,29 @@ class ZeroFractionTest(test_lib.TestCase): x_shape = [5, 17] x_np = np.random.randint(0, 2, size=x_shape).astype(np.float32) y_np = self._ZeroFraction(x_np) - with self.cached_session(): - x_tf = constant_op.constant(x_np) - x_tf.set_shape(x_shape) - y_tf = nn_impl.zero_fraction(x_tf) - y_tf_np = self.evaluate(y_tf) + + x_tf = constant_op.constant(x_np) + x_tf.set_shape(x_shape) + y_tf = nn_impl.zero_fraction(x_tf) + y_tf_np = self.evaluate(y_tf) + eps = 1e-8 self.assertAllClose(y_tf_np, y_np, eps) def testZeroFractionEmpty(self): - with self.cached_session(): - x = np.zeros(0) - y = nn_impl.zero_fraction(x).eval() - self.assertTrue(np.isnan(y)) + x = np.zeros(0) + y = self.evaluate(nn_impl.zero_fraction(x)) + self.assertTrue(np.isnan(y)) def testZeroFraction2_27Zeros(self): sparsity = nn_impl.zero_fraction( array_ops.zeros([int(2**27 * 1.01)], dtype=dtypes.int8)) - with self.cached_session(): - self.assertAllClose(1.0, self.evaluate(sparsity)) + self.assertAllClose(1.0, self.evaluate(sparsity)) def testZeroFraction2_27Ones(self): sparsity = nn_impl.zero_fraction( array_ops.ones([int(2**27 * 1.01)], dtype=dtypes.int8)) - with self.cached_session(): - self.assertAllClose(0.0, self.evaluate(sparsity)) + self.assertAllClose(0.0, self.evaluate(sparsity)) def testUnknownSize(self): value = array_ops.placeholder(dtype=dtypes.float32) @@ -302,19 +300,18 @@ class DropoutTest(test_lib.TestCase): y_dim = 30 num_iter = 10 for keep_prob in [0.1, 0.5, 0.8]: - with self.cached_session(): - t = constant_op.constant( - 1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) - dropout = nn_ops.dropout(t, keep_prob) - final_count = 0 - self.assertEqual([x_dim, y_dim], dropout.get_shape()) - for _ in xrange(0, num_iter): - value = self.evaluate(dropout) - final_count += np.count_nonzero(value) - # Verifies that there are only two values: 0 and 1/keep_prob. - sorted_value = np.unique(np.sort(value)) - self.assertEqual(0, sorted_value[0]) - self.assertAllClose(1 / keep_prob, sorted_value[1]) + t = constant_op.constant(1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) + dropout = nn_ops.dropout(t, keep_prob) + final_count = 0 + self.assertEqual([x_dim, y_dim], dropout.get_shape()) + for _ in xrange(0, num_iter): + value = self.evaluate(dropout) + final_count += np.count_nonzero(value) + # Verifies that there are only two values: 0 and 1/keep_prob. + sorted_value = np.unique(np.sort(value)) + self.assertEqual(0, sorted_value[0]) + self.assertAllClose(1 / keep_prob, sorted_value[1]) + # Check that we are in the 15% error range expected_count = x_dim * y_dim * keep_prob * num_iter rel_error = math.fabs(final_count - expected_count) / expected_count @@ -330,19 +327,18 @@ class DropoutTest(test_lib.TestCase): y_dim = 3 num_iter = 10 for keep_prob in [0.1, 0.5, 0.8]: - with self.cached_session(): - t = constant_op.constant( - 1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) - dropout = nn_ops.dropout(t, keep_prob, noise_shape=[x_dim, 1]) - self.assertEqual([x_dim, y_dim], dropout.get_shape()) - final_count = 0 - for _ in xrange(0, num_iter): - value = self.evaluate(dropout) - final_count += np.count_nonzero(value) - # Verifies that there are only two values: 0 and 1/keep_prob. - sorted_value = np.unique(np.sort(value)) - self.assertEqual(0, sorted_value[0]) - self.assertAllClose(1 / keep_prob, sorted_value[1]) + t = constant_op.constant(1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) + dropout = nn_ops.dropout(t, keep_prob, noise_shape=[x_dim, 1]) + self.assertEqual([x_dim, y_dim], dropout.get_shape()) + final_count = 0 + for _ in xrange(0, num_iter): + value = self.evaluate(dropout) + final_count += np.count_nonzero(value) + # Verifies that there are only two values: 0 and 1/keep_prob. + sorted_value = np.unique(np.sort(value)) + self.assertEqual(0, sorted_value[0]) + self.assertAllClose(1 / keep_prob, sorted_value[1]) + # Check that we are in the 15% error range expected_count = x_dim * y_dim * keep_prob * num_iter rel_error = math.fabs(final_count - expected_count) / expected_count @@ -355,17 +351,15 @@ class DropoutTest(test_lib.TestCase): y_dim = 30 num_iter = 10 for keep_prob in [0.1, 0.5, 0.8]: - with self.cached_session(): - t = constant_op.constant( - 1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) - dropout = nn_ops.dropout(t, keep_prob, noise_shape=[x_dim, 1]) - self.assertEqual([x_dim, y_dim], dropout.get_shape()) - for _ in xrange(0, num_iter): - value = self.evaluate(dropout) - # Verifies that each y column as only one type of activation. - for i in xrange(x_dim): - sorted_value = np.unique(np.sort(value[i, :])) - self.assertEqual(sorted_value.size, 1) + t = constant_op.constant(1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) + dropout = nn_ops.dropout(t, keep_prob, noise_shape=[x_dim, 1]) + self.assertEqual([x_dim, y_dim], dropout.get_shape()) + for _ in xrange(0, num_iter): + value = self.evaluate(dropout) + # Verifies that each y column as only one type of activation. + for i in xrange(x_dim): + sorted_value = np.unique(np.sort(value[i, :])) + self.assertEqual(sorted_value.size, 1) def testDropoutPlaceholderKeepProb(self): # Runs dropout with 0-1 tensor 10 times, sum the number of ones and validate @@ -409,20 +403,19 @@ class DropoutTest(test_lib.TestCase): y_dim = 3 num_iter = 10 for keep_prob in [0.1, 0.5, 0.8]: - with self.cached_session(): - t = constant_op.constant( - 1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) - # Set noise_shape=[None, 1] which means [x_dim, 1]. - dropout = nn_ops.dropout(t, keep_prob, noise_shape=[None, 1]) - self.assertEqual([x_dim, y_dim], dropout.get_shape()) - final_count = 0 - for _ in xrange(0, num_iter): - value = self.evaluate(dropout) - final_count += np.count_nonzero(value) - # Verifies that there are only two values: 0 and 1/keep_prob. - sorted_value = np.unique(np.sort(value)) - self.assertEqual(0, sorted_value[0]) - self.assertAllClose(1 / keep_prob, sorted_value[1]) + t = constant_op.constant(1.0, shape=[x_dim, y_dim], dtype=dtypes.float32) + # Set noise_shape=[None, 1] which means [x_dim, 1]. + dropout = nn_ops.dropout(t, keep_prob, noise_shape=[None, 1]) + self.assertEqual([x_dim, y_dim], dropout.get_shape()) + final_count = 0 + for _ in xrange(0, num_iter): + value = self.evaluate(dropout) + final_count += np.count_nonzero(value) + # Verifies that there are only two values: 0 and 1/keep_prob. + sorted_value = np.unique(np.sort(value)) + self.assertEqual(0, sorted_value[0]) + self.assertAllClose(1 / keep_prob, sorted_value[1]) + # Check that we are in the 15% error range expected_count = x_dim * y_dim * keep_prob * num_iter rel_error = math.fabs(final_count - expected_count) / expected_count @@ -563,78 +556,78 @@ class ComputeSampledLogitsTest(test_lib.TestCase): initializer=constant_op.constant(biases)) with self.session(graph=g) as sess: variables.global_variables_initializer().run() - return sess.run([list(sharded_weights), list(sharded_biases)]) + return self.evaluate([list(sharded_weights), list(sharded_biases)]) def testShapes(self): np.random.seed(0) num_classes = 5 batch_size = 3 - with self.cached_session() as sess: - for num_true in range(1, 5): - labels = np.random.randint( - low=0, high=num_classes, size=batch_size * num_true) - (weights, biases, hidden_acts, sampled_vals, exp_logits, - exp_labels) = self._GenerateTestData( - num_classes=num_classes, - dim=10, - batch_size=batch_size, - num_true=num_true, - labels=labels, - sampled=[1, 0, 2, 3], - subtract_log_q=False) - logits_tensor, labels_tensor = _compute_sampled_logits( - weights=constant_op.constant(weights), - biases=constant_op.constant(biases), - labels=constant_op.constant( - labels, dtype=dtypes.int64, shape=(batch_size, num_true)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=num_true, - sampled_values=sampled_vals, - subtract_log_q=False, - remove_accidental_hits=False, - partition_strategy="div", - name="sampled_logits_basic_num_true_%d" % num_true) - got_logits, got_labels = sess.run([logits_tensor, labels_tensor]) - self.assertEqual(exp_logits.shape, got_logits.shape, self._eps) - self.assertEqual(exp_labels.shape, got_labels.shape, self._eps) + + for num_true in range(1, 5): + labels = np.random.randint( + low=0, high=num_classes, size=batch_size * num_true) + (weights, biases, hidden_acts, sampled_vals, exp_logits, + exp_labels) = self._GenerateTestData( + num_classes=num_classes, + dim=10, + batch_size=batch_size, + num_true=num_true, + labels=labels, + sampled=[1, 0, 2, 3], + subtract_log_q=False) + logits_tensor, labels_tensor = _compute_sampled_logits( + weights=constant_op.constant(weights), + biases=constant_op.constant(biases), + labels=constant_op.constant( + labels, dtype=dtypes.int64, shape=(batch_size, num_true)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=num_true, + sampled_values=sampled_vals, + subtract_log_q=False, + remove_accidental_hits=False, + partition_strategy="div", + name="sampled_logits_basic_num_true_%d" % num_true) + got_logits, got_labels = self.evaluate([logits_tensor, labels_tensor]) + self.assertEqual(exp_logits.shape, got_logits.shape, self._eps) + self.assertEqual(exp_labels.shape, got_labels.shape, self._eps) def testBasic(self): """Without accidental hit removal or subtract_log_q.""" np.random.seed(0) num_classes = 5 batch_size = 3 - with self.cached_session() as sess: - for num_true in range(1, 5): - labels = np.random.randint( - low=0, high=num_classes, size=batch_size * num_true) - (weights, biases, hidden_acts, sampled_vals, exp_logits, - exp_labels) = self._GenerateTestData( - num_classes=num_classes, - dim=10, - batch_size=batch_size, - num_true=num_true, - labels=labels, - sampled=[1, 0, 2, 3], - subtract_log_q=False) - logits_tensor, labels_tensor = _compute_sampled_logits( - weights=constant_op.constant(weights), - biases=constant_op.constant(biases), - labels=constant_op.constant( - labels, dtype=dtypes.int64, shape=(batch_size, num_true)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=num_true, - sampled_values=sampled_vals, - subtract_log_q=False, - remove_accidental_hits=False, - partition_strategy="div", - name="sampled_logits_basic_num_true_%d" % num_true) - got_logits, got_labels = sess.run([logits_tensor, labels_tensor]) - self.assertAllClose(exp_logits, got_logits, self._eps) - self.assertAllClose(exp_labels, got_labels, self._eps) + + for num_true in range(1, 5): + labels = np.random.randint( + low=0, high=num_classes, size=batch_size * num_true) + (weights, biases, hidden_acts, sampled_vals, exp_logits, + exp_labels) = self._GenerateTestData( + num_classes=num_classes, + dim=10, + batch_size=batch_size, + num_true=num_true, + labels=labels, + sampled=[1, 0, 2, 3], + subtract_log_q=False) + logits_tensor, labels_tensor = _compute_sampled_logits( + weights=constant_op.constant(weights), + biases=constant_op.constant(biases), + labels=constant_op.constant( + labels, dtype=dtypes.int64, shape=(batch_size, num_true)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=num_true, + sampled_values=sampled_vals, + subtract_log_q=False, + remove_accidental_hits=False, + partition_strategy="div", + name="sampled_logits_basic_num_true_%d" % num_true) + got_logits, got_labels = self.evaluate([logits_tensor, labels_tensor]) + self.assertAllClose(exp_logits, got_logits, self._eps) + self.assertAllClose(exp_labels, got_labels, self._eps) def testAccidentalHitRemoval(self): """With accidental hit removal, no subtract_log_q.""" @@ -642,118 +635,118 @@ class ComputeSampledLogitsTest(test_lib.TestCase): num_classes = 5 batch_size = 3 sampled = [1, 0, 2, 3] - with self.cached_session(): - for num_true in range(1, 5): - labels = np.random.randint( - low=0, high=num_classes, size=batch_size * num_true) - (weights, biases, hidden_acts, sampled_vals, _, - _) = self._GenerateTestData( - num_classes=num_classes, - dim=10, - batch_size=batch_size, - num_true=num_true, - labels=labels, - sampled=sampled, - subtract_log_q=False) - logits_tensor, _ = _compute_sampled_logits( - weights=constant_op.constant(weights), - biases=constant_op.constant(biases), - labels=constant_op.constant( - labels, dtype=dtypes.int64, shape=(batch_size, num_true)), - inputs=constant_op.constant(hidden_acts), - num_sampled=len(sampled), - num_classes=num_classes, - num_true=num_true, - sampled_values=sampled_vals, - subtract_log_q=False, - remove_accidental_hits=True, - partition_strategy="div", - name="sampled_logits_accidental_hit_removal_num_true_%d" % num_true) - # Test that the exponentiated logits of accidental hits are near 0. - # First we need to find the hits in this random test run: - labels_reshape = labels.reshape((batch_size, num_true)) - got_logits = self.evaluate(logits_tensor) - for row in xrange(batch_size): - row_labels = labels_reshape[row, :] - for col in xrange(len(sampled)): - if sampled[col] in row_labels: - # We need to add the num_true_test offset into logits_* - self.assertNear( - np.exp(got_logits[row, col + num_true]), 0., self._eps) + + for num_true in range(1, 5): + labels = np.random.randint( + low=0, high=num_classes, size=batch_size * num_true) + (weights, biases, hidden_acts, sampled_vals, _, + _) = self._GenerateTestData( + num_classes=num_classes, + dim=10, + batch_size=batch_size, + num_true=num_true, + labels=labels, + sampled=sampled, + subtract_log_q=False) + logits_tensor, _ = _compute_sampled_logits( + weights=constant_op.constant(weights), + biases=constant_op.constant(biases), + labels=constant_op.constant( + labels, dtype=dtypes.int64, shape=(batch_size, num_true)), + inputs=constant_op.constant(hidden_acts), + num_sampled=len(sampled), + num_classes=num_classes, + num_true=num_true, + sampled_values=sampled_vals, + subtract_log_q=False, + remove_accidental_hits=True, + partition_strategy="div", + name="sampled_logits_accidental_hit_removal_num_true_%d" % num_true) + # Test that the exponentiated logits of accidental hits are near 0. + # First we need to find the hits in this random test run: + labels_reshape = labels.reshape((batch_size, num_true)) + got_logits = self.evaluate(logits_tensor) + for row in xrange(batch_size): + row_labels = labels_reshape[row, :] + for col in xrange(len(sampled)): + if sampled[col] in row_labels: + # We need to add the num_true_test offset into logits_* + self.assertNear( + np.exp(got_logits[row, col + num_true]), 0., self._eps) def testSubtractLogQ(self): """With subtract_log_q, no accidental hit removal.""" np.random.seed(0) num_classes = 5 batch_size = 3 - with self.cached_session() as sess: - for num_true in range(1, 5): - labels = np.random.randint( - low=0, high=num_classes, size=batch_size * num_true) - (weights, biases, hidden_acts, sampled_vals, exp_logits, - exp_labels) = self._GenerateTestData( - num_classes=num_classes, - dim=10, - batch_size=batch_size, - num_true=num_true, - labels=labels, - sampled=[1, 0, 2, 3], - subtract_log_q=True) - logits_tensor, labels_tensor = _compute_sampled_logits( - weights=constant_op.constant(weights), - biases=constant_op.constant(biases), - labels=constant_op.constant( - labels, dtype=dtypes.int64, shape=(batch_size, num_true)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=num_true, - sampled_values=sampled_vals, - subtract_log_q=True, - remove_accidental_hits=False, - partition_strategy="div", - name="sampled_logits_subtract_log_q_num_true_%d" % num_true) - got_logits, got_labels = sess.run([logits_tensor, labels_tensor]) - self.assertAllClose(exp_logits, got_logits, self._eps) - self.assertAllClose(exp_labels, got_labels, self._eps) + + for num_true in range(1, 5): + labels = np.random.randint( + low=0, high=num_classes, size=batch_size * num_true) + (weights, biases, hidden_acts, sampled_vals, exp_logits, + exp_labels) = self._GenerateTestData( + num_classes=num_classes, + dim=10, + batch_size=batch_size, + num_true=num_true, + labels=labels, + sampled=[1, 0, 2, 3], + subtract_log_q=True) + logits_tensor, labels_tensor = _compute_sampled_logits( + weights=constant_op.constant(weights), + biases=constant_op.constant(biases), + labels=constant_op.constant( + labels, dtype=dtypes.int64, shape=(batch_size, num_true)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=num_true, + sampled_values=sampled_vals, + subtract_log_q=True, + remove_accidental_hits=False, + partition_strategy="div", + name="sampled_logits_subtract_log_q_num_true_%d" % num_true) + got_logits, got_labels = self.evaluate([logits_tensor, labels_tensor]) + self.assertAllClose(exp_logits, got_logits, self._eps) + self.assertAllClose(exp_labels, got_labels, self._eps) def testSharded(self): """With sharded weights and sharded biases.""" np.random.seed(0) num_classes = 5 batch_size = 3 - with self.cached_session() as sess: - for num_true in range(1, 5): - labels = np.random.randint( - low=0, high=num_classes, size=batch_size * num_true) - (weights, biases, hidden_acts, sampled_vals, exp_logits, - exp_labels) = self._GenerateTestData( - num_classes=num_classes, - dim=10, - batch_size=batch_size, - num_true=num_true, - labels=labels, - sampled=[1, 0, 2, 3], - subtract_log_q=False) - weight_shards, bias_shards = self._ShardTestEmbeddings( - weights, biases, num_shards=3) - logits_tensor, labels_tensor = _compute_sampled_logits( - weights=[constant_op.constant(shard) for shard in weight_shards], - biases=[constant_op.constant(shard) for shard in bias_shards], - labels=constant_op.constant( - labels, dtype=dtypes.int64, shape=(batch_size, num_true)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=num_true, - sampled_values=sampled_vals, - subtract_log_q=False, - remove_accidental_hits=False, - partition_strategy="div", - name="sampled_logits_sharded_num_true_%d" % num_true) - got_logits, got_labels = sess.run([logits_tensor, labels_tensor]) - self.assertAllClose(exp_logits, got_logits, self._eps) - self.assertAllClose(exp_labels, got_labels, self._eps) + + for num_true in range(1, 5): + labels = np.random.randint( + low=0, high=num_classes, size=batch_size * num_true) + (weights, biases, hidden_acts, sampled_vals, exp_logits, + exp_labels) = self._GenerateTestData( + num_classes=num_classes, + dim=10, + batch_size=batch_size, + num_true=num_true, + labels=labels, + sampled=[1, 0, 2, 3], + subtract_log_q=False) + weight_shards, bias_shards = self._ShardTestEmbeddings( + weights, biases, num_shards=3) + logits_tensor, labels_tensor = _compute_sampled_logits( + weights=[constant_op.constant(shard) for shard in weight_shards], + biases=[constant_op.constant(shard) for shard in bias_shards], + labels=constant_op.constant( + labels, dtype=dtypes.int64, shape=(batch_size, num_true)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=num_true, + sampled_values=sampled_vals, + subtract_log_q=False, + remove_accidental_hits=False, + partition_strategy="div", + name="sampled_logits_sharded_num_true_%d" % num_true) + got_logits, got_labels = self.evaluate([logits_tensor, labels_tensor]) + self.assertAllClose(exp_logits, got_logits, self._eps) + self.assertAllClose(exp_labels, got_labels, self._eps) def testNCELoss(self): # A simple test to verify the numerics. @@ -782,35 +775,34 @@ class ComputeSampledLogitsTest(test_lib.TestCase): exp_nce_loss = np.sum( _SigmoidCrossEntropyWithLogits(exp_logits, exp_labels), 1) - with self.cached_session(): - got_nce_loss = nn_impl.nce_loss( - weights=constant_op.constant(weights), - biases=constant_op.constant(biases), - labels=constant_op.constant(labels, shape=(batch_size, 1)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=1, - sampled_values=sampled_vals, - partition_strategy="div") - - self.assertAllClose(exp_nce_loss, self.evaluate(got_nce_loss), 1e-4) - - # Test with sharded weights and sharded biases. - weight_shards, bias_shards = self._ShardTestEmbeddings( - weights, biases, num_shards=3) - got_nce_loss = nn_impl.nce_loss( - weights=[constant_op.constant(shard) for shard in weight_shards], - biases=[constant_op.constant(shard) for shard in bias_shards], - labels=constant_op.constant(labels, shape=(batch_size, 1)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=1, - sampled_values=sampled_vals, - partition_strategy="div") - - self.assertAllClose(exp_nce_loss, self.evaluate(got_nce_loss), 1e-4) + got_nce_loss = nn_impl.nce_loss( + weights=constant_op.constant(weights), + biases=constant_op.constant(biases), + labels=constant_op.constant(labels, shape=(batch_size, 1)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=1, + sampled_values=sampled_vals, + partition_strategy="div") + + self.assertAllClose(exp_nce_loss, self.evaluate(got_nce_loss), 1e-4) + + # Test with sharded weights and sharded biases. + weight_shards, bias_shards = self._ShardTestEmbeddings( + weights, biases, num_shards=3) + got_nce_loss = nn_impl.nce_loss( + weights=[constant_op.constant(shard) for shard in weight_shards], + biases=[constant_op.constant(shard) for shard in bias_shards], + labels=constant_op.constant(labels, shape=(batch_size, 1)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=1, + sampled_values=sampled_vals, + partition_strategy="div") + + self.assertAllClose(exp_nce_loss, self.evaluate(got_nce_loss), 1e-4) def testSampledSoftmaxLoss(self): # A simple test to verify the numerics. @@ -839,39 +831,38 @@ class ComputeSampledLogitsTest(test_lib.TestCase): exp_sampled_softmax_loss = _SoftmaxCrossEntropyWithLogits( exp_logits, exp_labels) - with self.cached_session(): - got_sampled_softmax_loss = nn_impl.sampled_softmax_loss( - weights=constant_op.constant(weights), - biases=constant_op.constant(biases), - labels=constant_op.constant(labels, shape=(batch_size, 1)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=1, - sampled_values=sampled_vals, - remove_accidental_hits=False, - partition_strategy="div") - - self.assertAllClose(exp_sampled_softmax_loss, - self.evaluate(got_sampled_softmax_loss), 1e-4) - - # Test with sharded weights and sharded biases. - weight_shards, bias_shards = self._ShardTestEmbeddings( - weights, biases, num_shards=3) - got_sampled_softmax_loss = nn_impl.sampled_softmax_loss( - weights=[constant_op.constant(shard) for shard in weight_shards], - biases=[constant_op.constant(shard) for shard in bias_shards], - labels=constant_op.constant(labels, shape=(batch_size, 1)), - inputs=constant_op.constant(hidden_acts), - num_sampled=4, - num_classes=num_classes, - num_true=1, - sampled_values=sampled_vals, - remove_accidental_hits=False, - partition_strategy="div") - - self.assertAllClose(exp_sampled_softmax_loss, - self.evaluate(got_sampled_softmax_loss), 1e-4) + got_sampled_softmax_loss = nn_impl.sampled_softmax_loss( + weights=constant_op.constant(weights), + biases=constant_op.constant(biases), + labels=constant_op.constant(labels, shape=(batch_size, 1)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=1, + sampled_values=sampled_vals, + remove_accidental_hits=False, + partition_strategy="div") + + self.assertAllClose(exp_sampled_softmax_loss, + self.evaluate(got_sampled_softmax_loss), 1e-4) + + # Test with sharded weights and sharded biases. + weight_shards, bias_shards = self._ShardTestEmbeddings( + weights, biases, num_shards=3) + got_sampled_softmax_loss = nn_impl.sampled_softmax_loss( + weights=[constant_op.constant(shard) for shard in weight_shards], + biases=[constant_op.constant(shard) for shard in bias_shards], + labels=constant_op.constant(labels, shape=(batch_size, 1)), + inputs=constant_op.constant(hidden_acts), + num_sampled=4, + num_classes=num_classes, + num_true=1, + sampled_values=sampled_vals, + remove_accidental_hits=False, + partition_strategy="div") + + self.assertAllClose(exp_sampled_softmax_loss, + self.evaluate(got_sampled_softmax_loss), 1e-4) def testSampledSoftmaxLossBf16(self): # A simple test to verify the numerics for bfloat16. @@ -900,29 +891,30 @@ class ComputeSampledLogitsTest(test_lib.TestCase): exp_sampled_softmax_loss = _SoftmaxCrossEntropyWithLogits( exp_logits, exp_labels) - with self.cached_session(): - true_exp_bf16 = np.full( - [batch_size, 1], fill_value=0.5, dtype=dtypes.bfloat16.as_numpy_dtype) - sampled_exp_bf16 = np.full( - [len(sampled)], fill_value=0.5, dtype=dtypes.bfloat16.as_numpy_dtype) - sampled_vals_bf16 = (sampled, true_exp_bf16, sampled_exp_bf16) - - got_sampled_softmax_loss = math_ops.cast( - nn_impl.sampled_softmax_loss( - weights=constant_op.constant(weights, dtype=dtypes.bfloat16), - biases=constant_op.constant(biases, dtype=dtypes.bfloat16), - labels=constant_op.constant( - labels, shape=(batch_size, 1), dtype=dtypes.bfloat16), - inputs=constant_op.constant(hidden_acts, dtype=dtypes.bfloat16), - num_sampled=4, - num_classes=num_classes, - num_true=1, - sampled_values=sampled_vals_bf16, - remove_accidental_hits=False, - partition_strategy="div"), dtypes.float32) - - self.assertAllClose(exp_sampled_softmax_loss, - self.evaluate(got_sampled_softmax_loss), 1e-1) + true_exp_bf16 = np.full([batch_size, 1], + fill_value=0.5, + dtype=dtypes.bfloat16.as_numpy_dtype) + sampled_exp_bf16 = np.full([len(sampled)], + fill_value=0.5, + dtype=dtypes.bfloat16.as_numpy_dtype) + sampled_vals_bf16 = (sampled, true_exp_bf16, sampled_exp_bf16) + + got_sampled_softmax_loss = math_ops.cast( + nn_impl.sampled_softmax_loss( + weights=constant_op.constant(weights, dtype=dtypes.bfloat16), + biases=constant_op.constant(biases, dtype=dtypes.bfloat16), + labels=constant_op.constant( + labels, shape=(batch_size, 1), dtype=dtypes.bfloat16), + inputs=constant_op.constant(hidden_acts, dtype=dtypes.bfloat16), + num_sampled=4, + num_classes=num_classes, + num_true=1, + sampled_values=sampled_vals_bf16, + remove_accidental_hits=False, + partition_strategy="div"), dtypes.float32) + + self.assertAllClose(exp_sampled_softmax_loss, + self.evaluate(got_sampled_softmax_loss), 1e-1) class CReluTest(test_lib.TestCase): @@ -931,9 +923,9 @@ class CReluTest(test_lib.TestCase): np.random.seed(1) # Make it reproducible. x = np.random.randn(3, 4).astype(np.float32) y = np.concatenate([x * (x > 0), -x * (x < 0)], axis=1) - with self.cached_session(): - z = nn_ops.crelu(constant_op.constant(x)).eval() - self.assertAllClose(y, z, 1e-4) + + z = self.evaluate(nn_ops.crelu(constant_op.constant(x))) + self.assertAllClose(y, z, 1e-4) class ReluTest(test_lib.TestCase): @@ -942,9 +934,9 @@ class ReluTest(test_lib.TestCase): np.random.seed(1) # Make it reproducible. x = np.random.randn(3, 4).astype(np.float32) y = np.maximum(x, 0.0) - with self.cached_session(): - z = nn_ops.relu(constant_op.constant(x)).eval() - self.assertAllEqual(y, z) + + z = self.evaluate(nn_ops.relu(constant_op.constant(x))) + self.assertAllEqual(y, z) def testNaNs(self): # Test that relu(nan) = nan for various sizes. @@ -967,8 +959,9 @@ class LeakyReluTest(test_lib.TestCase): outputs = nn_ops.leaky_relu(inputs) self.assertEquals(inputs.shape, outputs.shape) - with self.cached_session() as sess: - inputs, outputs = sess.run([inputs, outputs]) + + inputs, outputs = self.evaluate([inputs, outputs]) + self.assertGreaterEqual(outputs.min(), 0.0) self.assertLessEqual(outputs.max(), 1.0) self.assertAllClose(inputs, outputs) @@ -977,8 +970,9 @@ class LeakyReluTest(test_lib.TestCase): for dtype in [np.int32, np.int64, np.float16, np.float32, np.float64]: np_values = np.array([-2, -1, 0, 1, 2], dtype=dtype) outputs = nn_ops.leaky_relu(constant_op.constant(np_values)) - with self.cached_session() as sess: - outputs = self.evaluate(outputs) + + outputs = self.evaluate(outputs) + tol = 2e-3 if dtype == np.float16 else 1e-6 self.assertAllClose( outputs, [-0.4, -0.2, 0.0, 1.0, 2.0], rtol=tol, atol=tol) @@ -1004,9 +998,10 @@ class SwishTest(test_lib.TestCase): tf_values = constant_op.constant(np_values) actual_tf_outputs = nn_impl.swish(tf_values) expected_tf_outputs = tf_values * math_ops.sigmoid(tf_values) - with self.cached_session() as sess: - actual_outputs, expected_outputs = sess.run( - [actual_tf_outputs, expected_tf_outputs]) + + actual_outputs, expected_outputs = self.evaluate( + [actual_tf_outputs, expected_tf_outputs]) + self.assertAllClose(actual_outputs, expected_outputs) def testGradients(self): @@ -1051,7 +1046,7 @@ class MomentsTest(test_lib.TestCase): self.assertLess(err, 1e-3) # Evaluate. - [mean, variance] = sess.run([mean, variance]) + [mean, variance] = self.evaluate([mean, variance]) # Make sure that there are no NaNs self.assertFalse(np.isnan(mean).any()) self.assertFalse(np.isnan(variance).any()) @@ -1094,9 +1089,9 @@ class DataFormatDimMapTest(test_lib.TestCase): def _test(self, x_val, y_val_expected): x = constant_op.constant(x_val) y = nn_ops.data_format_dim_map(x) - with self.cached_session(use_gpu=test_lib.is_gpu_available()) as sess: - y_val = self.evaluate(y) - self.assertAllEqual(y_val, y_val_expected) + + y_val = self.evaluate(y) + self.assertAllEqual(y_val, y_val_expected) def test(self): self._test(0, 0) @@ -1117,7 +1112,7 @@ class DataFormatDimMapTest(test_lib.TestCase): y_val_expected = [2, 2, 3] x = constant_op.constant(x_val) y = nn_ops.data_format_dim_map(x, src_format="NHWC", dst_format="NCHW") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, y_val_expected) @@ -1126,7 +1121,7 @@ class DataFormatDimMapTest(test_lib.TestCase): y_val_expected = [2, 0, 1, 3, 2, 0, 1, 3] x = constant_op.constant(x_val) y = nn_ops.data_format_dim_map(x, src_format="NHWC", dst_format="HWNC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, y_val_expected) @@ -1135,7 +1130,7 @@ class DataFormatDimMapTest(test_lib.TestCase): y_val_expected = [3, 1, 0, 2, 3, 1, 0, 2] x = constant_op.constant(x_val) y = nn_ops.data_format_dim_map(x, src_format="NHWC", dst_format="WHCN") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, y_val_expected) @@ -1144,7 +1139,7 @@ class DataFormatDimMapTest(test_lib.TestCase): y_val_expected = [3, 2, 1, 0, 3, 2, 1, 0] x = constant_op.constant(x_val) y = nn_ops.data_format_dim_map(x, src_format="qwer", dst_format="rewq") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, y_val_expected) @@ -1155,7 +1150,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [7, 4, 9, 3] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x) - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [7, 3, 4, 9]) @@ -1163,7 +1158,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [7, 4, 9, 3] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x, src_format="NCHW", dst_format="NHWC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [7, 9, 3, 4]) @@ -1171,7 +1166,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [7, 4, 9, 3] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x, src_format="NHWC", dst_format="HWNC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [4, 9, 7, 3]) @@ -1179,7 +1174,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [7, 4, 9, 3] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x, src_format="HWNC", dst_format="NHWC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [9, 7, 4, 3]) @@ -1187,7 +1182,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [[7, 4], [9, 3], [4, 5], [5, 1]] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x) - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [[7, 4], [5, 1], [9, 3], [4, 5]]) @@ -1195,7 +1190,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [[7, 4], [9, 3], [4, 5], [5, 1]] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x, src_format="NHWC", dst_format="HWNC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [[9, 3], [4, 5], [7, 4], [5, 1]]) @@ -1203,7 +1198,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [[7, 4], [9, 3], [4, 5], [5, 1]] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x, src_format="HWNC", dst_format="NHWC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [[4, 5], [7, 4], [9, 3], [5, 1]]) @@ -1211,7 +1206,7 @@ class DataFormatVectorPermuteTest(test_lib.TestCase): x_val = [[7, 4], [9, 3], [4, 5], [5, 1]] x = constant_op.constant(x_val) y = nn_ops.data_format_vec_permute(x, src_format="NCHW", dst_format="NHWC") - with self.session(use_gpu=test_lib.is_gpu_available()) as sess: + with test_util.use_gpu(): y_val = self.evaluate(y) self.assertAllEqual(y_val, [[7, 4], [4, 5], [5, 1], [9, 3]]) diff --git a/tensorflow/python/training/rmsprop_test.py b/tensorflow/python/training/rmsprop_test.py index 9ec315f62d..a9b8954e39 100644 --- a/tensorflow/python/training/rmsprop_test.py +++ b/tensorflow/python/training/rmsprop_test.py @@ -28,6 +28,7 @@ from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -92,7 +93,7 @@ class RMSPropOptimizerTest(test.TestCase): # TODO(yori): Use ParameterizedTest when available for (dtype, learning_rate, decay, momentum, epsilon, centered, use_resource) in _TESTPARAMS: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): # Initialize variables for numpy implementation. var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) grads0_np = np.array([0.1, 0.2], dtype=dtype.as_numpy_dtype) @@ -115,7 +116,7 @@ class RMSPropOptimizerTest(test.TestCase): centered=centered) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) mg0 = opt.get_slot(var0, "mg") self.assertEqual(mg0 is not None, centered) @@ -143,7 +144,7 @@ class RMSPropOptimizerTest(test.TestCase): # Run 4 steps of RMSProp for _ in range(1, 5): - update.run() + self.evaluate(update) var0_np, mg0_np, rms0_np, mom0_np = self._rmsprop_update_numpy( var0_np, grads0_np, mg0_np, rms0_np, mom0_np, learning_rate, @@ -176,11 +177,11 @@ class RMSPropOptimizerTest(test.TestCase): momentum=0.0, epsilon=0.0, centered=False).minimize(loss) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) # Fetch params to validate initial values self.assertAllCloseAccordingToType([[1.0, 2.0]], self.evaluate(var0)) # Run 1 step of sgd - sgd_op.run() + self.evaluate(sgd_op) # Validate updated params self.assertAllCloseAccordingToType([[0., 1.]], self.evaluate(var0), @@ -199,11 +200,11 @@ class RMSPropOptimizerTest(test.TestCase): momentum=0.0, epsilon=1.0, centered=True).minimize(loss) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) # Fetch params to validate initial values self.assertAllCloseAccordingToType([[1.0, 2.0]], self.evaluate(var0)) # Run 1 step of sgd - sgd_op.run() + self.evaluate(sgd_op) # Validate updated params self.assertAllCloseAccordingToType([[-111, -138]], self.evaluate(var0), @@ -213,7 +214,7 @@ class RMSPropOptimizerTest(test.TestCase): # TODO(yori): Use ParameterizedTest when available for (dtype, learning_rate, decay, momentum, epsilon, centered, _) in _TESTPARAMS: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): # Initialize variables for numpy implementation. var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) grads0_np = np.array([0.1], dtype=dtype.as_numpy_dtype) @@ -237,7 +238,7 @@ class RMSPropOptimizerTest(test.TestCase): epsilon=epsilon, centered=centered) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) mg0 = opt.get_slot(var0, "mg") self.assertEqual(mg0 is not None, centered) @@ -265,7 +266,7 @@ class RMSPropOptimizerTest(test.TestCase): # Run 4 steps of RMSProp for _ in range(1, 5): - update.run() + self.evaluate(update) var0_np, mg0_np, rms0_np, mom0_np = self._sparse_rmsprop_update_numpy( var0_np, grads0_np_indices, grads0_np, mg0_np, rms0_np, mom0_np, @@ -287,7 +288,7 @@ class RMSPropOptimizerTest(test.TestCase): def testWithoutMomentum(self): for dtype in [dtypes.half, dtypes.float32]: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): var0 = variables.Variable([1.0, 2.0], dtype=dtype) var1 = variables.Variable([3.0, 4.0], dtype=dtype) grads0 = constant_op.constant([0.1, 0.1], dtype=dtype) @@ -295,7 +296,7 @@ class RMSPropOptimizerTest(test.TestCase): opt = rmsprop.RMSPropOptimizer( learning_rate=2.0, decay=0.9, momentum=0.0, epsilon=1.0) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) rms0 = opt.get_slot(var0, "rms") self.assertTrue(rms0 is not None) @@ -311,7 +312,7 @@ class RMSPropOptimizerTest(test.TestCase): self.assertAllClose([3.0, 4.0], self.evaluate(var1)) # Step 1: the rms accumulators where 1. So we should see a normal # update: v -= grad * learning_rate - update.run() + self.evaluate(update) # Check the root mean square accumulators. self.assertAllCloseAccordingToType( np.array([0.901, 0.901]), self.evaluate(rms0)) @@ -329,7 +330,7 @@ class RMSPropOptimizerTest(test.TestCase): 4.0 - (0.01 * 2.0 / math.sqrt(0.90001 + 1.0)) ]), self.evaluate(var1)) # Step 2: the root mean square accumulators contain the previous update. - update.run() + self.evaluate(update) # Check the rms accumulators. self.assertAllCloseAccordingToType( np.array([0.901 * 0.9 + 0.001, 0.901 * 0.9 + 0.001]), @@ -355,7 +356,7 @@ class RMSPropOptimizerTest(test.TestCase): def testWithMomentum(self): for dtype in [dtypes.half, dtypes.float32]: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): var0 = variables.Variable([1.0, 2.0], dtype=dtype) var1 = variables.Variable([3.0, 4.0], dtype=dtype) grads0 = constant_op.constant([0.1, 0.1], dtype=dtype) @@ -364,7 +365,7 @@ class RMSPropOptimizerTest(test.TestCase): opt = rmsprop.RMSPropOptimizer( learning_rate=2.0, decay=0.9, momentum=0.5, epsilon=1e-5) update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) rms0 = opt.get_slot(var0, "rms") self.assertTrue(rms0 is not None) @@ -380,7 +381,7 @@ class RMSPropOptimizerTest(test.TestCase): self.assertAllClose([3.0, 4.0], self.evaluate(var1)) # Step 1: rms = 1, mom = 0. So we should see a normal # update: v -= grad * learning_rate - update.run() + self.evaluate(update) # Check the root mean square accumulators. self.assertAllCloseAccordingToType( np.array([0.901, 0.901]), self.evaluate(rms0)) @@ -409,7 +410,7 @@ class RMSPropOptimizerTest(test.TestCase): ]), self.evaluate(var1)) # Step 2: the root mean square accumulators contain the previous update. - update.run() + self.evaluate(update) # Check the rms accumulators. self.assertAllCloseAccordingToType( np.array([0.901 * 0.9 + 0.001, 0.901 * 0.9 + 0.001]), -- GitLab From f5dd35d63187e697be79585d7bf8df6fe0436231 Mon Sep 17 00:00:00 2001 From: Pooya Davoodi Date: Tue, 20 Nov 2018 17:56:24 -0800 Subject: [PATCH 175/672] TFTRT: fix pylint and some clang-format There are more clang-format issues that need to be addressed. --- .../contrib/tensorrt/convert/convert_graph.cc | 21 +++++++------- .../contrib/tensorrt/convert/convert_nodes.cc | 28 +++++++++---------- .../contrib/tensorrt/kernels/trt_engine_op.cc | 5 ++-- .../tensorrt/python/trt_convert_test.py | 3 +- .../tensorrt/resources/trt_resources.h | 3 +- .../contrib/tensorrt/segment/segment.cc | 17 ++++++----- .../tensorrt/test/reshape_transpose_test.py | 2 +- 7 files changed, 39 insertions(+), 40 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index bc82b3c0f0..fa36fa377b 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -226,12 +226,12 @@ tensorflow::Status ConvertGraphDefToTensorRT( item.fetch = output_names; item.graph = graph_def; - // TODO(aaroey): we should have used single machine cluster like the - // following, but the problem is then wrap_conversion will depend on - // direct_session and cause double linking problems. To fix this we need to - // fix or get rid of the swig dependency. Here we use VirtualCluster - // as a work around, and we need to create a session to initialize the - // underlying device before calling this method. +// TODO(aaroey): we should have used single machine cluster like the +// following, but the problem is then wrap_conversion will depend on +// direct_session and cause double linking problems. To fix this we need to +// fix or get rid of the swig dependency. Here we use VirtualCluster +// as a work around, and we need to create a session to initialize the +// underlying device before calling this method. #if 0 // Create single machine cluster. Note that this will create a session and // initialize the gpu devices. @@ -869,9 +869,8 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { tensorflow::tensorrt::segment::SegmentNodesVector initial_segments; TrtCandidateSelector candidate_selector(*params.graph_properties); TF_RETURN_IF_ERROR(tensorrt::segment::SegmentGraph( - &graph, - std::bind(&TrtCandidateSelector::IsTensorRTCandidate, &candidate_selector, - std::placeholders::_1), + &graph, std::bind(&TrtCandidateSelector::IsTensorRTCandidate, + &candidate_selector, std::placeholders::_1), // Input validation is already done by TrtCandidateSelector, so we don't // need to check the input edges. [](const Edge* edge) { return true; }, OutputEdgeValidator(), @@ -970,8 +969,8 @@ tensorflow::Status ConvertAfterShapes(ConversionParams& params) { &graph, alloc.get(), &engine_nodes); // If status is ok, we successfully added the node to the graph and can // remove segment ops. Otherwise graph is not modified. - string msg = StrCat("TensorRT node ", engine.engine_name, " added for segment ", - i, " consisting of ", + string msg = StrCat("TensorRT node ", engine.engine_name, + " added for segment ", i, " consisting of ", converted_segments.at(i).first.size(), " nodes"); if (status.ok()) { LOG(INFO) << msg << " succeeded."; diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 0e4dca5960..7c53c6b4bb 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -405,8 +405,8 @@ size_t TRT_ShapedWeights::size_bytes() const { string TRT_ShapedWeights::DebugString() const { return StrCat("TRT_ShapedWeights(shape=", convert::DebugString(shape_), - ", type=", DataTypeString(type_), - ", values=", reinterpret_cast(GetValues()), ")"); + ", type=", DataTypeString(type_), ", values=", + reinterpret_cast(GetValues()), ")"); } // A fake ITensor implementation used to check whether the TF-TRT converter can @@ -651,11 +651,10 @@ void ReorderCKtoKC(const TRT_ShapedWeights& iweights, break; } case tensorflow::DataType::DT_HALF: { - Reorder2( - {k, c}, static_cast(iweights.GetValues()), - istrides, - static_cast(const_cast(oweights->GetValues())), - ostrides); + Reorder2({k, c}, static_cast(iweights.GetValues()), + istrides, static_cast( + const_cast(oweights->GetValues())), + ostrides); break; } default: @@ -2008,9 +2007,9 @@ tensorflow::Status ConvertConst(OpConverterParams* params) { uint8* data = reinterpret_cast(temp_weights.data()); std::copy(data, data + tensor.NumElements(), dst); } else { - return errors::FailedPrecondition( - "Unexpected data type: ", DataTypeString(dtype), - " at: ", node_def.name()); + return errors::FailedPrecondition("Unexpected data type: ", + DataTypeString(dtype), " at: ", + node_def.name()); } } } @@ -2671,9 +2670,9 @@ tensorflow::Status ConvertTopK(OpConverterParams* params) { op = nvinfer1::TopKOperation::kMAX; reducedAxes |= 1 << (nbDims - 1); } else { - return tensorflow::errors::Unimplemented( - "Operation: " + node_def.op() + - " not implemented, at: " + node_def.name()); + return tensorflow::errors::Unimplemented("Operation: " + node_def.op() + + " not implemented, at: " + + node_def.name()); } nvinfer1::ITopKLayer* layer = params->converter->network()->addTopK( @@ -2982,7 +2981,8 @@ tensorflow::Status ConvertSegmentToGraphDef( } } *common_scope = local_scope; - VLOG(1) << "Converted TensorRT candidate segment @scope '" << local_scope << "' to a GraphDef"; + VLOG(1) << "Converted TensorRT candidate segment @scope '" << local_scope + << "' to a GraphDef"; return tensorflow::Status::OK(); } diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc index 8037d47040..54f1d9b31f 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.cc @@ -252,9 +252,8 @@ int TRTEngineOp::GetEngineBatch(OpKernelContext* ctx) { cached_engine_batches_.push_back(num_batch); VLOG(1) << "Running with batch size " << num_batch; } else { - string msg = - StrCat("Engine buffer is full. buffer limit=", max_cached_engines_, - ", current entries="); + string msg = StrCat("Engine buffer is full. buffer limit=", + max_cached_engines_, ", current entries="); for (auto i : cached_engine_batches_) StrAppend(&msg, i, ","); StrAppend(&msg, " requested batch=", num_batch); LOG(WARNING) << msg; diff --git a/tensorflow/contrib/tensorrt/python/trt_convert_test.py b/tensorflow/contrib/tensorrt/python/trt_convert_test.py index 7f1045c199..dbf8dd2614 100644 --- a/tensorflow/contrib/tensorrt/python/trt_convert_test.py +++ b/tensorflow/contrib/tensorrt/python/trt_convert_test.py @@ -189,7 +189,8 @@ class TrtConvertTest(test_util.TensorFlowTestCase): execute_engine_test_value = ("done" if expect_engine_is_run else "") execute_native_segment_test_value = ("" if expect_engine_is_run else "done") self.assertEqual(execute_engine_test_value, - trt_convert.get_test_value("TRTEngineOp_0:ExecuteTrtEngine")) + trt_convert.get_test_value( + "TRTEngineOp_0:ExecuteTrtEngine")) self.assertEqual( execute_native_segment_test_value, trt_convert.get_test_value("TRTEngineOp_0:ExecuteNativeSegment")) diff --git a/tensorflow/contrib/tensorrt/resources/trt_resources.h b/tensorflow/contrib/tensorrt/resources/trt_resources.h index 6b68f92d16..aac9e5c7bd 100644 --- a/tensorflow/contrib/tensorrt/resources/trt_resources.h +++ b/tensorflow/contrib/tensorrt/resources/trt_resources.h @@ -39,7 +39,8 @@ namespace tensorrt { class TRTCalibrationResource : public tensorflow::ResourceBase { public: ~TRTCalibrationResource() { - LOG(INFO) << "Destroying Calibration Resource " << std::endl << DebugString(); + LOG(INFO) << "Destroying Calibration Resource " << std::endl + << DebugString(); builder_.reset(); engine_.reset(); // We need to manually destroy the builder and engine before the allocator diff --git a/tensorflow/contrib/tensorrt/segment/segment.cc b/tensorflow/contrib/tensorrt/segment/segment.cc index 917ff41fbf..d8f63779e6 100644 --- a/tensorflow/contrib/tensorrt/segment/segment.cc +++ b/tensorflow/contrib/tensorrt/segment/segment.cc @@ -434,11 +434,10 @@ tensorflow::Status SegmentGraph( } node_segments.emplace_back(node); } - string msg = StrCat("There are ", num_unsupported_ops, - " ops of ", unsupported_ops.size(), - " different types in the graph that", - " are not converted to TensorRT: "); - for (const auto& elem: unsupported_ops) { + string msg = StrCat( + "There are ", num_unsupported_ops, " ops of ", unsupported_ops.size(), + " different types in the graph that", " are not converted to TensorRT: "); + for (const auto& elem : unsupported_ops) { StrAppend(&msg, elem, ", "); } LOG(INFO) << msg << "(For more information see " @@ -461,7 +460,8 @@ tensorflow::Status SegmentGraph( std::vector order; order.reserve(graph->num_node_ids()); StableDFS(*graph, /*reverse=*/false, {graph->source_node()}, - /*enter=*/nullptr, [&order](const SimpleNode* n) { + /*enter=*/nullptr, + [&order](const SimpleNode* n) { order.push_back(n); return true; }); @@ -570,7 +570,7 @@ tensorflow::Status SegmentGraph( std::set& segment_nodes = itr.second; VLOG(1) << "Segment original size: " << segment_nodes.size(); while (true) { - std::deque in_nodes_que, out_nodes_que; + std::deque in_nodes_que, out_nodes_que; // Find an input node that is not eligible and add it to the queue. // Nodes that has no incoming edges should not be treated as "input", // as there are really no inputs to them. Similar for output nodes. @@ -616,8 +616,7 @@ tensorflow::Status SegmentGraph( // their outputs. In this way, for common cases the number of removed // nodes should be minimum. auto remove_nodes = [&segment_nodes]( - bool is_input_nodes, - std::deque* que) { + bool is_input_nodes, std::deque* que) { // Run a BFS on the queue to find all the input/output nodes. std::set visited; std::set logged(que->begin(), que->end()); diff --git a/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py b/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py index 419e52b768..207944468a 100644 --- a/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py +++ b/tensorflow/contrib/tensorrt/test/reshape_transpose_test.py @@ -80,7 +80,7 @@ class ReshapeTest(trt_test.TfTrtIntegrationTestBase): """Return the expected engines to build.""" return { "TRTEngineOp_0": ["reshape-%d" % i for i in range(7)] + - ["reshape-%d/shape" % i for i in range(7)] + ["reshape-%d/shape" % i for i in range(7)] } def ShouldRunTest(self, run_params): -- GitLab From bef3a3ffd7fba6839ab8233ea3710fa9fefa2d02 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 18:03:03 -0800 Subject: [PATCH 176/672] Add PickUnusedPortOrDie to c_api_experimental. PiperOrigin-RevId: 222336760 --- tensorflow/c/c_api_experimental.cc | 5 +++++ tensorflow/c/c_api_experimental.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc index 069de45e33..69de4cb711 100644 --- a/tensorflow/c/c_api_experimental.cc +++ b/tensorflow/c/c_api_experimental.cc @@ -26,6 +26,7 @@ limitations under the License. #include "tensorflow/core/graph/node_builder.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/init_main.h" +#include "tensorflow/core/platform/net.h" #include "tensorflow/core/platform/platform.h" #include "tensorflow/core/protobuf/config.pb.h" #include "tensorflow/core/protobuf/tensorflow_server.pb.h" @@ -8865,3 +8866,7 @@ int TF_OpIsStateful(const char* op_type, TF_Status* status) { void TF_InitMain(const char* usage, int* argc, char*** argv) { tensorflow::port::InitMain(usage, argc, argv); } + +int TF_PickUnusedPortOrDie() { + return tensorflow::internal::PickUnusedPortOrDie(); +} diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h index 728445e8fd..c04cd441bf 100644 --- a/tensorflow/c/c_api_experimental.h +++ b/tensorflow/c/c_api_experimental.h @@ -237,6 +237,10 @@ TF_CAPI_EXPORT extern int TF_OpIsStateful(const char* op_type, // this to be called. TF_CAPI_EXPORT void TF_InitMain(const char* usage, int* argc, char*** argv); +// Platform-specific implementation to return an unused port. (This should used +// in tests only.) +TF_CAPI_EXPORT int TF_PickUnusedPortOrDie(); + #ifdef __cplusplus } /* end extern "C" */ #endif -- GitLab From 26800f6872e47478cc605bd6dc46330e6d027826 Mon Sep 17 00:00:00 2001 From: akikaaa Date: Wed, 21 Nov 2018 10:28:50 +0800 Subject: [PATCH 177/672] fix return type error --- tensorflow/contrib/tpu/python/tpu/tpu_estimator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 932367f4dd..78c50fd8c5 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -2783,7 +2783,7 @@ def _export_output_to_tensors(export_output): elif isinstance(export_output, export_output_lib.RegressionOutput): return [export_output.value] elif isinstance(export_output, export_output_lib.PredictOutput): - return export_output.outputs.values() + return list(export_output.outputs.values()) else: raise ValueError( '`export_output` must be have type `ClassificationOutput`, ' -- GitLab From 3ffbbfb5a9e4cf0ae777453f0c70bc95c1e17d4e Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Tue, 20 Nov 2018 19:45:36 -0800 Subject: [PATCH 178/672] Move input spec checking logic to a separate file (part of a multi-step refactoring of base_layer.py to achieve better readability). PiperOrigin-RevId: 222344969 --- .../cudnn_rnn/python/layers/cudnn_rnn.py | 3 +- .../keras/api/keras/layers/__init__.py | 2 +- .../contrib/layers/python/layers/layers.py | 5 +- .../python/layers/core_layers.py | 9 +- tensorflow/contrib/rnn/python/ops/gru_ops.py | 4 +- tensorflow/contrib/rnn/python/ops/lstm_ops.py | 5 +- tensorflow/contrib/rnn/python/ops/rnn_cell.py | 14 +- tensorflow/python/keras/BUILD | 1 + tensorflow/python/keras/engine/__init__.py | 2 +- tensorflow/python/keras/engine/base_layer.py | 156 ++-------------- tensorflow/python/keras/engine/input_spec.py | 170 ++++++++++++++++++ tensorflow/python/keras/layers/__init__.py | 2 +- .../keras/layers/advanced_activations.py | 2 +- .../python/keras/layers/convolutional.py | 2 +- .../keras/layers/convolutional_recurrent.py | 2 +- tensorflow/python/keras/layers/core.py | 2 +- .../python/keras/layers/cudnn_recurrent.py | 2 +- tensorflow/python/keras/layers/local.py | 2 +- .../python/keras/layers/normalization.py | 2 +- tensorflow/python/keras/layers/pooling.py | 2 +- tensorflow/python/keras/layers/recurrent.py | 2 +- .../python/keras/layers/unified_rnn_test.py | 3 +- tensorflow/python/keras/layers/wrappers.py | 2 +- tensorflow/python/layers/base.py | 4 +- tensorflow/python/layers/base_test.py | 13 +- tensorflow/python/layers/layers.py | 2 +- tensorflow/python/ops/rnn_cell_impl.py | 9 +- .../tensorflow.keras.layers.-input-spec.pbtxt | 2 +- .../v1/tensorflow.layers.-input-spec.pbtxt | 2 +- .../tensorflow.keras.layers.-input-spec.pbtxt | 2 +- 30 files changed, 235 insertions(+), 195 deletions(-) create mode 100644 tensorflow/python/keras/engine/input_spec.py diff --git a/tensorflow/contrib/cudnn_rnn/python/layers/cudnn_rnn.py b/tensorflow/contrib/cudnn_rnn/python/layers/cudnn_rnn.py index 8bbcc7cd03..8e25637ed9 100644 --- a/tensorflow/contrib/cudnn_rnn/python/layers/cudnn_rnn.py +++ b/tensorflow/contrib/cudnn_rnn/python/layers/cudnn_rnn.py @@ -21,6 +21,7 @@ from tensorflow.contrib.cudnn_rnn.python.ops import cudnn_rnn_ops from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.keras.engine import input_spec from tensorflow.python.layers import base as base_layer from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops @@ -322,7 +323,7 @@ class _CudnnRNN(base_layer.Layer): raise ValueError("The last dimension of the inputs to `CudnnRNN` " "should be defined. Found `None`.") self._input_size = input_shape[-1].value - self.input_spec = base_layer.InputSpec(ndim=3, axes={-1: self._input_size}) + self.input_spec = input_spec.InputSpec(ndim=3, axes={-1: self._input_size}) self._set_scope(None) diff --git a/tensorflow/contrib/keras/api/keras/layers/__init__.py b/tensorflow/contrib/keras/api/keras/layers/__init__.py index 3327a9f9a6..9e19884df8 100644 --- a/tensorflow/contrib/keras/api/keras/layers/__init__.py +++ b/tensorflow/contrib/keras/api/keras/layers/__init__.py @@ -20,7 +20,7 @@ from __future__ import print_function # Generic layers. # pylint: disable=g-bad-import-order -from tensorflow.python.keras.engine.base_layer import InputSpec +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.engine.base_layer import Layer from tensorflow.python.keras.engine.input_layer import Input from tensorflow.python.keras.engine.input_layer import InputLayer diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py index ac9561c769..403b522ce4 100644 --- a/tensorflow/contrib/layers/python/layers/layers.py +++ b/tensorflow/contrib/layers/python/layers/layers.py @@ -35,6 +35,7 @@ from tensorflow.python.framework import function from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.keras.engine import input_spec from tensorflow.python.layers import base from tensorflow.python.layers import convolutional as convolutional_layers from tensorflow.python.layers import core as core_layers @@ -1958,7 +1959,7 @@ class GDN(base.Layer): self._reparam_offset = reparam_offset self.data_format = data_format self._channel_axis() # trigger ValueError early - self.input_spec = base.InputSpec(min_ndim=3, max_ndim=5) + self.input_spec = input_spec.InputSpec(min_ndim=3, max_ndim=5) def _channel_axis(self): try: @@ -2015,7 +2016,7 @@ class GDN(base.Layer): raise ValueError('The channel dimension of the inputs to `GDN` ' 'must be defined.') self._input_rank = input_shape.ndims - self.input_spec = base.InputSpec( + self.input_spec = input_spec.InputSpec( ndim=input_shape.ndims, axes={ channel_axis: num_channels }) diff --git a/tensorflow/contrib/model_pruning/python/layers/core_layers.py b/tensorflow/contrib/model_pruning/python/layers/core_layers.py index f0ce6fe039..1fa5c8cb48 100644 --- a/tensorflow/contrib/model_pruning/python/layers/core_layers.py +++ b/tensorflow/contrib/model_pruning/python/layers/core_layers.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.keras.engine import input_spec from tensorflow.python.layers import base from tensorflow.python.layers import utils from tensorflow.python.ops import array_ops @@ -119,7 +120,7 @@ class _MaskedConv(base.Layer): self.bias_initializer = bias_initializer self.kernel_regularizer = kernel_regularizer self.bias_regularizer = bias_regularizer - self.input_spec = base.InputSpec(ndim=self.rank + 2) + self.input_spec = input_spec.InputSpec(ndim=self.rank + 2) def build(self, input_shape): input_shape = tensor_shape.TensorShape(input_shape) @@ -171,7 +172,7 @@ class _MaskedConv(base.Layer): dtype=self.dtype) else: self.bias = None - self.input_spec = base.InputSpec( + self.input_spec = input_spec.InputSpec( ndim=self.rank + 2, axes={channel_axis: input_dim}) self.built = True @@ -393,14 +394,14 @@ class MaskedFullyConnected(base.Layer): self.bias_initializer = bias_initializer self.kernel_regularizer = kernel_regularizer self.bias_regularizer = bias_regularizer - self.input_spec = base.InputSpec(min_ndim=2) + self.input_spec = input_spec.InputSpec(min_ndim=2) def build(self, input_shape): input_shape = tensor_shape.TensorShape(input_shape) if tensor_shape.dimension_value(input_shape[-1]) is None: raise ValueError('The last dimension of the inputs to `Dense` ' 'should be defined. Found `None`.') - self.input_spec = base.InputSpec( + self.input_spec = input_spec.InputSpec( min_ndim=2, axes={-1: tensor_shape.dimension_value(input_shape[-1])}) self.kernel = self.add_variable( diff --git a/tensorflow/contrib/rnn/python/ops/gru_ops.py b/tensorflow/contrib/rnn/python/ops/gru_ops.py index b30ca7882f..251a933eae 100644 --- a/tensorflow/contrib/rnn/python/ops/gru_ops.py +++ b/tensorflow/contrib/rnn/python/ops/gru_ops.py @@ -21,7 +21,7 @@ from tensorflow.contrib.rnn.ops import gen_gru_ops from tensorflow.contrib.util import loader from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.layers import base as base_layer +from tensorflow.python.keras.engine import input_spec from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops from tensorflow.python.ops import math_ops @@ -165,7 +165,7 @@ class GRUBlockCell(LayerRNNCell): num_units = cell_size self._cell_size = num_units # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) @property def state_size(self): diff --git a/tensorflow/contrib/rnn/python/ops/lstm_ops.py b/tensorflow/contrib/rnn/python/ops/lstm_ops.py index 4db431f85a..b043026bc5 100644 --- a/tensorflow/contrib/rnn/python/ops/lstm_ops.py +++ b/tensorflow/contrib/rnn/python/ops/lstm_ops.py @@ -25,6 +25,7 @@ from tensorflow.contrib.rnn.ops import gen_lstm_ops from tensorflow.contrib.util import loader from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.keras.engine import input_spec from tensorflow.python.layers import base as base_layer from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops @@ -385,7 +386,7 @@ class LSTMBlockCell(LayerRNNCell): "scope": "lstm_cell" } # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) @property def state_size(self): @@ -628,7 +629,7 @@ class LSTMBlockFusedCell(LSTMBlockWrapper): self._use_peephole = use_peephole # Inputs must be 3-dimensional. - self.input_spec = base_layer.InputSpec(ndim=3) + self.input_spec = input_spec.InputSpec(ndim=3) @property def num_units(self): diff --git a/tensorflow/contrib/rnn/python/ops/rnn_cell.py b/tensorflow/contrib/rnn/python/ops/rnn_cell.py index e159dc9579..8a1c09f171 100644 --- a/tensorflow/contrib/rnn/python/ops/rnn_cell.py +++ b/tensorflow/contrib/rnn/python/ops/rnn_cell.py @@ -30,7 +30,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape from tensorflow.python.keras import activations from tensorflow.python.keras import initializers -from tensorflow.python.layers import base as base_layer +from tensorflow.python.keras.engine import input_spec from tensorflow.python.ops import array_ops from tensorflow.python.ops import clip_ops from tensorflow.python.ops import gen_array_ops @@ -2752,7 +2752,7 @@ class SRUCell(rnn_cell_impl.LayerRNNCell): self._activation = activation or math_ops.tanh # Restrict inputs to be 2-dimensional matrices - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) @property def state_size(self): @@ -3089,7 +3089,7 @@ class IndRNNCell(rnn_cell_impl.LayerRNNCell): super(IndRNNCell, self).__init__(_reuse=reuse, name=name, dtype=dtype) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._activation = activation or math_ops.tanh @@ -3183,7 +3183,7 @@ class IndyGRUCell(rnn_cell_impl.LayerRNNCell): super(IndyGRUCell, self).__init__(_reuse=reuse, name=name, dtype=dtype) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._activation = activation or math_ops.tanh @@ -3323,7 +3323,7 @@ class IndyLSTMCell(rnn_cell_impl.LayerRNNCell): super(IndyLSTMCell, self).__init__(_reuse=reuse, name=name, dtype=dtype) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._forget_bias = forget_bias @@ -3444,7 +3444,7 @@ class MinimalRNNCell(rnn_cell_impl.LayerRNNCell): super(MinimalRNNCell, self).__init__(name=name, dtype=dtype, **kwargs) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self.units = units self.activation = activations.get(activation) @@ -3558,7 +3558,7 @@ class CFNCell(rnn_cell_impl.LayerRNNCell): super(CFNCell, self).__init__(name=name, dtype=dtype, **kwargs) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self.units = units self.activation = activations.get(activation) diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index 81ef941ba6..540dd03768 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -124,6 +124,7 @@ py_library( "engine/base_layer.py", "engine/distributed_training_utils.py", "engine/input_layer.py", + "engine/input_spec.py", "engine/network.py", "engine/saving.py", "engine/sequential.py", diff --git a/tensorflow/python/keras/engine/__init__.py b/tensorflow/python/keras/engine/__init__.py index 26aed34766..005f6462ff 100644 --- a/tensorflow/python/keras/engine/__init__.py +++ b/tensorflow/python/keras/engine/__init__.py @@ -20,10 +20,10 @@ from __future__ import print_function # TODO(fchollet): Remove hourglass imports once external code is done importing # non-public APIs. -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer from tensorflow.python.keras.engine.input_layer import Input from tensorflow.python.keras.engine.input_layer import InputLayer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils.layer_utils import get_source_inputs del absolute_import diff --git a/tensorflow/python/keras/engine/base_layer.py b/tensorflow/python/keras/engine/base_layer.py index 5dcbc4d04b..c8e964d1f7 100644 --- a/tensorflow/python/keras/engine/base_layer.py +++ b/tensorflow/python/keras/engine/base_layer.py @@ -36,6 +36,7 @@ from tensorflow.python.keras import backend from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers +from tensorflow.python.keras.engine import input_spec from tensorflow.python.keras.utils import generic_utils from tensorflow.python.keras.utils import tf_utils # A module that only depends on `keras.layers` import these from here. @@ -797,7 +798,8 @@ class Layer(checkpointable.CheckpointableBase): with ops.name_scope(self._name_scope()): if not self.built: # Check input assumptions set before layer building, e.g. input rank. - self._assert_input_compatibility(inputs) + input_spec.assert_input_compatibility( + self.input_spec, inputs, self.name) if input_list and self._dtype is None: try: self._dtype = input_list[0].dtype.base_dtype.name @@ -822,7 +824,8 @@ class Layer(checkpointable.CheckpointableBase): if build_graph: # Symbolic execution on symbolic tensors. We will attempt to build # the corresponding TF subgraph inside `backend.get_graph()` - self._assert_input_compatibility(inputs) + input_spec.assert_input_compatibility( + self.input_spec, inputs, self.name) graph = backend.get_graph() with graph.as_default(): if not executing_eagerly: @@ -1492,101 +1495,6 @@ class Layer(checkpointable.CheckpointableBase): """Deprecated, do NOT use! Only for compatibility with external Keras.""" return self._outbound_nodes - def _assert_input_compatibility(self, inputs): - """Checks compatibility between the layer and provided inputs. - - This checks that the tensor(s) `inputs` verify the input assumptions - of the layer (if any). If not, a clear and actional exception gets raised. - - Arguments: - inputs: input tensor or list of input tensors. - - Raises: - ValueError: in case of mismatch between - the provided inputs and the expectations of the layer. - """ - if not self.input_spec: - return - if not isinstance(self.input_spec, (list, tuple)): - input_spec = nest.flatten(self.input_spec) - else: - input_spec = self.input_spec - inputs = nest.flatten(inputs) - if len(inputs) != len(input_spec): - raise ValueError('Layer ' + self.name + ' expects ' + - str(len(input_spec)) + ' inputs, ' - 'but it received ' + str(len(inputs)) + - ' input tensors. Inputs received: ' + str(inputs)) - for input_index, (x, spec) in enumerate(zip(inputs, input_spec)): - if spec is None: - continue - - if (spec.ndim is not None or - spec.min_ndim is not None or - spec.max_ndim is not None): - if x.shape.ndims is None: - raise ValueError('Input ' + str(input_index) + ' of layer ' + - self.name + ' is incompatible with the layer: ' - 'its rank is undefined, but the layer requires a ' - 'defined rank.') - - # Check ndim. - if spec.ndim is not None: - ndim = x.shape.ndims - if ndim != spec.ndim: - raise ValueError('Input ' + str(input_index) + ' of layer ' + - self.name + ' is incompatible with the layer: ' - 'expected ndim=' + str(spec.ndim) + ', found ndim=' + - str(ndim) + '. Full shape received: ' + - str(x.shape.as_list())) - if spec.max_ndim is not None: - ndim = x.shape.ndims - if ndim is not None and ndim > spec.max_ndim: - raise ValueError('Input ' + str(input_index) + ' of layer ' + - self.name + ' is incompatible with the layer: ' - 'expected max_ndim=' + str(spec.max_ndim) + - ', found ndim=' + str(ndim)) - if spec.min_ndim is not None: - ndim = x.shape.ndims - if ndim is not None and ndim < spec.min_ndim: - raise ValueError('Input ' + str(input_index) + ' of layer ' + - self.name + ' is incompatible with the layer: ' - ': expected min_ndim=' + str(spec.min_ndim) + - ', found ndim=' + str(ndim) + - '. Full shape received: ' + - str(x.shape.as_list())) - # Check dtype. - if spec.dtype is not None: - if x.dtype != spec.dtype: - raise ValueError('Input ' + str(input_index) + ' of layer ' + - self.name + ' is incompatible with the layer: ' - 'expected dtype=' + str(spec.dtype) + - ', found dtype=' + str(x.dtype)) - # Check specific shape axes. - if spec.axes: - shape = x.shape.as_list() - if shape is not None: - for axis, value in spec.axes.items(): - if hasattr(value, 'value'): - value = value.value - if value is not None and shape[int(axis)] not in {value, None}: - raise ValueError( - 'Input ' + str(input_index) + ' of layer ' + self.name + ' is' - ' incompatible with the layer: expected axis ' + str(axis) + - ' of input shape to have value ' + str(value) + - ' but received input with shape ' + str(shape)) - # Check shape. - if spec.shape is not None: - shape = x.shape.as_list() - if shape is not None: - for spec_dim, dim in zip(spec.shape, shape): - if spec_dim is not None and dim is not None: - if spec_dim != dim: - raise ValueError('Input ' + str(input_index) + - ' is incompatible with layer ' + self.name + - ': expected shape=' + str(spec.shape) + - ', found shape=' + str(shape)) - def set_weights(self, weights): """Sets the weights of the layer, from Numpy arrays. @@ -1687,55 +1595,6 @@ class Layer(checkpointable.CheckpointableBase): return self._call_is_graph_friendly -@tf_export( - 'keras.layers.InputSpec', v1=['keras.layers.InputSpec', 'layers.InputSpec']) -class InputSpec(object): - """Specifies the ndim, dtype and shape of every input to a layer. - - Every layer should expose (if appropriate) an `input_spec` attribute: - a list of instances of InputSpec (one per input tensor). - - A None entry in a shape is compatible with any dimension, - a None shape is compatible with any shape. - - Arguments: - dtype: Expected DataType of the input. - shape: Shape tuple, expected shape of the input - (may include None for unchecked axes). - ndim: Integer, expected rank of the input. - max_ndim: Integer, maximum rank of the input. - min_ndim: Integer, minimum rank of the input. - axes: Dictionary mapping integer axes to - a specific dimension value. - """ - - def __init__(self, - dtype=None, - shape=None, - ndim=None, - max_ndim=None, - min_ndim=None, - axes=None): - self.dtype = dtype - self.shape = shape - if shape is not None: - self.ndim = len(shape) - else: - self.ndim = ndim - self.max_ndim = max_ndim - self.min_ndim = min_ndim - self.axes = axes or {} - - def __repr__(self): - spec = [('dtype=' + str(self.dtype)) if self.dtype else '', - ('shape=' + str(self.shape)) if self.shape else '', - ('ndim=' + str(self.ndim)) if self.ndim else '', - ('max_ndim=' + str(self.max_ndim)) if self.max_ndim else '', - ('min_ndim=' + str(self.min_ndim)) if self.min_ndim else '', - ('axes=' + str(self.axes)) if self.axes else ''] - return 'InputSpec(%s)' % ', '.join(x for x in spec if x) - - class Node(object): """A `Node` describes the connectivity between two layers. @@ -2037,3 +1896,8 @@ def default(method): def generate_placeholders_from_shape(shape): return array_ops.placeholder(shape=shape, dtype=backend.floatx()) + + +# Avoid breaking users who directly import this symbol from this file. +# TODO(fchollet): remove this. +InputSpec = input_spec.InputSpec # pylint:disable=invalid-name diff --git a/tensorflow/python/keras/engine/input_spec.py b/tensorflow/python/keras/engine/input_spec.py new file mode 100644 index 0000000000..7277c16fe5 --- /dev/null +++ b/tensorflow/python/keras/engine/input_spec.py @@ -0,0 +1,170 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +# pylint: disable=protected-access +"""Contains the InputSpec class.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from six.moves import zip # pylint: disable=redefined-builtin + +from tensorflow.python.util import nest +from tensorflow.python.util.tf_export import tf_export + + +@tf_export('keras.layers.InputSpec', + v1=['keras.layers.InputSpec', 'layers.InputSpec']) +class InputSpec(object): + """Specifies the ndim, dtype and shape of every input to a layer. + + Every layer should expose (if appropriate) an `input_spec` attribute: + a list of instances of InputSpec (one per input tensor). + + A None entry in a shape is compatible with any dimension, + a None shape is compatible with any shape. + + Arguments: + dtype: Expected DataType of the input. + shape: Shape tuple, expected shape of the input + (may include None for unchecked axes). + ndim: Integer, expected rank of the input. + max_ndim: Integer, maximum rank of the input. + min_ndim: Integer, minimum rank of the input. + axes: Dictionary mapping integer axes to + a specific dimension value. + """ + + def __init__(self, + dtype=None, + shape=None, + ndim=None, + max_ndim=None, + min_ndim=None, + axes=None): + self.dtype = dtype + self.shape = shape + if shape is not None: + self.ndim = len(shape) + else: + self.ndim = ndim + self.max_ndim = max_ndim + self.min_ndim = min_ndim + self.axes = axes or {} + + def __repr__(self): + spec = [('dtype=' + str(self.dtype)) if self.dtype else '', + ('shape=' + str(self.shape)) if self.shape else '', + ('ndim=' + str(self.ndim)) if self.ndim else '', + ('max_ndim=' + str(self.max_ndim)) if self.max_ndim else '', + ('min_ndim=' + str(self.min_ndim)) if self.min_ndim else '', + ('axes=' + str(self.axes)) if self.axes else ''] + return 'InputSpec(%s)' % ', '.join(x for x in spec if x) + + +def assert_input_compatibility(input_spec, inputs, layer_name): + """Checks compatibility between the layer and provided inputs. + + This checks that the tensor(s) `inputs` verify the input assumptions + of a layer (if any). If not, a clear and actional exception gets raised. + + Arguments: + input_spec: An InputSpec instance, or None. + inputs: Input tensor or list of input tensors. + layer_name: String, name of the layer (for error message formatting). + + Raises: + ValueError: in case of mismatch between + the provided inputs and the expectations of the layer. + """ + if not input_spec: + return + if not isinstance(input_spec, (list, tuple)): + input_spec = nest.flatten(input_spec) + + inputs = nest.flatten(inputs) + if len(inputs) != len(input_spec): + raise ValueError('Layer ' + layer_name + ' expects ' + + str(len(input_spec)) + ' inputs, ' + 'but it received ' + str(len(inputs)) + + ' input tensors. Inputs received: ' + str(inputs)) + for input_index, (x, spec) in enumerate(zip(inputs, input_spec)): + if spec is None: + continue + + if (spec.ndim is not None or + spec.min_ndim is not None or + spec.max_ndim is not None): + if x.shape.ndims is None: + raise ValueError('Input ' + str(input_index) + ' of layer ' + + layer_name + ' is incompatible with the layer: ' + 'its rank is undefined, but the layer requires a ' + 'defined rank.') + + # Check ndim. + if spec.ndim is not None: + ndim = x.shape.ndims + if ndim != spec.ndim: + raise ValueError('Input ' + str(input_index) + ' of layer ' + + layer_name + ' is incompatible with the layer: ' + 'expected ndim=' + str(spec.ndim) + ', found ndim=' + + str(ndim) + '. Full shape received: ' + + str(x.shape.as_list())) + if spec.max_ndim is not None: + ndim = x.shape.ndims + if ndim is not None and ndim > spec.max_ndim: + raise ValueError('Input ' + str(input_index) + ' of layer ' + + layer_name + ' is incompatible with the layer: ' + 'expected max_ndim=' + str(spec.max_ndim) + + ', found ndim=' + str(ndim)) + if spec.min_ndim is not None: + ndim = x.shape.ndims + if ndim is not None and ndim < spec.min_ndim: + raise ValueError('Input ' + str(input_index) + ' of layer ' + + layer_name + ' is incompatible with the layer: ' + ': expected min_ndim=' + str(spec.min_ndim) + + ', found ndim=' + str(ndim) + + '. Full shape received: ' + + str(x.shape.as_list())) + # Check dtype. + if spec.dtype is not None: + if x.dtype != spec.dtype: + raise ValueError('Input ' + str(input_index) + ' of layer ' + + layer_name + ' is incompatible with the layer: ' + 'expected dtype=' + str(spec.dtype) + + ', found dtype=' + str(x.dtype)) + # Check specific shape axes. + if spec.axes: + shape = x.shape.as_list() + if shape is not None: + for axis, value in spec.axes.items(): + if hasattr(value, 'value'): + value = value.value + if value is not None and shape[int(axis)] not in {value, None}: + raise ValueError( + 'Input ' + str(input_index) + ' of layer ' + layer_name + ' is' + ' incompatible with the layer: expected axis ' + str(axis) + + ' of input shape to have value ' + str(value) + + ' but received input with shape ' + str(shape)) + # Check shape. + if spec.shape is not None: + shape = x.shape.as_list() + if shape is not None: + for spec_dim, dim in zip(spec.shape, shape): + if spec_dim is not None and dim is not None: + if spec_dim != dim: + raise ValueError('Input ' + str(input_index) + + ' is incompatible with layer ' + layer_name + + ': expected shape=' + str(spec.shape) + + ', found shape=' + str(shape)) diff --git a/tensorflow/python/keras/layers/__init__.py b/tensorflow/python/keras/layers/__init__.py index 7268040b02..49990b6bf4 100644 --- a/tensorflow/python/keras/layers/__init__.py +++ b/tensorflow/python/keras/layers/__init__.py @@ -22,7 +22,7 @@ from __future__ import print_function # pylint: disable=g-bad-import-order from tensorflow.python.keras.engine.input_layer import Input from tensorflow.python.keras.engine.input_layer import InputLayer -from tensorflow.python.keras.engine.base_layer import InputSpec +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.engine.base_layer import Layer # Advanced activations. diff --git a/tensorflow/python/keras/layers/advanced_activations.py b/tensorflow/python/keras/layers/advanced_activations.py index a2385dfdbb..35ac7830b2 100644 --- a/tensorflow/python/keras/layers/advanced_activations.py +++ b/tensorflow/python/keras/layers/advanced_activations.py @@ -22,8 +22,8 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils import tf_utils from tensorflow.python.ops import math_ops from tensorflow.python.util.tf_export import tf_export diff --git a/tensorflow/python/keras/layers/convolutional.py b/tensorflow/python/keras/layers/convolutional.py index d1b03b8822..6564d6e8fd 100644 --- a/tensorflow/python/keras/layers/convolutional.py +++ b/tensorflow/python/keras/layers/convolutional.py @@ -26,8 +26,8 @@ from tensorflow.python.keras import backend from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec # imports for backwards namespace compatibility # pylint: disable=unused-import from tensorflow.python.keras.layers.pooling import AveragePooling1D diff --git a/tensorflow/python/keras/layers/convolutional_recurrent.py b/tensorflow/python/keras/layers/convolutional_recurrent.py index 100542129b..cf3861da21 100644 --- a/tensorflow/python/keras/layers/convolutional_recurrent.py +++ b/tensorflow/python/keras/layers/convolutional_recurrent.py @@ -26,8 +26,8 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.layers.recurrent import _generate_dropout_mask from tensorflow.python.keras.layers.recurrent import _standardize_args from tensorflow.python.keras.layers.recurrent import RNN diff --git a/tensorflow/python/keras/layers/core.py b/tensorflow/python/keras/layers/core.py index 8031272e25..56dd70558c 100644 --- a/tensorflow/python/keras/layers/core.py +++ b/tensorflow/python/keras/layers/core.py @@ -34,8 +34,8 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils import conv_utils from tensorflow.python.keras.utils import generic_utils from tensorflow.python.keras.utils import tf_utils diff --git a/tensorflow/python/keras/layers/cudnn_recurrent.py b/tensorflow/python/keras/layers/cudnn_recurrent.py index beacdf2515..81f292817f 100644 --- a/tensorflow/python/keras/layers/cudnn_recurrent.py +++ b/tensorflow/python/keras/layers/cudnn_recurrent.py @@ -25,7 +25,7 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.layers.recurrent import RNN from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_cudnn_rnn_ops diff --git a/tensorflow/python/keras/layers/local.py b/tensorflow/python/keras/layers/local.py index 33d09a1660..d2c4aaa125 100644 --- a/tensorflow/python/keras/layers/local.py +++ b/tensorflow/python/keras/layers/local.py @@ -23,8 +23,8 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils import conv_utils from tensorflow.python.keras.utils import tf_utils from tensorflow.python.util.tf_export import tf_export diff --git a/tensorflow/python/keras/layers/normalization.py b/tensorflow/python/keras/layers/normalization.py index 7a91693128..aa8598d731 100644 --- a/tensorflow/python/keras/layers/normalization.py +++ b/tensorflow/python/keras/layers/normalization.py @@ -26,8 +26,8 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils import tf_utils from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops diff --git a/tensorflow/python/keras/layers/pooling.py b/tensorflow/python/keras/layers/pooling.py index 72a9c1d629..a0744cddad 100644 --- a/tensorflow/python/keras/layers/pooling.py +++ b/tensorflow/python/keras/layers/pooling.py @@ -22,8 +22,8 @@ import functools from tensorflow.python.framework import tensor_shape from tensorflow.python.keras import backend -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils import conv_utils from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops diff --git a/tensorflow/python/keras/layers/recurrent.py b/tensorflow/python/keras/layers/recurrent.py index d04533815e..5d0efc2f16 100644 --- a/tensorflow/python/keras/layers/recurrent.py +++ b/tensorflow/python/keras/layers/recurrent.py @@ -28,8 +28,8 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.utils import generic_utils from tensorflow.python.keras.utils import tf_utils from tensorflow.python.ops import array_ops diff --git a/tensorflow/python/keras/layers/unified_rnn_test.py b/tensorflow/python/keras/layers/unified_rnn_test.py index 22d29f191b..744d51824b 100644 --- a/tensorflow/python/keras/layers/unified_rnn_test.py +++ b/tensorflow/python/keras/layers/unified_rnn_test.py @@ -36,8 +36,7 @@ from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers from tensorflow.python.keras import testing_utils -from tensorflow.python.keras.engine.base_layer import \ - InputSpec +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.layers.cudnn_recurrent import CuDNNLSTM from tensorflow.python.keras.layers.recurrent import RNN from tensorflow.python.keras.utils import tf_utils diff --git a/tensorflow/python/keras/layers/wrappers.py b/tensorflow/python/keras/layers/wrappers.py index 27419a1ffc..67b154141e 100644 --- a/tensorflow/python/keras/layers/wrappers.py +++ b/tensorflow/python/keras/layers/wrappers.py @@ -23,8 +23,8 @@ import copy from tensorflow.python.framework import tensor_shape from tensorflow.python.keras import backend as K -from tensorflow.python.keras.engine.base_layer import InputSpec from tensorflow.python.keras.engine.base_layer import Layer +from tensorflow.python.keras.engine.input_spec import InputSpec from tensorflow.python.keras.layers.recurrent import _standardize_args from tensorflow.python.keras.utils import generic_utils from tensorflow.python.keras.utils import tf_utils diff --git a/tensorflow/python/layers/base.py b/tensorflow/python/layers/base.py index fccea484b0..42086e4c3e 100644 --- a/tensorflow/python/layers/base.py +++ b/tensorflow/python/layers/base.py @@ -30,10 +30,10 @@ from tensorflow.python.util import nest from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export - +# Avoid breaking users who directly import this symbol from this file. +# TODO(fchollet): remove this. InputSpec = base_layer.InputSpec # pylint: disable=invalid-name - _KERAS_STYLE_SCOPE = False diff --git a/tensorflow/python/layers/base_test.py b/tensorflow/python/layers/base_test.py index 90abf35e87..45099677e0 100644 --- a/tensorflow/python/layers/base_test.py +++ b/tensorflow/python/layers/base_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.keras.engine import base_layer as keras_base_layer +from tensorflow.python.keras.engine import input_spec from tensorflow.python.layers import base as base_layers from tensorflow.python.layers import core as core_layers from tensorflow.python.ops import array_ops @@ -251,7 +252,7 @@ class BaseLayerTest(test.TestCase): def __init__(self): super(CustomerLayer, self).__init__() - self.input_spec = base_layers.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) def call(self, inputs): return inputs @@ -278,7 +279,7 @@ class BaseLayerTest(test.TestCase): def __init__(self): super(CustomerLayer, self).__init__() - self.input_spec = base_layers.InputSpec(min_ndim=2) + self.input_spec = input_spec.InputSpec(min_ndim=2) def call(self, inputs): return inputs @@ -306,7 +307,7 @@ class BaseLayerTest(test.TestCase): def __init__(self): super(CustomerLayer, self).__init__() - self.input_spec = base_layers.InputSpec(max_ndim=2) + self.input_spec = input_spec.InputSpec(max_ndim=2) def call(self, inputs): return inputs @@ -334,7 +335,7 @@ class BaseLayerTest(test.TestCase): def __init__(self): super(CustomerLayer, self).__init__() - self.input_spec = base_layers.InputSpec(dtype='float32') + self.input_spec = input_spec.InputSpec(dtype='float32') def call(self, inputs): return inputs @@ -354,7 +355,7 @@ class BaseLayerTest(test.TestCase): def __init__(self): super(CustomerLayer, self).__init__() - self.input_spec = base_layers.InputSpec(axes={-1: 2}) + self.input_spec = input_spec.InputSpec(axes={-1: 2}) def call(self, inputs): return inputs @@ -376,7 +377,7 @@ class BaseLayerTest(test.TestCase): def __init__(self): super(CustomerLayer, self).__init__() - self.input_spec = base_layers.InputSpec(shape=(None, 3)) + self.input_spec = input_spec.InputSpec(shape=(None, 3)) def call(self, inputs): return inputs diff --git a/tensorflow/python/layers/layers.py b/tensorflow/python/layers/layers.py index 11a2ebc040..93eec38a08 100644 --- a/tensorflow/python/layers/layers.py +++ b/tensorflow/python/layers/layers.py @@ -24,7 +24,7 @@ from __future__ import print_function # Base objects. from tensorflow.python.layers.base import Layer -from tensorflow.python.layers.base import InputSpec +from tensorflow.python.keras.engine.input_spec import InputSpec # Core layers. from tensorflow.python.layers.core import Dense diff --git a/tensorflow/python/ops/rnn_cell_impl.py b/tensorflow/python/ops/rnn_cell_impl.py index 2bc1ad4e04..85efd6a4f7 100644 --- a/tensorflow/python/ops/rnn_cell_impl.py +++ b/tensorflow/python/ops/rnn_cell_impl.py @@ -36,6 +36,7 @@ from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util from tensorflow.python.keras import activations from tensorflow.python.keras import initializers +from tensorflow.python.keras.engine import input_spec from tensorflow.python.keras.utils import tf_utils from tensorflow.python.layers import base as base_layer from tensorflow.python.ops import array_ops @@ -410,7 +411,7 @@ class BasicRNNCell(LayerRNNCell): "performance on GPU.", self) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units if activation: @@ -507,7 +508,7 @@ class GRUCell(LayerRNNCell): "Please use tf.contrib.cudnn_rnn.CudnnGRU for better " "performance on GPU.", self) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units if activation: @@ -683,7 +684,7 @@ class BasicLSTMCell(LayerRNNCell): "performance on GPU.", self) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._forget_bias = forget_bias @@ -871,7 +872,7 @@ class LSTMCell(LayerRNNCell): "performance on GPU.", self) # Inputs must be 2-dimensional. - self.input_spec = base_layer.InputSpec(ndim=2) + self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._use_peepholes = use_peepholes diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-input-spec.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-input-spec.pbtxt index 5fd0a47a68..bc3ceb67a4 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-input-spec.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-input-spec.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.keras.layers.InputSpec" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member_method { name: "__init__" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.layers.-input-spec.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.layers.-input-spec.pbtxt index fd02c919ae..80834e08f7 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.layers.-input-spec.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.layers.-input-spec.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.layers.InputSpec" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member_method { name: "__init__" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-input-spec.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-input-spec.pbtxt index 5fd0a47a68..bc3ceb67a4 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-input-spec.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-input-spec.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.keras.layers.InputSpec" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member_method { name: "__init__" -- GitLab From abdd39fa9e078d2642397055ef669936746b4196 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Nov 2018 19:56:41 -0800 Subject: [PATCH 179/672] Move the implementation of MirroredStrategy to tensorflow/python/distribute/. Note that this implementation is not yet exposed publicly throught the TensorFlow API. PiperOrigin-RevId: 222345484 --- tensorflow/contrib/distribute/python/BUILD | 21 +- .../python/collective_all_reduce_strategy.py | 5 + .../distribute/python/mirrored_strategy.py | 791 +---------------- .../distribute/python/one_device_strategy.py | 5 + .../python/parameter_server_strategy.py | 5 + .../contrib/distribute/python/tpu_strategy.py | 5 + tensorflow/python/distribute/BUILD | 29 + .../python/distribute/mirrored_strategy.py | 805 ++++++++++++++++++ .../engine/distributed_training_utils.py | 11 +- tensorflow/python/training/distribute.py | 5 + 10 files changed, 878 insertions(+), 804 deletions(-) create mode 100644 tensorflow/python/distribute/mirrored_strategy.py diff --git a/tensorflow/contrib/distribute/python/BUILD b/tensorflow/contrib/distribute/python/BUILD index 2a595e7c87..91282a8c1d 100644 --- a/tensorflow/contrib/distribute/python/BUILD +++ b/tensorflow/contrib/distribute/python/BUILD @@ -49,28 +49,9 @@ py_library( srcs = ["mirrored_strategy.py"], visibility = ["//tensorflow:internal"], deps = [ - "//tensorflow/core:protos_all_py", - "//tensorflow/python:array_ops", - "//tensorflow/python:constant_op", - "//tensorflow/python:control_flow_ops", - "//tensorflow/python:device", - "//tensorflow/python:device_util", "//tensorflow/python:distribute", - "//tensorflow/python:dtypes", - "//tensorflow/python:framework_ops", - "//tensorflow/python:pywrap_tensorflow", - "//tensorflow/python:tensor_util", - "//tensorflow/python:training", - "//tensorflow/python:util", - "//tensorflow/python:variable_scope", - "//tensorflow/python:variables", - "//tensorflow/python/distribute:cross_device_ops", - "//tensorflow/python/distribute:multi_worker_util", - "//tensorflow/python/distribute:reduce_util", - "//tensorflow/python/distribute:shared_variable_creator", + "//tensorflow/python/distribute:mirrored_strategy", "//tensorflow/python/distribute:values", - "//tensorflow/python/eager:context", - "//tensorflow/python/eager:tape", ], ) diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py index f13cf26d36..906377b739 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py @@ -320,3 +320,8 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): @property def _num_replicas_in_sync(self): return len(self._devices) * self._num_workers + + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return False diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy.py b/tensorflow/contrib/distribute/python/mirrored_strategy.py index d671d1d562..a3bcc8db88 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy.py @@ -12,760 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Class MirroredStrategy implementing DistributionStrategy.""" +"""Contrib version of MirroredStrategy.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import contextlib -from functools import partial -import threading +import functools -from tensorflow.python import pywrap_tensorflow -from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib -from tensorflow.python.distribute import multi_worker_util -from tensorflow.python.distribute import reduce_util -from tensorflow.python.distribute import shared_variable_creator +from tensorflow.python.distribute import mirrored_strategy from tensorflow.python.distribute import values -from tensorflow.python.eager import context -from tensorflow.python.eager import tape -from tensorflow.python.framework import constant_op -from tensorflow.python.framework import device as tf_device -from tensorflow.python.framework import dtypes -from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_util -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import control_flow_ops -from tensorflow.python.ops import variable_scope -from tensorflow.python.training import coordinator -from tensorflow.python.training import device_util from tensorflow.python.training import distribute as distribute_lib -from tensorflow.python.util import nest -# TODO(josh11b): Replace asserts in this file with if ...: raise ... - - -@contextlib.contextmanager -def _enter_graph(g): - if context.executing_eagerly(): - with g.as_default(), context.eager_mode(): - yield - else: - with g.as_default(): - yield - - -def _cpu_device(device): - cpu_device = tf_device.DeviceSpec.from_string(device) - cpu_device.merge_from(tf_device.DeviceSpec(device_type="CPU", device_index=0)) - return cpu_device.to_string() - - -class _RequestedStop(Exception): - pass - - -# _call_for_each_replica and _reduce_non_distributed_value are not members of -# MirroredStrategy so that they are generally not allowed to use anything -# specific to MirroredStrategy and thus can be shared with other distribution -# strategies. - - -# TODO(yuefengz): maybe create a common class for those who need to call this -# _call_for_each_replica. -def _call_for_each_replica(distribution, fn, args, kwargs): - """Run `fn` in separate threads, once per replica/worker device. - - Args: - distribution: the DistributionStrategy object. - fn: function to run (will be run once per device, each in its own thread). - args: positional arguments for `fn` - kwargs: keyword arguments for `fn`. - - Returns: - Merged return value of `fn` across all replicas. - - Raises: - RuntimeError: If fn() calls get_replica_context().merge_call() a different - number of times from the available devices. - """ - # TODO(josh11b): Add this option once we add synchronization to variable - # creation. Until then, this is pretty unsafe to use. - run_concurrently = False - if not context.executing_eagerly(): - # Needed for per-thread device, etc. contexts in graph mode. - ops.get_default_graph().switch_to_thread_local() - - coord = coordinator.Coordinator(clean_stop_exception_types=(_RequestedStop,)) - - shared_variable_store = {} - - # TODO(isaprykin): Create these threads once instead of during every run() - # call. - threads = [] - for index, d in enumerate(distribution.extended.worker_devices): - variable_creator_fn = shared_variable_creator.make_fn( - shared_variable_store, index) - t = MirroredExtended._MirroredReplicaThread( # pylint: disable=protected-access - distribution, coord, d, variable_creator_fn, fn, - *values.select_device(d, args), **values.select_device(d, kwargs)) - threads.append(t) - - for t in threads: - t.start() - - # When `fn` starts `should_run` event is set on _MirroredReplicaThread - # (`MRT`) threads. The execution waits until - # `MRT.has_paused` is set, which indicates that either `fn` is - # complete or a `get_replica_context().merge_call()` is called. If `fn` is - # complete, then `MRT.done` is set to True. Otherwise, arguments - # of `get_replica_context().merge_call` from all paused threads are grouped - # and the `merge_fn` is performed. Results of the - # `get_replica_context().merge_call` are then set to `MRT.merge_result`. - # Each such `get_replica_context().merge_call` call returns the - # `MRT.merge_result` for that thread when `MRT.should_run` event - # is reset again. Execution of `fn` resumes. - - try: - with coord.stop_on_exception(): - all_done = False - while not all_done and not coord.should_stop(): - done = [] - if run_concurrently: - for t in threads: - t.should_run.set() - for t in threads: - t.has_paused.wait() - t.has_paused.clear() - if coord.should_stop(): - return None - done.append(t.done) - else: - for t in threads: - t.should_run.set() - t.has_paused.wait() - t.has_paused.clear() - if coord.should_stop(): - return None - done.append(t.done) - if coord.should_stop(): - return None - all_done = all(done) - if not all_done: - if any(done): - raise RuntimeError("Some replicas made a different number of " - "replica_context().merge_call() calls.") - # get_replica_context().merge_call() case - merge_args = values.regroup({t.device: t.merge_args for t in threads}) - merge_kwargs = values.regroup( - {t.device: t.merge_kwargs for t in threads}) - # We capture the name_scope of the MRT when we call merge_fn - # to ensure that if we have opened a name scope in the MRT, - # it will be respected when executing the merge function. We only - # capture the name_scope from the first MRT and assume it is - # the same for all other MRTs. - mtt_captured_name_scope = threads[0].captured_name_scope - with ops.name_scope(mtt_captured_name_scope): - merge_result = threads[0].merge_fn(distribution, *merge_args, - **merge_kwargs) - for t in threads: - t.merge_result = values.select_device(t.device, merge_result) - finally: - for t in threads: - t.should_run.set() - coord.join(threads) - - return values.regroup({t.device: t.main_result for t in threads}) - - -def _reduce_non_distributed_value(extended, reduce_op, value, destinations): - """Reduce a non-DistributedValue `value` to `destinations`.""" - if isinstance(value, values.DistributedValues): - raise ValueError("You are passing a `DistributedValue` to " - "`_reduce_non_distributed_value`, which is not allowed.") - - # If the same value is present on all replicas then the PerReplica value will - # be a single value. We also handle the case when `value` is a single value - # and equal to 0. - if value == 0: - return 0 - # If there is only a single value and the reduce op is MEAN, - # that value should be on all destinations. - if reduce_op == reduce_util.ReduceOp.MEAN: - return value - - cross_device_ops_lib.validate_destinations(destinations) - # We do not support a reduce op of SUM if the value is the same across - # all replicas. We call this as part of assign functions for MirroredVariables - # and summing up identical values across replicas is not clearly defined. - if (len(extended.worker_devices) != 1 or - not cross_device_ops_lib.check_destinations(destinations)): - raise ValueError("A non-DistributedValues value %s cannot be reduced with " - "the given reduce op %s." % (value, reduce_op)) - # TODO(anjalisridhar): Moves these methods to a device utility file? - devices = cross_device_ops_lib.get_devices_from(destinations) - if len(devices) == 1: - with ops.device(devices[0]): - return array_ops.identity(value) - else: - value_updates = {} - for d in devices: - with ops.device(d): - value_updates[d] = array_ops.identity(value) - return values.Mirrored(value_updates) - - -def _create_mirrored_variable(devices, real_mirrored_creator, *args, **kwargs): # pylint: disable=g-missing-docstring - # Figure out what collections this variable should be added to. - # We'll add the MirroredVariable to those collections instead. - collections = kwargs.pop("collections", None) - if collections is None: - collections = [ops.GraphKeys.GLOBAL_VARIABLES] - kwargs["collections"] = [] - - # Get synchronization value - synchronization = kwargs.get("synchronization", - variable_scope.VariableSynchronization.ON_WRITE) - if synchronization == variable_scope.VariableSynchronization.NONE: - raise ValueError("`NONE` variable synchronization mode is not " - "supported with `Mirrored` distribution strategy. Please" - " change the `synchronization` for variable: " + - kwargs["name"]) - elif synchronization == variable_scope.VariableSynchronization.ON_READ: - # Variables that are to be synced on read are replica local. - is_replica_local = True - kwargs["trainable"] = False - elif (synchronization == variable_scope.VariableSynchronization.ON_WRITE or - synchronization == variable_scope.VariableSynchronization.AUTO): - # `AUTO` synchronization for `MirroredStrategy` is `ON_WRITE`. - is_replica_local = False - else: - raise ValueError("Invalid variable synchronization mode: " + - synchronization + " for variable: " + kwargs["name"]) - - # Get aggregation value - aggregation = kwargs.pop("aggregation", - variable_scope.VariableAggregation.NONE) - if aggregation not in ( - variable_scope.VariableAggregation.NONE, - variable_scope.VariableAggregation.SUM, - variable_scope.VariableAggregation.MEAN, - variable_scope.VariableAggregation.ONLY_FIRST_REPLICA - ): - raise ValueError("Invalid variable aggregation mode: " + aggregation + - " for variable: " + kwargs["name"]) - - # Ignore user-specified caching device, not needed for mirrored variables. - kwargs.pop("caching_device", None) - - # TODO(josh11b,apassos): It would be better if variable initialization - # was never recorded on the tape instead of having to do this manually - # here. - with tape.stop_recording(): - index = real_mirrored_creator(devices, *args, **kwargs) - - if is_replica_local: - result = values.ReplicaLocalVariable( - index, index[devices[0]], aggregation) - else: - result = values.MirroredVariable(index, index[devices[0]], aggregation) - - # Add the wrapped variable to the requested collections. - # The handling of eager mode and the global step matches - # ResourceVariable._init_from_args(). - if not context.executing_eagerly(): - g = ops.get_default_graph() - # If "trainable" is True, next_creator() will add the member variables - # to the TRAINABLE_VARIABLES collection, so we manually remove - # them and replace with the MirroredVariable. We can't set - # "trainable" to False for next_creator() since that causes functions - # like implicit_gradients to skip those variables. - if kwargs.get("trainable", True): - collections.append(ops.GraphKeys.TRAINABLE_VARIABLES) - l = g.get_collection_ref(ops.GraphKeys.TRAINABLE_VARIABLES) - for v in index.values(): - if v in l: - l.remove(v) - g.add_to_collections(collections, result) - elif ops.GraphKeys.GLOBAL_STEP in collections: - ops.add_to_collections(ops.GraphKeys.GLOBAL_STEP, result) - - return result - - -class CoreMirroredStrategy(distribute_lib.DistributionStrategy): - """Mirrors vars to distribute across multiple devices and machines. - - *** core version *** - - This strategy uses one replica per device and sync replication for its - multi-GPU version. - - The multi-worker version will be added in the fture. - - Args: - devices: a list of device strings. - num_gpus_per_worker: number of GPUs per worker. - cross_device_ops: optional, a descedant of `CrossDeviceOps`. If this is not - set, nccl will be use by default. - """ - - def __init__(self, - devices=None, - num_gpus_per_worker=None, - cross_device_ops=None): - extended = CoreMirroredExtended(self, devices, num_gpus_per_worker, - cross_device_ops) - super(CoreMirroredStrategy, self).__init__(extended) - - -class CoreMirroredExtended(distribute_lib.DistributionStrategyExtended): - """Implementation of CoreMirroredStrategy.""" - - def __init__(self, - container_strategy, - devices=None, - num_gpus_per_worker=None, - cross_device_ops=None): - super(CoreMirroredExtended, self).__init__(container_strategy) - self._cross_device_ops = cross_device_ops - # Remember num GPUs which might be needed by `configure` method. - self._num_gpus = num_gpus_per_worker - - self._initialize_local(self._num_gpus, devices) - - def _initialize_local(self, num_gpus, devices): - """Initializes the object for local training.""" - self._cluster_spec = None - # Convert `num_gpus` into `devices`, shouldn't specify both. - if devices is None: - if num_gpus is None: - num_gpus = context.num_gpus() - if num_gpus == 0: - devices = ["/device:CPU:0"] - else: - devices = ["/device:GPU:%d" % d for d in range(num_gpus)] - elif num_gpus is not None: - raise ValueError("Must only specify one of `devices` and `num_gpus`.") - self._num_gpus = num_gpus - # TODO(yuefengz): consider setting the default device. - - assert devices, "Must specify at least one device." - assert len(set(devices)) == len(devices), ( - "No duplicates allowed in `devices` argument.") - # TODO(josh11b): Require at least 2 devices? - self._devices = [device_util.resolve(d) for d in devices] - self._canonical_device_set = set(self._devices) - self._device_index = values.PerReplica( - {d: i for i, d in enumerate(devices)}) - - def _initialize_multi_worker(self, num_gpus, cluster_spec): - """Initializes the object for multi-worker training.""" - cluster_spec = multi_worker_util.normalize_cluster_spec(cluster_spec) - self._cluster_spec = cluster_spec - - self._workers = [] - for job in ["chief", "worker"]: - for task in range(len(cluster_spec.as_dict().get(job, []))): - self._workers.append("/job:%s/task:%d" % (job, task)) - - if num_gpus is None: - raise ValueError("`num_gpus` is required if `cluster_spec` is given.") - if num_gpus > 0: - self._worker_devices = [ - (worker, [ - device_util.canonicalize(worker + "/device:GPU:%d" % gpu) - for gpu in range(num_gpus) - ]) for worker in self._workers - ] - else: - self._worker_devices = [ - (worker, [device_util.canonicalize(worker, "/device:CPU:0")]) - for worker in self._workers - ] - - devices = nest.flatten([l for _, l in self._worker_devices]) - - # Setting `_default_device` will add a device scope in the - # distribution.scope. We set the default device to the first worker. When - # users specify device under distribution.scope by - # with tf.device("/cpu:0"): - # ... - # their ops will end up on the cpu device of its first worker, e.g. - # "/job:worker/task:0/device:CPU:0". Note this is not used in replica mode. - self._default_device = self._workers[0] - - assert devices, "Must specify at least one device." - assert len(set(devices)) == len(devices), ( - "No duplicates allowed in `devices` argument.") - # TODO(josh11b): Require at least 2 devices? - self._devices = [device_util.resolve(d) for d in devices] - self._canonical_device_set = set(self._devices) - self._device_index = values.PerReplica( - {d: i for i, d in enumerate(devices)}) - - def _create_variable(self, next_creator, *args, **kwargs): - """Create a mirrored variable. See `DistributionStrategy.scope`.""" - colocate_with = kwargs.pop("colocate_with", None) - devices = self._get_devices_from(colocate_with) - - def _real_mirrored_creator(devices, *args, **kwargs): # pylint: disable=g-missing-docstring - index = {} - for i, d in enumerate(devices): - with ops.device(d): - if i > 0: - # Give replicas meaningful distinct names: - var0name = index[devices[0]].name.split(":")[0] - # We append a / to variable names created on replicas with id > 0 to - # ensure that we ignore the name scope and instead use the given - # name as the absolute name of the variable. - kwargs["name"] = "%s/replica_%d/" % (var0name, i) - # Initialize replicas with the same value: - def initial_value_fn(device=d): - if context.executing_eagerly(): - init_value = index[devices[0]].value() - return array_ops.identity(init_value) - else: - with ops.device(device): - init_value = index[devices[0]].initial_value - return array_ops.identity(init_value) - kwargs["initial_value"] = initial_value_fn - with context.context().device_policy(context.DEVICE_PLACEMENT_SILENT): - # Don't record operations (e.g. other variable reads) during - # variable creation. - with tape.stop_recording(): - v = next_creator(*args, **kwargs) - assert not isinstance(v, values.DistributedVariable) - index[d] = v - return index - - return _create_mirrored_variable(devices, _real_mirrored_creator, *args, - **kwargs) - - def _distribute_dataset(self, dataset_fn): - if self._cluster_spec: - return values.MultiWorkerDataset( - partial(self._call_dataset_fn, dataset_fn), - self._worker_devices, - auto_shard=False) - else: - return values.PerReplicaDataset( - self._call_dataset_fn(dataset_fn), self._devices) - - def _make_dataset_iterator(self, dataset): - if self._cluster_spec: - worker_device_pairs = self._worker_devices - else: - worker_device_pairs = [("/job:localhost", self._devices)] - return values.DatasetIterator(dataset, worker_device_pairs, - self._num_replicas_in_sync) - - def _make_input_fn_iterator( - self, - input_fn, - replication_mode=distribute_lib.InputReplicationMode.PER_WORKER): - input_contexts = [] - if self._cluster_spec: - num_workers = len(self._worker_devices) - worker_device_pairs = self._worker_devices - else: - num_workers = 1 - worker_device_pairs = [("/job:localhost", self._devices)] - for i in range(num_workers): - input_contexts.append(distribute_lib.InputContext( - num_input_pipelines=num_workers, - input_pipeline_id=i, - num_replicas_in_sync=self._num_replicas_in_sync)) - return values.InputFunctionIterator( - input_fn, worker_device_pairs, input_contexts) - - # TODO(priyag): Deal with OutOfRange errors once b/111349762 is fixed. - def _experimental_run_steps_on_iterator(self, fn, iterator, iterations, - initial_loop_values=None): - if initial_loop_values is None: - initial_loop_values = {} - initial_loop_values = nest.flatten(initial_loop_values) - - ctx = values.MultiStepContext() - def body(i, *args): - """A wrapper around `fn` to create the while loop body.""" - del args - fn_inputs = iterator.get_next() - if not isinstance(fn_inputs, tuple): - fn_inputs = (fn_inputs,) - fn_result = fn(ctx, fn_inputs) - for (name, output) in ctx.last_step_outputs.items(): - # Convert all outputs to tensors, potentially from `DistributedValues`. - ctx.last_step_outputs[name] = self._unwrap(output) - flat_last_step_outputs = nest.flatten(ctx.last_step_outputs) - with ops.control_dependencies([fn_result]): - return [i + 1] + flat_last_step_outputs - - # We capture the control_flow_context at this point, before we run `fn` - # inside a while_loop. This is useful in cases where we might need to exit - # these contexts and get back to the outer context to do some things, for - # e.g. create an op which should be evaluated only once at the end of the - # loop on the host. One such usage is in creating metrics' value op. - self._outer_control_flow_context = ( - ops.get_default_graph()._get_control_flow_context()) # pylint: disable=protected-access - - cond = lambda i, *args: i < iterations - i = constant_op.constant(0) - loop_result = control_flow_ops.while_loop( - cond, body, [i] + initial_loop_values, name="", - parallel_iterations=1, back_prop=False, swap_memory=False, - return_same_structure=True) - del self._outer_control_flow_context - - ctx.run_op = control_flow_ops.group(loop_result) - - # Convert the last_step_outputs from a list to the original dict structure - # of last_step_outputs. - last_step_tensor_outputs = loop_result[1:] - last_step_tensor_outputs_dict = nest.pack_sequence_as( - ctx.last_step_outputs, last_step_tensor_outputs) - - for name, reduce_op in ctx._last_step_outputs_reduce_ops.items(): # pylint: disable=protected-access - output = last_step_tensor_outputs_dict[name] - # For outputs that have already been reduced, wrap them in a Mirrored - # container, else in a PerReplica container. - if reduce_op is None: - last_step_tensor_outputs_dict[name] = values.regroup( - {d: t for d, t in zip(self._devices, output)}, values.PerReplica) - else: - assert len(output) == 1 - last_step_tensor_outputs_dict[name] = output[0] - - ctx._set_last_step_outputs(last_step_tensor_outputs_dict) # pylint: disable=protected-access - return ctx - - def _broadcast_to(self, tensor, destinations): - # This is both a fast path for Python constants, and a way to delay - # converting Python values to a tensor until we know what type it - # should be converted to. Otherwise we have trouble with: - # global_step.assign_add(1) - # since the `1` gets broadcast as an int32 but global_step is int64. - if isinstance(tensor, (float, int)): - return tensor - # TODO(josh11b): In eager mode, use one thread per device, or async mode. - return self._get_cross_device_ops().broadcast( - tensor, destinations or self._devices) - - def _call_for_each_replica(self, fn, args, kwargs): - return _call_for_each_replica(self._container_strategy(), fn, args, kwargs) - - def _configure(self, - session_config=None, - cluster_spec=None, - task_type=None, - task_id=None): - del task_type, task_id - - if session_config: - session_config.isolate_session_state = True - - if cluster_spec: - self._initialize_multi_worker(self._num_gpus, cluster_spec) - - if self._cross_device_ops is None: - if self._cluster_spec: - # It currently cannot detect the toplogy of remote workers. So we - # hard-code the multi-worker all-reduce algorithm for now. - if len(self._workers) == 1: - # The default is "nccl". - self._cross_device_ops = ( - cross_device_ops_lib.AllReduceCrossDeviceOps()) - else: - # The default is hierarchical reduce and broadcast. - self._cross_device_ops = cross_device_ops_lib.MultiWorkerAllReduce( - self._workers, self._num_gpus) - else: - self._cross_device_ops = cross_device_ops_lib.choose_the_best( - self._devices, session_config=session_config) - - def _get_cross_device_ops(self): - if self._cross_device_ops is None: - self._cross_device_ops = ( - cross_device_ops_lib.ReductionToOneDeviceCrossDeviceOps()) - return self._cross_device_ops - - def _reduce_to(self, reduce_op, value, destinations): - assert not isinstance(value, values.Mirrored) - if not isinstance(value, values.DistributedValues): - # This function handles reducing values that are not PerReplica or - # Mirrored values. For example, the same value could be present on all - # replicas in which case `value` would be a single value or value could - # be 0. - return _reduce_non_distributed_value(self, reduce_op, value, - destinations) - return self._get_cross_device_ops().reduce( - reduce_op, value, destinations=destinations) - - def _batch_reduce_to(self, reduce_op, value_destination_pairs): - return self._get_cross_device_ops().batch_reduce(reduce_op, - value_destination_pairs) - - def _update(self, var, fn, args, kwargs, group): - # TODO(josh11b): In eager mode, use one thread per device. - assert isinstance(var, values.DistributedVariable) - updates = {} - for d, v in var._index.items(): # pylint: disable=protected-access - name = "update_%d" % self._device_index.get(d) - with ops.device(d), distribute_lib.UpdateContext(d), ops.name_scope(name): - # If args and kwargs are not mirrored, the value is returned as is. - updates[d] = fn(v, - *values.select_device_mirrored(d, args), - **values.select_device_mirrored(d, kwargs)) - return values.update_regroup(self, updates, group) - - def _update_non_slot(self, colocate_with, fn, args, kwargs, group): - assert isinstance(colocate_with, list) - # TODO(josh11b): In eager mode, use one thread per device. - updates = {} - for d in colocate_with: - name = "update_%d" % self._device_index.get(d) - with ops.device(d), distribute_lib.UpdateContext(d), ops.name_scope(name): - updates[d] = fn(*values.select_device_mirrored(d, args), - **values.select_device_mirrored(d, kwargs)) - return values.update_regroup(self, updates, group) - - def read_var(self, replica_local_var): - """Read the aggregate value of a replica-local variable.""" - if isinstance(replica_local_var, values.ReplicaLocalVariable): - return replica_local_var._get_cross_replica() # pylint: disable=protected-access - assert isinstance(replica_local_var, values.Mirrored) - return array_ops.identity(replica_local_var.get()) - - def _unwrap(self, val): - if isinstance(val, values.DistributedValues): - # Return in a deterministic order. - if set(val.devices) == self._canonical_device_set: - return [val.get(device=d) for d in self._devices] - return [val.get(device=d) for d in sorted(val.devices)] - return [val] - - def value_container(self, val): - return values.value_container(val) - - @property - def _num_replicas_in_sync(self): - return len(self._devices) - - @property - def worker_devices(self): - # Make a copy to prevent users from accidentally mutating our copy. - return list(self._devices) - - @property - def parameter_devices(self): - return list(self._devices) - - @property - def experimental_between_graph(self): - return False - - @property - def experimental_should_init(self): - return True - - @property - def should_checkpoint(self): - return True - - @property - def should_save_summary(self): - return True - - def non_slot_devices(self, var_list): - del var_list - return list(self._devices) - - def _get_devices_from(self, colocate_with=None): - if colocate_with is None: - return self._devices - else: - return cross_device_ops_lib.get_devices_from(colocate_with) - - class _MirroredReplicaThread(threading.Thread): - """A thread that runs() a function on a device.""" - - def __init__(self, dist, coord, device, variable_creator_fn, fn, *args, - **kwargs): - super(CoreMirroredExtended._MirroredReplicaThread, self).__init__() # pylint: disable=protected-access - self.coord = coord - self.distribution = dist - self.device = device - self.replica_id = dist.extended.worker_devices.index(device) - self.variable_creator_fn = variable_creator_fn - # State needed to run and return the results of `fn`. - self.main_fn = fn - self.main_args = args - self.main_kwargs = kwargs - self.main_result = None - self.done = False - # State needed to run the next merge_call() (if any) requested via - # ReplicaContext. - self.merge_fn = None - self.merge_args = None - self.merge_kwargs = None - self.merge_result = None - self.captured_name_scope = None - # We use a thread.Event for the main thread to signal when this - # thread should start running (`should_run`), and another for - # this thread to transfer control back to the main thread - # (`has_paused`, either when it gets to a - # `get_replica_context().merge_call` or when `fn` returns). In - # either case the event starts cleared, is signaled by calling - # set(). The receiving thread waits for the signal by calling - # wait() and then immediately clearing the event using clear(). - self.should_run = threading.Event() - self.has_paused = threading.Event() - # These fields have to do with inheriting various contexts from the - # parent thread: - # pylint: disable=protected-access - self.context_mode = context.context()._eager_context.mode - if not context.context()._context_handle: - context.context()._initialize_handle_and_devices() - self.context_device_policy = ( - pywrap_tensorflow.TFE_ContextGetDevicePlacementPolicy( - context.context()._context_handle)) - self.graph = ops.get_default_graph() - self._variable_creator_stack = self.graph._variable_creator_stack[:] - self._captured_var_scope = variable_scope.get_variable_scope() - # Adding a "/" at end lets us re-enter this scope later. - self._name_scope = self.graph.get_name_scope() - if self._name_scope: - self._name_scope += "/" - if self.replica_id > 0: - if not self._name_scope: - self._name_scope = "" - self._name_scope += "replica_%d/" % self.replica_id - - def run(self): - # pylint: disable=protected-access - self.graph._variable_creator_stack = self._variable_creator_stack - self.should_run.wait() - self.should_run.clear() - try: - if self.coord.should_stop(): - return - with self.coord.stop_on_exception(), \ - context.context()._mode(self.context_mode), \ - context.context().device_policy(self.context_device_policy), \ - _enter_graph(self.graph), \ - MirroredReplicaContext(self.distribution, constant_op.constant( - self.replica_id, dtypes.int32)), \ - ops.device(self.device), \ - ops.name_scope(self._name_scope), \ - variable_scope.variable_scope( - self._captured_var_scope, reuse=self.replica_id > 0), \ - variable_scope.variable_creator_scope(self.variable_creator_fn): - self.main_result = self.main_fn(*self.main_args, **self.main_kwargs) - self.done = True - finally: - self.has_paused.set() +# pylint: disable=protected-access,invalid-name +_call_for_each_replica = mirrored_strategy._call_for_each_replica +_reduce_non_distributed_value = mirrored_strategy._reduce_non_distributed_value +_create_mirrored_variable = mirrored_strategy._create_mirrored_variable +CoreMirroredStrategy = mirrored_strategy.MirroredStrategy +CoreMirroredExtended = mirrored_strategy.MirroredExtended +# pylint: enable=protected-access,invalid-name class MirroredStrategy(distribute_lib.DistributionStrategy): @@ -873,43 +139,14 @@ class MirroredExtended(CoreMirroredExtended): def _distribute_dataset(self, dataset_fn): if self._cluster_spec: return values.MultiWorkerDataset( - partial(self._call_dataset_fn, dataset_fn), + functools.partial(self._call_dataset_fn, dataset_fn), self._worker_devices, auto_shard=self._auto_shard_dataset) else: return values.PerReplicaDataset( self._call_dataset_fn(dataset_fn), self._devices) - -class MirroredReplicaContext(distribute_lib.ReplicaContext): - """ReplicaContext used in MirroredStrategy.call_for_each_replica(). - - Opened in `_MirroredReplicaThread`, to allow the user to invoke - `MirroredStrategy`'s specific implementation of `merge_call()`, - which works by delegating the function and its arguments to - the main thread (the one that invoked - `MirroredStrategy.call_for_each_replica()`). - """ - - def _merge_call(self, fn, args, kwargs): - """Delegate to the main thread to actually perform merge_call().""" - t = threading.current_thread() # a _MirroredReplicaThread - t.merge_fn = fn - t.merge_args = args - t.merge_kwargs = kwargs - t.captured_name_scope = t.graph.get_name_scope() - # Adding a "/" at end lets us re-enter this scope later. - if t.captured_name_scope: - t.captured_name_scope += "/" - t.has_paused.set() - t.should_run.wait() - t.should_run.clear() - if t.coord.should_stop(): - raise _RequestedStop() - return t.merge_result - + # TODO(priyag): Delete this once all strategies use global batch size. @property - def devices(self): - distribute_lib.require_replica_context(self) - replica_id = tensor_util.constant_value(self._replica_id_in_sync_group) - return [self._distribution_strategy.extended.worker_devices[replica_id]] + def _global_batch_size(self): + return False diff --git a/tensorflow/contrib/distribute/python/one_device_strategy.py b/tensorflow/contrib/distribute/python/one_device_strategy.py index f881c234ac..421507232a 100644 --- a/tensorflow/contrib/distribute/python/one_device_strategy.py +++ b/tensorflow/contrib/distribute/python/one_device_strategy.py @@ -194,6 +194,11 @@ class OneDeviceExtended(distribute_lib.DistributionStrategyExtended): def should_save_summary(self): return True + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return True + class _OneDeviceReplicaContext(distribute_lib.ReplicaContext): """ReplicaContext for OneDeviceStrategy.""" diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy.py b/tensorflow/contrib/distribute/python/parameter_server_strategy.py index 6fc81a1e57..fc2d2b20c9 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy.py @@ -510,3 +510,8 @@ class ParameterServerExtended(distribute_lib.DistributionStrategyExtended): @property def should_save_summary(self): return self._is_chief + + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return False diff --git a/tensorflow/contrib/distribute/python/tpu_strategy.py b/tensorflow/contrib/distribute/python/tpu_strategy.py index 478e3accd7..f1115cb0c0 100644 --- a/tensorflow/contrib/distribute/python/tpu_strategy.py +++ b/tensorflow/contrib/distribute/python/tpu_strategy.py @@ -544,6 +544,11 @@ class TPUExtended(distribute_lib.DistributionStrategyExtended): if cluster_spec: session_config.cluster_def.CopyFrom(cluster_spec.as_cluster_def()) + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return True + class _TPUReplicaContext(distribute_lib.ReplicaContext): """Replication Context class for TPU Strategy.""" diff --git a/tensorflow/python/distribute/BUILD b/tensorflow/python/distribute/BUILD index 83c3901441..999543d71f 100644 --- a/tensorflow/python/distribute/BUILD +++ b/tensorflow/python/distribute/BUILD @@ -139,6 +139,35 @@ py_library( deps = [], ) +py_library( + name = "mirrored_strategy", + srcs = ["mirrored_strategy.py"], + deps = [ + ":cross_device_ops", + ":multi_worker_util", + ":reduce_util", + ":shared_variable_creator", + ":values", + "//tensorflow/core:protos_all_py", + "//tensorflow/python:array_ops", + "//tensorflow/python:constant_op", + "//tensorflow/python:control_flow_ops", + "//tensorflow/python:device", + "//tensorflow/python:device_util", + "//tensorflow/python:distribute", + "//tensorflow/python:dtypes", + "//tensorflow/python:framework_ops", + "//tensorflow/python:pywrap_tensorflow", + "//tensorflow/python:tensor_util", + "//tensorflow/python:training", + "//tensorflow/python:util", + "//tensorflow/python:variable_scope", + "//tensorflow/python:variables", + "//tensorflow/python/eager:context", + "//tensorflow/python/eager:tape", + ], +) + py_library( name = "multi_worker_util", srcs = [ diff --git a/tensorflow/python/distribute/mirrored_strategy.py b/tensorflow/python/distribute/mirrored_strategy.py new file mode 100644 index 0000000000..7ed096b863 --- /dev/null +++ b/tensorflow/python/distribute/mirrored_strategy.py @@ -0,0 +1,805 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Class MirroredStrategy implementing DistributionStrategy.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import contextlib +import functools +import threading + +from tensorflow.python import pywrap_tensorflow +from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib +from tensorflow.python.distribute import multi_worker_util +from tensorflow.python.distribute import reduce_util +from tensorflow.python.distribute import shared_variable_creator +from tensorflow.python.distribute import values +from tensorflow.python.eager import context +from tensorflow.python.eager import tape +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import device as tf_device +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_util +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import variable_scope +from tensorflow.python.training import coordinator +from tensorflow.python.training import device_util +from tensorflow.python.training import distribute as distribute_lib +from tensorflow.python.util import nest + + +# TODO(josh11b): Replace asserts in this file with if ...: raise ... + + +@contextlib.contextmanager +def _enter_graph(g): + if context.executing_eagerly(): + with g.as_default(), context.eager_mode(): + yield + else: + with g.as_default(): + yield + + +def _cpu_device(device): + cpu_device = tf_device.DeviceSpec.from_string(device) + cpu_device.merge_from(tf_device.DeviceSpec(device_type="CPU", device_index=0)) + return cpu_device.to_string() + + +class _RequestedStop(Exception): # pylint: disable=g-bad-exception-name + pass + + +# _call_for_each_replica and _reduce_non_distributed_value are not members of +# MirroredStrategy so that they are generally not allowed to use anything +# specific to MirroredStrategy and thus can be shared with other distribution +# strategies. + + +# TODO(yuefengz): maybe create a common class for those who need to call this +# _call_for_each_replica. +def _call_for_each_replica(distribution, fn, args, kwargs): + """Run `fn` in separate threads, once per replica/worker device. + + Args: + distribution: the DistributionStrategy object. + fn: function to run (will be run once per device, each in its own thread). + args: positional arguments for `fn` + kwargs: keyword arguments for `fn`. + + Returns: + Merged return value of `fn` across all replicas. + + Raises: + RuntimeError: If fn() calls get_replica_context().merge_call() a different + number of times from the available devices. + """ + # TODO(josh11b): Add this option once we add synchronization to variable + # creation. Until then, this is pretty unsafe to use. + run_concurrently = False + if not context.executing_eagerly(): + # Needed for per-thread device, etc. contexts in graph mode. + ops.get_default_graph().switch_to_thread_local() + + coord = coordinator.Coordinator(clean_stop_exception_types=(_RequestedStop,)) + + shared_variable_store = {} + + # TODO(isaprykin): Create these threads once instead of during every run() + # call. + threads = [] + for index, d in enumerate(distribution.extended.worker_devices): + variable_creator_fn = shared_variable_creator.make_fn( + shared_variable_store, index) + t = MirroredExtended._MirroredReplicaThread( # pylint: disable=protected-access + distribution, coord, d, variable_creator_fn, fn, + *values.select_device(d, args), **values.select_device(d, kwargs)) + threads.append(t) + + for t in threads: + t.start() + + # When `fn` starts `should_run` event is set on _MirroredReplicaThread + # (`MRT`) threads. The execution waits until + # `MRT.has_paused` is set, which indicates that either `fn` is + # complete or a `get_replica_context().merge_call()` is called. If `fn` is + # complete, then `MRT.done` is set to True. Otherwise, arguments + # of `get_replica_context().merge_call` from all paused threads are grouped + # and the `merge_fn` is performed. Results of the + # `get_replica_context().merge_call` are then set to `MRT.merge_result`. + # Each such `get_replica_context().merge_call` call returns the + # `MRT.merge_result` for that thread when `MRT.should_run` event + # is reset again. Execution of `fn` resumes. + + try: + with coord.stop_on_exception(): + all_done = False + while not all_done and not coord.should_stop(): + done = [] + if run_concurrently: + for t in threads: + t.should_run.set() + for t in threads: + t.has_paused.wait() + t.has_paused.clear() + if coord.should_stop(): + return None + done.append(t.done) + else: + for t in threads: + t.should_run.set() + t.has_paused.wait() + t.has_paused.clear() + if coord.should_stop(): + return None + done.append(t.done) + if coord.should_stop(): + return None + all_done = all(done) + if not all_done: + if any(done): + raise RuntimeError("Some replicas made a different number of " + "replica_context().merge_call() calls.") + # get_replica_context().merge_call() case + merge_args = values.regroup({t.device: t.merge_args for t in threads}) + merge_kwargs = values.regroup( + {t.device: t.merge_kwargs for t in threads}) + # We capture the name_scope of the MRT when we call merge_fn + # to ensure that if we have opened a name scope in the MRT, + # it will be respected when executing the merge function. We only + # capture the name_scope from the first MRT and assume it is + # the same for all other MRTs. + mtt_captured_name_scope = threads[0].captured_name_scope + with ops.name_scope(mtt_captured_name_scope): + merge_result = threads[0].merge_fn(distribution, *merge_args, + **merge_kwargs) + for t in threads: + t.merge_result = values.select_device(t.device, merge_result) + finally: + for t in threads: + t.should_run.set() + coord.join(threads) + + return values.regroup({t.device: t.main_result for t in threads}) + + +def _reduce_non_distributed_value(extended, reduce_op, value, destinations): + """Reduce a non-DistributedValue `value` to `destinations`.""" + if isinstance(value, values.DistributedValues): + raise ValueError("You are passing a `DistributedValue` to " + "`_reduce_non_distributed_value`, which is not allowed.") + + # If the same value is present on all replicas then the PerReplica value will + # be a single value. We also handle the case when `value` is a single value + # and equal to 0. + if value == 0: + return 0 + # If there is only a single value and the reduce op is MEAN, + # that value should be on all destinations. + if reduce_op == reduce_util.ReduceOp.MEAN: + return value + + cross_device_ops_lib.validate_destinations(destinations) + # We do not support a reduce op of SUM if the value is the same across + # all replicas. We call this as part of assign functions for MirroredVariables + # and summing up identical values across replicas is not clearly defined. + if (len(extended.worker_devices) != 1 or + not cross_device_ops_lib.check_destinations(destinations)): + raise ValueError("A non-DistributedValues value %s cannot be reduced with " + "the given reduce op %s." % (value, reduce_op)) + # TODO(anjalisridhar): Moves these methods to a device utility file? + devices = cross_device_ops_lib.get_devices_from(destinations) + if len(devices) == 1: + with ops.device(devices[0]): + return array_ops.identity(value) + else: + value_updates = {} + for d in devices: + with ops.device(d): + value_updates[d] = array_ops.identity(value) + return values.Mirrored(value_updates) + + +def _create_mirrored_variable(devices, real_mirrored_creator, *args, **kwargs): # pylint: disable=g-missing-docstring + # Figure out what collections this variable should be added to. + # We'll add the MirroredVariable to those collections instead. + collections = kwargs.pop("collections", None) + if collections is None: + collections = [ops.GraphKeys.GLOBAL_VARIABLES] + kwargs["collections"] = [] + + # Get synchronization value + synchronization = kwargs.get("synchronization", + variable_scope.VariableSynchronization.ON_WRITE) + if synchronization == variable_scope.VariableSynchronization.NONE: + raise ValueError("`NONE` variable synchronization mode is not " + "supported with `Mirrored` distribution strategy. Please" + " change the `synchronization` for variable: " + + kwargs["name"]) + elif synchronization == variable_scope.VariableSynchronization.ON_READ: + # Variables that are to be synced on read are replica local. + is_replica_local = True + kwargs["trainable"] = False + elif (synchronization == variable_scope.VariableSynchronization.ON_WRITE or + synchronization == variable_scope.VariableSynchronization.AUTO): + # `AUTO` synchronization for `MirroredStrategy` is `ON_WRITE`. + is_replica_local = False + else: + raise ValueError("Invalid variable synchronization mode: " + + synchronization + " for variable: " + kwargs["name"]) + + # Get aggregation value + aggregation = kwargs.pop("aggregation", + variable_scope.VariableAggregation.NONE) + if aggregation not in ( + variable_scope.VariableAggregation.NONE, + variable_scope.VariableAggregation.SUM, + variable_scope.VariableAggregation.MEAN, + variable_scope.VariableAggregation.ONLY_FIRST_REPLICA + ): + raise ValueError("Invalid variable aggregation mode: " + aggregation + + " for variable: " + kwargs["name"]) + + # Ignore user-specified caching device, not needed for mirrored variables. + kwargs.pop("caching_device", None) + + # TODO(josh11b,apassos): It would be better if variable initialization + # was never recorded on the tape instead of having to do this manually + # here. + with tape.stop_recording(): + index = real_mirrored_creator(devices, *args, **kwargs) + + if is_replica_local: + result = values.ReplicaLocalVariable( + index, index[devices[0]], aggregation) + else: + result = values.MirroredVariable(index, index[devices[0]], aggregation) + + # Add the wrapped variable to the requested collections. + # The handling of eager mode and the global step matches + # ResourceVariable._init_from_args(). + if not context.executing_eagerly(): + g = ops.get_default_graph() + # If "trainable" is True, next_creator() will add the member variables + # to the TRAINABLE_VARIABLES collection, so we manually remove + # them and replace with the MirroredVariable. We can't set + # "trainable" to False for next_creator() since that causes functions + # like implicit_gradients to skip those variables. + if kwargs.get("trainable", True): + collections.append(ops.GraphKeys.TRAINABLE_VARIABLES) + l = g.get_collection_ref(ops.GraphKeys.TRAINABLE_VARIABLES) + for v in index.values(): + if v in l: + l.remove(v) + g.add_to_collections(collections, result) + elif ops.GraphKeys.GLOBAL_STEP in collections: + ops.add_to_collections(ops.GraphKeys.GLOBAL_STEP, result) + + return result + + +class MirroredStrategy(distribute_lib.DistributionStrategy): + """Mirrors vars to distribute across multiple devices and machines. + + This strategy uses one replica per device and sync replication for its + multi-GPU version. + + The multi-worker version will be added in the fture. + + Args: + devices: a list of device strings. + num_gpus_per_worker: number of GPUs per worker. + cross_device_ops: optional, a descedant of `CrossDeviceOps`. If this is not + set, nccl will be use by default. + """ + + def __init__(self, + devices=None, + num_gpus_per_worker=None, + cross_device_ops=None): + extended = MirroredExtended(self, devices, num_gpus_per_worker, + cross_device_ops) + super(MirroredStrategy, self).__init__(extended) + + +class MirroredExtended(distribute_lib.DistributionStrategyExtended): + """Implementation of MirroredStrategy.""" + + def __init__(self, + container_strategy, + devices=None, + num_gpus_per_worker=None, + cross_device_ops=None): + super(MirroredExtended, self).__init__(container_strategy) + self._cross_device_ops = cross_device_ops + # Remember num GPUs which might be needed by `configure` method. + self._num_gpus = num_gpus_per_worker + + self._initialize_local(self._num_gpus, devices) + + def _initialize_local(self, num_gpus, devices): + """Initializes the object for local training.""" + self._cluster_spec = None + # Convert `num_gpus` into `devices`, shouldn't specify both. + if devices is None: + if num_gpus is None: + num_gpus = context.num_gpus() + if num_gpus == 0: + devices = ["/device:CPU:0"] + else: + devices = ["/device:GPU:%d" % d for d in range(num_gpus)] + elif num_gpus is not None: + raise ValueError("Must only specify one of `devices` and `num_gpus`.") + self._num_gpus = num_gpus + # TODO(yuefengz): consider setting the default device. + + assert devices, "Must specify at least one device." + assert len(set(devices)) == len(devices), ( + "No duplicates allowed in `devices` argument.") + # TODO(josh11b): Require at least 2 devices? + self._devices = [device_util.resolve(d) for d in devices] + self._canonical_device_set = set(self._devices) + self._device_index = values.PerReplica( + {d: i for i, d in enumerate(devices)}) + + def _initialize_multi_worker(self, num_gpus, cluster_spec): + """Initializes the object for multi-worker training.""" + cluster_spec = multi_worker_util.normalize_cluster_spec(cluster_spec) + self._cluster_spec = cluster_spec + + self._workers = [] + for job in ["chief", "worker"]: + for task in range(len(cluster_spec.as_dict().get(job, []))): + self._workers.append("/job:%s/task:%d" % (job, task)) + + if num_gpus is None: + raise ValueError("`num_gpus` is required if `cluster_spec` is given.") + if num_gpus > 0: + self._worker_devices = [ + (worker, [ + device_util.canonicalize(worker + "/device:GPU:%d" % gpu) + for gpu in range(num_gpus) + ]) for worker in self._workers + ] + else: + self._worker_devices = [ + (worker, [device_util.canonicalize(worker, "/device:CPU:0")]) + for worker in self._workers + ] + + devices = nest.flatten([l for _, l in self._worker_devices]) + + # Setting `_default_device` will add a device scope in the + # distribution.scope. We set the default device to the first worker. When + # users specify device under distribution.scope by + # with tf.device("/cpu:0"): + # ... + # their ops will end up on the cpu device of its first worker, e.g. + # "/job:worker/task:0/device:CPU:0". Note this is not used in replica mode. + self._default_device = self._workers[0] + + assert devices, "Must specify at least one device." + assert len(set(devices)) == len(devices), ( + "No duplicates allowed in `devices` argument.") + # TODO(josh11b): Require at least 2 devices? + self._devices = [device_util.resolve(d) for d in devices] + self._canonical_device_set = set(self._devices) + self._device_index = values.PerReplica( + {d: i for i, d in enumerate(devices)}) + + def _create_variable(self, next_creator, *args, **kwargs): + """Create a mirrored variable. See `DistributionStrategy.scope`.""" + colocate_with = kwargs.pop("colocate_with", None) + devices = self._get_devices_from(colocate_with) + + def _real_mirrored_creator(devices, *args, **kwargs): # pylint: disable=g-missing-docstring + index = {} + for i, d in enumerate(devices): + with ops.device(d): + if i > 0: + # Give replicas meaningful distinct names: + var0name = index[devices[0]].name.split(":")[0] + # We append a / to variable names created on replicas with id > 0 to + # ensure that we ignore the name scope and instead use the given + # name as the absolute name of the variable. + kwargs["name"] = "%s/replica_%d/" % (var0name, i) + # Initialize replicas with the same value: + def initial_value_fn(device=d): + if context.executing_eagerly(): + init_value = index[devices[0]].value() + return array_ops.identity(init_value) + else: + with ops.device(device): + init_value = index[devices[0]].initial_value + return array_ops.identity(init_value) + kwargs["initial_value"] = initial_value_fn + with context.context().device_policy(context.DEVICE_PLACEMENT_SILENT): + # Don't record operations (e.g. other variable reads) during + # variable creation. + with tape.stop_recording(): + v = next_creator(*args, **kwargs) + assert not isinstance(v, values.DistributedVariable) + index[d] = v + return index + + return _create_mirrored_variable(devices, _real_mirrored_creator, *args, + **kwargs) + + def _distribute_dataset(self, dataset_fn): + if self._cluster_spec: + return values.MultiWorkerDataset( + functools.partial(self._call_dataset_fn, dataset_fn), + self._worker_devices, + auto_shard=False) + else: + return values.PerReplicaDataset( + self._call_dataset_fn(dataset_fn), self._devices) + + def _make_dataset_iterator(self, dataset): + if self._cluster_spec: + worker_device_pairs = self._worker_devices + else: + worker_device_pairs = [("/job:localhost", self._devices)] + return values.DatasetIterator(dataset, worker_device_pairs, + self._num_replicas_in_sync) + + def _make_input_fn_iterator( + self, + input_fn, + replication_mode=distribute_lib.InputReplicationMode.PER_WORKER): + input_contexts = [] + if self._cluster_spec: + num_workers = len(self._worker_devices) + worker_device_pairs = self._worker_devices + else: + num_workers = 1 + worker_device_pairs = [("/job:localhost", self._devices)] + for i in range(num_workers): + input_contexts.append(distribute_lib.InputContext( + num_input_pipelines=num_workers, + input_pipeline_id=i, + num_replicas_in_sync=self._num_replicas_in_sync)) + return values.InputFunctionIterator( + input_fn, worker_device_pairs, input_contexts) + + # TODO(priyag): Deal with OutOfRange errors once b/111349762 is fixed. + def _experimental_run_steps_on_iterator(self, fn, iterator, iterations, + initial_loop_values=None): + if initial_loop_values is None: + initial_loop_values = {} + initial_loop_values = nest.flatten(initial_loop_values) + + ctx = values.MultiStepContext() + def body(i, *args): + """A wrapper around `fn` to create the while loop body.""" + del args + fn_inputs = iterator.get_next() + if not isinstance(fn_inputs, tuple): + fn_inputs = (fn_inputs,) + fn_result = fn(ctx, fn_inputs) + for (name, output) in ctx.last_step_outputs.items(): + # Convert all outputs to tensors, potentially from `DistributedValues`. + ctx.last_step_outputs[name] = self._unwrap(output) + flat_last_step_outputs = nest.flatten(ctx.last_step_outputs) + with ops.control_dependencies([fn_result]): + return [i + 1] + flat_last_step_outputs + + # We capture the control_flow_context at this point, before we run `fn` + # inside a while_loop. This is useful in cases where we might need to exit + # these contexts and get back to the outer context to do some things, for + # e.g. create an op which should be evaluated only once at the end of the + # loop on the host. One such usage is in creating metrics' value op. + self._outer_control_flow_context = ( + ops.get_default_graph()._get_control_flow_context()) # pylint: disable=protected-access + + cond = lambda i, *args: i < iterations + i = constant_op.constant(0) + loop_result = control_flow_ops.while_loop( + cond, body, [i] + initial_loop_values, name="", + parallel_iterations=1, back_prop=False, swap_memory=False, + return_same_structure=True) + del self._outer_control_flow_context + + ctx.run_op = control_flow_ops.group(loop_result) + + # Convert the last_step_outputs from a list to the original dict structure + # of last_step_outputs. + last_step_tensor_outputs = loop_result[1:] + last_step_tensor_outputs_dict = nest.pack_sequence_as( + ctx.last_step_outputs, last_step_tensor_outputs) + + for name, reduce_op in ctx._last_step_outputs_reduce_ops.items(): # pylint: disable=protected-access + output = last_step_tensor_outputs_dict[name] + # For outputs that have already been reduced, wrap them in a Mirrored + # container, else in a PerReplica container. + if reduce_op is None: + last_step_tensor_outputs_dict[name] = values.regroup( + {d: t for d, t in zip(self._devices, output)}, values.PerReplica) + else: + assert len(output) == 1 + last_step_tensor_outputs_dict[name] = output[0] + + ctx._set_last_step_outputs(last_step_tensor_outputs_dict) # pylint: disable=protected-access + return ctx + + def _broadcast_to(self, tensor, destinations): + # This is both a fast path for Python constants, and a way to delay + # converting Python values to a tensor until we know what type it + # should be converted to. Otherwise we have trouble with: + # global_step.assign_add(1) + # since the `1` gets broadcast as an int32 but global_step is int64. + if isinstance(tensor, (float, int)): + return tensor + # TODO(josh11b): In eager mode, use one thread per device, or async mode. + return self._get_cross_device_ops().broadcast( + tensor, destinations or self._devices) + + def _call_for_each_replica(self, fn, args, kwargs): + return _call_for_each_replica(self._container_strategy(), fn, args, kwargs) + + def _configure(self, + session_config=None, + cluster_spec=None, + task_type=None, + task_id=None): + del task_type, task_id + + if session_config: + session_config.isolate_session_state = True + + if cluster_spec: + self._initialize_multi_worker(self._num_gpus, cluster_spec) + + if self._cross_device_ops is None: + if self._cluster_spec: + # It currently cannot detect the toplogy of remote workers. So we + # hard-code the multi-worker all-reduce algorithm for now. + if len(self._workers) == 1: + # The default is "nccl". + self._cross_device_ops = ( + cross_device_ops_lib.AllReduceCrossDeviceOps()) + else: + # The default is hierarchical reduce and broadcast. + self._cross_device_ops = cross_device_ops_lib.MultiWorkerAllReduce( + self._workers, self._num_gpus) + else: + self._cross_device_ops = cross_device_ops_lib.choose_the_best( + self._devices, session_config=session_config) + + def _get_cross_device_ops(self): + if self._cross_device_ops is None: + self._cross_device_ops = ( + cross_device_ops_lib.ReductionToOneDeviceCrossDeviceOps()) + return self._cross_device_ops + + def _reduce_to(self, reduce_op, value, destinations): + assert not isinstance(value, values.Mirrored) + if not isinstance(value, values.DistributedValues): + # This function handles reducing values that are not PerReplica or + # Mirrored values. For example, the same value could be present on all + # replicas in which case `value` would be a single value or value could + # be 0. + return _reduce_non_distributed_value(self, reduce_op, value, + destinations) + return self._get_cross_device_ops().reduce( + reduce_op, value, destinations=destinations) + + def _batch_reduce_to(self, reduce_op, value_destination_pairs): + return self._get_cross_device_ops().batch_reduce(reduce_op, + value_destination_pairs) + + def _update(self, var, fn, args, kwargs, group): + # TODO(josh11b): In eager mode, use one thread per device. + assert isinstance(var, values.DistributedVariable) + updates = {} + for d, v in var._index.items(): # pylint: disable=protected-access + name = "update_%d" % self._device_index.get(d) + with ops.device(d), distribute_lib.UpdateContext(d), ops.name_scope(name): + # If args and kwargs are not mirrored, the value is returned as is. + updates[d] = fn(v, + *values.select_device_mirrored(d, args), + **values.select_device_mirrored(d, kwargs)) + return values.update_regroup(self, updates, group) + + def _update_non_slot(self, colocate_with, fn, args, kwargs, group): + assert isinstance(colocate_with, list) + # TODO(josh11b): In eager mode, use one thread per device. + updates = {} + for d in colocate_with: + name = "update_%d" % self._device_index.get(d) + with ops.device(d), distribute_lib.UpdateContext(d), ops.name_scope(name): + updates[d] = fn(*values.select_device_mirrored(d, args), + **values.select_device_mirrored(d, kwargs)) + return values.update_regroup(self, updates, group) + + def read_var(self, replica_local_var): + """Read the aggregate value of a replica-local variable.""" + if isinstance(replica_local_var, values.ReplicaLocalVariable): + return replica_local_var._get_cross_replica() # pylint: disable=protected-access + assert isinstance(replica_local_var, values.Mirrored) + return array_ops.identity(replica_local_var.get()) + + def _unwrap(self, val): + if isinstance(val, values.DistributedValues): + # Return in a deterministic order. + if set(val.devices) == self._canonical_device_set: + return [val.get(device=d) for d in self._devices] + return [val.get(device=d) for d in sorted(val.devices)] + return [val] + + def value_container(self, val): + return values.value_container(val) + + @property + def _num_replicas_in_sync(self): + return len(self._devices) + + @property + def worker_devices(self): + # Make a copy to prevent users from accidentally mutating our copy. + return list(self._devices) + + @property + def parameter_devices(self): + return list(self._devices) + + @property + def experimental_between_graph(self): + return False + + @property + def experimental_should_init(self): + return True + + @property + def should_checkpoint(self): + return True + + @property + def should_save_summary(self): + return True + + def non_slot_devices(self, var_list): + del var_list + return list(self._devices) + + def _get_devices_from(self, colocate_with=None): + if colocate_with is None: + return self._devices + else: + return cross_device_ops_lib.get_devices_from(colocate_with) + + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return True + + class _MirroredReplicaThread(threading.Thread): + """A thread that runs() a function on a device.""" + + def __init__(self, dist, coord, device, variable_creator_fn, fn, *args, + **kwargs): + super(MirroredExtended._MirroredReplicaThread, self).__init__() # pylint: disable=protected-access + self.coord = coord + self.distribution = dist + self.device = device + self.replica_id = dist.extended.worker_devices.index(device) + self.variable_creator_fn = variable_creator_fn + # State needed to run and return the results of `fn`. + self.main_fn = fn + self.main_args = args + self.main_kwargs = kwargs + self.main_result = None + self.done = False + # State needed to run the next merge_call() (if any) requested via + # ReplicaContext. + self.merge_fn = None + self.merge_args = None + self.merge_kwargs = None + self.merge_result = None + self.captured_name_scope = None + # We use a thread.Event for the main thread to signal when this + # thread should start running (`should_run`), and another for + # this thread to transfer control back to the main thread + # (`has_paused`, either when it gets to a + # `get_replica_context().merge_call` or when `fn` returns). In + # either case the event starts cleared, is signaled by calling + # set(). The receiving thread waits for the signal by calling + # wait() and then immediately clearing the event using clear(). + self.should_run = threading.Event() + self.has_paused = threading.Event() + # These fields have to do with inheriting various contexts from the + # parent thread: + # pylint: disable=protected-access + self.context_mode = context.context()._eager_context.mode + if not context.context()._context_handle: + context.context()._initialize_handle_and_devices() + self.context_device_policy = ( + pywrap_tensorflow.TFE_ContextGetDevicePlacementPolicy( + context.context()._context_handle)) + self.graph = ops.get_default_graph() + self._variable_creator_stack = self.graph._variable_creator_stack[:] + self._captured_var_scope = variable_scope.get_variable_scope() + # Adding a "/" at end lets us re-enter this scope later. + self._name_scope = self.graph.get_name_scope() + if self._name_scope: + self._name_scope += "/" + if self.replica_id > 0: + if not self._name_scope: + self._name_scope = "" + self._name_scope += "replica_%d/" % self.replica_id + + def run(self): + # pylint: disable=protected-access + self.graph._variable_creator_stack = self._variable_creator_stack + self.should_run.wait() + self.should_run.clear() + try: + if self.coord.should_stop(): + return + with self.coord.stop_on_exception(), \ + context.context()._mode(self.context_mode), \ + context.context().device_policy(self.context_device_policy), \ + _enter_graph(self.graph), \ + MirroredReplicaContext(self.distribution, constant_op.constant( + self.replica_id, dtypes.int32)), \ + ops.device(self.device), \ + ops.name_scope(self._name_scope), \ + variable_scope.variable_scope( + self._captured_var_scope, reuse=self.replica_id > 0), \ + variable_scope.variable_creator_scope(self.variable_creator_fn): + self.main_result = self.main_fn(*self.main_args, **self.main_kwargs) + self.done = True + finally: + self.has_paused.set() + + +class MirroredReplicaContext(distribute_lib.ReplicaContext): + """ReplicaContext used in MirroredStrategy.call_for_each_replica(). + + Opened in `_MirroredReplicaThread`, to allow the user to invoke + `MirroredStrategy`'s specific implementation of `merge_call()`, + which works by delegating the function and its arguments to + the main thread (the one that invoked + `MirroredStrategy.call_for_each_replica()`). + """ + + def _merge_call(self, fn, args, kwargs): + """Delegate to the main thread to actually perform merge_call().""" + t = threading.current_thread() # a _MirroredReplicaThread + t.merge_fn = fn + t.merge_args = args + t.merge_kwargs = kwargs + t.captured_name_scope = t.graph.get_name_scope() + # Adding a "/" at end lets us re-enter this scope later. + if t.captured_name_scope: + t.captured_name_scope += "/" + t.has_paused.set() + t.should_run.wait() + t.should_run.clear() + if t.coord.should_stop(): + raise _RequestedStop() + return t.merge_result + + @property + def devices(self): + distribute_lib.require_replica_context(self) + replica_id = tensor_util.constant_value(self._replica_id_in_sync_group) + return [self._distribution_strategy.extended.worker_devices[replica_id]] diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index 41da3930e2..25685fb5cf 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -391,14 +391,11 @@ def validate_inputs(x, y, distribution_strategy): 'Found unknown shape {} in input {}.'.format(s, i)) -# TODO(b/118776054): Currently we support global batch size for TPUStrategy -# and CoreMirroredStrategy only. Remove this check when contrib MirroredStrategy -# is no longer needed. +# TODO(b/118776054): Currently we support global batch size for TPUStrategy and +# core MirroredStrategy only. Remove this check when contrib MirroredStrategy is +# no longer needed. def global_batch_size_supported(distribution_strategy): - strategy_name = distribution_strategy.__class__.__name__ - # TODO(priyag): Change this to whatever condition makes sense when - # CoreMirroredStrategy is moved to core and renamed. - return strategy_name in ('TPUStrategy', 'CoreMirroredStrategy') + return distribution_strategy.extended._global_batch_size # pylint: disable=protected-access # TODO(sourabhbajaj): Remove this once we use the same API for all strategies. diff --git a/tensorflow/python/training/distribute.py b/tensorflow/python/training/distribute.py index 4ef784d121..f930a89f99 100644 --- a/tensorflow/python/training/distribute.py +++ b/tensorflow/python/training/distribute.py @@ -1604,6 +1604,11 @@ class _DefaultDistributionExtended(DistributionStrategyExtended): else: return [self._iterator.initializer] + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return True + # ------------------------------------------------------------------------------ # We haven't yet implemented deserialization for DistributedVariables. -- GitLab From 38ec3338777fbd8605e45e19bb50f4e4c0055a62 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 20 Nov 2018 20:36:21 -0800 Subject: [PATCH 180/672] Change API for feature_column.categorical_column_with_vocabulary_file for TF 2.0. PiperOrigin-RevId: 222348279 --- .../feature_column/feature_column_v2.py | 93 ++++++++++++++++++- .../golden/v2/tensorflow.feature_column.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 4 + 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/feature_column/feature_column_v2.py b/tensorflow/python/feature_column/feature_column_v2.py index 59828de840..2af2b9f254 100644 --- a/tensorflow/python/feature_column/feature_column_v2.py +++ b/tensorflow/python/feature_column/feature_column_v2.py @@ -1435,7 +1435,7 @@ def categorical_column_with_hash_bucket(key, return HashedCategoricalColumn(key, hash_bucket_size, dtype) -@tf_export('feature_column.categorical_column_with_vocabulary_file') +@tf_export(v1=['feature_column.categorical_column_with_vocabulary_file']) def categorical_column_with_vocabulary_file(key, vocabulary_file, vocabulary_size=None, @@ -1513,6 +1513,97 @@ def categorical_column_with_vocabulary_file(key, Returns: A `CategoricalColumn` with a vocabulary file. + Raises: + ValueError: `vocabulary_file` is missing or cannot be opened. + ValueError: `vocabulary_size` is missing or < 1. + ValueError: `num_oov_buckets` is a negative integer. + ValueError: `num_oov_buckets` and `default_value` are both specified. + ValueError: `dtype` is neither string nor integer. + """ + return categorical_column_with_vocabulary_file_v2( + key, vocabulary_file, vocabulary_size, + dtype, default_value, + num_oov_buckets) + + +@tf_export('feature_column.categorical_column_with_vocabulary_file', v1=[]) +def categorical_column_with_vocabulary_file_v2(key, + vocabulary_file, + vocabulary_size=None, + dtype=dtypes.string, + default_value=None, + num_oov_buckets=0): + """A `CategoricalColumn` with a vocabulary file. + + Use this when your inputs are in string or integer format, and you have a + vocabulary file that maps each value to an integer ID. By default, + out-of-vocabulary values are ignored. Use either (but not both) of + `num_oov_buckets` and `default_value` to specify how to include + out-of-vocabulary values. + + For input dictionary `features`, `features[key]` is either `Tensor` or + `SparseTensor`. If `Tensor`, missing values can be represented by `-1` for int + and `''` for string, which will be dropped by this feature column. + + Example with `num_oov_buckets`: + File '/us/states.txt' contains 50 lines, each with a 2-character U.S. state + abbreviation. All inputs with values in that file are assigned an ID 0-49, + corresponding to its line number. All other values are hashed and assigned an + ID 50-54. + + ```python + states = categorical_column_with_vocabulary_file( + key='states', vocabulary_file='/us/states.txt', vocabulary_size=50, + num_oov_buckets=5) + columns = [states, ...] + features = tf.parse_example(..., features=make_parse_example_spec(columns)) + linear_prediction = linear_model(features, columns) + ``` + + Example with `default_value`: + File '/us/states.txt' contains 51 lines - the first line is 'XX', and the + other 50 each have a 2-character U.S. state abbreviation. Both a literal 'XX' + in input, and other values missing from the file, will be assigned ID 0. All + others are assigned the corresponding line number 1-50. + + ```python + states = categorical_column_with_vocabulary_file( + key='states', vocabulary_file='/us/states.txt', vocabulary_size=51, + default_value=0) + columns = [states, ...] + features = tf.parse_example(..., features=make_parse_example_spec(columns)) + linear_prediction, _, _ = linear_model(features, columns) + ``` + + And to make an embedding with either: + + ```python + columns = [embedding_column(states, 3),...] + features = tf.parse_example(..., features=make_parse_example_spec(columns)) + dense_tensor = input_layer(features, columns) + ``` + + Args: + key: A unique string identifying the input feature. It is used as the + column name and the dictionary key for feature parsing configs, feature + `Tensor` objects, and feature columns. + vocabulary_file: The vocabulary file name. + vocabulary_size: Number of the elements in the vocabulary. This must be no + greater than length of `vocabulary_file`, if less than length, later + values are ignored. If None, it is set to the length of `vocabulary_file`. + dtype: The type of features. Only string and integer types are supported. + default_value: The integer ID value to return for out-of-vocabulary feature + values, defaults to `-1`. This can not be specified with a positive + `num_oov_buckets`. + num_oov_buckets: Non-negative integer, the number of out-of-vocabulary + buckets. All out-of-vocabulary inputs will be assigned IDs in the range + `[vocabulary_size, vocabulary_size+num_oov_buckets)` based on a hash of + the input value. A positive `num_oov_buckets` can not be specified with + `default_value`. + + Returns: + A `CategoricalColumn` with a vocabulary file. + Raises: ValueError: `vocabulary_file` is missing or cannot be opened. ValueError: `vocabulary_size` is missing or < 1. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.feature_column.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.feature_column.pbtxt index f6e165bd7a..3aadd7dc34 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.feature_column.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.feature_column.pbtxt @@ -14,7 +14,7 @@ tf_module { } member_method { name: "categorical_column_with_vocabulary_file" - argspec: "args=[\'key\', \'vocabulary_file\', \'vocabulary_size\', \'num_oov_buckets\', \'default_value\', \'dtype\'], varargs=None, keywords=None, defaults=[\'None\', \'0\', \'None\', \"\"], " + argspec: "args=[\'key\', \'vocabulary_file\', \'vocabulary_size\', \'dtype\', \'default_value\', \'num_oov_buckets\'], varargs=None, keywords=None, defaults=[\'None\', \"\", \'None\', \'0\'], " } member_method { name: "categorical_column_with_vocabulary_list" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index c60c6a4b32..0caf1743d7 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -205,6 +205,10 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "input", "min_range", "max_range", "T", "mode", "name", "round_mode" ], + "tf.feature_column.categorical_column_with_vocabulary_file": [ + "key", "vocabulary_file", "vocabulary_size", + "num_oov_buckets", "default_value", "dtype" + ], "tf.shape": ["input", "name", "out_type"], "tf.size": ["input", "name", "out_type"], "tf.sparse.concat": [ -- GitLab From a911ecf5a94e037554f677670762b0122c062b41 Mon Sep 17 00:00:00 2001 From: Cibifang Date: Wed, 21 Nov 2018 13:34:07 +0800 Subject: [PATCH 181/672] Raise error if trying to use Gradients when scope have device or control dependencies specified(Gradients doesn't currently support them). --- tensorflow/go/op/gradients.go | 16 +++++++++++++++- tensorflow/go/op/gradients_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tensorflow/go/op/gradients.go b/tensorflow/go/op/gradients.go index 2eaa7e70ab..9f892e1da6 100644 --- a/tensorflow/go/op/gradients.go +++ b/tensorflow/go/op/gradients.go @@ -16,7 +16,12 @@ limitations under the License. package op -import tf "github.com/tensorflow/tensorflow/tensorflow/go" +import ( + "fmt" + + tf "github.com/tensorflow/tensorflow/tensorflow/go" +) + // Gradients adds gradients computation ops to the graph according to scope. // @@ -27,6 +32,15 @@ import tf "github.com/tensorflow/tensorflow/tensorflow/go" // // return the partial derivatives func Gradients(scope *Scope, y []tf.Output, x []tf.Output, dx ...tf.Output) (output []tf.Output) { + if len(scope.controlDependencies) > 0 { + scope.UpdateErr("Gradients", fmt.Errorf("Gradients does not currently support control dependencies (via Scope.WithControlDependencies).")) + return + } + if scope.device != "" { + scope.UpdateErr("Gradients", fmt.Errorf("Gradients does not currently support device annotations (via Scope.WithDevice).")) + return + } + var err error if output, err = scope.graph.AddGradients(scope.opName("Gradients"), y, x, dx); err != nil { scope.UpdateErr("Gradients", err) diff --git a/tensorflow/go/op/gradients_test.go b/tensorflow/go/op/gradients_test.go index 1febd08366..3d1d57b77e 100644 --- a/tensorflow/go/op/gradients_test.go +++ b/tensorflow/go/op/gradients_test.go @@ -214,3 +214,33 @@ func TestValidateGradientsNames(t *testing.T) { t.Error("Gradients should have failed if executed more than once for scope of the same namespace") } } + +func TestAddGradientsWithControlDependencies(t *testing.T) { + var ( + s = NewScope() + zero = Const(s.SubScope("zero"), int32(0)) + x = Placeholder(s.SubScope("x"), tf.Float) + y0 = Square(s.SubScope("y0"), x) + variable = VarHandleOp(s, tf.Int32, tf.ScalarShape()) + init = AssignVariableOp(s, variable, zero) + readDeps = []*tf.Operation{init} + ) + s = s.WithControlDependencies(readDeps...) + Gradients(s, []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err == nil { + t.Error("Gradients should have failed when control dependencies are set") + } +} + +func TestAddGradientsWithDevice(t *testing.T) { + var ( + s = NewScope() + x = Placeholder(s.SubScope("x"), tf.Float) + y0 = Square(s.SubScope("y0"), x) + ) + s = s.WithDevice("/device:GPU:0") + Gradients(s, []tf.Output{y0}, []tf.Output{x}) + if err := s.Err(); err == nil { + t.Error("Gradients should have failed when device is set") + } +} -- GitLab From abea54aa8c963ea6cd3edaa9a28acf4999eb6e70 Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Tue, 20 Nov 2018 22:57:59 -0800 Subject: [PATCH 182/672] Adding V2 APIs for Mean and Accuracy metrics. PiperOrigin-RevId: 222357974 --- tensorflow/python/keras/metrics.py | 153 ++++++++++++-- tensorflow/python/keras/metrics_test.py | 48 ++++- tensorflow/python/ops/metrics_impl.py | 4 +- .../tensorflow.keras.metrics.-accuracy.pbtxt | 194 ++++++++++++++++++ ...rflow.keras.metrics.-binary-accuracy.pbtxt | 194 ++++++++++++++++++ ....keras.metrics.-categorical-accuracy.pbtxt | 194 ++++++++++++++++++ .../v2/tensorflow.keras.metrics.-mean.pbtxt | 192 +++++++++++++++++ ...metrics.-sparse-categorical-accuracy.pbtxt | 194 ++++++++++++++++++ .../golden/v2/tensorflow.keras.metrics.pbtxt | 20 ++ .../v2/tensorflow.metrics.-accuracy.pbtxt | 194 ++++++++++++++++++ .../tensorflow.metrics.-binary-accuracy.pbtxt | 194 ++++++++++++++++++ ...orflow.metrics.-categorical-accuracy.pbtxt | 194 ++++++++++++++++++ .../golden/v2/tensorflow.metrics.-mean.pbtxt | 192 +++++++++++++++++ ...metrics.-sparse-categorical-accuracy.pbtxt | 194 ++++++++++++++++++ .../api/golden/v2/tensorflow.metrics.pbtxt | 26 ++- 15 files changed, 2163 insertions(+), 24 deletions(-) create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-binary-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-categorical-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-mean.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-sparse-categorical-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.metrics.-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.metrics.-binary-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.metrics.-categorical-accuracy.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.metrics.-mean.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.metrics.-sparse-categorical-accuracy.pbtxt diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 0793585047..de99d47d5e 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -401,7 +401,7 @@ def _update_confusion_matrix_variables(variables_to_update, class Metric(Layer): """Encapsulates metric logic and state. - Usage with eager execution: + Usage: ```python m = SomeMetric(...) @@ -410,19 +410,6 @@ class Metric(Layer): print('Final result: ', m.result().numpy()) ``` - Usage with graph execution: - - ```python - m = SomeMetric(...) - init_op = tf.variables_initializer(m.variables) # Initialize variables - with tf.Session() as sess: - sess.run(init_op) - for input in ...: - update_op = m.update_state(input) - sess.run(update_op) - print('Final result: ', sess.run(m.result())) - ``` - Usage with tf.keras API: ```python @@ -600,15 +587,35 @@ class Metric(Layer): ### End: For use by subclasses ### +@tf_export('metrics.Mean', 'keras.metrics.Mean', v1=[]) class Mean(Metric): """Computes the (weighted) mean of the given values. + For example, if values is [1, 3, 5, 7] then the mean is 4. + If the weights were specified as [1, 1, 0, 0] then the mean would be 2. + This metric creates two variables, `total` and `count` that are used to compute the average of `values`. This average is ultimately returned as `mean` which is an idempotent operation that simply divides `total` by `count`. If `sample_weight` is `None`, weights default to 1. Use `sample_weight` of 0 to mask values. + + Usage: + + ```python + m = tf.metrics.Mean() + m.update_state([1, 3, 5, 7]) + print('Final result: ', m.result().numpy()) # Final result: 4.0 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.add_metric(metrics_module.Mean(name='mean_1')(outputs)) + model.compile('sgd', loss='mse') + ``` """ def __init__(self, name='mean', dtype=None): @@ -721,9 +728,56 @@ class MeanMetricWrapper(Mean): return dict(list(base_config.items()) + list(config.items())) +@tf_export('metrics.Accuracy', 'keras.metrics.Accuracy', v1=[]) +class Accuracy(MeanMetricWrapper): + """Calculates how often predictions matches labels. + + For example, if `y_true` is [1, 2, 3, 4] and `y_pred` is [0, 2, 3, 4] + then the accuracy is 3/4 or .75. If the weights were specified as + [1, 1, 0, 0] then the accuracy would be 1/2 or .5. + + This metric creates two local variables, `total` and `count` that are used to + compute the frequency with which `y_pred` matches `y_true`. This frequency is + ultimately returned as `binary accuracy`: an idempotent operation that simply + divides `total` by `count`. + + If `sample_weight` is `None`, weights default to 1. + Use `sample_weight` of 0 to mask values. + + Usage: + + ```python + m = tf.metrics.Accuracy() + m.update_state([1, 2, 3, 4], [0, 2, 3, 4]) + print('Final result: ', m.result().numpy()) # Final result: 0.75 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss='mse', metrics=[tf.metrics.Accuracy()]) + ``` + """ + + def __init__(self, name='accuracy', dtype=None): + super(Accuracy, self).__init__(accuracy, name, dtype=dtype) + + @classmethod + def from_config(cls, config): + if 'fn' in config: + config.pop('fn') + return super(Accuracy, cls).from_config(config) + + +@tf_export('metrics.BinaryAccuracy', 'keras.metrics.BinaryAccuracy', v1=[]) class BinaryAccuracy(MeanMetricWrapper): """Calculates how often predictions matches labels. + For example, if `y_true` is [1, 1, 0, 0] and `y_pred` is [0.98, 1, 0, 0.6] + then the binary accuracy is 3/4 or .75. If the weights were specified as + [1, 0, 0, 1] then the binary accuracy would be 1/2 or .5. + This metric creates two local variables, `total` and `count` that are used to compute the frequency with which `y_pred` matches `y_true`. This frequency is ultimately returned as `binary accuracy`: an idempotent operation that simply @@ -731,6 +785,21 @@ class BinaryAccuracy(MeanMetricWrapper): If `sample_weight` is `None`, weights default to 1. Use `sample_weight` of 0 to mask values. + + Usage: + + ```python + m = tf.metrics.BinaryAccuracy() + m.update_state([1, 1, 0, 0], [0.98, 1, 0, 0.6]) + print('Final result: ', m.result().numpy()) # Final result: 0.75 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss='mse', metrics=[tf.metrics.BinaryAccuracy()]) + ``` """ def __init__(self, name='binary_accuracy', dtype=None, threshold=0.5): @@ -752,9 +821,16 @@ class BinaryAccuracy(MeanMetricWrapper): return super(BinaryAccuracy, cls).from_config(config) +@tf_export( + 'metrics.CategoricalAccuracy', 'keras.metrics.CategoricalAccuracy', v1=[]) class CategoricalAccuracy(MeanMetricWrapper): """Calculates how often predictions matches labels. + For example, if `y_true` is [[0, 0, 1], [0, 1, 0]] and `y_pred` is + [[0.1, 0.9, 0.8], [0.05, 0.95, 0]] then the categorical accuracy is 1/2 or .5. + If the weights were specified as [0.7, 0.3] then the categorical accuracy + would be .3. + This metric creates two local variables, `total` and `count` that are used to compute the frequency with which `y_pred` matches `y_true`. This frequency is ultimately returned as `categorical accuracy`: an idempotent operation that @@ -765,6 +841,21 @@ class CategoricalAccuracy(MeanMetricWrapper): If `sample_weight` is `None`, weights default to 1. Use `sample_weight` of 0 to mask values. + + Usage: + + ```python + m = tf.metrics.CategoricalAccuracy() + m.update_state([[0, 0, 1], [0, 1, 0]], [[0.1, 0.9, 0.8], [0.05, 0.95, 0]]) + print('Final result: ', m.result().numpy()) # Final result: 0.5 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss='mse', metrics=[tf.metrics.CategoricalAccuracy()]) + ``` """ def __init__(self, name='categorical_accuracy', dtype=None): @@ -784,9 +875,18 @@ class CategoricalAccuracy(MeanMetricWrapper): return super(CategoricalAccuracy, cls).from_config(config) +@tf_export( + 'metrics.SparseCategoricalAccuracy', + 'keras.metrics.SparseCategoricalAccuracy', + v1=[]) class SparseCategoricalAccuracy(MeanMetricWrapper): """Calculates how often predictions matches integer labels. + For example, if `y_true` is [[2], [1]] and `y_pred` is + [[0.1, 0.9, 0.8], [0.05, 0.95, 0]] then the categorical accuracy is 1/2 or .5. + If the weights were specified as [0.7, 0.3] then the categorical accuracy + would be .3. + This metric creates two local variables, `total` and `count` that are used to compute the frequency with which `y_pred` matches `y_true`. This frequency is ultimately returned as `sparse categorical accuracy`: an idempotent operation @@ -794,6 +894,24 @@ class SparseCategoricalAccuracy(MeanMetricWrapper): If `sample_weight` is `None`, weights default to 1. Use `sample_weight` of 0 to mask values. + + Usage: + + ```python + m = tf.metrics.SparseCategoricalAccuracy() + m.update_state([[2], [1]], [[0.1, 0.9, 0.8], [0.05, 0.95, 0]]) + print('Final result: ', m.result().numpy()) # Final result: 0.5 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile( + 'sgd', + loss='mse', + metrics=[tf.metrics.SparseCategoricalAccuracy()]) + ``` """ def __init__(self, name='sparse_categorical_accuracy', dtype=None): @@ -1097,6 +1215,13 @@ class Recall(Metric): array_ops.zeros_like(self.thresholds)) +def accuracy(y_true, y_pred): + y_pred.get_shape().assert_is_compatible_with(y_true.get_shape()) + if y_true.dtype != y_pred.dtype: + y_pred = math_ops.cast(y_pred, y_true.dtype) + return math_ops.cast(math_ops.equal(y_true, y_pred), K.floatx()) + + @tf_export('keras.metrics.binary_accuracy') def binary_accuracy(y_true, y_pred, threshold=0.5): threshold = math_ops.cast(threshold, y_pred.dtype) diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index 535802a64a..eeade4f37d 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -49,7 +49,7 @@ class KerasMetricsTest(test.TestCase): output = metric(y_a, y_b) self.assertEqual(K.eval(output).shape, (6,)) - def test_sparse_categorical_accuracy(self): + def test_sparse_categorical_accuracy_int(self): with self.cached_session(): metric = metrics.sparse_categorical_accuracy y_true = K.variable(np.random.randint(0, 7, (6,))) @@ -367,6 +367,28 @@ class KerasMetricsTest(test.TestCase): self.assertEqual(200., self.evaluate(restore_mean.result())) self.assertEqual(3, self.evaluate(restore_mean.count)) + @test_util.run_in_graph_and_eager_modes + def test_accuracy(self): + acc_obj = metrics.Accuracy(name='my acc') + + # check config + self.assertEqual(acc_obj.name, 'my acc') + self.assertTrue(acc_obj.stateful) + self.assertEqual(len(acc_obj.variables), 2) + self.assertEqual(acc_obj.dtype, dtypes.float32) + self.evaluate(variables.variables_initializer(acc_obj.variables)) + + # verify that correct value is returned + update_op = acc_obj.update_state([[1], [2], [3], [4]], [[1], [2], [3], [4]]) + self.evaluate(update_op) + result = self.evaluate(acc_obj.result()) + self.assertEqual(result, 1) # 2/2 + + # check with sample_weight + result_t = acc_obj([[2], [1]], [[2], [0]], sample_weight=[[0.5], [0.2]]) + result = self.evaluate(result_t) + self.assertAlmostEqual(result, 0.96, 2) # 4.5/4.7 + @test_util.run_in_graph_and_eager_modes def test_binary_accuracy(self): acc_obj = metrics.BinaryAccuracy(name='my acc') @@ -437,6 +459,30 @@ class KerasMetricsTest(test.TestCase): result = self.evaluate(result_t) self.assertAlmostEqual(result, 0.93, 2) # 2.5/2.7 + @test_util.run_in_graph_and_eager_modes + def test_sparse_categorical_accuracy(self): + acc_obj = metrics.SparseCategoricalAccuracy(name='my acc') + + # check config + self.assertEqual(acc_obj.name, 'my acc') + self.assertTrue(acc_obj.stateful) + self.assertEqual(len(acc_obj.variables), 2) + self.assertEqual(acc_obj.dtype, dtypes.float32) + self.evaluate(variables.variables_initializer(acc_obj.variables)) + + # verify that correct value is returned + update_op = acc_obj.update_state([[2], [1]], + [[0.1, 0.1, 0.8], [0.05, 0.95, 0]]) + self.evaluate(update_op) + result = self.evaluate(acc_obj.result()) + self.assertEqual(result, 1) # 2/2 + + # check with sample_weight + result_t = acc_obj([[2], [1]], [[0.1, 0.1, 0.8], [0.05, 0, 0.95]], + [[0.5], [0.2]]) + result = self.evaluate(result_t) + self.assertAlmostEqual(result, 0.93, 2) # 2.5/2.7 + @test_util.run_in_graph_and_eager_modes def test_invalid_result(self): diff --git a/tensorflow/python/ops/metrics_impl.py b/tensorflow/python/ops/metrics_impl.py index 03de8d552a..0b91b8dde8 100644 --- a/tensorflow/python/ops/metrics_impl.py +++ b/tensorflow/python/ops/metrics_impl.py @@ -312,7 +312,7 @@ def _aggregate_across_replicas(metrics_collections, metric_value_fn, *args): fn, args=args) -@tf_export('metrics.mean') +@tf_export(v1=['metrics.mean']) def mean(values, weights=None, metrics_collections=None, @@ -393,7 +393,7 @@ def mean(values, return mean_t, update_op -@tf_export('metrics.accuracy') +@tf_export(v1=['metrics.accuracy']) def accuracy(labels, predictions, weights=None, diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-accuracy.pbtxt new file mode 100644 index 0000000000..2db07df523 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.keras.metrics.Accuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'accuracy\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-binary-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-binary-accuracy.pbtxt new file mode 100644 index 0000000000..904ad3a21a --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-binary-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.keras.metrics.BinaryAccuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\', \'threshold\'], varargs=None, keywords=None, defaults=[\'binary_accuracy\', \'None\', \'0.5\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-categorical-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-categorical-accuracy.pbtxt new file mode 100644 index 0000000000..17b74924fa --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-categorical-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.keras.metrics.CategoricalAccuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'categorical_accuracy\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-mean.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-mean.pbtxt new file mode 100644 index 0000000000..40fe64bbd2 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-mean.pbtxt @@ -0,0 +1,192 @@ +path: "tensorflow.keras.metrics.Mean" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'mean\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'values\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-sparse-categorical-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-sparse-categorical-accuracy.pbtxt new file mode 100644 index 0000000000..0c17452292 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-sparse-categorical-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.keras.metrics.SparseCategoricalAccuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'sparse_categorical_accuracy\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt index a296e13158..8a8fb97b96 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt @@ -1,5 +1,25 @@ path: "tensorflow.keras.metrics" tf_module { + member { + name: "Accuracy" + mtype: "" + } + member { + name: "BinaryAccuracy" + mtype: "" + } + member { + name: "CategoricalAccuracy" + mtype: "" + } + member { + name: "Mean" + mtype: "" + } + member { + name: "SparseCategoricalAccuracy" + mtype: "" + } member_method { name: "KLD" argspec: "args=[\'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-accuracy.pbtxt new file mode 100644 index 0000000000..f8e12f8817 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.metrics.Accuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'accuracy\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.-binary-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-binary-accuracy.pbtxt new file mode 100644 index 0000000000..b9bc6a716a --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-binary-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.metrics.BinaryAccuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\', \'threshold\'], varargs=None, keywords=None, defaults=[\'binary_accuracy\', \'None\', \'0.5\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.-categorical-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-categorical-accuracy.pbtxt new file mode 100644 index 0000000000..0ef75d8756 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-categorical-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.metrics.CategoricalAccuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'categorical_accuracy\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.-mean.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-mean.pbtxt new file mode 100644 index 0000000000..7fe6d6fda9 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-mean.pbtxt @@ -0,0 +1,192 @@ +path: "tensorflow.metrics.Mean" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'mean\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'values\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.-sparse-categorical-accuracy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-sparse-categorical-accuracy.pbtxt new file mode 100644 index 0000000000..7bce43fbde --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-sparse-categorical-accuracy.pbtxt @@ -0,0 +1,194 @@ +path: "tensorflow.metrics.SparseCategoricalAccuracy" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'sparse_categorical_accuracy\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt index e9b996c9f5..d82ce8b38a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt @@ -1,8 +1,24 @@ path: "tensorflow.metrics" tf_module { - member_method { - name: "accuracy" - argspec: "args=[\'labels\', \'predictions\', \'weights\', \'metrics_collections\', \'updates_collections\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " + member { + name: "Accuracy" + mtype: "" + } + member { + name: "BinaryAccuracy" + mtype: "" + } + member { + name: "CategoricalAccuracy" + mtype: "" + } + member { + name: "Mean" + mtype: "" + } + member { + name: "SparseCategoricalAccuracy" + mtype: "" } member_method { name: "auc" @@ -28,10 +44,6 @@ tf_module { name: "false_positives_at_thresholds" argspec: "args=[\'labels\', \'predictions\', \'thresholds\', \'weights\', \'metrics_collections\', \'updates_collections\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } - member_method { - name: "mean" - argspec: "args=[\'values\', \'weights\', \'metrics_collections\', \'updates_collections\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " - } member_method { name: "mean_absolute_error" argspec: "args=[\'labels\', \'predictions\', \'weights\', \'metrics_collections\', \'updates_collections\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " -- GitLab From 186da29b491d43b3c02c692e1a64222ca57b0be4 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Wed, 21 Nov 2018 00:25:50 -0800 Subject: [PATCH 183/672] Disable conv_ops_test in msan PiperOrigin-RevId: 222364783 --- tensorflow/core/kernels/BUILD | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index ae76034b0b..4fe0d2e87e 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -1257,6 +1257,9 @@ tf_cc_test( name = "conv_ops_test", size = "medium", srcs = ["conv_ops_test.cc"], + tags = [ + "nomsan", + ], deps = [ ":conv_ops", ":image", -- GitLab From 777039302d52565ef838082cde12bdfa6a1e38e1 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Wed, 21 Nov 2018 00:27:16 -0800 Subject: [PATCH 184/672] Disable flaky stats_dataset_ops_test in tsan. PiperOrigin-RevId: 222364901 --- tensorflow/python/data/experimental/kernel_tests/BUILD | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/data/experimental/kernel_tests/BUILD b/tensorflow/python/data/experimental/kernel_tests/BUILD index c9b11a2c38..6a387f55bd 100644 --- a/tensorflow/python/data/experimental/kernel_tests/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/BUILD @@ -618,7 +618,10 @@ py_test( size = "medium", srcs = ["stats_dataset_ops_test.py"], srcs_version = "PY2AND3", - tags = ["no_pip"], + tags = [ + "no_pip", + "notsan", + ], deps = [ ":reader_dataset_ops_test_base", ":stats_dataset_test_base", -- GitLab From 2d580e7d04d5fa96cf2553ed041b6234ffe4f62d Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Wed, 21 Nov 2018 00:29:00 -0800 Subject: [PATCH 185/672] Bump the size of c_api_exoerimental_test. It occasionally times out when run with thread sanitizer. PiperOrigin-RevId: 222364999 --- tensorflow/c/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/c/BUILD b/tensorflow/c/BUILD index 71089a87c7..f653e581bf 100644 --- a/tensorflow/c/BUILD +++ b/tensorflow/c/BUILD @@ -264,7 +264,7 @@ tf_cuda_cc_test( tf_cc_test( name = "c_api_experimental_test", - size = "small", + size = "medium", srcs = ["c_api_experimental_test.cc"], data = ["testdata/tf_record"], linkopts = select({ -- GitLab From f1b77734a76fe8ad6c1af21e7e748af93da88913 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 01:02:16 -0800 Subject: [PATCH 186/672] compat: Update forward compatibility horizon to 2018-11-21 PiperOrigin-RevId: 222368181 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 1b8114dd26..75290f0613 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 20) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 21) @tf_export("compat.forward_compatible") -- GitLab From 7586bb3cfba2bbfffe8d74522a9a5a00c137f6e3 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Wed, 21 Nov 2018 02:19:56 -0800 Subject: [PATCH 187/672] Simplify TopK xla client op. Instead of creating a rank 1 iota and broadcasting it, we can directly create the iota we need. PiperOrigin-RevId: 222377479 --- tensorflow/compiler/xla/client/lib/BUILD | 2 ++ tensorflow/compiler/xla/client/lib/sorting.cc | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tensorflow/compiler/xla/client/lib/BUILD b/tensorflow/compiler/xla/client/lib/BUILD index f833ddcd32..bbfe8712c5 100644 --- a/tensorflow/compiler/xla/client/lib/BUILD +++ b/tensorflow/compiler/xla/client/lib/BUILD @@ -179,7 +179,9 @@ cc_library( hdrs = ["sorting.h"], deps = [ ":numeric", + "//tensorflow/compiler/xla:shape_util", "//tensorflow/compiler/xla:types", + "//tensorflow/compiler/xla:util", "//tensorflow/compiler/xla:xla_data_proto", "//tensorflow/compiler/xla/client:xla_builder", ], diff --git a/tensorflow/compiler/xla/client/lib/sorting.cc b/tensorflow/compiler/xla/client/lib/sorting.cc index 0475fd9c94..d3980d5575 100644 --- a/tensorflow/compiler/xla/client/lib/sorting.cc +++ b/tensorflow/compiler/xla/client/lib/sorting.cc @@ -15,6 +15,8 @@ limitations under the License. #include "tensorflow/compiler/xla/client/lib/sorting.h" #include "tensorflow/compiler/xla/client/lib/numeric.h" +#include "tensorflow/compiler/xla/shape_util.h" +#include "tensorflow/compiler/xla/util.h" namespace xla { @@ -23,13 +25,12 @@ XlaOp TopK(XlaOp input, int64 k) { return builder->ReportErrorOrReturn([&]() -> StatusOr { TF_ASSIGN_OR_RETURN(Shape input_shape, builder->GetShape(input)); int last_dim = input_shape.dimensions_size() - 1; - int last_dim_size = input_shape.dimensions(last_dim); - XlaOp iota_s32 = Iota(builder, S32, last_dim_size); + Shape iota_shape = + ShapeUtil::MakeShape(S32, AsInt64Slice(input_shape.dimensions())); + XlaOp iota_s32 = Iota(builder, iota_shape, last_dim); auto input_dims = input_shape.dimensions(); - std::vector broadcast_dims(input_dims.begin(), input_dims.end() - 1); - XlaOp broadcast_s32 = Broadcast(iota_s32, broadcast_dims); - XlaOp sort_result = Sort(Neg(input), {broadcast_s32}); + XlaOp sort_result = Sort(Neg(input), {iota_s32}); std::vector start_indices(input_shape.dimensions_size(), 0); std::vector limit_indices(input_dims.begin(), input_dims.end()); limit_indices[last_dim] = k; -- GitLab From 887e6042951aadaa247cc801ae5713a87dc7666f Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Wed, 21 Nov 2018 04:47:21 -0800 Subject: [PATCH 188/672] Make TopK stable on the GPU backend. TopK op needs the guarantee that the sorting is stable. In that case, a 'values' parameter is passed which is a iota. We can use that to disambiguate comparison ties to sort by original index, which makes the sorting stable. Note that this still doesn't guarantee that the sort op is stable for all inputs, just that it is stable when used by TopK. PiperOrigin-RevId: 222390450 --- tensorflow/compiler/xla/client/lib/BUILD | 3 +- .../compiler/xla/client/lib/sorting_test.cc | 8 ++ .../xla/service/gpu/ir_emitter_unnested.cc | 18 +++- .../compiler/xla/service/llvm_ir/sort_util.cc | 85 +++++++++++-------- .../compiler/xla/service/llvm_ir/sort_util.h | 5 +- 5 files changed, 77 insertions(+), 42 deletions(-) diff --git a/tensorflow/compiler/xla/client/lib/BUILD b/tensorflow/compiler/xla/client/lib/BUILD index bbfe8712c5..45a7b020b3 100644 --- a/tensorflow/compiler/xla/client/lib/BUILD +++ b/tensorflow/compiler/xla/client/lib/BUILD @@ -191,8 +191,7 @@ xla_test( name = "sorting_test", srcs = ["sorting_test.cc"], blacklisted_backends = [ - "cpu", - "gpu", + "cpu", # Fails with --config=asan. ], tags = ["enable_for_xla_interpreter"], deps = [ diff --git a/tensorflow/compiler/xla/client/lib/sorting_test.cc b/tensorflow/compiler/xla/client/lib/sorting_test.cc index fef98c9923..ebb30d3acc 100644 --- a/tensorflow/compiler/xla/client/lib/sorting_test.cc +++ b/tensorflow/compiler/xla/client/lib/sorting_test.cc @@ -56,5 +56,13 @@ XLA_TEST_F(SortingTest, TopKFullSort) { ComputeAndCompareR1(&builder, inputs, {}); } +XLA_TEST_F(SortingTest, TopKFullSortWithDuplicates) { + XlaBuilder builder(TestName()); + XlaOp a; + auto a_data = CreateR1Parameter({1, 1, 2, 2, 1}, 0, "a", &builder, &a); + xla::GetTupleElement(xla::TopK(a, 5), 1); + ComputeAndCompareR1(&builder, {2, 3, 0, 1, 4}, {a_data.get()}); +} + } // namespace } // namespace xla diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc index efe335c1c1..ebd73f3a91 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc @@ -65,6 +65,7 @@ limitations under the License. #include "tensorflow/compiler/xla/service/hlo_casting_utils.h" #include "tensorflow/compiler/xla/service/hlo_computation.h" #include "tensorflow/compiler/xla/service/hlo_instruction.h" +#include "tensorflow/compiler/xla/service/hlo_instructions.h" #include "tensorflow/compiler/xla/service/hlo_opcode.h" #include "tensorflow/compiler/xla/service/llvm_ir/buffer_assignment_util.h" #include "tensorflow/compiler/xla/service/llvm_ir/dynamic_update_slice_util.h" @@ -2172,7 +2173,18 @@ Status IrEmitterUnnested::HandleSelect(HloInstruction* select) { Status IrEmitterUnnested::HandleSort(HloInstruction* sort) { std::vector> thunks; Shape keys_shape = sort->operand(0)->shape(); + int64 dimension_to_sort = sort->dimensions(0); + // In case there is a 'values' parameter that is a iota, we take note and use + // it later to ensure a stable sort. Otherwise, we don't guarantee a stable + // sort. + int64 iota_values_parameter_index = -1; for (int64 i = 0; i < sort->operand_count(); ++i) { + if (i > 0 && sort->operand(i)->opcode() == HloOpcode::kIota && + ShapeUtil::ElementIsIntegral(sort->operand(i)->shape()) && + Cast(sort->operand(i))->iota_dimension() == + dimension_to_sort) { + iota_values_parameter_index = i; + } ShapeIndex shape_index = sort->operand_count() > 1 ? ShapeIndex({i}) : ShapeIndex({}); // We assume that the layout of all involved operands and outputs is the @@ -2197,7 +2209,6 @@ Status IrEmitterUnnested::HandleSort(HloInstruction* sort) { } } - int64 dimension_to_sort = sort->dimensions(0); uint64 dimension_to_sort_bound = keys_shape.dimensions(dimension_to_sort); int64 num_stages = tensorflow::Log2Ceiling(dimension_to_sort_bound); CHECK_GE(1ULL << num_stages, dimension_to_sort_bound); @@ -2299,8 +2310,9 @@ Status IrEmitterUnnested::HandleSort(HloInstruction* sort) { } } return llvm_ir::EmitSortInPlace( - dimension_to_sort, keys_array, values_arrays, IrName(sort), xor_masks, - &b_, launch_dimensions, + dimension_to_sort, keys_array, values_arrays, + iota_values_parameter_index, IrName(sort), xor_masks, &b_, + launch_dimensions, xor_masks.size() > 1 ? num_iterations_in_sort_dim : standard_num_iterations_in_sort_dim, kTileSize); diff --git a/tensorflow/compiler/xla/service/llvm_ir/sort_util.cc b/tensorflow/compiler/xla/service/llvm_ir/sort_util.cc index fd16af67fe..e22c2173c2 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/sort_util.cc +++ b/tensorflow/compiler/xla/service/llvm_ir/sort_util.cc @@ -47,7 +47,8 @@ namespace { // Adds the inner comparison loop body where we compare elements. void EmitCompareLoopBody( int64 iteration_bound, PrimitiveType key_type, int64 num_values, - llvm::Value* element_pair_index, int64 xor_mask, llvm::Type* index_type, + int64 iota_values_parameter_index, llvm::Value* element_pair_index, + int64 xor_mask, llvm::Type* index_type, std::function read_element, std::function write_element, @@ -139,34 +140,42 @@ void EmitCompareLoopBody( is_signed_comparison = false; } // If key2 < key1 - ksl.IfReturnVoid( - "is_smaller_than", + auto is_smaller_than = b->CreateICmp(is_signed_comparison ? llvm::ICmpInst::ICMP_SLT : llvm::ICmpInst::ICMP_ULT, - compare_key2, compare_key1), - [&]() { - // Swap key1 with key2. - write_element(0, current_keys_index, key2); - write_element(0, compare_keys_index, key1); - for (int64 i = 1; i <= num_values; ++i) { - // Also swap the values. - auto value1 = read_element(i, current_keys_index); - auto value2 = read_element(i, compare_keys_index); - write_element(i, current_keys_index, value2); - write_element(i, compare_keys_index, value1); - } - }); + compare_key2, compare_key1); + if (iota_values_parameter_index >= 0) { + auto keys_equal = b->CreateICmpEQ(compare_key1, compare_key2); + auto key_index1 = + read_element(iota_values_parameter_index, current_keys_index); + auto key_index2 = + read_element(iota_values_parameter_index, compare_keys_index); + auto index_is_smaller_than = + b->CreateICmp(llvm::ICmpInst::ICMP_ULT, key_index2, key_index1); + is_smaller_than = b->CreateOr( + is_smaller_than, b->CreateAnd(keys_equal, index_is_smaller_than)); + } + ksl.IfReturnVoid("is_smaller_than", is_smaller_than, [&]() { + // Swap key1 with key2. + write_element(0, current_keys_index, key2); + write_element(0, compare_keys_index, key1); + for (int64 i = 1; i <= num_values; ++i) { + // Also swap the values. + auto value1 = read_element(i, current_keys_index); + auto value2 = read_element(i, compare_keys_index); + write_element(i, current_keys_index, value2); + write_element(i, compare_keys_index, value1); + } + }); }); } -void EmitTiledCompareLoop(const IrArray::Index& tiled_keys_index, - int64 dimension_to_sort, - int64 dimension_to_sort_bound, - PrimitiveType keys_type, - absl::Span xor_masks, - const std::vector& params, - const std::vector& param_shmem_buffers, - int64 tile_size, llvm::IRBuilder<>* b) { +void EmitTiledCompareLoop( + const IrArray::Index& tiled_keys_index, int64 dimension_to_sort, + int64 dimension_to_sort_bound, PrimitiveType keys_type, + absl::Span xor_masks, const std::vector& params, + const std::vector& param_shmem_buffers, + int64 iota_values_parameter_index, int64 tile_size, llvm::IRBuilder<>* b) { KernelSupportLibrary ksl(b); llvm::Value* thread_id = llvm_ir::EmitCallToIntrinsic( llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x, {}, {}, b); @@ -253,20 +262,22 @@ void EmitTiledCompareLoop(const IrArray::Index& tiled_keys_index, RoundDownToNearest(dimension_to_sort_bound, tile_size))), [&]() { EmitCompareLoopBody(dimension_to_sort_bound % tile_size, keys_type, - params.size() - 1, element_pair_index, xor_mask, + params.size() - 1, iota_values_parameter_index, + element_pair_index, xor_mask, tiled_keys_index.GetType(), read_element, write_element, b); }, [&]() { - EmitCompareLoopBody( - tile_size, keys_type, params.size() - 1, element_pair_index, - xor_mask, tiled_keys_index.GetType(), read_element, - write_element, b, /*needs_bounds_checks=*/false); + EmitCompareLoopBody(tile_size, keys_type, params.size() - 1, + iota_values_parameter_index, element_pair_index, + xor_mask, tiled_keys_index.GetType(), + read_element, write_element, b, + /*needs_bounds_checks=*/false); }); } else { EmitCompareLoopBody(tile_size, keys_type, params.size() - 1, - element_pair_index, xor_mask, - tiled_keys_index.GetType(), read_element, + iota_values_parameter_index, element_pair_index, + xor_mask, tiled_keys_index.GetType(), read_element, write_element, b, /*needs_bounds_checks=*/false); } // Wait until all comparisons have happened. @@ -296,6 +307,7 @@ void EmitTiledCompareLoop(const IrArray::Index& tiled_keys_index, Status EmitSortInPlace(int64 dimension_to_sort, const IrArray& keys_array, const std::vector& values_arrays, + int64 iota_values_parameter_index, absl::string_view name, absl::Span xor_masks, llvm::IRBuilder<>* b, const gpu::LaunchDimensions& launch_dimensions, @@ -367,8 +379,8 @@ Status EmitSortInPlace(int64 dimension_to_sort, const IrArray& keys_array, if (xor_masks.size() > 1) { EmitTiledCompareLoop(keys_index, dimension_to_sort, dimension_to_sort_bound, keys_shape.element_type(), - xor_masks, params, param_shmem_buffers, tile_size, - b); + xor_masks, params, param_shmem_buffers, + iota_values_parameter_index, tile_size, b); } else { auto read_element = [&](int64 operand, llvm::Value* index) { keys_index[dimension_to_sort] = index; @@ -380,9 +392,10 @@ Status EmitSortInPlace(int64 dimension_to_sort, const IrArray& keys_array, params[operand].EmitWriteArrayElement(keys_index, value, b); }; EmitCompareLoopBody(dimension_to_sort_bound, keys_shape.element_type(), - values_arrays.size(), tiles_index[rank - 1], - xor_masks[0], tiles_index.GetType(), read_element, - write_element, b); + values_arrays.size(), iota_values_parameter_index, + tiles_index[rank - 1], xor_masks[0], + tiles_index.GetType(), read_element, write_element, + b); } return Status::OK(); }; diff --git a/tensorflow/compiler/xla/service/llvm_ir/sort_util.h b/tensorflow/compiler/xla/service/llvm_ir/sort_util.h index 556a217322..685f9383ac 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/sort_util.h +++ b/tensorflow/compiler/xla/service/llvm_ir/sort_util.h @@ -31,9 +31,12 @@ namespace llvm_ir { // Emits llvm IR to do pairwise comparisons/swaps in the 'dimension_to_sort' // dimension of 'keys_array'. All other dimensions are kept as-is. This // implements the inner loop of BitonicSort. It is assumed that 'xor_masks' -// contains only powers of 2, or values 2^k - 1 (k > 0). +// contains only powers of 2, or values 2^k - 1 (k > 0). If +// 'iota_values_parameter_index' is >= 0, it points at a 'values_arrays' operand +// that is a iota and can be used to make the sorting stable. Status EmitSortInPlace(int64 dimension_to_sort, const IrArray& keys_array, const std::vector& values_arrays, + int64 iota_values_parameter_index, absl::string_view name, absl::Span xor_masks, llvm::IRBuilder<>* b, const gpu::LaunchDimensions& launch_dimensions, -- GitLab From 077fbf0a3518e6fadbf7fa671b134a420b52e759 Mon Sep 17 00:00:00 2001 From: Thomas Joerg Date: Wed, 21 Nov 2018 05:10:01 -0800 Subject: [PATCH 189/672] [XLA:GPU] Check explicitly for reduce input fusions in fusion_merger. Now that Scatter kInput fusions have been introduced, checking just the fusion kind is not enough. PiperOrigin-RevId: 222392637 --- .../compiler/xla/service/gpu/fusion_merger.cc | 2 +- .../compiler/xla/service/gpu/gpu_fusible.cc | 23 +++++++++--------- .../compiler/xla/service/gpu/gpu_fusible.h | 11 +++++---- .../xla/service/gpu/gpu_fusible_test.cc | 24 ++++++++++++------- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/fusion_merger.cc b/tensorflow/compiler/xla/service/gpu/fusion_merger.cc index 30c1f90889..470457935a 100644 --- a/tensorflow/compiler/xla/service/gpu/fusion_merger.cc +++ b/tensorflow/compiler/xla/service/gpu/fusion_merger.cc @@ -229,7 +229,7 @@ Status FusionInstructionMerger::HandleFusion(HloInstruction* fusion) { if (!absl::c_all_of(fusion->users(), [&](const HloInstruction* user) { return user->opcode() == HloOpcode::kFusion && (user->fusion_kind() == HloInstruction::FusionKind::kLoop || - (user->fusion_kind() == HloInstruction::FusionKind::kInput && + (IsReduceInputFusion(*user) && LayoutsAreReduceInputFusionFriendly(*fusion, *user))); })) { VLOG(3) << "Not merging " << fusion->name() diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc b/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc index 2d31fd5570..392b149abd 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc @@ -55,7 +55,7 @@ bool LayoutsAreReduceInputFusionFriendly(const HloInstruction& producer, }); } -bool IsInputFusibleReduction(const HloInstruction& instr) { +bool IsReduceInputFusion(const HloInstruction& instr) { if (instr.IsMultiOutputFusion()) { for (const HloInstruction* operand : instr.fused_expression_root()->operands()) { @@ -67,17 +67,18 @@ bool IsInputFusibleReduction(const HloInstruction& instr) { return true; } } - return false; - } else if (instr.opcode() == HloOpcode::kFusion) { - if (IsReductionToVector(*instr.fused_expression_root())) { - CHECK(instr.fusion_kind() == HloInstruction::FusionKind::kInput) - << " Fusion rooted at reduction-to-vector op must be of kind kInput: " - << instr.ToString(); - return true; - } - return false; + } else if (instr.opcode() == HloOpcode::kFusion && + IsReductionToVector(*instr.fused_expression_root())) { + CHECK(instr.fusion_kind() == HloInstruction::FusionKind::kInput) + << " Fusion rooted at reduction-to-vector op must be of kind kInput: " + << instr.ToString(); + return true; } - return IsReductionToVector(instr); + return false; +} + +bool IsInputFusibleReduction(const HloInstruction& instr) { + return IsReduceInputFusion(instr) || IsReductionToVector(instr); } } // namespace gpu diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible.h b/tensorflow/compiler/xla/service/gpu/gpu_fusible.h index f7c24a0d5b..c0be354730 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible.h +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible.h @@ -33,14 +33,17 @@ namespace gpu { bool LayoutsAreReduceInputFusionFriendly(const HloInstruction& producer, const HloInstruction& reduce); -// Whether `instr` is fusible as root of a reduce input fusions, i.e. `instr` -// is either an unfused reduction-to-vector op, an input fusion rooted at a -// reduction-to-vector op, or a multi-output input fusion with at least one -// reduction-to-vector op root. // Note that reduction ops are lowered in different ways. Reduce input fusions // are lowered by IrEmitterUnnested::EmitReductionToVector and must be rooted at // reduction-to-vector ops. Other reduction ops are lowered by // GpuElementalIrEmitter and fused like elementwise ops. + +// Whether `instr` is an input fusion rooted at a reduction-to-vector op or a +// multi-output input fusion with at least one reduction-to-vector op root. +bool IsReduceInputFusion(const HloInstruction& instr); + +// Whether `instr` is fusible as root of a reduce input fusions, i.e. `instr` +// is either an unfused reduction-to-vector op or a reduce input fusion. bool IsInputFusibleReduction(const HloInstruction& instr); } // namespace gpu diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc b/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc index d91b7bc61f..12222500ea 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc @@ -178,7 +178,7 @@ TEST_F(GpuFusibleTest, EXPECT_TRUE(LayoutsAreReduceInputFusionFriendly(*loop_fusion, *reduce)); } -TEST_F(GpuFusibleTest, IsInputFusibleReduction_ReductionToVector) { +TEST_F(GpuFusibleTest, IsReduceInputFusion_ReductionToVector) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( ENTRY entry { c0 = f32[] parameter(0) @@ -191,10 +191,11 @@ TEST_F(GpuFusibleTest, IsInputFusibleReduction_ReductionToVector) { const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kReduce); + EXPECT_FALSE(IsReduceInputFusion(*reduce)); EXPECT_TRUE(IsInputFusibleReduction(*reduce)); } -TEST_F(GpuFusibleTest, IsInputFusibleReduction_ElementalReduction) { +TEST_F(GpuFusibleTest, IsReduceInputFusion_ElementalReduction) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( ENTRY entry { c0 = f32[] parameter(0) @@ -207,10 +208,11 @@ TEST_F(GpuFusibleTest, IsInputFusibleReduction_ElementalReduction) { const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kReduce); + EXPECT_FALSE(IsReduceInputFusion(*reduce)); EXPECT_FALSE(IsInputFusibleReduction(*reduce)); } -TEST_F(GpuFusibleTest, IsInputFusibleReduction_SingleOutputInputReduceFusion) { +TEST_F(GpuFusibleTest, IsReduceInputFusion_SingleOutputInputReduceFusion) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( fused_reduction { c0 = f32[] parameter(0) @@ -225,10 +227,11 @@ TEST_F(GpuFusibleTest, IsInputFusibleReduction_SingleOutputInputReduceFusion) { const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kFusion); + EXPECT_TRUE(IsReduceInputFusion(*reduce)); EXPECT_TRUE(IsInputFusibleReduction(*reduce)); } -TEST_F(GpuFusibleTest, IsInputFusibleReduction_SingleOutputLoopReduceFusion) { +TEST_F(GpuFusibleTest, IsReduceInputFusion_SingleOutputLoopReduceFusion) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( fused_reduction { c0 = f32[] parameter(0) @@ -243,10 +246,11 @@ TEST_F(GpuFusibleTest, IsInputFusibleReduction_SingleOutputLoopReduceFusion) { const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kFusion); + EXPECT_FALSE(IsReduceInputFusion(*reduce)); EXPECT_FALSE(IsInputFusibleReduction(*reduce)); } -TEST_F(GpuFusibleTest, IsInputFusibleReduction_MultiOutputInputReduceFusion) { +TEST_F(GpuFusibleTest, IsReduceInputFusion_MultiOutputInputReduceFusion) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( fused_reduction { c0 = f32[] parameter(0) @@ -263,11 +267,12 @@ TEST_F(GpuFusibleTest, IsInputFusibleReduction_MultiOutputInputReduceFusion) { const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kFusion); + EXPECT_TRUE(IsReduceInputFusion(*reduce)); EXPECT_TRUE(IsInputFusibleReduction(*reduce)); } TEST_F(GpuFusibleTest, - IsInputFusibleReduction_MultiOutputInputReduceFusionWithExtraOutputs) { + IsReduceInputFusion_MultiOutputInputReduceFusionWithExtraOutputs) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( fused_reduction { c0 = f32[] parameter(0) @@ -284,10 +289,11 @@ TEST_F(GpuFusibleTest, const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kFusion); + EXPECT_TRUE(IsReduceInputFusion(*reduce)); EXPECT_TRUE(IsInputFusibleReduction(*reduce)); } -TEST_F(GpuFusibleTest, IsInputFusibleReduction_MultiOutputLoopReduceFusion) { +TEST_F(GpuFusibleTest, IsReduceInputFusion_MultiOutputLoopReduceFusion) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( fused_reduction { c0 = f32[] parameter(0) @@ -304,11 +310,12 @@ TEST_F(GpuFusibleTest, IsInputFusibleReduction_MultiOutputLoopReduceFusion) { const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kFusion); + EXPECT_FALSE(IsReduceInputFusion(*reduce)); EXPECT_FALSE(IsInputFusibleReduction(*reduce)); } TEST_F(GpuFusibleTest, - IsInputFusibleReduction_MultiOutputLoopFusionReduceAndElementwiseOp) { + IsReduceInputFusion_MultiOutputLoopFusionReduceAndElementwiseOp) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( fused_reduction { c0 = f32[] parameter(0) @@ -325,6 +332,7 @@ TEST_F(GpuFusibleTest, const HloInstruction* reduce = module->entry_computation()->root_instruction(); ASSERT_EQ(reduce->opcode(), HloOpcode::kFusion); + EXPECT_FALSE(IsReduceInputFusion(*reduce)); EXPECT_FALSE(IsInputFusibleReduction(*reduce)); } -- GitLab From 434dbe38970ffc90a5b546780be702e0b5de9a0c Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Wed, 21 Nov 2018 05:19:07 -0800 Subject: [PATCH 190/672] Fix undefined behavior caused by integer overflow in custom float comparison. PiperOrigin-RevId: 222393257 --- tensorflow/compiler/xla/client/lib/BUILD | 3 --- .../xla/service/cpu/runtime_key_value_sort.cc | 16 +++++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tensorflow/compiler/xla/client/lib/BUILD b/tensorflow/compiler/xla/client/lib/BUILD index 45a7b020b3..f8dce0db9f 100644 --- a/tensorflow/compiler/xla/client/lib/BUILD +++ b/tensorflow/compiler/xla/client/lib/BUILD @@ -190,9 +190,6 @@ cc_library( xla_test( name = "sorting_test", srcs = ["sorting_test.cc"], - blacklisted_backends = [ - "cpu", # Fails with --config=asan. - ], tags = ["enable_for_xla_interpreter"], deps = [ ":sorting", diff --git a/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc b/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc index c7fc101ec7..722aa3120e 100644 --- a/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc +++ b/tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.cc @@ -51,19 +51,21 @@ void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { // then y is ordered as an int32 such that finite values have the // obvious order, -0 is ordered before 0, and -NaN and NaN appear at // the beginning and end of the ordering. -template +template CastType Convert(KeyType value) { CastType casted_value; memcpy(&casted_value, &value, sizeof(CastType)); if (casted_value < 0) { - return std::numeric_limits::max() - casted_value; + return static_cast(std::numeric_limits::max()) - + casted_value; } return casted_value; } -template +template bool LessThan(KeyType lhs, KeyType rhs) { - return Convert(lhs) < Convert(rhs); + return Convert(lhs) < + Convert(rhs); } template <> @@ -71,7 +73,7 @@ void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { std::stable_sort(row_to_sort, row_to_sort + num_elements, [](const std::pair& lhs, const std::pair& rhs) -> bool { - return LessThan(lhs.first, rhs.first); + return LessThan(lhs.first, rhs.first); }); } @@ -80,7 +82,7 @@ void KeyValueSort(std::pair* row_to_sort, int64 num_elements) { std::stable_sort(row_to_sort, row_to_sort + num_elements, [](const std::pair& lhs, const std::pair& rhs) -> bool { - return LessThan(lhs.first, rhs.first); + return LessThan(lhs.first, rhs.first); }); } @@ -90,7 +92,7 @@ void KeyValueSort(std::pair* row_to_sort, std::stable_sort(row_to_sort, row_to_sort + num_elements, [](const std::pair& lhs, const std::pair& rhs) -> bool { - return LessThan( + return LessThan( Eigen::half_impl::half_to_float(lhs.first), Eigen::half_impl::half_to_float(rhs.first)); }); -- GitLab From e978c676341c3b047f90c18de74c15be24dd09f6 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Wed, 21 Nov 2018 05:59:55 -0800 Subject: [PATCH 191/672] Add deprecation warning for `tf_record_iterator` PiperOrigin-RevId: 222396408 --- tensorflow/python/lib/io/tf_record.py | 9 +++++---- tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt | 4 ---- tensorflow/tools/compatibility/renames_v2.py | 3 ++- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tensorflow/python/lib/io/tf_record.py b/tensorflow/python/lib/io/tf_record.py index b7fae85295..43086ab18d 100644 --- a/tensorflow/python/lib/io/tf_record.py +++ b/tensorflow/python/lib/io/tf_record.py @@ -150,10 +150,11 @@ class TFRecordOptions(object): return options -@tf_export( - "io.tf_record_iterator", - v1=["io.tf_record_iterator", "python_io.tf_record_iterator"]) -@deprecation.deprecated_endpoints("python_io.tf_record_iterator") +@tf_export(v1=["io.tf_record_iterator", "python_io.tf_record_iterator"]) +@deprecation.deprecated( + date=None, + instructions=("Use eager execution and: \n" + "`tf.data.TFRecordDataset(path)`")) def tf_record_iterator(path, options=None): """An iterator that read the records from a TFRecords file. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt index b27df178b5..caa207b022 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt @@ -120,10 +120,6 @@ tf_module { name: "serialize_tensor" argspec: "args=[\'tensor\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "tf_record_iterator" - argspec: "args=[\'path\', \'options\'], varargs=None, keywords=None, defaults=[\'None\'], " - } member_method { name: "write_file" argspec: "args=[\'filename\', \'contents\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index f002418020..d71dce42b1 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -211,6 +211,7 @@ renames = { 'tf.initializers.tables_initializer': 'tf.compat.v1.initializers.tables_initializer', 'tf.initializers.variables': 'tf.compat.v1.initializers.variables', 'tf.invert_permutation': 'tf.math.invert_permutation', + 'tf.io.tf_record_iterator': 'tf.compat.v1.io.tf_record_iterator', 'tf.is_finite': 'tf.math.is_finite', 'tf.is_inf': 'tf.math.is_inf', 'tf.is_nan': 'tf.math.is_nan', @@ -350,7 +351,7 @@ renames = { 'tf.python_io.TFRecordCompressionType': 'tf.io.TFRecordCompressionType', 'tf.python_io.TFRecordOptions': 'tf.io.TFRecordOptions', 'tf.python_io.TFRecordWriter': 'tf.io.TFRecordWriter', - 'tf.python_io.tf_record_iterator': 'tf.io.tf_record_iterator', + 'tf.python_io.tf_record_iterator': 'tf.compat.v1.python_io.tf_record_iterator', 'tf.qr': 'tf.linalg.qr', 'tf.quantize': 'tf.quantization.quantize', 'tf.quantize_v2': 'tf.compat.v1.quantize_v2', -- GitLab From 3ff69a2fca5f16ba9b9e9b35da546f6066ec19c7 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Wed, 21 Nov 2018 06:29:04 -0800 Subject: [PATCH 192/672] Use stable_sort instead of sort in HloEvaluator implementation of the sort op. We need to guarantee stable sorting when used by TopK. PiperOrigin-RevId: 222399261 --- tensorflow/compiler/xla/service/hlo_evaluator.cc | 8 ++++---- .../compiler/xla/service/hlo_evaluator_typed_visitor.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_evaluator.cc b/tensorflow/compiler/xla/service/hlo_evaluator.cc index 7fcafafc09..9783f0574f 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator.cc +++ b/tensorflow/compiler/xla/service/hlo_evaluator.cc @@ -1279,10 +1279,10 @@ StatusOr EvaluateSortInternal(HloInstruction* sort, key_value_vector.push_back( std::make_pair(keys_data[i], values_data[i])); } - std::sort(key_value_vector.begin(), key_value_vector.end(), - [](const kv_pair& a, const kv_pair& b) { - return SafeLess(a.first, b.first); - }); + std::stable_sort(key_value_vector.begin(), key_value_vector.end(), + [](const kv_pair& a, const kv_pair& b) { + return SafeLess(a.first, b.first); + }); std::vector result_keys; // We use a InlinedVector here because we need to convert it to an // absl::Span later, and this would not work with std::vector. diff --git a/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h b/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h index f975ba63bb..b87fc3e340 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h +++ b/tensorflow/compiler/xla/service/hlo_evaluator_typed_visitor.h @@ -1553,10 +1553,10 @@ class HloEvaluatorTypedVisitor : public DfsHloVisitorWithDefault { const auto& row_data = row_to_sort.data(); std::vector result_data(row_data.begin(), row_data.end()); - std::sort(result_data.begin(), result_data.end(), - [](const NativeT& a, const NativeT& b) { - return SafeLess(a, b); - }); + std::stable_sort(result_data.begin(), result_data.end(), + [](const NativeT& a, const NativeT& b) { + return SafeLess(a, b); + }); Literal sorted_row(ShapeUtil::MakeShape(keys->shape().element_type(), {sort_dim_elements})); sorted_row.PopulateR1(absl::Span(result_data)); -- GitLab From 7c828171d40ed9019aeefca9d1ad783c6be66d5e Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 21 Nov 2018 07:01:44 -0800 Subject: [PATCH 193/672] Change API for nn.softmax and nn.log_softmax for TF 2.0. PiperOrigin-RevId: 222402226 --- tensorflow/python/ops/nn_ops.py | 54 ++++++++++++++++++- .../tools/api/golden/v2/tensorflow.math.pbtxt | 4 +- .../tools/api/golden/v2/tensorflow.nn.pbtxt | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 6 +++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 21008fc392..755c8ffcd2 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -2118,7 +2118,7 @@ def _softmax(logits, compute_op, dim=-1, name=None): return output -@tf_export("nn.softmax", "math.softmax") +@tf_export(v1=["nn.softmax", "math.softmax"]) @deprecation.deprecated_args(None, "dim is deprecated, use axis instead", "dim") def softmax(logits, axis=None, name=None, dim=None): """Computes softmax activations. @@ -2148,7 +2148,32 @@ def softmax(logits, axis=None, name=None, dim=None): return _softmax(logits, gen_nn_ops.softmax, axis, name) -@tf_export("nn.log_softmax", "math.log_softmax") +@tf_export("nn.softmax", "math.softmax", v1=[]) +def softmax_v2(logits, axis=None, name=None): + """Computes softmax activations. + + This function performs the equivalent of + + softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis) + + Args: + logits: A non-empty `Tensor`. Must be one of the following types: `half`, + `float32`, `float64`. + axis: The dimension softmax would be performed on. The default is -1 which + indicates the last dimension. + name: A name for the operation (optional). + + Returns: + A `Tensor`. Has the same type and shape as `logits`. + + Raises: + InvalidArgumentError: if `logits` is empty or `axis` is beyond the last + dimension of `logits`. + """ + return _softmax(logits, gen_nn_ops.softmax, axis, name) + + +@tf_export(v1=["nn.log_softmax", "math.log_softmax"]) @deprecation.deprecated_args(None, "dim is deprecated, use axis instead", "dim") def log_softmax(logits, axis=None, name=None, dim=None): """Computes log softmax activations. @@ -2178,6 +2203,31 @@ def log_softmax(logits, axis=None, name=None, dim=None): return _softmax(logits, gen_nn_ops.log_softmax, axis, name) +@tf_export("nn.log_softmax", "math.log_softmax", v1=[]) +def log_softmax_v2(logits, axis=None, name=None): + """Computes log softmax activations. + + For each batch `i` and class `j` we have + + logsoftmax = logits - log(reduce_sum(exp(logits), axis)) + + Args: + logits: A non-empty `Tensor`. Must be one of the following types: `half`, + `float32`, `float64`. + axis: The dimension softmax would be performed on. The default is -1 which + indicates the last dimension. + name: A name for the operation (optional). + + Returns: + A `Tensor`. Has the same type as `logits`. Same shape as `logits`. + + Raises: + InvalidArgumentError: if `logits` is empty or `axis` is beyond the last + dimension of `logits`. + """ + return _softmax(logits, gen_nn_ops.log_softmax, axis, name) + + def _ensure_xent_args(name, sentinel, labels, logits): # Make sure that all arguments were passed as named arguments. if sentinel is not None: diff --git a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt index e6b8fd225d..86df970514 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt @@ -230,7 +230,7 @@ tf_module { } member_method { name: "log_softmax" - argspec: "args=[\'logits\', \'axis\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'logits\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "logical_and" @@ -382,7 +382,7 @@ tf_module { } member_method { name: "softmax" - argspec: "args=[\'logits\', \'axis\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'logits\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "softplus" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index 19380337d8..e550b2d754 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -190,7 +190,7 @@ tf_module { } member_method { name: "log_softmax" - argspec: "args=[\'logits\', \'axis\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'logits\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "lrn" @@ -262,7 +262,7 @@ tf_module { } member_method { name: "softmax" - argspec: "args=[\'logits\', \'axis\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'logits\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "softmax_cross_entropy_with_logits" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 0caf1743d7..a4d307032d 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -60,6 +60,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.nn.sufficient_statistics": { "keep_dims": "keepdims" }, + "tf.nn.log_softmax": { + "dim": "axis", + }, + "tf.nn.softmax": { + "dim": "axis", + }, "tf.debugging.assert_all_finite": { "t": "x", "msg": "message", -- GitLab From 2893986ce5ed2af52d2f2a72a093cab3734a9bab Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Wed, 21 Nov 2018 07:14:12 -0800 Subject: [PATCH 194/672] Remove Iota declaration from numeric.h The same declaration exists in xla_builder.h, and it is also implemented in xla_builder.cc Remove the header include of numeric.h where it was only used to get access to Iota. Add the xla_builder.h header instead if it was not already included. PiperOrigin-RevId: 222403720 --- tensorflow/compiler/tf2xla/BUILD | 1 - tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc | 1 - tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc | 1 - tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc | 1 - tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc | 1 - tensorflow/compiler/tf2xla/kernels/random_ops.cc | 1 - tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc | 1 - tensorflow/compiler/tf2xla/kernels/sequence_ops.cc | 2 +- tensorflow/compiler/tf2xla/xla_helpers.cc | 1 - tensorflow/compiler/xla/client/lib/BUILD | 2 -- tensorflow/compiler/xla/client/lib/numeric.h | 3 --- tensorflow/compiler/xla/client/lib/prng.cc | 1 - tensorflow/compiler/xla/client/lib/sorting.cc | 2 +- 13 files changed, 2 insertions(+), 16 deletions(-) diff --git a/tensorflow/compiler/tf2xla/BUILD b/tensorflow/compiler/tf2xla/BUILD index 486b4d8a8c..3458c7f1c4 100644 --- a/tensorflow/compiler/tf2xla/BUILD +++ b/tensorflow/compiler/tf2xla/BUILD @@ -211,7 +211,6 @@ cc_library( "//tensorflow/compiler/xla/client:xla_computation", "//tensorflow/compiler/xla/client/lib:arithmetic", "//tensorflow/compiler/xla/client/lib:constants", - "//tensorflow/compiler/xla/client/lib:numeric", "//tensorflow/core:core_cpu", "//tensorflow/core:core_cpu_internal", "//tensorflow/core:framework", diff --git a/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc b/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc index c9a1be4940..b1046fcc00 100644 --- a/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc +++ b/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc @@ -24,7 +24,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/lib/arithmetic.h" #include "tensorflow/compiler/xla/client/lib/constants.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/literal_util.h" #include "tensorflow/core/framework/node_def_util.h" diff --git a/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc b/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc index c68b0bfd79..29687c7b82 100644 --- a/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc @@ -17,7 +17,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_helpers.h" #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/core/util/tensor_format.h" diff --git a/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc b/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc index 8dfd7de591..a99b74565d 100644 --- a/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc @@ -16,7 +16,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_helpers.h" #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/core/framework/tensor_shape.h" diff --git a/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc b/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc index c0ca881ff8..4f980b6d14 100644 --- a/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc @@ -16,7 +16,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_helpers.h" #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" namespace tensorflow { diff --git a/tensorflow/compiler/tf2xla/kernels/random_ops.cc b/tensorflow/compiler/tf2xla/kernels/random_ops.cc index 415ce9b77f..8822e29f7e 100644 --- a/tensorflow/compiler/tf2xla/kernels/random_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/random_ops.cc @@ -26,7 +26,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/lib/arithmetic.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/tensor.h" diff --git a/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc b/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc index 7ff3e91638..d7b38e86cc 100644 --- a/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc @@ -18,7 +18,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/lib/constants.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/framework/tensor_shape.h" diff --git a/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc b/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc index 60b011ba6d..b1fa2915d5 100644 --- a/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc @@ -18,7 +18,7 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_helpers.h" #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" +#include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/literal.h" #include "tensorflow/compiler/xla/primitive_util.h" #include "tensorflow/core/framework/op_kernel.h" diff --git a/tensorflow/compiler/tf2xla/xla_helpers.cc b/tensorflow/compiler/tf2xla/xla_helpers.cc index 9a34cd8c6a..af378bc95c 100644 --- a/tensorflow/compiler/tf2xla/xla_helpers.cc +++ b/tensorflow/compiler/tf2xla/xla_helpers.cc @@ -26,7 +26,6 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/xla/client/lib/arithmetic.h" #include "tensorflow/compiler/xla/client/lib/constants.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/client/xla_computation.h" #include "tensorflow/compiler/xla/types.h" diff --git a/tensorflow/compiler/xla/client/lib/BUILD b/tensorflow/compiler/xla/client/lib/BUILD index f8dce0db9f..c5733bc66d 100644 --- a/tensorflow/compiler/xla/client/lib/BUILD +++ b/tensorflow/compiler/xla/client/lib/BUILD @@ -164,7 +164,6 @@ cc_library( deps = [ ":constants", ":math", - ":numeric", "//tensorflow/compiler/xla:util", "//tensorflow/compiler/xla:xla_data_proto", "//tensorflow/compiler/xla/client:xla_builder", @@ -178,7 +177,6 @@ cc_library( srcs = ["sorting.cc"], hdrs = ["sorting.h"], deps = [ - ":numeric", "//tensorflow/compiler/xla:shape_util", "//tensorflow/compiler/xla:types", "//tensorflow/compiler/xla:util", diff --git a/tensorflow/compiler/xla/client/lib/numeric.h b/tensorflow/compiler/xla/client/lib/numeric.h index efd8cdc257..f62fdab4b0 100644 --- a/tensorflow/compiler/xla/client/lib/numeric.h +++ b/tensorflow/compiler/xla/client/lib/numeric.h @@ -22,9 +22,6 @@ limitations under the License. namespace xla { -// Returns a rank 1 tensor of `type` containing values [0, 1, 2, ...]. -XlaOp Iota(XlaBuilder* builder, PrimitiveType type, int64 size); - // Returns an m x n matrix with 1s on the diagonal elements, zeros everywhere // else. XlaOp IdentityMatrix(XlaBuilder* builder, PrimitiveType type, int64 m, int64 n); diff --git a/tensorflow/compiler/xla/client/lib/prng.cc b/tensorflow/compiler/xla/client/lib/prng.cc index c6f68c8ee2..85b9e1827d 100644 --- a/tensorflow/compiler/xla/client/lib/prng.cc +++ b/tensorflow/compiler/xla/client/lib/prng.cc @@ -18,7 +18,6 @@ limitations under the License. #include "absl/base/casts.h" #include "tensorflow/compiler/xla/client/lib/constants.h" #include "tensorflow/compiler/xla/client/lib/math.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/util.h" diff --git a/tensorflow/compiler/xla/client/lib/sorting.cc b/tensorflow/compiler/xla/client/lib/sorting.cc index d3980d5575..e8553a08bb 100644 --- a/tensorflow/compiler/xla/client/lib/sorting.cc +++ b/tensorflow/compiler/xla/client/lib/sorting.cc @@ -14,7 +14,7 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/compiler/xla/client/lib/sorting.h" -#include "tensorflow/compiler/xla/client/lib/numeric.h" +#include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/shape_util.h" #include "tensorflow/compiler/xla/util.h" -- GitLab From 944efe54b6f566f5127e5122193b55db28ff9b4f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 07:40:44 -0800 Subject: [PATCH 195/672] Remove min_max_variable_partitioner from TF 2.0 API PiperOrigin-RevId: 222406576 --- tensorflow/python/ops/partitioned_variables.py | 2 +- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 4 ---- tensorflow/tools/compatibility/renames_v2.py | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 7743b634e8..6174979d5e 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -154,7 +154,7 @@ def variable_axis_size_partitioner( return _partitioner -@tf_export("min_max_variable_partitioner") +@tf_export(v1=["min_max_variable_partitioner"]) def min_max_variable_partitioner(max_partitions=1, axis=0, min_slice_size=256 << 10, bytes_per_string_element=16): diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index ec2d72290e..c91aa43671 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -820,10 +820,6 @@ tf_module { name: "meshgrid" argspec: "args=[], varargs=args, keywords=kwargs, defaults=None" } - member_method { - name: "min_max_variable_partitioner" - argspec: "args=[\'max_partitions\', \'axis\', \'min_slice_size\', \'bytes_per_string_element\'], varargs=None, keywords=None, defaults=[\'1\', \'0\', \'262144\', \'16\'], " - } member_method { name: "minimum" argspec: "args=[\'x\', \'y\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index d71dce42b1..088611dc6c 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -306,6 +306,7 @@ renames = { 'tf.matrix_solve_ls': 'tf.linalg.lstsq', 'tf.matrix_transpose': 'tf.linalg.transpose', 'tf.matrix_triangular_solve': 'tf.linalg.triangular_solve', + 'tf.min_max_variable_partitioner': 'tf.compat.v1.min_max_variable_partitioner', 'tf.model_variables': 'tf.compat.v1.model_variables', 'tf.moving_average_variables': 'tf.compat.v1.moving_average_variables', 'tf.multinomial': 'tf.compat.v1.multinomial', -- GitLab From c20b4ba1e6d25368e08b9a36ee348f0864734a82 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 08:25:02 -0800 Subject: [PATCH 196/672] batch_to_space changes for TF 2.0 API This change renames batch_to_space_nd to batch_to_space in TF 2.0. Arguments are re-ordered and the the block_size int argument has been to block_shape of type Tensor. Users may still use an int block_shape, for compatibility purposes those are silently converted to a Tensor. PiperOrigin-RevId: 222411473 --- .../python_api/api_def_BatchToSpaceND.pbtxt | 2 + tensorflow/python/ops/array_ops.py | 147 +++++++++++++++++- .../tools/api/golden/v2/tensorflow.pbtxt | 4 - tensorflow/tools/compatibility/renames_v2.py | 3 +- .../tools/compatibility/tf_upgrade_v2.py | 10 ++ 5 files changed, 160 insertions(+), 6 deletions(-) diff --git a/tensorflow/core/api_def/python_api/api_def_BatchToSpaceND.pbtxt b/tensorflow/core/api_def/python_api/api_def_BatchToSpaceND.pbtxt index 801dfbc285..94ffc7c068 100644 --- a/tensorflow/core/api_def/python_api/api_def_BatchToSpaceND.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_BatchToSpaceND.pbtxt @@ -1,7 +1,9 @@ op { graph_op_name: "BatchToSpaceND" + deprecation_message: "use batch_to_space" endpoint { name: "batch_to_space_nd" + deprecation_version: 2 } endpoint { name: "manip.batch_to_space_nd" diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index ed050d740e..0f80a28d7f 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -2675,7 +2675,7 @@ def depth_to_space(input, block_size, name=None, data_format="NHWC"): # pylint: depth_to_space.__doc__ = gen_array_ops.depth_to_space.__doc__ -@tf_export("batch_to_space") +@tf_export(v1=["batch_to_space"]) def batch_to_space(input, crops, block_size, name=None): # pylint: disable=redefined-builtin result = batch_to_space_nd( input, @@ -2689,6 +2689,151 @@ def batch_to_space(input, crops, block_size, name=None): # pylint: disable=rede batch_to_space.__doc__ = gen_array_ops.batch_to_space.__doc__ +@tf_export("batch_to_space", v1=[]) +def batch_to_space_v2(input, block_shape, crops, name=None): # pylint: disable=redefined-builtin + """BatchToSpace for N-D tensors of type T. + + This operation reshapes the "batch" dimension 0 into `M + 1` dimensions of + shape `block_shape + [batch]`, interleaves these blocks back into the grid + defined by the spatial dimensions `[1, ..., M]`, to obtain a result with the + same rank as the input. The spatial dimensions of this intermediate result + are then optionally cropped according to `crops` to produce the output. This + is the reverse of SpaceToBatch. See below for a precise description. + + Args: + input: A `Tensor`. + N-D with shape `input_shape = [batch] + spatial_shape + remaining_shape`, + where spatial_shape has M dimensions. + block_shape: A `Tensor`. Must be one of the following types: + `int32`, `int64`. 1-D with shape `[M]`, all values must be >= 1. + For backwards compatibility with TF 1.0, this parameter may be an int, in + which case it is converted to + `numpy.array([block_shape, block_shape], dtype=numpy.int64)`. + crops: A `Tensor`. Must be one of the following types: `int32`, `int64`. + 2-D with shape `[M, 2]`, all values must be >= 0. + `crops[i] = [crop_start, crop_end]` specifies the amount to crop from + input dimension `i + 1`, which corresponds to spatial dimension `i`. It + is required that + `crop_start[i] + crop_end[i] <= block_shape[i] * input_shape[i + 1]`. + + This operation is equivalent to the following steps: + + 1. Reshape `input` to `reshaped` of shape: + [block_shape[0], ..., block_shape[M-1], + batch / prod(block_shape), + input_shape[1], ..., input_shape[N-1]] + + 2. Permute dimensions of `reshaped` to produce `permuted` of shape + [batch / prod(block_shape), + + input_shape[1], block_shape[0], + ..., + input_shape[M], block_shape[M-1], + + input_shape[M+1], ..., input_shape[N-1]] + + 3. Reshape `permuted` to produce `reshaped_permuted` of shape + [batch / prod(block_shape), + + input_shape[1] * block_shape[0], + ..., + input_shape[M] * block_shape[M-1], + + input_shape[M+1], + ..., + input_shape[N-1]] + + 4. Crop the start and end of dimensions `[1, ..., M]` of + `reshaped_permuted` according to `crops` to produce the + output of shape: + [batch / prod(block_shape), + + input_shape[1] * block_shape[0] - crops[0,0] - crops[0,1], + ..., + input_shape[M] * block_shape[M-1] - crops[M-1,0] - crops[M-1,1], + + input_shape[M+1], ..., input_shape[N-1]] + + Some examples: + + (1) For the following input of shape `[4, 1, 1, 1]`, + `block_shape = [2, 2]`, and `crops = [[0, 0], [0, 0]]`: + + ``` + [[[[1]]], [[[2]]], [[[3]]], [[[4]]]] + ``` + + The output tensor has shape `[1, 2, 2, 1]` and value: + + ``` + x = [[[[1], [2]], [[3], [4]]]] + ``` + + (2) For the following input of shape `[4, 1, 1, 3]`, + `block_shape = [2, 2]`, and `crops = [[0, 0], [0, 0]]`: + + ``` + [[[1, 2, 3]], [[4, 5, 6]], [[7, 8, 9]], [[10, 11, 12]]] + ``` + + The output tensor has shape `[1, 2, 2, 3]` and value: + + ``` + x = [[[[1, 2, 3], [4, 5, 6]], + [[7, 8, 9], [10, 11, 12]]]] + ``` + + (3) For the following input of shape `[4, 2, 2, 1]`, + `block_shape = [2, 2]`, and `crops = [[0, 0], [0, 0]]`: + + ``` + x = [[[[1], [3]], [[9], [11]]], + [[[2], [4]], [[10], [12]]], + [[[5], [7]], [[13], [15]]], + [[[6], [8]], [[14], [16]]]] + ``` + + The output tensor has shape `[1, 4, 4, 1]` and value: + + ``` + x = [[[1], [2], [3], [4]], + [[5], [6], [7], [8]], + [[9], [10], [11], [12]], + [[13], [14], [15], [16]]] + ``` + + (4) For the following input of shape `[8, 1, 3, 1]`, + `block_shape = [2, 2]`, and `crops = [[0, 0], [2, 0]]`: + + ``` + x = [[[[0], [1], [3]]], [[[0], [9], [11]]], + [[[0], [2], [4]]], [[[0], [10], [12]]], + [[[0], [5], [7]]], [[[0], [13], [15]]], + [[[0], [6], [8]]], [[[0], [14], [16]]]] + ``` + + The output tensor has shape `[2, 2, 4, 1]` and value: + + ``` + x = [[[[1], [2], [3], [4]], + [[5], [6], [7], [8]]], + [[[9], [10], [11], [12]], + [[13], [14], [15], [16]]]] + ``` + name: A name for the operation (optional). + + Returns: + A `Tensor`. Has the same type as `input`. + """ + if isinstance(block_shape, int): + block_shape = np.array([block_shape, block_shape], dtype=np.int64) + + return batch_to_space_nd(input=input, + block_shape=block_shape, + crops=crops, + name=name) + + @tf_export("one_hot") def one_hot(indices, depth, diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index c91aa43671..0649ae267b 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -510,10 +510,6 @@ tf_module { } member_method { name: "batch_to_space" - argspec: "args=[\'input\', \'crops\', \'block_size\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "batch_to_space_nd" argspec: "args=[\'input\', \'block_shape\', \'crops\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 088611dc6c..a93b7d68bd 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -92,6 +92,7 @@ renames = { 'tf.assign': 'tf.compat.v1.assign', 'tf.assign_add': 'tf.compat.v1.assign_add', 'tf.assign_sub': 'tf.compat.v1.assign_sub', + 'tf.batch_to_space_nd': 'tf.compat.v1.batch_to_space_nd', 'tf.betainc': 'tf.math.betainc', 'tf.bincount': 'tf.math.bincount', 'tf.ceil': 'tf.math.ceil', @@ -287,7 +288,7 @@ renames = { 'tf.logical_xor': 'tf.math.logical_xor', 'tf.make_template': 'tf.compat.v1.make_template', 'tf.make_tensor_proto': 'tf.compat.v1.make_tensor_proto', - 'tf.manip.batch_to_space_nd': 'tf.batch_to_space_nd', + 'tf.manip.batch_to_space_nd': 'tf.compat.v1.manip.batch_to_space_nd', 'tf.manip.gather_nd': 'tf.gather_nd', 'tf.manip.reshape': 'tf.reshape', 'tf.manip.reverse': 'tf.reverse', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index a4d307032d..f85b2f08dc 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -43,6 +43,9 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.expand_dims": { "dim": "axis", }, + "tf.batch_to_space_nd": { + "block_size": "block_shape", + }, "tf.convert_to_tensor": { "preferred_dtype": "dtype_hint" }, @@ -84,6 +87,9 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "m": "mean", "v": "variance", }, + "tf.manip.batch_to_space_nd": { + "block_size": "block_shape", + }, "tf.nn.conv3d": { "filter": "filters" }, @@ -117,6 +123,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # function_reorders or function_keyword_renames, use the OLD function name. # These renames happen after the arguments have been processed. self.symbol_renames.update({ + "tf.batch_to_space_nd": "tf.batch_to_space", "tf.contrib.data.AUTOTUNE": "tf.data.experimental.AUTOTUNE", "tf.contrib.data.Counter": "tf.data.experimental.Counter", "tf.contrib.data.CheckpointInputPipelineHook": "tf.data.experimental.CheckpointInputPipelineHook", @@ -161,6 +168,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.contrib.data.unique": "tf.data.experimental.unique", "tf.contrib.framework.sort": "tf.sort", "tf.contrib.framework.argsort": "tf.argsort", + "tf.manip.batch_to_space_nd": "tf.batch_to_space", "tf.quantize_v2": "tf.quantization.quantize", "tf.sparse_concat": "tf.sparse.concat", "tf.sparse_split": "tf.sparse.split", @@ -186,6 +194,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): self.function_reorders = { "tf.argmax": ["input", "axis", "name", "dimension", "output_type"], "tf.argmin": ["input", "axis", "name", "dimension", "output_type"], + "tf.batch_to_space": ["input", "crops", "block_size", "name"], "tf.boolean_mask": ["tensor", "mask", "name", "axis"], "tf.convert_to_tensor": ["value", "dtype", "name", "preferred_dtype"], "tf.nn.convolution": [ @@ -200,6 +209,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "input", "filter", "strides", "padding", "rate", "name", "data_format" ], + "tf.manip.batch_to_space_nd": ["input", "crops", "block_size", "name"], "tf.multinomial": [ "logits", "num_samples", "seed", "name", "output_dtype" ], -- GitLab From 7b10cfd70094f619508f18b40c1fa60ab8d86083 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Wed, 21 Nov 2018 09:09:59 -0800 Subject: [PATCH 197/672] Aligned the reuse behaviour of plain and partitioned variables in eager Previously, plain variables were only stored if EagerVariableStore was active, whereas partitioned variables were always stored. PiperOrigin-RevId: 222417188 --- tensorflow/python/kernel_tests/variable_scope_test.py | 8 ++++++++ tensorflow/python/ops/variable_scope.py | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index 838838e0ac..de086860ea 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -1404,6 +1404,14 @@ class VariableScopeWithPartitioningTest(test.TestCase): v_reused = variable_scope.get_variable("name0") self.assertEqual(v, v_reused) + def testNoReuseInEagerByDefault(self): + with context.eager_mode(): + with variable_scope.variable_scope( + "scope0", partitioner=axis0_into2_partitioner): + v1 = variable_scope.get_variable("name0", shape=(3, 1, 1)) + v2 = variable_scope.get_variable("name0", shape=(3, 1, 1)) + self.assertIsNot(v1, v2) + @test_util.run_in_graph_and_eager_modes @run_inside_wrap_function_in_eager_mode def testPropagatePartitionerOnReopening(self): diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 077bb647ef..44bb62a5dc 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -799,15 +799,13 @@ class _VariableStore(object): vs.append(var) # pylint: enable=protected-access - # pylint: disable=protected-access partitioned_var = variables.PartitionedVariable(name=name, shape=shape, dtype=dtype, variable_list=vs, partitions=partitions) - # pylint: enable=protected-access - - self._partitioned_vars[name] = partitioned_var + if not context.executing_eagerly() or self._store_eager_variables: + self._partitioned_vars[name] = partitioned_var return partitioned_var def _get_single_variable(self, -- GitLab From 9fe074be83373dd66f1711e7267da37b05341327 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 21 Nov 2018 09:11:24 -0800 Subject: [PATCH 198/672] Removes spurious cond name scope in contrib metrics. PiperOrigin-RevId: 222417340 --- tensorflow/contrib/eager/python/metrics_impl.py | 6 ++++-- tensorflow/contrib/eager/python/metrics_test.py | 12 ------------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/tensorflow/contrib/eager/python/metrics_impl.py b/tensorflow/contrib/eager/python/metrics_impl.py index c88c0f52ee..566246de49 100644 --- a/tensorflow/contrib/eager/python/metrics_impl.py +++ b/tensorflow/contrib/eager/python/metrics_impl.py @@ -24,6 +24,7 @@ from tensorflow.python.eager import context from tensorflow.python.eager import function from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import smart_cond from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops @@ -354,9 +355,10 @@ class Mean(Metric): def write_summary_f(): summary_ops.scalar(name=self.name, tensor=t) return t - control_flow_ops.cond(write_summary, + smart_cond.smart_cond(write_summary, write_summary_f, - lambda: t) + lambda: t, + name="") return t diff --git a/tensorflow/contrib/eager/python/metrics_test.py b/tensorflow/contrib/eager/python/metrics_test.py index 9d2d172752..39e5957f5d 100644 --- a/tensorflow/contrib/eager/python/metrics_test.py +++ b/tensorflow/contrib/eager/python/metrics_test.py @@ -49,18 +49,6 @@ class MetricsTest(test.TestCase): self.assertEqual(dtypes.float64, m.dtype) self.assertEqual(dtypes.float64, m.result().dtype) - def testSummaryArg(self): - m = metrics.Mean() - m([1, 10, 100]) - m(1000) - m([10000.0, 100000.0]) - self.assertEqual(111111.0/6, m.result(write_summary=True).numpy()) - self.assertEqual(111111.0/6, m.result(write_summary=False).numpy()) - with self.assertRaises(ValueError): - m.result(write_summary=5) - with self.assertRaises(ValueError): - m.result(write_summary=[True]) - def testVariableCollections(self): with context.graph_mode(), ops.Graph().as_default(): m = metrics.Mean() -- GitLab From 80f3b787e485d0d7dc775412d981a09e95090b78 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 09:19:22 -0800 Subject: [PATCH 199/672] Fix a typo PiperOrigin-RevId: 222418257 --- tensorflow/python/eager/def_function.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/eager/def_function.py b/tensorflow/python/eager/def_function.py index 52830d41bf..6bacd7a962 100644 --- a/tensorflow/python/eager/def_function.py +++ b/tensorflow/python/eager/def_function.py @@ -552,9 +552,9 @@ def function(func=None, return x + tf.to_float(c) assert int(c) == 0 - assert f(1.0) == 3.0 + assert f(1.0) == 2.0 assert int(c) == 1 - assert f(1.0) == 4.0 + assert f(1.0) == 3.0 assert int(c) == 2 ``` -- GitLab From 4f92a46fa8731fc7883888bce3f8a081293f8345 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Wed, 21 Nov 2018 09:43:16 -0800 Subject: [PATCH 200/672] Automated rollback of commit fd46ffb7bd04d0959294a09ae8a9d2cbd74a48ca PiperOrigin-RevId: 222421495 --- tensorflow/python/data/experimental/ops/BUILD | 2 +- .../python/data/experimental/ops/grouping.py | 16 +- tensorflow/python/data/kernel_tests/BUILD | 4 + .../data/kernel_tests/dataset_ops_test.py | 61 ++++ tensorflow/python/data/ops/dataset_ops.py | 260 +++++++----------- tensorflow/python/data/ops/optional_ops.py | 12 +- tensorflow/python/data/util/structure.py | 26 +- tensorflow/python/data/util/structure_test.py | 9 +- 8 files changed, 202 insertions(+), 188 deletions(-) diff --git a/tensorflow/python/data/experimental/ops/BUILD b/tensorflow/python/data/experimental/ops/BUILD index 170fda90b6..b6c1376b6a 100644 --- a/tensorflow/python/data/experimental/ops/BUILD +++ b/tensorflow/python/data/experimental/ops/BUILD @@ -165,7 +165,7 @@ py_library( "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/util:nest", - "//tensorflow/python/data/util:sparse", + "//tensorflow/python/data/util:structure", ], ) diff --git a/tensorflow/python/data/experimental/ops/grouping.py b/tensorflow/python/data/experimental/ops/grouping.py index 80ca7104d8..db10ea3b7f 100644 --- a/tensorflow/python/data/experimental/ops/grouping.py +++ b/tensorflow/python/data/experimental/ops/grouping.py @@ -21,6 +21,7 @@ import numpy as np from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest +from tensorflow.python.data.util import structure from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -448,7 +449,10 @@ class _GroupByWindowDataset(dataset_ops.UnaryDataset): def _make_reduce_func(self, reduce_func, input_dataset): """Make wrapping defun for reduce_func.""" - nested_dataset = dataset_ops._NestedDatasetComponent(input_dataset) # pylint: disable=protected-access + nested_dataset = dataset_ops.DatasetStructure( + structure.Structure._from_legacy_structure( # pylint: disable=protected-access + input_dataset.output_types, input_dataset.output_shapes, + input_dataset.output_classes)) wrapped_func = dataset_ops.StructuredFunctionWrapper( reduce_func, self._transformation_name(), @@ -456,11 +460,13 @@ class _GroupByWindowDataset(dataset_ops.UnaryDataset): input_shapes=(tensor_shape.scalar(), nested_dataset), input_types=(dtypes.int64, nested_dataset)) if not isinstance( - wrapped_func.output_classes, dataset_ops._NestedDatasetComponent): # pylint: disable=protected-access + wrapped_func.output_structure, dataset_ops.DatasetStructure): raise TypeError("`reduce_func` must return a `Dataset` object.") - self._output_classes = wrapped_func.output_classes.output_classes - self._output_types = wrapped_func.output_types.output_types - self._output_shapes = wrapped_func.output_shapes.output_shapes + # pylint: disable=protected-access + element_structure = wrapped_func.output_structure._element_structure + self._output_classes = element_structure._to_legacy_output_classes() + self._output_types = element_structure._to_legacy_output_types() + self._output_shapes = element_structure._to_legacy_output_shapes() self._reduce_func = wrapped_func.function @property diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index 21eed2b070..fa1f6d701a 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -117,8 +117,12 @@ tf_py_test( "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", "//tensorflow/python:sparse_tensor", + "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:optional_ops", + "//tensorflow/python/data/util:structure", ], ) diff --git a/tensorflow/python/data/kernel_tests/dataset_ops_test.py b/tensorflow/python/data/kernel_tests/dataset_ops_test.py index a5324af4d0..1f22a37c2e 100644 --- a/tensorflow/python/data/kernel_tests/dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_ops_test.py @@ -24,10 +24,14 @@ import numpy as np from tensorflow.core.framework import graph_pb2 from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.ops import optional_ops from tensorflow.python.data.ops import readers from tensorflow.python.data.util import nest +from tensorflow.python.data.util import structure +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import tensor_shape from tensorflow.python.platform import test @@ -249,6 +253,63 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertTrue(ds.options().experimental_autotune) self.assertTrue(ds.options().experimental_filter_fusion) + # pylint: disable=g-long-lambda + @parameterized.named_parameters( + ("Tensor", lambda: constant_op.constant(37.0), + structure.TensorStructure(dtypes.float32, [])), + ("SparseTensor", lambda: sparse_tensor.SparseTensor( + indices=[[0]], values=constant_op.constant([0], dtype=dtypes.int32), + dense_shape=[1]), + structure.SparseTensorStructure(dtypes.int32, [1])), + ("Nest", lambda: { + "a": constant_op.constant(37.0), + "b": (constant_op.constant(["Foo"]), constant_op.constant("Bar"))}, + structure.NestedStructure({ + "a": structure.TensorStructure(dtypes.float32, []), + "b": (structure.TensorStructure(dtypes.string, [1]), + structure.TensorStructure(dtypes.string, []))})), + ("Dataset", lambda: dataset_ops.Dataset.from_tensor_slices( + constant_op.constant([1, 2, 3])), + dataset_ops.DatasetStructure( + structure.TensorStructure(dtypes.int32, []))), + ("Optional", lambda: optional_ops.Optional.from_value(37.0), + optional_ops.OptionalStructure( + structure.TensorStructure(dtypes.float32, []))), + ) + def testDatasetStructure(self, tf_value_fn, expected_element_structure): + dataset = dataset_ops.Dataset.from_tensors(0).map(lambda _: tf_value_fn()) + dataset_structure = structure.Structure.from_value(dataset) + self.assertIsInstance(dataset_structure, dataset_ops.DatasetStructure) + + # TODO(b/110122868): Add a public API to `tf.data.Dataset` for accessing + # the element structure. + self.assertTrue(expected_element_structure.is_compatible_with( + dataset_structure._element_structure)) + self.assertTrue(dataset_structure._element_structure.is_compatible_with( + expected_element_structure)) + + self.assertEqual([dtypes.variant], dataset_structure._flat_types) + self.assertEqual([tensor_shape.scalar()], dataset_structure._flat_shapes) + + # Assert that the `Dataset` survives a round-trip via _from_tensor_list() + # and _to_tensor_list(). + round_trip_dataset = dataset_structure._from_tensor_list( + dataset_structure._to_tensor_list(dataset)) + + value = tf_value_fn() + + if isinstance(value, dataset_ops.Dataset): + self.assertDatasetsEqual(value, dataset.flat_map(lambda x: x)) + elif isinstance(value, optional_ops.Optional): + self.assertDatasetProduces( + round_trip_dataset.map(lambda opt: opt.get_value()), + [self.evaluate(value.get_value())], + requires_initialization=True) + else: + self.assertDatasetProduces( + round_trip_dataset, [self.evaluate(tf_value_fn())], + requires_initialization=True) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 4a11619112..5c0cfe994d 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -31,6 +31,7 @@ from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.util import nest from tensorflow.python.data.util import random_seed from tensorflow.python.data.util import sparse +from tensorflow.python.data.util import structure as structure_lib from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -1868,57 +1869,6 @@ class SparseTensorSliceDataset(DatasetSource): return (dtypes.int64, self._sparse_tensor.dtype, dtypes.int64) -class _NestedDatasetComponent(object): - """The structure of a `Dataset` nested in a component of another `Dataset`. - - A `StructuredFunctionWrapper` around a function that returns a `Dataset` as - one of its components will have a `NestedDatasetComponent` in the - corresponding position in the `output_classes`, `output_shapes`, and - `output_types` properties. - - TODO(b/110122868): Add this class, or something equivalent, to the public API. - We are considering revising the public API for accessing Dataset structure - (`output_classes` etc.) based on experience with nested datasets and other - custom component types. - """ - - def __init__(self, - dataset=None, - output_shapes=None, - output_types=None, - output_classes=None): - if dataset is None: - if (output_classes is None or output_shapes is None or - output_types is None): - raise ValueError( - "Either `dataset`, or all of `output_classes`, " - "`output_shapes`, and `output_types` must be specified.") - self._output_classes = output_classes - self._output_shapes = output_shapes - self._output_types = output_types - else: - if not (output_classes is None and output_shapes is None and - output_types is None): - raise ValueError( - "Either `dataset`, or all of `output_classes`, " - "`output_shapes`, and `output_types` must be specified.") - self._output_classes = dataset.output_classes - self._output_shapes = dataset.output_shapes - self._output_types = dataset.output_types - - @property - def output_classes(self): - return self._output_classes - - @property - def output_shapes(self): - return self._output_shapes - - @property - def output_types(self): - return self._output_types - - class _VariantDataset(DatasetV2): """A Dataset wrapper around a `tf.variant`-typed function argument.""" @@ -1935,15 +1885,73 @@ class _VariantDataset(DatasetV2): @property def output_classes(self): - return self._structure.output_classes + return self._structure._to_legacy_output_classes() # pylint: disable=protected-access @property def output_shapes(self): - return self._structure.output_shapes + return self._structure._to_legacy_output_shapes() # pylint: disable=protected-access @property def output_types(self): - return self._structure.output_types + return self._structure._to_legacy_output_types() # pylint: disable=protected-access + + +class DatasetStructure(structure_lib.Structure): + """Represents a `Dataset` of structured values.""" + + def __init__(self, element_structure): + self._element_structure = element_structure + + @property + def _flat_shapes(self): + return [tensor_shape.scalar()] + + @property + def _flat_types(self): + return [dtypes.variant] + + def is_compatible_with(self, other): + # pylint: disable=protected-access + return (isinstance(other, DatasetStructure) and + self._element_structure.is_compatible_with( + other._element_structure)) + + def _to_tensor_list(self, value): + return [value._as_variant_tensor()] # pylint: disable=protected-access + + def _from_tensor_list(self, flat_value): + if (len(flat_value) != 1 or flat_value[0].dtype != dtypes.variant or + not flat_value[0].shape.is_compatible_with(tensor_shape.scalar())): + raise ValueError( + "DatasetStructure corresponds to a single tf.variant scalar.") + return self._from_compatible_tensor_list(flat_value) + + def _from_compatible_tensor_list(self, flat_value): + # pylint: disable=protected-access + return _VariantDataset(flat_value[0], self._element_structure) + + @staticmethod + def from_value(value): + # TODO(b/110122868): We can simplify this when a `Dataset` object has a + # `Structure`-valued property. + element_structure = structure_lib.Structure._from_legacy_structure( + value.output_types, value.output_shapes, value.output_classes) + return DatasetStructure(element_structure) + + def _to_legacy_output_types(self): + return self + + def _to_legacy_output_shapes(self): + return self + + def _to_legacy_output_classes(self): + return self + + +# pylint: disable=protected-access +structure_lib.Structure._register_custom_converter(DatasetV2, + DatasetStructure.from_value) +# pylint: enable=protected-access class StructuredFunctionWrapper(object): @@ -2001,6 +2009,9 @@ class StructuredFunctionWrapper(object): self._input_types = dataset.output_types self._input_classes = dataset.output_classes + self._input_structure = structure_lib.Structure._from_legacy_structure( # pylint: disable=protected-access + self._input_types, self._input_shapes, self._input_classes) + self._transformation_name = transformation_name readable_transformation_name = transformation_name.replace( ".", "_")[:-2] if len(transformation_name) > 2 else "" @@ -2008,35 +2019,18 @@ class StructuredFunctionWrapper(object): readable_transformation_name, function_utils.get_func_name(func), str(ops.uid()) - ]) if defun_kwargs is None: defun_kwargs = {} @function.Defun( - *self._defun_args(), func_name=self._func_name, **defun_kwargs) + *self._input_structure._flat_types, func_name=self._func_name, # pylint: disable=protected-access + **defun_kwargs) def tf_data_structured_function_wrapper(*args): """Wrapper for passing nested structures to and from tf.data functions.""" - flat_args = [] - for arg, arg_class, arg_shape, arg_type in zip( - args, - nest.flatten(self._input_classes), - nest.flatten(self._input_shapes), - nest.flatten(self._input_types)): - # TODO(b/110122868): Add a registration mechanism for new component - # types. - if arg_class is sparse_tensor_lib.SparseTensor: - arg = sparse.deserialize_sparse_tensors( - arg, arg_type, arg_shape, arg_class) - arg.indices.set_shape([None, arg_shape.ndims]) - arg.dense_shape.set_shape([arg_shape.ndims]) - elif isinstance(arg_class, _NestedDatasetComponent): - arg = _VariantDataset(arg, arg_class) - else: - arg.set_shape(arg_shape) - flat_args.append(arg) - nested_args = nest.pack_sequence_as(self._input_classes, flat_args) + # pylint: disable=protected-access + nested_args = self._input_structure._from_compatible_tensor_list(args) if not _should_unpack_args(nested_args): nested_args = (nested_args,) @@ -2054,50 +2048,14 @@ class StructuredFunctionWrapper(object): if isinstance(ret, list): ret = tuple(ret) - # Convert any `SparseTensorValue`s to `SparseTensor`s and all other - # values to tensors. - flat_ret = [] - flat_classes = [] - flat_shapes = [] - flat_types = [] - for t in nest.flatten(ret): - # TODO(b/110122868): Add a registration mechanism for new component - # types. - if sparse_tensor_lib.is_sparse(t): - t = sparse_tensor_lib.SparseTensor.from_value(t) - flat_ret.append(sparse.serialize_sparse_tensors(t)) - flat_classes.append(sparse_tensor_lib.SparseTensor) - flat_shapes.append(t.get_shape()) - flat_types.append(t.dtype) - elif isinstance(t, DatasetV2): - flat_ret.append(t._as_variant_tensor()) # pylint: disable=protected-access - component = _NestedDatasetComponent(t) - flat_classes.append(component) - flat_shapes.append(component) - flat_types.append(component) - if t.options() != Options(): - warnings.warn("Encountered a nested dataset with non-default " - "options. These options will not be propagated to " - "the outer dataset.") - else: - try: - t = ops.convert_to_tensor(t) - except (ValueError, TypeError): - raise TypeError("Unsupported return value from function passed to " - "%s: %s." % (transformation_name, t)) - flat_ret.append(t) - flat_classes.append(ops.Tensor) - flat_shapes.append(t.get_shape()) - flat_types.append(t.dtype) - - ret = nest.pack_sequence_as(ret, flat_ret) - self._output_classes = nest.pack_sequence_as(ret, flat_classes) - self._output_shapes = nest.pack_sequence_as(ret, flat_shapes) - self._output_types = nest.pack_sequence_as(ret, flat_types) + try: + self._output_structure = structure_lib.Structure.from_value(ret) + except (ValueError, TypeError): + raise TypeError("Unsupported return value from function passed to " + "%s: %s." % (transformation_name, ret)) _warn_if_collections(transformation_name) - - return flat_ret + return self._output_structure._to_tensor_list(ret) self._function = tf_data_structured_function_wrapper if add_to_graph: @@ -2108,32 +2066,21 @@ class StructuredFunctionWrapper(object): # in case (e.g.) we need to rerun the function. self._function._create_definition_if_needed() # pylint: disable=protected-access - def _defun_args(self): - """Returns a flat list of `tf.DType` for the input element structure.""" - ret = [] - for input_type, input_class in zip(nest.flatten(self._input_types), - nest.flatten(self._input_classes)): - # TODO(b/110122868): Add a registration mechanism for new component types. - if input_class is sparse_tensor_lib.SparseTensor: - ret.append(dtypes.variant) - elif isinstance(input_class, _NestedDatasetComponent): - ret.append(dtypes.variant) - else: - assert isinstance(input_type, dtypes.DType) - ret.append(input_type) - return ret + @property + def output_structure(self): + return self._output_structure @property def output_classes(self): - return self._output_classes + return self._output_structure._to_legacy_output_classes() # pylint: disable=protected-access @property def output_shapes(self): - return self._output_shapes + return self._output_structure._to_legacy_output_shapes() # pylint: disable=protected-access @property def output_types(self): - return self._output_types + return self._output_structure._to_legacy_output_types() # pylint: disable=protected-access @property def function(self): @@ -2156,30 +2103,12 @@ def flat_structure(dataset): A dictionary of keyword arguments that can be passed to many Dataset op constructors. """ - output_classes = [] - output_shapes = [] - output_types = [] - for output_class, output_shape, output_type in zip( - nest.flatten(dataset.output_classes), nest.flatten(dataset.output_shapes), - nest.flatten(dataset.output_types)): - if isinstance(output_class, _NestedDatasetComponent): - output_classes.append(output_class.output_classes) - output_shapes.append(output_shape.output_shapes) - output_types.append(output_type.output_types) - else: - output_classes.append(output_class) - output_shapes.append(output_shape) - output_types.append(output_type) - - output_classes = nest.pack_sequence_as(dataset.output_classes, output_classes) - output_shapes = nest.pack_sequence_as(dataset.output_shapes, output_shapes) - output_types = nest.pack_sequence_as(dataset.output_types, output_types) - + # pylint: disable=protected-access + structure = structure_lib.Structure._from_legacy_structure( + dataset.output_types, dataset.output_shapes, dataset.output_classes) return { - "output_shapes": - nest.flatten(sparse.as_dense_shapes(output_shapes, output_classes)), - "output_types": - nest.flatten(sparse.as_dense_types(output_types, output_classes)), + "output_shapes": structure._flat_shapes, + "output_types": structure._flat_types, } @@ -2902,11 +2831,13 @@ class FlatMapDataset(UnaryDataset): wrapped_func = StructuredFunctionWrapper( map_func, self._transformation_name(), dataset=input_dataset) - if not isinstance(wrapped_func.output_classes, _NestedDatasetComponent): + if not isinstance(wrapped_func.output_structure, DatasetStructure): raise TypeError("`map_func` must return a `Dataset` object.") - self._output_classes = wrapped_func.output_classes.output_classes - self._output_types = wrapped_func.output_types.output_types - self._output_shapes = wrapped_func.output_shapes.output_shapes + # pylint: disable=protected-access + element_structure = wrapped_func.output_structure._element_structure + self._output_classes = element_structure._to_legacy_output_classes() + self._output_types = element_structure._to_legacy_output_types() + self._output_shapes = element_structure._to_legacy_output_shapes() self._map_func = wrapped_func.function def _as_variant_tensor(self): @@ -3048,10 +2979,9 @@ class WindowDataset(UnaryDataset): self._output_classes = nest.pack_sequence_as( input_dataset.output_classes, [ - _NestedDatasetComponent( # pylint: disable=protected-access - output_classes=output_class, - output_shapes=output_shape, - output_types=output_type) + DatasetStructure( + structure_lib.Structure._from_legacy_structure( # pylint: disable=protected-access + output_type, output_shape, output_class)) for output_class, output_shape, output_type in zip( nest.flatten(input_dataset.output_classes), nest.flatten(input_dataset.output_shapes), diff --git a/tensorflow/python/data/ops/optional_ops.py b/tensorflow/python/data/ops/optional_ops.py index 91cf883ce9..4113b7ed31 100644 --- a/tensorflow/python/data/ops/optional_ops.py +++ b/tensorflow/python/data/ops/optional_ops.py @@ -183,19 +183,13 @@ class OptionalStructure(structure.Structure): return OptionalStructure(value.value_structure) def _to_legacy_output_types(self): - raise NotImplementedError("The `output_types` property is not supported on " - "structured objects containing an `Optional`. " - "Use the corresponding `structure` property.") + return self def _to_legacy_output_shapes(self): - raise NotImplementedError("The `output_shapes` property is not supported on" - " structured objects containing an `Optional`. " - "Use the corresponding `structure` property.") + return self def _to_legacy_output_classes(self): - raise NotImplementedError("The `output_classes` property is not supported " - "on structured objects containing an `Optional`. " - "Use the corresponding `structure` property.") + return self # pylint: disable=protected-access diff --git a/tensorflow/python/data/util/structure.py b/tensorflow/python/data/util/structure.py index 9a3118297d..3cf67b0745 100644 --- a/tensorflow/python/data/util/structure.py +++ b/tensorflow/python/data/util/structure.py @@ -208,14 +208,16 @@ class Structure(object): flat_ret = [] for flat_type, flat_shape, flat_class in zip(flat_types, flat_shapes, flat_classes): - if issubclass(flat_class, sparse_tensor_lib.SparseTensor): + if isinstance(flat_class, Structure): + flat_ret.append(flat_class) + elif issubclass(flat_class, sparse_tensor_lib.SparseTensor): flat_ret.append(SparseTensorStructure(flat_type, flat_shape)) elif issubclass(flat_class, ops.Tensor): flat_ret.append(TensorStructure(flat_type, flat_shape)) else: # NOTE(mrry): Since legacy structures produced by iterators only - # comprise Tensors, SparseTensors, and nests, we do not need to support - # all structure types here. + # comprise Tensors, SparseTensors, and nests, we do not need to + # support all structure types here. raise TypeError( "Could not build a structure for output class %r" % flat_type) @@ -381,6 +383,13 @@ class TensorStructure(Structure): return self._from_compatible_tensor_list(flat_value) def _from_compatible_tensor_list(self, flat_value): + # TODO(b/112266545): It would be cleaner to create a new `ensure_shape()` + # op here and return that, instead of mutating the input's shape using + # `Tensor.set_shape()`. However, that would add extra ops on the arguments + # of each `tf.data` function, which could impact performance. When this + # bug is resolved, we should be able to add the `ensure_shape()` ops and + # optimize them away using contextual shape information. + flat_value[0].set_shape(self._shape) return flat_value[0] @staticmethod @@ -406,7 +415,11 @@ class SparseTensorStructure(Structure): @property def _flat_shapes(self): - return [tensor_shape.vector(3)] + # NOTE(mrry): The default flat shape of a boxed `SparseTensor` is `(3,)`, + # but a `SparseTensorStructure` can also represent a batch of boxed + # `SparseTensor` objects with shape `(?, 3)` (and batches of batches, etc.), + # so the flat shape must be unknown. + return [tensor_shape.unknown_shape(None)] @property def _flat_types(self): @@ -428,8 +441,11 @@ class SparseTensorStructure(Structure): return self._from_compatible_tensor_list(flat_value) def _from_compatible_tensor_list(self, flat_value): - return sparse_ops.deserialize_sparse( + ret = sparse_ops.deserialize_sparse( flat_value[0], dtype=self._dtype, rank=self._dense_shape.ndims) + ret.indices.set_shape([None, self._dense_shape.ndims]) + ret.dense_shape.set_shape([self._dense_shape.ndims]) + return ret @staticmethod def from_value(value): diff --git a/tensorflow/python/data/util/structure_test.py b/tensorflow/python/data/util/structure_test.py index 630a0c912b..65a41a50f1 100644 --- a/tensorflow/python/data/util/structure_test.py +++ b/tensorflow/python/data/util/structure_test.py @@ -44,7 +44,7 @@ class StructureTest(test.TestCase, parameterized.TestCase): [dtypes.float32], [[]]), (lambda: sparse_tensor.SparseTensor( indices=[[3, 4]], values=[-1], dense_shape=[4, 5]), - structure.SparseTensorStructure, [dtypes.variant], [[3]]), + structure.SparseTensorStructure, [dtypes.variant], [None]), (lambda: (constant_op.constant(37.0), constant_op.constant([1, 2, 3])), structure.NestedStructure, [dtypes.float32, dtypes.int32], [[], [3]]), (lambda: { @@ -58,14 +58,17 @@ class StructureTest(test.TestCase, parameterized.TestCase): sparse_tensor.SparseTensor( indices=[[3, 4]], values=[-1], dense_shape=[4, 5])) }, structure.NestedStructure, - [dtypes.float32, dtypes.variant, dtypes.variant], [[], [3], [3]])) + [dtypes.float32, dtypes.variant, dtypes.variant], [[], None, None])) def testFlatStructure(self, value_fn, expected_structure, expected_types, expected_shapes): value = value_fn() s = structure.Structure.from_value(value) self.assertIsInstance(s, expected_structure) self.assertEqual(expected_types, s._flat_types) - self.assertEqual(expected_shapes, s._flat_shapes) + for expected, actual in zip(expected_shapes, s._flat_shapes): + self.assertTrue(actual.is_compatible_with(expected)) + self.assertTrue( + tensor_shape.as_shape(expected).is_compatible_with(actual)) @parameterized.parameters( (lambda: constant_op.constant(37.0), lambda: [ -- GitLab From 1799b11347253cd80408d15715fb443c7a1814e9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 09:52:26 -0800 Subject: [PATCH 201/672] Reduce ops v2 API changes PiperOrigin-RevId: 222422608 --- .../python/kernel_tests/monte_carlo_test.py | 2 +- .../bayesflow/python/ops/monte_carlo_impl.py | 4 +- .../boosted_trees/python/utils/losses.py | 3 +- .../normal_conjugate_posteriors_test.py | 2 +- .../python/kernel_tests/wishart_test.py | 5 +- .../python/ops/bijectors/softmax_centered.py | 2 +- tensorflow/contrib/eager/python/tfe_test.py | 4 +- .../contrib/layers/python/layers/encoders.py | 3 +- .../layers/python/layers/feature_column.py | 3 +- .../layers/python/layers/layers_test.py | 4 +- .../estimators/dynamic_rnn_estimator_test.py | 6 +- .../contrib/losses/python/losses/loss_ops.py | 18 +- .../contrib/metrics/python/ops/metric_ops.py | 2 +- .../contrib/quantize/python/quant_ops.py | 8 +- tensorflow/python/eager/backprop_test.py | 2 +- .../python/grappler/cost_analyzer_test.py | 4 +- tensorflow/python/ops/linalg/linalg_impl.py | 2 +- .../python/ops/linalg/linear_operator.py | 2 +- .../ops/linalg/linear_operator_circulant.py | 10 +- .../python/ops/linalg/linear_operator_diag.py | 4 +- .../linalg/linear_operator_low_rank_update.py | 2 +- .../linear_operator_lower_triangular.py | 4 +- tensorflow/python/ops/losses/losses_impl.py | 9 +- tensorflow/python/ops/math_ops.py | 584 +++++++++++++----- tensorflow/python/ops/math_ops_test.py | 4 +- tensorflow/python/ops/metrics_impl.py | 4 +- .../ops/parallel_for/control_flow_ops_test.py | 7 +- tensorflow/python/ops/sparse_grad.py | 2 +- tensorflow/python/ops/special_math_ops.py | 7 +- .../tools/api/golden/v1/tensorflow.math.pbtxt | 4 +- .../tools/api/golden/v2/tensorflow.math.pbtxt | 20 +- .../tools/api/golden/v2/tensorflow.pbtxt | 16 +- .../tools/compatibility/tf_upgrade_v2.py | 154 ++++- 33 files changed, 659 insertions(+), 248 deletions(-) diff --git a/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py b/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py index 13215ffabf..8b6ed9f041 100644 --- a/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py +++ b/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py @@ -81,7 +81,7 @@ class ExpectationImportanceSampleTest(test.TestCase): # Compute E_p[X_1 * X_2 > 0], with X_i the ith component of X ~ p(x). # Should equal 1/2 because p is a spherical Gaussian centered at (0, 0). def indicator(x): - x1_times_x2 = math_ops.reduce_prod(x, reduction_indices=[-1]) + x1_times_x2 = math_ops.reduce_prod(x, axis=[-1]) return 0.5 * (math_ops.sign(x1_times_x2) + 1.0) prob = mc.expectation_importance_sampler( diff --git a/tensorflow/contrib/bayesflow/python/ops/monte_carlo_impl.py b/tensorflow/contrib/bayesflow/python/ops/monte_carlo_impl.py index 18d40fc1df..e83a548511 100644 --- a/tensorflow/contrib/bayesflow/python/ops/monte_carlo_impl.py +++ b/tensorflow/contrib/bayesflow/python/ops/monte_carlo_impl.py @@ -353,12 +353,12 @@ def expectation(f, samples, log_prob=None, use_reparametrization=True, def _sample_mean(values): """Mean over sample indices. In this module this is always [0].""" - return math_ops.reduce_mean(values, reduction_indices=[0]) + return math_ops.reduce_mean(values, axis=[0]) def _sample_max(values): """Max over sample indices. In this module this is always [0].""" - return math_ops.reduce_max(values, reduction_indices=[0]) + return math_ops.reduce_max(values, axis=[0]) def _get_samples(dist, z, n, seed): diff --git a/tensorflow/contrib/boosted_trees/python/utils/losses.py b/tensorflow/contrib/boosted_trees/python/utils/losses.py index 7a99dccdd1..220e981618 100644 --- a/tensorflow/contrib/boosted_trees/python/utils/losses.py +++ b/tensorflow/contrib/boosted_trees/python/utils/losses.py @@ -119,8 +119,7 @@ def per_example_maxent_loss(labels, weights, logits, num_classes, eps=1e-15): labels = array_ops.expand_dims(labels, 1) # Labels are indices of classes, convert them to one hot encodings. target_one_hot = array_ops.one_hot(indices=labels, depth=num_classes) - labels = math_ops.reduce_sum( - input_tensor=target_one_hot, reduction_indices=[1]) + labels = math_ops.reduce_sum(input_tensor=target_one_hot, axis=[1]) labels = math_ops.to_float(labels) # Calculate softmax probabilities for each class. diff --git a/tensorflow/contrib/distributions/python/kernel_tests/normal_conjugate_posteriors_test.py b/tensorflow/contrib/distributions/python/kernel_tests/normal_conjugate_posteriors_test.py index 29eeaf43c5..ab3c07172a 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/normal_conjugate_posteriors_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/normal_conjugate_posteriors_test.py @@ -82,7 +82,7 @@ class NormalTest(test.TestCase): x = constant_op.constant( [[-2.5, 2.5, 4.0, 0.0, -1.0, 2.0], [2.5, -2.5, -4.0, 0.0, 1.0, -2.0]], dtype=dtypes.float32) - s = math_ops.reduce_sum(x, reduction_indices=[1]) + s = math_ops.reduce_sum(x, axis=[1]) x = array_ops.transpose(x) # Reshape to shape (6, 2) n = constant_op.constant([6] * 2) prior = distributions.Normal(loc=mu0, scale=sigma0) diff --git a/tensorflow/contrib/distributions/python/kernel_tests/wishart_test.py b/tensorflow/contrib/distributions/python/kernel_tests/wishart_test.py index a60056c444..cdee30bbc4 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/wishart_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/wishart_test.py @@ -147,14 +147,13 @@ class WishartCholeskyTest(test.TestCase): x = chol_w.sample(10000, seed=42) self.assertAllEqual((10000, 3, 3), x.get_shape()) - moment1_estimate = math_ops.reduce_mean(x, reduction_indices=[0]).eval() + moment1_estimate = math_ops.reduce_mean(x, axis=[0]).eval() self.assertAllClose(chol_w.mean().eval(), moment1_estimate, rtol=0.05) # The Variance estimate uses the squares rather than outer-products # because Wishart.Variance is the diagonal of the Wishart covariance # matrix. - variance_estimate = (math_ops.reduce_mean( - math_ops.square(x), reduction_indices=[0]) - + variance_estimate = (math_ops.reduce_mean(math_ops.square(x), axis=[0]) - math_ops.square(moment1_estimate)).eval() self.assertAllClose( chol_w.variance().eval(), variance_estimate, rtol=0.05) diff --git a/tensorflow/contrib/distributions/python/ops/bijectors/softmax_centered.py b/tensorflow/contrib/distributions/python/ops/bijectors/softmax_centered.py index 15c241d5d7..74765f19e5 100644 --- a/tensorflow/contrib/distributions/python/ops/bijectors/softmax_centered.py +++ b/tensorflow/contrib/distributions/python/ops/bijectors/softmax_centered.py @@ -168,7 +168,7 @@ class SoftmaxCentered(bijector.Bijector): # log_normalization = 1 + reduce_sum(exp(logits)) # -log_normalization + reduce_sum(logits - log_normalization) log_normalization = nn_ops.softplus( - math_ops.reduce_logsumexp(x, axis=-1, keep_dims=True)) + math_ops.reduce_logsumexp(x, axis=-1, keepdims=True)) return array_ops.squeeze( (-log_normalization + math_ops.reduce_sum( x - log_normalization, axis=-1, keepdims=True)), axis=-1) diff --git a/tensorflow/contrib/eager/python/tfe_test.py b/tensorflow/contrib/eager/python/tfe_test.py index 4454abfb96..8c35dddb5a 100644 --- a/tensorflow/contrib/eager/python/tfe_test.py +++ b/tensorflow/contrib/eager/python/tfe_test.py @@ -87,8 +87,8 @@ class TFETest(test_util.TensorFlowTestCase): x += 1. # Without a device context, heuristics are used to place ops. # In this case, ops.reduce_mean runs on the GPU. - reduction_indices = range(x.shape.ndims) - m = math_ops.reduce_mean(x, reduction_indices) + axis = range(x.shape.ndims) + m = math_ops.reduce_mean(x, axis) # m is on GPU, bring it back to CPU and compare. self.assertEqual(3.5, m.cpu().numpy()) diff --git a/tensorflow/contrib/layers/python/layers/encoders.py b/tensorflow/contrib/layers/python/layers/encoders.py index f42112206d..3671633c8d 100644 --- a/tensorflow/contrib/layers/python/layers/encoders.py +++ b/tensorflow/contrib/layers/python/layers/encoders.py @@ -84,8 +84,7 @@ def bow_encoder(ids, if isinstance(ids, sparse_tensor.SparseTensor): raise TypeError('ids are expected to be dense Tensor, got: %s', ids) return math_ops.reduce_mean( - embedding_ops.embedding_lookup(embeddings, ids), - reduction_indices=1) + embedding_ops.embedding_lookup(embeddings, ids), axis=1) def embed_sequence(ids, diff --git a/tensorflow/contrib/layers/python/layers/feature_column.py b/tensorflow/contrib/layers/python/layers/feature_column.py index 222404b19d..00d819ed0e 100644 --- a/tensorflow/contrib/layers/python/layers/feature_column.py +++ b/tensorflow/contrib/layers/python/layers/feature_column.py @@ -1015,8 +1015,7 @@ class _OneHotColumn( dense_id_tensor, depth=self.length, on_value=1.0, off_value=0.0) # Reduce to get a multi-hot per example. - return math_ops.reduce_sum( - one_hot_id_tensor, reduction_indices=[output_rank - 1]) + return math_ops.reduce_sum(one_hot_id_tensor, axis=[output_rank - 1]) @property def _variable_shape(self): diff --git a/tensorflow/contrib/layers/python/layers/layers_test.py b/tensorflow/contrib/layers/python/layers/layers_test.py index 8ead6336a0..0a4d2c6d4c 100644 --- a/tensorflow/contrib/layers/python/layers/layers_test.py +++ b/tensorflow/contrib/layers/python/layers/layers_test.py @@ -3811,7 +3811,7 @@ class UnitNormTests(test.TestCase): image = random_ops.random_uniform((height, width, 3)) output = _layers.unit_norm(image, dim=dim, epsilon=1e-6) norms = math_ops.sqrt( - math_ops.reduce_sum(math_ops.square(output), reduction_indices=dim)) + math_ops.reduce_sum(math_ops.square(output), axis=dim)) shape = [height, width, 3] del shape[dim] @@ -3847,7 +3847,7 @@ class UnitNormTests(test.TestCase): image = array_ops.placeholder(dtypes.float32, (None, None, 3)) output = _layers.unit_norm(image, dim=dim, epsilon=1e-6) norms = math_ops.sqrt( - math_ops.reduce_sum(math_ops.square(output), reduction_indices=dim)) + math_ops.reduce_sum(math_ops.square(output), axis=dim)) with self.cached_session(): actual = norms.eval({image: placeholder_value}) diff --git a/tensorflow/contrib/learn/python/learn/estimators/dynamic_rnn_estimator_test.py b/tensorflow/contrib/learn/python/learn/estimators/dynamic_rnn_estimator_test.py index 1d8a59281a..28c4964527 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/dynamic_rnn_estimator_test.py +++ b/tensorflow/contrib/learn/python/learn/estimators/dynamic_rnn_estimator_test.py @@ -668,7 +668,7 @@ class DynamicRNNEstimatorLearningTest(test.TestCase): sequences = centers + noise inputs = array_ops.expand_dims(sequences, 2) - labels = math_ops.reduce_mean(sequences, reduction_indices=[1]) + labels = math_ops.reduce_mean(sequences, axis=[1]) return {'inputs': inputs}, labels return input_fn @@ -722,8 +722,8 @@ class DynamicRNNEstimatorLearningTest(test.TestCase): inputs = array_ops.expand_dims(math_ops.to_float(random_sequence), 2) labels = math_ops.to_int32( array_ops.squeeze( - math_ops.reduce_sum( - inputs, reduction_indices=[1]) > (sequence_length / 2.0))) + math_ops.reduce_sum(inputs, axis=[1]) > ( + sequence_length / 2.0))) return {'inputs': inputs}, labels return input_fn diff --git a/tensorflow/contrib/losses/python/losses/loss_ops.py b/tensorflow/contrib/losses/python/losses/loss_ops.py index d8ac4163b2..709a042bbc 100644 --- a/tensorflow/contrib/losses/python/losses/loss_ops.py +++ b/tensorflow/contrib/losses/python/losses/loss_ops.py @@ -59,9 +59,8 @@ def _scale_losses(losses, weights): """ # First, compute the sum of the losses over all elements: start_index = max(0, weights.get_shape().ndims) - reduction_indices = list(range(start_index, losses.get_shape().ndims)) - reduced_losses = math_ops.reduce_sum( - losses, reduction_indices=reduction_indices) + axis = list(range(start_index, losses.get_shape().ndims)) + reduced_losses = math_ops.reduce_sum(losses, axis=axis) reduced_losses = math_ops.multiply(reduced_losses, weights) return math_ops.reduce_sum(reduced_losses) @@ -158,10 +157,9 @@ def _num_present(losses, weights, per_batch=False): # First, count the number of nonzero weights: if weights.get_shape().ndims >= 1: - reduction_indices = list(range(1, weights.get_shape().ndims)) + axis = list(range(1, weights.get_shape().ndims)) num_nonzero_per_batch = math_ops.reduce_sum( - math_ops.to_float(math_ops.not_equal(weights, 0)), - reduction_indices=reduction_indices) + math_ops.to_float(math_ops.not_equal(weights, 0)), axis=axis) # Next, determine the number of elements that weights would broadcast to: broadcast_dims = array_ops.slice( @@ -577,16 +575,16 @@ def mean_pairwise_squared_error(predictions, if weights.get_shape().ndims is None: raise ValueError("weights.get_shape().ndims cannot be None") - reduction_indices = list(range(1, diffs.get_shape().ndims)) + axis = list(range(1, diffs.get_shape().ndims)) sum_squares_diff_per_batch = math_ops.reduce_sum( - math_ops.square(diffs), reduction_indices=reduction_indices) + math_ops.square(diffs), axis=axis) num_present_per_batch = _num_present(diffs, weights, per_batch=True) term1 = 2.0 * math_ops.div_no_nan( sum_squares_diff_per_batch, num_present_per_batch, name="value") - sum_diff = math_ops.reduce_sum(diffs, reduction_indices=reduction_indices) + sum_diff = math_ops.reduce_sum(diffs, axis=axis) term2 = 2.0 * math_ops.div_no_nan( math_ops.square(sum_diff), math_ops.square(num_present_per_batch), @@ -645,7 +643,7 @@ def cosine_distance(predictions, radial_diffs = math_ops.multiply(predictions, labels) losses = 1 - math_ops.reduce_sum( - radial_diffs, reduction_indices=[ + radial_diffs, axis=[ axis, ]) return compute_weighted_loss(losses, weights, scope=scope) diff --git a/tensorflow/contrib/metrics/python/ops/metric_ops.py b/tensorflow/contrib/metrics/python/ops/metric_ops.py index 09fe65b73f..7b432f8bd2 100644 --- a/tensorflow/contrib/metrics/python/ops/metric_ops.py +++ b/tensorflow/contrib/metrics/python/ops/metric_ops.py @@ -3416,7 +3416,7 @@ def streaming_mean_cosine_distance(predictions, predictions.get_shape().assert_is_compatible_with(labels.get_shape()) radial_diffs = math_ops.multiply(predictions, labels) radial_diffs = math_ops.reduce_sum( - radial_diffs, reduction_indices=[ + radial_diffs, axis=[ dim, ], keepdims=True) mean_distance, update_op = streaming_mean(radial_diffs, weights, None, None, diff --git a/tensorflow/contrib/quantize/python/quant_ops.py b/tensorflow/contrib/quantize/python/quant_ops.py index 6f659347fb..8619708cda 100644 --- a/tensorflow/contrib/quantize/python/quant_ops.py +++ b/tensorflow/contrib/quantize/python/quant_ops.py @@ -138,7 +138,7 @@ def LastValueQuantize(inputs, if per_channel: if input_dim >= 2: batch_min = math_ops.reduce_min( - inputs, reduction_indices=reduce_dims, name='BatchMin') + inputs, axis=reduce_dims, name='BatchMin') else: batch_min = inputs else: @@ -147,7 +147,7 @@ def LastValueQuantize(inputs, if per_channel: if input_dim >= 2: batch_max = math_ops.reduce_max( - inputs, reduction_indices=reduce_dims, name='BatchMax') + inputs, axis=reduce_dims, name='BatchMax') else: batch_max = inputs else: @@ -263,7 +263,7 @@ def MovingAvgQuantize(inputs, if per_channel: if input_dim >= 2: batch_min = math_ops.reduce_min( - inputs, reduction_indices=reduce_dims, name='BatchMin') + inputs, axis=reduce_dims, name='BatchMin') else: batch_min = inputs else: @@ -272,7 +272,7 @@ def MovingAvgQuantize(inputs, if per_channel: if input_dim >= 2: batch_max = math_ops.reduce_max( - inputs, reduction_indices=reduce_dims, name='BatchMax') + inputs, axis=reduce_dims, name='BatchMax') else: batch_max = inputs else: diff --git a/tensorflow/python/eager/backprop_test.py b/tensorflow/python/eager/backprop_test.py index 237b7f304e..8b85548e5c 100644 --- a/tensorflow/python/eager/backprop_test.py +++ b/tensorflow/python/eager/backprop_test.py @@ -74,7 +74,7 @@ class BackpropTest(test.TestCase): tf_g1 = embedding_ops.embedding_lookup(tf_var, tf_ind1) tf_g2 = embedding_ops.embedding_lookup(tf_var, tf_ind2) tf_g3 = embedding_ops.embedding_lookup(tf_var, tf_ind3) - tf_g4 = math_ops.reduce_sum(tf_var * 2.0, reduction_indices=(0, 1)) + tf_g4 = math_ops.reduce_sum(tf_var * 2.0, axis=(0, 1)) tf_y = tf_g1 * tf_g2 * tf_g3 * tf_g4 tf_grad = gradients.gradients(tf_y, [tf_var])[0] diff --git a/tensorflow/python/grappler/cost_analyzer_test.py b/tensorflow/python/grappler/cost_analyzer_test.py index b8225b81a5..de80df1879 100644 --- a/tensorflow/python/grappler/cost_analyzer_test.py +++ b/tensorflow/python/grappler/cost_analyzer_test.py @@ -96,8 +96,8 @@ class CostAnalysisTest(test.TestCase): b_fc = variables.Variable(random_ops.truncated_normal([10], stddev=0.1)) y_conv = nn_ops.softmax(math_ops.matmul(h_conv_flat, w_fc) + b_fc) - cross_entropy = math_ops.reduce_mean(-math_ops.reduce_sum( - label * math_ops.log(y_conv), reduction_indices=[1])) + cross_entropy = math_ops.reduce_mean( + -math_ops.reduce_sum(label * math_ops.log(y_conv), axis=[1])) _ = adam.AdamOptimizer(1e-4).minimize(cross_entropy) mg = meta_graph.create_meta_graph_def(graph=ops.get_default_graph()) diff --git a/tensorflow/python/ops/linalg/linalg_impl.py b/tensorflow/python/ops/linalg/linalg_impl.py index 08d50ce622..2c9476a9bd 100644 --- a/tensorflow/python/ops/linalg/linalg_impl.py +++ b/tensorflow/python/ops/linalg/linalg_impl.py @@ -88,7 +88,7 @@ def logdet(matrix, name=None): chol = gen_linalg_ops.cholesky(matrix) return 2.0 * math_ops.reduce_sum( math_ops.log(math_ops.real(array_ops.matrix_diag_part(chol))), - reduction_indices=[-1]) + axis=[-1]) @tf_export('linalg.adjoint') diff --git a/tensorflow/python/ops/linalg/linear_operator.py b/tensorflow/python/ops/linalg/linear_operator.py index 6fb7a57e4d..8efafda3a1 100644 --- a/tensorflow/python/ops/linalg/linear_operator.py +++ b/tensorflow/python/ops/linalg/linear_operator.py @@ -690,7 +690,7 @@ class LinearOperator(object): " Requires conversion to a dense matrix and O(N^3) operations.") if self._can_use_cholesky(): diag = array_ops.matrix_diag_part(linalg_ops.cholesky(self.to_dense())) - return 2 * math_ops.reduce_sum(math_ops.log(diag), reduction_indices=[-1]) + return 2 * math_ops.reduce_sum(math_ops.log(diag), axis=[-1]) _, log_abs_det = linalg.slogdet(self.to_dense()) return log_abs_det diff --git a/tensorflow/python/ops/linalg/linear_operator_circulant.py b/tensorflow/python/ops/linalg/linear_operator_circulant.py index 09f0c518e7..b74baa5dfd 100644 --- a/tensorflow/python/ops/linalg/linear_operator_circulant.py +++ b/tensorflow/python/ops/linalg/linear_operator_circulant.py @@ -418,15 +418,13 @@ class _BaseLinearOperatorCirculant(linear_operator.LinearOperator): return math_ops.cast(y, self.dtype) def _determinant(self): - reduction_indices = [-(i + 1) for i in range(self.block_depth)] - det = math_ops.reduce_prod( - self.spectrum, reduction_indices=reduction_indices) + axis = [-(i + 1) for i in range(self.block_depth)] + det = math_ops.reduce_prod(self.spectrum, axis=axis) return math_ops.cast(det, self.dtype) def _log_abs_determinant(self): - reduction_indices = [-(i + 1) for i in range(self.block_depth)] - lad = math_ops.reduce_sum( - math_ops.log(self._abs_spectrum), reduction_indices=reduction_indices) + axis = [-(i + 1) for i in range(self.block_depth)] + lad = math_ops.reduce_sum(math_ops.log(self._abs_spectrum), axis=axis) return math_ops.cast(lad, self.dtype) def _solve(self, rhs, adjoint=False, adjoint_arg=False): diff --git a/tensorflow/python/ops/linalg/linear_operator_diag.py b/tensorflow/python/ops/linalg/linear_operator_diag.py index ed53decc00..be893c705c 100644 --- a/tensorflow/python/ops/linalg/linear_operator_diag.py +++ b/tensorflow/python/ops/linalg/linear_operator_diag.py @@ -228,11 +228,11 @@ class LinearOperatorDiag(linear_operator.LinearOperator): return diag_mat * x def _determinant(self): - return math_ops.reduce_prod(self._diag, reduction_indices=[-1]) + return math_ops.reduce_prod(self._diag, axis=[-1]) def _log_abs_determinant(self): log_det = math_ops.reduce_sum( - math_ops.log(math_ops.abs(self._diag)), reduction_indices=[-1]) + math_ops.log(math_ops.abs(self._diag)), axis=[-1]) if self.dtype.is_complex: log_det = math_ops.cast(log_det, dtype=self.dtype) return log_det diff --git a/tensorflow/python/ops/linalg/linear_operator_low_rank_update.py b/tensorflow/python/ops/linalg/linear_operator_low_rank_update.py index c4288ff8f8..aa0500aff0 100644 --- a/tensorflow/python/ops/linalg/linear_operator_low_rank_update.py +++ b/tensorflow/python/ops/linalg/linear_operator_low_rank_update.py @@ -391,7 +391,7 @@ class LinearOperatorLowRankUpdate(linear_operator.LinearOperator): if self._use_cholesky: chol_cap_diag = array_ops.matrix_diag_part(self._chol_capacitance) log_abs_det_c = 2 * math_ops.reduce_sum( - math_ops.log(chol_cap_diag), reduction_indices=[-1]) + math_ops.log(chol_cap_diag), axis=[-1]) else: det_c = linalg_ops.matrix_determinant(self._capacitance) log_abs_det_c = math_ops.log(math_ops.abs(det_c)) diff --git a/tensorflow/python/ops/linalg/linear_operator_lower_triangular.py b/tensorflow/python/ops/linalg/linear_operator_lower_triangular.py index ca6d3f5405..d33fe17e04 100644 --- a/tensorflow/python/ops/linalg/linear_operator_lower_triangular.py +++ b/tensorflow/python/ops/linalg/linear_operator_lower_triangular.py @@ -195,11 +195,11 @@ class LinearOperatorLowerTriangular(linear_operator.LinearOperator): self._tril, x, adjoint_a=adjoint, adjoint_b=adjoint_arg) def _determinant(self): - return math_ops.reduce_prod(self._diag, reduction_indices=[-1]) + return math_ops.reduce_prod(self._diag, axis=[-1]) def _log_abs_determinant(self): return math_ops.reduce_sum( - math_ops.log(math_ops.abs(self._diag)), reduction_indices=[-1]) + math_ops.log(math_ops.abs(self._diag)), axis=[-1]) def _solve(self, rhs, adjoint=False, adjoint_arg=False): rhs = linalg.adjoint(rhs) if adjoint_arg else rhs diff --git a/tensorflow/python/ops/losses/losses_impl.py b/tensorflow/python/ops/losses/losses_impl.py index e8cadf931b..0a5b511f82 100644 --- a/tensorflow/python/ops/losses/losses_impl.py +++ b/tensorflow/python/ops/losses/losses_impl.py @@ -583,12 +583,10 @@ def mean_pairwise_squared_error( diffs = math_ops.subtract(predictions, labels) - reduction_indices = math_ops.range(1, array_ops.rank(diffs)) + axis = math_ops.range(1, array_ops.rank(diffs)) sum_squares_diff_per_batch = math_ops.reduce_sum( - math_ops.square(diffs), - reduction_indices=reduction_indices, - keepdims=True) + math_ops.square(diffs), axis=axis, keepdims=True) num_present_per_batch = _num_present(diffs, weights, per_batch=True) term1 = 2.0 * math_ops.div_no_nan( @@ -596,8 +594,7 @@ def mean_pairwise_squared_error( math_ops.maximum(num_present_per_batch - 1, 0), name="value") - sum_diff = math_ops.reduce_sum( - diffs, reduction_indices=reduction_indices, keepdims=True) + sum_diff = math_ops.reduce_sum(diffs, axis=axis, keepdims=True) term2 = 2.0 * math_ops.div_no_nan( math_ops.square(sum_diff), math_ops.maximum( diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index 952a2a1e79..73ca3d527a 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -1314,7 +1314,7 @@ def range(start, limit=None, delta=1, dtype=None, name="range"): # pylint: disa # Reduction operations -def _ReductionDims(x, axis, reduction_indices): +def _ReductionDims(x, axis, reduction_indices=None): # pylint: disable=invalid-name """Returns range(0, rank(x)) if reduction_indices is None.""" # TODO(aselle): Remove this after deprecation if reduction_indices is not None: @@ -1337,23 +1337,23 @@ def _ReductionDims(x, axis, reduction_indices): return range(0, array_ops.rank(x)) -def _may_reduce_to_scalar(keepdims, axis, reduction_indices, output): +def _may_reduce_to_scalar(keepdims, axis, output): """Set a reduction's output shape to be a scalar if we are certain.""" if not common_shapes.has_fully_defined_shape(output) and (not keepdims) and ( - axis is None) and (reduction_indices is None): + axis is None): output.set_shape(()) return output -@tf_export("math.reduce_sum", "reduce_sum") +@tf_export(v1=["math.reduce_sum", "reduce_sum"]) @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_sum(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +def reduce_sum_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes the sum of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1393,18 +1393,58 @@ def reduce_sum(input_tensor, int64 while tensorflow returns the same dtype as the input. @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) - if keepdims is None: - keepdims = False + return reduce_sum(input_tensor, axis, keepdims, name) + - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops._sum( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) +@tf_export("math.reduce_sum", "reduce_sum", v1=[]) +def reduce_sum(input_tensor, axis=None, keepdims=False, name=None): + """Computes the sum of elements across dimensions of a tensor. + + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. + + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. + + For example: + + ```python + x = tf.constant([[1, 1, 1], [1, 1, 1]]) + tf.reduce_sum(x) # 6 + tf.reduce_sum(x, 0) # [2, 2, 2] + tf.reduce_sum(x, 1) # [3, 3] + tf.reduce_sum(x, 1, keepdims=True) # [[3], [3]] + tf.reduce_sum(x, [0, 1]) # 6 + ``` + + Args: + input_tensor: The tensor to reduce. Should have numeric type. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor, of the same dtype as the input_tensor. + + @compatibility(numpy) + Equivalent to np.sum apart the fact that numpy upcast uint8 and int32 to + int64 while tensorflow returns the same dtype as the input. + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops._sum( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) @tf_export(v1=["math.count_nonzero", "count_nonzero"]) @@ -1544,15 +1584,13 @@ def count_nonzero_v2(input, # pylint: disable=redefined-builtin dtype=dtype) -@tf_export("math.reduce_mean", "reduce_mean") -@deprecation.deprecated_args( - None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_mean(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +@tf_export(v1=["math.reduce_mean", "reduce_mean"]) +def reduce_mean_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes the mean of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1602,22 +1640,72 @@ def reduce_mean(input_tensor, @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) + return reduce_mean(input_tensor, axis, keepdims, name) - if keepdims is None: - keepdims = False - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops.mean( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) + +@tf_export("math.reduce_mean", "reduce_mean", v1=[]) +def reduce_mean(input_tensor, axis=None, keepdims=False, name=None): + """Computes the mean of elements across dimensions of a tensor. + + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. + + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. + + For example: + + ```python + x = tf.constant([[1., 1.], [2., 2.]]) + tf.reduce_mean(x) # 1.5 + tf.reduce_mean(x, 0) # [1.5, 1.5] + tf.reduce_mean(x, 1) # [1., 2.] + ``` + + Args: + input_tensor: The tensor to reduce. Should have numeric type. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + + @compatibility(numpy) + Equivalent to np.mean + + Please note that `np.mean` has a `dtype` parameter that could be used to + specify the output type. By default this is `dtype=float64`. On the other + hand, `tf.reduce_mean` has an aggressive type inference from `input_tensor`, + for example: + + ```python + x = tf.constant([1, 0, 1, 0]) + tf.reduce_mean(x) # 0 + y = tf.constant([1., 0., 1., 0.]) + tf.reduce_mean(y) # 0.5 + ``` + + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops.mean( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) @tf_export("math.reduce_variance") -def reduce_variance(input_tensor, axis=None, keepdims=None, name=None): +def reduce_variance(input_tensor, axis=None, keepdims=False, name=None): """Computes the variance of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1665,7 +1753,7 @@ def reduce_variance(input_tensor, axis=None, keepdims=None, name=None): @tf_export("math.reduce_std") -def reduce_std(input_tensor, axis=None, keepdims=None, name=None): +def reduce_std(input_tensor, axis=None, keepdims=False, name=None): """Computes the standard deviation of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1710,15 +1798,8 @@ def reduce_std(input_tensor, axis=None, keepdims=None, name=None): return sqrt(variance) -@tf_export("math.reduce_prod", "reduce_prod") -@deprecation.deprecated_args( - None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_prod(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +@tf_export("math.reduce_prod", "reduce_prod", v1=[]) +def reduce_prod(input_tensor, axis=None, keepdims=False, name=None): """Computes the product of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1736,6 +1817,48 @@ def reduce_prod(input_tensor, `[-rank(input_tensor), rank(input_tensor))`. keepdims: If true, retains reduced dimensions with length 1. name: A name for the operation (optional). + + Returns: + The reduced tensor. + + @compatibility(numpy) + Equivalent to np.prod + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops.prod( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) + + +@tf_export(v1=["math.reduce_prod", "reduce_prod"]) +@deprecation.deprecated_args( + None, "keep_dims is deprecated, use keepdims instead", "keep_dims") +def reduce_prod_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): + """Computes the product of elements across dimensions of a tensor. + + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. + + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. + + Args: + input_tensor: The tensor to reduce. Should have numeric type. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). reduction_indices: The old (deprecated) name for axis. keep_dims: Deprecated alias for `keepdims`. @@ -1746,29 +1869,22 @@ def reduce_prod(input_tensor, Equivalent to np.prod @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) + return reduce_prod(input_tensor, axis, keepdims, name) - if keepdims is None: - keepdims = False - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops.prod( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) - -@tf_export("math.reduce_min", "reduce_min") +@tf_export(v1=["math.reduce_min", "reduce_min"]) @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_min(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +def reduce_min_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes the minimum of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1781,9 +1897,9 @@ def reduce_min(input_tensor, Args: input_tensor: The tensor to reduce. Should have real numeric type. - axis: The dimensions to reduce. If `None` (the default), - reduces all dimensions. Must be in the range - `[-rank(input_tensor), rank(input_tensor))`. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. keepdims: If true, retains reduced dimensions with length 1. name: A name for the operation (optional). reduction_indices: The old (deprecated) name for axis. @@ -1796,28 +1912,57 @@ def reduce_min(input_tensor, Equivalent to np.min @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) - if keepdims is None: - keepdims = False - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops._min( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) + return reduce_min(input_tensor, axis, keepdims, name) + + +@tf_export("math.reduce_min", "reduce_min", v1=[]) +def reduce_min(input_tensor, axis=None, keepdims=False, name=None): + """Computes the minimum of elements across dimensions of a tensor. + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. + + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. -@tf_export("math.reduce_max", "reduce_max") + Args: + input_tensor: The tensor to reduce. Should have real numeric type. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + + @compatibility(numpy) + Equivalent to np.min + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops._min( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) + + +@tf_export(v1=["math.reduce_max", "reduce_max"]) @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_max(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +def reduce_max_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes the maximum of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1845,28 +1990,57 @@ def reduce_max(input_tensor, Equivalent to np.max @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) - if keepdims is None: - keepdims = False - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops._max( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) + return reduce_max(input_tensor, axis, keepdims, name) + + +@tf_export("math.reduce_max", "reduce_max", v1=[]) +def reduce_max(input_tensor, axis=None, keepdims=False, name=None): + """Computes the maximum of elements across dimensions of a tensor. + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. -@tf_export("math.reduce_all", "reduce_all") + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. + + Args: + input_tensor: The tensor to reduce. Should have real numeric type. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + + @compatibility(numpy) + Equivalent to np.max + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops._max( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) + + +@tf_export(v1=["math.reduce_all", "reduce_all"]) @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_all(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +def reduce_all_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes the "logical and" of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1888,9 +2062,9 @@ def reduce_all(input_tensor, Args: input_tensor: The boolean tensor to reduce. - axis: The dimensions to reduce. If `None` (the default), - reduces all dimensions. Must be in the range - `[-rank(input_tensor), rank(input_tensor))`. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. keepdims: If true, retains reduced dimensions with length 1. name: A name for the operation (optional). reduction_indices: The old (deprecated) name for axis. @@ -1903,28 +2077,66 @@ def reduce_all(input_tensor, Equivalent to np.all @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) - if keepdims is None: - keepdims = False - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops._all( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) + return reduce_all(input_tensor, axis, keepdims, name) + +@tf_export("reduce_all", "math.reduce_all", v1=[]) +def reduce_all(input_tensor, axis=None, keepdims=False, name=None): + """Computes the "logical and" of elements across dimensions of a tensor. + + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. -@tf_export("math.reduce_any", "reduce_any") + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. + + For example: + + ```python + x = tf.constant([[True, True], [False, False]]) + tf.reduce_all(x) # False + tf.reduce_all(x, 0) # [False, False] + tf.reduce_all(x, 1) # [True, False] + ``` + + Args: + input_tensor: The boolean tensor to reduce. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + + @compatibility(numpy) + Equivalent to np.all + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops._all( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) + + +@tf_export(v1=["math.reduce_any", "reduce_any"]) @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_any(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +def reduce_any_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes the "logical or" of elements across dimensions of a tensor. Reduces `input_tensor` along the dimensions given in `axis`. @@ -1946,9 +2158,9 @@ def reduce_any(input_tensor, Args: input_tensor: The boolean tensor to reduce. - axis: The dimensions to reduce. If `None` (the default), - reduces all dimensions. Must be in the range - `[-rank(input_tensor), rank(input_tensor))`. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. keepdims: If true, retains reduced dimensions with length 1. name: A name for the operation (optional). reduction_indices: The old (deprecated) name for axis. @@ -1961,28 +2173,66 @@ def reduce_any(input_tensor, Equivalent to np.any @end_compatibility """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) - if keepdims is None: - keepdims = False - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, - gen_math_ops._any( - input_tensor, - _ReductionDims(input_tensor, axis, - reduction_indices), - keepdims, - name=name)) + return reduce_any(input_tensor, axis, keepdims, name) + + +@tf_export("math.reduce_any", "reduce_any", v1=[]) +def reduce_any(input_tensor, axis=None, keepdims=False, name=None): + """Computes the "logical or" of elements across dimensions of a tensor. + + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. + If `axis` is None, all dimensions are reduced, and a + tensor with a single element is returned. + + For example: + + ```python + x = tf.constant([[True, True], [False, False]]) + tf.reduce_any(x) # True + tf.reduce_any(x, 0) # [True, True] + tf.reduce_any(x, 1) # [True, False] + ``` -@tf_export("math.reduce_logsumexp", "reduce_logsumexp") + Args: + input_tensor: The boolean tensor to reduce. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + + @compatibility(numpy) + Equivalent to np.any + @end_compatibility + """ + keepdims = False if keepdims is None else keepdims + return _may_reduce_to_scalar( + keepdims, axis, + gen_math_ops._any( + input_tensor, _ReductionDims(input_tensor, axis), keepdims, + name=name)) + + +@tf_export(v1=["math.reduce_logsumexp", "reduce_logsumexp"]) @deprecation.deprecated_args( None, "keep_dims is deprecated, use keepdims instead", "keep_dims") -def reduce_logsumexp(input_tensor, - axis=None, - keepdims=None, - name=None, - reduction_indices=None, - keep_dims=None): +def reduce_logsumexp_v1(input_tensor, + axis=None, + keepdims=None, + name=None, + reduction_indices=None, + keep_dims=None): """Computes log(sum(exp(elements across dimensions of a tensor))). Reduces `input_tensor` along the dimensions given in `axis`. @@ -2010,9 +2260,9 @@ def reduce_logsumexp(input_tensor, Args: input_tensor: The tensor to reduce. Should have numeric type. - axis: The dimensions to reduce. If `None` (the default), - reduces all dimensions. Must be in the range - `[-rank(input_tensor), rank(input_tensor))`. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. keepdims: If true, retains reduced dimensions with length 1. name: A name for the operation (optional). reduction_indices: The old (deprecated) name for axis. @@ -2021,16 +2271,57 @@ def reduce_logsumexp(input_tensor, Returns: The reduced tensor. """ + axis = deprecation.deprecated_argument_lookup( + "axis", axis, "reduction_indices", reduction_indices) keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, "keep_dims", keep_dims) - if keepdims is None: - keepdims = False + return reduce_logsumexp(input_tensor, axis, keepdims, name) + + +@tf_export("math.reduce_logsumexp", "reduce_logsumexp", v1=[]) +def reduce_logsumexp(input_tensor, axis=None, keepdims=False, name=None): + """Computes log(sum(exp(elements across dimensions of a tensor))). + + Reduces `input_tensor` along the dimensions given in `axis`. + Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each + entry in `axis`. If `keepdims` is true, the reduced dimensions + are retained with length 1. + + If `axis` has no entries, all dimensions are reduced, and a + tensor with a single element is returned. + + This function is more numerically stable than log(sum(exp(input))). It avoids + overflows caused by taking the exp of large inputs and underflows caused by + taking the log of small inputs. + + For example: + + ```python + x = tf.constant([[0., 0., 0.], [0., 0., 0.]]) + tf.reduce_logsumexp(x) # log(6) + tf.reduce_logsumexp(x, 0) # [log(2), log(2), log(2)] + tf.reduce_logsumexp(x, 1) # [log(3), log(3)] + tf.reduce_logsumexp(x, 1, keepdims=True) # [[log(3)], [log(3)]] + tf.reduce_logsumexp(x, [0, 1]) # log(6) + ``` + + Args: + input_tensor: The tensor to reduce. Should have numeric type. + axis: The dimensions to reduce. If `None` (the default), reduces all + dimensions. Must be in the range `[-rank(input_tensor), + rank(input_tensor))`. + keepdims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + """ + keepdims = False if keepdims is None else keepdims input_tensor = ops.convert_to_tensor(input_tensor) with ops.name_scope(name, "ReduceLogSumExp", [input_tensor]) as name: raw_max = reduce_max( input_tensor, axis=axis, - reduction_indices=reduction_indices, keepdims=True) my_max = array_ops.stop_gradient( array_ops.where( @@ -2040,12 +2331,11 @@ def reduce_logsumexp(input_tensor, reduce_sum( gen_math_ops.exp(gen_math_ops.sub(input_tensor, my_max)), axis, - keepdims=keepdims, - reduction_indices=reduction_indices)) + keepdims=keepdims)) if not keepdims: my_max = array_ops.reshape(my_max, array_ops.shape(result)) result = gen_math_ops.add(result, my_max) - return _may_reduce_to_scalar(keepdims, axis, reduction_indices, result) + return _may_reduce_to_scalar(keepdims, axis, result) @tf_export("linalg.trace", v1=["linalg.trace", "trace"]) diff --git a/tensorflow/python/ops/math_ops_test.py b/tensorflow/python/ops/math_ops_test.py index e0329f66ff..cd45b6f136 100644 --- a/tensorflow/python/ops/math_ops_test.py +++ b/tensorflow/python/ops/math_ops_test.py @@ -104,7 +104,7 @@ class LogSumExpTest(test_util.TensorFlowTestCase): for dtype in [np.float16, np.float32, np.double]: x_np = np.random.rand(5, 5).astype(dtype) with self.cached_session(use_gpu=True): - y_tf = math_ops.reduce_logsumexp(x_np, reduction_indices=[0]) + y_tf = math_ops.reduce_logsumexp(x_np, axis=[0]) y_np = log(np.sum(exp(x_np), axis=0)) self.assertShapeEqual(y_np, y_tf) y_tf_np = self.evaluate(y_tf) @@ -114,7 +114,7 @@ class LogSumExpTest(test_util.TensorFlowTestCase): for dtype in [np.float16, np.float32, np.double]: x_np = np.random.rand(5, 5).astype(dtype) with self.cached_session(use_gpu=True): - y_tf = math_ops.reduce_logsumexp(x_np, reduction_indices=0) + y_tf = math_ops.reduce_logsumexp(x_np, axis=0) y_np = log(np.sum(exp(x_np), axis=0)) self.assertShapeEqual(y_np, y_tf) y_tf_np = self.evaluate(y_tf) diff --git a/tensorflow/python/ops/metrics_impl.py b/tensorflow/python/ops/metrics_impl.py index 0b91b8dde8..27269c51c1 100644 --- a/tensorflow/python/ops/metrics_impl.py +++ b/tensorflow/python/ops/metrics_impl.py @@ -948,7 +948,7 @@ def mean_cosine_distance(labels, predictions=predictions, labels=labels, weights=weights) radial_diffs = math_ops.multiply(predictions, labels) radial_diffs = math_ops.reduce_sum( - radial_diffs, reduction_indices=[ + radial_diffs, axis=[ dim, ], keepdims=True) mean_distance, update_op = mean(radial_diffs, weights, None, None, name or @@ -3045,7 +3045,7 @@ def _sparse_average_precision_at_top_k(labels, predictions_idx): # Reduce along k dimension to get the sum, yielding a [D1, ... DN] tensor. precision_sum = math_ops.reduce_sum( - relevant_precision_per_k, reduction_indices=(-1,), name='precision_sum') + relevant_precision_per_k, axis=(-1,), name='precision_sum') # Divide by number of relevant items to get average precision. These are # the "num_relevant_items" and "AveP" terms from the formula above. diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py index 4470c0b958..72db0952b4 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py @@ -1324,13 +1324,12 @@ class ControlFlowTest(PForTest): pfor_out, pfor_out_grad = pfor_control_flow_ops.pfor(loop_fn, 4) # Note that tf.while_loop does not work in the setup above. So we manually # construct the equivalent computation of the above loops here. - real_out = math_ops.reduce_sum(inp, reduction_indices=[0]) - real_out = math_ops.reduce_prod(real_out, reduction_indices=[1]) + real_out = math_ops.reduce_sum(inp, axis=[0]) + real_out = math_ops.reduce_prod(real_out, axis=[1]) # Note that gradients of real_out will accumulate the gradients across the # output value. Hence we do the same aggregation on pfor_out_grad. real_out_grad = gradient_ops.gradients(real_out, inp)[0] - sum_pfor_out_grad = math_ops.reduce_sum( - pfor_out_grad, reduction_indices=[0]) + sum_pfor_out_grad = math_ops.reduce_sum(pfor_out_grad, axis=[0]) with session.Session() as sess: v1, v2, v1_grad, v2_grad = sess.run( diff --git a/tensorflow/python/ops/sparse_grad.py b/tensorflow/python/ops/sparse_grad.py index 1223b290ff..2ca9c0c647 100644 --- a/tensorflow/python/ops/sparse_grad.py +++ b/tensorflow/python/ops/sparse_grad.py @@ -195,7 +195,7 @@ def _SparseTensorDenseMatMulGrad(op, grad): parts_a = array_ops.gather(grad, rows if not adj_a else cols) parts_b = array_ops.gather(b if not adj_b else array_ops.transpose(b), cols if not adj_a else rows) - a_values_grad = math_ops.reduce_sum(parts_a * parts_b, reduction_indices=1) + a_values_grad = math_ops.reduce_sum(parts_a * parts_b, axis=1) # gradients w.r.t. (a_indices, a_values, a_shape, b) return (None, a_values_grad, None, b_grad) diff --git a/tensorflow/python/ops/special_math_ops.py b/tensorflow/python/ops/special_math_ops.py index f44f694109..21f4996798 100644 --- a/tensorflow/python/ops/special_math_ops.py +++ b/tensorflow/python/ops/special_math_ops.py @@ -70,8 +70,7 @@ def lbeta(x, name=None): x = ops.convert_to_tensor(x, name='x') # Note reduce_sum([]) = 0. - log_prod_gamma_x = math_ops.reduce_sum( - math_ops.lgamma(x), reduction_indices=[-1]) + log_prod_gamma_x = math_ops.reduce_sum(math_ops.lgamma(x), axis=[-1]) # Note lgamma(0) = infinity, so if x = [] # log_gamma_sum_x = lgamma(0) = infinity, and @@ -264,11 +263,11 @@ def einsum(equation, *inputs, **kwargs): missing_indices = set(temp_axis_labels) - set(output_axis_labels) if missing_indices: - reduction_indices = [ + axis = [ i for i, a in enumerate(temp_axis_labels) if a not in output_axis_labels ] - temp = math_ops.reduce_sum(temp, reduction_indices=reduction_indices) + temp = math_ops.reduce_sum(temp, axis=axis) temp_axis_labels = ''.join( a for a in temp_axis_labels if a in output_axis_labels) diff --git a/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt index 67f348be21..b7a99caeb7 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt @@ -318,7 +318,7 @@ tf_module { } member_method { name: "reduce_std" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_sum" @@ -326,7 +326,7 @@ tf_module { } member_method { name: "reduce_variance" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "rint" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt index 86df970514..5215cfbab0 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt @@ -290,43 +290,43 @@ tf_module { } member_method { name: "reduce_all" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_any" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_logsumexp" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_max" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_mean" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_min" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_prod" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_std" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_sum" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_variance" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "rint" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 0649ae267b..873c41a390 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -898,35 +898,35 @@ tf_module { } member_method { name: "reduce_all" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_any" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_logsumexp" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_max" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_mean" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_min" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_prod" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "reduce_sum" - argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\', \'reduction_indices\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\'], " + argspec: "args=[\'input_tensor\', \'axis\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "register_tensor_conversion_function" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index f85b2f08dc..aab7aa8af5 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -73,6 +73,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "t": "x", "msg": "message", }, + "tf.sparse.add": ["a", "b", "thresh"], "tf.sparse.split": { "split_dim": "axis", }, @@ -113,6 +114,73 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.random.stateless_multinomial": { "output_dtype": "dtype", }, + "tf.sparse.concat": [ + "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" + ], + "tf.reduce_all": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_all": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_any": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_any": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_min": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_min": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_max": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_max": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_sum": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_sum": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_mean": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_mean": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_prod": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_prod": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.reduce_logsumexp": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, + "tf.math.reduce_logsumexp": { + "reduction_indices": "axis", + "keep_dims": "keepdims", + }, } # Mapping from function to the new name of the function @@ -199,7 +267,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.convert_to_tensor": ["value", "dtype", "name", "preferred_dtype"], "tf.nn.convolution": [ "input", "filter", "padding", "strides", "dilation_rate", "name", - "data_format"], + "data_format" + ], "tf.nn.crelu": ["features", "name", "axis"], "tf.nn.pool": [ "input", "window_shape", "pooling_type", "padding", "dilation_rate", @@ -218,19 +287,19 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): ], "tf.pad": ["tensor", "paddings", "mode", "name", "constant_values"], "tf.quantize_v2": [ - "input", "min_range", "max_range", "T", "mode", "name", - "round_mode" + "input", "min_range", "max_range", "T", "mode", "name", "round_mode" ], "tf.feature_column.categorical_column_with_vocabulary_file": [ - "key", "vocabulary_file", "vocabulary_size", - "num_oov_buckets", "default_value", "dtype" + "key", "vocabulary_file", "vocabulary_size", "num_oov_buckets", + "default_value", "dtype" ], "tf.shape": ["input", "name", "out_type"], "tf.size": ["input", "name", "out_type"], + "tf.random.poisson": ["lam", "shape", "dtype", "seed", "name"], + "tf.sparse.add": ["a", "b", "thresh"], "tf.sparse.concat": [ "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" ], - "tf.random.poisson": ["lam", "shape", "dtype", "seed", "name"], "tf.sparse.segment_mean": [ "data", "indices", "segment_ids", "name", "num_segments" ], @@ -243,10 +312,75 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.strings.length": ["input", "name", "unit"], "tf.transpose": ["a", "perm", "name", "conjugate"], "tf.tuple": ["tensors", "name", "control_inputs"], - "tf.while_loop": ["cond", "body", "loop_vars", "shape_invariants", - "parallel_iterations", "back_prop", "swap_memory", - "name", "maximum_iterations", - "return_same_structure"], + "tf.while_loop": [ + "cond", "body", "loop_vars", "shape_invariants", + "parallel_iterations", "back_prop", "swap_memory", "name", + "maximum_iterations", "return_same_structure" + ], + "tf.reduce_all": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_all": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_any": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_any": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_min": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_min": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_max": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_max": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_sum": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_sum": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_mean": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_mean": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_prod": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_prod": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.reduce_logsumexp": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], + "tf.math.reduce_logsumexp": [ + "input_tensor", "axis", "keepdims", "name", "reduction_indices", + "keep_dims" + ], } # Specially handled functions. -- GitLab From c59719cf1f29a98cfc027b9c56f2028dff887663 Mon Sep 17 00:00:00 2001 From: Zhenyu Tan Date: Wed, 21 Nov 2018 10:03:25 -0800 Subject: [PATCH 202/672] Expose amsgrad argument for Adam, but error out if it is set to True. PiperOrigin-RevId: 222424267 --- tensorflow/python/keras/optimizer_v2/adam.py | 56 +++++++++++++++---- .../python/keras/optimizer_v2/adam_test.py | 5 ++ .../python/keras/optimizer_v2/adamax.py | 8 ++- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/tensorflow/python/keras/optimizer_v2/adam.py b/tensorflow/python/keras/optimizer_v2/adam.py index 962680fad6..fd5918dbfa 100644 --- a/tensorflow/python/keras/optimizer_v2/adam.py +++ b/tensorflow/python/keras/optimizer_v2/adam.py @@ -35,9 +35,13 @@ class Adam(optimizer_v2.OptimizerV2): requirement, invariant to diagonal rescaling of gradients, and is well suited for problems that are large in terms of data/parameters'. + Note, amsgrad is currently not supported and the argument can only be False. + # References See [Kingma et al., 2014](http://arxiv.org/abs/1412.6980) ([pdf](http://arxiv.org/pdf/1412.6980.pdf)). + For AMSGrad see [Reddi et al., 2-18] + (https://openreview.net/pdf?id=ryQu7f-RZ) """ def __init__(self, @@ -45,26 +49,47 @@ class Adam(optimizer_v2.OptimizerV2): beta_1=0.9, beta_2=0.999, epsilon=1e-7, + amsgrad=False, name='Adam'): r"""Construct a new Adam optimizer. - Initialization: + If amsgrad = False: + Initialization: + + $$m_0 := 0 \text{(Initialize initial 1st moment vector)}$$ + $$v_0 := 0 \text{(Initialize initial 2nd moment vector)}$$ + $$t := 0 \text{(Initialize timestep)}$$ + + The update rule for `variable` with gradient `g` uses an optimization + described at the end of section2 of the paper: + + $$t := t + 1$$ + $$lr_t := \text{learning\_rate} * \sqrt{1 - beta_2^t} / (1 - beta_1^t)$$ + + $$m_t := beta_1 * m_{t-1} + (1 - beta_1) * g$$ + $$v_t := beta_2 * v_{t-1} + (1 - beta_2) * g * g$$ + $$variable := variable - lr_t * m_t / (\sqrt{v_t} + \epsilon)$$ + + If amsgrad = True: + Initialization: - $$m_0 := 0 \text{(Initialize initial 1st moment vector)}$$ - $$v_0 := 0 \text{(Initialize initial 2nd moment vector)}$$ - $$t := 0 \text{(Initialize timestep)}$$ + $$m_0 := 0 \text{(Initialize initial 1st moment vector)}$$ + $$v_0 := 0 \text{(Initialize initial 2nd moment vector)}$$ + $$v_hat_0 := 0 \text{(Initialize initial 2nd moment vector)}$$ + $$t := 0 \text{(Initialize timestep)}$$ - The update rule for `variable` with gradient `g` uses an optimization - described at the end of section2 of the paper: + The update rule for `variable` with gradient `g` uses an optimization + described at the end of section2 of the paper: - $$t := t + 1$$ - $$lr_t := \text{learning\_rate} * \sqrt{1 - beta_2^t} / (1 - beta_1^t)$$ + $$t := t + 1$$ + $$lr_t := \text{learning\_rate} * \sqrt{1 - beta_2^t} / (1 - beta_1^t)$$ - $$m_t := beta_1 * m_{t-1} + (1 - beta_1) * g$$ - $$v_t := beta_2 * v_{t-1} + (1 - beta_2) * g * g$$ - $$variable := variable - lr_t * m_t / (\sqrt{v_t} + \epsilon)$$ + $$m_t := beta_1 * m_{t-1} + (1 - beta_1) * g$$ + $$v_t := beta_2 * v_{t-1} + (1 - beta_2) * g * g$$ + $$v_hat_t := max(v_hat_{t-1}, v_t) + $$variable := variable - lr_t * m_t / (\sqrt{v_hat_t} + \epsilon)$$ - The default value of 1e-8 for epsilon might not be a good default in + The default value of 1e-7 for epsilon might not be a good default in general. For example, when training an Inception network on ImageNet a current good choice is 1.0 or 0.1. Note that since AdamOptimizer uses the formulation just before Section 2.1 of the Kingma and Ba paper rather than @@ -89,6 +114,8 @@ class Adam(optimizer_v2.OptimizerV2): epsilon: A small constant for numerical stability. This epsilon is "epsilon hat" in the Kingma and Ba paper (in the formula just before Section 2.1), not the epsilon in Algorithm 1 of the paper. + amsgrad: boolean. Whether to apply AMSGrad variant of this algorithm from + the paper "On the Convergence of Adam and beyond". name: Optional name for the operations created when applying gradients. Defaults to "Adam". @compatibility(eager) When eager execution is enabled, `learning_rate`, `beta_1`, `beta_2`, and `epsilon` can each be @@ -102,6 +129,10 @@ class Adam(optimizer_v2.OptimizerV2): self._set_hyper('beta_1', beta_1) self._set_hyper('beta_2', beta_2) self._set_hyper('epsilon', epsilon) + # TODO(tanzheny): create op for resource_apply_adam_with_amsgrad + if amsgrad: + raise ValueError('Amsgrad is currently not supported.') + self._amsgrad = amsgrad def _create_slots(self, var_list): # Create slots for the first and second moments. @@ -173,5 +204,6 @@ class Adam(optimizer_v2.OptimizerV2): 'beta_1': self._serialize_hyperparameter('beta_1'), 'beta_2': self._serialize_hyperparameter('beta_2'), 'epsilon': self._serialize_hyperparameter('epsilon'), + 'amsgrad': self._amsgrad, }) return config diff --git a/tensorflow/python/keras/optimizer_v2/adam_test.py b/tensorflow/python/keras/optimizer_v2/adam_test.py index 46a45af224..20780ead9c 100644 --- a/tensorflow/python/keras/optimizer_v2/adam_test.py +++ b/tensorflow/python/keras/optimizer_v2/adam_test.py @@ -298,6 +298,11 @@ class AdamOptimizerTest(test.TestCase): # variables for v1 and v2 respectively. self.assertEqual(9, len(set(opt.variables()))) + def testAmsgradWithError(self): + with self.assertRaisesRegexp(ValueError, + "Amsgrad is currently not supported"): + adam.Adam(learning_rate=1., beta_1=0.9, beta_2=0.99, amsgrad=True) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/keras/optimizer_v2/adamax.py b/tensorflow/python/keras/optimizer_v2/adamax.py index 7530e629d1..67b678f862 100644 --- a/tensorflow/python/keras/optimizer_v2/adamax.py +++ b/tensorflow/python/keras/optimizer_v2/adamax.py @@ -89,7 +89,13 @@ class Adamax(adam.Adam): Defaults to "Adamax". """ # pylint: disable=useless-super-delegation - super(Adamax, self).__init__(learning_rate, beta_1, beta_2, epsilon, name) + super(Adamax, self).__init__( + learning_rate=learning_rate, + beta_1=beta_1, + beta_2=beta_2, + epsilon=epsilon, + amsgrad=False, + name=name) # pylint: enable=useless-super-delegation def _resource_apply_dense(self, grad, var): -- GitLab From 42e2bb488ad7571317f23cbdd5851227140b1985 Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Wed, 21 Nov 2018 10:07:11 -0800 Subject: [PATCH 203/672] Fix bug that resulted in unnecessary placeholders created during functional model cloning when input tensors were specified. PiperOrigin-RevId: 222424883 --- tensorflow/python/keras/engine/input_layer.py | 28 +++++++++--------- tensorflow/python/keras/models.py | 14 +++++---- tensorflow/python/keras/models_test.py | 29 +++++++++++++++++++ 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/tensorflow/python/keras/engine/input_layer.py b/tensorflow/python/keras/engine/input_layer.py index 590b935d40..9874efe2bc 100644 --- a/tensorflow/python/keras/engine/input_layer.py +++ b/tensorflow/python/keras/engine/input_layer.py @@ -19,12 +19,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.python.eager import context from tensorflow.python.framework import tensor_shape from tensorflow.python.keras import backend from tensorflow.python.keras.engine import base_layer from tensorflow.python.keras.utils import tf_utils -from tensorflow.python.ops import array_ops from tensorflow.python.util.tf_export import tf_export @@ -94,19 +92,19 @@ class InputLayer(base_layer.Layer): else: batch_input_shape = None graph = backend.get_graph() - with context.graph_mode(): - with graph.as_default(): - # In graph mode, create a graph placeholder to call the layer on. - if sparse: - input_tensor = array_ops.sparse_placeholder( - shape=batch_input_shape, - dtype=dtype, - name=self.name) - else: - input_tensor = array_ops.placeholder( - shape=batch_input_shape, - dtype=dtype, - name=self.name) + with graph.as_default(): + # In graph mode, create a graph placeholder to call the layer on. + if sparse: + input_tensor = backend.placeholder( + shape=batch_input_shape, + dtype=dtype, + name=self.name, + sparse=True) + else: + input_tensor = backend.placeholder( + shape=batch_input_shape, + dtype=dtype, + name=self.name) self.is_placeholder = True self._batch_input_shape = batch_input_shape diff --git a/tensorflow/python/keras/models.py b/tensorflow/python/keras/models.py index 3a0c51b497..4813b8061e 100644 --- a/tensorflow/python/keras/models.py +++ b/tensorflow/python/keras/models.py @@ -100,17 +100,19 @@ def _clone_functional_model(model, input_tensors=None): input_tensors = list(input_tensors) input_tensors = generic_utils.to_list(input_tensors) input_tensors_ = [] - for i, x in enumerate(input_tensors): - if not K.is_keras_tensor(x): - name = model._input_layers[i].name - input_tensor = Input(tensor=x, name='input_wrapper_for_' + name) + for i in range(len(input_tensors)): + input_tensor = input_tensors[i] + if not K.is_keras_tensor(input_tensor): + original_input_layer = model._input_layers[i] + name = original_input_layer.name + input_tensor = Input(tensor=input_tensor, + name='input_wrapper_for_' + name) input_tensors_.append(input_tensor) # Cache newly created input layer. - original_input_layer = x._keras_history[0] newly_created_input_layer = input_tensor._keras_history[0] layer_map[original_input_layer] = newly_created_input_layer else: - input_tensors_.append(x) + input_tensors_.append(input_tensor) input_tensors = input_tensors_ for x, y in zip(model.inputs, input_tensors): diff --git a/tensorflow/python/keras/models_test.py b/tensorflow/python/keras/models_test.py index 4b6bb74ef9..23321a2d16 100644 --- a/tensorflow/python/keras/models_test.py +++ b/tensorflow/python/keras/models_test.py @@ -26,10 +26,12 @@ import numpy as np from tensorflow.python import keras from tensorflow.python.eager import context from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.keras import backend as K from tensorflow.python.keras import metrics from tensorflow.python.keras import models +from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.platform import test @@ -219,6 +221,33 @@ class TestModelCloning(test.TestCase): with self.assertRaises(ValueError): keras.models._clone_sequential_model(seq_model, input_tensors=y) + def test_functional_cloning_does_not_create_unnecessary_placeholders(self): + with ops.Graph().as_default(): + x = keras.Input((4,)) + y = keras.layers.Dense(4)(x) + model = keras.models.Model(x, y) + graph = ops.Graph() + with graph.as_default(): + x = array_ops.ones((10, 4)) + _ = keras.models.clone_model(model, input_tensors=[x]) + has_placeholder = _has_placeholder(graph) + self.assertFalse(has_placeholder) + + def test_sequential_cloning_does_not_create_unnecessary_placeholders(self): + with ops.Graph().as_default(): + model = keras.models.Sequential([keras.layers.Dense(4)]) + graph = ops.Graph() + with graph.as_default(): + x = array_ops.ones((10, 4)) + _ = keras.models.clone_model(model, input_tensors=[x]) + has_placeholder = _has_placeholder(graph) + self.assertFalse(has_placeholder) + + +def _has_placeholder(graph): + ops_types = [op.type for op in graph.get_operations()] + return any('Placeholder' in s for s in ops_types) + class CheckpointingTests(test.TestCase): -- GitLab From a38f4113eeef01da0d38f467ba36dc0eb86a73ba Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Wed, 21 Nov 2018 10:08:58 -0800 Subject: [PATCH 204/672] Marked create_partitioned_variables as @deprecated It has been deprecated for a while, but did not include a relevant note in the docs. PiperOrigin-RevId: 222425114 --- tensorflow/python/ops/partitioned_variables.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 6174979d5e..5ba1d46a66 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -57,7 +57,7 @@ import math from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape from tensorflow.python.ops import variable_scope -from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.util import deprecation from tensorflow.python.util.tf_export import tf_export __all__ = [ @@ -238,6 +238,9 @@ def fixed_size_partitioner(num_shards, axis=0): @tf_export("create_partitioned_variables") +@deprecation.deprecated( + date=None, + instructions="Use tf.get_variable with a partitioner set.") def create_partitioned_variables( shape, slicing, initializer, dtype=dtypes.float32, trainable=True, collections=None, name=None, reuse=None): @@ -282,11 +285,6 @@ def create_partitioned_variables( Raises: ValueError: If any of the arguments is malformed. """ - logging.warn( - "create_partitioned_variables is deprecated. Use " - "tf.get_variable with a partitioner set, or " - "tf.get_partitioned_variable_list, instead.") - if len(shape) != len(slicing): raise ValueError("The 'shape' and 'slicing' of a partitioned Variable " "must have the length: shape: %s, slicing: %s" % -- GitLab From 086e7c3474a247dffb3ddc179197217e38c103ed Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Wed, 21 Nov 2018 10:17:59 -0800 Subject: [PATCH 205/672] Upgrade ARM_NEON_2_x86_SSE to 1200fe9 to fix warnings PiperOrigin-RevId: 222426343 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 101d0e4c7a..5c58bb1080 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -689,11 +689,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "arm_neon_2_x86_sse", build_file = clean_dep("//third_party:arm_neon_2_x86_sse.BUILD"), - sha256 = "c8d90aa4357f8079d427e87a6f4c493da1fa4140aee926c05902d7ec1533d9a5", - strip_prefix = "ARM_NEON_2_x86_SSE-0f77d9d182265259b135dad949230ecbf1a2633d", + sha256 = "213733991310b904b11b053ac224fee2d4e0179e46b52fe7f8735b8831e04dcc", + strip_prefix = "ARM_NEON_2_x86_SSE-1200fe90bb174a6224a525ee60148671a786a71f", urls = [ - "https://mirror.bazel.build/github.com/intel/ARM_NEON_2_x86_SSE/archive/0f77d9d182265259b135dad949230ecbf1a2633d.tar.gz", - "https://github.com/intel/ARM_NEON_2_x86_SSE/archive/0f77d9d182265259b135dad949230ecbf1a2633d.tar.gz", + "https://mirror.bazel.build/github.com/intel/ARM_NEON_2_x86_SSE/archive/1200fe90bb174a6224a525ee60148671a786a71f.tar.gz", + "https://github.com/intel/ARM_NEON_2_x86_SSE/archive/1200fe90bb174a6224a525ee60148671a786a71f.tar.gz", ], ) -- GitLab From ed52111074869696825d3dbf5c8bba800f3cefe2 Mon Sep 17 00:00:00 2001 From: Yanhui Liang Date: Wed, 21 Nov 2018 10:20:32 -0800 Subject: [PATCH 206/672] Update image.xxx api to make its main in io. Include: image.decode_bmp|gif|jpeg|image, image.is_jpeg, image.decode_and_crop_jpeg, image.encode_jpeg, image.extract_jpeg_shape PiperOrigin-RevId: 222426690 --- .../api_def_DecodeAndCropJpeg.pbtxt | 4 +-- .../python_api/api_def_DecodeBmp.pbtxt | 4 +-- .../python_api/api_def_DecodeGif.pbtxt | 4 +-- .../python_api/api_def_DecodeJpeg.pbtxt | 4 +-- .../python_api/api_def_DecodePng.pbtxt | 4 +-- .../python_api/api_def_EncodeJpeg.pbtxt | 4 +-- .../python_api/api_def_ExtractJpegShape.pbtxt | 4 +-- tensorflow/python/ops/image_ops_impl.py | 24 +++++++++++-- .../tools/api/golden/v1/tensorflow.io.pbtxt | 36 +++++++++++++++++++ .../tools/api/golden/v2/tensorflow.io.pbtxt | 36 +++++++++++++++++++ 10 files changed, 101 insertions(+), 23 deletions(-) diff --git a/tensorflow/core/api_def/python_api/api_def_DecodeAndCropJpeg.pbtxt b/tensorflow/core/api_def/python_api/api_def_DecodeAndCropJpeg.pbtxt index fbe9c88253..2c3857cc53 100644 --- a/tensorflow/core/api_def/python_api/api_def_DecodeAndCropJpeg.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_DecodeAndCropJpeg.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "DecodeAndCropJpeg" - endpoint { - name: "image.decode_and_crop_jpeg" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_DecodeBmp.pbtxt b/tensorflow/core/api_def/python_api/api_def_DecodeBmp.pbtxt index 573d83f373..ffe19ca8dc 100644 --- a/tensorflow/core/api_def/python_api/api_def_DecodeBmp.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_DecodeBmp.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "DecodeBmp" - endpoint { - name: "image.decode_bmp" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_DecodeGif.pbtxt b/tensorflow/core/api_def/python_api/api_def_DecodeGif.pbtxt index eed64df79c..ff68b997e1 100644 --- a/tensorflow/core/api_def/python_api/api_def_DecodeGif.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_DecodeGif.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "DecodeGif" - endpoint { - name: "image.decode_gif" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_DecodeJpeg.pbtxt b/tensorflow/core/api_def/python_api/api_def_DecodeJpeg.pbtxt index 994bc4e1f4..97d262abe5 100644 --- a/tensorflow/core/api_def/python_api/api_def_DecodeJpeg.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_DecodeJpeg.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "DecodeJpeg" - endpoint { - name: "image.decode_jpeg" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_DecodePng.pbtxt b/tensorflow/core/api_def/python_api/api_def_DecodePng.pbtxt index 309eec5ac3..3b9290a2c5 100644 --- a/tensorflow/core/api_def/python_api/api_def_DecodePng.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_DecodePng.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "DecodePng" - endpoint { - name: "image.decode_png" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_EncodeJpeg.pbtxt b/tensorflow/core/api_def/python_api/api_def_EncodeJpeg.pbtxt index 5c31e9d0f3..054ffb997b 100644 --- a/tensorflow/core/api_def/python_api/api_def_EncodeJpeg.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_EncodeJpeg.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "EncodeJpeg" - endpoint { - name: "image.encode_jpeg" - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_ExtractJpegShape.pbtxt b/tensorflow/core/api_def/python_api/api_def_ExtractJpegShape.pbtxt index 6849a6d3fa..a57955c8a7 100644 --- a/tensorflow/core/api_def/python_api/api_def_ExtractJpegShape.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_ExtractJpegShape.pbtxt @@ -1,6 +1,4 @@ op { graph_op_name: "ExtractJpegShape" - endpoint { - name: "image.extract_jpeg_shape" - } + visibility: HIDDEN } diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 1618b79504..229393c970 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1760,7 +1760,7 @@ def adjust_saturation(image, saturation_factor, name=None): orig_dtype) -@tf_export('image.is_jpeg') +@tf_export('io.is_jpeg', 'image.is_jpeg', v1=['io.is_jpeg', 'image.is_jpeg']) def is_jpeg(contents, name=None): r"""Convenience function to check if the 'contents' encodes a JPEG image. @@ -1795,8 +1795,28 @@ def _is_png(contents, name=None): substr = string_ops.substr(contents, 0, 3) return math_ops.equal(substr, b'\211PN', name=name) +tf_export('io.decode_and_crop_jpeg', 'image.decode_and_crop_jpeg', + v1=['io.decode_and_crop_jpeg', 'image.decode_and_crop_jpeg'])( + gen_image_ops.decode_and_crop_jpeg) -@tf_export('image.decode_image') +tf_export('io.decode_bmp', 'image.decode_bmp', + v1=['io.decode_bmp', 'image.decode_bmp'])(gen_image_ops.decode_bmp) +tf_export('io.decode_gif', 'image.decode_gif', + v1=['io.decode_gif', 'image.decode_gif'])(gen_image_ops.decode_gif) +tf_export('io.decode_jpeg', 'image.decode_jpeg', + v1=['io.decode_jpeg', 'image.decode_jpeg'])(gen_image_ops.decode_jpeg) +tf_export('io.decode_png', 'image.decode_png', + v1=['io.decode_png', 'image.decode_png'])(gen_image_ops.decode_png) + +tf_export('io.encode_jpeg', 'image.encode_jpeg', + v1=['io.encode_jpeg', 'image.encode_jpeg'])(gen_image_ops.encode_jpeg) +tf_export('io.extract_jpeg_shape', 'image.extract_jpeg_shape', + v1=['io.extract_jpeg_shape', 'image.extract_jpeg_shape'])( + gen_image_ops.extract_jpeg_shape) + + +@tf_export('io.decode_image', 'image.decode_image', + v1=['io.decode_image', 'image.decode_image']) def decode_image(contents, channels=None, dtype=dtypes.uint8, name=None): """Convenience function for `decode_bmp`, `decode_gif`, `decode_jpeg`, and `decode_png`. diff --git a/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt index 64b63ed1a4..fee12594ee 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt @@ -44,10 +44,18 @@ tf_module { name: "VarLenFeature" mtype: "" } + member_method { + name: "decode_and_crop_jpeg" + argspec: "args=[\'contents\', \'crop_window\', \'channels\', \'ratio\', \'fancy_upscaling\', \'try_recover_truncated\', \'acceptable_fraction\', \'dct_method\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'1\', \'True\', \'False\', \'1\', \'\', \'None\'], " + } member_method { name: "decode_base64" argspec: "args=[\'input\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "decode_bmp" + argspec: "args=[\'contents\', \'channels\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'None\'], " + } member_method { name: "decode_compressed" argspec: "args=[\'bytes\', \'compression_type\', \'name\'], varargs=None, keywords=None, defaults=[\'\', \'None\'], " @@ -56,10 +64,26 @@ tf_module { name: "decode_csv" argspec: "args=[\'records\', \'record_defaults\', \'field_delim\', \'use_quote_delim\', \'name\', \'na_value\', \'select_cols\'], varargs=None, keywords=None, defaults=[\',\', \'True\', \'None\', \'\', \'None\'], " } + member_method { + name: "decode_gif" + argspec: "args=[\'contents\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "decode_image" + argspec: "args=[\'contents\', \'channels\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \"\", \'None\'], " + } + member_method { + name: "decode_jpeg" + argspec: "args=[\'contents\', \'channels\', \'ratio\', \'fancy_upscaling\', \'try_recover_truncated\', \'acceptable_fraction\', \'dct_method\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'1\', \'True\', \'False\', \'1\', \'\', \'None\'], " + } member_method { name: "decode_json_example" argspec: "args=[\'json_examples\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "decode_png" + argspec: "args=[\'contents\', \'channels\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \"\", \'None\'], " + } member_method { name: "decode_raw" argspec: "args=[\'bytes\', \'out_type\', \'little_endian\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'None\'], " @@ -72,6 +96,18 @@ tf_module { name: "encode_base64" argspec: "args=[\'input\', \'pad\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\'], " } + member_method { + name: "encode_jpeg" + argspec: "args=[\'image\', \'format\', \'quality\', \'progressive\', \'optimize_size\', \'chroma_downsampling\', \'density_unit\', \'x_density\', \'y_density\', \'xmp_metadata\', \'name\'], varargs=None, keywords=None, defaults=[\'\', \'95\', \'False\', \'False\', \'True\', \'in\', \'300\', \'300\', \'\', \'None\'], " + } + member_method { + name: "extract_jpeg_shape" + argspec: "args=[\'contents\', \'output_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " + } + member_method { + name: "is_jpeg" + argspec: "args=[\'contents\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "match_filenames_once" argspec: "args=[\'pattern\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt index caa207b022..1de2fc9e5d 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt @@ -48,10 +48,18 @@ tf_module { name: "gfile" mtype: "" } + member_method { + name: "decode_and_crop_jpeg" + argspec: "args=[\'contents\', \'crop_window\', \'channels\', \'ratio\', \'fancy_upscaling\', \'try_recover_truncated\', \'acceptable_fraction\', \'dct_method\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'1\', \'True\', \'False\', \'1\', \'\', \'None\'], " + } member_method { name: "decode_base64" argspec: "args=[\'input\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "decode_bmp" + argspec: "args=[\'contents\', \'channels\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'None\'], " + } member_method { name: "decode_compressed" argspec: "args=[\'bytes\', \'compression_type\', \'name\'], varargs=None, keywords=None, defaults=[\'\', \'None\'], " @@ -60,10 +68,26 @@ tf_module { name: "decode_csv" argspec: "args=[\'records\', \'record_defaults\', \'field_delim\', \'use_quote_delim\', \'name\', \'na_value\', \'select_cols\'], varargs=None, keywords=None, defaults=[\',\', \'True\', \'None\', \'\', \'None\'], " } + member_method { + name: "decode_gif" + argspec: "args=[\'contents\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "decode_image" + argspec: "args=[\'contents\', \'channels\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \"\", \'None\'], " + } + member_method { + name: "decode_jpeg" + argspec: "args=[\'contents\', \'channels\', \'ratio\', \'fancy_upscaling\', \'try_recover_truncated\', \'acceptable_fraction\', \'dct_method\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'1\', \'True\', \'False\', \'1\', \'\', \'None\'], " + } member_method { name: "decode_json_example" argspec: "args=[\'json_examples\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "decode_png" + argspec: "args=[\'contents\', \'channels\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \"\", \'None\'], " + } member_method { name: "decode_raw" argspec: "args=[\'bytes\', \'out_type\', \'little_endian\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'None\'], " @@ -76,6 +100,18 @@ tf_module { name: "encode_base64" argspec: "args=[\'input\', \'pad\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\'], " } + member_method { + name: "encode_jpeg" + argspec: "args=[\'image\', \'format\', \'quality\', \'progressive\', \'optimize_size\', \'chroma_downsampling\', \'density_unit\', \'x_density\', \'y_density\', \'xmp_metadata\', \'name\'], varargs=None, keywords=None, defaults=[\'\', \'95\', \'False\', \'False\', \'True\', \'in\', \'300\', \'300\', \'\', \'None\'], " + } + member_method { + name: "extract_jpeg_shape" + argspec: "args=[\'contents\', \'output_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " + } + member_method { + name: "is_jpeg" + argspec: "args=[\'contents\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "match_filenames_once" argspec: "args=[\'pattern\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " -- GitLab From 408597998261a335c2311f674a846b0dd160de2b Mon Sep 17 00:00:00 2001 From: Tong Shen Date: Wed, 21 Nov 2018 10:36:21 -0800 Subject: [PATCH 207/672] Support DT_INT32 for Cumsum/Cumprod. PiperOrigin-RevId: 222429176 --- tensorflow/compiler/tests/scan_ops_test.py | 4 ++-- tensorflow/compiler/tf2xla/kernels/scan_ops.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/compiler/tests/scan_ops_test.py b/tensorflow/compiler/tests/scan_ops_test.py index 897db384b7..17639bd8a7 100644 --- a/tensorflow/compiler/tests/scan_ops_test.py +++ b/tensorflow/compiler/tests/scan_ops_test.py @@ -71,7 +71,7 @@ def handle_options(func, x, axis, exclusive, reverse): class CumsumTest(xla_test.XLATestCase): - valid_dtypes = [np.float32] + valid_dtypes = [np.float32, np.int32] def axis_dtypes(self): return set(self.int_types).intersection([np.int32, np.int64]) @@ -149,7 +149,7 @@ class CumsumTest(xla_test.XLATestCase): class CumprodTest(xla_test.XLATestCase): - valid_dtypes = [np.float32] + valid_dtypes = [np.float32, np.int32] def axis_dtypes(self): return set(self.int_types).intersection([np.int32, np.int64]) diff --git a/tensorflow/compiler/tf2xla/kernels/scan_ops.cc b/tensorflow/compiler/tf2xla/kernels/scan_ops.cc index b5fd7850bf..7f4fef146f 100644 --- a/tensorflow/compiler/tf2xla/kernels/scan_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/scan_ops.cc @@ -39,8 +39,8 @@ namespace { // TODO(phawkins): implement double-sized windowed reductions in XLA and remove // the type constraint. -constexpr std::array kScanOpTypes = { - {DT_HALF, DT_BFLOAT16, DT_FLOAT}}; +constexpr std::array kScanOpTypes = { + {DT_HALF, DT_BFLOAT16, DT_FLOAT, DT_INT32}}; class ScanOp : public XlaOpKernel { public: -- GitLab From 95d7bbb2fcfda083ab69f8e73d0719013cd9c3d4 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Wed, 21 Nov 2018 10:40:10 -0800 Subject: [PATCH 208/672] Replaced list comprehensions inside all/any/sum with generator expressions PiperOrigin-RevId: 222429778 --- configure.py | 2 +- tensorflow/compiler/tests/dense_layer_test.py | 2 +- tensorflow/compiler/tests/jit_test.py | 2 +- .../python/constrained_minimization_problem.py | 4 ++-- .../python/kernel_tests/cudnn_rnn_ops_test.py | 6 ++---- .../python/kernel_tests/cudnn_rnn_test.py | 4 ++-- .../distribute/python/minimize_loss_test.py | 2 +- .../contrib/distribute/python/tpu_strategy.py | 2 +- .../gan/python/losses/python/losses_impl.py | 4 +--- tensorflow/contrib/gan/python/train_test.py | 2 +- .../kernel_methods/python/kernel_estimators.py | 2 +- .../layers/python/layers/regularizers_test.py | 2 +- .../contrib/learn/python/learn/estimators/dnn.py | 4 ++-- .../learn/estimators/dnn_linear_combined.py | 8 ++++---- .../learn/python/learn/estimators/estimator.py | 6 +++--- .../learn/python/learn/estimators/linear.py | 4 ++-- tensorflow/contrib/quantize/python/quantize.py | 4 ++-- .../kernel_tests/attention_wrapper_test.py | 4 ++-- tensorflow/contrib/tpu/python/tpu/tpu.py | 2 +- tensorflow/python/autograph/utils/type_check.py | 2 +- .../optimization/map_vectorization_test.py | 2 +- .../filter_dataset_serialization_test.py | 6 ++---- .../python/data/experimental/ops/parsing_ops.py | 4 ++-- .../python/data/kernel_tests/dataset_ops_test.py | 2 +- tensorflow/python/data/util/sparse.py | 2 +- tensorflow/python/distribute/cross_device_ops.py | 16 ++++++++-------- .../python/distribute/cross_device_utils.py | 2 +- tensorflow/python/eager/backprop.py | 6 +++--- tensorflow/python/eager/function.py | 4 ++-- tensorflow/python/framework/function.py | 4 ++-- tensorflow/python/framework/meta_graph_test.py | 4 ++-- tensorflow/python/framework/op_def_library.py | 2 +- tensorflow/python/framework/test_util.py | 2 +- tensorflow/python/keras/backend.py | 2 +- tensorflow/python/keras/engine/base_layer.py | 7 +++---- .../keras/engine/distributed_training_utils.py | 6 +++++- tensorflow/python/keras/engine/network.py | 4 ++-- tensorflow/python/keras/engine/saving.py | 2 +- tensorflow/python/keras/engine/training_utils.py | 6 +++--- tensorflow/python/keras/layers/merge.py | 6 +++--- tensorflow/python/keras/utils/layer_utils.py | 2 +- .../kernel_tests/control_flow_ops_py_test.py | 6 +++--- tensorflow/python/ops/bitwise_ops_test.py | 2 +- tensorflow/python/ops/control_flow_ops.py | 12 ++++++------ tensorflow/python/ops/data_flow_ops.py | 6 +++--- tensorflow/python/ops/gradients_impl.py | 8 ++++---- tensorflow/python/ops/parallel_for/pfor.py | 7 +++---- tensorflow/python/ops/rnn.py | 2 +- tensorflow/python/ops/rnn_cell_impl.py | 2 +- tensorflow/python/ops/variable_scope.py | 2 +- tensorflow/python/ops/variables.py | 8 ++++---- tensorflow/python/ops/while_v2.py | 2 +- tensorflow/python/tools/inspect_checkpoint.py | 2 +- tensorflow/python/training/evaluation.py | 2 +- tensorflow/python/training/warm_starting_util.py | 6 +++--- .../tools/api/tests/api_compatibility_test.py | 4 ++-- 56 files changed, 113 insertions(+), 117 deletions(-) diff --git a/configure.py b/configure.py index 234561d94a..0b16fe1314 100644 --- a/configure.py +++ b/configure.py @@ -859,7 +859,7 @@ def set_tf_cuda_version(environ_cp): cuda_toolkit_paths_full = [ os.path.join(cuda_toolkit_path, x) for x in cuda_rt_lib_paths ] - if any([os.path.exists(x) for x in cuda_toolkit_paths_full]): + if any(os.path.exists(x) for x in cuda_toolkit_paths_full): break # Reset and retry diff --git a/tensorflow/compiler/tests/dense_layer_test.py b/tensorflow/compiler/tests/dense_layer_test.py index d1b90f098d..23c94cf245 100644 --- a/tensorflow/compiler/tests/dense_layer_test.py +++ b/tensorflow/compiler/tests/dense_layer_test.py @@ -42,7 +42,7 @@ def GetRunMetadataLabels(run_metadata): def InLabels(labels, substr): """Returns true iff one of the labels contains substr.""" - return any([substr in x for x in labels]) + return any(substr in x for x in labels) class DenseLayerTest(test.TestCase): diff --git a/tensorflow/compiler/tests/jit_test.py b/tensorflow/compiler/tests/jit_test.py index 6f51ae33a1..dbea9849e2 100644 --- a/tensorflow/compiler/tests/jit_test.py +++ b/tensorflow/compiler/tests/jit_test.py @@ -75,7 +75,7 @@ def RunMetadataLabels(run_metadata): def InLabels(labels, substr): """Returns true iff one of the labels contains substr.""" - return any([substr in x for x in labels]) + return any(substr in x for x in labels) def MetadataHasXlaRunOp(run_metadata): diff --git a/tensorflow/contrib/constrained_optimization/python/constrained_minimization_problem.py b/tensorflow/contrib/constrained_optimization/python/constrained_minimization_problem.py index 41258edd90..6926c0d03f 100644 --- a/tensorflow/contrib/constrained_optimization/python/constrained_minimization_problem.py +++ b/tensorflow/contrib/constrained_optimization/python/constrained_minimization_problem.py @@ -74,8 +74,8 @@ class ConstrainedMinimizationProblem(object): if (constraints_shape.ndims is None or proxy_constraints_shape.ndims is None or - any([ii is None for ii in constraints_shape.as_list()]) or - any([ii is None for ii in proxy_constraints_shape.as_list()])): + any(ii is None for ii in constraints_shape.as_list()) or + any(ii is None for ii in proxy_constraints_shape.as_list())): raise ValueError( "constraints and proxy_constraints must have fully-known shapes") if constraints_shape != proxy_constraints_shape: diff --git a/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_ops_test.py b/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_ops_test.py index 1e2c9121d6..a268415f0e 100644 --- a/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_ops_test.py +++ b/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_ops_test.py @@ -778,8 +778,7 @@ class CudnnParamsFormatConverterTest(TensorFlowTestCase, # Test opaque_params size lower bound opaque_params_size_v = sess.run(opaque_params_size) - min_params_size = ( - np.sum([x.size for x in ws]) + np.sum([x.size for x in bs])) + min_params_size = sum(x.size for x in ws) + np.sum(x.size for x in bs) logging.info("min_parm_size: %d vs actual_opaque_param_size: %d", min_params_size, opaque_params_size_v) self.assertLessEqual(min_params_size, opaque_params_size_v) @@ -853,8 +852,7 @@ class CudnnParamsFormatConverterTest(TensorFlowTestCase, # Test opaque_params size lower bound opaque_params_size_v = sess.run(opaque_params_size) - min_params_size = ( - np.sum([x.size for x in ws]) + np.sum([x.size for x in bs])) + min_params_size = sum(x.size for x in ws) + sum(x.size for x in bs) logging.info("min_parm_size: %d vs actual_opaque_param_size: %d", min_params_size, opaque_params_size_v) self.assertLessEqual(min_params_size, opaque_params_size_v) diff --git a/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_test.py b/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_test.py index 6cc93dccb0..7e1b4062ce 100644 --- a/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_test.py +++ b/tensorflow/contrib/cudnn_rnn/python/kernel_tests/cudnn_rnn_test.py @@ -1045,8 +1045,8 @@ class CudnnRNNTestParamsSize(test_util.TensorFlowTestCase): # Min param size estimate = sum(weights.size) + sum(biases.size) min_params_size = ( - np.sum(list(map(np.prod, rnn.canonical_weight_shapes))) + - np.sum([sp[0] for sp in rnn.canonical_bias_shapes])) + sum(map(np.prod, rnn.canonical_weight_shapes)) + + sum(sp[0] for sp in rnn.canonical_bias_shapes)) opaque_params = rnn.trainable_variables[0] with self.test_session(use_gpu=True, graph=ops.get_default_graph()): diff --git a/tensorflow/contrib/distribute/python/minimize_loss_test.py b/tensorflow/contrib/distribute/python/minimize_loss_test.py index e77d3d455b..129b394bb6 100644 --- a/tensorflow/contrib/distribute/python/minimize_loss_test.py +++ b/tensorflow/contrib/distribute/python/minimize_loss_test.py @@ -344,7 +344,7 @@ class MinimizeLossStepTest(test.TestCase, parameterized.TestCase): run_step() v = all_vars[0] - self.assertTrue(all([v is vi for vi in all_vars[1:]])) + self.assertTrue(all(v is vi for vi in all_vars[1:])) weight = numpy.squeeze(self.evaluate(v)) # Our model is: # predict = x * w diff --git a/tensorflow/contrib/distribute/python/tpu_strategy.py b/tensorflow/contrib/distribute/python/tpu_strategy.py index f1115cb0c0..94cf548cb4 100644 --- a/tensorflow/contrib/distribute/python/tpu_strategy.py +++ b/tensorflow/contrib/distribute/python/tpu_strategy.py @@ -254,7 +254,7 @@ class TPUExtended(distribute_lib.DistributionStrategyExtended): self, fn, multi_worker_iterator, iterations, initial_loop_values=None): output_shapes = multi_worker_iterator.output_shapes shapes = nest.flatten(output_shapes) - if any([not s.is_fully_defined() for s in shapes]): + if any(not s.is_fully_defined() for s in shapes): raise ValueError( "TPU currently requires fully defined shapes. Either use " "set_shape() on the input tensors or use " diff --git a/tensorflow/contrib/gan/python/losses/python/losses_impl.py b/tensorflow/contrib/gan/python/losses/python/losses_impl.py index df0342c80c..c91ce2c0f3 100644 --- a/tensorflow/contrib/gan/python/losses/python/losses_impl.py +++ b/tensorflow/contrib/gan/python/losses/python/losses_impl.py @@ -36,8 +36,6 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import numpy as np - from tensorflow.contrib.framework.python.ops import variables as contrib_variables_lib from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util @@ -817,7 +815,7 @@ def _numerically_stable_global_norm(tensor_list): Returns: A scalar tensor with the global norm. """ - if np.all([x is None for x in tensor_list]): + if all(x is None for x in tensor_list): return 0.0 list_max = math_ops.reduce_max([math_ops.reduce_max(math_ops.abs(x)) for x in diff --git a/tensorflow/contrib/gan/python/train_test.py b/tensorflow/contrib/gan/python/train_test.py index 31d9e82700..e8c24eea3d 100644 --- a/tensorflow/contrib/gan/python/train_test.py +++ b/tensorflow/contrib/gan/python/train_test.py @@ -759,7 +759,7 @@ class TensorPoolAdjusteModelTest(test.TestCase): # For [pool_size, ?), the pool is full, tensor2 must be equal to some # historical values of tensor1 (which is previously stored in the # pool). - self.assertTrue(any([(v == t2).all() for v in history_values])) + self.assertTrue(any((v == t2).all() for v in history_values)) def _make_new_model_and_check(self, model, pool_size): pool_fn = lambda x: random_tensor_pool.tensor_pool(x, pool_size=pool_size) diff --git a/tensorflow/contrib/kernel_methods/python/kernel_estimators.py b/tensorflow/contrib/kernel_methods/python/kernel_estimators.py index de7530231d..1626e55b9b 100644 --- a/tensorflow/contrib/kernel_methods/python/kernel_estimators.py +++ b/tensorflow/contrib/kernel_methods/python/kernel_estimators.py @@ -90,7 +90,7 @@ def _update_features_and_columns(features, feature_columns, mapped_column_name = column_name + "_MAPPED" # Construct new feature columns based on provided kernel_mappers. column_kernel_mappers = kernel_mappers_dict[feature_column] - new_dim = sum([mapper.output_dim for mapper in column_kernel_mappers]) + new_dim = sum(mapper.output_dim for mapper in column_kernel_mappers) mapped_columns.add( layers.feature_column.real_valued_column(mapped_column_name, new_dim)) diff --git a/tensorflow/contrib/layers/python/layers/regularizers_test.py b/tensorflow/contrib/layers/python/layers/regularizers_test.py index 51faba30c7..5cb00b7684 100644 --- a/tensorflow/contrib/layers/python/layers/regularizers_test.py +++ b/tensorflow/contrib/layers/python/layers/regularizers_test.py @@ -141,7 +141,7 @@ class RegularizerTest(test.TestCase): dummy_regularizer = lambda x: math_ops.reduce_sum(2 * x) array_weights_list = [[1.5], [2, 3, 4.2], [10, 42, 666.6]] tensor_weights_list = [constant_op.constant(x) for x in array_weights_list] - expected = sum([2 * x for l in array_weights_list for x in l]) + expected = sum(2 * x for l in array_weights_list for x in l) with self.cached_session(): result = regularizers.apply_regularization(dummy_regularizer, tensor_weights_list) diff --git a/tensorflow/contrib/learn/python/learn/estimators/dnn.py b/tensorflow/contrib/learn/python/learn/estimators/dnn.py index 18ca4214a1..10fbd60ba2 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/dnn.py +++ b/tensorflow/contrib/learn/python/learn/estimators/dnn.py @@ -150,10 +150,10 @@ def _dnn_model_fn(features, labels, mode, params, config=None): "input_from_feature_columns", values=tuple(six.itervalues(features)), partitioner=input_layer_partitioner) as input_layer_scope: - if all([ + if all( isinstance(fc, feature_column._FeatureColumn) # pylint: disable=protected-access for fc in feature_columns - ]): + ): net = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=feature_columns, diff --git a/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py b/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py index 7a3cc8bd98..2ade6b7b6c 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py +++ b/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py @@ -236,10 +236,10 @@ def _dnn_linear_combined_model_fn(features, labels, mode, params, config=None): "input_from_feature_columns", values=tuple(six.itervalues(features)), partitioner=input_layer_partitioner) as dnn_input_scope: - if all([ + if all( isinstance(fc, feature_column_lib._FeatureColumn) # pylint: disable=protected-access for fc in dnn_feature_columns - ]): + ): net = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=dnn_feature_columns, @@ -292,8 +292,8 @@ def _dnn_linear_combined_model_fn(features, labels, mode, params, config=None): linear_parent_scope, values=tuple(six.itervalues(features)), partitioner=linear_partitioner) as scope: - if all([isinstance(fc, feature_column_lib._FeatureColumn) # pylint: disable=protected-access - for fc in linear_feature_columns]): + if all(isinstance(fc, feature_column_lib._FeatureColumn) # pylint: disable=protected-access + for fc in linear_feature_columns): if joint_linear_weights: linear_logits, _, _ = layers.joint_weighted_sum_from_feature_columns( columns_to_tensors=features, diff --git a/tensorflow/contrib/learn/python/learn/estimators/estimator.py b/tensorflow/contrib/learn/python/learn/estimators/estimator.py index 8bc869db89..9132b2209b 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/estimator.py +++ b/tensorflow/contrib/learn/python/learn/estimators/estimator.py @@ -1066,11 +1066,11 @@ class BaseEstimator(sklearn.BaseEstimator, evaluable.Evaluable, chief_hooks = [] if (self._config.save_checkpoints_secs or self._config.save_checkpoints_steps): - saver_hook_exists = any([ + saver_hook_exists = any( isinstance(h, basic_session_run_hooks.CheckpointSaverHook) for h in (all_hooks + model_fn_ops.training_hooks + chief_hooks + model_fn_ops.training_chief_hooks) - ]) + ) if not saver_hook_exists: chief_hooks = [ basic_session_run_hooks.CheckpointSaverHook( @@ -1493,7 +1493,7 @@ class Estimator(BaseEstimator): # pylint: disable=protected-access class SKCompat(sklearn.BaseEstimator): """Scikit learn wrapper for TensorFlow Learn Estimator. - + THIS CLASS IS DEPRECATED. See [contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md) for general migration instructions. diff --git a/tensorflow/contrib/learn/python/learn/estimators/linear.py b/tensorflow/contrib/learn/python/learn/estimators/linear.py index 439b17e505..9ee8d8004b 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/linear.py +++ b/tensorflow/contrib/learn/python/learn/estimators/linear.py @@ -155,8 +155,8 @@ def _linear_model_fn(features, labels, mode, params, config=None): parent_scope, values=tuple(six.itervalues(features)), partitioner=partitioner) as scope: - if all([isinstance(fc, feature_column._FeatureColumn) # pylint: disable=protected-access - for fc in feature_columns]): + if all(isinstance(fc, feature_column._FeatureColumn) # pylint: disable=protected-access + for fc in feature_columns): if joint_weights: layer_fn = layers.joint_weighted_sum_from_feature_columns else: diff --git a/tensorflow/contrib/quantize/python/quantize.py b/tensorflow/contrib/quantize/python/quantize.py index 338923f751..21d1b12130 100644 --- a/tensorflow/contrib/quantize/python/quantize.py +++ b/tensorflow/contrib/quantize/python/quantize.py @@ -160,7 +160,7 @@ def Quantize(graph, # shouldn't quantize it, since the activation will be Fused into the # Add at inference time. consumers = input_to_ops_map.ConsumerOperations(layer_match.bypass_op) - if any([consumer.type in _ACTIVATION_TYPES for consumer in consumers]): + if any(consumer.type in _ACTIVATION_TYPES for consumer in consumers): logging.info('Skipping %s, because its followed by an activation.', layer_match.bypass_op.name) else: @@ -195,7 +195,7 @@ def Quantize(graph, # Add at inference time. consumers = input_to_ops_map.ConsumerOperations( layer_match.post_activation_bypass_op) - if any([consumer.type in _RELU_TYPES for consumer in consumers]): + if any(consumer.type in _RELU_TYPES for consumer in consumers): logging.info('Skipping %s, because its followed by an activation.', layer_match.post_activation_bypass_op.name) else: diff --git a/tensorflow/contrib/seq2seq/python/kernel_tests/attention_wrapper_test.py b/tensorflow/contrib/seq2seq/python/kernel_tests/attention_wrapper_test.py index 8668c67cf9..922f21b98b 100644 --- a/tensorflow/contrib/seq2seq/python/kernel_tests/attention_wrapper_test.py +++ b/tensorflow/contrib/seq2seq/python/kernel_tests/attention_wrapper_test.py @@ -154,8 +154,8 @@ class AttentionWrapperTest(test.TestCase): if attention_layer_sizes is not None: # Compute sum of attention_layer_sizes. Use encoder_output_depth if None. - attention_depth = sum([attention_layer_size or encoder_output_depth - for attention_layer_size in attention_layer_sizes]) + attention_depth = sum(attention_layer_size or encoder_output_depth + for attention_layer_size in attention_layer_sizes) elif attention_layers is not None: # Compute sum of attention_layers output depth. attention_depth = sum( diff --git a/tensorflow/contrib/tpu/python/tpu/tpu.py b/tensorflow/contrib/tpu/python/tpu/tpu.py index a02361241c..def57da20d 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu.py @@ -1111,7 +1111,7 @@ def validate_inference_rewrite_for_variables(graph): Raises: RuntimeError: if validation failed. """ - if not any([x.type == "GuaranteeConst" for x in graph.get_operations()]): + if not any(x.type == "GuaranteeConst" for x in graph.get_operations()): raise RuntimeError( "No GuaranteeConst ops found in the graph after running " "tpu.rewrite_for_inference(...). Please check that you are using " diff --git a/tensorflow/python/autograph/utils/type_check.py b/tensorflow/python/autograph/utils/type_check.py index 8748abc47b..ccef7dee03 100644 --- a/tensorflow/python/autograph/utils/type_check.py +++ b/tensorflow/python/autograph/utils/type_check.py @@ -30,4 +30,4 @@ def is_tensor(*args): Returns: True if any *args are TensorFlow types, False if none are. """ - return any([tensor_util.is_tensor(a) for a in args]) + return any(tensor_util.is_tensor(a) for a in args) diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py index 470de580e8..18b3bc9424 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py @@ -459,7 +459,7 @@ class MapVectorizationBenchmark(test.Benchmark): return median_time def _compare(self, input_dataset, map_fn, batch_size, input_size, str_id): - num_elems = int(np.sum([np.prod(x) for x in input_size])) + num_elems = sum(np.prod(x) for x in input_size) name_template = "{}__batch_size_{}_input_element_size_{}_{}" unoptimized = input_dataset.map(map_fn).batch(batch_size) unoptimized_op = unoptimized.make_one_shot_iterator().get_next() diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/filter_dataset_serialization_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/filter_dataset_serialization_test.py index 225f6cbac0..e3ba8ad231 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/filter_dataset_serialization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/filter_dataset_serialization_test.py @@ -17,8 +17,6 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import numpy as np - from tensorflow.python.data.experimental.kernel_tests.serialization import dataset_serialization_test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import sparse_tensor @@ -35,7 +33,7 @@ class FilterDatasetSerializationTest( def testFilterCore(self): div = 3 - num_outputs = np.sum([x % 3 != 2 for x in range(100)]) + num_outputs = sum(x % 3 != 2 for x in range(100)) self.run_core_tests(lambda: self._build_filter_range_graph(div), lambda: self._build_filter_range_graph(div * 2), num_outputs) @@ -47,7 +45,7 @@ class FilterDatasetSerializationTest( lambda d: d["foo"] + d["bar"]) def testFilterDictCore(self): - num_outputs = np.sum([(x**2) % 2 == 0 for x in range(10)]) + num_outputs = sum((x**2) % 2 == 0 for x in range(10)) self.run_core_tests(self._build_filter_dict_graph, None, num_outputs) def _build_sparse_filter(self): diff --git a/tensorflow/python/data/experimental/ops/parsing_ops.py b/tensorflow/python/data/experimental/ops/parsing_ops.py index 6615b9022a..a63eb8c516 100644 --- a/tensorflow/python/data/experimental/ops/parsing_ops.py +++ b/tensorflow/python/data/experimental/ops/parsing_ops.py @@ -138,10 +138,10 @@ def parse_example_dataset(features, num_parallel_calls=1): def _apply_fn(dataset): """Function from `Dataset` to `Dataset` that applies the transformation.""" out_dataset = _ParseExampleDataset(dataset, features, num_parallel_calls) - if any([ + if any( isinstance(feature, parsing_ops.SparseFeature) for _, feature in features.items() - ]): + ): # pylint: disable=protected-access # pylint: disable=g-long-lambda out_dataset = out_dataset.map( diff --git a/tensorflow/python/data/kernel_tests/dataset_ops_test.py b/tensorflow/python/data/kernel_tests/dataset_ops_test.py index 1f22a37c2e..3454082f96 100644 --- a/tensorflow/python/data/kernel_tests/dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_ops_test.py @@ -42,7 +42,7 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: graph = graph_pb2.GraphDef().FromString( sess.run(dataset._as_serialized_graph())) - self.assertTrue(any([node.op != "RangeDataset" for node in graph.node])) + self.assertTrue(any(node.op != "RangeDataset" for node in graph.node)) @staticmethod def make_apply_fn(dataset): diff --git a/tensorflow/python/data/util/sparse.py b/tensorflow/python/data/util/sparse.py index 5e6d224709..f2e22fefd3 100644 --- a/tensorflow/python/data/util/sparse.py +++ b/tensorflow/python/data/util/sparse.py @@ -34,7 +34,7 @@ def any_sparse(classes): Returns: `True` if `classes` contains a sparse tensor type and `False` otherwise. """ - return any([c is sparse_tensor.SparseTensor for c in nest.flatten(classes)]) + return any(c is sparse_tensor.SparseTensor for c in nest.flatten(classes)) def as_dense_shapes(shapes, classes): diff --git a/tensorflow/python/distribute/cross_device_ops.py b/tensorflow/python/distribute/cross_device_ops.py index f55385eddc..de25b718bf 100644 --- a/tensorflow/python/distribute/cross_device_ops.py +++ b/tensorflow/python/distribute/cross_device_ops.py @@ -103,10 +103,10 @@ def _validate_value_destination_pairs(value_destination_pairs): # pylint: disable=g-missing-docstring if not value_destination_pairs: return False if not isinstance(value_destination_pairs, (list, tuple)): return False - if not all([isinstance(pair, tuple) for pair in value_destination_pairs]): + if not all(isinstance(pair, tuple) for pair in value_destination_pairs): return False - if not all([isinstance(v[0], value_lib.PerReplica) - for v in value_destination_pairs]): + if not all(isinstance(v[0], value_lib.PerReplica) + for v in value_destination_pairs): return False return True @@ -132,10 +132,10 @@ def _devices_match(left, right): def _all_devices_match(value_destination_pairs): - if not all([_devices_match(v, d) for v, d in value_destination_pairs]): + if not all(_devices_match(v, d) for v, d in value_destination_pairs): return False - if not all([_devices_match(v, value_destination_pairs[0][0]) - for v, _ in value_destination_pairs[1:]]): + if not all(_devices_match(v, value_destination_pairs[0][0]) + for v, _ in value_destination_pairs[1:]): return False return True @@ -401,7 +401,7 @@ class ConcatAndSplitPacker(object): # all gradient shapes are defined, we use another method to get the # total size. # TODO(yuefengz): move this logic to array_ops.size. - if all([g.shape.is_fully_defined() for g, _ in device_grads_and_vars]): + if all(g.shape.is_fully_defined() for g, _ in device_grads_and_vars): total_grad_size = sum( [g.shape.num_elements() for g, _ in device_grads_and_vars]) else: @@ -941,7 +941,7 @@ def choose_the_best(devices, session_config=None): "TensorFlow sessions.") return ReductionToOneDeviceCrossDeviceOps() - if any([d.device_type.lower() != "gpu" for d in using_devices]): + if any(d.device_type.lower() != "gpu" for d in using_devices): logging.warning("Not all devices in DistributionStrategy are visible to " "TensorFlow session.") return ReductionToOneDeviceCrossDeviceOps() diff --git a/tensorflow/python/distribute/cross_device_utils.py b/tensorflow/python/distribute/cross_device_utils.py index 7903992ac7..0faadd7e0c 100644 --- a/tensorflow/python/distribute/cross_device_utils.py +++ b/tensorflow/python/distribute/cross_device_utils.py @@ -420,7 +420,7 @@ def sum_gradients_all_reduce(dev_prefixes, replica_grads, num_workers, alg, Returns: list of reduced tensors """ - alg_contains_shuffle = any([n in alg for n in ['pscpu', 'psgpu']]) + alg_contains_shuffle = any(n in alg for n in ['pscpu', 'psgpu']) is_hierarchical = '/' in alg if 'pscpu' in alg: aux_devices = [prefix + '/cpu:0' for prefix in dev_prefixes] diff --git a/tensorflow/python/eager/backprop.py b/tensorflow/python/eager/backprop.py index 84b61f47c1..99da422781 100644 --- a/tensorflow/python/eager/backprop.py +++ b/tensorflow/python/eager/backprop.py @@ -547,11 +547,11 @@ def _aggregate_grads(gradients): if len(gradients) == 1: return gradients[0] - if all([isinstance(g, ops.Tensor) for g in gradients]): + if all(isinstance(g, ops.Tensor) for g in gradients): return gen_math_ops.add_n(gradients) else: - assert all([isinstance(g, (ops.Tensor, ops.IndexedSlices)) - for g in gradients]) + assert all(isinstance(g, (ops.Tensor, ops.IndexedSlices)) + for g in gradients) indexed_slices_list = [] for grad in gradients: # TODO(xpan): Support nested IndexedSlices and core IndexedSlices diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index bc92a0c974..eff7a384b8 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -89,8 +89,8 @@ def _parse_func_attrs(attributes): """ attrs = {} for key, value in attributes.items(): - if not any([re.match(reg, key) - for reg in WHITELIST_FUNCTION_ATTRIBUTE_REGEX]): + if not any(re.match(reg, key) + for reg in WHITELIST_FUNCTION_ATTRIBUTE_REGEX): raise ValueError("Attribute name is not whitelisted. " "Whitelisted: prefix %s, got: %s" % (WHITELIST_FUNCTION_ATTRIBUTE_REGEX, key)) diff --git a/tensorflow/python/framework/function.py b/tensorflow/python/framework/function.py index 230a554641..622686ce00 100644 --- a/tensorflow/python/framework/function.py +++ b/tensorflow/python/framework/function.py @@ -874,7 +874,7 @@ def func_graph_from_py_func(func, arg_names, arg_types, name=None, # If func only returned one value, make it a tuple. if not isinstance(outputs, (list, tuple)): outputs = (outputs,) - if any([_ is None for _ in outputs]): + if any(_ is None for _ in outputs): raise ValueError("Function %s can not return None." % name) # Ensures each output is a Tensor in the function graph. outputs = [ops.convert_to_tensor(t) for t in outputs] @@ -1190,7 +1190,7 @@ def get_extra_args(): def _type_list_to_str(types): - if any([_ not in _DTYPE_TO_STR for _ in types]): + if any(_ not in _DTYPE_TO_STR for _ in types): raise ValueError("Unsupported dtypes: %s" % types) return "".join([_DTYPE_TO_STR[_] for _ in types]) diff --git a/tensorflow/python/framework/meta_graph_test.py b/tensorflow/python/framework/meta_graph_test.py index 3605ed7fa2..559a76bebb 100644 --- a/tensorflow/python/framework/meta_graph_test.py +++ b/tensorflow/python/framework/meta_graph_test.py @@ -600,11 +600,11 @@ class ScopedMetaGraphTest(test.TestCase): with graph.as_default(): variables.Variable(initial_value=1.0, trainable=True) self.assertTrue( - all([ + all( graph.get_collection(key) for key in [ops.GraphKeys.GLOBAL_VARIABLES, ops.GraphKeys.TRAINABLE_VARIABLES] - ])) + )) meta_graph.export_scoped_meta_graph( filename=meta_graph_filename, graph=graph) diff --git a/tensorflow/python/framework/op_def_library.py b/tensorflow/python/framework/op_def_library.py index 9955a9a2cd..2318b32ef1 100644 --- a/tensorflow/python/framework/op_def_library.py +++ b/tensorflow/python/framework/op_def_library.py @@ -570,7 +570,7 @@ class OpDefLibrary(object): "than minimum length %d." % (input_name, op_type_name, len(values), num_attr.minimum)) # All tensors must have the same base type. - if any([bt != base_types[0] for bt in base_types]): + if any(bt != base_types[0] for bt in base_types): raise TypeError( "All tensors passed to '%s' of '%s' Op " "must have the same type." % diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index bf0ebaea99..7c486b2cbe 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -1044,7 +1044,7 @@ def is_gpu_available(cuda_only=False, min_cuda_compute_capability=None): return True return False except errors_impl.NotFoundError as e: - if not all([x in str(e) for x in ["CUDA", "not find"]]): + if not all(x in str(e) for x in ["CUDA", "not find"]): raise e else: logging.error(str(e)) diff --git a/tensorflow/python/keras/backend.py b/tensorflow/python/keras/backend.py index 54421d9022..c7654642d0 100644 --- a/tensorflow/python/keras/backend.py +++ b/tensorflow/python/keras/backend.py @@ -2325,7 +2325,7 @@ def concatenate(tensors, axis=-1): else: axis = 0 - if py_all([is_sparse(x) for x in tensors]): + if py_all(is_sparse(x) for x in tensors): return sparse_ops.sparse_concat(axis, tensors) else: return array_ops.concat([to_dense(x) for x in tensors], axis) diff --git a/tensorflow/python/keras/engine/base_layer.py b/tensorflow/python/keras/engine/base_layer.py index c8e964d1f7..5426965509 100644 --- a/tensorflow/python/keras/engine/base_layer.py +++ b/tensorflow/python/keras/engine/base_layer.py @@ -768,7 +768,7 @@ class Layer(checkpointable.CheckpointableBase): if context.executing_eagerly(): # Accept NumPy inputs by converting to Tensors when executing eagerly. - if all([isinstance(x, (np.ndarray, float, int)) for x in input_list]): + if all(isinstance(x, (np.ndarray, float, int)) for x in input_list): inputs = nest.map_structure(ops.convert_to_tensor, inputs) input_list = nest.flatten(inputs) @@ -1442,8 +1442,7 @@ class Layer(checkpointable.CheckpointableBase): ', but the layer isn\'t built. ' 'You can build it manually via: `' + self.name + '.build(batch_input_shape)`.') - weight_shapes = [w.shape.as_list() for w in self.weights] - return int(sum([np.prod(w) for w in weight_shapes])) + return int(sum(np.prod(w.shape.as_list()) for w in self.weights)) @property def output_shape(self): @@ -1758,7 +1757,7 @@ def have_all_keras_metadata(iterable_or_element): iterable = [iterable_or_element] else: iterable = nest.flatten(iterable_or_element) - return all([hasattr(x, '_keras_history') for x in iterable]) + return all(hasattr(x, '_keras_history') for x in iterable) def collect_previous_mask(input_tensors): diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index 25685fb5cf..7d915544fc 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -383,7 +383,11 @@ def validate_inputs(x, y, distribution_strategy): for i in [x, y]: if isinstance(i, dataset_ops.Dataset): shapes = nest.flatten(i.output_shapes) - if any([not s.is_fully_defined() for s in shapes]): + try: + s = next(s for s in shapes if not s.is_fully_defined()) + except StopIteration: + continue + else: raise ValueError( 'Using TPUs currently requires fully defined shapes. Either use ' 'set_shape() on the input tensors or use ' diff --git a/tensorflow/python/keras/engine/network.py b/tensorflow/python/keras/engine/network.py index 4163176483..f854cdd4e0 100644 --- a/tensorflow/python/keras/engine/network.py +++ b/tensorflow/python/keras/engine/network.py @@ -428,8 +428,8 @@ class Network(base_layer.Layer): @property def stateful(self): - return any([(hasattr(layer, 'stateful') and layer.stateful) - for layer in self.layers]) + return any((hasattr(layer, 'stateful') and layer.stateful) + for layer in self.layers) def reset_states(self): for layer in self.layers: diff --git a/tensorflow/python/keras/engine/saving.py b/tensorflow/python/keras/engine/saving.py index 22c48e3f13..54d9e32fb2 100644 --- a/tensorflow/python/keras/engine/saving.py +++ b/tensorflow/python/keras/engine/saving.py @@ -917,7 +917,7 @@ def save_attributes_to_hdf5_group(group, name, data): chunked_data = np.array_split(data_npy, num_chunks) # This will never loop forever thanks to the test above. - while any([x.nbytes > HDF5_OBJECT_HEADER_LIMIT for x in chunked_data]): + while any(x.nbytes > HDF5_OBJECT_HEADER_LIMIT for x in chunked_data): num_chunks += 1 chunked_data = np.array_split(data_npy, num_chunks) diff --git a/tensorflow/python/keras/engine/training_utils.py b/tensorflow/python/keras/engine/training_utils.py index 8669daf99e..1735db8b6b 100644 --- a/tensorflow/python/keras/engine/training_utils.py +++ b/tensorflow/python/keras/engine/training_utils.py @@ -58,10 +58,10 @@ def _map_nested(data, func): def _nested_all(data, cond_func): """Checks if all elements in a nested structure satisfy cond_func.""" if isinstance(data, (tuple, list)): - return all([_nested_all(nested_data, cond_func) for nested_data in data]) + return all(_nested_all(nested_data, cond_func) for nested_data in data) elif isinstance(data, dict): return all( - [_nested_all(nested_data, cond_func) for nested_data in data.values()]) + _nested_all(nested_data, cond_func) for nested_data in data.values()) else: return cond_func(data) @@ -69,7 +69,7 @@ def _nested_all(data, cond_func): def _nested_any(data, cond_func): """Checks if any nested_elements in a nested structure satisfy cond_func.""" if isinstance(data, (tuple, list)): - return any([_nested_any(nested_data, cond_func) for nested_data in data]) + return any(_nested_any(nested_data, cond_func) for nested_data in data) elif isinstance(data, dict): return any( [_nested_any(nested_data, cond_func) for nested_data in data.values()]) diff --git a/tensorflow/python/keras/layers/merge.py b/tensorflow/python/keras/layers/merge.py index f295af3fe0..45e705c696 100644 --- a/tensorflow/python/keras/layers/merge.py +++ b/tensorflow/python/keras/layers/merge.py @@ -212,7 +212,7 @@ class _Merge(Layer): if len(mask) != len(inputs): raise ValueError('The lists `inputs` and `mask` ' 'should have the same length.') - if all([m is None for m in mask]): + if all(m is None for m in mask): return None masks = [array_ops.expand_dims(m, axis=0) for m in mask if m is not None] return K.all(K.concatenate(masks, axis=0), axis=0, keepdims=False) @@ -378,7 +378,7 @@ class Concatenate(_Merge): if not isinstance(input_shape, list) or len(input_shape) < 2: raise ValueError('A `Concatenate` layer should be called ' 'on a list of at least 2 inputs') - if all([shape is None for shape in input_shape]): + if all(shape is None for shape in input_shape): return reduced_inputs_shapes = [list(shape) for shape in input_shape] shape_set = set() @@ -418,7 +418,7 @@ class Concatenate(_Merge): if len(mask) != len(inputs): raise ValueError('The lists `inputs` and `mask` ' 'should have the same length.') - if all([m is None for m in mask]): + if all(m is None for m in mask): return None # Make a list of masks while making sure # the dimensionality of each mask diff --git a/tensorflow/python/keras/utils/layer_utils.py b/tensorflow/python/keras/utils/layer_utils.py index 158a9a5e76..60677be735 100644 --- a/tensorflow/python/keras/utils/layer_utils.py +++ b/tensorflow/python/keras/utils/layer_utils.py @@ -77,7 +77,7 @@ def count_params(weights): Returns: The total number of scalars composing the weights """ - return int(np.sum([np.prod(p.get_shape().as_list()) for p in set(weights)])) + return int(sum(np.prod(p.get_shape().as_list()) for p in set(weights))) def print_summary(model, line_length=None, positions=None, print_fn=None): diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 3b8f917282..59966ebc84 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -863,13 +863,13 @@ class ControlFlowTest(test.TestCase): # Should just be [1, 1], but possibly a sparse representation gv, gi = sess.run([grad.values, grad.indices], feed_dict={c: 1}) dense_gv = [ - sum([y for (x, y) in zip(gi, gv) if x == i]) for i in range(2) + sum(y for (x, y) in zip(gi, gv) if x == i) for i in range(2) ] self.assertAllEqual(dense_gv, [1.0, 1.0]) # Should be [0, 2], as the else forwards v1[1] twice gv, gi = sess.run([grad.values, grad.indices], feed_dict={c: 3}) dense_gv = [ - sum([y for (x, y) in zip(gi, gv) if x == i]) for i in range(2) + sum(y for (x, y) in zip(gi, gv) if x == i) for i in range(2) ] self.assertAllEqual(dense_gv, [0.0, 2.0]) @@ -2809,7 +2809,7 @@ class ControlFlowTest(test.TestCase): self.assertAllClose([156.0, 400.0], sess.run(r, feed_dict=feed_dict)) name = "gradients/while/stopped_grad" all_ops = x.graph.get_operations() - self.assertFalse(any([name in op.name for op in all_ops])) + self.assertFalse(any(name in op.name for op in all_ops)) @test_util.disable_control_flow_v2("b/117954949") def testWhileGradGradFail(self): diff --git a/tensorflow/python/ops/bitwise_ops_test.py b/tensorflow/python/ops/bitwise_ops_test.py index dfb40db2d5..f6f35374c0 100644 --- a/tensorflow/python/ops/bitwise_ops_test.py +++ b/tensorflow/python/ops/bitwise_ops_test.py @@ -59,7 +59,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): 2**31 - 1, 2**31, 2**32 - 1, 2**32, -2**32 + 1, -2**32, -2**63 + 1, 2**63 - 1] def count_bits(x): - return sum([bin(z).count("1") for z in six.iterbytes(x.tobytes())]) + return sum(bin(z).count("1") for z in six.iterbytes(x.tobytes())) for dtype in dtype_list: with self.cached_session(use_gpu=True) as sess: print("PopulationCount test: ", dtype) diff --git a/tensorflow/python/ops/control_flow_ops.py b/tensorflow/python/ops/control_flow_ops.py index 4417632e69..a36a24ebb0 100644 --- a/tensorflow/python/ops/control_flow_ops.py +++ b/tensorflow/python/ops/control_flow_ops.py @@ -158,7 +158,7 @@ def Assert(condition, data, summarize=None, name=None): with ops.name_scope(name, "Assert", [condition, data]) as name: xs = ops.convert_n_to_tensor(data) - if all([x.dtype in {dtypes.string, dtypes.int32} for x in xs]): + if all(x.dtype in {dtypes.string, dtypes.int32} for x in xs): # As a simple heuristic, we assume that string and int32 are # on host to avoid the need to use cond. If it is not case, # we will pay the price copying the tensor to host memory. @@ -457,19 +457,19 @@ def merge(inputs, name=None): ValueError: If any of the inputs is None, or inputs are IndexedSlices and some but not all have a dense_shape property. """ - if any([inp is None for inp in inputs]): + if any(inp is None for inp in inputs): raise ValueError("At least one of the merge inputs is None: %s" % inputs) with ops.name_scope(name, "Merge", inputs) as name: inputs = [ ops.internal_convert_to_tensor_or_indexed_slices(inp, as_ref=True) for inp in inputs ] - if all([isinstance(v, ops.Tensor) for v in inputs]): - if all([v.dtype._is_ref_dtype for v in inputs]): # pylint: disable=protected-access + if all(isinstance(v, ops.Tensor) for v in inputs): + if all(v.dtype._is_ref_dtype for v in inputs): # pylint: disable=protected-access return gen_control_flow_ops.ref_merge(inputs, name) else: return gen_control_flow_ops.merge(inputs, name) - elif all([isinstance(v, sparse_tensor.SparseTensor) for v in inputs]): + elif all(isinstance(v, sparse_tensor.SparseTensor) for v in inputs): # Only handle the case when all inputs are SparseTensor. values, _ = merge([inp.values for inp in inputs], name=name) indices, chosen_index = gen_control_flow_ops.merge( @@ -557,7 +557,7 @@ def _SetShapeInvariants(input_vars, enter_vars, shapes): if shapes is None: return flat_shapes = nest.flatten(shapes) - if not all([isinstance(s, tensor_shape.TensorShape) for s in flat_shapes]): + if not all(isinstance(s, tensor_shape.TensorShape) for s in flat_shapes): raise ValueError("`shapes` must be a (possibly nested) list of shapes.") # Check that the shapes of the inputs are less than the shape invariants, # and set the shapes of `enter_vars` to the shape invariants. diff --git a/tensorflow/python/ops/data_flow_ops.py b/tensorflow/python/ops/data_flow_ops.py index 0fac7994cb..bb08dbaea1 100644 --- a/tensorflow/python/ops/data_flow_ops.py +++ b/tensorflow/python/ops/data_flow_ops.py @@ -79,7 +79,7 @@ def _as_shape_list(shapes, shapes = [shapes] shapes = [tensor_shape.as_shape(shape) for shape in shapes] if not unknown_dim_allowed: - if any([not shape.is_fully_defined() for shape in shapes]): + if any(not shape.is_fully_defined() for shape in shapes): raise ValueError("All shapes must be fully defined: %s" % shapes) if not unknown_rank_allowed: if any([shape.dims is None for shape in shapes]): @@ -198,11 +198,11 @@ class QueueBase(object): raise TypeError("A list of queues expected") dtypes = queues[0].dtypes - if not all([dtypes == q.dtypes for q in queues[1:]]): + if not all(dtypes == q.dtypes for q in queues[1:]): raise TypeError("Queues do not have matching component dtypes.") names = queues[0].names - if not all([names == q.names for q in queues[1:]]): + if not all(names == q.names for q in queues[1:]): raise TypeError("Queues do not have matching component names.") queue_shapes = [q.shapes for q in queues] diff --git a/tensorflow/python/ops/gradients_impl.py b/tensorflow/python/ops/gradients_impl.py index 53c0709e32..278008526c 100644 --- a/tensorflow/python/ops/gradients_impl.py +++ b/tensorflow/python/ops/gradients_impl.py @@ -895,7 +895,7 @@ def _HasAnyNotNoneGrads(grads, op): if isinstance(out_grad, (ops.Tensor, ops.IndexedSlices)): return True if out_grad and isinstance(out_grad, collections.Sequence): - if any([g is not None for g in out_grad]): + if any(g is not None for g in out_grad): return True return False @@ -1110,11 +1110,11 @@ def _AggregatedGrads(grads, assert control_flow_util.IsLoopSwitch(op) continue # Grads have to be Tensors or IndexedSlices - if (isinstance(out_grad, collections.Sequence) and not all([ + if (isinstance(out_grad, collections.Sequence) and not all( isinstance(g, (ops.Tensor, ops.IndexedSlices)) for g in out_grad if g is not None - ])): + )): raise TypeError("gradients have to be either all Tensors " "or all IndexedSlices") # Aggregate multiple gradients, and convert [] to None. @@ -1122,7 +1122,7 @@ def _AggregatedGrads(grads, if len(out_grad) < 2: used = "nop" out_grads[i] = out_grad[0] - elif all([isinstance(g, ops.Tensor) for g in out_grad if g is not None]): + elif all(isinstance(g, ops.Tensor) for g in out_grad if g is not None): tensor_shape = _AccumulatorShape(out_grad) if (aggregation_method == AggregationMethod.EXPERIMENTAL_ACCUMULATE_N and len(out_grad) > 2 and tensor_shape.is_fully_defined()): diff --git a/tensorflow/python/ops/parallel_for/pfor.py b/tensorflow/python/ops/parallel_for/pfor.py index d789dc65b1..a22c1126c9 100644 --- a/tensorflow/python/ops/parallel_for/pfor.py +++ b/tensorflow/python/ops/parallel_for/pfor.py @@ -1152,9 +1152,8 @@ class PFor(object): continue converted_inputs = [self._conversion_map[inp] for inp in y_op.inputs] - some_input_converted = any( - [self._was_converted(x) for x in y_op.inputs]) - some_input_stacked = any([x.is_stacked for x in converted_inputs]) + some_input_converted = any(self._was_converted(x) for x in y_op.inputs) + some_input_stacked = any(x.is_stacked for x in converted_inputs) converted_control_ops = set() some_control_input_converted = False @@ -1198,7 +1197,7 @@ class PFor(object): # All inputs are unstacked or uncoverted but some control inputs are # converted. # TODO(rachelim): Handle the case where some inputs are sparsely - # stacked (i.e. any([x.is_sparse_stacked for x in converted_inputs])) + # stacked (i.e. any(x.is_sparse_stacked for x in converted_inputs)) new_op = _create_op(y_op.type, [x.t for x in converted_inputs], [x.dtype for x in y_op.outputs], y_op.node_def.attr) diff --git a/tensorflow/python/ops/rnn.py b/tensorflow/python/ops/rnn.py index c23b85847c..ec48cab91d 100644 --- a/tensorflow/python/ops/rnn.py +++ b/tensorflow/python/ops/rnn.py @@ -117,7 +117,7 @@ def _infer_state_dtype(explicit_dtype, state): inferred_dtypes = [element.dtype for element in nest.flatten(state)] if not inferred_dtypes: raise ValueError("Unable to infer dtype from empty state.") - all_same = all([x == inferred_dtypes[0] for x in inferred_dtypes]) + all_same = all(x == inferred_dtypes[0] for x in inferred_dtypes) if not all_same: raise ValueError( "State has tensors of different inferred_dtypes. Unable to infer a " diff --git a/tensorflow/python/ops/rnn_cell_impl.py b/tensorflow/python/ops/rnn_cell_impl.py index 85efd6a4f7..ffc45619a7 100644 --- a/tensorflow/python/ops/rnn_cell_impl.py +++ b/tensorflow/python/ops/rnn_cell_impl.py @@ -1456,7 +1456,7 @@ class MultiRNNCell(RNNCell): if self._state_is_tuple: return tuple(cell.state_size for cell in self._cells) else: - return sum([cell.state_size for cell in self._cells]) + return sum(cell.state_size for cell in self._cells) @property def output_size(self): diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 44bb62a5dc..4f210e3b12 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -680,7 +680,7 @@ class _VariableStore(object): "Partitioner returned a partition list that does not match the " "Variable's rank: %s vs. %s" % (partitions, shape)) - if any([p < 1 for p in partitions]): + if any(p < 1 for p in partitions): raise ValueError( "Partitioner returned zero partitions for some axes: %s" % partitions) diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index 5bee522481..c8d12c8ecf 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -2482,21 +2482,21 @@ class PartitionedVariable(object): "variable_list is not a list or tuple: %s" % variable_list) if not isinstance(partitions, (list, tuple)): raise TypeError("partitions is not a list or tuple: %s" % partitions) - if not all([p >= 1 for p in partitions]): + if not all(p >= 1 for p in partitions): raise ValueError("partition values must be positive: %s" % partitions) if not variable_list: raise ValueError("variable_list may not be empty") # pylint: disable=protected-access for v in variable_list: # Sort the variable_list lexicographically according to var offset value. - if not all([v._get_save_slice_info() is not None for v in variable_list]): + if not all(v._get_save_slice_info() is not None for v in variable_list): raise ValueError( "All variables must have a save_slice_info available: %s" % [v.name for v in variable_list]) if len(shape) != len(partitions): raise ValueError("len(shape) != len(partitions): %s vs. %s" % (shape, partitions)) - if not all([v._get_save_slice_info().full_shape == shape]): + if v._get_save_slice_info().full_shape != shape: raise ValueError( "All variables' full shapes must match shape: %s; " "but full shapes were: %s" @@ -2523,7 +2523,7 @@ class PartitionedVariable(object): return len(self._variable_list) def _partition_axes(self): - if all([p == 1 for p in self._partitions]): + if all(p == 1 for p in self._partitions): return [0] else: return [i for i, p in enumerate(self._partitions) if p > 1] diff --git a/tensorflow/python/ops/while_v2.py b/tensorflow/python/ops/while_v2.py index 5ab7bffedc..1252c7fb03 100644 --- a/tensorflow/python/ops/while_v2.py +++ b/tensorflow/python/ops/while_v2.py @@ -509,7 +509,7 @@ def _grad_fn(ys, xs, args, func_graph): # TODO(b/118712257): Handle the case when grad_outs has None's e.g. when there # is a tf.StopGradient in the loop body. - assert all([g is not None for g in grad_outs]) + assert all(g is not None for g in grad_outs) counter = args[0] total_iters = args[1] return [counter + 1, total_iters] + grad_outs diff --git a/tensorflow/python/tools/inspect_checkpoint.py b/tensorflow/python/tools/inspect_checkpoint.py index 6504fbc107..ea1f6aa555 100644 --- a/tensorflow/python/tools/inspect_checkpoint.py +++ b/tensorflow/python/tools/inspect_checkpoint.py @@ -63,7 +63,7 @@ def print_tensors_in_checkpoint_file(file_name, tensor_name, all_tensors, print("It's likely that your checkpoint file has been compressed " "with SNAPPY.") if ("Data loss" in str(e) and - (any([e in file_name for e in [".index", ".meta", ".data"]]))): + any(e in file_name for e in [".index", ".meta", ".data"])): proposed_file = ".".join(file_name.split(".")[0:-1]) v2_file_error_template = """ It's likely that this is a V2 checkpoint and you need to provide the filename diff --git a/tensorflow/python/training/evaluation.py b/tensorflow/python/training/evaluation.py index 2c4eb02d53..a10178f8cf 100644 --- a/tensorflow/python/training/evaluation.py +++ b/tensorflow/python/training/evaluation.py @@ -230,7 +230,7 @@ def _evaluate_once(checkpoint_path, hooks = list(hooks or []) if eval_ops is not None: - if any([isinstance(h, _MultiStepStopAfterNEvalsHook) for h in hooks]): + if any(isinstance(h, _MultiStepStopAfterNEvalsHook) for h in hooks): steps_per_run_variable = \ basic_session_run_hooks.get_or_create_steps_per_run_variable() update_eval_step = state_ops.assign_add( diff --git a/tensorflow/python/training/warm_starting_util.py b/tensorflow/python/training/warm_starting_util.py index 78dbb465b5..3649d313ae 100644 --- a/tensorflow/python/training/warm_starting_util.py +++ b/tensorflow/python/training/warm_starting_util.py @@ -248,7 +248,7 @@ def _warm_start_var_with_vocab(var, prev_tensor_name = _infer_var_name(var) # TODO(eddz): Fix functionality for rank-1 Variables (like FC biases). - total_v_first_axis = sum([v.get_shape().as_list()[0] for v in var]) + total_v_first_axis = sum(v.get_shape().as_list()[0] for v in var) for v in var: v_shape = v.get_shape().as_list() slice_info = v._get_save_slice_info() @@ -333,12 +333,12 @@ def _get_grouped_variables(vars_to_warm_start): ops.GraphKeys.TRAINABLE_VARIABLES, scope=vars_to_warm_start) elif isinstance(vars_to_warm_start, list): - if all([isinstance(v, str) for v in vars_to_warm_start]): + if all(isinstance(v, str) for v in vars_to_warm_start): list_of_vars = [] for v in vars_to_warm_start: list_of_vars += ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES, scope=v) - elif all([checkpoint_utils._is_variable(v) for v in vars_to_warm_start]): # pylint: disable=protected-access + elif all(checkpoint_utils._is_variable(v) for v in vars_to_warm_start): # pylint: disable=protected-access list_of_vars = vars_to_warm_start else: raise ValueError("If `vars_to_warm_start` is a list, it must be all " diff --git a/tensorflow/tools/api/tests/api_compatibility_test.py b/tensorflow/tools/api/tests/api_compatibility_test.py index b0f3742af1..cba6246fef 100644 --- a/tensorflow/tools/api/tests/api_compatibility_test.py +++ b/tensorflow/tools/api/tests/api_compatibility_test.py @@ -126,9 +126,9 @@ def _FilterNonCoreGoldenFiles(golden_file_list): filtered_file_list = [] filtered_package_prefixes = ['tensorflow.%s.' % p for p in _NON_CORE_PACKAGES] for f in golden_file_list: - if any([ + if any( f.rsplit('/')[-1].startswith(pre) for pre in filtered_package_prefixes - ]): + ): continue filtered_file_list.append(f) return filtered_file_list -- GitLab From c16394423c5226d7633d7255c37df762e85f6584 Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Wed, 21 Nov 2018 10:48:49 -0800 Subject: [PATCH 209/672] Refactor to allow creation of an object graph proto with no variable values Will be useful for creating a SavedModel object proto PiperOrigin-RevId: 222430965 --- .../python/training/checkpointable/BUILD | 2 +- .../python/training/checkpointable/util.py | 80 ++++++++++++------- .../training/checkpointable/util_test.py | 16 +++- 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/tensorflow/python/training/checkpointable/BUILD b/tensorflow/python/training/checkpointable/BUILD index d26932c1aa..f97f42a659 100644 --- a/tensorflow/python/training/checkpointable/BUILD +++ b/tensorflow/python/training/checkpointable/BUILD @@ -152,7 +152,7 @@ py_test( "//tensorflow/python:variable_scope", "//tensorflow/python/eager:backprop", "//tensorflow/python/eager:context", - "//tensorflow/python/eager:function", + "//tensorflow/python/eager:def_function", "//tensorflow/python/eager:test", "//tensorflow/python/keras:engine", "//tensorflow/python/keras:layers", diff --git a/tensorflow/python/training/checkpointable/util.py b/tensorflow/python/training/checkpointable/util.py index f45f7445f1..85844393f3 100644 --- a/tensorflow/python/training/checkpointable/util.py +++ b/tensorflow/python/training/checkpointable/util.py @@ -549,13 +549,11 @@ def _serialize_slot_variables(checkpointable_objects, node_ids, object_names): return slot_variables -def _serialize_checkpointables( - checkpointable_objects, node_ids, object_names, slot_variables, +def _add_attributes_to_object_graph( + checkpointable_objects, object_graph_proto, node_ids, object_names, saveables_cache, object_map): - """Name non-slot `Checkpointable`s and add them to `object_graph_proto`.""" - object_graph_proto = ( - checkpointable_object_graph_pb2.CheckpointableObjectGraph()) - named_saveables = [] + """Create SaveableObjects and corresponding SerializedTensor protos.""" + named_saveable_objects = [] if saveables_cache is None: # No SaveableObject caching. Either we're executing eagerly, or building a # static save which is specialized to the current Python state. @@ -564,10 +562,9 @@ def _serialize_checkpointables( # If we are caching SaveableObjects, we need to build up a feed_dict with # functions computing volatile Python state to be saved with the checkpoint. feed_additions = {} - for checkpoint_id, checkpointable in enumerate(checkpointable_objects): + for checkpoint_id, (checkpointable, object_proto) in enumerate( + zip(checkpointable_objects, object_graph_proto.nodes)): assert node_ids[checkpointable] == checkpoint_id - object_proto = object_graph_proto.nodes.add() - object_proto.slot_variables.extend(slot_variables.get(checkpointable, ())) object_name = object_names[checkpointable] if object_map: object_to_save = object_map.get(checkpointable, checkpointable) @@ -645,14 +642,24 @@ def _serialize_checkpointables( "value.") % (checkpointable, new_feed_key)) feed_additions.update(saveable_feed_dict) - named_saveables.append(saveable) + named_saveable_objects.append(saveable) + return named_saveable_objects, feed_additions + + +def _make_object_graph_proto(checkpointable_objects, node_ids, slot_variables): + """Name non-slot `Checkpointable`s and add them to `object_graph_proto`.""" + object_graph_proto = ( + checkpointable_object_graph_pb2.CheckpointableObjectGraph()) + for checkpoint_id, checkpointable in enumerate(checkpointable_objects): + assert node_ids[checkpointable] == checkpoint_id + object_proto = object_graph_proto.nodes.add() + object_proto.slot_variables.extend(slot_variables.get(checkpointable, ())) for child in checkpointable._checkpoint_dependencies: # pylint: disable=protected-access child_proto = object_proto.children.add() child_proto.node_id = node_ids[child.ref] child_proto.local_name = child.name - - return named_saveables, object_graph_proto, feed_additions + return object_graph_proto def _serialize_gathered_objects( @@ -668,13 +675,18 @@ def _serialize_gathered_objects( checkpointable_objects=checkpointable_objects, node_ids=node_ids, object_names=object_names) - return _serialize_checkpointables( + object_graph_proto = _make_object_graph_proto( checkpointable_objects=checkpointable_objects, node_ids=node_ids, + slot_variables=slot_variables) + named_saveable_objects, feed_additions = _add_attributes_to_object_graph( + checkpointable_objects=checkpointable_objects, + object_graph_proto=object_graph_proto, + node_ids=node_ids, object_names=object_names, - slot_variables=slot_variables, saveables_cache=saveables_cache, object_map=object_map) + return named_saveable_objects, object_graph_proto, feed_additions def _serialize_object_graph(root_checkpointable, saveables_cache): @@ -716,6 +728,23 @@ def named_saveables(root_checkpointable): return _serialize_object_graph(root_checkpointable, None)[0] +def _find_objects(root_checkpointable): + """Find and number objects which are dependencies of `root_checkpointable`.""" + checkpointable_objects, path_to_root = ( + _breadth_first_checkpointable_traversal(root_checkpointable)) + object_names = _ObjectIdentityDictionary() + for obj, path in path_to_root.items(): + object_names[obj] = _object_prefix_from_path(path) + node_ids = _ObjectIdentityDictionary() + for node_id, node in enumerate(checkpointable_objects): + node_ids[node] = node_id + slot_variables = _serialize_slot_variables( + checkpointable_objects=checkpointable_objects, + node_ids=node_ids, + object_names=object_names) + return checkpointable_objects, node_ids, slot_variables + + def list_objects(root_checkpointable): """Traverse the object graph and list all accessible objects. @@ -730,23 +759,18 @@ def list_objects(root_checkpointable): Returns: A flat list of objects. """ - # TODO(allenl): Extract out gathering logic so the naming logic doesn't have - # to run. - checkpointable_objects, path_to_root = ( - _breadth_first_checkpointable_traversal(root_checkpointable)) - object_names = _ObjectIdentityDictionary() - for obj, path in path_to_root.items(): - object_names[obj] = _object_prefix_from_path(path) - node_ids = _ObjectIdentityDictionary() - for node_id, node in enumerate(checkpointable_objects): - node_ids[node] = node_id - _serialize_slot_variables( - checkpointable_objects=checkpointable_objects, - node_ids=node_ids, - object_names=object_names) + checkpointable_objects, _, _ = _find_objects(root_checkpointable) return checkpointable_objects +def make_object_graph_without_attributes(root_checkpointable): + """Construct a CheckpointableObjectGraph proto with no variable values.""" + checkpointable_objects, node_ids, slot_variables = _find_objects( + root_checkpointable) + return _make_object_graph_proto( + checkpointable_objects, node_ids, slot_variables) + + def gather_initializers(root_checkpointable): """Traverse the object graph and find initialization ops. diff --git a/tensorflow/python/training/checkpointable/util_test.py b/tensorflow/python/training/checkpointable/util_test.py index 1995514012..de9cac0863 100644 --- a/tensorflow/python/training/checkpointable/util_test.py +++ b/tensorflow/python/training/checkpointable/util_test.py @@ -26,7 +26,7 @@ from tensorflow.python import pywrap_tensorflow from tensorflow.python.client import session as session_lib from tensorflow.python.eager import backprop from tensorflow.python.eager import context -from tensorflow.python.eager import function +from tensorflow.python.eager import def_function from tensorflow.python.eager import test from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -44,6 +44,7 @@ from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables from tensorflow.python.training import adam from tensorflow.python.training import checkpoint_management +from tensorflow.python.training import momentum from tensorflow.python.training import saver as saver_lib from tensorflow.python.training import training_util from tensorflow.python.training.checkpointable import base @@ -198,6 +199,17 @@ class InterfaceTests(test.TestCase): with self.assertRaises(NotImplementedError): checkpoint_reversed.save(prefix) + @test_util.run_in_graph_and_eager_modes(assert_no_eager_garbage=True) + def test_object_graph_no_attributes(self): + root = tracking.Checkpointable() + root.v = resource_variable_ops.ResourceVariable(1.) + root.opt = momentum.MomentumOptimizer(0.01, 0.5) + root.opt.minimize(root.v.read_value) + object_graph = checkpointable_utils.make_object_graph_without_attributes( + root) + # Four objects: Root, v, opt, and a slot variable for v + self.assertEqual(4, len(object_graph.nodes)) + class _MirroringSaveable(saver_lib.BaseSaverBuilder.SaveableObject): @@ -632,7 +644,7 @@ class CheckpointingTests(test.TestCase): checkpoint_directory) status = root.restore(save_path=checkpoint_path) def train_fn(): - @function.defun + @def_function.function def _call_model(x): return model(x) with backprop.GradientTape() as tape: -- GitLab From f6ce9fd485e740f4ecded2d556a191a782b26808 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 21 Nov 2018 11:09:47 -0800 Subject: [PATCH 210/672] Automated rollback of commit 1fdd7c7408aa1cb37729e76a6e9fbfe8daa0b1f5 PiperOrigin-RevId: 222434204 --- .../compiler/tests/categorical_op_test.py | 10 +- tensorflow/compiler/tests/concat_ops_test.py | 8 +- tensorflow/compiler/tests/eager_test.py | 2 +- tensorflow/compiler/tests/function_test.py | 6 +- tensorflow/compiler/tests/lstm_test.py | 4 +- tensorflow/compiler/tests/placeholder_test.py | 2 +- tensorflow/compiler/tests/random_ops_test.py | 14 +- .../compiler/tests/tensor_array_ops_test.py | 2 +- .../compiler/tests/variable_ops_test.py | 30 +- .../autograph/integration_tests/keras_test.py | 2 +- .../integration_tests/list_literals_test.py | 2 +- .../speech_commands/input_data_test.py | 2 +- .../speech_commands/label_wav_test.py | 2 +- .../speech_commands/wav_to_features_test.py | 2 +- .../autograph/converters/call_trees_test.py | 2 +- .../python/autograph/converters/lists_test.py | 6 +- .../converters/side_effect_guards_test.py | 20 +- .../autograph/converters/slices_test.py | 2 +- tensorflow/python/autograph/impl/api_test.py | 46 +- .../autograph/lang/special_functions_test.py | 12 +- .../autograph/operators/control_flow_test.py | 14 +- .../operators/data_structures_test.py | 16 +- .../autograph/operators/logical_test.py | 14 +- .../autograph/operators/py_builtins_test.py | 28 +- .../python/autograph/operators/slices_test.py | 8 +- .../python/autograph/utils/misc_test.py | 4 +- .../python/autograph/utils/py_func_test.py | 18 +- .../autograph/utils/tensor_list_test.py | 4 +- .../client/session_clusterspec_prop_test.py | 6 +- tensorflow/python/client/timeline_test.py | 4 +- tensorflow/python/client/virtual_gpu_test.py | 2 +- .../kernel_tests/batch_dataset_op_test.py | 54 ++- .../bucket_by_sequence_length_test.py | 2 +- .../kernel_tests/copy_to_device_test.py | 84 ++-- .../experimental/kernel_tests/counter_test.py | 12 +- .../dense_to_sparse_batch_test.py | 8 +- .../directed_interleave_dataset_test.py | 6 +- .../kernel_tests/enumerate_dataset_test.py | 6 +- .../function_buffering_resource_test.py | 70 +-- .../kernel_tests/group_by_reducer_test.py | 6 +- .../kernel_tests/group_by_window_test.py | 52 +-- .../kernel_tests/ignore_errors_test.py | 16 +- .../kernel_tests/indexed_dataset_ops_test.py | 6 +- .../make_batched_features_dataset_test.py | 4 +- .../kernel_tests/make_csv_dataset_test.py | 2 +- .../make_tf_record_dataset_test.py | 6 +- .../kernel_tests/map_and_batch_test.py | 38 +- .../kernel_tests/map_defun_op_test.py | 2 +- .../kernel_tests/override_threadpool_test.py | 2 +- .../kernel_tests/parallel_interleave_test.py | 6 +- .../kernel_tests/prefetch_to_device_test.py | 26 +- .../experimental/kernel_tests/scan_test.py | 6 +- .../range_dataset_serialization_test.py | 26 +- .../serialization_integration_test.py | 4 +- .../kernel_tests/shuffle_and_repeat_test.py | 2 +- .../experimental/kernel_tests/sleep_test.py | 4 +- .../kernel_tests/sql_dataset_test.py | 97 ++-- .../kernel_tests/stats_dataset_ops_test.py | 58 ++- .../experimental/kernel_tests/unbatch_test.py | 12 +- .../experimental/kernel_tests/unique_test.py | 4 +- .../kernel_tests/batch_dataset_op_test.py | 26 +- .../kernel_tests/cache_dataset_op_test.py | 18 +- .../concatenate_dataset_op_test.py | 8 +- .../dataset_constructor_op_test.py | 44 +- .../dataset_from_generator_op_test.py | 78 ++-- .../kernel_tests/filter_dataset_op_test.py | 26 +- .../kernel_tests/flat_map_dataset_op_test.py | 20 +- .../interleave_dataset_op_test.py | 8 +- .../kernel_tests/iterator_ops_cluster_test.py | 12 +- .../data/kernel_tests/iterator_ops_test.py | 44 +- .../list_files_dataset_op_test.py | 2 +- .../data/kernel_tests/map_dataset_op_test.py | 126 +++--- .../multi_device_iterator_test.py | 68 +-- .../data/kernel_tests/optional_ops_test.py | 4 +- .../kernel_tests/prefetch_dataset_op_test.py | 2 +- .../kernel_tests/range_dataset_op_test.py | 116 ++--- .../kernel_tests/reader_dataset_ops_test.py | 112 ++--- .../kernel_tests/reduce_dataset_op_test.py | 11 +- .../kernel_tests/sequence_dataset_op_test.py | 20 +- .../kernel_tests/shuffle_dataset_op_test.py | 12 +- .../kernel_tests/window_dataset_op_test.py | 24 +- .../data/kernel_tests/zip_dataset_op_test.py | 6 +- tensorflow/python/data/util/convert_test.py | 8 +- .../python/debug/cli/analyzer_cli_test.py | 2 +- .../lib/debug_graph_reconstruction_test.py | 14 +- .../debug/lib/dist_session_debug_grpc_test.py | 8 +- .../debug/lib/session_debug_multi_gpu_test.py | 2 +- .../python/debug/lib/source_utils_test.py | 4 +- .../python/distribute/input_ops_test.py | 7 +- tensorflow/python/eager/def_function_test.py | 8 +- .../python/eager/function_gradients_test.py | 2 +- tensorflow/python/eager/function_test.py | 4 +- .../feature_column/feature_column_test.py | 8 +- .../feature_column/feature_column_v2_test.py | 11 +- tensorflow/python/framework/function_test.py | 50 +-- .../python/framework/graph_util_test.py | 10 +- tensorflow/python/framework/importer_test.py | 12 +- .../python/framework/meta_graph_test.py | 12 +- tensorflow/python/framework/ops_test.py | 6 +- .../python/framework/smart_cond_test.py | 8 +- .../python/framework/sparse_tensor_test.py | 2 +- .../python/framework/tensor_util_test.py | 2 +- .../python/grappler/constant_folding_test.py | 2 +- .../python/grappler/layout_optimizer_test.py | 48 +- .../python/grappler/memory_optimizer_test.py | 12 +- tensorflow/python/keras/backend_test.py | 2 +- .../python/keras/layers/recurrent_test.py | 4 +- .../python/kernel_tests/accumulate_n_test.py | 2 +- .../python/kernel_tests/array_ops_test.py | 14 +- .../python/kernel_tests/basic_gpu_test.py | 8 +- .../boosted_trees/quantile_ops_test.py | 4 +- .../boosted_trees/stats_ops_test.py | 30 +- .../python/kernel_tests/bucketize_op_test.py | 6 +- .../candidate_sampler_ops_test.py | 2 +- .../python/kernel_tests/cast_op_test.py | 2 +- .../python/kernel_tests/concat_op_test.py | 6 +- .../conditional_accumulator_test.py | 8 +- .../kernel_tests/control_flow_ops_py_test.py | 48 +- .../python/kernel_tests/conv_ops_3d_test.py | 10 +- .../python/kernel_tests/conv_ops_test.py | 12 +- .../python/kernel_tests/cwise_ops_test.py | 4 +- .../kernel_tests/decode_jpeg_op_test.py | 2 +- .../dense_update_ops_no_tsan_test.py | 8 +- .../kernel_tests/depthwise_conv_op_test.py | 6 +- .../distributions/categorical_test.py | 4 +- .../kernel_tests/dynamic_partition_op_test.py | 28 +- .../python/kernel_tests/fifo_queue_test.py | 84 ++-- .../kernel_tests/functional_ops_test.py | 46 +- .../kernel_tests/gradient_correctness_test.py | 8 +- .../python/kernel_tests/init_ops_test.py | 8 +- .../python/kernel_tests/lookup_ops_test.py | 2 +- tensorflow/python/kernel_tests/losses_test.py | 4 +- .../python/kernel_tests/map_stage_op_test.py | 22 +- .../kernel_tests/matrix_inverse_op_test.py | 2 +- .../kernel_tests/matrix_solve_op_test.py | 2 +- .../matrix_square_root_op_test.py | 2 +- .../python/kernel_tests/metrics_test.py | 419 +++++++++--------- .../neon_depthwise_conv_op_test.py | 6 +- .../python/kernel_tests/norm_op_test.py | 2 +- .../kernel_tests/nth_element_op_test.py | 2 +- .../kernel_tests/padding_fifo_queue_test.py | 88 ++-- .../parse_single_example_op_test.py | 2 +- .../python/kernel_tests/parsing_ops_test.py | 4 +- .../kernel_tests/pooling_ops_3d_test.py | 2 +- .../kernel_tests/priority_queue_test.py | 20 +- .../python/kernel_tests/py_func_test.py | 14 +- tensorflow/python/kernel_tests/qr_op_test.py | 2 +- .../random/multinomial_op_big_test.py | 6 +- .../random/multinomial_op_test.py | 12 +- .../kernel_tests/random/random_gamma_test.py | 2 +- .../kernel_tests/random/random_ops_test.py | 12 +- .../random/random_poisson_test.py | 2 +- .../random/random_shuffle_queue_test.py | 66 +-- .../python/kernel_tests/reader_ops_test.py | 2 +- .../python/kernel_tests/record_input_test.py | 16 +- .../python/kernel_tests/reduction_ops_test.py | 18 +- .../resource_variable_ops_test.py | 2 +- .../kernel_tests/scatter_nd_ops_test.py | 14 +- .../kernel_tests/self_adjoint_eig_op_test.py | 2 +- .../python/kernel_tests/session_ops_test.py | 22 +- tensorflow/python/kernel_tests/sets_test.py | 2 +- .../python/kernel_tests/shape_ops_test.py | 4 +- .../signal/reconstruction_ops_test.py | 8 +- .../python/kernel_tests/sparse_add_op_test.py | 8 +- .../kernel_tests/sparse_concat_op_test.py | 14 +- .../sparse_conditional_accumulator_test.py | 24 +- .../kernel_tests/sparse_cross_op_test.py | 34 +- .../python/kernel_tests/sparse_ops_test.py | 34 +- .../kernel_tests/sparse_reorder_op_test.py | 4 +- .../kernel_tests/sparse_reshape_op_test.py | 4 +- .../sparse_serialization_ops_test.py | 2 +- .../sparse_tensors_map_ops_test.py | 11 +- .../python/kernel_tests/stage_op_test.py | 18 +- .../kernel_tests/string_length_op_test.py | 2 +- .../kernel_tests/string_split_op_test.py | 28 +- .../kernel_tests/string_strip_op_test.py | 6 +- .../kernel_tests/summary_v1_audio_op_test.py | 2 +- .../kernel_tests/summary_v1_image_op_test.py | 4 +- .../kernel_tests/summary_v1_ops_test.py | 6 +- .../kernel_tests/summary_v1_tensor_op_test.py | 12 +- tensorflow/python/kernel_tests/svd_op_test.py | 4 +- .../python/kernel_tests/template_test.py | 8 +- .../kernel_tests/tensor_array_ops_test.py | 6 +- .../kernel_tests/unicode_transcode_op_test.py | 46 +- .../kernel_tests/variable_scope_test.py | 16 +- .../python/kernel_tests/while_v2_test.py | 56 +-- .../python/kernel_tests/xent_op_test.py | 4 +- .../python/layers/convolutional_test.py | 16 +- tensorflow/python/layers/core_test.py | 2 +- .../python/layers/normalization_test.py | 74 ++-- .../python/ops/control_flow_ops_test.py | 12 +- tensorflow/python/ops/gradients_test.py | 28 +- tensorflow/python/ops/image_grad_test.py | 8 +- tensorflow/python/ops/image_ops_test.py | 30 +- tensorflow/python/ops/init_ops_test.py | 4 +- tensorflow/python/ops/math_ops_test.py | 4 +- .../python/ops/nn_fused_batchnorm_test.py | 2 +- .../python/ops/parallel_for/gradients_test.py | 2 +- .../python/ops/quantized_conv_ops_test.py | 2 +- tensorflow/python/ops/quantized_ops_test.py | 4 +- .../ops/ragged/ragged_gather_nd_op_test.py | 2 +- .../python/profiler/model_analyzer_test.py | 30 +- .../python/profiler/profile_context_test.py | 8 +- tensorflow/python/saved_model/loader_test.py | 4 +- .../python/saved_model/saved_model_test.py | 42 +- .../python/saved_model/simple_save_test.py | 2 +- tensorflow/python/tools/strip_unused_test.py | 4 +- .../training/basic_session_run_hooks_test.py | 32 +- .../python/training/checkpoint_ops_test.py | 2 +- tensorflow/python/training/input_test.py | 54 +-- .../python/training/monitored_session_test.py | 16 +- .../python/training/moving_averages_test.py | 12 +- tensorflow/python/training/saver_test.py | 62 +-- .../training/server_lib_sparse_job_test.py | 2 +- tensorflow/python/training/supervisor_test.py | 10 +- .../training/warm_starting_util_test.py | 76 ++-- 216 files changed, 1980 insertions(+), 2004 deletions(-) diff --git a/tensorflow/compiler/tests/categorical_op_test.py b/tensorflow/compiler/tests/categorical_op_test.py index 15108487cf..f17e84df13 100644 --- a/tensorflow/compiler/tests/categorical_op_test.py +++ b/tensorflow/compiler/tests/categorical_op_test.py @@ -61,7 +61,7 @@ class CategoricalTest(xla_test.XLATestCase): random_seed.set_random_seed(1618) op = random_ops.multinomial(logits, num_samples, output_dtype=dtypes.int32) - d = self.evaluate(op) + d = sess.run(op) batch_size, num_classes = logits.shape freqs_mat = [] @@ -86,9 +86,9 @@ class CategoricalTest(xla_test.XLATestCase): # The random-number generator, if working correctly, should produce the # same output multiple times with low probability. - y = self.evaluate(x) - z = self.evaluate(x) - w = self.evaluate(x) + y = sess.run(x) + z = sess.run(x) + w = sess.run(x) # We use exact equality here. If the random-number generator is producing # deterministic output, all three outputs will be bitwise identical. @@ -113,7 +113,7 @@ class CategoricalTest(xla_test.XLATestCase): x = random_ops.multinomial( array_ops.ones(shape=[1, 20], dtype=dtype), 1000, output_dtype=output_dtype) - y = self.evaluate(x) + y = sess.run(x) self.assertTrue((y >= 0).sum() == 1000) self.assertTrue((y < 20).sum() == 1000) diff --git a/tensorflow/compiler/tests/concat_ops_test.py b/tensorflow/compiler/tests/concat_ops_test.py index deb9ac186e..30fbe6f701 100644 --- a/tensorflow/compiler/tests/concat_ops_test.py +++ b/tensorflow/compiler/tests/concat_ops_test.py @@ -337,7 +337,7 @@ class ConcatOffsetTest(xla_test.XLATestCase): s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = self.evaluate(off) + ans = sess.run(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) @@ -350,7 +350,7 @@ class PackTest(xla_test.XLATestCase): s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) packed = array_ops.stack([s0, s1, s2]) - ans = self.evaluate(packed) + ans = sess.run(packed) self.assertAllEqual(ans, [[2, 3, 5], [2, 7, 5], [2, 20, 5]]) def testScalars(self): @@ -360,7 +360,7 @@ class PackTest(xla_test.XLATestCase): s1 = constant_op.constant(3, dtypes.int32) s2 = constant_op.constant(5, dtypes.int32) packed = array_ops.stack([s0, s1, s2]) - ans = self.evaluate(packed) + ans = sess.run(packed) self.assertAllEqual(ans, [2, 3, 5]) def testEmpty(self): @@ -370,7 +370,7 @@ class PackTest(xla_test.XLATestCase): s1 = constant_op.constant([[]], dtypes.int32) s2 = constant_op.constant([[]], dtypes.int32) packed = array_ops.stack([s0, s1, s2]) - ans = self.evaluate(packed) + ans = sess.run(packed) self.assertAllEqual(ans, [[[]], [[]], [[]]]) diff --git a/tensorflow/compiler/tests/eager_test.py b/tensorflow/compiler/tests/eager_test.py index 76706ad40a..63cee550fd 100644 --- a/tensorflow/compiler/tests/eager_test.py +++ b/tensorflow/compiler/tests/eager_test.py @@ -106,7 +106,7 @@ class EagerTest(xla_test.XLATestCase): three = constant_op.constant(3) five = constant_op.constant(5) product = three * five - self.assertAllEqual(15, self.evaluate(product)) + self.assertAllEqual(15, sess.run(product)) def testDegenerateSlices(self): with self.test_scope(): diff --git a/tensorflow/compiler/tests/function_test.py b/tensorflow/compiler/tests/function_test.py index dd9b7f30ef..b1891b918c 100644 --- a/tensorflow/compiler/tests/function_test.py +++ b/tensorflow/compiler/tests/function_test.py @@ -50,7 +50,7 @@ class FunctionTest(xla_test.XLATestCase): b = constant_op.constant(bval, name="b") with self.test_scope(): call_f = Foo(a, b) - result = self.evaluate(call_f) + result = sess.run(call_f) self.assertAllClose(result, expected, rtol=1e-3) def testNestedFunctions(self): @@ -76,7 +76,7 @@ class FunctionTest(xla_test.XLATestCase): b = constant_op.constant(bval, name="b") with self.test_scope(): call_g = Foo(a, b) - result = self.evaluate(call_g) + result = sess.run(call_g) self.assertAllClose(result, expected, rtol=1e-3) def testFunctionMultipleRetvals(self): @@ -100,7 +100,7 @@ class FunctionTest(xla_test.XLATestCase): b = constant_op.constant(bval, name="b") with self.test_scope(): call_f = Foo(a, b) - result = self.evaluate(call_f) + result = sess.run(call_f) self.assertAllClose(result, expected, rtol=1e-3) def testCompileTimeConstantsInDefun(self): diff --git a/tensorflow/compiler/tests/lstm_test.py b/tensorflow/compiler/tests/lstm_test.py index fd02a50aff..265c0b6d14 100644 --- a/tensorflow/compiler/tests/lstm_test.py +++ b/tensorflow/compiler/tests/lstm_test.py @@ -88,7 +88,7 @@ class LSTMTest(test.TestCase): (basename, m_prev_scalar, c_prev_scalar, pad_scalar)) # Initialize variables and run the unrolled LSTM step. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) return sess.run([m, c]) def testLSTMCell(self): @@ -173,7 +173,7 @@ class LSTMTest(test.TestCase): (basename, m_init_scalar, c_init_scalar, pad_scalar)) # Initialize variables and run the unrolled LSTM layer. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) return sess.run(out_seq) def testLSTMLayer(self): diff --git a/tensorflow/compiler/tests/placeholder_test.py b/tensorflow/compiler/tests/placeholder_test.py index 9671ae0ae9..77bb839409 100644 --- a/tensorflow/compiler/tests/placeholder_test.py +++ b/tensorflow/compiler/tests/placeholder_test.py @@ -33,7 +33,7 @@ class PlaceholderTest(xla_test.XLATestCase): ph = array_ops.placeholder_with_default(v, shape=[]) out = ph * 2 sess.run(variables.variables_initializer([v])) - self.assertEqual(8.0, self.evaluate(out)) + self.assertEqual(8.0, sess.run(out)) def test_placeholder_with_default_fed(self): with self.cached_session() as sess, self.test_scope(): diff --git a/tensorflow/compiler/tests/random_ops_test.py b/tensorflow/compiler/tests/random_ops_test.py index 1e91390945..36ef6ed5fe 100644 --- a/tensorflow/compiler/tests/random_ops_test.py +++ b/tensorflow/compiler/tests/random_ops_test.py @@ -46,9 +46,9 @@ class RandomOpsTest(xla_test.XLATestCase): # The random-number generator, if working correctly, should produce the # same output multiple times with low probability. - y = self.evaluate(x) - z = self.evaluate(x) - w = self.evaluate(x) + y = sess.run(x) + z = sess.run(x) + w = sess.run(x) # We use exact equality here. If the random-number generator is producing # deterministic output, all three outputs will be bitwise identical. @@ -83,7 +83,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.test_scope(): x = random_ops.random_uniform( shape=[1000], dtype=dtype, minval=-2, maxval=33) - y = self.evaluate(x) + y = sess.run(x) self.assertTrue((y >= -2).sum() == 1000) self.assertTrue((y < 33).sum() == 1000) @@ -102,7 +102,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.cached_session() as sess: with self.test_scope(): x = random_ops.truncated_normal(shape=[count], dtype=dtype) - y = self.evaluate(x) + y = sess.run(x) def normal_cdf(x): return .5 * math.erfc(-x / math.sqrt(2)) @@ -148,7 +148,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.test_scope(): x = math_ops.range(1 << 16) shuffle = random_ops.random_shuffle(x) - result = self.evaluate(shuffle) + result = sess.run(shuffle) expected = range(1 << 16) # Compare sets to avoid randomness behavior changes but make sure still # have all the values. @@ -159,7 +159,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.test_scope(): x = array_ops.diag(math_ops.range(20)) shuffle = random_ops.random_shuffle(x) - result = self.evaluate(shuffle) + result = sess.run(shuffle) expected = np.diag(range(20)).flatten() # Compare sets to avoid randomness behavior changes but make sure still # have all the values. diff --git a/tensorflow/compiler/tests/tensor_array_ops_test.py b/tensorflow/compiler/tests/tensor_array_ops_test.py index d7e26d79c4..c8208adb58 100644 --- a/tensorflow/compiler/tests/tensor_array_ops_test.py +++ b/tensorflow/compiler/tests/tensor_array_ops_test.py @@ -505,7 +505,7 @@ class TensorArrayTest(xla_test.XLATestCase): [-0.5, 1.5], # read(0) gradient [20.0, 30.0, 40.0, 50.0], # concat gradient ]) - grad_vals = self.evaluate(grad_r) # 2 + 2 entries + grad_vals = sess.run(grad_r) # 2 + 2 entries self.assertAllClose([2.0 - 0.5 + 20.0, 3.0 + 1.5 + 30.0], grad_vals[0]) self.assertAllEqual([4.0 + 40.0, 5.0 + 50.0], grad_vals[1]) diff --git a/tensorflow/compiler/tests/variable_ops_test.py b/tensorflow/compiler/tests/variable_ops_test.py index e776c8a951..77cdeac816 100644 --- a/tensorflow/compiler/tests/variable_ops_test.py +++ b/tensorflow/compiler/tests/variable_ops_test.py @@ -229,7 +229,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_add( handle, [0], constant_op.constant([[2]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertAllEqual(self.evaluate(read), [[3], [7]]) + self.assertAllEqual(sess.run(read), [[3], [7]]) def testScatterSub(self): with self.test_session() as sess, self.test_scope(): @@ -242,7 +242,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_sub( handle, [1], constant_op.constant([[2]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertAllEqual(self.evaluate(read), [[4], [-1]]) + self.assertAllEqual(sess.run(read), [[4], [-1]]) def testScatterMul(self): with self.test_session() as sess, self.test_scope(): @@ -255,7 +255,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_mul( handle, [0], constant_op.constant([[5]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[5]]) + self.assertEqual(sess.run(read), [[5]]) def testScatterDiv(self): with self.test_session() as sess, self.test_scope(): @@ -268,7 +268,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_div( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertAllEqual(self.evaluate(read), [[2]]) + self.assertAllEqual(sess.run(read), [[2]]) def testScatterMin(self): with self.test_session() as sess, self.test_scope(): @@ -281,7 +281,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_min( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[3]]) + self.assertEqual(sess.run(read), [[3]]) def testScatterMax(self): with self.test_session() as sess, self.test_scope(): @@ -294,7 +294,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_max( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[6]]) + self.assertEqual(sess.run(read), [[6]]) def testScatterUpdate(self): with self.test_session() as sess, self.test_scope(): @@ -307,7 +307,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_update( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[3]]) + self.assertEqual(sess.run(read), [[3]]) def testScatterAddScalar(self): with self.test_session() as sess, self.test_scope(): @@ -320,7 +320,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_add( handle, [0], constant_op.constant(2, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[3]]) + self.assertEqual(sess.run(read), [[3]]) def testScatterSubScalar(self): with self.test_session() as sess, self.test_scope(): @@ -333,7 +333,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_sub( handle, [0], constant_op.constant(2, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[-1]]) + self.assertEqual(sess.run(read), [[-1]]) def testScatterMulScalar(self): with self.test_session() as sess, self.test_scope(): @@ -346,7 +346,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_mul( handle, [0], constant_op.constant(5, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[5]]) + self.assertEqual(sess.run(read), [[5]]) def testScatterDivScalar(self): with self.test_session() as sess, self.test_scope(): @@ -359,7 +359,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_div( handle, [0], constant_op.constant(3, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[2]]) + self.assertEqual(sess.run(read), [[2]]) def testScatterMinScalar(self): with self.test_session() as sess, self.test_scope(): @@ -372,7 +372,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_min( handle, [0], constant_op.constant(3, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[3]]) + self.assertEqual(sess.run(read), [[3]]) def testScatterMaxScalar(self): with self.test_session() as sess, self.test_scope(): @@ -385,7 +385,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_max( handle, [0], constant_op.constant(3, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(self.evaluate(read), [[6]]) + self.assertEqual(sess.run(read), [[6]]) def testScatterNdAddOps(self): with self.test_session() as sess, self.test_scope(): @@ -400,7 +400,7 @@ class VariableOpsTest(xla_test.XLATestCase): sess.run(gen_state_ops.resource_scatter_nd_add(handle, indices, updates)) read = resource_variable_ops.read_variable_op( handle, dtype=dtypes.float32) - self.assertAllClose(expected, self.evaluate(read)) + self.assertAllClose(expected, sess.run(read)) def testScatterNdUpdateAddOps(self): with self.test_session() as sess, self.test_scope(): @@ -416,7 +416,7 @@ class VariableOpsTest(xla_test.XLATestCase): gen_state_ops.resource_scatter_nd_update(handle, indices, updates)) read = resource_variable_ops.read_variable_op( handle, dtype=dtypes.float32) - self.assertAllClose(expected, self.evaluate(read)) + self.assertAllClose(expected, sess.run(read)) class StridedSliceAssignChecker(object): diff --git a/tensorflow/examples/autograph/integration_tests/keras_test.py b/tensorflow/examples/autograph/integration_tests/keras_test.py index 9828ac34dc..dca7c07b47 100644 --- a/tensorflow/examples/autograph/integration_tests/keras_test.py +++ b/tensorflow/examples/autograph/integration_tests/keras_test.py @@ -96,7 +96,7 @@ class KerasTest(tf.test.TestCase): sess.run(init) sample_input = tf.random_uniform((1, 10, 10, 1)) output = model(sample_input) # pylint: disable=not-callable - self.assertEqual(self.evaluate(output).shape, (1, 3)) + self.assertEqual(sess.run(output).shape, (1, 3)) if __name__ == '__main__': diff --git a/tensorflow/examples/autograph/integration_tests/list_literals_test.py b/tensorflow/examples/autograph/integration_tests/list_literals_test.py index e85d4abcfc..917f5ff9d8 100644 --- a/tensorflow/examples/autograph/integration_tests/list_literals_test.py +++ b/tensorflow/examples/autograph/integration_tests/list_literals_test.py @@ -34,7 +34,7 @@ class ListLiteralsTest(tf.test.TestCase): result = converted() with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(result), [1, 2, 3]) + self.assertAllEqual(sess.run(result), [1, 2, 3]) if __name__ == '__main__': diff --git a/tensorflow/examples/speech_commands/input_data_test.py b/tensorflow/examples/speech_commands/input_data_test.py index 33b58b9d09..b766ba6de0 100644 --- a/tensorflow/examples/speech_commands/input_data_test.py +++ b/tensorflow/examples/speech_commands/input_data_test.py @@ -35,7 +35,7 @@ class InputDataTest(test.TestCase): with self.cached_session() as sess: sample_data = tf.zeros([32000, 2]) wav_encoder = contrib_audio.encode_wav(sample_data, 16000) - wav_data = self.evaluate(wav_encoder) + wav_data = sess.run(wav_encoder) return wav_data def _saveTestWavFile(self, filename, wav_data): diff --git a/tensorflow/examples/speech_commands/label_wav_test.py b/tensorflow/examples/speech_commands/label_wav_test.py index 77a88f98e1..f0af2a4798 100644 --- a/tensorflow/examples/speech_commands/label_wav_test.py +++ b/tensorflow/examples/speech_commands/label_wav_test.py @@ -33,7 +33,7 @@ class LabelWavTest(test.TestCase): with self.cached_session() as sess: sample_data = tf.zeros([1000, 2]) wav_encoder = contrib_audio.encode_wav(sample_data, 16000) - wav_data = self.evaluate(wav_encoder) + wav_data = sess.run(wav_encoder) return wav_data def _saveTestWavFile(self, filename, wav_data): diff --git a/tensorflow/examples/speech_commands/wav_to_features_test.py b/tensorflow/examples/speech_commands/wav_to_features_test.py index cb8ea912fa..87f2987693 100644 --- a/tensorflow/examples/speech_commands/wav_to_features_test.py +++ b/tensorflow/examples/speech_commands/wav_to_features_test.py @@ -33,7 +33,7 @@ class WavToFeaturesTest(test.TestCase): with self.cached_session() as sess: sample_data = tf.zeros([32000, 2]) wav_encoder = contrib_audio.encode_wav(sample_data, 16000) - wav_data = self.evaluate(wav_encoder) + wav_data = sess.run(wav_encoder) return wav_data def _saveTestWavFile(self, filename, wav_data): diff --git a/tensorflow/python/autograph/converters/call_trees_test.py b/tensorflow/python/autograph/converters/call_trees_test.py index 892f90e350..916c736fb4 100644 --- a/tensorflow/python/autograph/converters/call_trees_test.py +++ b/tensorflow/python/autograph/converters/call_trees_test.py @@ -113,7 +113,7 @@ class CallTreesTest(converter_testing.TestCase): with self.compiled(node, ns) as result: with self.cached_session() as sess: result_tensor = result.test_fn(constant_op.constant(1)) - self.assertEquals(self.evaluate(result_tensor), 3) + self.assertEquals(sess.run(result_tensor), 3) def test_call_to_decorated_function(self): diff --git a/tensorflow/python/autograph/converters/lists_test.py b/tensorflow/python/autograph/converters/lists_test.py index 8c8135acef..f6da845fcc 100644 --- a/tensorflow/python/autograph/converters/lists_test.py +++ b/tensorflow/python/autograph/converters/lists_test.py @@ -68,7 +68,7 @@ class ListTest(converter_testing.TestCase): with self.cached_session() as sess: tl = result.test_fn() r = list_ops.tensor_list_stack(tl, dtypes.int32) - self.assertAllEqual(self.evaluate(r), [1, 2, 3]) + self.assertAllEqual(sess.run(r), [1, 2, 3]) def test_list_pop(self): @@ -91,8 +91,8 @@ class ListTest(converter_testing.TestCase): with self.cached_session() as sess: ts, tl = result.test_fn() r = list_ops.tensor_list_stack(tl, dtypes.int32) - self.assertAllEqual(self.evaluate(r), [1, 2]) - self.assertAllEqual(self.evaluate(ts), 3) + self.assertAllEqual(sess.run(r), [1, 2]) + self.assertAllEqual(sess.run(ts), 3) def test_double_list_pop(self): diff --git a/tensorflow/python/autograph/converters/side_effect_guards_test.py b/tensorflow/python/autograph/converters/side_effect_guards_test.py index e72b5eac32..cef3199169 100644 --- a/tensorflow/python/autograph/converters/side_effect_guards_test.py +++ b/tensorflow/python/autograph/converters/side_effect_guards_test.py @@ -48,12 +48,12 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - self.evaluate(v.initializer) + sess.run(v.initializer) sess.run(result.test_fn(v)) # TODO(mdan): Add support for this use case. # Right now the variable `a` is not conditioned on the `assign` because # there's no way to add control dependencies to a variable object. - self.assertEqual(2, self.evaluate(v)) + self.assertEqual(2, sess.run(v)) def test_side_effect_on_used_variable(self): @@ -69,11 +69,11 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - self.evaluate(v.initializer) + sess.run(v.initializer) sess.run(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. # Right now it's 3 or 4 based on whether the read is synchronized. - self.assertEqual(3, self.evaluate(v)) + self.assertEqual(3, sess.run(v)) def test_side_effect_on_tensor(self): @@ -109,10 +109,10 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign_add) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - self.evaluate(v.initializer) + sess.run(v.initializer) sess.run(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. - self.assertEqual(4, self.evaluate(v)) + self.assertEqual(4, sess.run(v)) def test_multiline_nested_block(self): @@ -130,10 +130,10 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign, ops.name_scope) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - self.evaluate(v.initializer) + sess.run(v.initializer) sess.run(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. - self.assertEqual(3, self.evaluate(v)) + self.assertEqual(3, sess.run(v)) def test_multiline_block_unsafe(self): @@ -153,10 +153,10 @@ class SideEffectGuardsTest(converter_testing.TestCase): state_ops.assign_add) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - self.evaluate(v.initializer) + sess.run(v.initializer) sess.run(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. - self.assertEqual(4, self.evaluate(v)) + self.assertEqual(4, sess.run(v)) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/converters/slices_test.py b/tensorflow/python/autograph/converters/slices_test.py index bd049afdfc..e190a7cfe8 100644 --- a/tensorflow/python/autograph/converters/slices_test.py +++ b/tensorflow/python/autograph/converters/slices_test.py @@ -49,7 +49,7 @@ class SliceTest(converter_testing.TestCase): tl = list_ops.tensor_list_from_tensor( [1, 2], element_shape=constant_op.constant([], dtype=dtypes.int32)) y = result.test_fn(tl) - self.assertEqual(2, self.evaluate(y)) + self.assertEqual(2, sess.run(y)) def test_index_access_multiple_definitions(self): diff --git a/tensorflow/python/autograph/impl/api_test.py b/tensorflow/python/autograph/impl/api_test.py index 44cb99d657..ef577568c4 100644 --- a/tensorflow/python/autograph/impl/api_test.py +++ b/tensorflow/python/autograph/impl/api_test.py @@ -63,7 +63,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], self.evaluate(x).tolist()) + self.assertListEqual([0, 1], sess.run(x).tolist()) def test_decorator_does_not_recurse(self): @@ -83,7 +83,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], self.evaluate(x).tolist()) + self.assertListEqual([0, 1], sess.run(x).tolist()) def test_decorator_calls_unconverted_graph(self): @@ -104,7 +104,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], self.evaluate(x).tolist()) + self.assertListEqual([0, 1], sess.run(x).tolist()) def test_decorator_calls_unconverted_py_func(self): @@ -130,7 +130,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], self.evaluate(x).tolist()) + self.assertListEqual([0, 1], sess.run(x).tolist()) def test_decorator_calls_decorated(self): @@ -153,7 +153,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], self.evaluate(x).tolist()) + self.assertListEqual([0, 1], sess.run(x).tolist()) def test_decorator_preserves_argspec(self): @@ -192,7 +192,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], self.evaluate(x).tolist()) + self.assertListEqual([0, 1], sess.run(x).tolist()) def test_converted_call_builtin(self): x = api.converted_call(range, None, converter.ConversionOptions(), 3) @@ -208,7 +208,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = api.converted_call(test_fn, None, converter.ConversionOptions(), constant_op.constant(-1)) - self.assertEqual(1, self.evaluate(x)) + self.assertEqual(1, sess.run(x)) def test_converted_call_method_explicit_owner(self): # TODO(mdan): Implement. @@ -234,7 +234,7 @@ class ApiTest(test.TestCase): tc = TestClass(constant_op.constant(-1)) x = api.converted_call(tc.test_method, None, converter.ConversionOptions(), tc) - self.assertEqual(1, self.evaluate(x)) + self.assertEqual(1, sess.run(x)) def test_converted_call_method_by_class(self): @@ -252,7 +252,7 @@ class ApiTest(test.TestCase): tc = TestClass(constant_op.constant(-1)) x = api.converted_call(TestClass.test_method, None, converter.ConversionOptions(), tc) - self.assertEqual(1, self.evaluate(x)) + self.assertEqual(1, sess.run(x)) def test_converted_call_callable_object(self): @@ -269,7 +269,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: tc = TestClass(constant_op.constant(-1)) x = api.converted_call(tc, None, converter.ConversionOptions()) - self.assertEqual(1, self.evaluate(x)) + self.assertEqual(1, sess.run(x)) def test_converted_call_constructor(self): @@ -288,7 +288,7 @@ class ApiTest(test.TestCase): constant_op.constant(-1)) # tc is now a converted object. x = tc.test_method() - self.assertEqual(1, self.evaluate(x)) + self.assertEqual(1, sess.run(x)) def test_converted_call_already_converted(self): @@ -298,12 +298,12 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = api.converted_call(f, None, converter.ConversionOptions(), constant_op.constant(0)) - self.assertTrue(self.evaluate(x)) + self.assertTrue(sess.run(x)) converted_f = api.to_graph(f) x = api.converted_call(converted_f, None, converter.ConversionOptions(), constant_op.constant(0)) - self.assertTrue(self.evaluate(x)) + self.assertTrue(sess.run(x)) def test_converted_call_no_user_code(self): @@ -334,8 +334,8 @@ class ApiTest(test.TestCase): constant_op.constant([[0.0]]), training=True) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - self.assertAllEqual([[0.0, 0.0]], self.evaluate(x)) + sess.run(variables.global_variables_initializer()) + self.assertAllEqual([[0.0, 0.0]], sess.run(x)) def test_converted_call_whitelisted_method_extra_self(self): @@ -349,8 +349,8 @@ class ApiTest(test.TestCase): model, constant_op.constant([[0.0]]), training=True) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - self.assertAllEqual([[0.0, 0.0]], self.evaluate(x)) + sess.run(variables.global_variables_initializer()) + self.assertAllEqual([[0.0, 0.0]], sess.run(x)) def test_converted_call_whitelisted_method_via_owner(self): @@ -364,8 +364,8 @@ class ApiTest(test.TestCase): constant_op.constant([[0.0]]), training=True) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - self.assertAllEqual([[0.0, 0.0]], self.evaluate(x)) + sess.run(variables.global_variables_initializer()) + self.assertAllEqual([[0.0, 0.0]], sess.run(x)) def test_converted_call_lambda(self): @@ -376,8 +376,8 @@ class ApiTest(test.TestCase): x = api.converted_call(l, None, opts, constant_op.constant(0)) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - self.assertAllEqual(True, self.evaluate(x)) + sess.run(variables.global_variables_initializer()) + self.assertAllEqual(True, sess.run(x)) def test_to_graph_basic(self): @@ -390,7 +390,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = compiled_fn(constant_op.constant([4, 8]), 4) - self.assertListEqual([1, 2], self.evaluate(x).tolist()) + self.assertListEqual([1, 2], sess.run(x).tolist()) def test_to_graph_with_defaults(self): @@ -405,7 +405,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = compiled_fn(constant_op.constant([4, 8])) - self.assertListEqual([1, 2], self.evaluate(x).tolist()) + self.assertListEqual([1, 2], sess.run(x).tolist()) def test_to_code_basic(self): diff --git a/tensorflow/python/autograph/lang/special_functions_test.py b/tensorflow/python/autograph/lang/special_functions_test.py index 8d40f4036c..123ee65b32 100644 --- a/tensorflow/python/autograph/lang/special_functions_test.py +++ b/tensorflow/python/autograph/lang/special_functions_test.py @@ -36,7 +36,7 @@ class SpecialFunctionsTest(test.TestCase): python_one = special_functions.match_staging_level(1, 1) with self.cached_session() as sess: self.assertTrue(tensor_util.is_tensor(tensor_one)) - self.assertAllEqual(self.evaluate(tensor_one), 1) + self.assertAllEqual(sess.run(tensor_one), 1) self.assertEqual(python_one, 1) def test_tensor_list_empty_list(self): @@ -45,21 +45,21 @@ class SpecialFunctionsTest(test.TestCase): element_shape=()) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(sl), []) + self.assertAllEqual(sess.run(sl), []) l = special_functions.tensor_list((), element_dtype=dtypes.int32, element_shape=()) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(sl), []) + self.assertAllEqual(sess.run(sl), []) def test_tensor_list_tensor(self): l = special_functions.tensor_list( constant_op.constant([], dtype=dtypes.int32)) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(sl), []) + self.assertAllEqual(sess.run(sl), []) def test_tensor_list_unsupported_initializer(self): with self.assertRaisesRegexp(ValueError, 'unknown type'): @@ -76,7 +76,7 @@ class SpecialFunctionsTest(test.TestCase): l = special_functions.tensor_list(elements) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(sl), [[1, 2], [3, 4]]) + self.assertAllEqual(sess.run(sl), [[1, 2], [3, 4]]) def test_tensor_list_array_from_elements(self): elements = [constant_op.constant([1, 2]), constant_op.constant([3, 4])] @@ -84,7 +84,7 @@ class SpecialFunctionsTest(test.TestCase): l = special_functions.tensor_list(elements, use_tensor_array=True) sl = l.stack() with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(sl), [[1, 2], [3, 4]]) + self.assertAllEqual(sess.run(sl), [[1, 2], [3, 4]]) def test_stack(self): self.assertEqual(special_functions.stack(1, strict=False), 1) diff --git a/tensorflow/python/autograph/operators/control_flow_test.py b/tensorflow/python/autograph/operators/control_flow_test.py index 05b5660941..2dea18dc5f 100644 --- a/tensorflow/python/autograph/operators/control_flow_test.py +++ b/tensorflow/python/autograph/operators/control_flow_test.py @@ -35,7 +35,7 @@ class ForLoopTest(test.TestCase): body=lambda i, s: (s + i,), init_state=(0,)) with self.cached_session() as sess: - self.assertEqual((10,), self.evaluate(s)) + self.assertEqual((10,), sess.run(s)) def test_python(self): s = control_flow.for_stmt( @@ -53,7 +53,7 @@ class ForLoopTest(test.TestCase): body=lambda i, s: (s + i,), init_state=(0,)) with self.cached_session() as sess: - self.assertEqual((10,), self.evaluate(s)) + self.assertEqual((10,), sess.run(s)) class WhileLoopTest(test.TestCase): @@ -66,7 +66,7 @@ class WhileLoopTest(test.TestCase): init_state=(0, 0), extra_deps=(n,)) with self.cached_session() as sess: - self.assertEqual((5, 10), self.evaluate(results)) + self.assertEqual((5, 10), sess.run(results)) def test_python(self): n = 5 @@ -90,9 +90,9 @@ class IfStmtTest(test.TestCase): def test_tensor(self): with self.cached_session() as sess: t = self.single_return_if_stmt(constant_op.constant(True)) - self.assertEqual(1, self.evaluate(t)) + self.assertEqual(1, sess.run(t)) t = self.single_return_if_stmt(constant_op.constant(False)) - self.assertEqual(-1, self.evaluate(t)) + self.assertEqual(-1, sess.run(t)) def test_python(self): self.assertEqual(1, self.single_return_if_stmt(True)) @@ -101,9 +101,9 @@ class IfStmtTest(test.TestCase): def test_tensor_multiple_returns(self): with self.cached_session() as sess: t = self.multi_return_if_stmt(constant_op.constant(True)) - self.assertAllEqual([1, 2], self.evaluate(t)) + self.assertAllEqual([1, 2], sess.run(t)) t = self.multi_return_if_stmt(constant_op.constant(False)) - self.assertAllEqual([-1, -2], self.evaluate(t)) + self.assertAllEqual([-1, -2], sess.run(t)) def test_python_multiple_returns(self): self.assertEqual((1, 2), self.multi_return_if_stmt(True)) diff --git a/tensorflow/python/autograph/operators/data_structures_test.py b/tensorflow/python/autograph/operators/data_structures_test.py index dc50edb4c9..72476ccb6b 100644 --- a/tensorflow/python/autograph/operators/data_structures_test.py +++ b/tensorflow/python/autograph/operators/data_structures_test.py @@ -43,7 +43,7 @@ class ListTest(test.TestCase): l = data_structures.tf_tensor_list_new([3, 4, 5]) t = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(t), [3, 4, 5]) + self.assertAllEqual(sess.run(t), [3, 4, 5]) def test_tf_tensor_list_new_empty(self): l = data_structures.tf_tensor_list_new([], @@ -51,13 +51,13 @@ class ListTest(test.TestCase): element_shape=()) t = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(t), []) + self.assertAllEqual(sess.run(t), []) def test_tf_tensor_list_new_from_tensor(self): l = data_structures.tf_tensor_list_new(constant_op.constant([3, 4, 5])) t = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(t), [3, 4, 5]) + self.assertAllEqual(sess.run(t), [3, 4, 5]) def test_tf_tensor_list_new_illegal_input(self): with self.assertRaises(ValueError): @@ -77,7 +77,7 @@ class ListTest(test.TestCase): l = data_structures.tf_tensor_array_new([3, 4, 5]) t = l.stack() with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(t), [3, 4, 5]) + self.assertAllEqual(sess.run(t), [3, 4, 5]) def test_tf_tensor_array_new_illegal_input(self): with self.assertRaises(ValueError): @@ -102,7 +102,7 @@ class ListTest(test.TestCase): t = list_ops.tensor_list_stack(l, element_dtype=x.dtype) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(t), [[1, 2, 3]]) + self.assertAllEqual(sess.run(t), [[1, 2, 3]]) def test_append_tensorarray(self): l = tensor_array_ops.TensorArray(dtypes.int32, size=0, dynamic_size=True) @@ -131,10 +131,10 @@ class ListTest(test.TestCase): with self.cached_session() as sess: l, x = data_structures.list_pop(l, None, opts) - self.assertAllEqual(self.evaluate(x), [3, 4]) + self.assertAllEqual(sess.run(x), [3, 4]) t = list_ops.tensor_list_stack(l, element_dtype=initial_list.dtype) - self.assertAllEqual(self.evaluate(t), [[1, 2]]) + self.assertAllEqual(sess.run(t), [[1, 2]]) def test_pop_python(self): l = [1, 2, 3] @@ -152,7 +152,7 @@ class ListTest(test.TestCase): with self.cached_session() as sess: t = data_structures.list_stack(l, opts) - self.assertAllEqual(sess.run(t), self.evaluate(initial_list)) + self.assertAllEqual(sess.run(t), sess.run(initial_list)) def test_stack_tensor_list_empty(self): l = list_ops.empty_tensor_list( diff --git a/tensorflow/python/autograph/operators/logical_test.py b/tensorflow/python/autograph/operators/logical_test.py index ebf6458f01..d6649f7b2b 100644 --- a/tensorflow/python/autograph/operators/logical_test.py +++ b/tensorflow/python/autograph/operators/logical_test.py @@ -45,11 +45,11 @@ class LogicalOperatorsTest(test.TestCase): def test_and_tf(self): with self.cached_session() as sess: t = logical.and_(self._tf_true, self._tf_true) - self.assertEqual(self.evaluate(t), True) + self.assertEqual(sess.run(t), True) t = logical.and_(self._tf_true, lambda: True) - self.assertEqual(self.evaluate(t), True) + self.assertEqual(sess.run(t), True) t = logical.and_(self._tf_false, lambda: True) - self.assertEqual(self.evaluate(t), False) + self.assertEqual(sess.run(t), False) # TODO(mdan): Add a test for ops with side effects. def test_or_python(self): @@ -63,11 +63,11 @@ class LogicalOperatorsTest(test.TestCase): def test_or_tf(self): with self.cached_session() as sess: t = logical.or_(self._tf_false, self._tf_true) - self.assertEqual(self.evaluate(t), True) + self.assertEqual(sess.run(t), True) t = logical.or_(self._tf_false, lambda: True) - self.assertEqual(self.evaluate(t), True) + self.assertEqual(sess.run(t), True) t = logical.or_(self._tf_true, lambda: True) - self.assertEqual(self.evaluate(t), True) + self.assertEqual(sess.run(t), True) # TODO(mdan): Add a test for ops with side effects. def test_not_python(self): @@ -78,7 +78,7 @@ class LogicalOperatorsTest(test.TestCase): def test_not_tf(self): with self.cached_session() as sess: t = logical.not_(self._tf_false()) - self.assertEqual(self.evaluate(t), True) + self.assertEqual(sess.run(t), True) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/operators/py_builtins_test.py b/tensorflow/python/autograph/operators/py_builtins_test.py index 4d9eec77c3..443e30a475 100644 --- a/tensorflow/python/autograph/operators/py_builtins_test.py +++ b/tensorflow/python/autograph/operators/py_builtins_test.py @@ -38,29 +38,29 @@ class PyBuiltinsTest(test.TestCase): self.assertEqual(py_builtins.abs_(-1), 1) with self.cached_session() as sess: t = py_builtins.abs_(constant_op.constant(-1)) - self.assertEqual(self.evaluate(t), 1) + self.assertEqual(sess.run(t), 1) t = py_builtins.abs_(constant_op.constant([-1, 2, -3])) - self.assertAllEqual(self.evaluate(t), [1, 2, 3]) + self.assertAllEqual(sess.run(t), [1, 2, 3]) def test_float(self): self.assertEqual(py_builtins.float_(10), 10.0) self.assertEqual(py_builtins.float_('10.0'), 10.0) with self.cached_session() as sess: t = py_builtins.float_(constant_op.constant(1, dtype=dtypes.int64)) - self.assertEqual(self.evaluate(t), 1.0) + self.assertEqual(sess.run(t), 1.0) st = py_builtins.float_(constant_op.constant('1.0')) - self.assertEqual(self.evaluate(st), 1.0) + self.assertEqual(sess.run(st), 1.0) def test_int(self): self.assertEqual(py_builtins.int_(10.0), 10) self.assertEqual(py_builtins.int_('11', 2), 3) with self.cached_session() as sess: t = py_builtins.int_(constant_op.constant(1, dtype=dtypes.float64)) - self.assertEqual(self.evaluate(t), 1) + self.assertEqual(sess.run(t), 1) st = py_builtins.int_(constant_op.constant('1')) - self.assertEqual(self.evaluate(st), 1) + self.assertEqual(sess.run(st), 1) st = py_builtins.int_(constant_op.constant('1'), 10) - self.assertEqual(self.evaluate(st), 1) + self.assertEqual(sess.run(st), 1) def test_int_unsupported_base(self): t = constant_op.constant(1, dtype=dtypes.float64) @@ -73,9 +73,9 @@ class PyBuiltinsTest(test.TestCase): t = py_builtins.len_(constant_op.constant([[1], [2], [3]])) self.assertEqual(t, 3) ta = py_builtins.len_(tensor_array_ops.TensorArray(dtypes.int32, size=5)) - self.assertEqual(self.evaluate(ta), 5) + self.assertEqual(sess.run(ta), 5) tl = py_builtins.len_(data_structures.tf_tensor_list_new([3, 4, 5])) - self.assertEqual(self.evaluate(tl), 3) + self.assertEqual(sess.run(tl), 3) def test_len_scalar(self): with self.assertRaises(ValueError): @@ -120,18 +120,18 @@ class PyBuiltinsTest(test.TestCase): def test_range_tensor(self): with self.cached_session() as sess: r = py_builtins.range_(constant_op.constant(3)) - self.assertAllEqual(self.evaluate(r), [0, 1, 2]) + self.assertAllEqual(sess.run(r), [0, 1, 2]) r = py_builtins.range_(1, constant_op.constant(3)) - self.assertAllEqual(self.evaluate(r), [1, 2]) + self.assertAllEqual(sess.run(r), [1, 2]) r = py_builtins.range_(2, 0, constant_op.constant(-1)) - self.assertAllEqual(self.evaluate(r), [2, 1]) + self.assertAllEqual(sess.run(r), [2, 1]) def test_range_tensor_empty_range(self): with self.session() as sess: r = py_builtins.range_(constant_op.constant(-3)) - self.assertAllEqual(self.evaluate(r), []) + self.assertAllEqual(sess.run(r), []) r = py_builtins.range_(5, constant_op.constant(2)) - self.assertAllEqual(self.evaluate(r), []) + self.assertAllEqual(sess.run(r), []) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/operators/slices_test.py b/tensorflow/python/autograph/operators/slices_test.py index d444054fd7..9e4865b3c6 100644 --- a/tensorflow/python/autograph/operators/slices_test.py +++ b/tensorflow/python/autograph/operators/slices_test.py @@ -34,7 +34,7 @@ class SlicesTest(test.TestCase): with self.cached_session() as sess: t = list_ops.tensor_list_stack(l, element_dtype=initial_list.dtype) - self.assertAllEqual(self.evaluate(t), [[5, 6], [3, 4]]) + self.assertAllEqual(sess.run(t), [[5, 6], [3, 4]]) def test_get_item_tensor_list(self): initial_list = constant_op.constant([[1, 2], [3, 4]]) @@ -44,7 +44,7 @@ class SlicesTest(test.TestCase): l, 1, slices.GetItemOpts(element_dtype=initial_list.dtype)) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(t), [3, 4]) + self.assertAllEqual(sess.run(t), [3, 4]) def test_get_item_tensor_string(self): initial_str = constant_op.constant('abcd') @@ -52,14 +52,14 @@ class SlicesTest(test.TestCase): slices.GetItemOpts(element_dtype=initial_str.dtype)) with self.cached_session() as sess: - self.assertEqual(self.evaluate(t), b'b') + self.assertEqual(sess.run(t), b'b') initial_list_str = constant_op.constant(['abcd', 'bcde']) t = slices.get_item(initial_list_str, 1, slices.GetItemOpts(element_dtype=initial_str.dtype)) with self.cached_session() as sess: - self.assertEqual(self.evaluate(t), b'bcde') + self.assertEqual(sess.run(t), b'bcde') if __name__ == '__main__': diff --git a/tensorflow/python/autograph/utils/misc_test.py b/tensorflow/python/autograph/utils/misc_test.py index c813e0f5c9..8d2b0d6e13 100644 --- a/tensorflow/python/autograph/utils/misc_test.py +++ b/tensorflow/python/autograph/utils/misc_test.py @@ -32,7 +32,7 @@ class MiscTest(test.TestCase): new_a = alias_tensors(a) self.assertFalse(new_a is a) with self.cached_session() as sess: - self.assertEqual(1, self.evaluate(new_a)) + self.assertEqual(1, sess.run(new_a)) def test_alias_tensors(self): a = constant(1) @@ -47,7 +47,7 @@ class MiscTest(test.TestCase): self.assertTrue(new_s is s) self.assertTrue(new_l is l) with self.cached_session() as sess: - self.assertEqual(1, self.evaluate(new_a)) + self.assertEqual(1, sess.run(new_a)) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/utils/py_func_test.py b/tensorflow/python/autograph/utils/py_func_test.py index 28cefd8c3e..1c220d9492 100644 --- a/tensorflow/python/autograph/utils/py_func_test.py +++ b/tensorflow/python/autograph/utils/py_func_test.py @@ -34,13 +34,13 @@ class PyFuncTest(test.TestCase): with self.cached_session() as sess: result = py_func.wrap_py_func(test_fn, dtypes.int64, (1, constant_op.constant(1), 1)) - self.assertEqual(3, self.evaluate(result)) + self.assertEqual(3, sess.run(result)) result = py_func.wrap_py_func(test_fn, dtypes.int64, (1, 1, 1)) - self.assertEqual(3, self.evaluate(result)) + self.assertEqual(3, sess.run(result)) result = py_func.wrap_py_func( test_fn, dtypes.int64, (constant_op.constant(1), 1, constant_op.constant(1))) - self.assertEqual(3, self.evaluate(result)) + self.assertEqual(3, sess.run(result)) def test_wrap_py_func_complex_args(self): @@ -54,10 +54,10 @@ class PyFuncTest(test.TestCase): with self.cached_session() as sess: result = py_func.wrap_py_func(test_fn, dtypes.int64, (7, TestClass())) - self.assertEqual(35, self.evaluate(result)) + self.assertEqual(35, sess.run(result)) result = py_func.wrap_py_func(test_fn, dtypes.int64, (constant_op.constant(7), TestClass())) - self.assertEqual(35, self.evaluate(result)) + self.assertEqual(35, sess.run(result)) def test_wrap_py_func_kwargs(self): @@ -74,13 +74,13 @@ class PyFuncTest(test.TestCase): 'c': 11, 'd': TestClass(13) }) - self.assertEqual(178, self.evaluate(result)) + self.assertEqual(178, sess.run(result)) result = py_func.wrap_py_func(test_fn, dtypes.int64, (constant_op.constant(7), TestClass(5)), { 'c': constant_op.constant(11), 'd': TestClass(13) }) - self.assertEqual(178, self.evaluate(result)) + self.assertEqual(178, sess.run(result)) def test_wrap_py_func_dummy_return(self): @@ -91,11 +91,11 @@ class PyFuncTest(test.TestCase): with self.cached_session() as sess: result = py_func.wrap_py_func(test_fn, None, (5,), use_dummy_return=True) - self.assertEqual(1, self.evaluate(result)) + self.assertEqual(1, sess.run(result)) self.assertEqual([1], side_counter) result = py_func.wrap_py_func( test_fn, None, (constant_op.constant(5),), use_dummy_return=True) - self.assertEqual(1, self.evaluate(result)) + self.assertEqual(1, sess.run(result)) self.assertEqual([2], side_counter) diff --git a/tensorflow/python/autograph/utils/tensor_list_test.py b/tensorflow/python/autograph/utils/tensor_list_test.py index a5bbd97cf9..697c166eb1 100644 --- a/tensorflow/python/autograph/utils/tensor_list_test.py +++ b/tensorflow/python/autograph/utils/tensor_list_test.py @@ -43,13 +43,13 @@ class TensorListTest(test.TestCase): l = tl.dynamic_list_append(l, 1) s = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(s), [1]) + self.assertAllEqual(sess.run(s), [1]) l = tensor_array_ops.TensorArray(dtypes.int32, size=0, dynamic_size=True) l = tl.dynamic_list_append(l, 1) s = l.stack() with self.cached_session() as sess: - self.assertAllEqual(self.evaluate(s), [1]) + self.assertAllEqual(sess.run(s), [1]) l = tl.TensorList(self._shape(()), dtypes.int32) l = tl.dynamic_list_append(l, 1) diff --git a/tensorflow/python/client/session_clusterspec_prop_test.py b/tensorflow/python/client/session_clusterspec_prop_test.py index 224f880ed1..df020f88a8 100644 --- a/tensorflow/python/client/session_clusterspec_prop_test.py +++ b/tensorflow/python/client/session_clusterspec_prop_test.py @@ -62,7 +62,7 @@ class SessionClusterSpecPropagationTest(test_util.TensorFlowTestCase): const = constant_op.constant(17) sess = session.Session(server1.target, config=config) - output = self.evaluate(const) + output = sess.run(const) self.assertEqual(17, output) def testClusterSpecPropagationWorker2Placement(self): @@ -106,7 +106,7 @@ class SessionClusterSpecPropagationTest(test_util.TensorFlowTestCase): with ops.Graph().as_default() as g, ops.device('/job:worker/task:0'): const = constant_op.constant(17) sess = session.Session(server1.target, config=config, graph=g) - output = self.evaluate(const) + output = sess.run(const) self.assertEqual(17, output) def testCanonicalDeviceNames(self): @@ -208,7 +208,7 @@ class SessionClusterSpecPropagationTest(test_util.TensorFlowTestCase): with ops.device('/job:worker/task:0/cpu:0'): sum3 = sum1 + sum2 sess = session.Session(server1.target, config=config, graph=g) - output = self.evaluate(sum3) + output = sess.run(sum3) self.assertEqual(40, output) def testLegacyDeviceNames(self): diff --git a/tensorflow/python/client/timeline_test.py b/tensorflow/python/client/timeline_test.py index f9bd50957a..dfd0147643 100644 --- a/tensorflow/python/client/timeline_test.py +++ b/tensorflow/python/client/timeline_test.py @@ -147,7 +147,7 @@ class TimelineTest(test.TestCase): num2 = variables.Variable(2.0, name='num2') with ops.device('/cpu:2'): result = num1 + num2 + num1 * num2 - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) sess.run(result, options=run_options, run_metadata=run_metadata) self.assertTrue(run_metadata.HasField('step_stats')) @@ -176,7 +176,7 @@ class TimelineTest(test.TestCase): num2 = variables.Variable(2.0, name='num2') with ops.device('/cpu:2'): result = num1 + num2 + num1 * num2 - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) sess.run(result, options=run_options, run_metadata=run_metadata) self.assertTrue(run_metadata.HasField('step_stats')) step_stats = run_metadata.step_stats diff --git a/tensorflow/python/client/virtual_gpu_test.py b/tensorflow/python/client/virtual_gpu_test.py index e82ee0666c..5892e0fc84 100644 --- a/tensorflow/python/client/virtual_gpu_test.py +++ b/tensorflow/python/client/virtual_gpu_test.py @@ -216,7 +216,7 @@ class VirtualGpuTest(test_util.TensorFlowTestCase): for d in self._util.devices: with ops.device(d): var = variables.Variable(random_ops.random_uniform(mat_shape)) - self.evaluate(var.initializer) + sess.run(var.initializer) data.append(var) s = data[0] for i in range(1, len(data)): diff --git a/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py index dbb780c47d..e896752a26 100644 --- a/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py @@ -53,10 +53,10 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for start in range(0, len(components), 4): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual([[i, j] for i, c in enumerate(components[start:start + 4]) for j in range(c)], results.indices) @@ -81,10 +81,10 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for start in range(0, len(components), 4): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual([[i, j, z] for i, c in enumerate(components[start:start + 4]) for j in range(c) @@ -141,7 +141,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={placeholder: [0, 1, 2, 3]}) for i in range(4): - self.assertEqual(i, self.evaluate(next_elem)) + self.assertEqual(i, sess.run(next_elem)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_elem) @@ -159,7 +159,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual((i,) * 3, self.evaluate(op)) + self.assertEqual((i,) * 3, sess.run(op)) with self.assertRaises(errors.OutOfRangeError): sess.run(op) @@ -179,7 +179,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual((i, compat.as_bytes(str(i)), i), self.evaluate(op)) + self.assertEqual((i, compat.as_bytes(str(i)), i), sess.run(op)) with self.assertRaises(errors.OutOfRangeError): sess.run(op) @@ -198,7 +198,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - st_row = self.evaluate(next_element) + st_row = sess.run(next_element) self.assertEqual([i], st_row.indices) self.assertEqual([i], st_row.values) self.assertEqual([10], st_row.dense_shape) @@ -219,7 +219,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - dense_elem, st_row = self.evaluate(next_element) + dense_elem, st_row = sess.run(next_element) self.assertEqual(i, dense_elem) self.assertEqual([i], st_row.indices) self.assertEqual([i], st_row.values) @@ -241,7 +241,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(((i,),) * 3, self.evaluate(op)) + self.assertEqual(((i,),) * 3, sess.run(op)) with self.assertRaises(errors.OutOfRangeError): sess.run(op) @@ -354,7 +354,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(init_op, feed_dict={count: 28, batch_size: 14}) num_batches = (28 * 7) // 14 for i in range(num_batches): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(14): self.assertAllEqual(component[(i * 14 + j) % 7]**2, @@ -369,12 +369,12 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): # We expect (num_batches - 1) full-sized batches. num_batches = int(math.ceil((14 * 7) / 8)) for i in range(num_batches - 1): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(8): self.assertAllEqual(component[(i * 8 + j) % 7]**2, result_component[j]) - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range((14 * 7) % 8): self.assertAllEqual(component[((num_batches - 1) * 8 + j) % 7]**2, @@ -408,10 +408,10 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual([None, 1], iterator.output_shapes.as_list()) next_element = iterator.get_next() with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], self.evaluate(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], self.evaluate(next_element)) + self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) + self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) if not drop_remainder: - self.assertAllEqual([[64], [81]], self.evaluate(next_element)) + self.assertAllEqual([[64], [81]], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -423,9 +423,9 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual([None, 1], iterator.output_shapes.as_list()) next_element = iterator.get_next() with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], self.evaluate(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], self.evaluate(next_element)) - self.assertAllEqual([[64], [81]], self.evaluate(next_element)) + self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) + self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) + self.assertAllEqual([[64], [81]], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -439,7 +439,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): elements.append(iterator.get_next()) with self.cached_session() as sess: for i in range(5): - got = self.evaluate(elements) + got = sess.run(elements) got.sort(key=lambda x: x[0]) expected = [] for j in range(100): @@ -459,7 +459,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): elements.append(iterator.get_next()) with self.cached_session() as sess: for i in range(4): - got = self.evaluate(elements) + got = sess.run(elements) got.sort(key=lambda x: x[0]) expected = [] for j in range(100): @@ -480,9 +480,9 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(2): - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], @@ -524,7 +524,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): init_op = iterator.initializer get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaisesRegexp(errors.InvalidArgumentError, "number of elements does not match"): sess.run(get_next) @@ -576,8 +576,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(threshold // 10): - self.assertAllEqual([i * 10 + j for j in range(10)], - self.evaluate(get_next)) + self.assertAllEqual([i * 10 + j for j in range(10)], sess.run(get_next)) if threshold % 10 != 0: self.assertAllEqual( [threshold // 10 * 10 + j for j in range(threshold % 10)], @@ -610,8 +609,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for _ in range(10): - self.assertAllEqual([element for _ in range(10)], - self.evaluate(get_next)) + self.assertAllEqual([element for _ in range(10)], sess.run(get_next)) class UnbatchDatasetBenchmark(test.Benchmark): diff --git a/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py b/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py index 4263a90f4c..3903ec49b9 100644 --- a/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py @@ -300,7 +300,7 @@ class BucketBySequenceLengthTest(test_base.DatasetTestBase): with self.cached_session() as sess: with self.assertRaises(errors.OutOfRangeError): while True: - output = self.evaluate(batch) + output = sess.run(batch) sprs_tensor = (tuple([tuple(idx) for idx in output.indices]), tuple(output.values)) all_sparse_tensors.add(sprs_tensor) diff --git a/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py index 6d063ac9c8..cea8bd6f0b 100644 --- a/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py @@ -57,7 +57,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -82,7 +82,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - self.assertAllEqual([0, 1, 2, 3], self.evaluate(next_element)) + self.assertAllEqual([0, 1, 2, 3], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -108,7 +108,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -134,7 +134,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -160,7 +160,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual({"a": i}, self.evaluate(next_element)) + self.assertEqual({"a": i}, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -186,7 +186,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual({"a": i}, self.evaluate(next_element)) + self.assertEqual({"a": i}, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -217,7 +217,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - actual = self.evaluate(next_element) + actual = sess.run(next_element) self.assertAllEqual([i], actual.values) self.assertAllEqual([[0, 0]], actual.indices) self.assertAllEqual([2, 2], actual.dense_shape) @@ -251,7 +251,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - actual = self.evaluate(next_element) + actual = sess.run(next_element) self.assertAllEqual([i], actual.values) self.assertAllEqual([[0, 0]], actual.indices) self.assertAllEqual([2, 2], actual.dense_shape) @@ -271,9 +271,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -290,9 +290,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -323,9 +323,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(10): - x, y, z = self.evaluate(next_element) + x, y, z = sess.run(next_element) self.assertEqual(i**2, x) self.assertEqual(float(i**2), y) self.assertEqual(util_compat.as_bytes(str(i)), z) @@ -345,8 +345,8 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) - self.assertAllEqual([0, 1, 2, 3], self.evaluate(next_element)) + sess.run(iterator.initializer) + self.assertAllEqual([0, 1, 2, 3], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -363,8 +363,8 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) - self.assertAllEqual([0, 1, 2, 3], self.evaluate(next_element)) + sess.run(iterator.initializer) + self.assertAllEqual([0, 1, 2, 3], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -381,8 +381,8 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) - self.assertAllEqual([b"a", b"b", b"c"], self.evaluate(next_element)) + sess.run(iterator.initializer) + self.assertAllEqual([b"a", b"b", b"c"], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -399,8 +399,8 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) - self.assertAllEqual([b"a", b"b", b"c"], self.evaluate(next_element)) + sess.run(iterator.initializer) + self.assertAllEqual([b"a", b"b", b"c"], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -420,9 +420,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -447,12 +447,12 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(5): - self.assertEqual(i, self.evaluate(next_element)) - self.evaluate(iterator.initializer) + self.assertEqual(i, sess.run(next_element)) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -477,12 +477,12 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(5): - self.assertEqual(i, self.evaluate(next_element)) - self.evaluate(iterator.initializer) + self.assertEqual(i, sess.run(next_element)) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -499,12 +499,12 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(5): - self.assertEqual(i, self.evaluate(next_element)) - self.evaluate(iterator.initializer) + self.assertEqual(i, sess.run(next_element)) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -521,12 +521,12 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(5): - self.assertEqual(i, self.evaluate(next_element)) - self.evaluate(iterator.initializer) + self.assertEqual(i, sess.run(next_element)) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -553,7 +553,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): # For each element of the dataset, assert that the optional evaluates to # the expected value. - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(3): elem_has_value, elem_value = sess.run([elem_has_value_t, elem_value_t]) self.assertTrue(elem_has_value) @@ -562,7 +562,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): # After exhausting the iterator, `next_elem.has_value()` will evaluate to # false, and attempting to get the value will fail. for _ in range(2): - self.assertFalse(self.evaluate(elem_has_value_t)) + self.assertFalse(sess.run(elem_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): sess.run(elem_value_t) diff --git a/tensorflow/python/data/experimental/kernel_tests/counter_test.py b/tensorflow/python/data/experimental/kernel_tests/counter_test.py index d1dd07a879..4e114ac479 100644 --- a/tensorflow/python/data/experimental/kernel_tests/counter_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/counter_test.py @@ -38,13 +38,13 @@ class CounterTest(test_base.DatasetTestBase): negative_get_next = negative_iterator.get_next() with self.cached_session() as sess: - self.assertEqual(3, self.evaluate(get_next)) - self.assertEqual(3 + 4, self.evaluate(get_next)) - self.assertEqual(3 + 2 * 4, self.evaluate(get_next)) + self.assertEqual(3, sess.run(get_next)) + self.assertEqual(3 + 4, sess.run(get_next)) + self.assertEqual(3 + 2 * 4, sess.run(get_next)) - self.assertEqual(0, self.evaluate(negative_get_next)) - self.assertEqual(-1, self.evaluate(negative_get_next)) - self.assertEqual(-2, self.evaluate(negative_get_next)) + self.assertEqual(0, sess.run(negative_get_next)) + self.assertEqual(-1, sess.run(negative_get_next)) + self.assertEqual(-2, sess.run(negative_get_next)) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py b/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py index 9fe2ee43ed..73be6cbcca 100644 --- a/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py @@ -41,10 +41,10 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for start in range(0, len(components), 4): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual([[i, j] for i, c in enumerate(components[start:start + 4]) for j in range(c)], results.indices) @@ -69,10 +69,10 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for start in range(0, len(components), 4): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual([[i, j, z] for i, c in enumerate(components[start:start + 4]) for j in range(c) diff --git a/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py index 234fd86bdd..796a692c56 100644 --- a/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py @@ -40,10 +40,10 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for _ in range(100): for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -107,7 +107,7 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in choice_array: - self.assertEqual(words[i], self.evaluate(next_element)) + self.assertEqual(words[i], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) diff --git a/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py index 78805bb801..e54235d9f8 100644 --- a/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py @@ -44,9 +44,9 @@ class EnumerateDatasetTest(test_base.DatasetTestBase): [t.shape for t in get_next[1]]) with self.cached_session() as sess: - self.evaluate(init_op) - self.assertEqual((20, (b"a", 1, 37.0)), self.evaluate(get_next)) - self.assertEqual((21, (b"b", 2, 38.0)), self.evaluate(get_next)) + sess.run(init_op) + self.assertEqual((20, (b"a", 1, 37.0)), sess.run(get_next)) + self.assertEqual((21, (b"b", 2, 38.0)), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py b/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py index 860442571e..d38452e265 100644 --- a/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py @@ -94,18 +94,18 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): device0, device1) with self.test_session(config=worker_config) as sess: - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [1.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [2.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [3.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [4.0]) self._event.wait() - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [5.0]) - self.evaluate(destroy_op) + sess.run(destroy_op) def testSameDeviceCPU(self): self._prefetch_fn_helper_one_shot("same_device_cpu", @@ -135,35 +135,35 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): ds, ds_iterator, "reinit", device0, device1) with self.test_session(config=worker_config) as sess: - self.evaluate(ds_iterator.initializer) - elem = self.evaluate(prefetch_op) + sess.run(ds_iterator.initializer) + elem = sess.run(prefetch_op) self.assertEqual(elem, [1.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [2.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [3.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [4.0]) self._event.wait() - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [5.0]) # Lets reset the function buffering resource and reinitialize the # iterator. Should be able to go through this again. self._event.clear() - self.evaluate(reset_op) - self.evaluate(ds_iterator.initializer) - elem = self.evaluate(prefetch_op) + sess.run(reset_op) + sess.run(ds_iterator.initializer) + elem = sess.run(prefetch_op) self.assertEqual(elem, [1.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [2.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [3.0]) - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [4.0]) self._event.wait() - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [5.0]) - self.evaluate(destroy_op) + sess.run(destroy_op) def testReinitializationOutOfRange(self): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) @@ -175,30 +175,30 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): ds, ds_iterator, "reinit", device0, device1) with self.test_session(config=worker_config) as sess: - self.evaluate(ds_iterator.initializer) + sess.run(ds_iterator.initializer) for i in range(1, 10): - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [float(i)]) # Try fetching after its over twice to test out end of sequence. with self.assertRaises(errors.OutOfRangeError): - self.evaluate(prefetch_op) + sess.run(prefetch_op) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(prefetch_op) + sess.run(prefetch_op) # Now reset everything and try it out again. self._event.clear() - self.evaluate(reset_op) - self.evaluate(ds_iterator.initializer) + sess.run(reset_op) + sess.run(ds_iterator.initializer) for i in range(1, 10): - elem = self.evaluate(prefetch_op) + elem = sess.run(prefetch_op) self.assertEqual(elem, [float(i)]) # Try fetching after its over twice to test out end of sequence. with self.assertRaises(errors.OutOfRangeError): - self.evaluate(prefetch_op) + sess.run(prefetch_op) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(prefetch_op) + sess.run(prefetch_op) - self.evaluate(destroy_op) + sess.run(destroy_op) def testStringsGPU(self): if not test_util.is_gpu_available(): @@ -235,13 +235,13 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): buffer_resource_handle, ignore_lookup_error=True) with self.cached_session() as sess: - self.assertEqual([b"a"], self.evaluate(prefetch_op)) - self.assertEqual([b"b"], self.evaluate(prefetch_op)) - self.assertEqual([b"c"], self.evaluate(prefetch_op)) + self.assertEqual([b"a"], sess.run(prefetch_op)) + self.assertEqual([b"b"], sess.run(prefetch_op)) + self.assertEqual([b"c"], sess.run(prefetch_op)) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(prefetch_op) + sess.run(prefetch_op) - self.evaluate(destroy_op) + sess.run(destroy_op) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py b/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py index 15396f329d..9030328593 100644 --- a/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py @@ -39,7 +39,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): get_next = dataset.make_one_shot_iterator().get_next() with self.cached_session() as sess: for expected in values: - got = self.evaluate(get_next) + got = sess.run(get_next) self.assertEqual(got, expected) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -127,7 +127,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): iterator = dataset.make_one_shot_iterator() get_next = iterator.get_next() with self.cached_session() as sess: - x, y = self.evaluate(get_next) + x, y = sess.run(get_next) self.assertAllEqual([0] * (2**i), x) self.assertAllEqual(np.array(1, ndmin=i), y) with self.assertRaises(errors.OutOfRangeError): @@ -190,7 +190,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): grouping.group_by_reducer(lambda x, y: np.int64(0), reducer)) get_next = dataset.make_one_shot_iterator().get_next() with self.cached_session() as sess: - x, y = self.evaluate(get_next) + x, y = sess.run(get_next) self.assertAllEqual(x, np.asarray([x for x in range(10)])) self.assertEqual(y, 45) diff --git a/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py b/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py index cfc357ba13..557d56e8b9 100644 --- a/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py @@ -68,9 +68,9 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) - which_bucket, bucketed_values = self.evaluate(get_next) + which_bucket, bucketed_values = sess.run(get_next) self.assertEqual(0, which_bucket) @@ -103,11 +103,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) # Get two minibatches (one containing even values, one containing odds) - which_bucket_even, bucketed_values_even = self.evaluate(get_next) - which_bucket_odd, bucketed_values_odd = self.evaluate(get_next) + which_bucket_even, bucketed_values_even = sess.run(get_next) + which_bucket_odd, bucketed_values_odd = sess.run(get_next) # Count number of bucket_tensors. self.assertEqual(3, len(bucketed_values_even)) @@ -174,11 +174,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) # Get two minibatches ([0, 2, ...] and [64, 66, ...]) - which_bucket0, bucketed_values_even0 = self.evaluate(get_next) - which_bucket1, bucketed_values_even1 = self.evaluate(get_next) + which_bucket0, bucketed_values_even0 = sess.run(get_next) + which_bucket1, bucketed_values_even1 = sess.run(get_next) # Ensure that bucket 1 was completely filtered out self.assertAllEqual(0, which_bucket0) @@ -207,11 +207,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaises(errors.OutOfRangeError): batches = 0 while True: - result = self.evaluate(get_next) + result = sess.run(get_next) is_even = all(x % 2 == 0 for x in result) is_odd = all(x % 2 == 1 for x in result) self.assertTrue(is_even or is_odd) @@ -232,11 +232,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) counts = [] with self.assertRaises(errors.OutOfRangeError): while True: - result = self.evaluate(get_next) + result = sess.run(get_next) self.assertTrue( all(x % 2 == 0 for x in result) or all(x % 2 == 1) @@ -259,16 +259,16 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) # The input is infinite, so this test demonstrates that: # 1. We produce output without having to consume the entire input, # 2. Different buckets can produce output at different rates, and # 3. For deterministic input, the output is deterministic. for _ in range(3): - self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) - self.assertAllEqual([1, 1, 1, 1], self.evaluate(get_next)) - self.assertAllEqual([2, 2, 2, 2], self.evaluate(get_next)) - self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) + self.assertAllEqual([0, 0, 0, 0], sess.run(get_next)) + self.assertAllEqual([1, 1, 1, 1], sess.run(get_next)) + self.assertAllEqual([2, 2, 2, 2], sess.run(get_next)) + self.assertAllEqual([0, 0, 0, 0], sess.run(get_next)) def testSmallGroups(self): components = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], dtype=np.int64) @@ -280,13 +280,13 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) - self.assertAllEqual([1, 1, 1, 1], self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual([0, 0, 0, 0], sess.run(get_next)) + self.assertAllEqual([1, 1, 1, 1], sess.run(get_next)) # The small outputs at the end are deterministically produced in key # order. - self.assertAllEqual([0, 0, 0], self.evaluate(get_next)) - self.assertAllEqual([1], self.evaluate(get_next)) + self.assertAllEqual([0, 0, 0], sess.run(get_next)) + self.assertAllEqual([1], sess.run(get_next)) def testEmpty(self): iterator = ( @@ -297,7 +297,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaisesRegexp( errors.InvalidArgumentError, "Window size must be greater than zero, but got 0."): @@ -323,7 +323,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaises(errors.InvalidArgumentError): sess.run(get_next) @@ -351,11 +351,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) counts = [] with self.assertRaises(errors.OutOfRangeError): while True: - tight_result, multiple_of_10_result = self.evaluate(get_next) + tight_result, multiple_of_10_result = sess.run(get_next) self.assertEqual(0, multiple_of_10_result.shape[1] % 10) self.assertAllEqual(tight_result, multiple_of_10_result[:, :tight_result.shape[1]]) diff --git a/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py b/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py index cb0fc13914..c0ec1486ab 100644 --- a/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py @@ -47,9 +47,9 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for x in [1., 2., 3., 5.]: - self.assertEqual(x, self.evaluate(get_next)) + self.assertEqual(x, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -65,9 +65,9 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for x in [1., 2., 3., 5.]: - self.assertEqual(x, self.evaluate(get_next)) + self.assertEqual(x, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -93,9 +93,9 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): with self.cached_session() as sess: # All of the files are present. - self.evaluate(init_op) + sess.run(init_op) for filename in filenames: - self.assertEqual(compat.as_bytes(filename), self.evaluate(get_next)) + self.assertEqual(compat.as_bytes(filename), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -104,9 +104,9 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): # Attempting to read filenames[0] will fail, but ignore_errors() # will catch the error. - self.evaluate(init_op) + sess.run(init_op) for filename in filenames[1:]: - self.assertEqual(compat.as_bytes(filename), self.evaluate(get_next)) + self.assertEqual(compat.as_bytes(filename), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py b/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py index c4076daef2..c93a8353ce 100644 --- a/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py @@ -53,7 +53,7 @@ class IndexedDatasetOpsTest(test_base.DatasetTestBase): ds = indexed_dataset_ops.IdentityIndexedDataset(16) materialized = ds.materialize() with self.cached_session() as sess: - self.evaluate(materialized.initializer) + sess.run(materialized.initializer) placeholder = array_ops.placeholder(dtypes.uint64, shape=[]) for i in range(16): output = sess.run( @@ -68,9 +68,9 @@ class IndexedDatasetOpsTest(test_base.DatasetTestBase): itr = ds.make_initializable_iterator() n = itr.get_next() with self.cached_session() as sess: - self.evaluate(itr.initializer) + sess.run(itr.initializer) for i in range(16): - output = self.evaluate(n) + output = sess.run(n) self.assertEqual(i, output) with self.assertRaises(errors.OutOfRangeError): sess.run(n) diff --git a/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py index c6cefa7034..91ae8cb1bd 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py @@ -112,10 +112,10 @@ class MakeBatchedFeaturesDatasetTest( next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for file_batch, _, _, _, record_batch, _ in self._next_expected_batch( range(self._num_files), 2, 10): - actual_batch = self.evaluate(next_element) + actual_batch = sess.run(next_element) self.assertAllEqual(file_batch, actual_batch["file"]) self.assertAllEqual(record_batch, actual_batch["record"]) with self.assertRaises(errors.OutOfRangeError): diff --git a/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py index 5486369462..e4bf089184 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py @@ -90,7 +90,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): batch_size, num_epochs, ): - actual_features = self.evaluate(nxt) + actual_features = sess.run(nxt) if label_name is not None: expected_labels = expected_features.pop(label_name) diff --git a/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py index 404edf2fda..657cf3c00e 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py @@ -105,7 +105,7 @@ class MakeTFRecordDatasetTest( for expected_batch in self._next_expected_batch( file_indices, batch_size, num_epochs, interleave_cycle_length, drop_final_batch, use_parser_fn): - actual_batch = self.evaluate(outputs) + actual_batch = sess.run(outputs) self.assertAllEqual(expected_batch, actual_batch) def _read_test(self, batch_size, num_epochs, file_index=None, @@ -188,7 +188,7 @@ class MakeTFRecordDatasetTest( iterator = dataset.make_initializable_iterator() next_element = iterator.get_next() - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) first_batches = [] try: while True: @@ -196,7 +196,7 @@ class MakeTFRecordDatasetTest( except errors.OutOfRangeError: pass - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) second_batches = [] try: while True: diff --git a/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py b/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py index b4bc4a617f..5ead6d1c75 100644 --- a/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py @@ -89,7 +89,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(init_op, feed_dict={count: 28, batch_size: 14}) num_batches = (28 * 7) // 14 for i in range(num_batches): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(14): self.assertAllEqual(component[(i * 14 + j) % 7]**2, @@ -104,12 +104,12 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): # We expect (num_batches - 1) full-sized batches. num_batches = int(math.ceil((14 * 7) / 8)) for i in range(num_batches - 1): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(8): self.assertAllEqual(component[(i * 8 + j) % 7]**2, result_component[j]) - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range((14 * 7) % 8): self.assertAllEqual(component[((num_batches - 1) * 8 + j) % 7]**2, @@ -152,10 +152,10 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual([None, 1], iterator.output_shapes.as_list()) next_element = iterator.get_next() with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], self.evaluate(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], self.evaluate(next_element)) + self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) + self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) if not drop_remainder: - self.assertAllEqual([[64], [81]], self.evaluate(next_element)) + self.assertAllEqual([[64], [81]], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -177,9 +177,9 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual([None, 1], iterator.output_shapes.as_list()) next_element = iterator.get_next() with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], self.evaluate(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], self.evaluate(next_element)) - self.assertAllEqual([[64], [81]], self.evaluate(next_element)) + self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) + self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) + self.assertAllEqual([[64], [81]], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -201,7 +201,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): elements.append(iterator.get_next()) with self.cached_session() as sess: for i in range(5): - got = self.evaluate(elements) + got = sess.run(elements) got.sort(key=lambda x: x[0]) expected = [] for j in range(100): @@ -230,7 +230,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): elements.append(iterator.get_next()) with self.cached_session() as sess: for i in range(4): - got = self.evaluate(elements) + got = sess.run(elements) got.sort(key=lambda x: x[0]) expected = [] for j in range(100): @@ -261,9 +261,9 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(2): - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], @@ -321,7 +321,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): init_op = iterator.initializer get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaisesRegexp(errors.InvalidArgumentError, "number of elements does not match"): sess.run(get_next) @@ -393,8 +393,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(threshold // 10): - self.assertAllEqual([i * 10 + j for j in range(10)], - self.evaluate(get_next)) + self.assertAllEqual([i * 10 + j for j in range(10)], sess.run(get_next)) if threshold % 10 != 0: self.assertAllEqual( [threshold // 10 * 10 + j for j in range(threshold % 10)], @@ -443,8 +442,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for _ in range(10): - self.assertAllEqual([element for _ in range(10)], - self.evaluate(get_next)) + self.assertAllEqual([element for _ in range(10)], sess.run(get_next)) @parameterized.named_parameters( ("Identity", None, lambda x: x, None), @@ -464,7 +462,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): else: expected = map_fn( sess.run(self.structuredElement(structure, shape=[10]))) - self.assertAllEqual(expected, self.evaluate(get_next)) + self.assertAllEqual(expected, sess.run(get_next)) def testShortCircuitCapturedInput(self): captured_t = array_ops.placeholder(dtypes.int64, shape=[]) @@ -475,7 +473,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={captured_t: 42}) - self.assertAllEqual([42] * 10, self.evaluate(get_next)) + self.assertAllEqual([42] * 10, sess.run(get_next)) @parameterized.named_parameters( ("Normal", False), diff --git a/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py b/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py index 3cf3b89c3f..11694540fa 100644 --- a/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py @@ -218,7 +218,7 @@ class MapDefunTest(test_base.DatasetTestBase): def _assert_op_cancelled(self, sess, map_defun_op): with self.assertRaisesRegexp(errors.CancelledError, "was cancelled"): - self.evaluate(map_defun_op) + sess.run(map_defun_op) def testMapDefunWithParentCancellation(self): # Checks that a cancellation of the parent graph is threaded through to diff --git a/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py b/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py index ca8bc5ff97..5e419a9b2f 100644 --- a/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py @@ -72,7 +72,7 @@ class OverrideThreadpoolTest(test_base.DatasetTestBase, next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) thread_ids = [] try: while True: diff --git a/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py b/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py index 91908f5582..90ac250df7 100644 --- a/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py @@ -637,11 +637,11 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): for j in range(2): expected = [i, 0] if j % 2 == 0 else [0, -i] - self.assertAllEqual(expected, self.evaluate(get_next)) + self.assertAllEqual(expected, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -796,7 +796,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): with self.cached_session() as sess: for _ in range(2): elements = [] - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) try: while True: elements.extend(sess.run(next_element)) diff --git a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py index 60c3741d32..f73725366c 100644 --- a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py @@ -57,7 +57,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -87,7 +87,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -117,7 +117,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual({"a": i}, self.evaluate(next_element)) + self.assertEqual({"a": i}, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -150,7 +150,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - actual = self.evaluate(next_element) + actual = sess.run(next_element) self.assertAllEqual([i], actual.values) self.assertAllEqual([[0, 0]], actual.indices) self.assertAllEqual([2, 2], actual.dense_shape) @@ -170,7 +170,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -199,12 +199,12 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(5): - self.assertEqual(i, self.evaluate(next_element)) - self.evaluate(iterator.initializer) + self.assertEqual(i, sess.run(next_element)) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -220,12 +220,12 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(5): - self.assertEqual(i, self.evaluate(next_element)) - self.evaluate(iterator.initializer) + self.assertEqual(i, sess.run(next_element)) + sess.run(iterator.initializer) for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) diff --git a/tensorflow/python/data/experimental/kernel_tests/scan_test.py b/tensorflow/python/data/experimental/kernel_tests/scan_test.py index 0e9bb462f3..0730455431 100644 --- a/tensorflow/python/data/experimental/kernel_tests/scan_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/scan_test.py @@ -60,7 +60,7 @@ class ScanTest(test_base.DatasetTestBase): feed_dict={start: start_val, step: step_val, take: take_val}) for expected, _ in zip( itertools.count(start_val, step_val), range(take_val)): - self.assertEqual(expected, self.evaluate(next_element)) + self.assertEqual(expected, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -110,7 +110,7 @@ class ScanTest(test_base.DatasetTestBase): feed_dict={start: start_val, step: step_val, take: take_val}) for expected, _ in zip( itertools.count(start_val, step_val), range(take_val)): - self.assertEqual(expected, self.evaluate(next_element).values[0]) + self.assertEqual(expected, sess.run(next_element).values[0]) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -136,7 +136,7 @@ class ScanTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in range(5): - (longer_vector_val, larger_rank_val), _ = self.evaluate(next_element) + (longer_vector_val, larger_rank_val), _ = sess.run(next_element) self.assertAllEqual([0] * (2**i), longer_vector_val) self.assertAllEqual(np.array(1, ndmin=i), larger_rank_val) with self.assertRaises(errors.OutOfRangeError): diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py index 704a40721f..ef99d01c73 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py @@ -71,19 +71,19 @@ class RangeDatasetSerializationTest( with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next, _, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(init_op) - self.evaluate(restore_op) + sess.run(init_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -91,14 +91,14 @@ class RangeDatasetSerializationTest( with ops.Graph().as_default() as g: init_op, get_next, save_op, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) - self.evaluate(restore_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py index 496fd45947..88d5c896c9 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py @@ -62,7 +62,7 @@ class SerializationIntegrationTest(test.TestCase): with self.session(graph=g) as sess: sess.run(init_ops) for _ in range(break_point): - output = self.evaluate(get_next_ops) + output = sess.run(get_next_ops) for i in range(num_pipelines): all_outputs[i].append(output[i]) saver.save(sess, self._ckpt_path()) @@ -73,7 +73,7 @@ class SerializationIntegrationTest(test.TestCase): with self.session(graph=g) as sess: saver.restore(sess, self._ckpt_path()) for _ in range(num_outputs - break_point): - output = self.evaluate(get_next_ops) + output = sess.run(get_next_ops) for i in range(num_pipelines): all_outputs[i].append(output[i]) diff --git a/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py b/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py index 5f7d9051ec..c208963a86 100644 --- a/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py @@ -108,7 +108,7 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): shuffle_ops.shuffle_and_repeat(buffer_size=21)) get_next_op = ds.make_one_shot_iterator().get_next() with self.session(graph=g) as sess: - self.evaluate(get_next_op) + sess.run(get_next_op) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/sleep_test.py b/tensorflow/python/data/experimental/kernel_tests/sleep_test.py index f7d42bc5b3..bf53acc82a 100644 --- a/tensorflow/python/data/experimental/kernel_tests/sleep_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/sleep_test.py @@ -38,10 +38,10 @@ class SleepTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) start_time = time.time() for i in range(10): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) end_time = time.time() self.assertGreater(end_time - start_time, (10 * sleep_microseconds) / 1e6) with self.assertRaises(errors.OutOfRangeError): diff --git a/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py index e11bad7969..a2c1169638 100644 --- a/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py @@ -39,9 +39,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) for _ in range(2): # Dataset is repeated. See setUp. - self.assertEqual((b"John", b"Doe", b"Hi!"), self.evaluate(get_next)) - self.assertEqual((b"Jane", b"Moe", b"Hi again!"), - self.evaluate(get_next)) + self.assertEqual((b"John", b"Doe", b"Hi!"), sess.run(get_next)) + self.assertEqual((b"Jane", b"Moe", b"Hi again!"), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -59,8 +58,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ON students.first_name = people.first_name " "AND students.last_name = people.last_name" }) - self.assertEqual((b"John", b"California", b"Hi!"), - self.evaluate(get_next)) + self.assertEqual((b"John", b"California", b"Hi!"), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -77,9 +75,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT first_name, last_name, favorite_nonsense_word " "FROM students ORDER BY first_name DESC" }) - self.assertEqual((b"John", b"Doe", b"n\0nsense"), self.evaluate(get_next)) - self.assertEqual((b"Jane", b"Moe", b"nonsense\0"), - self.evaluate(get_next)) + self.assertEqual((b"John", b"Doe", b"n\0nsense"), sess.run(get_next)) + self.assertEqual((b"Jane", b"Moe", b"nonsense\0"), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -96,8 +93,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, last_name, motto FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", b"Doe", b"Hi!"), self.evaluate(get_next)) - self.assertEqual((b"Jane", b"Moe", b"Hi again!"), self.evaluate(get_next)) + self.assertEqual((b"John", b"Doe", b"Hi!"), sess.run(get_next)) + self.assertEqual((b"Jane", b"Moe", b"Hi again!"), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) sess.run( @@ -106,8 +103,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, last_name, state FROM people " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", b"Doe", b"California"), - self.evaluate(get_next)) + self.assertEqual((b"John", b"Doe", b"California"), sess.run(get_next)) self.assertEqual((b"Benjamin", b"Franklin", b"Pennsylvania"), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): @@ -216,8 +212,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), self.evaluate(get_next)) - self.assertEqual((b"Jane", 127), self.evaluate(get_next)) + self.assertEqual((b"John", 9), sess.run(get_next)) + self.assertEqual((b"Jane", 127), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -234,7 +230,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "FROM students " "WHERE first_name = 'John' ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0, -2), self.evaluate(get_next)) + self.assertEqual((b"John", 0, -2), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -250,9 +246,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT desk_number, favorite_negative_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((9, -2), self.evaluate(get_next)) + self.assertEqual((9, -2), sess.run(get_next)) # Max and min values of int8 - self.assertEqual((127, -128), self.evaluate(get_next)) + self.assertEqual((127, -128), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -267,8 +263,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), self.evaluate(get_next)) - self.assertEqual((b"Jane", 127), self.evaluate(get_next)) + self.assertEqual((b"John", 9), sess.run(get_next)) + self.assertEqual((b"Jane", 127), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -285,7 +281,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "FROM students " "WHERE first_name = 'John' ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0, -2), self.evaluate(get_next)) + self.assertEqual((b"John", 0, -2), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -301,9 +297,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "FROM students ORDER BY first_name DESC" }) # Max value of int16 - self.assertEqual((b"John", 32767), self.evaluate(get_next)) + self.assertEqual((b"John", 32767), sess.run(get_next)) # Min value of int16 - self.assertEqual((b"Jane", -32768), self.evaluate(get_next)) + self.assertEqual((b"Jane", -32768), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -318,8 +314,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), self.evaluate(get_next)) - self.assertEqual((b"Jane", 127), self.evaluate(get_next)) + self.assertEqual((b"John", 9), sess.run(get_next)) + self.assertEqual((b"Jane", 127), sess.run(get_next)) # Test that `SqlDataset` can read a negative or 0-valued integer from a # SQLite database table and place it in an `int32` tensor. @@ -332,8 +328,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, income FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0), self.evaluate(get_next)) - self.assertEqual((b"Jane", -20000), self.evaluate(get_next)) + self.assertEqual((b"John", 0), sess.run(get_next)) + self.assertEqual((b"Jane", -20000), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -349,9 +345,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Max value of int32 - self.assertEqual((b"John", 2147483647), self.evaluate(get_next)) + self.assertEqual((b"John", 2147483647), sess.run(get_next)) # Min value of int32 - self.assertEqual((b"Jane", -2147483648), self.evaluate(get_next)) + self.assertEqual((b"Jane", -2147483648), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -366,8 +362,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, school_id FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 123), self.evaluate(get_next)) - self.assertEqual((b"Jane", 1000), self.evaluate(get_next)) + self.assertEqual((b"John", 123), sess.run(get_next)) + self.assertEqual((b"Jane", 1000), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -382,8 +378,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), self.evaluate(get_next)) - self.assertEqual((b"Jane", 127), self.evaluate(get_next)) + self.assertEqual((b"John", 9), sess.run(get_next)) + self.assertEqual((b"Jane", 127), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -398,8 +394,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, income FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0), self.evaluate(get_next)) - self.assertEqual((b"Jane", -20000), self.evaluate(get_next)) + self.assertEqual((b"John", 0), sess.run(get_next)) + self.assertEqual((b"Jane", -20000), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -416,9 +412,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Max value of int64 - self.assertEqual((b"John", 9223372036854775807), self.evaluate(get_next)) + self.assertEqual((b"John", 9223372036854775807), sess.run(get_next)) # Min value of int64 - self.assertEqual((b"Jane", -9223372036854775808), self.evaluate(get_next)) + self.assertEqual((b"Jane", -9223372036854775808), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -433,8 +429,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), self.evaluate(get_next)) - self.assertEqual((b"Jane", 127), self.evaluate(get_next)) + self.assertEqual((b"John", 9), sess.run(get_next)) + self.assertEqual((b"Jane", 127), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -450,9 +446,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Min value of uint8 - self.assertEqual((b"John", 0), self.evaluate(get_next)) + self.assertEqual((b"John", 0), sess.run(get_next)) # Max value of uint8 - self.assertEqual((b"Jane", 255), self.evaluate(get_next)) + self.assertEqual((b"Jane", 255), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -467,8 +463,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), self.evaluate(get_next)) - self.assertEqual((b"Jane", 127), self.evaluate(get_next)) + self.assertEqual((b"John", 9), sess.run(get_next)) + self.assertEqual((b"Jane", 127), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -484,9 +480,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Min value of uint16 - self.assertEqual((b"John", 0), self.evaluate(get_next)) + self.assertEqual((b"John", 0), sess.run(get_next)) # Max value of uint16 - self.assertEqual((b"Jane", 65535), self.evaluate(get_next)) + self.assertEqual((b"Jane", 65535), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -503,8 +499,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT first_name, registration_complete FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", True), self.evaluate(get_next)) - self.assertEqual((b"Jane", False), self.evaluate(get_next)) + self.assertEqual((b"John", True), sess.run(get_next)) + self.assertEqual((b"Jane", False), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -519,8 +515,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, favorite_medium_sized_number " "FROM students ORDER BY first_name DESC" }) - self.assertEqual((b"John", True), self.evaluate(get_next)) - self.assertEqual((b"Jane", True), self.evaluate(get_next)) + self.assertEqual((b"John", True), sess.run(get_next)) + self.assertEqual((b"Jane", True), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -537,9 +533,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT first_name, last_name, victories FROM townspeople " "ORDER BY first_name" }) - self.assertEqual((b"George", b"Washington", 20.0), - self.evaluate(get_next)) - self.assertEqual((b"John", b"Adams", -19.95), self.evaluate(get_next)) + self.assertEqual((b"George", b"Washington", 20.0), sess.run(get_next)) + self.assertEqual((b"John", b"Adams", -19.95), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py b/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py index 958c3f0038..83028937d3 100644 --- a/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py @@ -74,18 +74,18 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) expected_sum = 0.0 for i in range(100): self.assertAllEqual( np.array([i] * i, dtype=np.int64), sess.run(next_element)) - summary_str = self.evaluate(summary_t) + summary_str = sess.run(summary_t) self._assertSummaryHasCount(summary_str, "bytes_produced", float(i + 1)) expected_sum += i * 8.0 self._assertSummaryHasSum(summary_str, "bytes_produced", expected_sum) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) - summary_str = self.evaluate(summary_t) + summary_str = sess.run(summary_t) self._assertSummaryHasCount(summary_str, "bytes_produced", 100.0) self._assertSummaryHasSum(summary_str, "bytes_produced", expected_sum) @@ -99,15 +99,14 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(100): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) self._assertSummaryHasCount( sess.run(summary_t), "record_latency", float(i + 1)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) - self._assertSummaryHasCount( - self.evaluate(summary_t), "record_latency", 100.0) + self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 100.0) def testPrefetchBufferUtilization(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -119,11 +118,11 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(100): self.assertAllEqual( np.array([i] * i, dtype=np.int64), sess.run(next_element)) - summary_str = self.evaluate(summary_t) + summary_str = sess.run(summary_t) self._assertSummaryHasCount(summary_str, "Prefetch::buffer_utilization", float(i + 1)) self._assertSummaryContains(summary_str, "Prefetch::buffer_capacity") @@ -132,7 +131,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): 0, 1) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) - summary_str = self.evaluate(summary_t) + summary_str = sess.run(summary_t) self._assertSummaryHasCount(summary_str, "Prefetch::buffer_utilization", 100) @@ -146,11 +145,11 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(10): self.assertAllEqual( np.array([i] * i, dtype=np.int64), sess.run(next_element)) - summary_str = self.evaluate(summary_t) + summary_str = sess.run(summary_t) self._assertSummaryHasScalarValue(summary_str, "Prefetch::buffer_capacity", 0) self._assertSummaryHasScalarValue(summary_str, "Prefetch::buffer_size", @@ -168,9 +167,9 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.test_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(34): - self.assertEqual(i * 3, self.evaluate(next_element)) + self.assertEqual(i * 3, sess.run(next_element)) if i is not 0: self._assertSummaryHasScalarValue( sess.run(summary_t), "Filter::dropped_elements", float(i * 2)) @@ -262,9 +261,9 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): with self.cached_session() as sess: for j in range(5): - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(100): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) self._assertSummaryHasCount( sess.run(summary_t), "record_latency", float((j * 100) + i + 1)) with self.assertRaises(errors.OutOfRangeError): @@ -279,9 +278,9 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(100): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -296,17 +295,16 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(100): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) self._assertSummaryHasCount( sess.run(summary_t), "record_latency", float(i + 1)) self._assertSummaryHasCount( sess.run(summary_t), "record_latency_2", float(i + 1)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) - self._assertSummaryHasCount( - self.evaluate(summary_t), "record_latency", 100.0) + self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 100.0) self._assertSummaryHasCount( sess.run(summary_t), "record_latency_2", 100.0) @@ -321,15 +319,14 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for i in range(100): - self.assertEqual(i, self.evaluate(next_element)) + self.assertEqual(i, sess.run(next_element)) self._assertSummaryHasCount( sess.run(summary_t), "record_latency", float(2 * (i + 1))) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) - self._assertSummaryHasCount( - self.evaluate(summary_t), "record_latency", 200.0) + self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 200.0) def testMultipleIteratorsSameAggregator(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -344,13 +341,12 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): with self.cached_session() as sess: sess.run([iterator_0.initializer, iterator_1.initializer]) for i in range(100): - self.assertEqual(i * 2, self.evaluate(next_element)) + self.assertEqual(i * 2, sess.run(next_element)) self._assertSummaryHasCount( sess.run(summary_t), "record_latency", float(2 * (i + 1))) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) - self._assertSummaryHasCount( - self.evaluate(summary_t), "record_latency", 200.0) + self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 200.0) def testMultipleDatasetWithPrefixes(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -368,7 +364,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): with self.test_session() as sess: sess.run([iterator_0.initializer, iterator_1.initializer]) for i in range(100): - self.assertEqual(i * 2, self.evaluate(next_element)) + self.assertEqual(i * 2, sess.run(next_element)) self._assertSummaryHasCount( sess.run(summary_t), "dataset1_record_latency", float(i + 1)) self._assertSummaryHasCount( @@ -425,7 +421,7 @@ class FeatureStatsDatasetTest( summary_t = aggregator.get_summary() with self.test_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for _ in range(num_output): sess.run(next_element) diff --git a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py index 755294ac45..0278a208cb 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py @@ -50,7 +50,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={placeholder: [0, 1, 2, 3]}) for i in range(4): - self.assertEqual(i, self.evaluate(next_elem)) + self.assertEqual(i, sess.run(next_elem)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_elem) @@ -68,7 +68,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual((i,) * 3, self.evaluate(op)) + self.assertEqual((i,) * 3, sess.run(op)) with self.assertRaises(errors.OutOfRangeError): sess.run(op) @@ -88,7 +88,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual((i, compat.as_bytes(str(i)), i), self.evaluate(op)) + self.assertEqual((i, compat.as_bytes(str(i)), i), sess.run(op)) with self.assertRaises(errors.OutOfRangeError): sess.run(op) @@ -107,7 +107,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - st_row = self.evaluate(next_element) + st_row = sess.run(next_element) self.assertEqual([i], st_row.indices) self.assertEqual([i], st_row.values) self.assertEqual([10], st_row.dense_shape) @@ -128,7 +128,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - dense_elem, st_row = self.evaluate(next_element) + dense_elem, st_row = sess.run(next_element) self.assertEqual(i, dense_elem) self.assertEqual([i], st_row.indices) self.assertEqual([i], st_row.values) @@ -150,7 +150,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(((i,),) * 3, self.evaluate(op)) + self.assertEqual(((i,),) * 3, sess.run(op)) with self.assertRaises(errors.OutOfRangeError): sess.run(op) diff --git a/tensorflow/python/data/experimental/kernel_tests/unique_test.py b/tensorflow/python/data/experimental/kernel_tests/unique_test.py index 4b14a7e963..847cff26b0 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unique_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unique_test.py @@ -49,11 +49,11 @@ class UniqueTest(test_base.DatasetTestBase): with self.cached_session() as sess: for test_case, expected in test_cases: current_test_case = test_case - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for element in expected: if dtype == dtypes.string: element = compat.as_bytes(element) - self.assertAllEqual(element, self.evaluate(next_element)) + self.assertAllEqual(element, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) diff --git a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py index 10a0427c7f..e8decb9ad0 100644 --- a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py @@ -93,13 +93,13 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): }) num_full_batches = (count * 7) // batch_size for i in range(num_full_batches): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(batch_size): self.assertAllEqual(component[(i * batch_size + j) % 7]**2, result_component[j]) if not drop_remainder and (count * 7) % batch_size > 0: - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range((count * 7) % batch_size): self.assertAllEqual( @@ -128,9 +128,9 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(2): - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], @@ -155,9 +155,9 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(2): - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected_indices = [] expected_values = [] for j in range(5): @@ -185,8 +185,8 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - actual = self.evaluate(get_next) + sess.run(init_op) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0]], @@ -211,7 +211,7 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) with self.assertRaisesRegexp( errors.InvalidArgumentError, r'Cannot batch tensors with different shapes in component 0. ' @@ -271,7 +271,7 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): num_full_batches = len(seq_lens) // batch_size for i in range(num_full_batches): - result = self.evaluate(get_next) + result = sess.run(get_next) padded_len = padded_shapes[0] if padded_len is None or padded_len == -1: padded_len = np.max(result) if result.size > 0 else 0 @@ -283,7 +283,7 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): [0] * (padded_len - seq_len)) if not drop_remainder and len(seq_lens) % batch_size > 0: - result = self.evaluate(get_next) + result = sess.run(get_next) padded_len = np.max(result) if result.size > 0 else 0 self.assertEqual((len(seq_lens) % batch_size, padded_len), result.shape) @@ -315,7 +315,7 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - result = self.evaluate(get_next) + result = sess.run(get_next) self.assertAllEqual([[], [], [], []], result) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -347,7 +347,7 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): seq_lens: random_seq_lens }) for i in range(8): - result = self.evaluate(get_next) + result = sess.run(get_next) padded_len = np.max(result[0]) self.assertEqual((4, padded_len), result[0].shape) self.assertEqual((4, padded_len), result[1].shape) diff --git a/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py b/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py index 1f351279c6..63625fac03 100644 --- a/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py @@ -71,7 +71,7 @@ class FileCacheDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: # First run without caching to collect the "ground truth". - self.evaluate(init_fifo_op) + sess.run(init_fifo_op) elements = [] for _ in range(20): elements.append(sess.run(get_next)) @@ -220,14 +220,14 @@ class MemoryCacheDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: - self.evaluate(repeat_count.initializer) - self.evaluate(cached_iterator.initializer) - self.evaluate(uncached_iterator.initializer) + sess.run(repeat_count.initializer) + sess.run(cached_iterator.initializer) + sess.run(uncached_iterator.initializer) for i in range(3): for _ in range(10): - self.assertEqual(self.evaluate(cached_next), i) - self.assertEqual(self.evaluate(uncached_next), i) + self.assertEqual(sess.run(cached_next), i) + self.assertEqual(sess.run(uncached_next), i) sess.run(repeat_count.assign(0)) @@ -238,7 +238,7 @@ class MemoryCacheDatasetTest(test_base.DatasetTestBase): # The cached iterator replays from cache. for i in range(3): for _ in range(10): - self.assertEqual(self.evaluate(cached_next), i) + self.assertEqual(sess.run(cached_next), i) # The cached iterator should now be empty. with self.assertRaises(errors.OutOfRangeError): @@ -280,7 +280,7 @@ class MemoryCacheDatasetTest(test_base.DatasetTestBase): i2 = d2.make_initializable_iterator() with self.cached_session() as sess: - self.evaluate(i1.initializer) + sess.run(i1.initializer) self.assertEqual(1, sess.run(i1.get_next())) self.assertEqual(2, sess.run(i1.get_next())) @@ -307,7 +307,7 @@ class MemoryCacheDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i, expected in enumerate(expected_values): - self.assertEqual(expected, self.evaluate(n), + self.assertEqual(expected, sess.run(n), "Unexpected value at index %s" % i) with self.assertRaises(errors.OutOfRangeError): diff --git a/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py b/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py index a0ef69f082..83af31f380 100644 --- a/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py @@ -51,9 +51,9 @@ class ConcatenateDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(9): - result = self.evaluate(get_next) + result = sess.run(get_next) if i < 4: for component, result_component in zip(input_components, result): self.assertAllEqual(component[i], result_component) @@ -85,9 +85,9 @@ class ConcatenateDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(9): - result = self.evaluate(get_next) + result = sess.run(get_next) if i < 4: for component, result_component in zip(input_components, result): self.assertAllEqual(component[i], result_component) diff --git a/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py b/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py index f7b500881c..bc6b36285a 100644 --- a/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py @@ -52,8 +52,8 @@ class DatasetConstructorTest(test_base.DatasetTestBase): [t.shape for t in get_next]) with self.cached_session() as sess: - self.evaluate(init_op) - results = self.evaluate(get_next) + sess.run(init_op) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -81,8 +81,8 @@ class DatasetConstructorTest(test_base.DatasetTestBase): [shape for shape in iterator.output_shapes]) with self.cached_session() as sess: - self.evaluate(init_op) - results = self.evaluate(get_next) + sess.run(init_op) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertSparseValuesEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -112,8 +112,8 @@ class DatasetConstructorTest(test_base.DatasetTestBase): ], [shape for shape in iterator.output_shapes]) with self.cached_session() as sess: - self.evaluate(init_op) - results = self.evaluate(get_next) + sess.run(init_op) + results = sess.run(get_next) for component, result_component in zip(components, results): if sparse_tensor.is_sparse(component): self.assertSparseValuesEqual(component, result_component) @@ -139,9 +139,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): [t.shape for t in get_next]) with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(4): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component[i], result_component) with self.assertRaises(errors.OutOfRangeError): @@ -169,7 +169,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): [shape for shape in iterator.output_shapes]) with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) expected = [ (sparse_tensor.SparseTensorValue( indices=np.array([[0]]), @@ -197,7 +197,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): dense_shape=np.array([3]))), ] for i in range(3): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(expected[i], results): self.assertSparseValuesEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -229,7 +229,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): ], [shape for shape in iterator.output_shapes]) with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) expected = [ (sparse_tensor.SparseTensorValue( indices=np.array([[0]]), @@ -257,7 +257,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): dense_shape=np.array([3]))), ] for i in range(3): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip( (list(zip(*components[:3]))[i] + expected[i]), results): if sparse_tensor.is_sparse(component): @@ -280,9 +280,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): self.assertEqual((1,), iterator.output_shapes["bar"]) with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(3): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertEqual(components["foo"][i], results["foo"]) self.assertEqual(components["bar"][i], results["bar"]) with self.assertRaises(errors.OutOfRangeError): @@ -308,7 +308,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): dense_shape) sess.run(init_op, feed_dict={st: sparse_feed}) for i, s in enumerate(slices): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual(s, results.values) expected_indices = np.array( [[j] for j in range(len(slices[i]))]).reshape([-1, 1]) @@ -474,15 +474,15 @@ class DatasetConstructorTest(test_base.DatasetTestBase): with ops.device("/cpu:0"): var_0 = resource_variable_ops.ResourceVariable(initial_value=0) dataset = dataset.map(lambda x: x + var_0.read_value()) - self.evaluate(var_0.initializer) + sess.run(var_0.initializer) with ops.device("/cpu:1"): var_1 = resource_variable_ops.ResourceVariable(initial_value=0) dataset = dataset.map(lambda x: x + var_1.read_value()) - self.evaluate(var_1.initializer) + sess.run(var_1.initializer) iterator = dataset.make_initializable_iterator() - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) with self.assertRaisesRegexp( errors.FailedPreconditionError, @@ -506,7 +506,7 @@ class DatasetConstructorBenchmark(test.Benchmark): next_element = iterator.get_next() with session.Session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) # Run one whole epoch to burn in the computation. for _ in range(input_size // batch_size): sess.run(next_element) @@ -543,7 +543,7 @@ class DatasetConstructorBenchmark(test.Benchmark): next_element = iterator.get_next() with session.Session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) get_next_element = sess.make_callable(next_element) # Run one whole epoch to burn in the computation. for _ in range(input_size // batch_size): @@ -582,7 +582,7 @@ class DatasetConstructorBenchmark(test.Benchmark): next_element = iterator.get_next() with session.Session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) get_next_element = sess.make_callable(next_element) # Run one whole epoch to burn in the computation. for _ in range(input_size // batch_size): @@ -620,7 +620,7 @@ class DatasetConstructorBenchmark(test.Benchmark): next_element = iterator.get_next() with session.Session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) get_next_element = sess.make_callable(next_element) # Run one whole epoch to burn in the computation. for _ in range(input_size // batch_size): diff --git a/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py b/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py index 7087b4dd57..cb8cb9a77d 100644 --- a/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py @@ -47,10 +47,10 @@ class DatasetConstructorTest(test_base.DatasetTestBase): with self.cached_session() as sess: for _ in range(2): # Run twice to test reinitialization. - self.evaluate(init_op) + sess.run(init_op) for _ in range(num_repeats): for elem in elem_sequence: - self.assertAllEqual(elem, self.evaluate(get_next)) + self.assertAllEqual(elem, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -65,7 +65,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): with self.cached_session() as sess: for _ in range(num_repeats): for elem in elem_sequence: - self.assertAllEqual(elem, self.evaluate(get_next)) + self.assertAllEqual(elem, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -133,10 +133,10 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for _ in range(num_inner_repeats * num_outer_repeats): for elem in input_list: - val0, val1 = self.evaluate(get_next) + val0, val1 = sess.run(get_next) self.assertAllEqual(elem[0], val0) self.assertAllEqual(elem[1], val1) with self.assertRaises(errors.OutOfRangeError): @@ -192,10 +192,10 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for elem in [0, 1]: for _ in range(num_parallel_iterators): - self.assertAllEqual(elem, self.evaluate(get_next)) + self.assertAllEqual(elem, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -215,9 +215,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): self.assertEqual(dtype, get_next.dtype) with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for expected in [[1], [2], [3]]: - next_val = self.evaluate(get_next) + next_val = sess.run(get_next) self.assertEqual(dtype.as_numpy_dtype, next_val.dtype) self.assertAllEqual(expected, next_val) with self.assertRaises(errors.OutOfRangeError): @@ -236,9 +236,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for expected in [b"foo", b"bar", b"baz"]: - next_val = self.evaluate(get_next) + next_val = sess.run(get_next) self.assertAllEqual(expected, next_val) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -257,12 +257,12 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual([1, 2, 3], self.evaluate(get_next)) - self.assertAllEqual([4, 5, 6], self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual([1, 2, 3], sess.run(get_next)) + self.assertAllEqual([4, 5, 6], sess.run(get_next)) with self.assertRaisesOpError("The expected type was int64"): sess.run(get_next) - self.assertAllEqual([7, 8, 9], self.evaluate(get_next)) + self.assertAllEqual([7, 8, 9], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -280,12 +280,12 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual([1, 2, 3], self.evaluate(get_next)) - self.assertAllEqual([4, 5, 6], self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual([1, 2, 3], sess.run(get_next)) + self.assertAllEqual([4, 5, 6], sess.run(get_next)) with self.assertRaisesOpError(r"element of shape \(3,\) was expected"): sess.run(get_next) - self.assertAllEqual([11, 12, 13], self.evaluate(get_next)) + self.assertAllEqual([11, 12, 13], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -304,16 +304,16 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertEqual((1, 2), self.evaluate(get_next)) - self.assertEqual((3, 4), self.evaluate(get_next)) + sess.run(init_op) + self.assertEqual((1, 2), sess.run(get_next)) + self.assertEqual((3, 4), sess.run(get_next)) with self.assertRaisesOpError( r"The expected structure was \(tf\.int64, tf\.int64\)"): sess.run(get_next) with self.assertRaisesOpError( r"The expected structure was \(tf\.int64, tf\.int64\)"): sess.run(get_next) - self.assertEqual((9, 10), self.evaluate(get_next)) + self.assertEqual((9, 10), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -329,9 +329,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual(1, self.evaluate(get_next)) - self.assertAllEqual([2, 3], self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual(1, sess.run(get_next)) + self.assertAllEqual([2, 3], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -349,9 +349,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual(0, self.evaluate(get_next)) - self.assertAllEqual(1, self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual(0, sess.run(get_next)) + self.assertAllEqual(1, sess.run(get_next)) def testFromGeneratorDestructorCalled(self): # Use an `Event` to signal that the generator has been deleted. @@ -378,9 +378,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with session.Session() as sess: - self.evaluate(init_op) - self.assertAllEqual(42, self.evaluate(get_next)) - self.assertAllEqual(42, self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual(42, sess.run(get_next)) + self.assertAllEqual(42, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # Test that `GeneratorWrapper` object is destroyed when the @@ -407,10 +407,10 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) expected = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] for x in expected: - self.assertEqual(x, self.evaluate(get_next)) + self.assertEqual(x, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -436,13 +436,13 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) expected = [(0, b"Hi!"), (0, b"Hi!"), (1, b"Hi!"), (0, b"Hi!"), (1, b"Hi!"), (2, b"Hi!"), (0, b"Hi!"), (1, b"Hi!"), (2, b"Hi!"), (3, b"Hi!")] for x in expected: - self.assertEqual(x, self.evaluate(get_next)) + self.assertEqual(x, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -470,9 +470,9 @@ class DatasetConstructorTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual(37, self.evaluate(get_next)) - self.assertAllEqual(37, self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual(37, sess.run(get_next)) + self.assertAllEqual(37, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) self.assertTrue(event.is_set()) diff --git a/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py b/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py index 5ddb22285f..a0c6b37a6d 100644 --- a/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py @@ -67,7 +67,7 @@ class FilterDatasetTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={count: count_val, modulus: modulus_val}) for _ in range(count_val): for i in [x for x in range(7) if x**2 % modulus_val == 0]: - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): self.assertAllEqual(component[i]**2, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -86,9 +86,9 @@ class FilterDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.assertEqual(0, self.evaluate(get_next)) - self.assertEqual(1, self.evaluate(get_next)) - self.assertEqual(3, self.evaluate(get_next)) + self.assertEqual(0, sess.run(get_next)) + self.assertEqual(1, sess.run(get_next)) + self.assertEqual(3, sess.run(get_next)) def testFilterDict(self): iterator = (dataset_ops.Dataset.range(10) @@ -100,10 +100,10 @@ class FilterDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): if (i ** 2) % 2 == 0: - self.assertEqual(i * 2 + i**2, self.evaluate(get_next)) + self.assertEqual(i * 2 + i ** 2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -125,8 +125,8 @@ class FilterDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual(input_data[0], self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual(input_data[0], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -148,9 +148,9 @@ class FilterDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(5): - actual = self.evaluate(get_next) + actual = sess.run(get_next) self.assertTrue(isinstance(actual, sparse_tensor.SparseTensorValue)) self.assertSparseValuesEqual(actual, _map_fn(i * 2)[0]) with self.assertRaises(errors.OutOfRangeError): @@ -166,9 +166,9 @@ class FilterDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - self.assertEqual((i, True), self.evaluate(get_next)) + self.assertEqual((i, True), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -178,7 +178,7 @@ class FilterDatasetTest(test_base.DatasetTestBase): iterators = [dataset.make_one_shot_iterator() for _ in range(10)] next_elements = [iterator.get_next() for iterator in iterators] with self.cached_session() as sess: - self.assertEqual([0 for _ in range(10)], self.evaluate(next_elements)) + self.assertEqual([0 for _ in range(10)], sess.run(next_elements)) class FilterDatasetBenchmark(test.Benchmark): diff --git a/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py b/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py index 02979fc2c4..68038f9cfc 100644 --- a/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py @@ -45,10 +45,10 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in repeats: for _ in range(i): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -64,11 +64,11 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for row in repeats: for i in row: for _ in range(i): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -94,12 +94,12 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): with session.Session(server.target) as sess2: for _ in range(3): sess = random.choice([sess1, sess2]) - self.evaluate(init_op) + sess.run(init_op) for row in repeats: for i in row: for _ in range(i): sess = random.choice([sess1, sess2]) - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess = random.choice([sess1, sess2]) @@ -115,10 +115,10 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): for _ in range(i ** 2): - self.assertEqual(i * 2, self.evaluate(get_next)) + self.assertEqual(i * 2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # pylint: enable=g-long-lambda @@ -139,11 +139,11 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): for j in range(2): expected = [i, 0] if j % 2 == 0 else [0, -i] - self.assertAllEqual(expected, self.evaluate(get_next)) + self.assertAllEqual(expected, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py b/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py index 56434d6e4c..b911c249ce 100644 --- a/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py @@ -196,7 +196,7 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for expected_element in _interleave( _repeat(input_values, count), cycle_length, block_length): - self.assertEqual(expected_element, self.evaluate(get_next)) + self.assertEqual(expected_element, sess.run(get_next)) for _ in range(2): with self.assertRaises(errors.OutOfRangeError): @@ -231,7 +231,7 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.InvalidArgumentError): sess.run(get_next) else: - self.assertEqual(value, self.evaluate(get_next)) + self.assertEqual(value, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -254,7 +254,7 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for i in range(10): for j in range(2): expected = [i, 0] if j % 2 == 0 else [0, -i] - self.assertAllEqual(expected, self.evaluate(get_next)) + self.assertAllEqual(expected, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -308,7 +308,7 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for element in elements: coordination_events[element].set() - self.assertEqual(element * element, self.evaluate(get_next)) + self.assertEqual(element * element, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py b/tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py index cb38728f23..bf5fd781d6 100644 --- a/tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py +++ b/tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py @@ -57,7 +57,7 @@ class IteratorClusterTest(test.TestCase): with session.Session(worker[0].target) as sess: with self.assertRaises(errors.InvalidArgumentError): - self.evaluate(get_next_op) + sess.run(get_next_op) def _testRemoteIteratorHelper(self, device0, device1, target): with ops.device(device1): @@ -134,12 +134,12 @@ class IteratorClusterTest(test.TestCase): get_next = iterator.get_next() with session.Session(worker[0].target) as sess: - self.evaluate(table.initializer) - self.evaluate(init_op) - self.assertAllEqual([0, 0, -1, 1, 2], self.evaluate(get_next)) + sess.run(table.initializer) + sess.run(init_op) + self.assertAllEqual([0, 0, -1, 1, 2], sess.run(get_next)) with session.Session(worker[0].target) as sess: - self.assertAllEqual([2, 0], self.evaluate(get_next)) + self.assertAllEqual([2, 0], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -166,7 +166,7 @@ class IteratorClusterTest(test.TestCase): get_next = iterator.get_next() with session.Session(worker[0].target) as sess: - self.evaluate(init_op) + sess.run(init_op) for _ in range(3): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/iterator_ops_test.py b/tensorflow/python/data/kernel_tests/iterator_ops_test.py index 405d94d956..490ca813dc 100644 --- a/tensorflow/python/data/kernel_tests/iterator_ops_test.py +++ b/tensorflow/python/data/kernel_tests/iterator_ops_test.py @@ -97,7 +97,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: for _ in range(14): for i in range(7): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): self.assertAllEqual(component[i]**2, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -123,7 +123,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: for _ in range(14): for i in range(7): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): self.assertAllEqual(component[i]**2, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -159,7 +159,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): for _ in range(14): for i in range(7): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): self.assertAllEqual(component[i]**2, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -175,7 +175,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): config = config_pb2.ConfigProto( inter_op_parallelism_threads=1, use_per_session_threads=True) with session.Session(config=config) as sess: - self.assertAllEqual([1, 4, 9], self.evaluate(next_element)) + self.assertAllEqual([1, 4, 9], sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -254,15 +254,15 @@ class IteratorTest(test.TestCase, parameterized.TestCase): get_next = iterator.get_next() with session.Session(server.target) as sess: - self.evaluate(init_op) - results = self.evaluate(get_next) + sess.run(init_op) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # Re-initialize the iterator in the first session. - self.evaluate(init_op) + sess.run(init_op) with ops.Graph().as_default(): # Re-define the iterator manually, without defining any of the @@ -277,7 +277,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with session.Session(server.target) as sess: # Use the iterator without re-initializing in the second session. - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -317,20 +317,20 @@ class IteratorTest(test.TestCase, parameterized.TestCase): sess.run(get_next) # Initialize with one dataset. - self.evaluate(dataset_3_init_op) - self.assertAllEqual([1, 2, 3], self.evaluate(get_next)) + sess.run(dataset_3_init_op) + self.assertAllEqual([1, 2, 3], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # Initialize with a different dataset. - self.evaluate(dataset_4_init_op) - self.assertAllEqual([4, 5, 6, 7], self.evaluate(get_next)) + sess.run(dataset_4_init_op) + self.assertAllEqual([4, 5, 6, 7], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) # Reinitialize with the first dataset. - self.evaluate(dataset_3_init_op) - self.assertAllEqual([1, 2, 3], self.evaluate(get_next)) + sess.run(dataset_3_init_op) + self.assertAllEqual([1, 2, 3], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -348,7 +348,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): g, output_types=dtypes.int64) sess.run(iterator.make_initializer(dataset_1)) for expected in range(10): - self.assertEqual(expected, self.evaluate(next_element)) + self.assertEqual(expected, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -356,7 +356,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): g, output_types=dtypes.int64) sess.run(iterator.make_initializer(dataset_2)) for expected in range(10): - self.assertEqual(expected, self.evaluate(next_element)) + self.assertEqual(expected, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -679,10 +679,10 @@ class IteratorTest(test.TestCase, parameterized.TestCase): n = itr.get_next() with session.Session(s3.target, config=config) as sess: - self.evaluate(itr.initializer) + sess.run(itr.initializer) expected_values = worker_devices for expected in expected_values: - self.assertEqual((compat.as_bytes(expected),), self.evaluate(n)) + self.assertEqual((compat.as_bytes(expected),), sess.run(n)) with self.assertRaises(errors.OutOfRangeError): sess.run(n) @@ -786,8 +786,8 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with ops.Graph().as_default() as g: init_op, _, save_op, _ = _build_range_dataset_graph() with self.session(graph=g) as sess: - self.evaluate(init_op) - self.evaluate(save_op) + sess.run(init_op) + sess.run(save_op) # Attempt to restore the saved iterator into an IteratorResource of # incompatible type. An iterator of RangeDataset has output type int64, @@ -798,7 +798,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): _, _, _, restore_op = _build_reader_dataset_graph() with self.session(graph=g) as sess: with self.assertRaises(errors.InvalidArgumentError): - self.evaluate(restore_op) + sess.run(restore_op) def testRepeatedGetNextWarning(self): iterator = dataset_ops.Dataset.range(10).make_one_shot_iterator() @@ -949,7 +949,7 @@ class IteratorCheckpointingTest(test.TestCase): checkpoint.restore(checkpoint_management.latest_checkpoint( checkpoint_directory)).initialize_or_restore(sess) for j in range(2): - self.assertEqual(i * 2 + j, self.evaluate(get_next)) + self.assertEqual(i * 2 + j, sess.run(get_next)) checkpoint.save(file_prefix=checkpoint_prefix) diff --git a/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py b/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py index ac6fbabcd5..b58c1444da 100644 --- a/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py @@ -102,7 +102,7 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): all_produced_filenames = [] for _ in range(3): produced_filenames = [] - self.evaluate(itr.initializer) + sess.run(itr.initializer) try: while True: produced_filenames.append(sess.run(next_element)) diff --git a/tensorflow/python/data/kernel_tests/map_dataset_op_test.py b/tensorflow/python/data/kernel_tests/map_dataset_op_test.py index 8f7a19d7e1..187b9da14c 100644 --- a/tensorflow/python/data/kernel_tests/map_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/map_dataset_op_test.py @@ -114,7 +114,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(init_op, feed_dict={count: 14}) for _ in range(14): for i in range(7): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): self.assertAllEqual(component[i]**2, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -185,7 +185,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): output_buffer_size: output_buffer_size_val}) for _ in range(14): for i in range(7): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): self.assertAllEqual(component[i]**2, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -242,7 +242,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for _ in range(3): sess.run(get_next) @@ -257,7 +257,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for _ in range(3): sess.run(get_next) @@ -272,7 +272,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for _ in range(3): sess.run(get_next) # The 4th element is NaN, so `array_ops.check_numerics()` should fail. @@ -293,7 +293,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for _ in range(3): sess.run(get_next) # The 4th element is NaN, so `array_ops.check_numerics()` should fail. @@ -325,10 +325,10 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with ops.Graph().as_default() as g: captured_init_op, init_op, get_next = _build_graph() with self.session(graph=g) as sess: - self.evaluate(captured_init_op) - self.evaluate(init_op) + sess.run(captured_init_op) + sess.run(init_op) for i in range(10): - self.assertEqual(i * i, self.evaluate(get_next)) + self.assertEqual(i * i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -353,8 +353,8 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(table.initializer) - self.evaluate(init_op) + sess.run(table.initializer) + sess.run(init_op) sess.run(get_next) sess.run(get_next) with self.assertRaises(errors.OutOfRangeError): @@ -371,11 +371,11 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(enqueue_op) - self.evaluate(close_op) - self.evaluate(init_op) + sess.run(enqueue_op) + sess.run(close_op) + sess.run(init_op) for element in elements: - self.assertEqual(element, self.evaluate(get_next)) + self.assertEqual(element, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -396,9 +396,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(enqueue_op) - self.evaluate(close_op) - self.evaluate(init_op) + sess.run(enqueue_op) + sess.run(close_op) + sess.run(init_op) for i in range(100): self.assertEqual(sorted([elements[i * 2], elements[i * 2 + 1]]), sorted(sess.run(get_next))) @@ -415,15 +415,15 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(counter_var.initializer) - self.evaluate(init_op) + sess.run(counter_var.initializer) + sess.run(init_op) for i in range(10): - self.assertEqual(i, self.evaluate(counter_var)) - self.assertEqual(i + 1, self.evaluate(get_next)) - self.assertEqual(10, self.evaluate(counter_var)) + self.assertEqual(i, sess.run(counter_var)) + self.assertEqual(i + 1, sess.run(get_next)) + self.assertEqual(10, sess.run(counter_var)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) - self.assertEqual(10, self.evaluate(counter_var)) + self.assertEqual(10, sess.run(counter_var)) def testCaptureUninitializedVariableError(self): counter_var = variable_scope.get_variable( @@ -435,7 +435,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaises(errors.NotFoundError): sess.run(get_next) @@ -447,14 +447,14 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) random_values = [] with self.assertRaises(errors.OutOfRangeError): while True: random_values.extend(sess.run(get_next)) self.assertEqual(10, len(random_values)) self.assertGreater(np.abs(np.diff(random_values)).max(), 1e-6) - self.evaluate(init_op) + sess.run(init_op) random_values_2 = [] with self.assertRaises(errors.OutOfRangeError): while True: @@ -473,8 +473,8 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - random_values = self.evaluate(get_next) + sess.run(init_op) + random_values = sess.run(get_next) # Assert that one of the next 99 batches yielded by the iterator is # different from the first. @@ -500,15 +500,15 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(counter_var.initializer) - self.evaluate(init_op) + sess.run(counter_var.initializer) + sess.run(init_op) for i in range(10): - self.assertEqual(i, self.evaluate(counter_var)) - self.assertEqual(i, self.evaluate(get_next)) - self.assertEqual(10, self.evaluate(counter_var)) + self.assertEqual(i, sess.run(counter_var)) + self.assertEqual(i, sess.run(get_next)) + self.assertEqual(10, sess.run(counter_var)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) - self.assertEqual(10, self.evaluate(counter_var)) + self.assertEqual(10, sess.run(counter_var)) def testMapDict(self): iterator = (dataset_ops.Dataset.range(10) @@ -519,9 +519,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - self.assertEqual(i * 2 + i**2, self.evaluate(get_next)) + self.assertEqual(i * 2 + i ** 2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -569,8 +569,8 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) - self.assertAllEqual(row**2, self.evaluate(get_next)) + sess.run(init_op) + self.assertAllEqual(row ** 2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -611,7 +611,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): row = np.arange(6) for num in [2, 3, 4]: init_op, get_next = build_dataset(row, num) - self.evaluate(init_op) + sess.run(init_op) for i in range(6): self.assertEqual( (i // 2 if i % 2 else i * 2) if (num == 2 or num == 3) else i * 2, @@ -652,7 +652,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): row = np.arange(6) for num in [2, 3, 4]: init_op, get_next = build_dataset(row, num) - self.evaluate(init_op) + sess.run(init_op) self.assertAllEqual( [x // 2 if (num == 2 or num == 3) else x * 2 for x in row], sess.run(get_next)) @@ -697,7 +697,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) self.assertAllEqual([(x // 2 if x % 2 else x * 2) if (num == 2 or num == 3) else x * 2 for x in row], sess.run(get_next)) @@ -735,7 +735,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for buffer_size in [1, 10, 100, 1000]: sess.run(init_op, feed_dict={buffer_size_placeholder: buffer_size}) for i in range(100): - self.assertEqual(i * i, self.evaluate(get_next)) + self.assertEqual(i * i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -753,10 +753,10 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(init_op, feed_dict={buffer_size_placeholder: buffer_size}) for i in range(event_will_be_set_after_consuming): self.assertFalse(ev.is_set()) - self.assertEqual(i * i, self.evaluate(get_next)) + self.assertEqual(i * i, sess.run(get_next)) ev.wait() for i in range(event_will_be_set_after_consuming, 100): - self.assertEqual(i * i, self.evaluate(get_next)) + self.assertEqual(i * i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -768,9 +768,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - self.assertEqual((i, 37.0), self.evaluate(get_next)) + self.assertEqual((i, 37.0), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -789,9 +789,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - self.assertEqual((i, 37.0), self.evaluate(get_next)) + self.assertEqual((i, 37.0), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -810,9 +810,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - actual = self.evaluate(get_next) + actual = sess.run(get_next) self.assertIsInstance(actual, sparse_tensor.SparseTensorValue) self.assertSparseValuesEqual(actual, _sparse(i)) with self.assertRaises(errors.OutOfRangeError): @@ -837,9 +837,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - actual = self.evaluate(get_next) + actual = sess.run(get_next) self.assertIsInstance(actual, sparse_tensor.SparseTensorValue) self.assertSparseValuesEqual(actual, _check(_sparse(i)).eval()) with self.assertRaises(errors.OutOfRangeError): @@ -861,9 +861,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(100): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -875,9 +875,9 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for i in range(10): - self.assertEqual((i, b"hello", 10), self.evaluate(get_next)) + self.assertEqual((i, b"hello", 10), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -945,7 +945,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: with self.assertRaisesRegexp(errors.InvalidArgumentError, "BrokenConst"): - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) # pylint: disable=g-long-lambda @parameterized.named_parameters( @@ -972,7 +972,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - tids = self.evaluate(get_next) + tids = sess.run(get_next) self.assertTrue(all(tids[0] == tid for tid in tids)) # pylint: enable=g-long-lambda @@ -996,7 +996,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): expected = map_fn(*sess.run(self.structuredElement(structure))) else: expected = map_fn(sess.run(self.structuredElement(structure))) - self.assertEqual(expected, self.evaluate(get_next)) + self.assertEqual(expected, sess.run(get_next)) @parameterized.named_parameters( ("Sequential", None), @@ -1011,7 +1011,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={captured_t: 42}) - self.assertEqual(42, self.evaluate(get_next)) + self.assertEqual(42, sess.run(get_next)) @parameterized.named_parameters( ("1", 1, 1), @@ -1030,7 +1030,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session(config=config) as sess: for i in range(num_elements): coordination_events[i].set() - self.assertEqual(i * i, self.evaluate(get_next)) + self.assertEqual(i * i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -1052,7 +1052,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for element in elements: coordination_events[element].set() - self.assertEqual(element * element, self.evaluate(get_next)) + self.assertEqual(element * element, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py index ea6828e575..42ee1e2186 100644 --- a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py +++ b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py @@ -40,7 +40,7 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) def testBasic(self): dataset = dataset_ops.Dataset.range(10) @@ -50,10 +50,10 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) - self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i + 1, sess.run(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -67,10 +67,10 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) - self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i + 1, sess.run(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -85,12 +85,12 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 20, 4): - self.assertEqual(i, self.evaluate(elem_on_1)) - self.assertEqual(i + 1, self.evaluate(elem_on_2)) - self.assertEqual(i + 2, self.evaluate(elem_on_3)) - self.assertEqual(i + 3, self.evaluate(elem_on_4)) + self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i + 2, sess.run(elem_on_3)) + self.assertEqual(i + 3, sess.run(elem_on_4)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -105,11 +105,11 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 8, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) - self.assertEqual(i + 1, self.evaluate(elem_on_2)) - self.assertEqual(8, self.evaluate(elem_on_1)) + self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(8, sess.run(elem_on_1)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -126,7 +126,7 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 8, 2): elem_on_1_has_value, elem_on_1_value = sess.run( [elem_on_1_has_value_t, elem_on_1_t]) @@ -140,8 +140,8 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): [elem_on_1_has_value_t, elem_on_1_t]) self.assertTrue(elem_on_1_has_value) self.assertEqual(8, elem_on_1_value) - self.assertFalse(self.evaluate(elem_on_1_has_value_t)) - self.assertFalse(self.evaluate(elem_on_2_has_value_t)) + self.assertFalse(sess.run(elem_on_1_has_value_t)) + self.assertFalse(sess.run(elem_on_2_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): sess.run(elem_on_1_t) with self.assertRaises(errors.InvalidArgumentError): @@ -155,11 +155,11 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i, sess.run(elem_on_1)) for i in range(0, 10, 2): - self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i + 1, sess.run(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -192,10 +192,10 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2, "GPU": 1}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) - self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i + 1, sess.run(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -211,11 +211,11 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2, "GPU": 1}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i, sess.run(elem_on_1)) for i in range(0, 10, 2): - self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i + 1, sess.run(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) @@ -235,7 +235,7 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2, "GPU": 1}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 8, 2): elem_on_1_has_value, elem_on_1_value = sess.run( [elem_on_1_has_value_t, elem_on_1_t]) @@ -249,8 +249,8 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): [elem_on_1_has_value_t, elem_on_1_t]) self.assertTrue(elem_on_1_has_value) self.assertEqual(8, elem_on_1_value) - self.assertFalse(self.evaluate(elem_on_1_has_value_t)) - self.assertFalse(self.evaluate(elem_on_2_has_value_t)) + self.assertFalse(sess.run(elem_on_1_has_value_t)) + self.assertFalse(sess.run(elem_on_2_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): sess.run(elem_on_1_t) with self.assertRaises(errors.InvalidArgumentError): @@ -272,10 +272,10 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - self.evaluate(multi_device_iterator.initializer) + sess.run(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, self.evaluate(elem_on_1)) - self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i + 1, sess.run(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): sess.run(elem_on_1) sess.run(elem_on_2) diff --git a/tensorflow/python/data/kernel_tests/optional_ops_test.py b/tensorflow/python/data/kernel_tests/optional_ops_test.py index 0981ff9651..604e3ad88e 100644 --- a/tensorflow/python/data/kernel_tests/optional_ops_test.py +++ b/tensorflow/python/data/kernel_tests/optional_ops_test.py @@ -227,7 +227,7 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): # For each element of the dataset, assert that the optional evaluates to # the expected value. - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) for _ in range(3): elem_has_value, elem_value = sess.run([elem_has_value_t, elem_value_t]) self.assertTrue(elem_has_value) @@ -236,7 +236,7 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): # After exhausting the iterator, `next_elem.has_value()` will evaluate to # false, and attempting to get the value will fail. for _ in range(2): - self.assertFalse(self.evaluate(elem_has_value_t)) + self.assertFalse(sess.run(elem_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): sess.run(elem_value_t) diff --git a/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py index af326ec210..76e2697b29 100644 --- a/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py @@ -40,7 +40,7 @@ class PrefetchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(init_op, feed_dict={buffer_size_t: buffer_size}) for m in range(10): - self.assertEqual(m, self.evaluate(get_next)) + self.assertEqual(m, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/range_dataset_op_test.py b/tensorflow/python/data/kernel_tests/range_dataset_op_test.py index fcb025c8b8..9fc79707d0 100644 --- a/tensorflow/python/data/kernel_tests/range_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/range_dataset_op_test.py @@ -124,19 +124,19 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next, _, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(init_op) - self.evaluate(restore_op) + sess.run(init_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -144,14 +144,14 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): with ops.Graph().as_default() as g: init_op, get_next, save_op, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) - self.evaluate(restore_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -175,14 +175,14 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop, num_epochs) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for _ in range(break_epoch): for i in range(start, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: # Create an empty IteratorResource and restore the Iterator into it. @@ -193,12 +193,12 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): restore_op = self._restore_op(iterator._iterator_resource) get_next = iterator.get_next() with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) for _ in range(break_epoch + 1, num_epochs): for i in range(start, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -221,20 +221,20 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: # Intentionally build a graph with a different value for stop to make sure # the original dataset graph is actually getting loaded. init_op, get_next, _, restore_op = _build_graph(start, stop_1) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -259,19 +259,19 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next, _, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(init_op) - self.evaluate(restore_op) + sess.run(init_op) + sess.run(restore_op) for i in range(break_point, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -294,27 +294,27 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) for i in range(start, break_point1): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next, save_op, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for i in range(break_point1, break_point2): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) break_point2 = 7 with ops.Graph().as_default() as g: init_op, get_next, save_op, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for i in range(break_point2, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -338,28 +338,28 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): init_op, get_next, save_op, restore_op = _build_graph( start, stop, num_epochs) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for _ in range(break_epoch - 1): for i in range(start, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) for i in range(start, break_range): - self.assertEqual(i, self.evaluate(get_next)) - self.evaluate(save_op) + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for i in range(break_range, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) for _ in range(break_epoch, num_epochs): for i in range(start, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -381,23 +381,23 @@ class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): init_op, get_next, save_op, restore_op = _build_graph( start, stop, num_epochs) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) - self.evaluate(init_op) + sess.run(variables.global_variables_initializer()) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for _ in range(num_epochs): for i in range(start, stop): - self.assertEqual(i, self.evaluate(get_next)) + self.assertEqual(i, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) - self.evaluate(save_op) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py b/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py index e26381e902..4fef4f30bf 100644 --- a/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py @@ -107,7 +107,7 @@ class TextLineDatasetTest(test_base.DatasetTestBase): init_op, feed_dict={filenames: [test_filenames[0]], num_epochs: 1}) for i in range(5): - self.assertEqual(self._lineText(0, i), self.evaluate(get_next)) + self.assertEqual(self._lineText(0, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -116,7 +116,7 @@ class TextLineDatasetTest(test_base.DatasetTestBase): init_op, feed_dict={filenames: [test_filenames[1]], num_epochs: 1}) for i in range(5): - self.assertEqual(self._lineText(1, i), self.evaluate(get_next)) + self.assertEqual(self._lineText(1, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -124,7 +124,7 @@ class TextLineDatasetTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={filenames: test_filenames, num_epochs: 1}) for j in range(2): for i in range(5): - self.assertEqual(self._lineText(j, i), self.evaluate(get_next)) + self.assertEqual(self._lineText(j, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -133,7 +133,7 @@ class TextLineDatasetTest(test_base.DatasetTestBase): for _ in range(10): for j in range(2): for i in range(5): - self.assertEqual(self._lineText(j, i), self.evaluate(get_next)) + self.assertEqual(self._lineText(j, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -267,7 +267,7 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, feed_dict={filenames: [test_filenames[0]], num_epochs: 1}) for i in range(self._num_records): - self.assertEqual(self._record(0, i), self.evaluate(get_next)) + self.assertEqual(self._record(0, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -276,7 +276,7 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, feed_dict={filenames: [test_filenames[1]], num_epochs: 1}) for i in range(self._num_records): - self.assertEqual(self._record(1, i), self.evaluate(get_next)) + self.assertEqual(self._record(1, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -284,7 +284,7 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={filenames: test_filenames, num_epochs: 1}) for j in range(self._num_files): for i in range(self._num_records): - self.assertEqual(self._record(j, i), self.evaluate(get_next)) + self.assertEqual(self._record(j, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -293,7 +293,7 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): for _ in range(10): for j in range(self._num_files): for i in range(self._num_records): - self.assertEqual(self._record(j, i), self.evaluate(get_next)) + self.assertEqual(self._record(j, i), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -405,19 +405,19 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): if (epoch == epoch_break and f == file_break and r == record_break): - self.evaluate(save_op) + sess.run(save_op) break - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) else: continue break @@ -426,13 +426,13 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): break else: with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) with ops.Graph().as_default() as g: init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): @@ -441,9 +441,9 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): (epoch == epoch_break and f == file_break and r < record_break)): continue - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) def testInitThenRestore(self): # Note: Calling init_op before restore_op is redundant. This test just makes @@ -458,19 +458,19 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): if (epoch == epoch_break and f == file_break and r == record_break): - self.evaluate(save_op) + sess.run(save_op) break - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) else: continue break @@ -479,14 +479,14 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): break else: with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) with ops.Graph().as_default() as g: init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) - self.evaluate(restore_op) + sess.run(init_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): @@ -495,9 +495,9 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): (epoch == epoch_break and f == file_break and r < record_break)): continue - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) def testRestoreInModifiedGraph(self): num_epochs = 10 @@ -510,19 +510,19 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): if (epoch == epoch_break and f == file_break and r == record_break): - self.evaluate(save_op) + sess.run(save_op) break - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) else: continue break @@ -531,13 +531,13 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): break else: with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) with ops.Graph().as_default() as g: init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs_1) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): @@ -546,9 +546,9 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): (epoch == epoch_break and f == file_break and r < record_break)): continue - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) def testRestoreWithoutBuildingDatasetGraph(self): num_epochs = 10 @@ -560,19 +560,19 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): if (epoch == epoch_break and f == file_break and r == record_break): - self.evaluate(save_op) + sess.run(save_op) break - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) else: continue break @@ -581,12 +581,12 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): break else: with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) with ops.Graph().as_default() as g: restore_op, get_next_op = self._restore_iterator() with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for epoch in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): @@ -595,9 +595,9 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): (epoch == epoch_break and f == file_break and r < record_break)): continue - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) def testRestoreUnusedIterator(self): num_epochs = 10 @@ -605,22 +605,22 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) # Save unused iterator. - self.evaluate(save_op) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) for _ in range(num_epochs * self._num_files * self._num_records): - self.evaluate(get_next_op) + sess.run(get_next_op) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) def testRestoreExhaustedIterator(self): num_epochs = 10 @@ -629,26 +629,26 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(init_op) + sess.run(init_op) # Note: There is no checkpoint saved currently so a NotFoundError is # raised. with self.assertRaises(errors.NotFoundError): - self.evaluate(restore_op) + sess.run(restore_op) for _ in range(num_epochs): for f in range(self._num_files): for r in range(self._num_records): - self.assertEqual(self._record(f, r), self.evaluate(get_next_op)) + self.assertEqual(self._record(f, r), sess.run(get_next_op)) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) - self.evaluate(save_op) + sess.run(get_next_op) + sess.run(save_op) with ops.Graph().as_default() as g: init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( num_epochs=num_epochs) with self.session(graph=g) as sess: - self.evaluate(restore_op) + sess.run(restore_op) with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next_op) + sess.run(get_next_op) class TFRecordDatasetTest(test_base.DatasetTestBase): @@ -807,7 +807,7 @@ class TFRecordDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: for j in range(self._num_files): for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), self.evaluate(next_element)) + self.assertAllEqual(self._record(j, i), sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -819,7 +819,7 @@ class TFRecordDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: for j in range(self._num_files): for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), self.evaluate(next_element)) + self.assertAllEqual(self._record(j, i), sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) diff --git a/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py b/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py index d7f3988b1a..11e07300b9 100644 --- a/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py @@ -36,7 +36,7 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ds = dataset_ops.Dataset.range(1, i + 1) result = ds.reduce(np.int64(0), lambda x, y: x + y) with self.cached_session() as sess: - self.assertEqual(((i + 1) * i) // 2, self.evaluate(result)) + self.assertEqual(((i + 1) * i) // 2, sess.run(result)) def testSumTuple(self): @@ -49,7 +49,7 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ds = dataset_ops.Dataset.zip((ds, ds)) result = ds.reduce(np.int64(0), reduce_fn) with self.cached_session() as sess: - self.assertEqual(((i + 1) * i), self.evaluate(result)) + self.assertEqual(((i + 1) * i), sess.run(result)) def testSumAndCount(self): @@ -61,7 +61,7 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ds = dataset_ops.Dataset.range(1, i + 1) result = ds.reduce((np.int64(0), np.int64(0)), reduce_fn) with self.cached_session() as sess: - s, c = self.evaluate(result) + s, c = sess.run(result) self.assertEqual(((i + 1) * i) // 2, s) self.assertEqual(i, c) @@ -93,8 +93,7 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ds = dataset_ops.Dataset.from_tensors(make_sparse_fn(i+1)) result = ds.reduce(make_sparse_fn(0), reduce_fn) with self.cached_session() as sess: - self.assertSparseValuesEqual( - make_sparse_fn(i + 1), self.evaluate(result)) + self.assertSparseValuesEqual(make_sparse_fn(i+1), sess.run(result)) def testNested(self): @@ -117,7 +116,7 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ds = dataset_ops.Dataset.range(1, i + 1).map(map_fn) result = ds.reduce(map_fn(0), reduce_fn) with self.cached_session() as sess: - result = self.evaluate(result) + result = sess.run(result) self.assertEqual(((i + 1) * i) // 2, result["dense"]) self.assertSparseValuesEqual(make_sparse_fn(i), result["sparse"]) diff --git a/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py b/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py index 946aa01f73..e86356dee7 100644 --- a/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py @@ -49,7 +49,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # Test a finite repetition. sess.run(init_op, feed_dict={count_placeholder: 3}) for _ in range(3): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) @@ -59,7 +59,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # Test a different finite repetition. sess.run(init_op, feed_dict={count_placeholder: 7}) for _ in range(7): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -75,7 +75,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # actually is infinite. sess.run(init_op, feed_dict={count_placeholder: -1}) for _ in range(17): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) @@ -95,7 +95,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # Take fewer than input size sess.run(init_op, feed_dict={count_placeholder: 4}) for i in range(4): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual(results, components[0][i:i+1]) with self.assertRaises(errors.OutOfRangeError): @@ -104,7 +104,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # Take more than input size sess.run(init_op, feed_dict={count_placeholder: 25}) for i in range(10): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual(results, components[0][i:i+1]) with self.assertRaises(errors.OutOfRangeError): @@ -113,7 +113,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # Take all of input sess.run(init_op, feed_dict={count_placeholder: -1}) for i in range(10): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual(results, components[0][i:i+1]) with self.assertRaises(errors.OutOfRangeError): @@ -142,7 +142,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # the first 4 elements and then read the rest. sess.run(init_op, feed_dict={count_placeholder: 4}) for i in range(4, 10): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual(results, components[0][i:i+1]) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -165,7 +165,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # Skip nothing sess.run(init_op, feed_dict={count_placeholder: 0}) for i in range(0, 10): - results = self.evaluate(get_next) + results = sess.run(get_next) self.assertAllEqual(results, components[0][i:i+1]) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -187,7 +187,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: sess.run(init_op, feed_dict={inner_count: 7, outer_count: 14}) for _ in range(7 * 14): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) with self.assertRaises(errors.OutOfRangeError): @@ -201,7 +201,7 @@ class SequenceDatasetTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py b/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py index 990f4f212b..cad28f860e 100644 --- a/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py @@ -66,7 +66,7 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: # First run without shuffling to collect the "ground truth". - self.evaluate(init_fifo_op) + sess.run(init_fifo_op) unshuffled_elements = [] for _ in range(20): unshuffled_elements.append(sess.run(get_next)) @@ -159,7 +159,7 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={seed_placeholder: 0}) for elem in elems: - self.assertEqual(elem, self.evaluate(get_next)) + self.assertEqual(elem, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -188,9 +188,9 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): next_element = iterator.get_next() with self.cached_session() as sess: - initial_permutation = self.evaluate(next_element) - self.assertAllEqual(initial_permutation, self.evaluate(next_element)) - self.assertAllEqual(initial_permutation, self.evaluate(next_element)) + initial_permutation = sess.run(next_element) + self.assertAllEqual(initial_permutation, sess.run(next_element)) + self.assertAllEqual(initial_permutation, sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -261,7 +261,7 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.session(graph=g) as sess: for iterator in iterators: if initializable: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) next_element = iterator.get_next() run_results = [] for _ in range(300): diff --git a/tensorflow/python/data/kernel_tests/window_dataset_op_test.py b/tensorflow/python/data/kernel_tests/window_dataset_op_test.py index 35adcddfe7..9d06781094 100644 --- a/tensorflow/python/data/kernel_tests/window_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/window_dataset_op_test.py @@ -102,7 +102,7 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): num_full_batches = max( 0, (count * 7 - ((size - 1) * stride + 1)) // shift + 1) for i in range(num_full_batches): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): for j in range(size): self.assertAllEqual(component[(i * shift + j * stride) % 7]**2, @@ -111,7 +111,7 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): num_partial_batches = (count * 7) // shift + ( (count * 7) % shift > 0) - num_full_batches for i in range(num_partial_batches): - result = self.evaluate(get_next) + result = sess.run(get_next) for component, result_component in zip(components, result): remaining = (count * 7) - ((num_full_batches + i) * shift) num_elements = remaining // stride + ((remaining % stride) > 0) @@ -164,10 +164,10 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) num_batches = (10 - 5) // 3 + 1 for i in range(num_batches): - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 3, i * 3 + 1, i * 3 + 2, i * 3 + 3, i * 3 + 4], @@ -193,10 +193,10 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) num_batches = (10 - 5) // 3 + 1 for i in range(num_batches): - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected_indices = [] expected_values = [] for j in range(5): @@ -227,9 +227,9 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) # Slide: 1st batch. - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [2, 0, 0], [2, 1, 0], @@ -239,7 +239,7 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertTrue(sparse_tensor.is_sparse(actual)) self.assertSparseValuesEqual(actual, expected) # Slide: 2nd batch. - actual = self.evaluate(get_next) + actual = sess.run(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [2, 0, 0], [2, 1, 0], @@ -265,7 +265,7 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): next_element = iterator.get_next() with self.cached_session() as sess: - self.evaluate(iterator.initializer) + sess.run(iterator.initializer) with self.assertRaisesRegexp( errors.InvalidArgumentError, r"Cannot batch tensors with different shapes in component 0. " @@ -281,8 +281,8 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = dataset.make_one_shot_iterator().get_next() with self.cached_session() as sess: - self.assertAllEqual(np.float32([1., 2.]), self.evaluate(get_next)) - self.assertAllEqual(np.float32([2., 3.]), self.evaluate(get_next)) + self.assertAllEqual(np.float32([1., 2.]), sess.run(get_next)) + self.assertAllEqual(np.float32([2., 3.]), sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) diff --git a/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py b/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py index b60ec4ecce..9d76387a34 100644 --- a/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py @@ -55,7 +55,7 @@ class ZipDatasetTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={ph: value for ph, value in zip( component_placeholders, equal_length_components)}) for i in range(4): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip( equal_length_components, results): self.assertAllEqual(component[i], result_component) @@ -66,7 +66,7 @@ class ZipDatasetTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={ph: value for ph, value in zip( component_placeholders, variable_length_components)}) for i in range(2): - results = self.evaluate(get_next) + results = sess.run(get_next) for component, result_component in zip( variable_length_components, results): self.assertAllEqual(component[i], result_component) @@ -103,7 +103,7 @@ class ZipDatasetTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={ph: value for ph, value in zip( component_placeholders, equal_length_components)}) for i in range(4): - result1, (result2, result3) = self.evaluate(get_next) + result1, (result2, result3) = sess.run(get_next) self.assertAllEqual(equal_length_components[0][i], result1) self.assertAllEqual(equal_length_components[1][i], result2) self.assertAllEqual(equal_length_components[2][i], result3) diff --git a/tensorflow/python/data/util/convert_test.py b/tensorflow/python/data/util/convert_test.py index 4a5b730381..89c3afb296 100644 --- a/tensorflow/python/data/util/convert_test.py +++ b/tensorflow/python/data/util/convert_test.py @@ -31,24 +31,24 @@ class ConvertTest(test.TestCase): def testInteger(self): resp = convert.optional_param_to_tensor("foo", 3) with self.cached_session() as sess: - self.assertEqual(3, self.evaluate(resp)) + self.assertEqual(3, sess.run(resp)) def testIntegerDefault(self): resp = convert.optional_param_to_tensor("foo", None) with self.cached_session() as sess: - self.assertEqual(0, self.evaluate(resp)) + self.assertEqual(0, sess.run(resp)) def testStringDefault(self): resp = convert.optional_param_to_tensor("bar", None, "default", dtypes.string) with self.cached_session() as sess: - self.assertEqual(compat.as_bytes("default"), self.evaluate(resp)) + self.assertEqual(compat.as_bytes("default"), sess.run(resp)) def testString(self): resp = convert.optional_param_to_tensor("bar", "value", "default", dtypes.string) with self.cached_session() as sess: - self.assertEqual(compat.as_bytes("value"), self.evaluate(resp)) + self.assertEqual(compat.as_bytes("value"), sess.run(resp)) def testPartialShapeToTensorKnownDimension(self): with self.cached_session() as sess: diff --git a/tensorflow/python/debug/cli/analyzer_cli_test.py b/tensorflow/python/debug/cli/analyzer_cli_test.py index 5aa7d1bb4c..f197a9e4dc 100644 --- a/tensorflow/python/debug/cli/analyzer_cli_test.py +++ b/tensorflow/python/debug/cli/analyzer_cli_test.py @@ -1583,7 +1583,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): x = variables.VariableV1([1, 3, 3, 7], name="x") _, idx = array_ops.unique(x, name="x_unique") idx_times_two = math_ops.multiply(idx, 2, name="idx_times_two") - self.evaluate(x.initializer) + sess.run(x.initializer) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph( diff --git a/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py b/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py index 34030c0adc..1f67f8a0d4 100644 --- a/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py +++ b/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py @@ -126,8 +126,8 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): u = variables.Variable([12.0], name="u") v = variables.Variable([30.0], name="v") w = math_ops.add(u, v, name="w") - self.evaluate(u.initializer) - self.evaluate(v.initializer) + sess.run(u.initializer) + sess.run(v.initializer) self._compareOriginalAndReconstructedGraphDefs( sess, w, expected_output=[42.0]) @@ -139,7 +139,7 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): b = math_ops.add(a, a, name="b") with ops.control_dependencies([a, b]): c = math_ops.multiply(b, b, name="c") - self.evaluate(a.initializer) + sess.run(a.initializer) self._compareOriginalAndReconstructedGraphDefs( sess, c, expected_output=400.0) @@ -150,8 +150,8 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): y = variables.Variable(20.0, name="y") cond = control_flow_ops.cond( x > y, lambda: math_ops.add(x, 1), lambda: math_ops.add(y, 1)) - self.evaluate(x.initializer) - self.evaluate(y.initializer) + sess.run(x.initializer) + sess.run(y.initializer) self._compareOriginalAndReconstructedGraphDefs( sess, cond, expected_output=21.0) @@ -173,8 +173,8 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): toy_loss = x * (u - v) train_op = gradient_descent.GradientDescentOptimizer( learning_rate=0.1).minimize(toy_loss, name="train_op") - self.evaluate(u.initializer) - self.evaluate(v.initializer) + sess.run(u.initializer) + sess.run(v.initializer) self._compareOriginalAndReconstructedGraphDefs(sess, train_op) diff --git a/tensorflow/python/debug/lib/dist_session_debug_grpc_test.py b/tensorflow/python/debug/lib/dist_session_debug_grpc_test.py index b78c3d16d4..74498c8ea3 100644 --- a/tensorflow/python/debug/lib/dist_session_debug_grpc_test.py +++ b/tensorflow/python/debug/lib/dist_session_debug_grpc_test.py @@ -131,8 +131,8 @@ class DistributedSessionDebugTest(test_util.TensorFlowTestCase): with session.Session( config=self.session_config, graph=graph, target=self.server_target) as sess: - self.evaluate(self.a.initializer) - self.evaluate(self.b.initializer) + sess.run(self.a.initializer) + sess.run(self.b.initializer) run_options = config_pb2.RunOptions() debug_utils.watch_graph( @@ -198,8 +198,8 @@ class DistributedSessionDebugTest(test_util.TensorFlowTestCase): with session.Session( config=self.session_config, graph=graph, target=self.server_target) as sess: - self.evaluate(self.a.initializer) - self.evaluate(self.b.initializer) + sess.run(self.a.initializer) + sess.run(self.b.initializer) def watch_fn(feeds, fetch_keys): del feeds, fetch_keys diff --git a/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py b/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py index 8eef45392f..b0dc25851c 100644 --- a/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py +++ b/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py @@ -67,7 +67,7 @@ class SessionDebugMultiGPUTest(test_util.TensorFlowTestCase): u1 = math_ops.multiply(v, v, name="u1") w = math_ops.subtract(u1, u0, name="w") - self.evaluate(v.initializer) + sess.run(v.initializer) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph(run_options, sess.graph, diff --git a/tensorflow/python/debug/lib/source_utils_test.py b/tensorflow/python/debug/lib/source_utils_test.py index a16d68329a..4a8d4eaa99 100644 --- a/tensorflow/python/debug/lib/source_utils_test.py +++ b/tensorflow/python/debug/lib/source_utils_test.py @@ -109,8 +109,8 @@ class SourceHelperTest(test_util.TensorFlowTestCase): self.w = math_ops.matmul(self.u, self.v, name="w") self.w_line_number = line_number_above() - self.evaluate(self.u.initializer) - self.evaluate(self.v.initializer) + sess.run(self.u.initializer) + sess.run(self.v.initializer) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph( diff --git a/tensorflow/python/distribute/input_ops_test.py b/tensorflow/python/distribute/input_ops_test.py index 54f7c5d012..cbb93e8995 100644 --- a/tensorflow/python/distribute/input_ops_test.py +++ b/tensorflow/python/distribute/input_ops_test.py @@ -92,7 +92,7 @@ class AutoShardDatasetTest(test.TestCase): with self.cached_session() as sess: for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - self.assertAllEqual(record_fn(r, f), self.evaluate(next_element)) + self.assertAllEqual(record_fn(r, f), sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) @@ -205,11 +205,10 @@ class AutoShardDatasetTest(test.TestCase): with self.cached_session() as sess: for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - self.assertAllEqual(self._record(r, f), self.evaluate(next_element)) + self.assertAllEqual(self._record(r, f), sess.run(next_element)) for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - self.assertAllEqual( - self._text_line(r, f), self.evaluate(next_element)) + self.assertAllEqual(self._text_line(r, f), sess.run(next_element)) with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) diff --git a/tensorflow/python/eager/def_function_test.py b/tensorflow/python/eager/def_function_test.py index 54991344b7..f0f71a219e 100644 --- a/tensorflow/python/eager/def_function_test.py +++ b/tensorflow/python/eager/def_function_test.py @@ -149,9 +149,9 @@ class DefFunctionTest(test.TestCase): result = fn(3.0) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllEqual(sess.run(state[0]), 2.0) - self.assertAllEqual(self.evaluate(result), 6.0) + self.assertAllEqual(sess.run(result), 6.0) def testLegacyGraphModeVariablesNonTrivialInitializer(self): with ops.Graph().as_default(), self.test_session() as sess: @@ -168,9 +168,9 @@ class DefFunctionTest(test.TestCase): result = fn(3.0) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllEqual(sess.run(state[0]), 6.0) - self.assertAllEqual(self.evaluate(result), 18.0) + self.assertAllEqual(sess.run(result), 18.0) def testLegacyGraphModeInputDependentInitializerFails(self): with ops.Graph().as_default(): diff --git a/tensorflow/python/eager/function_gradients_test.py b/tensorflow/python/eager/function_gradients_test.py index 1ba596573f..d4f8aaa7e3 100644 --- a/tensorflow/python/eager/function_gradients_test.py +++ b/tensorflow/python/eager/function_gradients_test.py @@ -78,7 +78,7 @@ class FunctionGradientsTest(test.TestCase, parameterized.TestCase): c = constant_op.constant([[2.]]) f_c = f(c) g, = gradients_impl.gradients(f_c, c) - self.assertAllEqual(self.evaluate(g).values, [[1.0]]) + self.assertAllEqual(sess.run(g).values, [[1.0]]) def testNoSymGradNestedDefun(self): diff --git a/tensorflow/python/eager/function_test.py b/tensorflow/python/eager/function_test.py index a206b1f791..b58b09140d 100644 --- a/tensorflow/python/eager/function_test.py +++ b/tensorflow/python/eager/function_test.py @@ -564,7 +564,7 @@ class FunctionTest(test.TestCase, parameterized.TestCase): variables.global_variables_initializer().run() call = def_function.function(o.call) op = call() - self.assertAllEqual(self.evaluate(op), 2.0) + self.assertAllEqual(sess.run(op), 2.0) def testGraphModeManyFunctions(self): with ops.Graph().as_default(), self.cached_session(): @@ -1732,7 +1732,7 @@ class FunctionTest(test.TestCase, parameterized.TestCase): function.register(cpu_boost, x) y = gpu_boost(x) - y_value = self.evaluate(y) + y_value = sess.run(y) if test.is_gpu_available(): self.assertEqual(y_value, 5.0) diff --git a/tensorflow/python/feature_column/feature_column_test.py b/tensorflow/python/feature_column/feature_column_test.py index 2c70d66810..e9b11c3960 100644 --- a/tensorflow/python/feature_column/feature_column_test.py +++ b/tensorflow/python/feature_column/feature_column_test.py @@ -1027,7 +1027,7 @@ class CrossedColumnTest(test.TestCase): outputs = _transform_features(features, [price_cross_wire]) output = outputs[price_cross_wire] with self.cached_session() as sess: - output_val = self.evaluate(output) + output_val = sess.run(output) self.assertAllEqual( [[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [1, 3]], output_val.indices) for val in output_val.values: @@ -1886,8 +1886,7 @@ class LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], - self.evaluate(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc._numeric_column('price') @@ -2526,8 +2525,7 @@ class _LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], - self.evaluate(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc._numeric_column('price') diff --git a/tensorflow/python/feature_column/feature_column_v2_test.py b/tensorflow/python/feature_column/feature_column_v2_test.py index 23131e22ed..115763f656 100644 --- a/tensorflow/python/feature_column/feature_column_v2_test.py +++ b/tensorflow/python/feature_column/feature_column_v2_test.py @@ -1188,7 +1188,7 @@ class CrossedColumnTest(test.TestCase): outputs = fc._transform_features_v2(features, [price_cross_wire], None) output = outputs[price_cross_wire] with self.cached_session() as sess: - output_val = self.evaluate(output) + output_val = sess.run(output) self.assertAllEqual( [[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [1, 3]], output_val.indices) for val in output_val.values: @@ -2088,8 +2088,7 @@ class LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [100 - 10 + 5.]], - self.evaluate(net)) + self.assertAllClose([[10 - 1000 + 5.], [100 - 10 + 5.]], sess.run(net)) coord.request_stop() coord.join(threads) @@ -2125,8 +2124,7 @@ class LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], - self.evaluate(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc.numeric_column('price') @@ -2845,8 +2843,7 @@ class OldLinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], - self.evaluate(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc.numeric_column('price') diff --git a/tensorflow/python/framework/function_test.py b/tensorflow/python/framework/function_test.py index 90deb9765f..971219d5b0 100644 --- a/tensorflow/python/framework/function_test.py +++ b/tensorflow/python/framework/function_test.py @@ -102,7 +102,7 @@ class FunctionTest(test.TestCase): call = MyIdentityFunc([18.0]) self.assertEqual("MyIdentity", call.op.name) with session.Session() as sess: - self.assertAllEqual([18.0], self.evaluate(call)) + self.assertAllEqual([18.0], sess.run(call)) def testIdentityImplicitDeref(self): @@ -116,8 +116,8 @@ class FunctionTest(test.TestCase): self.assertEqual("MyIdentity", call.op.name) for cfg in _OptimizerOptions(): with session.Session(config=cfg) as sess: - self.evaluate(var.initializer) - self.assertAllEqual([18.0], self.evaluate(call)) + sess.run(var.initializer) + self.assertAllEqual([18.0], sess.run(call)) def testIdentityOutputName(self): @@ -130,7 +130,7 @@ class FunctionTest(test.TestCase): call = MyIdentityFunc([18.0]) self.assertEqual("MyIdentity", call.op.name) with session.Session() as sess: - self.assertAllEqual([18.0], self.evaluate(call)) + self.assertAllEqual([18.0], sess.run(call)) def testTooManyOutputNames(self): @@ -158,7 +158,7 @@ class FunctionTest(test.TestCase): call = APlus2B([1.0], [2.0]) self.assertEqual("APlus2B", call.op.name) with session.Session() as sess: - self.assertAllEqual([5.0], self.evaluate(call)) + self.assertAllEqual([5.0], sess.run(call)) def testFunctionWithNoOutput(self): @@ -187,7 +187,7 @@ class FunctionTest(test.TestCase): call = APlus2B([1.0], [2.0]) self.assertEqual("APlus2B", call.op.name) with session.Session() as sess: - self.assertAllEqual([5.0], self.evaluate(call)) + self.assertAllEqual([5.0], sess.run(call)) def testDefineFunctionDuplicateOutputs(self): @@ -224,8 +224,8 @@ class FunctionTest(test.TestCase): call_g = XSquarePlusOneGrad([2.0], [0.1]) with session.Session() as sess: - self.assertAllClose([5.0], self.evaluate(call_f)) - self.assertAllClose([0.4], self.evaluate(call_g)) + self.assertAllClose([5.0], sess.run(call_f)) + self.assertAllClose([0.4], sess.run(call_g)) def testTanhSymGrad(self): @@ -387,7 +387,7 @@ class FunctionTest(test.TestCase): call = AConstant() self.assertEqual("AConstant", call.op.name) with session.Session() as sess: - self.assertAllEqual([42], self.evaluate(call)) + self.assertAllEqual([42], sess.run(call)) def testDefineFunctionNames(self): @@ -468,7 +468,7 @@ class FunctionTest(test.TestCase): loop = control_flow_ops.while_loop(lambda x: x < 1e5, Body, [1.0]) - ans = self.evaluate(loop) + ans = sess.run(loop) self.assertAllClose(ans, 131072.) def testControlFlowStrictness(self): @@ -650,8 +650,8 @@ class FunctionTest(test.TestCase): # pylint: enable=unexpected-keyword-arg self.assertEqual("next", call2.op.name) with session.Session() as sess: - self.assertAllEqual([1], self.evaluate(call1)) - self.assertAllEqual([0], self.evaluate(call2)) + self.assertAllEqual([1], sess.run(call1)) + self.assertAllEqual([0], sess.run(call2)) def testNestedFunction(self): @@ -794,7 +794,7 @@ class FunctionTest(test.TestCase): y = Foo() with self.session(graph=g) as sess: - self.assertEqual(self.evaluate(y), 10) + self.assertEqual(sess.run(y), 10) def testCaptureInCond(self): g = ops.Graph() @@ -809,8 +809,8 @@ class FunctionTest(test.TestCase): z = Foo(False) with self.session(graph=g) as sess: - self.assertEqual(self.evaluate(y), 1) - self.assertEqual(self.evaluate(z), 2) + self.assertEqual(sess.run(y), 1) + self.assertEqual(sess.run(z), 2) def testStableName(self): @@ -900,7 +900,7 @@ class FunctionTest(test.TestCase): self.assertEqual(global_vars[0].name, "linear/w:0") with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) output_val = sess.run( output_op, feed_dict={input_op: np.random.rand(32, 100)}) self.assertEqual(output_val.shape, (32, 100)) @@ -928,7 +928,7 @@ class FunctionTest(test.TestCase): self.assertEqual(global_vars[0].name, "vs1/var:0") with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) out1, out2 = sess.run( [out1_op, out2_op], feed_dict={input_op: np.linspace(1, 10, 10)}) self.assertAllEqual(out1, np.linspace(2, 11, 10)) @@ -991,8 +991,8 @@ class FunctionTest(test.TestCase): result_2 = Bar(constant_op.constant(100, dtype=dtypes.int64)) with session.Session() as sess: - self.assertEqual(4.0, self.evaluate(result_1)) - self.assertEqual(100, self.evaluate(result_2)) + self.assertEqual(4.0, sess.run(result_1)) + self.assertEqual(100, sess.run(result_2)) self.assertEqual((4.0, 100), sess.run((result_1, result_2))) def testStatefulFunction(self): @@ -1052,8 +1052,8 @@ class FunctionTest(test.TestCase): for config in _OptimizerOptions(): config.device_count["CPU"] = 2 with session.Session(config=config) as sess: - self.assertEqual(42.0, self.evaluate(f_0)) - self.assertEqual(44.0, self.evaluate(f_1)) + self.assertEqual(42.0, sess.run(f_0)) + self.assertEqual(44.0, sess.run(f_1)) self.assertEqual((42.0, 44.0), sess.run((f_0, f_1))) def testGuaranteedConstsAreCaptured(self): @@ -1076,7 +1076,7 @@ class FunctionTest(test.TestCase): return output with self.session(use_gpu=False) as sess: - self.evaluate(var.initializer) + sess.run(var.initializer) _ = sess.run(CapturesGuaranteedConst(), {also_not_const: 1.0}) def testSameFunctionDifferentGrads(self): @@ -1651,8 +1651,8 @@ class ModuleFunctionTest(test.TestCase): y = LinearWithCApi(a, b, c) z = Linear2WithCApi(a, b, c, d, e) with session.Session() as sess: - self.assertAllEqual([[1]], self.evaluate(y)) - self.assertAllEqual([[5]], self.evaluate(z)) + self.assertAllEqual([[1]], sess.run(y)) + self.assertAllEqual([[5]], sess.run(z)) class VariableHoistingTest(test.TestCase): @@ -1704,7 +1704,7 @@ class VariableHoistingTest(test.TestCase): self.assertEqual("Foo/b", b.op.name) with self.session(graph=g) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) w, b, x, y0, loss, dw, db = sess.run([w, b, x, y0, loss, dw, db]) self.assertAllEqual(w.shape, (64, 64)) diff --git a/tensorflow/python/framework/graph_util_test.py b/tensorflow/python/framework/graph_util_test.py index 7a9f2e8d86..563a177dd0 100644 --- a/tensorflow/python/framework/graph_util_test.py +++ b/tensorflow/python/framework/graph_util_test.py @@ -211,7 +211,7 @@ class DeviceFunctionsTest(test.TestCase): with session.Session() as sess: init = variables.variables_initializer([variable_node]) sess.run(init) - output = self.evaluate(output_node) + output = sess.run(output_node) self.assertNear(4.0, output, 0.00001) variable_graph_def = sess.graph.as_graph_def() @@ -242,8 +242,8 @@ class DeviceFunctionsTest(test.TestCase): output_node = math_ops_lib.multiply( variable_node, 2.0, name="output_node") with session.Session() as sess: - self.evaluate(variable_node.initializer) - output = self.evaluate(output_node) + sess.run(variable_node.initializer) + output = sess.run(output_node) self.assertNear(2.0, output, 0.00001) variable_graph_def = sess.graph.as_graph_def() # First get the constant_graph_def when variable_names_whitelist is @@ -256,7 +256,7 @@ class DeviceFunctionsTest(test.TestCase): # Then initialize the unused variable, and get another # constant_graph_def when variable_names_whitelist is not set. - self.evaluate(another_variable.initializer) + sess.run(another_variable.initializer) constant_graph_def_without_variable_whitelist = ( graph_util.convert_variables_to_constants( sess, variable_graph_def, ["output_node"])) @@ -295,7 +295,7 @@ class DeviceFunctionsTest(test.TestCase): ["Variable", "VariableV2", "VarHandleOp", "ReadVariableOp"]) with session.Session() as sess: output_node = sess.graph.get_tensor_by_name("output_node:0") - output = self.evaluate(output_node) + output = sess.run(output_node) self.assertNear(2.0, output, 0.00001) def create_node_def(self, op, name, inputs): diff --git a/tensorflow/python/framework/importer_test.py b/tensorflow/python/framework/importer_test.py index a57f0b3654..fc7367649e 100644 --- a/tensorflow/python/framework/importer_test.py +++ b/tensorflow/python/framework/importer_test.py @@ -398,10 +398,10 @@ class ImportGraphDefTest(test.TestCase): # TODO(b/76173421): make this work (currently DCHECKS) # with self.cached_session() as sess: # sess.run(imported_init) - # self.assertEqual(self.evaluate(imported_var), 1.0) - # self.assertEqual(self.evaluate(imported_assign), 2.0) - # self.assertEqual(list(self.evaluate(imported_shape)), []) - # self.assertEqual(list(self.evaluate(new_var_shape)), []) + # self.assertEqual(sess.run(imported_var), 1.0) + # self.assertEqual(sess.run(imported_assign), 2.0) + # self.assertEqual(list(sess.run(imported_shape)), []) + # self.assertEqual(list(sess.run(new_var_shape)), []) def testWhileLoop(self): # Produce GraphDef containing while loop. @@ -418,7 +418,7 @@ class ImportGraphDefTest(test.TestCase): return_elements=[r.name]) self.assertEqual(imported_r.name, "import/" + r.name) with self.cached_session() as sess: - self.assertEqual(self.evaluate(imported_r), 10) + self.assertEqual(sess.run(imported_r), 10) def testImportWhileLoopInCond(self): # Produce GraphDef containing while loop. @@ -458,7 +458,7 @@ class ImportGraphDefTest(test.TestCase): lambda i: i < 2, ImportFn, [0], shape_invariants=[tensor_shape.TensorShape(None)]) with self.cached_session() as sess: - self.assertEqual(self.evaluate(out), 10) + self.assertEqual(sess.run(out), 10) def testTypeMismatchInGraphDef(self): # TODO(skyewm): improve error message diff --git a/tensorflow/python/framework/meta_graph_test.py b/tensorflow/python/framework/meta_graph_test.py index 559a76bebb..84e7f361bb 100644 --- a/tensorflow/python/framework/meta_graph_test.py +++ b/tensorflow/python/framework/meta_graph_test.py @@ -492,8 +492,8 @@ class ScopedMetaGraphTest(test.TestCase): init_op = variables.global_variables_initializer() grad = gradients_impl.gradients([output], [var]) with session.Session() as sess: - self.evaluate(init_op) - expected_grad_value = self.evaluate(grad) + sess.run(init_op) + expected_grad_value = sess.run(grad) # Restore the MetaGraphDef into a new Graph with an import scope. with ops.Graph().as_default(): @@ -518,8 +518,8 @@ class ScopedMetaGraphTest(test.TestCase): init_op = variables.global_variables_initializer() with session.Session() as sess: - self.evaluate(init_op) - actual_grad_value = self.evaluate(grad) + sess.run(init_op) + actual_grad_value = sess.run(grad) self.assertEqual(expected_grad_value, actual_grad_value) def testImportWhileLoopInWhileLoop(self): @@ -544,7 +544,7 @@ class ScopedMetaGraphTest(test.TestCase): _, x = control_flow_ops.while_loop(lambda i, x: i < 2, body, [0, 0.0], name="") with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) sess.run(x) def testScopedImportUnderNameScope(self): @@ -869,7 +869,7 @@ class MetaGraphWithVariableScopeTest(test.TestCase): initializer = variables.local_variables_initializer() sess.run(initializer) - self.evaluate(update_op) + sess.run(update_op) meta_graph.export_scoped_meta_graph( filename=meta_graph_filename, graph=graph) diff --git a/tensorflow/python/framework/ops_test.py b/tensorflow/python/framework/ops_test.py index b9c690849d..3957d1de53 100644 --- a/tensorflow/python/framework/ops_test.py +++ b/tensorflow/python/framework/ops_test.py @@ -517,21 +517,21 @@ class OperationTest(test_util.TensorFlowTestCase): self.assertEquals(x.consumers(), []) self.assertEquals(y.consumers(), [z.op, z.op]) with session.Session(graph=g) as sess: - self.assertEquals(self.evaluate(z), 4) + self.assertEquals(sess.run(z), 4) z.op._update_input(0, x) # pylint: disable=protected-access self.assertEquals(list(z.op.inputs), [x, y]) self.assertEquals(x.consumers(), [z.op]) self.assertEquals(y.consumers(), [z.op]) with session.Session(graph=g) as sess: - self.assertEquals(self.evaluate(z), 3) + self.assertEquals(sess.run(z), 3) z.op._update_input(1, y) # pylint: disable=protected-access self.assertEquals(list(z.op.inputs), [x, y]) self.assertEquals(x.consumers(), [z.op]) self.assertEquals(y.consumers(), [z.op]) with session.Session(graph=g) as sess: - self.assertEquals(self.evaluate(z), 3) + self.assertEquals(sess.run(z), 3) def testUpdateInputGraphError(self): g_0 = ops.Graph() diff --git a/tensorflow/python/framework/smart_cond_test.py b/tensorflow/python/framework/smart_cond_test.py index 174ada9fe1..b8a9672b06 100644 --- a/tensorflow/python/framework/smart_cond_test.py +++ b/tensorflow/python/framework/smart_cond_test.py @@ -109,8 +109,8 @@ class SmartCaseTest(test_util.TensorFlowTestCase): exclusive=True) with session.Session() as sess: # No feed_dict necessary - self.assertEqual(self.evaluate(y), 1) - self.assertEqual(self.evaluate(z), 1) + self.assertEqual(sess.run(y), 1) + self.assertEqual(sess.run(z), 1) def testFalse(self): conditions = [(False, raise_exception)] @@ -121,8 +121,8 @@ class SmartCaseTest(test_util.TensorFlowTestCase): default=lambda: constant_op.constant(1), exclusive=True) with session.Session() as sess: - self.assertEqual(self.evaluate(y), 1) - self.assertEqual(self.evaluate(z), 1) + self.assertEqual(sess.run(y), 1) + self.assertEqual(sess.run(z), 1) def testMix(self): x = array_ops.placeholder(dtype=dtypes.int32, shape=[]) diff --git a/tensorflow/python/framework/sparse_tensor_test.py b/tensorflow/python/framework/sparse_tensor_test.py index 9ee1bd75a5..2f7591abbd 100644 --- a/tensorflow/python/framework/sparse_tensor_test.py +++ b/tensorflow/python/framework/sparse_tensor_test.py @@ -50,7 +50,7 @@ class SparseTensorTest(test_util.TensorFlowTestCase): self.assertAllEqual(indices, value.indices) self.assertAllEqual(values, value.values) self.assertAllEqual(shape, value.dense_shape) - sess_run_value = self.evaluate(sp) + sess_run_value = sess.run(sp) self.assertAllEqual(sess_run_value.indices, value.indices) self.assertAllEqual(sess_run_value.values, value.values) self.assertAllEqual(sess_run_value.dense_shape, value.dense_shape) diff --git a/tensorflow/python/framework/tensor_util_test.py b/tensorflow/python/framework/tensor_util_test.py index 87d65c8c46..bdf759f220 100644 --- a/tensorflow/python/framework/tensor_util_test.py +++ b/tensorflow/python/framework/tensor_util_test.py @@ -771,7 +771,7 @@ class TensorUtilTest(test.TestCase): with self.cached_session() as sess: ma = MockArray(np.array([10, 20, 30])) t = ops.convert_to_tensor(ma) - a = self.evaluate(t) + a = sess.run(t) self.assertEquals(np.int64, a.dtype) self.assertAllClose(np.array([10, 20, 30], dtype=np.int64), a) diff --git a/tensorflow/python/grappler/constant_folding_test.py b/tensorflow/python/grappler/constant_folding_test.py index 30c1e14681..ab1d0ed25b 100644 --- a/tensorflow/python/grappler/constant_folding_test.py +++ b/tensorflow/python/grappler/constant_folding_test.py @@ -61,7 +61,7 @@ class ConstantFoldingTest(test.TestCase): back_prop=False, parallel_iterations=1) with session.Session() as sess: - y_v = self.evaluate(y) + y_v = sess.run(y) self.assertAllEqual(np.zeros([10, 20, 30]), y_v) diff --git a/tensorflow/python/grappler/layout_optimizer_test.py b/tensorflow/python/grappler/layout_optimizer_test.py index 55ccfbb93c..7b68d5e80d 100644 --- a/tensorflow/python/grappler/layout_optimizer_test.py +++ b/tensorflow/python/grappler/layout_optimizer_test.py @@ -241,7 +241,7 @@ class LayoutOptimizerTest(test.TestCase): if restore: saver.restore(sess, checkpoint_path) else: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np.random.seed(0) for _ in range(2): @@ -262,7 +262,7 @@ class LayoutOptimizerTest(test.TestCase): output = _two_layer_model(x) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -365,7 +365,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(pad) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -396,7 +396,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -425,7 +425,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(cast) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -456,7 +456,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(squeeze) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -486,7 +486,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(squeeze) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -516,7 +516,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(squeeze) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -545,7 +545,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -574,7 +574,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -603,7 +603,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -632,7 +632,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -662,7 +662,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -691,7 +691,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -724,7 +724,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(concat) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -835,7 +835,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reverse) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -905,7 +905,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(select) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -966,7 +966,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(select) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1179,7 +1179,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(s) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1214,7 +1214,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(s) with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1347,7 +1347,7 @@ class LayoutOptimizerTest(test.TestCase): output = _loop() with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1374,7 +1374,7 @@ class LayoutOptimizerTest(test.TestCase): output = _loop_with_branch() with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1398,7 +1398,7 @@ class LayoutOptimizerTest(test.TestCase): output = _loop_with_vec_and_4d() with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1422,7 +1422,7 @@ class LayoutOptimizerTest(test.TestCase): output = _model_with_second_port() with session.Session(config=_get_config(False)) as sess: - output_val_ref = self.evaluate(output) + output_val_ref = sess.run(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() diff --git a/tensorflow/python/grappler/memory_optimizer_test.py b/tensorflow/python/grappler/memory_optimizer_test.py index d233629cbb..98cbb1a4b6 100644 --- a/tensorflow/python/grappler/memory_optimizer_test.py +++ b/tensorflow/python/grappler/memory_optimizer_test.py @@ -231,10 +231,10 @@ class MemoryOptimizerRecomputeTest(test.TestCase): train_op = graph.get_operation_by_name(train_op_name) loss_op = graph.get_tensor_by_name(loss_op_name) with session.Session(config=config, graph=graph) as sess: - self.evaluate(init_op) - self.evaluate(train_op) - self.evaluate(train_op) - return self.evaluate(loss_op) + sess.run(init_op) + sess.run(train_op) + sess.run(train_op) + return sess.run(loss_op) def testRecomputationRewritingNoErrors(self): """Tests that graph output is not significantly different with rewriting.""" @@ -295,8 +295,8 @@ class MemoryOptimizerRecomputeTest(test.TestCase): rewrite_options=manual_memory_config) session_config = config_pb2.ConfigProto(graph_options=graph_options) with session.Session(config=session_config) as sess: - self.evaluate(init_op) - self.evaluate(train_op) + sess.run(init_op) + sess.run(train_op) def testHintDoesRewrite(self): graph = self._annotated_graph()[0] diff --git a/tensorflow/python/keras/backend_test.py b/tensorflow/python/keras/backend_test.py index 48fdd56e9f..a727e99f66 100644 --- a/tensorflow/python/keras/backend_test.py +++ b/tensorflow/python/keras/backend_test.py @@ -136,7 +136,7 @@ class BackendUtilsTest(test.TestCase): x = keras.Input((3,)) y = keras.layers.BatchNormalization()(x) if not context.executing_eagerly(): - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) sess.run(y, feed_dict={x: np.random.random((2, 3))}) def test_learning_phase_scope(self): diff --git a/tensorflow/python/keras/layers/recurrent_test.py b/tensorflow/python/keras/layers/recurrent_test.py index b1449069e3..7172571f7c 100644 --- a/tensorflow/python/keras/layers/recurrent_test.py +++ b/tensorflow/python/keras/layers/recurrent_test.py @@ -1013,8 +1013,8 @@ class RNNTest(test.TestCase): inputs, _ = cell(inputs, initial_state) output = inputs if not context.executing_eagerly(): - self.evaluate(variables_lib.global_variables_initializer()) - output = self.evaluate(output) + sess.run(variables_lib.global_variables_initializer()) + output = sess.run(output) return output random_seed.set_random_seed(12345) diff --git a/tensorflow/python/kernel_tests/accumulate_n_test.py b/tensorflow/python/kernel_tests/accumulate_n_test.py index c7f11f854d..ae24cf8f14 100644 --- a/tensorflow/python/kernel_tests/accumulate_n_test.py +++ b/tensorflow/python/kernel_tests/accumulate_n_test.py @@ -65,7 +65,7 @@ class AccumulateNV2Test(test_util.TensorFlowTestCase): for _ in range(0, num_inputs) ] accum_n = math_ops.accumulate_n(input_vars) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) accum_n_grad = gradients.gradients(accum_n, input_vars) self.assertAllEqual( np.repeat(1.0, num_inputs), # d/dx (x + y + ...) = 1 diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py index afc158f697..d345138ec7 100644 --- a/tensorflow/python/kernel_tests/array_ops_test.py +++ b/tensorflow/python/kernel_tests/array_ops_test.py @@ -833,7 +833,7 @@ class StridedSliceGradTest(test_util.TensorFlowTestCase): index = constant_op.constant(1, dtype=dtypes.int64) b = 2. * a[index] grad, = gradients_impl.gradients(b, a) - self.assertAllEqual(self.evaluate(grad), [0., 2., 0.]) + self.assertAllEqual(sess.run(grad), [0., 2., 0.]) class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): @@ -846,7 +846,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32), shape=(4, 1, 1))) varshape = variables.Variable([6, 4, 4], dtype=dtypes.int32) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) begin = constant_op.constant([0, 0, 0]) end = constant_op.constant([4, 1, 1]) strides = constant_op.constant([1, 1, 1]) @@ -859,7 +859,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32), shape=(4, 1, 1)) original_shape = constant_op.constant([6, 4, 4], dtype=dtypes.int64) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) begin = constant_op.constant([0, 0, 0], dtype=dtypes.int64) end = constant_op.constant([4, 1, 1], dtype=dtypes.int64) strides = constant_op.constant([1, 1, 1], dtype=dtypes.int64) @@ -873,7 +873,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32), shape=(4, 1, 1)) original_shape = constant_op.constant([6, 4, 4], dtype=dtypes.int64) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) begin = constant_op.constant([0, 0, 0], dtype=dtypes.int32) end = constant_op.constant([4, 1, 1], dtype=dtypes.int64) strides = constant_op.constant([1, 1, 1], dtype=dtypes.int64) @@ -1042,7 +1042,7 @@ class SliceAssignTest(test_util.TensorFlowTestCase): too_large_val = constant_op.constant([3, 4], dtype=dtypes.int64) v = resource_variable_ops.ResourceVariable(init_val) with self.cached_session() as sess: - self.evaluate(v.initializer) + sess.run(v.initializer) with self.assertRaises(ValueError): sess.run(v[:].assign(too_large_val)) with self.assertRaises(ValueError): @@ -1269,7 +1269,7 @@ class GuaranteeConstOpTest(test_util.TensorFlowTestCase): initializer=init_ops.constant_initializer(10.0), use_resource=use_resource) guarantee_a = array_ops.guarantee_const(a) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(10.0, guarantee_a.eval()) def testResourceRejection(self): @@ -1279,7 +1279,7 @@ class GuaranteeConstOpTest(test_util.TensorFlowTestCase): initializer=init_ops.constant_initializer(10.0), use_resource=True) guarantee_a = array_ops.guarantee_const(a.handle) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) with self.assertRaisesWithPredicateMatch(errors.InvalidArgumentError, "cannot be a resource variable"): guarantee_a.eval() diff --git a/tensorflow/python/kernel_tests/basic_gpu_test.py b/tensorflow/python/kernel_tests/basic_gpu_test.py index cd33048121..ac5cbc810a 100644 --- a/tensorflow/python/kernel_tests/basic_gpu_test.py +++ b/tensorflow/python/kernel_tests/basic_gpu_test.py @@ -44,13 +44,13 @@ class GPUBinaryOpsTest(test.TestCase): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) - tf_gpu = self.evaluate(out) + tf_gpu = sess.run(out) with self.cached_session(use_gpu=False) as sess: inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) - tf_cpu = self.evaluate(out) + tf_cpu = sess.run(out) self.assertAllClose(tf_cpu, tf_gpu) @@ -96,7 +96,7 @@ class MathBuiltinUnaryTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: inx = ops.convert_to_tensor(x) ofunc = tf_func(inx) - tf_out = self.evaluate(ofunc) + tf_out = sess.run(ofunc) self.assertAllClose(np_out, tf_out) def _inv(self, x): @@ -148,7 +148,7 @@ class MathBuiltinUnaryTest(test.TestCase): iny = ops.convert_to_tensor(y + 0.1) ofunc = inx / iny out_func2 = math_ops.floor(ofunc) - tf_out = self.evaluate(out_func2) + tf_out = sess.run(out_func2) self.assertAllClose(np_out, tf_out) diff --git a/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py index adfb094971..12afb6a2ad 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py @@ -98,8 +98,8 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): quantile_accumulator_handle, num_features=2) quantiles = boosted_trees_ops.boosted_trees_bucketize( [self._feature_0, self._feature_1], buckets) - self.evaluate(summary_op) - self.evaluate(flush_op) + sess.run(summary_op) + sess.run(flush_op) self.assertAllClose(self._feature_0_boundaries, buckets[0].eval()) self.assertAllClose(self._feature_1_boundaries, buckets[1].eval()) diff --git a/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py index e4c5431c26..cc3984015d 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py @@ -65,10 +65,10 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) self.assertAllClose([[0.004775, 0.41184], [0.02823, 0.41184]], sess.run(gains_list)) - self.assertAllEqual([[1, 1], [1, 1]], self.evaluate(thresholds_list)) + self.assertAllEqual([[1, 1], [1, 1]], sess.run(thresholds_list)) # The left node contrib will be later added to the previous node value to # make the left node value, and the same for right node contrib. self.assertAllClose([[[-.416667], [.568966]], [[-.6], [-.75]]], @@ -113,10 +113,10 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) self.assertAllClose([[0., 0.33931375], [0.01879096, 0.33931375]], sess.run(gains_list)) - self.assertAllEqual([[0, 1], [1, 1]], self.evaluate(thresholds_list)) + self.assertAllEqual([[0, 1], [1, 1]], sess.run(thresholds_list)) # The left node contrib will be later added to the previous node value to # make the left node value, and the same for right node contrib. self.assertAllClose([[[0.], [.485294]], [[-.5], [-.6]]], @@ -162,9 +162,9 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[0, 1], [1, 1]], self.evaluate(thresholds_list)) + self.assertAllEqual([[0, 1], [1, 1]], sess.run(thresholds_list)) - self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) self.assertAllClose([[[0.0], [0.3965517]], [[-0.4], [-0.5]]], sess.run(left_node_contribs_list)) @@ -214,12 +214,12 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) self.assertAllClose([[-3., -2.66068625], [-2.98120904, -2.66068625]], sess.run(gains_list)) - self.assertAllEqual([[0, 1], [1, 1]], self.evaluate(thresholds_list)) + self.assertAllEqual([[0, 1], [1, 1]], sess.run(thresholds_list)) # The left node contrib will be later added to the previous node value to # make the left node value, and the same for right node contrib. self.assertAllClose([[[0.], [.485294]], [[-.5], [-.6]]], @@ -266,9 +266,9 @@ class StatsOpsTest(test_util.TensorFlowTestCase): # We can't split node 1 on feature 1 and node 2 on feature 2 because of # the min node weight. - self.assertAllEqual([[2], [1]], self.evaluate(node_ids_list)) - self.assertAllClose([[0.384314], [0.098013]], self.evaluate(gains_list)) - self.assertAllEqual([[1], [1]], self.evaluate(thresholds_list)) + self.assertAllEqual([[2], [1]], sess.run(node_ids_list)) + self.assertAllClose([[0.384314], [0.098013]], sess.run(gains_list)) + self.assertAllEqual([[1], [1]], sess.run(thresholds_list)) self.assertAllClose([[[0.4852941]], [[-.6]]], sess.run(left_node_contribs_list)) self.assertAllClose([[[-0.75]], [[-0.014925]]], @@ -311,9 +311,9 @@ class StatsOpsTest(test_util.TensorFlowTestCase): max_splits=max_splits) # We can't split either of the nodes on the first feature - self.assertEqual(2, len(self.evaluate(node_ids_list))) - self.assertAllEqual([], self.evaluate(node_ids_list)[0]) - self.assertAllEqual([1], self.evaluate(node_ids_list)[1]) + self.assertEqual(2, len(sess.run(node_ids_list))) + self.assertAllEqual([], sess.run(node_ids_list)[0]) + self.assertAllEqual([1], sess.run(node_ids_list)[1]) # Now check when we can't split on any feature (node_ids_list, _, _, _, @@ -325,7 +325,7 @@ class StatsOpsTest(test_util.TensorFlowTestCase): tree_complexity=0.0, min_node_weight=10, max_splits=max_splits) - self.assertAllEqual([[], []], self.evaluate(node_ids_list)) + self.assertAllEqual([[], []], sess.run(node_ids_list)) def testMakeStatsSummarySimple(self): """Simple test for MakeStatsSummary.""" diff --git a/tensorflow/python/kernel_tests/bucketize_op_test.py b/tensorflow/python/kernel_tests/bucketize_op_test.py index 9575b28899..57413e6af5 100644 --- a/tensorflow/python/kernel_tests/bucketize_op_test.py +++ b/tensorflow/python/kernel_tests/bucketize_op_test.py @@ -32,7 +32,7 @@ class BucketizationOpTest(test.TestCase): boundaries=[0, 3, 8, 11]) expected_out = [0, 1, 1, 2, 2, 3, 3, 4, 4] with self.session(use_gpu=True) as sess: - self.assertAllEqual(expected_out, self.evaluate(op)) + self.assertAllEqual(expected_out, sess.run(op)) def testFloat(self): op = math_ops._bucketize( @@ -40,7 +40,7 @@ class BucketizationOpTest(test.TestCase): boundaries=[0., 3., 8., 11.]) expected_out = [0, 1, 1, 2, 2, 3, 3, 4, 4] with self.session(use_gpu=True) as sess: - self.assertAllEqual(expected_out, self.evaluate(op)) + self.assertAllEqual(expected_out, sess.run(op)) def test2DInput(self): op = math_ops._bucketize( @@ -48,7 +48,7 @@ class BucketizationOpTest(test.TestCase): boundaries=[0, 3, 8, 11]) expected_out = [[0, 1, 1, 2, 2], [3, 3, 4, 4, 1]] with self.session(use_gpu=True) as sess: - self.assertAllEqual(expected_out, self.evaluate(op)) + self.assertAllEqual(expected_out, sess.run(op)) def testInvalidBoundariesOrder(self): op = math_ops._bucketize( diff --git a/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py b/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py index 031accee55..46ab71537f 100644 --- a/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py +++ b/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py @@ -97,7 +97,7 @@ class RangeSamplerOpsTest(test.TestCase): true_classes, self.NUM_TRUE, self.NUM_SAMPLED, True) accidental_hits = candidate_sampling_ops.compute_accidental_hits( true_classes, sampled_candidates, self.NUM_TRUE) - indices, ids, weights = self.evaluate(accidental_hits) + indices, ids, weights = sess.run(accidental_hits) self.assertEqual(1, accidental_hits[0].get_shape().ndims) self.assertEqual(1, accidental_hits[1].get_shape().ndims) diff --git a/tensorflow/python/kernel_tests/cast_op_test.py b/tensorflow/python/kernel_tests/cast_op_test.py index cdeaf7b696..bc49cd5a04 100644 --- a/tensorflow/python/kernel_tests/cast_op_test.py +++ b/tensorflow/python/kernel_tests/cast_op_test.py @@ -187,7 +187,7 @@ class CastOpTest(test.TestCase): y = variables.Variable(True, dtype=dtypes.bool) cast = math_ops.cast(y, x.dtype) variables.global_variables_initializer().run() - self.assertEqual(1.0, self.evaluate(cast)) + self.assertEqual(1.0, sess.run(cast)) def testGradients(self): t = [dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128] diff --git a/tensorflow/python/kernel_tests/concat_op_test.py b/tensorflow/python/kernel_tests/concat_op_test.py index 6944d73c5f..149302831b 100644 --- a/tensorflow/python/kernel_tests/concat_op_test.py +++ b/tensorflow/python/kernel_tests/concat_op_test.py @@ -627,7 +627,7 @@ class ConcatOffsetTest(test.TestCase): s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = self.evaluate(off) + ans = sess.run(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) def testNotVector(self): @@ -679,7 +679,7 @@ class ConcatOffsetTest(test.TestCase): s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = self.evaluate(off) + ans = sess.run(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) cdim = constant_op.constant(-3, dtypes.int32) @@ -687,7 +687,7 @@ class ConcatOffsetTest(test.TestCase): s1 = constant_op.constant([1, 3, 5], dtypes.int32) s2 = constant_op.constant([3, 3, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = self.evaluate(off) + ans = sess.run(off) self.assertAllEqual(ans, [[0, 0, 0], [2, 0, 0], [3, 0, 0]]) diff --git a/tensorflow/python/kernel_tests/conditional_accumulator_test.py b/tensorflow/python/kernel_tests/conditional_accumulator_test.py index 8388070c63..893cb7cce3 100644 --- a/tensorflow/python/kernel_tests/conditional_accumulator_test.py +++ b/tensorflow/python/kernel_tests/conditional_accumulator_test.py @@ -424,7 +424,7 @@ class ConditionalAccumulatorTest(test.TestCase): takeg_t = q.take_grad(1) def apply_grad(accum_op): - self.evaluate(accum_op) + sess.run(accum_op) threads = [ self.checkedThread( @@ -451,7 +451,7 @@ class ConditionalAccumulatorTest(test.TestCase): def apply_grad(): for accum_op in accum_ops: time.sleep(1.0) - self.evaluate(accum_op) + sess.run(accum_op) apply_grad_thread = self.checkedThread(target=apply_grad) @@ -485,7 +485,7 @@ class ConditionalAccumulatorTest(test.TestCase): def apply_grad(): time.sleep(1.0) for accum_op in accum_ops: - self.evaluate(accum_op) + sess.run(accum_op) return_array = [] @@ -503,7 +503,7 @@ class ConditionalAccumulatorTest(test.TestCase): def _blocking_takeg(self, sess, takeg_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(takeg_op) + sess.run(takeg_op) def testAccumulatorCancel(self): with self.cached_session() as sess: diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 59966ebc84..9a198d445f 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -593,7 +593,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: [math_ops.add(x, 1), math_ops.add(x, 2)] fn2 = lambda: [y, y] r = control_flow_ops.cond(pred, fn1, fn2) - self.assertAllEqual([11, 12], self.evaluate(r)) + self.assertAllEqual([11, 12], sess.run(r)) def testCondListOutput(self): with self.cached_session() as sess: @@ -603,7 +603,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: [math_ops.add(x, y), math_ops.add(x, y)] fn2 = lambda: [y, y] r = control_flow_ops.cond(pred, fn1, fn2) - test_result = self.evaluate(r) + test_result = sess.run(r) self.assertListEqual([210, 210], test_result) def testTupleOutput(self): @@ -614,7 +614,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: (math_ops.add(x, y), math_ops.add(x, y)) fn2 = lambda: (y, y) r = control_flow_ops.cond(pred, fn1, fn2) - test_result = self.evaluate(r) + test_result = sess.run(r) self.assertTupleEqual((210, 210), test_result) def testDictOutput(self): @@ -625,7 +625,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: {"a": math_ops.add(x, y), "b": math_ops.add(x, y)} fn2 = lambda: {"a": y, "b": y} r = control_flow_ops.cond(pred, fn1, fn2) - test_result = self.evaluate(r) + test_result = sess.run(r) self.assertDictEqual({"a": 210, "b": 210}, test_result) def testEmbeddedListOutput(self): @@ -638,7 +638,7 @@ class ControlFlowTest(test.TestCase): # Pass strict=True flag as cond_v2 allows for tensors to be # in nested output structures as singletons r = control_flow_ops.cond(pred, fn1, fn2, strict=True) - test_result = self.evaluate(r) + test_result = sess.run(r) self.assertListEqual([[210, 210]], test_result) def testEmbeddedTupleOutput(self): @@ -649,7 +649,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: ((math_ops.add(x, y), math_ops.add(x, y))) fn2 = lambda: ((y, y)) r = control_flow_ops.cond(pred, fn1, fn2) - test_result = self.evaluate(r) + test_result = sess.run(r) self.assertTupleEqual(((210, 210)), test_result) def testEmbeddedDictOutput(self): @@ -662,7 +662,7 @@ class ControlFlowTest(test.TestCase): fn2 = lambda: {"a": {"c": y}, "b": {"d": y}} r = control_flow_ops.cond(pred, fn1, fn2) - test_result = self.evaluate(r) + test_result = sess.run(r) self.assertDictEqual({"a": {"c": 210}, "b": {"d": 210}}, test_result) def testCheckNestedOutputStruct(self): @@ -677,7 +677,7 @@ class ControlFlowTest(test.TestCase): with self.assertRaisesRegexp( ValueError, v2_msg if control_flow_ops.ENABLE_COND_V2 else v1_msg): r = control_flow_ops.cond(pred, fn1, fn2) - self.evaluate(r) + test_result = sess.run(r) def testCondRef(self): @@ -1050,7 +1050,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual(r[0].dtype, dtypes.int32) self.assertEqual(r[1].dtype, dtypes.int32_ref) - value_i, value_x = self.evaluate(r) + value_i, value_x = sess.run(r) self.assertEqual(100, value_i) self.assertEqual(0, value_x) @@ -1642,7 +1642,7 @@ class ControlFlowTest(test.TestCase): with ops.control_dependencies([control_flow_ops.no_op()]): loop = control_flow_ops.while_loop(cond, body, (constant_op.constant(5),)) - self.assertEqual(0, self.evaluate(loop)) + self.assertEqual(0, sess.run(loop)) @test_util.disable_control_flow_v2("b/113324949 (ref vars)") def testWhileCondWithControl_1(self): @@ -2055,7 +2055,7 @@ class ControlFlowTest(test.TestCase): self.assertFalse(gpu_dev_name in dev) with self.session(graph=graph) as sess: - self.assertAllClose(1024.0, self.evaluate(r)) + self.assertAllClose(1024.0, sess.run(r)) @test_util.disable_control_flow_v2("b/116351701 (colocation)") def testWhileGrad_ColocateGradients(self): @@ -2547,8 +2547,8 @@ class ControlFlowTest(test.TestCase): res = outer_loop(inp) optimizer = adam.AdamOptimizer(learning_rate=0.001) train_op = optimizer.minimize(math_ops.reduce_mean(math_ops.square(res))) - self.evaluate(variables.global_variables_initializer()) - self.evaluate(train_op) + sess.run(variables.global_variables_initializer()) + sess.run(train_op) self.assertAllClose(2.999, self.evaluate(var)) def _testWhileCondGrad_Simple(self, use_gpu): @@ -2607,11 +2607,11 @@ class ControlFlowTest(test.TestCase): [i0.get_shape(), tensor_shape.TensorShape([None, 2])]) s = math_ops.reduce_sum(h) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) optimizer = gradient_descent.GradientDescentOptimizer(0.01) op = optimizer.minimize(s) sess.run(op) - self.assertAllClose([[0.98000002, 1.98000002]], self.evaluate(x)) + self.assertAllClose([[0.98000002, 1.98000002]], sess.run(x)) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") def testWhileWithRefsWithGradients_1(self): @@ -2705,7 +2705,7 @@ class ControlFlowTest(test.TestCase): output_grad = control_flow_ops.while_loop( c, b, [i0, constant_op.constant(0.0)]) - self.assertAllClose(600.0, self.evaluate(output_grad)[1]) + self.assertAllClose(600.0, sess.run(output_grad)[1]) def testWhileAndTensorArray(self): with self.cached_session() as sess: @@ -2724,7 +2724,7 @@ class ControlFlowTest(test.TestCase): r = control_flow_ops.while_loop(c, b, [n0, y0], parallel_iterations=1) r = gradients_impl.gradients(r, param)[0] - self.assertAllClose(107520.0, self.evaluate(r)) + self.assertAllClose(107520.0, sess.run(r)) def testWhileGrad_StopGrad(self): with self.cached_session(): @@ -2857,8 +2857,8 @@ class ControlFlowTest(test.TestCase): dy_dq, = gradients_impl.gradients(y, q) self.assertIsNotNone(dy_dq) with self.cached_session() as sess: - self.evaluate(q.initializer) - self.assertAllClose([0., 0.], self.evaluate(dy_dq)) + sess.run(q.initializer) + self.assertAllClose([0., 0.], sess.run(dy_dq)) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") def testWhileGradientWithNontrainablePath2(self): @@ -2875,8 +2875,8 @@ class ControlFlowTest(test.TestCase): dy_dq, = gradients_impl.gradients(y, q) self.assertIsNotNone(dy_dq) with self.cached_session() as sess: - self.evaluate(q.initializer) - self.assertAllClose([1., 1.], self.evaluate(dy_dq)) + sess.run(q.initializer) + self.assertAllClose([1., 1.], sess.run(dy_dq)) @test_util.disable_control_flow_v2("b/115920078 (gradients)") def testIssue16504(self): @@ -3295,7 +3295,7 @@ class ControlFlowTest(test.TestCase): result = control_flow_ops.while_loop(condition, body, [constant_op.constant(4)]) - self.assertEqual(10, self.evaluate(result)) + self.assertEqual(10, sess.run(result)) # Ensure that we cannot run a tensor that escapes the loop body # accidentally. @@ -3353,7 +3353,7 @@ class ControlFlowTest(test.TestCase): shape=[1], dtype=dtypes.qint8, name="v", container="", shared_name="") assign_op = state_ops.assign( var_qint, constant_op.constant(np.array([42]), dtypes.qint8)) - self.evaluate(assign_op) + sess.run(assign_op) cond = constant_op.constant(True, dtypes.bool) v_f, v_t = control_flow_ops.ref_switch(var_qint, cond) @@ -3682,7 +3682,7 @@ class WhileOpBenchmark(test.Benchmark): with session.Session() as sess, ops.device(default_device): # Get the initial id i, input x, and kernel. i, x, kernel = self._getInitVariables() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) if static_unroll: for _ in xrange(steps): diff --git a/tensorflow/python/kernel_tests/conv_ops_3d_test.py b/tensorflow/python/kernel_tests/conv_ops_3d_test.py index 3ec5c29df7..3924e13575 100644 --- a/tensorflow/python/kernel_tests/conv_ops_3d_test.py +++ b/tensorflow/python/kernel_tests/conv_ops_3d_test.py @@ -109,7 +109,7 @@ class Conv3DTest(test.TestCase): results.append(result) with self.cached_session() as sess: - values = self.evaluate(results) + values = sess.run(results) for value in values: print("expected = ", expected) print("actual = ", value) @@ -184,8 +184,8 @@ class Conv3DTest(test.TestCase): computed_results.append(computed) tolerance = 1e-2 if use_gpu else 1e-5 with self.cached_session() as sess: - expected_values = self.evaluate(expected_results) - computed_values = self.evaluate(computed_results) + expected_values = sess.run(expected_results) + computed_values = sess.run(computed_results) for e_value, c_value in zip(expected_values, computed_values): print("expected = ", e_value) print("actual = ", c_value) @@ -715,8 +715,8 @@ class Conv3DTest(test.TestCase): expected_grad = gradients_impl.gradients(expected, t1 if mode == "input" else t2)[0] # "values" consists of two tensors for two backprops - actual_value = self.evaluate(actual_grad) - expected_value = self.evaluate(expected_grad) + actual_value = sess.run(actual_grad) + expected_value = sess.run(expected_grad) self.assertShapeEqual(actual_value, actual_grad) self.assertShapeEqual(expected_value, expected_grad) print("expected = ", expected_value) diff --git a/tensorflow/python/kernel_tests/conv_ops_test.py b/tensorflow/python/kernel_tests/conv_ops_test.py index 2d21f6f4ae..835cc1504d 100644 --- a/tensorflow/python/kernel_tests/conv_ops_test.py +++ b/tensorflow/python/kernel_tests/conv_ops_test.py @@ -908,8 +908,8 @@ class Conv2DTest(test.TestCase): conv = gradients_impl.gradients(conv_forward, t1)[0] conv_2 = gradients_impl.gradients(conv_forward_2, t1)[0] # "values" consists of two tensors for two backprops - value = self.evaluate(conv) - value_2 = self.evaluate(conv_2) + value = sess.run(conv) + value_2 = sess.run(conv_2) self.assertShapeEqual(value, conv) self.assertShapeEqual(value_2, conv_2) tf_logging.info("expected = ", value_2) @@ -961,8 +961,8 @@ class Conv2DTest(test.TestCase): conv_forward_2 = test_util.NCHWToNHWC(conv_forward_2) conv = gradients_impl.gradients(conv_forward, t2)[0] conv_2 = gradients_impl.gradients(conv_forward, t2)[0] - value = self.evaluate(conv) - value_2 = self.evaluate(conv_2) + value = sess.run(conv) + value_2 = sess.run(conv_2) self.assertShapeEqual(value, conv) self.assertShapeEqual(value_2, conv_2) tf_logging.info("expected = ", value_2) @@ -1545,7 +1545,7 @@ class DepthwiseConv2DTest(test.TestCase): t2 = constant_op.constant(x2, shape=filter_in_sizes) conv = nn_impl.depthwise_conv2d( t1, t2, strides=[1, stride, stride, 1], padding=padding) - value = self.evaluate(conv) + value = sess.run(conv) tf_logging.info("value = ", value) self.assertArrayNear(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) @@ -1667,7 +1667,7 @@ class SeparableConv2DTest(test.TestCase): if data_format == "NCHW": conv = array_ops.transpose(conv, [0, 2, 3, 1]) - value = self.evaluate(conv) + value = sess.run(conv) tf_logging.info("value = ", value) self.assertArrayNear(expected, np.ravel(value), 1e-3) self.assertShapeEqual(value, conv) diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index 87248bf9c8..d7dbf5ab9a 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -788,7 +788,7 @@ class RoundingTest(test.TestCase): y = np.rint(x) if y is None else np.asarray(y) with self.cached_session() as sess: tf_rint = math_ops.rint(x) - np_rint = self.evaluate(tf_rint) + np_rint = sess.run(tf_rint) self.assertAllEqual(y, np_rint) self.assertShapeEqual(y, tf_rint) @@ -881,7 +881,7 @@ class ComplexMakeRealImagTest(test.TestCase): force_gpu=use_gpu and test_util.is_gpu_available()) as sess: inx = ops.convert_to_tensor(cplx) tf_angle = math_ops.angle(inx) - tf_angle_val = self.evaluate(tf_angle) + tf_angle_val = sess.run(tf_angle) self.assertAllEqual(np_angle, tf_angle_val) self.assertShapeEqual(np_angle, tf_angle) diff --git a/tensorflow/python/kernel_tests/decode_jpeg_op_test.py b/tensorflow/python/kernel_tests/decode_jpeg_op_test.py index 8c4ccbd88e..66b3e0f22f 100644 --- a/tensorflow/python/kernel_tests/decode_jpeg_op_test.py +++ b/tensorflow/python/kernel_tests/decode_jpeg_op_test.py @@ -80,7 +80,7 @@ class DecodeJpegBenchmark(test.Benchmark): initializer=image_ops.encode_jpeg(tiled_image)) with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) images = [] for _ in xrange(parallelism): if crop_window is None: diff --git a/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py b/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py index 0676664685..3ed7dba966 100644 --- a/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py +++ b/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py @@ -43,7 +43,7 @@ class AssignOpTest(test.TestCase): variables.global_variables_initializer().run() def run_add(add_op): - self.evaluate(add_op) + sess.run(add_op) threads = [ self.checkedThread( @@ -70,7 +70,7 @@ class AssignOpTest(test.TestCase): variables.global_variables_initializer().run() def run_assign(assign_op): - self.evaluate(assign_op) + sess.run(assign_op) threads = [ self.checkedThread( @@ -103,7 +103,7 @@ class AssignOpTest(test.TestCase): p.initializer.run() def run_add(add_op): - self.evaluate(add_op) + sess.run(add_op) threads = [ self.checkedThread( @@ -131,7 +131,7 @@ class AssignOpTest(test.TestCase): p.initializer.run() def run_assign(assign_op): - self.evaluate(assign_op) + sess.run(assign_op) threads = [ self.checkedThread( diff --git a/tensorflow/python/kernel_tests/depthwise_conv_op_test.py b/tensorflow/python/kernel_tests/depthwise_conv_op_test.py index f6d834c2f8..f65d0be367 100644 --- a/tensorflow/python/kernel_tests/depthwise_conv_op_test.py +++ b/tensorflow/python/kernel_tests/depthwise_conv_op_test.py @@ -162,7 +162,7 @@ class DepthwiseConv2DTest(test.TestCase): conv_native = array_ops.transpose(conv_native, [0, 2, 3, 1]) try: - native_result = self.evaluate(conv_native) + native_result = sess.run(conv_native) except errors.InvalidArgumentError as e: # Grouped convolution kernel is only registered for cuDNN 7. Silently # return when we are running on an earlier version or without GPU. @@ -174,7 +174,7 @@ class DepthwiseConv2DTest(test.TestCase): conv_interface = nn_impl.depthwise_conv2d( t1, t2, strides=[1, stride, stride, 1], padding=padding) - interface_result = self.evaluate(conv_interface) + interface_result = sess.run(conv_interface) tf_logging.info( "data_type: %r, use_gpu: %r, grouped_conv: %r, max diff = %f", @@ -269,7 +269,7 @@ class DepthwiseConv2DTest(test.TestCase): t2 = constant_op.constant(x2, shape=filter_in_sizes) conv = nn_ops.depthwise_conv2d_native( t1, t2, strides=[1, stride, stride, 1], padding=padding) - value = self.evaluate(conv) + value = sess.run(conv) tf_logging.info("value = %r", value) self.assertArrayNear(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) diff --git a/tensorflow/python/kernel_tests/distributions/categorical_test.py b/tensorflow/python/kernel_tests/distributions/categorical_test.py index 9c593d2737..f116c54bd1 100644 --- a/tensorflow/python/kernel_tests/distributions/categorical_test.py +++ b/tensorflow/python/kernel_tests/distributions/categorical_test.py @@ -287,7 +287,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): } with self.cached_session() as sess: - run_result = self.evaluate(to_run) + run_result = sess.run(to_run) self.assertAllEqual(run_result["cat_prob"].shape, run_result["norm_prob"].shape) @@ -462,7 +462,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): b = categorical.Categorical(logits=b_logits) kl = kullback_leibler.kl_divergence(a, b) - kl_val = self.evaluate(kl) + kl_val = sess.run(kl) # Make sure KL(a||a) is 0 kl_same = sess.run(kullback_leibler.kl_divergence(a, a)) diff --git a/tensorflow/python/kernel_tests/dynamic_partition_op_test.py b/tensorflow/python/kernel_tests/dynamic_partition_op_test.py index 80da39dfde..07da855a01 100644 --- a/tensorflow/python/kernel_tests/dynamic_partition_op_test.py +++ b/tensorflow/python/kernel_tests/dynamic_partition_op_test.py @@ -40,7 +40,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant([0, 0, 2, 3, 2, 1]) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual([0, 13], partition_vals[0]) @@ -62,7 +62,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant([0, 0, 2, 3, 2, 1]) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual([[0, 1, 2], [3, 4, 5]], partition_vals[0]) @@ -87,7 +87,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual(part1, partition_vals[0]) @@ -109,7 +109,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=num_partitions) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(num_partitions, len(partition_vals)) for i in range(num_partitions): @@ -125,7 +125,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual([3 + 4j, 7 + 8j], partition_vals[0]) @@ -138,7 +138,7 @@ class DynamicPartitionTest(test.TestCase): indices = 3 partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual(np.array([], dtype=np.float64).reshape(-1, 4), @@ -164,7 +164,7 @@ class DynamicPartitionTest(test.TestCase): outputs = data_flow_ops.dynamic_partition( data_t, partitions_t, num_partitions=n) self.assertEqual(n, len(outputs)) - outputs_val = self.evaluate(outputs) + outputs_val = sess.run(outputs) for i, output in enumerate(outputs_val): self.assertAllEqual(output, data[partitions == i]) @@ -183,7 +183,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual([], partition_vals[0]) @@ -199,7 +199,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=3) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(3, len(partition_vals)) self.assertAllEqual([[]], partition_vals[0]) @@ -215,7 +215,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual([], partition_vals[0]) @@ -236,7 +236,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual([6], partition_vals[0]) @@ -257,7 +257,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=5) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(5, len(partition_vals)) self.assertAllEqual([5], partition_vals[0]) @@ -281,7 +281,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=40) - partition_vals = self.evaluate(partitions) + partition_vals = sess.run(partitions) self.assertEqual(40, len(partition_vals)) for i in range(40): @@ -335,7 +335,7 @@ class DynamicPartitionTest(test.TestCase): self.assertEqual(len(inds), x.shape[0]) partitioned = data_flow_ops.dynamic_partition(x, inds, 16) with self.cached_session() as sess: - res = self.evaluate(partitioned) + res = sess.run(partitioned) self.assertEqual(res[-1].shape[0], 192) diff --git a/tensorflow/python/kernel_tests/fifo_queue_test.py b/tensorflow/python/kernel_tests/fifo_queue_test.py index c184b93c80..e3742f2e72 100644 --- a/tensorflow/python/kernel_tests/fifo_queue_test.py +++ b/tensorflow/python/kernel_tests/fifo_queue_test.py @@ -159,7 +159,7 @@ class FIFOQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) threads = [ self.checkedThread( @@ -240,7 +240,7 @@ class FIFOQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) for enqueue_op in enqueue_ops: - self.evaluate(enqueue_op) + sess.run(enqueue_op) results = [] @@ -269,7 +269,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() for i in xrange(len(elems)): - x_val, y_val = self.evaluate(dequeued_t) + x_val, y_val = sess.run(dequeued_t) x, y = elems[i] self.assertEqual([x], x_val) self.assertEqual([y], y_val) @@ -356,7 +356,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() for i in range(8): - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertEqual(float_elems[i % 4], float_val) self.assertAllEqual(int_elems[i % 4], int_val) @@ -399,17 +399,17 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertEqual(float_val.shape, dequeued_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_t[1].get_shape()) - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) self.assertAllEqual(float_elems[8], float_val) self.assertAllEqual(int_elems[8], int_val) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) @@ -429,13 +429,13 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertEqual([None], dequeued_t[0].get_shape().as_list()) self.assertEqual([None, 2], dequeued_t[1].get_shape().as_list()) - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) @@ -529,7 +529,7 @@ class FIFOQueueTest(test.TestCase): # Enqueue 100 items in parallel on 10 threads. def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) threads = [self.checkedThread(target=enqueue) for _ in range(10)] for thread in threads: @@ -596,11 +596,11 @@ class FIFOQueueTest(test.TestCase): def enqueue(): for _ in xrange(100): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): for _ in xrange(100): - self.assertTrue(self.evaluate(dequeued_t) in (10.0, 20.0)) + self.assertTrue(sess.run(dequeued_t) in (10.0, 20.0)) enqueue_threads = [self.checkedThread(target=enqueue) for _ in range(10)] dequeue_threads = [self.checkedThread(target=dequeue) for _ in range(10)] @@ -632,7 +632,7 @@ class FIFOQueueTest(test.TestCase): def dequeue(): for i in xrange(250): - self.assertEqual(i, self.evaluate(dequeued_t)) + self.assertEqual(i, sess.run(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -663,7 +663,7 @@ class FIFOQueueTest(test.TestCase): dequeuemany_t = q.dequeue_many(count_placeholder) def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -701,7 +701,7 @@ class FIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): dequeued_elems.extend(sess.run(dequeued_t).tolist()) @@ -728,7 +728,7 @@ class FIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): dequeued_elems.extend(sess.run(dequeued_t).tolist()) @@ -797,7 +797,7 @@ class FIFOQueueTest(test.TestCase): def dequeue(): for elem in elems: - self.assertEqual([elem], self.evaluate(dequeued_t)) + self.assertEqual([elem], sess.run(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): @@ -842,7 +842,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems, self.evaluate(dequeued_t)) + self.assertAllEqual(elems, sess.run(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): @@ -867,7 +867,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[:3], sess.run(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): @@ -892,8 +892,8 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) - self.assertAllEqual(elems[3:], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[:3], sess.run(dequeued_t)) + self.assertAllEqual(elems[3:], sess.run(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -913,16 +913,16 @@ class FIFOQueueTest(test.TestCase): cleanup_dequeue_t = q.dequeue() def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): - self.assertAllEqual(elems[0:3], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[0:3], sess.run(dequeued_t)) with self.assertRaises(errors_impl.OutOfRangeError): sess.run(dequeued_t) - self.assertEqual(elems[3], self.evaluate(cleanup_dequeue_t)) + self.assertEqual(elems[3], sess.run(cleanup_dequeue_t)) def close(): - self.evaluate(close_op) + sess.run(close_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -1051,7 +1051,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1074,7 +1074,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1103,7 +1103,7 @@ class FIFOQueueTest(test.TestCase): def blocking_enqueue(): # Expect the operation to succeed once the dequeue op runs. - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1113,7 +1113,7 @@ class FIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - self.evaluate(close_op) + sess.run(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1138,7 +1138,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1148,7 +1148,7 @@ class FIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - self.evaluate(close_op) + sess.run(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1266,19 +1266,19 @@ class FIFOQueueTest(test.TestCase): def _blockingDequeue(self, sess, dequeue_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_op) + sess.run(dequeue_op) def _blockingDequeueMany(self, sess, dequeue_many_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_many_op) + sess.run(dequeue_many_op) def _blockingEnqueue(self, sess, enqueue_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def _blockingEnqueueMany(self, sess, enqueue_many_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(enqueue_many_op) + sess.run(enqueue_many_op) def testResetOfBlockingOperation(self): with self.cached_session() as sess: @@ -1331,14 +1331,14 @@ class FIFOQueueTest(test.TestCase): results = [] results.append(deq.eval()) # Will only complete after the enqueue starts. self.assertEqual(len(enq_done), 1) - self.assertEqual(self.evaluate(size_op), 5) + self.assertEqual(sess.run(size_op), 5) for _ in range(3): results.append(deq.eval()) time.sleep(0.1) self.assertEqual(len(enq_done), 1) - self.assertEqual(self.evaluate(size_op), 5) + self.assertEqual(sess.run(size_op), 5) # This dequeue will unblock the thread. results.append(deq.eval()) @@ -1405,7 +1405,7 @@ class FIFOQueueTest(test.TestCase): q.enqueue_many(input_tuple).run() output_tuple_t = q.dequeue_many(32) - output_tuple = self.evaluate(output_tuple_t) + output_tuple = sess.run(output_tuple_t) for (input_elem, output_elem) in zip(input_tuple, output_tuple): self.assertAllEqual(input_elem, output_elem) @@ -1507,7 +1507,7 @@ class FIFOQueueDictTest(test.TestCase): enqueue_op4 = q.enqueue_many({"f": [40.0, 50.0]}) dequeue = q.dequeue() dequeue_2 = q.dequeue_many(2) - self.evaluate(enqueue_op) + sess.run(enqueue_op) sess.run(enqueue_op2) sess.run(enqueue_op3) sess.run(enqueue_op4) @@ -1565,7 +1565,7 @@ class FIFOQueueDictTest(test.TestCase): }) dequeue = q.dequeue() dequeue_2 = q.dequeue_many(2) - self.evaluate(enqueue_op) + sess.run(enqueue_op) sess.run(enqueue_op2) sess.run(enqueue_op3) sess.run(enqueue_op4) @@ -1613,8 +1613,8 @@ class FIFOQueueWithTimeoutTest(test.TestCase): "Timed out waiting for notification"): sess.run(dequeued_t, options=config_pb2.RunOptions(timeout_in_ms=10)) - self.evaluate(enqueue_op) - self.assertEqual(37, self.evaluate(dequeued_t)) + sess.run(enqueue_op) + self.assertEqual(37, sess.run(dequeued_t)) class QueueContainerTest(test.TestCase): diff --git a/tensorflow/python/kernel_tests/functional_ops_test.py b/tensorflow/python/kernel_tests/functional_ops_test.py index 0af32b048e..503569f3b1 100644 --- a/tensorflow/python/kernel_tests/functional_ops_test.py +++ b/tensorflow/python/kernel_tests/functional_ops_test.py @@ -567,8 +567,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:worker/replica:0/task:0/cpu:1") with session.Session(worker[0].target) as sess: - self.evaluate(variables.global_variables_initializer()) - mul = self.evaluate(remote_op) + sess.run(variables.global_variables_initializer()) + mul = sess.run(remote_op) self.assertEqual(mul, [6]) def testRemoteFunctionDirectSession(self): @@ -591,8 +591,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:localhost/replica:0/task:0/cpu:1") with self.test_session(config=worker_config) as sess: - self.evaluate(variables.global_variables_initializer()) - mul = self.evaluate(remote_op) + sess.run(variables.global_variables_initializer()) + mul = sess.run(remote_op) self.assertEqual(mul, [6]) def testRemoteFunctionSameDeviceDirectSession(self): @@ -610,8 +610,8 @@ class FunctionalOpsTest(test.TestCase): args=[a, b], Tout=[dtypes.int32], f=_remote_fn, target="/cpu:0") with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - mul = self.evaluate(remote_op) + sess.run(variables.global_variables_initializer()) + mul = sess.run(remote_op) self.assertEqual(mul, [6]) def testRemoteFunctionCPUGPU(self): @@ -634,8 +634,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:localhost/replica:0/task:0/device:GPU:0")[0] + 3.0 with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - mul = self.evaluate(remote_op) + sess.run(variables.global_variables_initializer()) + mul = sess.run(remote_op) self.assertEqual(mul, 9.0) def testRemoteFunctionGPUCPU(self): @@ -658,8 +658,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:localhost/replica:0/task:0/cpu:0")[0] + 3.0 with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - mul = self.evaluate(remote_op) + sess.run(variables.global_variables_initializer()) + mul = sess.run(remote_op) self.assertEqual(mul, 9.0) def testRemoteFunctionGPUCPUStrings(self): @@ -677,7 +677,7 @@ class FunctionalOpsTest(test.TestCase): args=[a], Tout=[dtypes.string], f=_remote_fn, target="/cpu:0") with self.cached_session() as sess: - ret = self.evaluate(remote_op) + ret = sess.run(remote_op) self.assertAllEqual(ret, [b"a"]) def testRemoteFunctionCrossProcess(self): @@ -699,8 +699,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:worker/replica:0/task:1/cpu:0")[0] + 3.0 with session.Session(workers[0].target) as sess: - self.evaluate(variables.global_variables_initializer()) - mul = self.evaluate(remote_op) + sess.run(variables.global_variables_initializer()) + mul = sess.run(remote_op) self.assertEqual(mul, 9) def testIf(self): @@ -857,11 +857,11 @@ class FunctionalOpsTest(test.TestCase): result_binary = functional_ops.While( [1.0, 0., 0.], function.Defun(*[dtypes.float32] * 3)(TestCond), TestBinary) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) assert len(result_unary) == 2 - self.assertEqual([10.0, 54.0], self.evaluate(result_unary)) + self.assertEqual([10.0, 54.0], sess.run(result_unary)) assert len(result_binary) == 3 - self.assertEqual([10.0, 54.0, 9.0], self.evaluate(result_binary)) + self.assertEqual([10.0, 54.0, 9.0], sess.run(result_binary)) def TestCondCapture(n, *args): del args @@ -892,7 +892,7 @@ class FunctionalOpsTest(test.TestCase): 100, 0, -1, [0.], Body, rewrite_with_while=rewrite_with_while) [0], ] - xvals = self.evaluate(xs) + xvals = sess.run(xs) self.assertAllEqual(210, xvals[0]) self.assertAllEqual(5050, xvals[1]) @@ -949,16 +949,16 @@ class FunctionalOpsTest(test.TestCase): result_binary = functional_ops.For( 1, 10, 1, [0., 0.], TestBinary, rewrite_with_while=rewrite_with_while) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) assert not result_nullary # The nullary variant doesn't return anything so we can't easily run it. # As a total hack, fetch the operation by name and run it. sess.run(ops.get_default_graph().get_operation_by_name( "While" if rewrite_with_while else "For")) assert len(result_unary) == 1 - self.assertEqual([54.0], self.evaluate(result_unary)) + self.assertEqual([54.0], sess.run(result_unary)) assert len(result_binary) == 2 - self.assertEqual([54.0, 9.0], self.evaluate(result_binary)) + self.assertEqual([54.0, 9.0], sess.run(result_binary)) def _tfMLP(self, xval, wsval, bsval, rewrite_with_while): # On GPU, don't rewrite using a while loop. @@ -1041,8 +1041,8 @@ class FunctionalOpsTest(test.TestCase): avals = [Poly(a), Grad(a)] b = constant_op.constant(1.) bvals = [Poly(b), Grad(b)] - self.assertAllEqual(self.evaluate(avals), [8., 4.]) - self.assertAllEqual(self.evaluate(bvals), [17., 16.]) + self.assertAllEqual(sess.run(avals), [8., 4.]) + self.assertAllEqual(sess.run(bvals), [17., 16.]) # TODO(akshayka): Replace `function.Defun` with tf.contrib.eager.defun` in the @@ -1193,7 +1193,7 @@ class PartitionedCallTest(test.TestCase): allow_soft_placement=False, log_device_placement=True, device_count={"CPU": 2})) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) expected = sess.run(sum_gather()) result = sess.run( functional_ops.partitioned_call( diff --git a/tensorflow/python/kernel_tests/gradient_correctness_test.py b/tensorflow/python/kernel_tests/gradient_correctness_test.py index 12b8a4c8e3..291a69ebac 100644 --- a/tensorflow/python/kernel_tests/gradient_correctness_test.py +++ b/tensorflow/python/kernel_tests/gradient_correctness_test.py @@ -35,7 +35,7 @@ class GradientCorrectnessTest(test.TestCase): yexp = math_ops.exp(x) yexplog = math_ops.log(yexp) grads = gradients_impl.gradients([yexp, yexplog], [x]) - grad_vals = self.evaluate(grads) + grad_vals = sess.run(grads) exp1_plus_one = (1.0 + np.exp(1.0)).astype(np.float32) # [dexp(x)/dx + d(log(exp(x)))/dx] @ x=1 == exp(1) + 1 self.assertAllClose(grad_vals[0], exp1_plus_one) @@ -44,13 +44,13 @@ class GradientCorrectnessTest(test.TestCase): x = constant_op.constant(3.) dx_dx, = gradients_impl.gradients(x, x) with self.cached_session() as sess: - self.assertAllClose(1., self.evaluate(dx_dx)) + self.assertAllClose(1., sess.run(dx_dx)) def testIntegerIdentityGradient(self): x = constant_op.constant(3) dx_dx, = gradients_impl.gradients(x, x) with self.cached_session() as sess: - self.assertAllClose(1, self.evaluate(dx_dx)) + self.assertAllClose(1, sess.run(dx_dx)) def testGradientWithIntegerPath(self): x = constant_op.constant([3.9, 4.1]) @@ -58,7 +58,7 @@ class GradientCorrectnessTest(test.TestCase): y = x * k dy_dx, = gradients_impl.gradients(y, x) with self.cached_session() as sess: - self.assertAllClose([3., 4.], self.evaluate(dy_dx)) + self.assertAllClose([3., 4.], sess.run(dy_dx)) def testNoIntegerGradient1(self): x = constant_op.constant([3.9, 4.1]) diff --git a/tensorflow/python/kernel_tests/init_ops_test.py b/tensorflow/python/kernel_tests/init_ops_test.py index 074985dd93..a3f2c0ddd7 100644 --- a/tensorflow/python/kernel_tests/init_ops_test.py +++ b/tensorflow/python/kernel_tests/init_ops_test.py @@ -709,7 +709,7 @@ class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the delta-orthogonal kernel. - self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) def testNonuniformity(self): value = 0 @@ -847,7 +847,7 @@ class ConvolutionOrthogonal1dInitializerTest(test.TestCase): t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the orthogonal kernel. - self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) class ConvolutionOrthogonal2dInitializerTest(test.TestCase): @@ -942,7 +942,7 @@ class ConvolutionOrthogonal2dInitializerTest(test.TestCase): t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the orthogonal kernel. - self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) class ConvolutionOrthogonal3dInitializerTest(test.TestCase): @@ -1067,7 +1067,7 @@ class ConvolutionOrthogonal3dInitializerTest(test.TestCase): t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the orthogonal kernel. - self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) class IdentityInitializerTest(test.TestCase): diff --git a/tensorflow/python/kernel_tests/lookup_ops_test.py b/tensorflow/python/kernel_tests/lookup_ops_test.py index ab4c9c730b..3efad4ea11 100644 --- a/tensorflow/python/kernel_tests/lookup_ops_test.py +++ b/tensorflow/python/kernel_tests/lookup_ops_test.py @@ -174,7 +174,7 @@ class HashTableOpTest(test.TestCase): constant_op.constant(sp_shape, dtypes.int64)) output = table.lookup(input_tensor) - out_indices, out_values, out_shape = self.evaluate(output) + out_indices, out_values, out_shape = sess.run(output) self.assertAllEqual([0, 1, -1], out_values) self.assertAllEqual(sp_indices, out_indices) diff --git a/tensorflow/python/kernel_tests/losses_test.py b/tensorflow/python/kernel_tests/losses_test.py index bda63bcaa9..d3a907852a 100644 --- a/tensorflow/python/kernel_tests/losses_test.py +++ b/tensorflow/python/kernel_tests/losses_test.py @@ -1046,9 +1046,9 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): init_op = variables.global_variables_initializer() with self.cached_session() as sess: - self.evaluate(init_op) + sess.run(init_op) for grad, _ in gradients_to_variables: - np_grad = self.evaluate(grad) + np_grad = sess.run(grad) self.assertFalse(np.isnan(np_grad).any()) def testNonZeroLossWithPythonScalarWeight(self): diff --git a/tensorflow/python/kernel_tests/map_stage_op_test.py b/tensorflow/python/kernel_tests/map_stage_op_test.py index 4b5bd4059f..d503f3d7c9 100644 --- a/tensorflow/python/kernel_tests/map_stage_op_test.py +++ b/tensorflow/python/kernel_tests/map_stage_op_test.py @@ -148,7 +148,7 @@ class MapStageTest(test.TestCase): for i in range(n): self.assertTrue(sess.run(peek, feed_dict={gi: i})[0] == i) - self.assertTrue(self.evaluate(size) == 10) + self.assertTrue(sess.run(size) == 10) def testSizeAndClear(self): with ops.Graph().as_default() as G: @@ -170,11 +170,11 @@ class MapStageTest(test.TestCase): with self.session(use_gpu=True, graph=G) as sess: sess.run(stage, feed_dict={x: -1, pi: 3}) - self.assertEqual(self.evaluate(size), 1) + self.assertEqual(sess.run(size), 1) sess.run(stage, feed_dict={x: -1, pi: 1}) - self.assertEqual(self.evaluate(size), 2) + self.assertEqual(sess.run(size), 2) sess.run(clear) - self.assertEqual(self.evaluate(size), 0) + self.assertEqual(sess.run(size), 0) def testCapacity(self): capacity = 3 @@ -231,13 +231,13 @@ class MapStageTest(test.TestCase): capacity)) # Should have capacity elements in the staging area - self.assertTrue(self.evaluate(size) == capacity) + self.assertTrue(sess.run(size) == capacity) # Clear the staging area completely for i in range(n): sess.run(get) - self.assertTrue(self.evaluate(size) == 0) + self.assertTrue(sess.run(size) == 0) def testMemoryLimit(self): memory_limit = 512 * 1024 # 512K @@ -295,13 +295,13 @@ class MapStageTest(test.TestCase): capacity)) # Should have capacity elements in the staging area - self.assertTrue(self.evaluate(size) == capacity) + self.assertTrue(sess.run(size) == capacity) # Clear the staging area completely for i in range(n): sess.run(get) - self.assertTrue(self.evaluate(size) == 0) + self.assertTrue(sess.run(size) == 0) def testOrdering(self): import six @@ -332,14 +332,14 @@ class MapStageTest(test.TestCase): for i in keys: sess.run(stage, feed_dict={pi: i, x: i}) - self.assertTrue(self.evaluate(size) == n) + self.assertTrue(sess.run(size) == n) # Check that key, values come out in ascending order for i, k in enumerate(reversed(keys)): - get_key, values = self.evaluate(get) + get_key, values = sess.run(get) self.assertTrue(i == k == get_key == values) - self.assertTrue(self.evaluate(size) == 0) + self.assertTrue(sess.run(size) == 0) def testPartialDictInsert(self): with ops.Graph().as_default() as G: diff --git a/tensorflow/python/kernel_tests/matrix_inverse_op_test.py b/tensorflow/python/kernel_tests/matrix_inverse_op_test.py index 5cef4b79a3..434458721c 100644 --- a/tensorflow/python/kernel_tests/matrix_inverse_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_inverse_op_test.py @@ -146,7 +146,7 @@ class InverseOpTest(test.TestCase): inv1 = linalg_ops.matrix_inverse(matrix1, adjoint=adjoint_) inv2 = linalg_ops.matrix_inverse(matrix2, adjoint=adjoint_) all_ops += [inv1, inv2] - inv = self.evaluate(all_ops) + inv = sess.run(all_ops) self.assertAllEqual(inv[0], inv[1]) self.assertAllEqual(inv[2], inv[3]) diff --git a/tensorflow/python/kernel_tests/matrix_solve_op_test.py b/tensorflow/python/kernel_tests/matrix_solve_op_test.py index 80badee896..1334d0c4ce 100644 --- a/tensorflow/python/kernel_tests/matrix_solve_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_solve_op_test.py @@ -126,7 +126,7 @@ class MatrixSolveOpTest(test.TestCase): s1 = linalg_ops.matrix_solve(lhs1, rhs1, adjoint=adjoint_) s2 = linalg_ops.matrix_solve(lhs2, rhs2, adjoint=adjoint_) all_ops += [s1, s2] - val = self.evaluate(all_ops) + val = sess.run(all_ops) self.assertAllEqual(val[0], val[1]) self.assertAllEqual(val[2], val[3]) diff --git a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py index 1f2144bdee..9212580313 100644 --- a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py @@ -108,7 +108,7 @@ class SquareRootOpTest(test.TestCase): sqrt1 = gen_linalg_ops.matrix_square_root(matrix1) sqrt2 = gen_linalg_ops.matrix_square_root(matrix2) all_ops = [sqrt1, sqrt2] - sqrt = self.evaluate(all_ops) + sqrt = sess.run(all_ops) self.assertAllEqual(sqrt[0], sqrt[1]) diff --git a/tensorflow/python/kernel_tests/metrics_test.py b/tensorflow/python/kernel_tests/metrics_test.py index b68327105a..5dcdb9e420 100644 --- a/tensorflow/python/kernel_tests/metrics_test.py +++ b/tensorflow/python/kernel_tests/metrics_test.py @@ -203,10 +203,10 @@ class MeanTest(test.TestCase): mean, update_op = metrics.mean(values) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(4): - self.evaluate(update_op) - self.assertAlmostEqual(1.65, self.evaluate(mean), 5) + sess.run(update_op) + self.assertAlmostEqual(1.65, sess.run(mean), 5) def testUpdateOpsReturnsCurrentValue(self): with self.cached_session() as sess: @@ -220,14 +220,14 @@ class MeanTest(test.TestCase): mean, update_op = metrics.mean(values) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.5, self.evaluate(update_op), 5) - self.assertAlmostEqual(1.475, self.evaluate(update_op), 5) - self.assertAlmostEqual(12.4 / 6.0, self.evaluate(update_op), 5) - self.assertAlmostEqual(1.65, self.evaluate(update_op), 5) + self.assertAlmostEqual(0.5, sess.run(update_op), 5) + self.assertAlmostEqual(1.475, sess.run(update_op), 5) + self.assertAlmostEqual(12.4 / 6.0, sess.run(update_op), 5) + self.assertAlmostEqual(1.65, sess.run(update_op), 5) - self.assertAlmostEqual(1.65, self.evaluate(mean), 5) + self.assertAlmostEqual(1.65, sess.run(mean), 5) def testUnweighted(self): values = _test_values((3, 2, 4, 1)) @@ -370,10 +370,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(4): - self.evaluate(update_op) - self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(mean)) + sess.run(update_op) + self.assertAllClose([[-0.9 / 4., 3.525]], sess.run(mean)) def testMultiDimensional(self): with self.cached_session() as sess: @@ -391,11 +391,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(2): - self.evaluate(update_op) - self.assertAllClose([[[1, 2], [1, 2]], [[2, 3], [5, 6]]], - self.evaluate(mean)) + sess.run(update_op) + self.assertAllClose([[[1, 2], [1, 2]], [[2, 3], [5, 6]]], sess.run(mean)) def testUpdateOpsReturnsCurrentValue(self): with self.cached_session() as sess: @@ -409,14 +408,14 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) - self.assertAllClose([[0, 1]], self.evaluate(update_op), 5) - self.assertAllClose([[-2.1, 5.05]], self.evaluate(update_op), 5) - self.assertAllClose([[2.3 / 3., 10.1 / 3.]], self.evaluate(update_op), 5) - self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(update_op), 5) + self.assertAllClose([[0, 1]], sess.run(update_op), 5) + self.assertAllClose([[-2.1, 5.05]], sess.run(update_op), 5) + self.assertAllClose([[2.3 / 3., 10.1 / 3.]], sess.run(update_op), 5) + self.assertAllClose([[-0.9 / 4., 3.525]], sess.run(update_op), 5) - self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(mean), 5) + self.assertAllClose([[-0.9 / 4., 3.525]], sess.run(mean), 5) def testBinaryWeighted1d(self): with self.cached_session() as sess: @@ -440,10 +439,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(4): - self.evaluate(update_op) - self.assertAllClose([[3.25, 0.5]], self.evaluate(mean), 5) + sess.run(update_op) + self.assertAllClose([[3.25, 0.5]], sess.run(mean), 5) def testWeighted1d(self): with self.cached_session() as sess: @@ -467,10 +466,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(4): - self.evaluate(update_op) - self.assertAllClose([[0.8, 3.52]], self.evaluate(mean), 5) + sess.run(update_op) + self.assertAllClose([[0.8, 3.52]], sess.run(mean), 5) def testWeighted2d_1(self): with self.cached_session() as sess: @@ -494,10 +493,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(4): - self.evaluate(update_op) - self.assertAllClose([[-2.1, 0.5]], self.evaluate(mean), 5) + sess.run(update_op) + self.assertAllClose([[-2.1, 0.5]], sess.run(mean), 5) def testWeighted2d_2(self): with self.cached_session() as sess: @@ -521,10 +520,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(4): - self.evaluate(update_op) - self.assertAllClose([[0, 0.5]], self.evaluate(mean), 5) + sess.run(update_op) + self.assertAllClose([[0, 0.5]], sess.run(mean), 5) class AccuracyTest(test.TestCase): @@ -577,11 +576,11 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_accuracy = accuracy.eval() @@ -610,10 +609,10 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in xrange(3): - self.evaluate(update_op) - self.assertEqual(0.5, self.evaluate(update_op)) + sess.run(update_op) + self.assertEqual(0.5, sess.run(update_op)) self.assertEqual(0.5, accuracy.eval()) def testEffectivelyEquivalentSizes(self): @@ -622,7 +621,7 @@ class AccuracyTest(test.TestCase): with self.cached_session() as sess: accuracy, update_op = metrics.accuracy(labels, predictions) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertEqual(1.0, update_op.eval()) self.assertEqual(1.0, accuracy.eval()) @@ -632,7 +631,7 @@ class AccuracyTest(test.TestCase): with self.cached_session() as sess: accuracy, update_op = metrics.accuracy(labels, predictions, weights=2.0) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertEqual(1.0, update_op.eval()) self.assertEqual(1.0, accuracy.eval()) @@ -646,7 +645,7 @@ class AccuracyTest(test.TestCase): with self.cached_session() as sess: accuracy, update_op = metrics.accuracy(labels, predictions, weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # if streaming_accuracy does not flatten the weight, accuracy would be # 0.33333334 due to an intended broadcast of weight. Due to flattening, # it will be higher than .95 @@ -667,7 +666,7 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions, weights_placeholder) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # if streaming_accuracy does not flatten the weight, accuracy would be # 0.33333334 due to an intended broadcast of weight. Due to flattening, # it will be higher than .95 @@ -705,10 +704,10 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions, weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in xrange(3): - self.evaluate(update_op) - self.assertEqual(1.0, self.evaluate(update_op)) + sess.run(update_op) + self.assertEqual(1.0, sess.run(update_op)) self.assertEqual(1.0, accuracy.eval()) @@ -748,11 +747,11 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_precision = precision.eval() @@ -767,8 +766,8 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(1, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(1, sess.run(update_op)) self.assertAlmostEqual(1, precision.eval()) def testSomeCorrect_multipleInputDtypes(self): @@ -780,7 +779,7 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAlmostEqual(0.5, update_op.eval()) self.assertAlmostEqual(0.5, precision.eval()) @@ -883,8 +882,8 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.evaluate(update_op) + sess.run(variables.local_variables_initializer()) + sess.run(update_op) self.assertAlmostEqual(0, precision.eval()) def testZeroTrueAndFalsePositivesGivesZeroPrecision(self): @@ -893,8 +892,8 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.evaluate(update_op) + sess.run(variables.local_variables_initializer()) + sess.run(update_op) self.assertEqual(0.0, precision.eval()) @@ -935,11 +934,11 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_recall = recall.eval() @@ -954,8 +953,8 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.evaluate(update_op) + sess.run(variables.local_variables_initializer()) + sess.run(update_op) self.assertEqual(1, recall.eval()) def testSomeCorrect_multipleInputDtypes(self): @@ -967,7 +966,7 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAlmostEqual(0.5, update_op.eval()) self.assertAlmostEqual(0.5, recall.eval()) @@ -978,7 +977,7 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) weighted_tp = 2.0 + 5.0 weighted_t = (2.0 + 2.0) + (5.0 + 5.0) expected_precision = weighted_tp / weighted_t @@ -992,7 +991,7 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) weighted_tp = 3.0 + 1.0 weighted_t = (2.0 + 3.0) + (4.0 + 1.0) expected_precision = weighted_tp / weighted_t @@ -1007,8 +1006,8 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.evaluate(update_op) + sess.run(variables.local_variables_initializer()) + sess.run(update_op) self.assertEqual(0, recall.eval()) def testZeroTruePositivesAndFalseNegativesGivesZeroRecall(self): @@ -1017,8 +1016,8 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.evaluate(update_op) + sess.run(variables.local_variables_initializer()) + sess.run(update_op) self.assertEqual(0, recall.eval()) @@ -1057,11 +1056,11 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_auc = auc.eval() @@ -1079,8 +1078,8 @@ class AUCTest(test.TestCase): labels = constant_op.constant(inputs) auc, update_op = metrics.auc(labels, predictions, curve=curve) - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(1, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(1, sess.run(update_op)) self.assertEqual(1, auc.eval()) @@ -1094,8 +1093,8 @@ class AUCTest(test.TestCase): constant_op.constant([0, 1, 1, 0], shape=(1, 4)), dtype=label_dtype) auc, update_op = metrics.auc(labels, predictions) - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.5, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.5, sess.run(update_op)) self.assertAlmostEqual(0.5, auc.eval()) @@ -1107,8 +1106,8 @@ class AUCTest(test.TestCase): weights = constant_op.constant([2], shape=(1, 1)) auc, update_op = metrics.auc(labels, predictions, weights=weights) - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.5, self.evaluate(update_op), 5) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.5, sess.run(update_op), 5) self.assertAlmostEqual(0.5, auc.eval(), 5) @@ -1120,8 +1119,8 @@ class AUCTest(test.TestCase): weights = constant_op.constant([1, 2, 3, 4], shape=(1, 4)) auc, update_op = metrics.auc(labels, predictions, weights=weights) - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.7, self.evaluate(update_op), 5) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.7, sess.run(update_op), 5) self.assertAlmostEqual(0.7, auc.eval(), 5) @@ -1135,10 +1134,10 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='careful_interpolation') - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # expected ~= 0.79726744594 expected = 1 - math.log(1.5) / 2 - self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) + self.assertAlmostEqual(expected, sess.run(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) def testCorrectAnotherAUCPRSpecialCase(self): @@ -1151,10 +1150,10 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='careful_interpolation') - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # expected ~= 0.61350593198 expected = (2.5 - 2 * math.log(4./3) - 0.25 * math.log(7./5)) / 3 - self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) + self.assertAlmostEqual(expected, sess.run(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) def testThirdCorrectAUCPRSpecialCase(self): @@ -1167,10 +1166,10 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='careful_interpolation') - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # expected ~= 0.90410597584 expected = 1 - math.log(4./3) / 3 - self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) + self.assertAlmostEqual(expected, sess.run(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) def testIncorrectAUCPRSpecialCase(self): @@ -1181,8 +1180,8 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='trapezoidal') - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.79166, self.evaluate(update_op), delta=1e-3) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.79166, sess.run(update_op), delta=1e-3) self.assertAlmostEqual(0.79166, auc.eval(), delta=1e-3) @@ -1196,8 +1195,8 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='trapezoidal') - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.610317, self.evaluate(update_op), delta=1e-3) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.610317, sess.run(update_op), delta=1e-3) self.assertAlmostEqual(0.610317, auc.eval(), delta=1e-3) @@ -1211,8 +1210,8 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='trapezoidal') - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.90277, self.evaluate(update_op), delta=1e-3) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.90277, sess.run(update_op), delta=1e-3) self.assertAlmostEqual(0.90277, auc.eval(), delta=1e-3) @@ -1224,8 +1223,8 @@ class AUCTest(test.TestCase): labels = constant_op.constant(1 - inputs, dtype=dtypes_lib.float32) auc, update_op = metrics.auc(labels, predictions) - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0, sess.run(update_op)) self.assertAlmostEqual(0, auc.eval()) @@ -1235,8 +1234,8 @@ class AUCTest(test.TestCase): labels = array_ops.zeros([4]) auc, update_op = metrics.auc(labels, predictions) - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(1, self.evaluate(update_op), 6) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(1, sess.run(update_op), 6) self.assertAlmostEqual(1, auc.eval(), 6) @@ -1246,8 +1245,8 @@ class AUCTest(test.TestCase): labels = array_ops.ones([4]) auc, update_op = metrics.auc(labels, predictions, curve='PR') - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(1, self.evaluate(update_op), 6) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(1, sess.run(update_op), 6) self.assertAlmostEqual(1, auc.eval(), 6) @@ -1318,9 +1317,9 @@ class AUCTest(test.TestCase): num_thresholds=500, weights=tf_weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for i in range(num_batches): - self.evaluate(update_op) + sess.run(update_op) # Since this is only approximate, we can't expect a 6 digits match. # Although with higher number of samples/thresholds we should see the @@ -1372,11 +1371,11 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.7) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_specificity = specificity.eval() @@ -1392,8 +1391,8 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.7) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(1, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(1, sess.run(update_op)) self.assertEqual(1, specificity.eval()) def testSomeCorrectHighSensitivity(self): @@ -1407,8 +1406,8 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.8) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(1.0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(1.0, sess.run(update_op)) self.assertAlmostEqual(1.0, specificity.eval()) def testSomeCorrectLowSensitivity(self): @@ -1422,9 +1421,9 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.4) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.6, self.evaluate(update_op)) + self.assertAlmostEqual(0.6, sess.run(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) def testWeighted1d_multipleLabelDtypes(self): @@ -1441,9 +1440,9 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, weights=weights, sensitivity=0.4) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.6, self.evaluate(update_op)) + self.assertAlmostEqual(0.6, sess.run(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) def testWeighted2d(self): @@ -1459,9 +1458,9 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, weights=weights, sensitivity=0.4) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(8.0 / 15.0, self.evaluate(update_op)) + self.assertAlmostEqual(8.0 / 15.0, sess.run(update_op)) self.assertAlmostEqual(8.0 / 15.0, specificity.eval()) @@ -1509,11 +1508,11 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.7) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_sensitivity = sensitivity.eval() @@ -1529,8 +1528,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.7) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(1, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(1, sess.run(update_op)) self.assertEqual(1, specificity.eval()) def testSomeCorrectHighSpecificity(self): @@ -1544,8 +1543,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.8) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.8, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.8, sess.run(update_op)) self.assertAlmostEqual(0.8, specificity.eval()) def testSomeCorrectLowSpecificity(self): @@ -1559,8 +1558,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.4) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.6, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.6, sess.run(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) def testWeighted_multipleLabelDtypes(self): @@ -1578,8 +1577,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, weights=weights, specificity=0.4) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.675, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(0.675, sess.run(update_op)) self.assertAlmostEqual(0.675, specificity.eval()) @@ -1640,7 +1639,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates, then verify idempotency. sess.run([prec_op, rec_op]) @@ -1664,7 +1663,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertEqual(1, prec.eval()) @@ -1684,7 +1683,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertAlmostEqual(0.5, prec.eval()) @@ -1702,7 +1701,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertAlmostEqual(0, prec.eval()) @@ -1730,7 +1729,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec_low = array_ops.reshape(rec_low, shape=()) rec_high = array_ops.reshape(rec_high, shape=()) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertAlmostEqual(1.0, prec_low.eval(), places=5) @@ -1760,7 +1759,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec_low = array_ops.reshape(rec_low, shape=()) rec_high = array_ops.reshape(rec_high, shape=()) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertAlmostEqual(1.0, prec_low.eval(), places=5) @@ -1784,7 +1783,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): [rec_low, rec_high] = array_ops.split( value=rec, num_or_size_splits=2, axis=0) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertAlmostEqual(0.75, prec_low.eval()) @@ -1802,7 +1801,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([prec_op, rec_op]) self.assertAlmostEqual(0, prec.eval(), 6) @@ -1870,7 +1869,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(tf_labels, tf_predictions, thresholds) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(int(num_samples / batch_size)): sess.run([prec_op, rec_op]) # Since this is only approximate, we can't expect a 6 digits match. @@ -2803,11 +2802,11 @@ class MeanAbsoluteErrorTest(test.TestCase): error, update_op = metrics.mean_absolute_error(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_error = error.eval() @@ -2824,8 +2823,8 @@ class MeanAbsoluteErrorTest(test.TestCase): error, update_op = metrics.mean_absolute_error(labels, predictions, weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(3, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(3, sess.run(update_op)) self.assertEqual(3, error.eval()) @@ -2868,11 +2867,11 @@ class MeanRelativeErrorTest(test.TestCase): normalizer) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_error = error.eval() @@ -2893,8 +2892,8 @@ class MeanRelativeErrorTest(test.TestCase): labels, predictions, normalizer=labels) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(expected_error, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(expected_error, sess.run(update_op)) self.assertEqual(expected_error, error.eval()) def testSingleUpdateNormalizedByZeros(self): @@ -2909,8 +2908,8 @@ class MeanRelativeErrorTest(test.TestCase): labels, predictions, normalizer=array_ops.zeros_like(labels)) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(0.0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(0.0, sess.run(update_op)) self.assertEqual(0.0, error.eval()) @@ -2947,11 +2946,11 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_error = error.eval() @@ -2965,8 +2964,8 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(0, sess.run(update_op)) self.assertEqual(0, error.eval()) def testSingleUpdateWithError(self): @@ -2978,8 +2977,8 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(6, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(6, sess.run(update_op)) self.assertEqual(6, error.eval()) def testSingleUpdateWithErrorAndWeights(self): @@ -2992,8 +2991,8 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions, weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(13, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(13, sess.run(update_op)) self.assertEqual(13, error.eval()) def testMultipleBatchesOfSizeOne(self): @@ -3014,9 +3013,9 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) - self.evaluate(variables.local_variables_initializer()) - self.evaluate(update_op) - self.assertAlmostEqual(208.0 / 6, self.evaluate(update_op), 5) + sess.run(variables.local_variables_initializer()) + sess.run(update_op) + self.assertAlmostEqual(208.0 / 6, sess.run(update_op), 5) self.assertAlmostEqual(208.0 / 6, error.eval(), 5) @@ -3055,7 +3054,7 @@ class MeanSquaredErrorTest(test.TestCase): mse1, update_op1 = metrics.mean_squared_error( labels1, predictions1, name='msd1') - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([update_op0, update_op1]) sess.run([update_op0, update_op1]) @@ -3082,7 +3081,7 @@ class MeanSquaredErrorTest(test.TestCase): mae, ma_update_op = metrics.mean_absolute_error(labels, predictions) mse, ms_update_op = metrics.mean_squared_error(labels, predictions) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([ma_update_op, ms_update_op]) sess.run([ma_update_op, ms_update_op]) @@ -3124,11 +3123,11 @@ class RootMeanSquaredErrorTest(test.TestCase): error, update_op = metrics.root_mean_squared_error(labels, predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_error = error.eval() @@ -3143,8 +3142,8 @@ class RootMeanSquaredErrorTest(test.TestCase): rmse, update_op = metrics.root_mean_squared_error(labels, predictions) - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(0, sess.run(update_op)) self.assertEqual(0, rmse.eval()) @@ -3157,7 +3156,7 @@ class RootMeanSquaredErrorTest(test.TestCase): rmse, update_op = metrics.root_mean_squared_error(labels, predictions) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAlmostEqual(math.sqrt(6), update_op.eval(), 5) self.assertAlmostEqual(math.sqrt(6), rmse.eval(), 5) @@ -3172,8 +3171,8 @@ class RootMeanSquaredErrorTest(test.TestCase): rmse, update_op = metrics.root_mean_squared_error(labels, predictions, weights) - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(math.sqrt(13), self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(math.sqrt(13), sess.run(update_op)) self.assertAlmostEqual(math.sqrt(13), rmse.eval(), 5) @@ -3222,11 +3221,11 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=1) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_error = error.eval() @@ -3244,8 +3243,8 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=2) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(0, sess.run(update_op)) self.assertEqual(0, error.eval()) def testSingleUpdateWithError1(self): @@ -3260,8 +3259,8 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=2) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(1, self.evaluate(update_op), 5) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(1, sess.run(update_op), 5) self.assertAlmostEqual(1, error.eval(), 5) def testSingleUpdateWithError2(self): @@ -3281,8 +3280,8 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=2) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(1.0, self.evaluate(update_op), 5) + sess.run(variables.local_variables_initializer()) + self.assertAlmostEqual(1.0, sess.run(update_op), 5) self.assertAlmostEqual(1.0, error.eval(), 5) def testSingleUpdateWithErrorAndWeights1(self): @@ -3300,8 +3299,8 @@ class MeanCosineDistanceTest(test.TestCase): labels, predictions, dim=2, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) - self.assertEqual(0, self.evaluate(update_op)) + sess.run(variables.local_variables_initializer()) + self.assertEqual(0, sess.run(update_op)) self.assertEqual(0, error.eval()) def testSingleUpdateWithErrorAndWeights2(self): @@ -3319,7 +3318,7 @@ class MeanCosineDistanceTest(test.TestCase): labels, predictions, dim=2, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertEqual(1.5, update_op.eval()) self.assertEqual(1.5, error.eval()) @@ -3361,7 +3360,7 @@ class PcntBelowThreshTest(test.TestCase): pcnt1, update_op1 = metrics.percentage_below(values, 7, name='medium') pcnt2, update_op2 = metrics.percentage_below(values, 1, name='low') - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) sess.run([update_op0, update_op1, update_op2]) pcnt0, pcnt1, pcnt2 = sess.run([pcnt0, pcnt1, pcnt2]) @@ -3383,7 +3382,7 @@ class PcntBelowThreshTest(test.TestCase): pcnt2, update_op2 = metrics.percentage_below( values, 1, weights=weights, name='low') - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertListEqual([1.0, 0.5, 0.0], sess.run([update_op0, update_op1, update_op2])) @@ -3447,11 +3446,11 @@ class MeanIOUTest(test.TestCase): labels, predictions, num_classes=num_classes) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_mean_iou = mean_iou.eval() @@ -3483,9 +3482,9 @@ class MeanIOUTest(test.TestCase): miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(5): - self.evaluate(update_op) + sess.run(update_op) desired_output = np.mean([1.0 / 2.0, 1.0 / 4.0, 0.]) self.assertEqual(desired_output, miou.eval()) @@ -3530,7 +3529,7 @@ class MeanIOUTest(test.TestCase): variables.local_variables_initializer().run() for _ in range(6): - self.evaluate(update_op) + sess.run(update_op) desired_output = np.mean([2.0 / 3.0, 1.0 / 2.0]) self.assertAlmostEqual(desired_output, mean_iou.eval()) @@ -3564,9 +3563,9 @@ class MeanIOUTest(test.TestCase): miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(5): - self.evaluate(update_op) + sess.run(update_op) desired_output = np.mean([1.0 / 3.0, 2.0 / 4.0]) self.assertAlmostEqual(desired_output, miou.eval()) @@ -3588,7 +3587,7 @@ class MeanIOUTest(test.TestCase): num_classes = 2 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) confusion_matrix = update_op.eval() self.assertAllEqual([[3, 0], [2, 5]], confusion_matrix) desired_miou = np.mean([3. / 5., 5. / 7.]) @@ -3600,7 +3599,7 @@ class MeanIOUTest(test.TestCase): num_classes = 1 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertEqual(40, update_op.eval()[0]) self.assertEqual(1.0, miou.eval()) @@ -3610,7 +3609,7 @@ class MeanIOUTest(test.TestCase): num_classes = 2 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual([[0, 0], [40, 0]], update_op.eval()) self.assertEqual(0., miou.eval()) @@ -3641,7 +3640,7 @@ class MeanIOUTest(test.TestCase): with self.cached_session() as sess: miou, update_op = metrics.mean_iou( labels, predictions, num_classes, weights=weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual([[2, 0], [2, 4]], update_op.eval()) desired_miou = np.mean([2. / 4., 4. / 6.]) self.assertAlmostEqual(desired_miou, miou.eval()) @@ -3660,7 +3659,7 @@ class MeanIOUTest(test.TestCase): num_classes = 3 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual([[7, 4, 3], [3, 5, 2], [0, 0, 0]], update_op.eval()) self.assertAlmostEqual( 1 / 3 * (7 / (7 + 3 + 7) + 5 / (5 + 4 + 5) + 0 / (0 + 5 + 0)), @@ -3672,7 +3671,7 @@ class MeanIOUTest(test.TestCase): num_classes = 2 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual([[1, 0], [0, 0]], update_op.eval()) self.assertAlmostEqual(1, miou.eval()) @@ -3690,7 +3689,7 @@ class MeanIOUTest(test.TestCase): num_classes = 3 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual([[9, 5, 0], [3, 7, 0], [0, 0, 0]], update_op.eval()) self.assertAlmostEqual( 1 / 2 * (9 / (9 + 3 + 5) + 7 / (7 + 5 + 3)), miou.eval()) @@ -3753,11 +3752,11 @@ class MeanPerClassAccuracyTest(test.TestCase): labels, predictions, num_classes=num_classes) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - self.evaluate(update_op) + sess.run(update_op) # Then verify idempotency. initial_mean_accuracy = mean_accuracy.eval() @@ -3789,9 +3788,9 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(5): - self.evaluate(update_op) + sess.run(update_op) desired_output = np.mean([1.0, 1.0 / 3.0, 0.0]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) @@ -3836,7 +3835,7 @@ class MeanPerClassAccuracyTest(test.TestCase): variables.local_variables_initializer().run() for _ in range(6): - self.evaluate(update_op) + sess.run(update_op) desired_output = np.mean([2.0 / 2.0, 0.5 / 1.5]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) @@ -3871,9 +3870,9 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) for _ in range(5): - self.evaluate(update_op) + sess.run(update_op) desired_output = np.mean([1.0 / 2.0, 2.0 / 3.0, 0.]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) @@ -3884,7 +3883,7 @@ class MeanPerClassAccuracyTest(test.TestCase): with self.cached_session() as sess: mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertEqual(1.0, update_op.eval()[0]) self.assertEqual(1.0, mean_accuracy.eval()) @@ -3895,7 +3894,7 @@ class MeanPerClassAccuracyTest(test.TestCase): with self.cached_session() as sess: mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual([0.0, 0.0], update_op.eval()) self.assertEqual(0., mean_accuracy.eval()) @@ -3914,7 +3913,7 @@ class MeanPerClassAccuracyTest(test.TestCase): with self.cached_session() as sess: mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes, weights=weights) - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) desired_accuracy = np.array([2. / 2., 4. / 6.], dtype=np.float32) self.assertAllEqual(desired_accuracy, update_op.eval()) desired_mean_accuracy = np.mean(desired_accuracy) @@ -3946,7 +3945,7 @@ class FalseNegativesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(3., tn_update_op.eval()) self.assertAllClose(3., tn.eval()) @@ -3965,7 +3964,7 @@ class FalseNegativesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(5., tn_update_op.eval()) self.assertAllClose(5., tn.eval()) @@ -3995,7 +3994,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), fn.eval()) self.assertAllEqual((0, 2, 3), fn_update_op.eval()) self.assertAllEqual((0, 2, 3), fn.eval()) @@ -4014,7 +4013,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), fn.eval()) self.assertAllEqual((0.0, 8.0, 11.0), fn_update_op.eval()) self.assertAllEqual((0.0, 8.0, 11.0), fn.eval()) @@ -4045,7 +4044,7 @@ class FalsePositivesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(7., tn_update_op.eval()) self.assertAllClose(7., tn.eval()) @@ -4064,7 +4063,7 @@ class FalsePositivesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(14., tn_update_op.eval()) self.assertAllClose(14., tn.eval()) @@ -4094,7 +4093,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), fp.eval()) self.assertAllEqual((7, 4, 2), fp_update_op.eval()) self.assertAllEqual((7, 4, 2), fp.eval()) @@ -4115,7 +4114,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), fp.eval()) self.assertAllEqual((125.0, 42.0, 12.0), fp_update_op.eval()) self.assertAllEqual((125.0, 42.0, 12.0), fp.eval()) @@ -4146,7 +4145,7 @@ class TrueNegativesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(3., tn_update_op.eval()) self.assertAllClose(3., tn.eval()) @@ -4165,7 +4164,7 @@ class TrueNegativesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(4., tn_update_op.eval()) self.assertAllClose(4., tn.eval()) @@ -4195,7 +4194,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), tn.eval()) self.assertAllEqual((2, 5, 7), tn_update_op.eval()) self.assertAllEqual((2, 5, 7), tn.eval()) @@ -4214,7 +4213,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), tn.eval()) self.assertAllEqual((5.0, 15.0, 23.0), tn_update_op.eval()) self.assertAllEqual((5.0, 15.0, 23.0), tn.eval()) @@ -4245,7 +4244,7 @@ class TruePositivesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(7., tn_update_op.eval()) self.assertAllClose(7., tn.eval()) @@ -4264,7 +4263,7 @@ class TruePositivesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(12., tn_update_op.eval()) self.assertAllClose(12., tn.eval()) @@ -4294,7 +4293,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), tp.eval()) self.assertAllEqual((3, 1, 0), tp_update_op.eval()) self.assertAllEqual((3, 1, 0), tp.eval()) @@ -4311,7 +4310,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - self.evaluate(variables.local_variables_initializer()) + sess.run(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), tp.eval()) self.assertAllEqual((111.0, 37.0, 0.0), tp_update_op.eval()) self.assertAllEqual((111.0, 37.0, 0.0), tp.eval()) diff --git a/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py b/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py index 87f1991aa7..15e3826542 100644 --- a/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py +++ b/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py @@ -142,8 +142,8 @@ class DepthwiseConv2DTest(test.TestCase): conv_interface = nn_impl.depthwise_conv2d( t1, t2, strides=[1, stride, stride, 1], padding=padding) - native_result = self.evaluate(conv_native) - interface_result = self.evaluate(conv_interface) + native_result = sess.run(conv_native) + interface_result = sess.run(conv_interface) print("depthwise conv_2d: ", tensor_in_sizes, "*", filter_in_sizes, ", stride:", stride, ", padding: ", padding, ", max diff: ", @@ -211,7 +211,7 @@ class DepthwiseConv2DTest(test.TestCase): t2 = constant_op.constant(x2, shape=filter_in_sizes) conv = nn_ops.depthwise_conv2d_native( t1, t2, strides=[1, stride, stride, 1], padding=padding) - value = self.evaluate(conv) + value = sess.run(conv) print("value = ", value) self.assertAllClose(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) diff --git a/tensorflow/python/kernel_tests/norm_op_test.py b/tensorflow/python/kernel_tests/norm_op_test.py index 5ff0c58bf1..e202b6e8a4 100644 --- a/tensorflow/python/kernel_tests/norm_op_test.py +++ b/tensorflow/python/kernel_tests/norm_op_test.py @@ -70,7 +70,7 @@ def _GetNormOpTest(dtype_, shape_, ord_, axis_, keep_dims_, use_static_shape_): tf_matrix = constant_op.constant(matrix) tf_norm = linalg_ops.norm( tf_matrix, ord=ord_, axis=axis_, keepdims=keep_dims_) - tf_norm_val = self.evaluate(tf_norm) + tf_norm_val = sess.run(tf_norm) else: tf_matrix = array_ops.placeholder(dtype_) tf_norm = linalg_ops.norm( diff --git a/tensorflow/python/kernel_tests/nth_element_op_test.py b/tensorflow/python/kernel_tests/nth_element_op_test.py index 6cd4974671..338b6cec01 100644 --- a/tensorflow/python/kernel_tests/nth_element_op_test.py +++ b/tensorflow/python/kernel_tests/nth_element_op_test.py @@ -35,7 +35,7 @@ class NthElementTest(test.TestCase): with self.cached_session(use_gpu=False) as sess: inputs_op = ops.convert_to_tensor(inputs, dtype=dtype) values_op = nn_ops.nth_element(inputs_op, n, reverse=reverse) - values = self.evaluate(values_op) + values = sess.run(values_op) self.assertShapeEqual(np_expected_values, values_op) self.assertAllClose(np_expected_values, values) diff --git a/tensorflow/python/kernel_tests/padding_fifo_queue_test.py b/tensorflow/python/kernel_tests/padding_fifo_queue_test.py index 3696298132..520b663375 100644 --- a/tensorflow/python/kernel_tests/padding_fifo_queue_test.py +++ b/tensorflow/python/kernel_tests/padding_fifo_queue_test.py @@ -126,7 +126,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) threads = [ self.checkedThread( @@ -193,7 +193,7 @@ class PaddingFIFOQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) for enqueue_op in enqueue_ops: - self.evaluate(enqueue_op) + sess.run(enqueue_op) results = [] @@ -224,7 +224,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() for i in xrange(len(elems)): - x_val, y_val = self.evaluate(dequeued_t) + x_val, y_val = sess.run(dequeued_t) x, y = elems[i] self.assertEqual([x], x_val) self.assertEqual([y], y_val) @@ -327,7 +327,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() for i in range(8): - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertEqual(float_elems[i % 4], float_val) self.assertAllEqual(int_elems[i % 4], int_val) @@ -344,7 +344,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() for i in range(8): - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertEqual(float_elems[i % 4], float_val) self.assertAllEqual(int_elems[i % 4], int_val) @@ -387,17 +387,17 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertEqual(float_val.shape, dequeued_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_t[1].get_shape()) - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) self.assertAllEqual(float_elems[8], float_val) self.assertAllEqual(int_elems[8], int_val) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) @@ -418,7 +418,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertTrue( @@ -428,11 +428,11 @@ class PaddingFIFOQueueTest(test.TestCase): tensor_shape.TensorShape(int_val.shape).is_compatible_with(dequeued_t[ 1].get_shape())) - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) self.assertAllEqual(float_elems[8], float_val) self.assertAllEqual(int_elems[8], int_val) self.assertTrue( @@ -459,7 +459,7 @@ class PaddingFIFOQueueTest(test.TestCase): for enqueue_op in enqueue_ops: enqueue_op.run() - string_val, int_val = self.evaluate(dequeued_t) + string_val, int_val = sess.run(dequeued_t) self.assertAllEqual([[b"a", b"", b""], [b"ab", b"", b""], [b"abc", b"", b""], [b"abc", b"d", b""], @@ -473,7 +473,7 @@ class PaddingFIFOQueueTest(test.TestCase): tensor_shape.TensorShape(int_val.shape).is_compatible_with(dequeued_t[ 1].get_shape())) - string_val, int_val = self.evaluate(dequeued_single_t) + string_val, int_val = sess.run(dequeued_single_t) self.assertAllEqual([b"abc", b"d", b"e", b"f"], string_val) self.assertAllEqual([[1, 2, 3, 4]], int_val) self.assertTrue( @@ -500,7 +500,7 @@ class PaddingFIFOQueueTest(test.TestCase): for enqueue_op in enqueue_ops: enqueue_op.run() - string_val, int_val = self.evaluate(dequeued_t) + string_val, int_val = sess.run(dequeued_t) self.assertAllEqual([[b"a", b"", b""], [b"ab", b"", b""], [b"abc", b"", b""], [b"abc", b"d", b""], @@ -514,7 +514,7 @@ class PaddingFIFOQueueTest(test.TestCase): tensor_shape.TensorShape(int_val.shape).is_compatible_with(dequeued_t[ 1].get_shape())) - string_val, int_val = self.evaluate(dequeued_single_t) + string_val, int_val = sess.run(dequeued_single_t) self.assertAllEqual([b"abc", b"d", b"e", b"f"], string_val) self.assertAllEqual([[1, 2, 3, 4]], int_val) self.assertTrue( @@ -633,7 +633,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Enqueue 100 items in parallel on 10 threads. def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) threads = [self.checkedThread(target=enqueue) for _ in range(10)] for thread in threads: @@ -700,11 +700,11 @@ class PaddingFIFOQueueTest(test.TestCase): def enqueue(): for _ in xrange(100): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): for _ in xrange(100): - self.assertTrue(self.evaluate(dequeued_t) in (10.0, 20.0)) + self.assertTrue(sess.run(dequeued_t) in (10.0, 20.0)) enqueue_threads = [self.checkedThread(target=enqueue) for _ in range(10)] dequeue_threads = [self.checkedThread(target=dequeue) for _ in range(10)] @@ -736,7 +736,7 @@ class PaddingFIFOQueueTest(test.TestCase): def dequeue(): for i in xrange(250): - self.assertEqual(i, self.evaluate(dequeued_t)) + self.assertEqual(i, sess.run(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -767,7 +767,7 @@ class PaddingFIFOQueueTest(test.TestCase): dequeuemany_t = q.dequeue_many(count_placeholder) def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -805,7 +805,7 @@ class PaddingFIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): dequeued_elems.extend(sess.run(dequeued_t).tolist()) @@ -832,7 +832,7 @@ class PaddingFIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): dequeued_elems.extend(sess.run(dequeued_t).tolist()) @@ -901,7 +901,7 @@ class PaddingFIFOQueueTest(test.TestCase): def dequeue(): for elem in elems: - self.assertEqual([elem], self.evaluate(dequeued_t)) + self.assertEqual([elem], sess.run(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): @@ -926,8 +926,8 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) - self.assertAllEqual(elems[3:], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[:3], sess.run(dequeued_t)) + self.assertAllEqual(elems[3:], sess.run(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -968,7 +968,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems, self.evaluate(dequeued_t)) + self.assertAllEqual(elems, sess.run(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): @@ -993,7 +993,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[:3], sess.run(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): @@ -1017,16 +1017,16 @@ class PaddingFIFOQueueTest(test.TestCase): cleanup_dequeue_t = q.dequeue() def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): - self.assertAllEqual(elems[0:3], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[0:3], sess.run(dequeued_t)) with self.assertRaises(errors_impl.OutOfRangeError): sess.run(dequeued_t) - self.assertEqual(elems[3], self.evaluate(cleanup_dequeue_t)) + self.assertEqual(elems[3], sess.run(cleanup_dequeue_t)) def close(): - self.evaluate(close_op) + sess.run(close_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -1155,7 +1155,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1178,7 +1178,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1207,7 +1207,7 @@ class PaddingFIFOQueueTest(test.TestCase): def blocking_enqueue(): # Expect the operation to succeed once the dequeue op runs. - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1217,7 +1217,7 @@ class PaddingFIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - self.evaluate(close_op) + sess.run(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1242,7 +1242,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1252,7 +1252,7 @@ class PaddingFIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - self.evaluate(close_op) + sess.run(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1379,19 +1379,19 @@ class PaddingFIFOQueueTest(test.TestCase): def _blockingDequeue(self, sess, dequeue_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_op) + sess.run(dequeue_op) def _blockingDequeueMany(self, sess, dequeue_many_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_many_op) + sess.run(dequeue_many_op) def _blockingEnqueue(self, sess, enqueue_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def _blockingEnqueueMany(self, sess, enqueue_many_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(enqueue_many_op) + sess.run(enqueue_many_op) def testResetOfBlockingOperation(self): with self.cached_session() as sess: @@ -1444,14 +1444,14 @@ class PaddingFIFOQueueTest(test.TestCase): results = [] results.append(deq.eval()) # Will only complete after the enqueue starts. self.assertEqual(len(enq_done), 1) - self.assertEqual(self.evaluate(size_op), 5) + self.assertEqual(sess.run(size_op), 5) for _ in range(3): results.append(deq.eval()) time.sleep(0.1) self.assertEqual(len(enq_done), 1) - self.assertEqual(self.evaluate(size_op), 5) + self.assertEqual(sess.run(size_op), 5) # This dequeue will unblock the thread. results.append(deq.eval()) @@ -1517,7 +1517,7 @@ class PaddingFIFOQueueTest(test.TestCase): q.enqueue_many(input_tuple).run() output_tuple_t = q.dequeue_many(32) - output_tuple = self.evaluate(output_tuple_t) + output_tuple = sess.run(output_tuple_t) for (input_elem, output_elem) in zip(input_tuple, output_tuple): self.assertAllEqual(input_elem, output_elem) diff --git a/tensorflow/python/kernel_tests/parse_single_example_op_test.py b/tensorflow/python/kernel_tests/parse_single_example_op_test.py index 3f50087282..a84895a287 100644 --- a/tensorflow/python/kernel_tests/parse_single_example_op_test.py +++ b/tensorflow/python/kernel_tests/parse_single_example_op_test.py @@ -107,7 +107,7 @@ class ParseExampleTest(test.TestCase): for result_dict in [out, out_with_example_name]: result = flatten_values_tensors_or_sparse(result_dict.values()) # Check values. - tf_result = self.evaluate(result) + tf_result = sess.run(result) _compare_output_to_expected(self, result_dict, expected_values, tf_result) diff --git a/tensorflow/python/kernel_tests/parsing_ops_test.py b/tensorflow/python/kernel_tests/parsing_ops_test.py index d87adbfc2e..8f359bd32c 100644 --- a/tensorflow/python/kernel_tests/parsing_ops_test.py +++ b/tensorflow/python/kernel_tests/parsing_ops_test.py @@ -101,7 +101,7 @@ class ParseExampleTest(test.TestCase): out = parsing_ops.parse_example(**kwargs) result = flatten_values_tensors_or_sparse(out.values()) # Check values. - tf_result = self.evaluate(result) + tf_result = sess.run(result) _compare_output_to_expected(self, out, expected_values, tf_result) # Check shapes; if serialized is a Tensor we need its size to @@ -1614,7 +1614,7 @@ class DecodeJSONExampleTest(test.TestCase): shape=examples.shape, dtype=dtypes.string) binary_tensor = parsing_ops.decode_json_example(json_tensor) - binary_val = self.evaluate(binary_tensor) + binary_val = sess.run(binary_tensor) if examples.shape: self.assertShapeEqual(binary_val, json_tensor) diff --git a/tensorflow/python/kernel_tests/pooling_ops_3d_test.py b/tensorflow/python/kernel_tests/pooling_ops_3d_test.py index a8e962bc3a..e393c7a022 100644 --- a/tensorflow/python/kernel_tests/pooling_ops_3d_test.py +++ b/tensorflow/python/kernel_tests/pooling_ops_3d_test.py @@ -81,7 +81,7 @@ class PoolingTest(test.TestCase): data_format=data_format) if data_format == "NCDHW": t = test_util.NCHWToNHWC(t) - vals = self.evaluate(t) + vals = sess.run(t) # Verifies values. actual = vals.flatten() self.assertAllClose(expected, actual) diff --git a/tensorflow/python/kernel_tests/priority_queue_test.py b/tensorflow/python/kernel_tests/priority_queue_test.py index a510fccaaa..73a9c81638 100644 --- a/tensorflow/python/kernel_tests/priority_queue_test.py +++ b/tensorflow/python/kernel_tests/priority_queue_test.py @@ -50,7 +50,7 @@ class PriorityQueueTest(test.TestCase): enq.run() deq = q.dequeue_many(100) - deq_elem, deq_value_0, deq_value_1 = self.evaluate(deq) + deq_elem, deq_value_0, deq_value_1 = sess.run(deq) allowed = {} missed = set() @@ -81,7 +81,7 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) dequeue_op = q.dequeue_many(100) @@ -93,7 +93,7 @@ class PriorityQueueTest(test.TestCase): for t in enqueue_threads: t.start() - deq_elem, deq_value_0, deq_value_1 = self.evaluate(dequeue_op) + deq_elem, deq_value_0, deq_value_1 = sess.run(dequeue_op) for t in enqueue_threads: t.join() @@ -132,12 +132,12 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) dequeued = [] def dequeue(dequeue_op): - (dequeue_indices, dequeue_values) = self.evaluate(dequeue_op) + (dequeue_indices, dequeue_values) = sess.run(dequeue_op) self.assertAllEqual(dequeue_indices, dequeue_values) dequeued.extend(dequeue_indices) @@ -184,10 +184,10 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(dequeue_op, dequeued): - (dequeue_indices, dequeue_values) = self.evaluate(dequeue_op) + (dequeue_indices, dequeue_values) = sess.run(dequeue_op) self.assertAllEqual(dequeue_indices, dequeue_values) dequeue_wait.acquire() dequeued.extend(dequeue_indices) @@ -236,7 +236,7 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) dequeue_op = q.dequeue_many(100) @@ -248,7 +248,7 @@ class PriorityQueueTest(test.TestCase): for t in enqueue_threads: t.start() - deq_elem, deq_value_0, deq_value_1 = self.evaluate(dequeue_op) + deq_elem, deq_value_0, deq_value_1 = sess.run(dequeue_op) for t in enqueue_threads: t.join() @@ -276,7 +276,7 @@ class PriorityQueueTest(test.TestCase): side_value_1 = np.random.rand(1000).astype(bytes) q.enqueue_many((elem, side_value_0, side_value_1)).run() deq = q.dequeue_many(1000) - deq_elem, deq_value_0, deq_value_1 = self.evaluate(deq) + deq_elem, deq_value_0, deq_value_1 = sess.run(deq) allowed = {} for e, v0, v1 in zip(elem, side_value_0, side_value_1): diff --git a/tensorflow/python/kernel_tests/py_func_test.py b/tensorflow/python/kernel_tests/py_func_test.py index c9cbe44a7f..b101da036e 100644 --- a/tensorflow/python/kernel_tests/py_func_test.py +++ b/tensorflow/python/kernel_tests/py_func_test.py @@ -307,9 +307,9 @@ class PyFuncTest(test.TestCase): with session_lib.Session() as sess: producer = iter(range(3)) x, = script_ops.py_func(lambda: next(producer), [], [dtypes.int64]) - self.assertEqual(self.evaluate(x), 0) - self.assertEqual(self.evaluate(x), 1) - self.assertEqual(self.evaluate(x), 2) + self.assertEqual(sess.run(x), 0) + self.assertEqual(sess.run(x), 1) + self.assertEqual(sess.run(x), 2) def testStateless(self): # Not using self.cached_session(), which disables optimization. @@ -317,9 +317,9 @@ class PyFuncTest(test.TestCase): producer = iter(range(3)) x, = script_ops.py_func( lambda: next(producer), [], [dtypes.int64], stateful=False) - self.assertEqual(self.evaluate(x), 0) - self.assertEqual(self.evaluate(x), 0) - self.assertEqual(self.evaluate(x), 0) + self.assertEqual(sess.run(x), 0) + self.assertEqual(sess.run(x), 0) + self.assertEqual(sess.run(x), 0) def testGradientFunction(self): # Input to tf.py_func is necessary, otherwise get_gradient_function() @@ -390,7 +390,7 @@ class PyFuncTest(test.TestCase): f = script_ops.py_func( do_nothing, [constant_op.constant(3, dtypes.int64)], [], stateful=False) with self.cached_session() as sess: - self.assertEqual(self.evaluate(f), []) + self.assertEqual(sess.run(f), []) def _testExceptionHandling(self, py_exp, tf_exp, eager=False): diff --git a/tensorflow/python/kernel_tests/qr_op_test.py b/tensorflow/python/kernel_tests/qr_op_test.py index 114481ed6a..617b724204 100644 --- a/tensorflow/python/kernel_tests/qr_op_test.py +++ b/tensorflow/python/kernel_tests/qr_op_test.py @@ -60,7 +60,7 @@ class QrOpTest(test.TestCase): q1, r1 = linalg_ops.qr(matrix1, full_matrices=full_matrices_) q2, r2 = linalg_ops.qr(matrix2, full_matrices=full_matrices_) all_ops += [q1, r1, q2, r2] - val = self.evaluate(all_ops) + val = sess.run(all_ops) for i in range(8): q = 4 * i self.assertAllEqual(val[q], val[q + 2]) # q1 == q2 diff --git a/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py b/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py index cab841741e..0023506b77 100644 --- a/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py +++ b/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py @@ -39,7 +39,7 @@ class MultinomialTest(test.TestCase): num_samples=1000000, seed=15) for _ in range(100): - x = self.evaluate(samples) + x = sess.run(samples) indices, counts = np.unique(x, return_counts=True) for index, count in zip(indices, counts): if index in counts_by_indices.keys(): @@ -57,7 +57,7 @@ class MultinomialTest(test.TestCase): num_samples=1000000, seed=15) for _ in range(100): - x = self.evaluate(samples) + x = sess.run(samples) indices, counts = np.unique(x, return_counts=True) for index, count in zip(indices, counts): if index in counts_by_indices.keys(): @@ -79,7 +79,7 @@ class MultinomialTest(test.TestCase): # we'll run out of memory if we try to draw 1e9 samples directly # really should fit in 12GB of memory... for _ in range(100): - x = self.evaluate(samples) + x = sess.run(samples) indices, counts = np.unique(x, return_counts=True) for index, count in zip(indices, counts): if index in counts_by_indices.keys(): diff --git a/tensorflow/python/kernel_tests/random/multinomial_op_test.py b/tensorflow/python/kernel_tests/random/multinomial_op_test.py index 8d2718c6d5..cfec4d08fb 100644 --- a/tensorflow/python/kernel_tests/random/multinomial_op_test.py +++ b/tensorflow/python/kernel_tests/random/multinomial_op_test.py @@ -70,8 +70,8 @@ class MultinomialTest(test.TestCase): with self.test_session(use_gpu=True) as sess: sample_op1, _ = self._make_ops(10) # Consecutive runs shouldn't yield identical output. - sample1a = self.evaluate(sample_op1) - sample1b = self.evaluate(sample_op1) + sample1a = sess.run(sample_op1) + sample1b = sess.run(sample_op1) self.assertFalse(np.equal(sample1a, sample1b).all()) def testEagerOneOpMultipleStepsIndependent(self): @@ -160,7 +160,7 @@ class MultinomialTest(test.TestCase): with self.test_session(use_gpu=True) as sess: random_seed.set_random_seed(1618) op = sampler(constant_op.constant(logits), num_samples) - d = self.evaluate(op) + d = sess.run(op) batch_size, num_classes = logits.shape freqs_mat = [] @@ -225,10 +225,8 @@ def native_op_vs_composed_ops(batch_size, num_classes, num_samples, num_iters): native_op = control_flow_ops.group(native_sampler(logits, num_samples)) composed_op = control_flow_ops.group(composed_sampler(logits, num_samples)) - native_dt = timeit.timeit( - lambda: sess.run(native_op), number=num_iters) - composed_dt = timeit.timeit( - lambda: sess.run(composed_op), number=num_iters) + native_dt = timeit.timeit(lambda: sess.run(native_op), number=num_iters) + composed_dt = timeit.timeit(lambda: sess.run(composed_op), number=num_iters) return native_dt, composed_dt diff --git a/tensorflow/python/kernel_tests/random/random_gamma_test.py b/tensorflow/python/kernel_tests/random/random_gamma_test.py index d18e3feb04..606e8862c4 100644 --- a/tensorflow/python/kernel_tests/random/random_gamma_test.py +++ b/tensorflow/python/kernel_tests/random/random_gamma_test.py @@ -48,7 +48,7 @@ class RandomGammaTest(test.TestCase): [num], alpha, beta=beta, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = self.evaluate(rng) + ret[i, :] = sess.run(rng) return ret return func diff --git a/tensorflow/python/kernel_tests/random/random_ops_test.py b/tensorflow/python/kernel_tests/random/random_ops_test.py index 76618316b2..6de894846b 100644 --- a/tensorflow/python/kernel_tests/random/random_ops_test.py +++ b/tensorflow/python/kernel_tests/random/random_ops_test.py @@ -49,9 +49,9 @@ class RandomOpTestCommon(test.TestCase): random_seed.set_random_seed(graph_seed) x = rng_func([num], min_or_mean, max_or_stddev, dtype=dtype, seed=op_seed) - y = self.evaluate(x) - z = self.evaluate(x) - w = self.evaluate(x) + y = sess.run(x) + z = sess.run(x) + w = sess.run(x) # We use exact equality here. If the random-number generator is producing # the same output, all three outputs will be bitwise identical. @@ -69,7 +69,7 @@ class RandomNormalTest(RandomOpTestCommon): [num], mean=mu, stddev=sigma, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = self.evaluate(rng) + ret[i, :] = sess.run(rng) return ret return func @@ -160,7 +160,7 @@ class TruncatedNormalTest(test.TestCase): [num], mean=mu, stddev=sigma, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = self.evaluate(rng) + ret[i, :] = sess.run(rng) return ret return func @@ -256,7 +256,7 @@ class RandomUniformTest(RandomOpTestCommon): [num], minval=minv, maxval=maxv, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = self.evaluate(rng) + ret[i, :] = sess.run(rng) return ret return func diff --git a/tensorflow/python/kernel_tests/random/random_poisson_test.py b/tensorflow/python/kernel_tests/random/random_poisson_test.py index 47c0858db7..95e48101f6 100644 --- a/tensorflow/python/kernel_tests/random/random_poisson_test.py +++ b/tensorflow/python/kernel_tests/random/random_poisson_test.py @@ -43,7 +43,7 @@ class RandomPoissonTest(test.TestCase): rng = random_ops.random_poisson(lam, [num], dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = self.evaluate(rng) + ret[i, :] = sess.run(rng) return ret return func diff --git a/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py b/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py index 5601b9864b..f3fcf1eff7 100644 --- a/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py +++ b/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py @@ -84,7 +84,7 @@ class RandomShuffleQueueTest(test.TestCase): dequeue_t = q.dequeue() results = [] for _ in range(2): - a, b = self.evaluate(dequeue_t) + a, b = sess.run(dequeue_t) results.append((a, b)) a, b = sess.run(q.dequeue_many(3)) for i in range(3): @@ -101,7 +101,7 @@ class RandomShuffleQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - self.evaluate(enqueue_op) + sess.run(enqueue_op) threads = [ self.checkedThread( @@ -167,7 +167,7 @@ class RandomShuffleQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) for enqueue_op in enqueue_ops: - self.evaluate(enqueue_op) + sess.run(enqueue_op) results = [] @@ -197,7 +197,7 @@ class RandomShuffleQueueTest(test.TestCase): results = [] for _ in xrange(len(elems)): - x, y = self.evaluate(dequeued_t) + x, y = sess.run(dequeued_t) results.append((x, y)) self.assertItemsEqual(elems, results) @@ -321,7 +321,7 @@ class RandomShuffleQueueTest(test.TestCase): results = [] for _ in range(8): - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) results.append((float_val, [int_val[0], int_val[1]])) expected = list(zip(float_elems, int_elems)) * 2 self.assertItemsEqual(expected, results) @@ -368,20 +368,20 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() results = [] - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) self.assertEqual(float_val.shape, dequeued_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_t[1].get_shape()) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_single_t[1].get_shape()) results.append((float_val, int_val.tolist())) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) results.append((float_val, int_val.tolist())) self.assertItemsEqual(zip(float_elems, int_elems), results) @@ -402,21 +402,21 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() results = [] - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) # dequeue_up_to has undefined shape. self.assertEqual([None], dequeued_t[0].get_shape().as_list()) self.assertEqual([None, 2], dequeued_t[1].get_shape().as_list()) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = self.evaluate(dequeued_t) + float_val, int_val = sess.run(dequeued_t) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_single_t[1].get_shape()) results.append((float_val, int_val.tolist())) - float_val, int_val = self.evaluate(dequeued_single_t) + float_val, int_val = sess.run(dequeued_single_t) results.append((float_val, int_val.tolist())) self.assertItemsEqual(zip(float_elems, int_elems), results) @@ -442,7 +442,7 @@ class RandomShuffleQueueTest(test.TestCase): # Enqueue 100 items in parallel on 10 threads. def enqueue(): - self.evaluate(enqueue_op) + sess.run(enqueue_op) threads = [self.checkedThread(target=enqueue) for _ in range(10)] for thread in threads: @@ -515,7 +515,7 @@ class RandomShuffleQueueTest(test.TestCase): dequeued_elems = [] def dequeue(dequeue_op): - dequeued_elems.extend(self.evaluate(dequeue_op)) + dequeued_elems.extend(sess.run(dequeue_op)) threads = [] for dequeue_op in dequeue_ops: @@ -539,7 +539,7 @@ class RandomShuffleQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): dequeued_elems.extend(sess.run(dequeued_t).tolist()) @@ -566,7 +566,7 @@ class RandomShuffleQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - self.evaluate(enqueue_op) + sess.run(enqueue_op) def dequeue(): dequeued_elems.extend(sess.run(dequeued_t).tolist()) @@ -727,7 +727,7 @@ class RandomShuffleQueueTest(test.TestCase): progress = [] # Must be mutable def dequeue(): - self.assertItemsEqual(elems, self.evaluate(dequeued_t)) + self.assertItemsEqual(elems, sess.run(dequeued_t)) progress.append(1) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, @@ -922,7 +922,7 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -950,7 +950,7 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -987,11 +987,11 @@ class RandomShuffleQueueTest(test.TestCase): def blocking_enqueue(): # Expect the operation to succeed since it will complete # before the queue is closed. - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.CancelledError, "closed"): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread1 = self.checkedThread(target=blocking_enqueue) thread1.start() @@ -1001,7 +1001,7 @@ class RandomShuffleQueueTest(test.TestCase): time.sleep(0.1) def blocking_close(): - self.evaluate(close_op) + sess.run(close_op) thread2 = self.checkedThread(target=blocking_close) thread2.start() @@ -1032,7 +1032,7 @@ class RandomShuffleQueueTest(test.TestCase): def blocking_enqueue(): # This will block until the dequeue after the close. - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) thread1 = self.checkedThread(target=blocking_enqueue) thread1.start() @@ -1050,7 +1050,7 @@ class RandomShuffleQueueTest(test.TestCase): time.sleep(0.1) def blocking_close(): - self.evaluate(close_op) + sess.run(close_op) thread2 = self.checkedThread(target=blocking_close) thread2.start() @@ -1064,7 +1064,7 @@ class RandomShuffleQueueTest(test.TestCase): # At this point the close operation will complete, so the next enqueue # will fail. with self.assertRaisesRegexp(errors_impl.CancelledError, "closed"): - self.evaluate(blocking_enqueue_op) + sess.run(blocking_enqueue_op) def testSharedQueueSameSession(self): with self.cached_session(): @@ -1216,23 +1216,23 @@ class RandomShuffleQueueTest(test.TestCase): def _blockingDequeue(self, sess, dequeue_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_op) + sess.run(dequeue_op) def _blockingDequeueMany(self, sess, dequeue_many_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_many_op) + sess.run(dequeue_many_op) def _blockingDequeueUpTo(self, sess, dequeue_up_to_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(dequeue_up_to_op) + sess.run(dequeue_up_to_op) def _blockingEnqueue(self, sess, enqueue_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(enqueue_op) + sess.run(enqueue_op) def _blockingEnqueueMany(self, sess, enqueue_many_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(enqueue_many_op) + sess.run(enqueue_many_op) def testResetOfBlockingOperation(self): with self.cached_session() as sess: @@ -1393,14 +1393,14 @@ class RandomShuffleQueueTest(test.TestCase): results = [] results.append(deq.eval()) # Will only complete after the enqueue starts. self.assertEqual(len(enq_done), 1) - self.assertEqual(self.evaluate(size_op), 5) + self.assertEqual(sess.run(size_op), 5) for _ in range(3): results.append(deq.eval()) time.sleep(0.1) self.assertEqual(len(enq_done), 1) - self.assertEqual(self.evaluate(size_op), 5) + self.assertEqual(sess.run(size_op), 5) # This dequeue will unblock the thread. results.append(deq.eval()) diff --git a/tensorflow/python/kernel_tests/reader_ops_test.py b/tensorflow/python/kernel_tests/reader_ops_test.py index 4d9b26f4eb..18a8a3d547 100644 --- a/tensorflow/python/kernel_tests/reader_ops_test.py +++ b/tensorflow/python/kernel_tests/reader_ops_test.py @@ -724,7 +724,7 @@ class AsyncReaderTest(test.TestCase): thread_data.append(thread_data_t(t, queue, output)) # Start all readers. They are all blocked waiting for queue entries. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for d in thread_data: d.thread.start() diff --git a/tensorflow/python/kernel_tests/record_input_test.py b/tensorflow/python/kernel_tests/record_input_test.py index 74020667d9..ebb9872f22 100644 --- a/tensorflow/python/kernel_tests/record_input_test.py +++ b/tensorflow/python/kernel_tests/record_input_test.py @@ -54,7 +54,7 @@ class RecordInputOpTest(test.TestCase): batch_size=1, name="record_input").get_yield_op() - self.assertEqual(self.evaluate(yield_op), b"0000000000") + self.assertEqual(sess.run(yield_op), b"0000000000") def testRecordInputSimpleGzip(self): with self.cached_session() as sess: @@ -73,7 +73,7 @@ class RecordInputOpTest(test.TestCase): compression_type=tf_record.TFRecordCompressionType.GZIP).get_yield_op( ) - self.assertEqual(self.evaluate(yield_op), b"0000000000") + self.assertEqual(sess.run(yield_op), b"0000000000") def testRecordInputSimpleZlib(self): with self.cached_session() as sess: @@ -92,7 +92,7 @@ class RecordInputOpTest(test.TestCase): compression_type=tf_record.TFRecordCompressionType.ZLIB).get_yield_op( ) - self.assertEqual(self.evaluate(yield_op), b"0000000000") + self.assertEqual(sess.run(yield_op), b"0000000000") def testRecordInputEpochs(self): files = 100 @@ -117,7 +117,7 @@ class RecordInputOpTest(test.TestCase): for _ in range(3): epoch_set = set() for _ in range(int(files * records_per_file / batches)): - op_list = self.evaluate(yield_op) + op_list = sess.run(yield_op) self.assertTrue(len(op_list) is batches) for r in op_list: self.assertTrue(r[0] not in epoch_set) @@ -138,15 +138,15 @@ class RecordInputOpTest(test.TestCase): yield_op = records.get_yield_op() for _ in range(50): - self.evaluate(yield_op) + sess.run(yield_op) def testEmptyGlob(self): with self.cached_session() as sess: record_input = data_flow_ops.RecordInput(file_pattern="foo") yield_op = record_input.get_yield_op() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) with self.assertRaises(NotFoundError): - self.evaluate(yield_op) + sess.run(yield_op) def testBufferTooSmall(self): files = 10 @@ -171,7 +171,7 @@ class RecordInputOpTest(test.TestCase): for _ in range(3): epoch_set = set() for _ in range(int(files * records_per_file / batches)): - op_list = self.evaluate(yield_op) + op_list = sess.run(yield_op) self.assertTrue(len(op_list) is batches) for r in op_list: self.assertTrue(r[0] not in epoch_set) diff --git a/tensorflow/python/kernel_tests/reduction_ops_test.py b/tensorflow/python/kernel_tests/reduction_ops_test.py index 612b2c56a5..d1a295f42b 100644 --- a/tensorflow/python/kernel_tests/reduction_ops_test.py +++ b/tensorflow/python/kernel_tests/reduction_ops_test.py @@ -185,7 +185,7 @@ class SumReductionTest(BaseReductionTest): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_sum([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -216,7 +216,7 @@ class SumReductionTest(BaseReductionTest): tf_arr = variables.Variable(arr) variables.global_variables_initializer().run() tf_mean = math_ops.reduce_mean(tf_arr, 0, False) - tf_out_mean = self.evaluate(tf_mean) + tf_out_mean = sess.run(tf_mean) self.assertAllClose(tf_out_mean, 1.) def testFloat32(self): @@ -400,7 +400,7 @@ class MeanReductionTest(BaseReductionTest): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_mean([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -473,7 +473,7 @@ class ProdReductionTest(BaseReductionTest): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_prod([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -576,7 +576,7 @@ class MinReductionTest(test.TestCase): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_min([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -689,7 +689,7 @@ class MaxReductionTest(test.TestCase): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_max([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -817,7 +817,7 @@ class AllReductionTest(test.TestCase): with self.session(use_gpu=True) as sess: v = math_ops.reduce_all([True, True], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, True) def testAll3D(self): @@ -866,7 +866,7 @@ class AnyReductionTest(test.TestCase): with self.session(use_gpu=True) as sess: v = math_ops.reduce_any([True, True], constant_op.constant(0, dtype=dtype)) - tf_v = self.evaluate(v) + tf_v = sess.run(v) self.assertAllEqual(tf_v, True) def testAll3D(self): @@ -962,7 +962,7 @@ class CountNonzeroReductionTest(test.TestCase): # Test case for GitHub issue 18712 with self.cached_session() as sess: v = math_ops.count_nonzero(constant_op.constant(["test"])) - self.assertAllClose(self.evaluate(v), 1) + self.assertAllClose(sess.run(v), 1) def testStringReduce1D(self): # Create a 1D array of strings diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index c351a18c8f..e85b04469b 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -153,7 +153,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): def testCachedValueReadBeforeWrite(self): with self.cached_session() as sess: v = resource_variable_ops.ResourceVariable(0.0, caching_device="cpu:0") - self.evaluate(v.initializer) + sess.run(v.initializer) value, _ = sess.run([v, v.assign_add(1.0)]) self.assertAllEqual(value, 0.0) diff --git a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py index 1f1249727c..952ef34456 100644 --- a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py +++ b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py @@ -162,7 +162,7 @@ class StatefulScatterNdTest(test.TestCase): with self.session(use_gpu=True) as sess: sess.run(init) - result = self.evaluate(scatter) + result = sess.run(scatter) self.assertAllClose(result, expected) def testSimpleResource(self): @@ -190,7 +190,7 @@ class StatefulScatterNdTest(test.TestCase): with self.session(use_gpu=True) as sess: sess.run(init) - result = self.evaluate(scatter) + result = sess.run(scatter) self.assertAllClose(result, expected) def testSimple3(self): @@ -204,7 +204,7 @@ class StatefulScatterNdTest(test.TestCase): with self.session(use_gpu=True) as sess: sess.run(init) - result = self.evaluate(scatter) + result = sess.run(scatter) self.assertAllClose(result, expected) def testVariableRankUpdate(self): @@ -342,7 +342,7 @@ class StatefulScatterNdTest(test.TestCase): with session.Session() as sess: sess.run(init) - result = self.evaluate(scatter) + result = sess.run(scatter) assert np.allclose(result, expected_result) # TODO(fpmc): Re-enable this test when gpu_pip test actually runs on a GPU. @@ -421,7 +421,7 @@ class ScatterNdTest(test.TestCase): b"", b"", b"seven"]) scatter = self.scatter_nd(indices, updates, shape=(8,)) with self.cached_session() as sess: - result = self.evaluate(scatter) + result = sess.run(scatter) self.assertAllEqual(expected, result) # Same indice is updated twice by same value. @@ -432,7 +432,7 @@ class ScatterNdTest(test.TestCase): expected = np.array([b"", b"", b"", b"bb", b"a", b"", b"", b"c"]) scatter = self.scatter_nd(indices, updates, shape=(8,)) with self.cached_session() as sess: - result = self.evaluate(scatter) + result = sess.run(scatter) self.assertAllEqual(expected, result) # Same indice is updated twice by different value. @@ -444,7 +444,7 @@ class ScatterNdTest(test.TestCase): np.array([b"", b"", b"", b"cb", b"a", b"", b"", b"d"])] scatter = self.scatter_nd(indices, updates, shape=(8,)) with self.cached_session() as sess: - result = self.evaluate(scatter) + result = sess.run(scatter) self.assertTrue(np.array_equal(result, expected[0]) or np.array_equal(result, expected[1])) diff --git a/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py b/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py index 8ca8e9dddf..85756b769d 100644 --- a/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py +++ b/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py @@ -63,7 +63,7 @@ class SelfAdjointEigTest(test.TestCase): e1 = linalg_ops.self_adjoint_eigvals(matrix1) e2 = linalg_ops.self_adjoint_eigvals(matrix2) all_ops += [e1, e2] - val = self.evaluate(all_ops) + val = sess.run(all_ops) self.assertAllEqual(val[0], val[2]) # The algorithm is slightly different for compute_v being True and False, # so require approximate equality only here. diff --git a/tensorflow/python/kernel_tests/session_ops_test.py b/tensorflow/python/kernel_tests/session_ops_test.py index 73d85ddc07..03e1ae852f 100644 --- a/tensorflow/python/kernel_tests/session_ops_test.py +++ b/tensorflow/python/kernel_tests/session_ops_test.py @@ -37,7 +37,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = self.evaluate(h) + h = sess.run(h) # Feed a tensor handle. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -51,7 +51,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = self.evaluate(h) + h = sess.run(h) # Get the tensor from its handle. self.assertEqual(50, h.eval()) @@ -94,7 +94,7 @@ class SessionOpsTest(test.TestCase): # Initialize a handle. a = constant_op.constant(0) h = session_ops.get_session_handle(a) - h = self.evaluate(h) + h = sess.run(h) # Do some computation. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -111,7 +111,7 @@ class SessionOpsTest(test.TestCase): # Initialize a handle. a = constant_op.constant(0) h = session_ops.get_session_handle(a) - h = self.evaluate(h) + h = sess.run(h) # Do some computation. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -133,7 +133,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = self.evaluate(h) + h = sess.run(h) # Feed a tensor handle. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -144,7 +144,7 @@ class SessionOpsTest(test.TestCase): with ops.device(test.gpu_device_name()): a = constant_op.constant(10) h = session_ops.get_session_handle(a) - h = self.evaluate(h) + h = sess.run(h) self.assertEqual(100, sess.run(y, feed_dict={f: h.handle})) def testHandleDelete(self): @@ -163,7 +163,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = self.evaluate(h) + h = sess.run(h) # Delete using a raw tensor handle. raw_h = h.get_raw_handle() @@ -219,8 +219,8 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(2.0) b_handle_op = session_ops.get_session_handle(b) - a_handle = self.evaluate(a_handle_op) - b_handle = self.evaluate(b_handle_op) + a_handle = sess.run(a_handle_op) + b_handle = sess.run(b_handle_op) a_p, a_t = session_ops.get_session_tensor(a_handle.handle, dtypes.float32) b_p, b_t = session_ops.get_session_tensor(b_handle.handle, dtypes.float32) @@ -288,10 +288,10 @@ class SessionOpsTest(test.TestCase): a = variables.Variable(12.0) inc_a = state_ops.assign_add(a, 2.0) b = math_ops.add(a, 5.0) - self.evaluate(a.initializer) + sess.run(a.initializer) h_a_read = sess.run(session_ops.get_session_handle(a.read_value())) - self.assertAllClose(12.0, self.evaluate(a)) + self.assertAllClose(12.0, sess.run(a)) self.assertAllClose(17.0, sess.run(b, feed_dict={a: h_a_read})) sess.run(inc_a) diff --git a/tensorflow/python/kernel_tests/sets_test.py b/tensorflow/python/kernel_tests/sets_test.py index e037f51e0f..8335e9c139 100644 --- a/tensorflow/python/kernel_tests/sets_test.py +++ b/tensorflow/python/kernel_tests/sets_test.py @@ -159,7 +159,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertEqual(None, op.get_shape().dims) self.assertEqual(dtypes.int32, op.dtype) with self.cached_session() as sess: - results = self.evaluate(ops) + results = sess.run(ops) self.assertAllEqual(results[0], results[1]) return results[0] diff --git a/tensorflow/python/kernel_tests/shape_ops_test.py b/tensorflow/python/kernel_tests/shape_ops_test.py index a0506fbfc5..3e0eae326b 100644 --- a/tensorflow/python/kernel_tests/shape_ops_test.py +++ b/tensorflow/python/kernel_tests/shape_ops_test.py @@ -73,8 +73,8 @@ class ShapeOpsTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: tf_ans = array_ops.shape_n([x, x, x]) tf_ans_64 = array_ops.shape_n([x, x, x], out_type=dtypes.int64) - result = self.evaluate(tf_ans) - result_64 = self.evaluate(tf_ans_64) + result = sess.run(tf_ans) + result_64 = sess.run(tf_ans_64) for i in range(3): self.assertAllEqual(np_ans, result[i]) self.assertAllEqual(np_ans, result_64[i]) diff --git a/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py b/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py index de3351e543..c4e5b6f674 100644 --- a/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py @@ -56,7 +56,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, 2) with self.session(use_gpu=True) as sess: - output = self.evaluate(reconstruction) + output = sess.run(reconstruction) expected_output = np.array([1, 1, 2, 2, 3, 2, 2, 1, 1]) @@ -99,7 +99,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, self.frame_hop) with self.session(use_gpu=True) as sess: - output = self.evaluate(reconstruction) + output = sess.run(reconstruction) string_output = [np.base_repr(x, self.bases[0]) for x in output] self.assertEqual(string_output, self.expected_string) @@ -109,7 +109,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, self.frame_hop) with self.session(use_gpu=True) as sess: - output = self.evaluate(reconstruction) + output = sess.run(reconstruction) accumulator = True for i in range(self.batch_size): @@ -125,7 +125,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, self.frame_hop) with self.session(use_gpu=True) as sess: - output = self.evaluate(reconstruction) + output = sess.run(reconstruction) string_output = [np.base_repr(int(x), self.bases[0]) for x in np.squeeze(output)] diff --git a/tensorflow/python/kernel_tests/sparse_add_op_test.py b/tensorflow/python/kernel_tests/sparse_add_op_test.py index 845950bca7..a746830afb 100644 --- a/tensorflow/python/kernel_tests/sparse_add_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_add_op_test.py @@ -91,7 +91,7 @@ class SparseAddTest(test.TestCase): sp_sum = sparse_ops.sparse_add(sp_a, sp_b) self.assertAllEqual((3, 3), sp_sum.get_shape()) - sum_out = self.evaluate(sp_sum) + sum_out = sess.run(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, [[0, 1], [1, 0], [2, 0], [2, 1]]) @@ -104,7 +104,7 @@ class SparseAddTest(test.TestCase): sp_b = self._SparseTensor_3x3(negate=True) sp_sum = sparse_ops.sparse_add(sp_a, sp_b, 0.1) - sum_out = self.evaluate(sp_sum) + sum_out = sess.run(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, np.empty([0, 2])) @@ -123,7 +123,7 @@ class SparseAddTest(test.TestCase): # two values should vanish: |.1| < .21, and |-.2| < .21 sp_sum = sparse_ops.sparse_add(sp_a, sp_b, thresh=0.21) - sum_out = self.evaluate(sp_sum) + sum_out = sess.run(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, [[0, 1], [2, 0]]) @@ -132,7 +132,7 @@ class SparseAddTest(test.TestCase): # only .1 vanishes sp_sum = sparse_ops.sparse_add(sp_a, sp_b, thresh=0.11) - sum_out = self.evaluate(sp_sum) + sum_out = sess.run(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, [[0, 1], [2, 0], [2, 1]]) diff --git a/tensorflow/python/kernel_tests/sparse_concat_op_test.py b/tensorflow/python/kernel_tests/sparse_concat_op_test.py index a3d136c8d5..402c5eb4ea 100644 --- a/tensorflow/python/kernel_tests/sparse_concat_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_concat_op_test.py @@ -147,7 +147,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [4]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = self.evaluate(sp_concat) + concat_out = sess.run(sp_concat) self.assertAllEqual(concat_out.indices, [[0, 2], [1, 0], [2, 0], [2, 2]]) @@ -169,7 +169,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [8]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = self.evaluate(sp_concat) + concat_out = sess.run(sp_concat) self.assertAllEqual(concat_out.indices, [[0, 2], [1, 0], [1, 4], [2, 0], [2, 2], [2, 3], @@ -195,7 +195,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [7]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = self.evaluate(sp_concat) + concat_out = sess.run(sp_concat) self.assertAllEqual( concat_out.indices, @@ -220,7 +220,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [10]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = self.evaluate(sp_concat) + concat_out = sess.run(sp_concat) self.assertAllEqual(concat_out.indices, [[0, 2], [1, 0], [1, 4], [1, 8], [2, 0], [2, 2], [2, 3], [2, 6], @@ -244,7 +244,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [8]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = self.evaluate(sp_concat) + concat_out = sess.run(sp_concat) self.assertAllEqual( concat_out.indices, @@ -302,8 +302,8 @@ class SparseConcatTest(test.TestCase): sp_concat_dim1 = sparse_ops.sparse_concat( concat_dim1, [sp_a, sp_b, sp_c, sp_d], expand_nonconcat_dim=True) - sp_concat_dim0_out = self.evaluate(sp_concat_dim0) - sp_concat_dim1_out = self.evaluate(sp_concat_dim1) + sp_concat_dim0_out = sess.run(sp_concat_dim0) + sp_concat_dim1_out = sess.run(sp_concat_dim1) self.assertAllEqual(sp_concat_dim0_out.indices, [[0, 2], [1, 0], [2, 0], [2, 2], [4, 1], [5, 0], diff --git a/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py b/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py index 267275e771..a824d5c826 100644 --- a/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py +++ b/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py @@ -189,7 +189,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = self.evaluate(takeg_t) + val = sess.run(takeg_t) self.assertAllEqual([0, 1, 2], val.indices) self.assertAllEqual([[0.5, 0.5], [0, 2], [3, 0]], val.values) self.assertAllEqual([-1, 2], val.dense_shape) @@ -209,7 +209,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = self.evaluate(takeg_t) + val = sess.run(takeg_t) self.assertAllEqual([0, 1, 2], val.indices) self.assertAllEqual([[1, 1], [0, 2], [3, 0]], val.values) self.assertAllEqual([-1, 2], val.dense_shape) @@ -235,7 +235,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = self.evaluate(takeg_t) + val = sess.run(takeg_t) self.assertAllEqual(val.indices, [0, 1, 2]) self.assertAllEqual(val.values, [[0.5, 0.5], [0, 2], [3, 0]]) self.assertAllEqual(val.dense_shape, [-1, 2]) @@ -252,7 +252,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = self.evaluate(takeg_t) + val = sess.run(takeg_t) self.assertAllEqual(val.indices, [0, 1, 2]) self.assertAllEqual(val.values, [[5, 5], [0, 20], [30, 0]]) self.assertAllEqual(val.dense_shape, [-1, 2]) @@ -269,7 +269,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): takeg_t = q.take_indexed_slices_grad(1) def apply_indexed_slices_grad(accum_op): - self.evaluate(accum_op) + sess.run(accum_op) threads = [ self.checkedThread( @@ -281,7 +281,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): for thread in threads: thread.join() - val = self.evaluate(takeg_t) + val = sess.run(takeg_t) expected_val = sum(elems) / len(elems) self._assertEqual_nparray( @@ -303,7 +303,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): takeg_t = q.take_indexed_slices_grad(1) def apply_indexed_slices_grad(accum_op): - self.evaluate(accum_op) + sess.run(accum_op) threads = [ self.checkedThread(target=apply_indexed_slices_grad, args=(o,)) @@ -315,7 +315,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): for thread in threads: thread.join() - val = self.evaluate(takeg_t) + val = sess.run(takeg_t) expected_val = 550.0 self._assertEqual_nparray( @@ -338,13 +338,13 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): def apply_indexed_slices_grad(): for accum_op in accum_ops: time.sleep(1.0) - self.evaluate(accum_op) + sess.run(accum_op) apply_indexed_slices_grad_thread = self.checkedThread( target=apply_indexed_slices_grad) def take_grad(): - t = self.evaluate(takeg_t) + t = sess.run(takeg_t) results.append(t) threads = [self.checkedThread(target=take_grad) for _ in range(10)] @@ -378,7 +378,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): def apply_indexed_slices_grad(): for accum_op in accum_ops: - self.evaluate(accum_op) + sess.run(accum_op) def take_grad(): results.append(sess.run(takeg_t)) @@ -394,7 +394,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): def _blocking_takeg(self, sess, takeg_op): with self.assertRaisesOpError("was cancelled"): - self.evaluate(takeg_op) + sess.run(takeg_op) def testAccumulatorCancel(self): with self.cached_session() as sess: diff --git a/tensorflow/python/kernel_tests/sparse_cross_op_test.py b/tensorflow/python/kernel_tests/sparse_cross_op_test.py index 8451b96c56..17e867439a 100644 --- a/tensorflow/python/kernel_tests/sparse_cross_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_cross_op_test.py @@ -43,7 +43,7 @@ class SparseCrossOpTest(test.TestCase): 'batch2-FC1-F2_X_batch2-FC2-F1', 'batch2-FC1-F2_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_dense(self): """Tests only dense inputs.""" @@ -63,7 +63,7 @@ class SparseCrossOpTest(test.TestCase): 'batch2-FC1-F2_X_batch2-FC2-F1', 'batch2-FC1-F2_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_integer_mixed_string_sparse(self): """Tests mixed type.""" @@ -77,7 +77,7 @@ class SparseCrossOpTest(test.TestCase): '55555_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_integer_mixed_string_dense(self): """Tests mixed dense inputs.""" @@ -95,7 +95,7 @@ class SparseCrossOpTest(test.TestCase): '999999_X_batch2-FC2-F1', '999999_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_sparse_cross_dense(self): """Tests sparse and dense inputs.""" @@ -112,7 +112,7 @@ class SparseCrossOpTest(test.TestCase): 'batch2-FC1-F2_X_batch2-FC2-F1', 'batch2-FC1-F2_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_integer_sparse_input(self): """Tests mixed type sparse and dense inputs.""" @@ -128,7 +128,7 @@ class SparseCrossOpTest(test.TestCase): '5555_X_batch2-FC2-F1', '5555_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_permutation_3x3x3(self): """Tests 3x3x3 permutation.""" @@ -170,7 +170,7 @@ class SparseCrossOpTest(test.TestCase): 'batch1-FC1-F3_X_batch1-FC2-F3_X_batch1-FC3-F3' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_permutation_3x1x2(self): """Tests 3x1x2 permutation.""" @@ -189,7 +189,7 @@ class SparseCrossOpTest(test.TestCase): 'batch1-FC1-F3_X_batch1-FC2-F1_X_batch1-FC3-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_large_batch(self): """Tests with large batch size to force multithreading.""" @@ -222,7 +222,7 @@ class SparseCrossOpTest(test.TestCase): expected_out = self._sparse_tensor(col_out) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_one_column_empty(self): """Tests when one column is empty. @@ -235,7 +235,7 @@ class SparseCrossOpTest(test.TestCase): self._sparse_tensor([['batch1-FC3-F1', 'batch1-FC3-F2']]) ]) with self.cached_session() as sess: - self._assert_sparse_tensor_empty(self.evaluate(op)) + self._assert_sparse_tensor_empty(sess.run(op)) def test_some_columns_empty(self): """Tests when more than one columns are empty. @@ -254,7 +254,7 @@ class SparseCrossOpTest(test.TestCase): 'batch1-FC1-F2_X_batch1-FC2-F1_X_batch1-FC3-F2' ]], 2) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_all_columns_empty(self): """Tests when all columns are empty. @@ -267,7 +267,7 @@ class SparseCrossOpTest(test.TestCase): self._sparse_tensor([]) ]) with self.cached_session() as sess: - self._assert_sparse_tensor_empty(self.evaluate(op)) + self._assert_sparse_tensor_empty(sess.run(op)) def test_hashed_zero_bucket_no_hash_key(self): op = sparse_ops.sparse_cross_hashed([ @@ -278,7 +278,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[1971693436396284976]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_hashed_zero_bucket(self): op = sparse_ops.sparse_cross_hashed( @@ -291,7 +291,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[4847552627144134031]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) # TODO(sibyl-Aix6ihai): Add benchmark to compare Hashed vs Non-hashed. def test_hashed_no_hash_key(self): @@ -305,7 +305,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[83]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_hashed_output(self): op = sparse_ops.sparse_cross_hashed( @@ -319,7 +319,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[31]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + self._assert_sparse_tensor_equals(expected_out, sess.run(op)) def test_hashed__has_no_collision(self): """Tests that fingerprint concatenation has no collisions.""" @@ -345,7 +345,7 @@ class SparseCrossOpTest(test.TestCase): ], num_buckets=1000) with self.cached_session() as sess: - out = self.evaluate(op) + out = sess.run(op) self.assertEqual(6, len(out.values)) self.assertAllEqual([[0, i] for i in range(6)], out.indices) self.assertTrue(all(x < 1000 and x >= 0 for x in out.values)) diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index ad253595d2..db3f6c44e2 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -154,7 +154,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sparse_tensor.SparseTensor.from_value(values_v)): sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat32(self): @@ -163,7 +163,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float32) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat64(self): @@ -172,7 +172,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float64) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt32AndFloat32NonCanonicalOrder(self): @@ -182,7 +182,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_merge( indices, values, vocab_size, already_sorted=True) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsNotSorted(output, vocab_size) def testInt64AndFloat32NonCanonicalOrder(self): @@ -192,7 +192,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_merge( indices, values, vocab_size, already_sorted=True) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsNotSorted(output, vocab_size) def testInt64AndFloat64NonCanonicalOrder(self): @@ -203,7 +203,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_merge( indices, values, vocab_size_tensor, already_sorted=True) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsNotSorted(output, vocab_size) def testShouldSetLastDimensionInDynamicShape(self): @@ -261,7 +261,7 @@ class SparseMergeHighDimTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float32) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat64(self): @@ -270,7 +270,7 @@ class SparseMergeHighDimTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float64) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat64Shape(self): @@ -279,7 +279,7 @@ class SparseMergeHighDimTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float64) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self._AssertResultsSorted(output, vocab_size) @@ -302,7 +302,7 @@ class SparseRetainTest(test_util.TensorFlowTestCase): to_retain = np.array([1, 0, 0, 1, 1, 0], dtype=np.bool) sp_output = sparse_ops.sparse_retain(sp_input, to_retain) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self.assertAllEqual(output.indices, [[0, 0], [1, 4], [3, 2]]) self.assertAllEqual(output.values, [0, 14, 32]) @@ -314,7 +314,7 @@ class SparseRetainTest(test_util.TensorFlowTestCase): to_retain = np.zeros((6,), dtype=np.bool) sp_output = sparse_ops.sparse_retain(sp_input, to_retain) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self.assertAllEqual(output.indices, np.array([]).reshape((0, 2))) self.assertAllEqual(output.values, []) @@ -365,7 +365,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): new_shape = np.array([3, 6, 7], dtype=np.int64) sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]]) @@ -378,7 +378,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): new_shape = np.array([3, 6, 7], dtype=np.int64) sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]]) @@ -404,7 +404,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): sp_input = self._SparseTensor_2x5x6() sp_output = sparse_ops.sparse_reset_shape(sp_input) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]]) @@ -416,7 +416,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): sp_input = self._SparseTensor_2x5x6_Empty() sp_output = sparse_ops.sparse_reset_shape(sp_input) - output = self.evaluate(sp_output) + output = sess.run(sp_output) self.assertAllEqual(output.indices.shape, [0, 3]) self.assertAllEqual(output.values.shape, [0]) @@ -591,8 +591,8 @@ class SparseAddTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_add(sp_input, sp_input) with self.session(use_gpu=False) as sess: - self.evaluate(variables.global_variables_initializer()) - output = self.evaluate(sp_output) + sess.run(variables.global_variables_initializer()) + output = sess.run(sp_output) self.assertAllEqual(output.values, [2]) diff --git a/tensorflow/python/kernel_tests/sparse_reorder_op_test.py b/tensorflow/python/kernel_tests/sparse_reorder_op_test.py index bbf2f39202..7b83ae5177 100644 --- a/tensorflow/python/kernel_tests/sparse_reorder_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_reorder_op_test.py @@ -60,7 +60,7 @@ class SparseReorderTest(test.TestCase): input_val = self._SparseTensorValue_5x6(np.arange(6)) sp_output = sparse_ops.sparse_reorder(input_val) - output_val = self.evaluate(sp_output) + output_val = sess.run(sp_output) self.assertAllEqual(output_val.indices, input_val.indices) self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) @@ -83,7 +83,7 @@ class SparseReorderTest(test.TestCase): input_val = self._SparseTensorValue_5x6(np.random.permutation(6)) sp_output = sparse_ops.sparse_reorder(input_val) - output_val = self.evaluate(sp_output) + output_val = sess.run(sp_output) self.assertAllEqual(output_val.indices, expected_output_val.indices) self.assertAllEqual(output_val.values, expected_output_val.values) self.assertAllEqual(output_val.dense_shape, diff --git a/tensorflow/python/kernel_tests/sparse_reshape_op_test.py b/tensorflow/python/kernel_tests/sparse_reshape_op_test.py index 918af27091..f7be397c33 100644 --- a/tensorflow/python/kernel_tests/sparse_reshape_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_reshape_op_test.py @@ -81,7 +81,7 @@ class SparseReshapeTest(test.TestCase): input_val = self._SparseTensorValue_5x6() sp_output = sparse_ops.sparse_reshape(input_val, [5, 6]) - output_val = self.evaluate(sp_output) + output_val = sess.run(sp_output) self.assertAllEqual(output_val.indices, input_val.indices) self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) @@ -151,7 +151,7 @@ class SparseReshapeTest(test.TestCase): input_val = self._SparseTensorValue_5x6() sp_output = sparse_ops.sparse_reshape(input_val, [2, 3, 5]) - output_val = self.evaluate(sp_output) + output_val = sess.run(sp_output) self.assertAllEqual(output_val.indices, np.array([[0, 0, 0], [0, 1, 1], [0, 1, 4], [0, 2, 0], [1, 1, 0], [1, 1, 1]])) diff --git a/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py b/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py index 39a9ab9b49..b24a086969 100644 --- a/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py @@ -73,7 +73,7 @@ class SerializeSparseTest(test.TestCase): serialized = serialize_fn(sp_input, out_type=out_type) sp_deserialized = deserialize_fn(serialized, dtype=dtypes.int32) - indices, values, shape = self.evaluate(sp_deserialized) + indices, values, shape = sess.run(sp_deserialized) self.assertAllEqual(indices, sp_input[0]) self.assertAllEqual(values, sp_input[1]) diff --git a/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py b/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py index e63ba8f697..e08464a701 100644 --- a/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py @@ -88,7 +88,7 @@ class SparseTensorsMapTest(test.TestCase): sp_out = take_many_sparse_from_tensors_map( sparse_map_op=handle0.op, sparse_handles=handles_concat) - combined_indices, combined_values, combined_shape = self.evaluate(sp_out) + combined_indices, combined_values, combined_shape = sess.run(sp_out) self.assertAllEqual(combined_indices[:6, 0], [0] * 6) # minibatch 0 self.assertAllEqual(combined_indices[:6, 1:], sp_input0[0]) @@ -114,8 +114,7 @@ class SparseTensorsMapTest(test.TestCase): sp_roundtrip = take_many_sparse_from_tensors_map( sparse_map_op=handle.op, sparse_handles=sparse_handles) - combined_indices, combined_values, combined_shape = self.evaluate( - sp_roundtrip) + combined_indices, combined_values, combined_shape = sess.run(sp_roundtrip) self.assertAllEqual(combined_indices[:6, 0], [0] * 6) # minibatch 0 self.assertAllEqual(combined_indices[:6, 1:], input0_val[0]) @@ -172,7 +171,7 @@ class SparseTensorsMapTest(test.TestCase): with self.session(use_gpu=False) as sess: input_val = self._SparseTensorValue_5x6(np.arange(6)) handle = add_sparse_to_tensors_map(input_val) - handle_value = self.evaluate(handle) + handle_value = sess.run(handle) bad_handle = handle_value + 10 sp_roundtrip = take_many_sparse_from_tensors_map( sparse_map_op=handle.op, sparse_handles=[handle_value, bad_handle]) @@ -213,8 +212,8 @@ class BenchmarkSparseTensorsMapVsSerialization(test.Benchmark): variables.global_variables_initializer().run() - st_roundtrip_values = self.evaluate(st_roundtrip) - st_deserialized_values = self.evaluate(st_deserialized) + st_roundtrip_values = sess.run(st_roundtrip) + st_deserialized_values = sess.run(st_deserialized) np.testing.assert_equal(st_roundtrip_values.values, st_deserialized_values.values) np.testing.assert_equal(st_roundtrip_values.indices, diff --git a/tensorflow/python/kernel_tests/stage_op_test.py b/tensorflow/python/kernel_tests/stage_op_test.py index b1e7ce5d62..b814843b86 100644 --- a/tensorflow/python/kernel_tests/stage_op_test.py +++ b/tensorflow/python/kernel_tests/stage_op_test.py @@ -152,11 +152,11 @@ class StageTest(test.TestCase): with self.session(use_gpu=True, graph=G) as sess: sess.run(stage, feed_dict={x: -1}) - self.assertEqual(self.evaluate(size), 1) + self.assertEqual(sess.run(size), 1) sess.run(stage, feed_dict={x: -1}) - self.assertEqual(self.evaluate(size), 2) + self.assertEqual(sess.run(size), 2) sess.run(clear) - self.assertEqual(self.evaluate(size), 0) + self.assertEqual(sess.run(size), 0) def testCapacity(self): capacity = 3 @@ -210,14 +210,14 @@ class StageTest(test.TestCase): capacity)) # Should have capacity elements in the staging area - self.assertTrue(self.evaluate(size) == capacity) + self.assertTrue(sess.run(size) == capacity) # Clear the staging area completely for i in range(n): - self.assertTrue(self.evaluate(ret) == [i]) + self.assertTrue(sess.run(ret) == [i]) # It should now be empty - self.assertTrue(self.evaluate(size) == 0) + self.assertTrue(sess.run(size) == 0) def testMemoryLimit(self): memory_limit = 512 * 1024 # 512K @@ -274,13 +274,13 @@ class StageTest(test.TestCase): capacity)) # Should have capacity elements in the staging area - self.assertTrue(self.evaluate(size) == capacity) + self.assertTrue(sess.run(size) == capacity) # Clear the staging area completely for i in range(n): - self.assertTrue(np.all(self.evaluate(ret)[0] == i)) + self.assertTrue(np.all(sess.run(ret)[0] == i)) - self.assertTrue(self.evaluate(size) == 0) + self.assertTrue(sess.run(size) == 0) if __name__ == '__main__': diff --git a/tensorflow/python/kernel_tests/string_length_op_test.py b/tensorflow/python/kernel_tests/string_length_op_test.py index 0c68f0cadd..57db7302b1 100644 --- a/tensorflow/python/kernel_tests/string_length_op_test.py +++ b/tensorflow/python/kernel_tests/string_length_op_test.py @@ -29,7 +29,7 @@ class StringLengthOpTest(test.TestCase): with self.cached_session() as sess: lengths = string_ops.string_length(strings) - values = self.evaluate(lengths) + values = sess.run(lengths) self.assertAllEqual(values, [[[1, 2], [3, 4], [5, 6]]]) def testUnit(self): diff --git a/tensorflow/python/kernel_tests/string_split_op_test.py b/tensorflow/python/kernel_tests/string_split_op_test.py index 92e13db0f7..b968e885ed 100644 --- a/tensorflow/python/kernel_tests/string_split_op_test.py +++ b/tensorflow/python/kernel_tests/string_split_op_test.py @@ -34,7 +34,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [0, 3], [1, 0]]) self.assertAllEqual(values, [b"pigs", b"on", b"the", b"wing", b"animals"]) self.assertAllEqual(shape, [2, 4]) @@ -44,7 +44,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, delimiter="") - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]) @@ -62,7 +62,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual( indices, [[1, 0], [2, 0], [3, 0], [5, 0], [6, 0], [7, 0], [8, 0]]) @@ -74,7 +74,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, delimiter=" .") - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual( indices, [[1, 0], [2, 0], [3, 0], [5, 0], [6, 0], [7, 0], [8, 0]]) @@ -92,13 +92,13 @@ class StringSplitOpTest(test.TestCase): ValueError, string_ops.string_split, strings, delimiter=["a"]) tokens = string_ops.string_split(strings, delimiter="|") - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0]]) self.assertAllEqual(values, [b"hello", b"world", b"hello world"]) self.assertAllEqual(shape, [2, 2]) tokens = string_ops.string_split(strings, delimiter="| ") - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertAllEqual(values, [b"hello", b"world", b"hello", b"world"]) self.assertAllEqual(shape, [2, 2]) @@ -145,7 +145,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, "#", skip_empty=False) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1], [2, 2]]) @@ -154,7 +154,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, "#") - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(values, [b"a", b"b", b"c"]) self.assertAllEqual(indices, [[0, 0], [1, 0], [2, 0]]) self.assertAllEqual(shape, [3, 1]) @@ -167,7 +167,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [0, 3], [1, 0]]) self.assertAllEqual(values, [b"pigs", b"on", b"the", b"wing", b"animals"]) self.assertAllEqual(shape, [2, 4]) @@ -182,7 +182,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, sep="<>") - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual( indices, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]]) @@ -200,7 +200,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, sep=',') - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]]) self.assertAllEqual(values, [b"1", b"2", b"3", @@ -217,7 +217,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]) self.assertAllEqual(values, [b"1", b"2", b"3", b"4", b"5", b"6"]) @@ -233,7 +233,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, sep=',', maxsplit=1) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertAllEqual(values, [b"1", b"2,3", b"4", b"5,,6,"]) @@ -249,7 +249,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, maxsplit=1) - indices, values, shape = self.evaluate(tokens) + indices, values, shape = sess.run(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertAllEqual(values, [b"1", b"2 3", b"4", b"5 6 "]) diff --git a/tensorflow/python/kernel_tests/string_strip_op_test.py b/tensorflow/python/kernel_tests/string_strip_op_test.py index edff3862ff..1e404b7146 100644 --- a/tensorflow/python/kernel_tests/string_strip_op_test.py +++ b/tensorflow/python/kernel_tests/string_strip_op_test.py @@ -30,7 +30,7 @@ class StringStripOpTest(test.TestCase): with self.cached_session() as sess: output = string_ops.string_strip(strings) - output = self.evaluate(output) + output = sess.run(output) self.assertAllEqual(output, [b"pigs on the wing", b"animals"]) def test_string_strip_2d(self): @@ -39,7 +39,7 @@ class StringStripOpTest(test.TestCase): with self.cached_session() as sess: output = string_ops.string_strip(strings) - output = self.evaluate(output) + output = sess.run(output) self.assertAllEqual(output, [[b"pigs on the wing", b"animals"], [b"hello", b"world"]]) @@ -48,7 +48,7 @@ class StringStripOpTest(test.TestCase): with self.cached_session() as sess: output = string_ops.string_strip(strings) - output = self.evaluate(output) + output = sess.run(output) self.assertAllEqual(output, [b"hello", b"", b"world", b""]) diff --git a/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py b/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py index 1547c55f8b..63ce77b9d5 100644 --- a/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py @@ -60,7 +60,7 @@ class SummaryV1AudioOpTest(test.TestCase): sample_rate = 8000 summ = summary.audio( "snd", const, max_outputs=3, sample_rate=sample_rate) - value = self.evaluate(summ) + value = sess.run(summ) self.assertEqual([], summ.get_shape()) audio_summ = self._AsSummary(value) diff --git a/tensorflow/python/kernel_tests/summary_v1_image_op_test.py b/tensorflow/python/kernel_tests/summary_v1_image_op_test.py index e1b24756f3..094606944f 100644 --- a/tensorflow/python/kernel_tests/summary_v1_image_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_image_op_test.py @@ -70,7 +70,7 @@ class SummaryV1ImageOpTest(test.TestCase): # Summarize summ = summary.image("img", const) - value = self.evaluate(summ) + value = sess.run(summ) self.assertEqual([], summ.get_shape()) image_summ = self._AsSummary(value) @@ -97,7 +97,7 @@ class SummaryV1ImageOpTest(test.TestCase): # Summarize summ = summary.image("img", tf_images) - value = self.evaluate(summ) + value = sess.run(summ) self.assertEqual([], summ.get_shape()) image_summ = self._AsSummary(value) diff --git a/tensorflow/python/kernel_tests/summary_v1_ops_test.py b/tensorflow/python/kernel_tests/summary_v1_ops_test.py index 1206cb7013..6c4e106b11 100644 --- a/tensorflow/python/kernel_tests/summary_v1_ops_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_ops_test.py @@ -42,7 +42,7 @@ class SummaryV1OpsTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant([10.0, 20.0]) summ = logging_ops.scalar_summary(["c1", "c2"], const, name="mysumm") - value = self.evaluate(summ) + value = sess.run(summ) self.assertEqual([], summ.get_shape()) self.assertProtoEquals(""" value { tag: "c1" simple_value: 10.0 } @@ -53,7 +53,7 @@ class SummaryV1OpsTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant([10.0, 20.0]) summ = logging_ops.scalar_summary(["c1", "c2"], const) - value = self.evaluate(summ) + value = sess.run(summ) self.assertEqual([], summ.get_shape()) self.assertProtoEquals(""" value { tag: "c1" simple_value: 10.0 } @@ -66,7 +66,7 @@ class SummaryV1OpsTest(test.TestCase): summ1 = summary.histogram("h", const) summ2 = logging_ops.scalar_summary("c", const) merge = summary.merge([summ1, summ2]) - value = self.evaluate(merge) + value = sess.run(merge) self.assertEqual([], merge.get_shape()) self.assertProtoEquals(""" value { diff --git a/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py b/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py index 71251f5602..34f771679a 100644 --- a/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py @@ -68,7 +68,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(10.0) summ = summary_lib.tensor_summary("foo", const) - result = self.evaluate(summ) + result = sess.run(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) @@ -79,7 +79,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(s) summ = summary_lib.tensor_summary("foo", const) - result = self.evaluate(summ) + result = sess.run(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) @@ -89,7 +89,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = array_ops.ones([5, 5, 5]) summ = summary_lib.tensor_summary("foo", const) - result = self.evaluate(summ) + result = sess.run(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) self._AssertNumpyEq(n, np.ones([5, 5, 5])) @@ -99,7 +99,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(strings) summ = summary_lib.tensor_summary("foo", const) - result = self.evaluate(summ) + result = sess.run(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) self._AssertNumpyEq(n, strings) @@ -109,7 +109,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(bools) summ = summary_lib.tensor_summary("foo", const) - result = self.evaluate(summ) + result = sess.run(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) @@ -119,7 +119,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: def get_description(summary_op): - summ_str = self.evaluate(summary_op) + summ_str = sess.run(summary_op) summ = summary_pb2.Summary() summ.ParseFromString(summ_str) return summ.value[0].metadata diff --git a/tensorflow/python/kernel_tests/svd_op_test.py b/tensorflow/python/kernel_tests/svd_op_test.py index 589172e4b7..32c97a7b19 100644 --- a/tensorflow/python/kernel_tests/svd_op_test.py +++ b/tensorflow/python/kernel_tests/svd_op_test.py @@ -68,7 +68,7 @@ class SvdOpTest(test.TestCase): s2 = linalg_ops.svd( matrix2, compute_uv=compute_uv_, full_matrices=full_matrices_) all_ops += [s1, s2] - val = self.evaluate(all_ops) + val = sess.run(all_ops) for i in range(2): s = 6 * i self.assertAllEqual(val[s], val[s + 3]) # s1 == s2 @@ -158,7 +158,7 @@ def _GetSvdOpTest(dtype_, shape_, use_static_shape_, compute_uv_, s_tf = linalg_ops.svd( x_tf, compute_uv=compute_uv_, full_matrices=full_matrices_) if use_static_shape_: - s_tf_val = self.evaluate(s_tf) + s_tf_val = sess.run(s_tf) else: s_tf_val = sess.run(s_tf, feed_dict={x_tf: x_np}) diff --git a/tensorflow/python/kernel_tests/template_test.py b/tensorflow/python/kernel_tests/template_test.py index a187fa115c..9dcdaa61ed 100644 --- a/tensorflow/python/kernel_tests/template_test.py +++ b/tensorflow/python/kernel_tests/template_test.py @@ -104,10 +104,10 @@ class TemplateTest(test.TestCase): train_op = optimizer.minimize(train_loss) with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) - initial_test_loss = self.evaluate(test_loss) - self.evaluate(train_op) - final_test_loss = self.evaluate(test_loss) + sess.run(variables.global_variables_initializer()) + initial_test_loss = sess.run(test_loss) + sess.run(train_op) + final_test_loss = sess.run(test_loss) # Parameters are tied, so the loss should have gone down when we trained it. self.assertLess(final_test_loss, initial_test_loss) diff --git a/tensorflow/python/kernel_tests/tensor_array_ops_test.py b/tensorflow/python/kernel_tests/tensor_array_ops_test.py index 4ee1c27a87..7e8db8947b 100644 --- a/tensorflow/python/kernel_tests/tensor_array_ops_test.py +++ b/tensorflow/python/kernel_tests/tensor_array_ops_test.py @@ -751,7 +751,7 @@ class TensorArrayTest(test.TestCase): [-0.5, 1.5], # read(0) gradient [20.0, 30.0, 40.0, 50.0] ]) # concat gradient - grad_vals = self.evaluate(grad_r) # 2 + 2 entries + grad_vals = sess.run(grad_r) # 2 + 2 entries self.assertAllClose([2.0 - 0.5 + 20.0, 3.0 + 1.5 + 30.0], grad_vals[0]) self.assertAllEqual([4.0 + 40.0, 5.0 + 50.0], grad_vals[1]) @@ -1286,7 +1286,7 @@ class TensorArrayTest(test.TestCase): r = w1.stack() self.assertAllEqual(np.array([1.0, 2.0, 3.0, 4.0]), self.evaluate(r)) grad = gradients_impl.gradients(ys=[r], xs=[x]) - self.assertAllEqual(np.array([1.0, 1.0, 1.0]), self.evaluate(grad)[0]) + self.assertAllEqual(np.array([1.0, 1.0, 1.0]), sess.run(grad)[0]) @test_util.disable_control_flow_v2("b/117943489") def testSkipEagerTensorArrayUnpackDynamic(self): @@ -1303,7 +1303,7 @@ class TensorArrayTest(test.TestCase): r = w1.concat() self.assertAllEqual(np.array([1.0, 2.0, 3.0, 4.0]), self.evaluate(r)) grad = gradients_impl.gradients(ys=[r], xs=[x]) - self.assertAllEqual(np.array([1.0, 1.0, 1.0]), self.evaluate(grad)[0]) + self.assertAllEqual(np.array([1.0, 1.0, 1.0]), sess.run(grad)[0]) def _testTensorArrayEvalEmpty(self): with self.cached_session(use_gpu=True): diff --git a/tensorflow/python/kernel_tests/unicode_transcode_op_test.py b/tensorflow/python/kernel_tests/unicode_transcode_op_test.py index d1c7b41c7b..4ad5ee4103 100644 --- a/tensorflow/python/kernel_tests/unicode_transcode_op_test.py +++ b/tensorflow/python/kernel_tests/unicode_transcode_op_test.py @@ -42,7 +42,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, strings) outputs = string_ops.unicode_transcode( @@ -52,7 +52,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, strings) outputs = string_ops.unicode_transcode( @@ -62,7 +62,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, strings) def test_transcode_utf16_to_utf8(self): @@ -77,7 +77,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, expected) def test_transcode_bad_utf8(self): @@ -90,7 +90,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=True) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b" ") outputs = string_ops.unicode_transcode( @@ -100,7 +100,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"\x00 ") def test_transcode_bad_utf8_with_some_good(self): @@ -113,7 +113,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"abc abcdefg") def test_transcode_bad_utf8_with_defaults(self): @@ -121,7 +121,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bad_string, input_encoding="UTF-8", output_encoding="UTF-8") - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"\x00\xef\xbf\xbd") def test_transcode_bad_utf8_with_space_replacement(self): @@ -130,7 +130,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): outputs = string_ops.unicode_transcode( bad_string, input_encoding="UTF-8", output_encoding="UTF-8", replacement_char=ord(" ")) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"\x00 ") def test_transcode_bad_utf8_with_strict_errors(self): @@ -165,7 +165,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): input_encoding="UTF-8", output_encoding="UTF-8", errors="ignore") - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"\x00") def test_transcode_bad_utf8_with_elision_including_control_chars(self): @@ -177,7 +177,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-8", errors="ignore", replace_control_characters=True) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"") def test_transcode_bad_utf8_termination_with_defaults(self): @@ -185,7 +185,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bad_string, input_encoding="UTF-8", output_encoding="UTF-8") - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"a\xef\xbf\xbd") # 0xFFFD def test_transcode_utf8_with_replacement_char(self): @@ -194,13 +194,13 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): outputs = string_ops.unicode_transcode( strings, input_encoding="UTF-8", output_encoding="UTF-8", errors="strict") - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, [b"a\xef\xbf\xbd"]) outputs = string_ops.unicode_transcode( strings, input_encoding="UTF-8", output_encoding="UTF-8", errors="replace", replacement_char=ord("?")) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, [b"a\xef\xbf\xbd"]) def test_transcode_utf8_to_utf16(self): @@ -214,7 +214,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-16-BE", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) print("values=", values) self.assertAllEqual(values, expected) @@ -230,7 +230,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-8", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, expected) def test_transcode_utf8_to_utf32(self): @@ -243,7 +243,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-32-BE", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, expected) # Documentation in ICU suggests that getNextUChar may produce a different @@ -258,7 +258,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-8", replacement_char=ord(" "), replace_control_characters=False) - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, strings) def test_transcode_utf8_with_bom(self): @@ -266,12 +266,12 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-8", output_encoding="UTF-8") - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"\xef\xbb\xbfabcdefg") # BOM preserved outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-8", output_encoding="UTF-16-BE") - values = self.evaluate(outputs) + values = sess.run(outputs) utf16expected = bom_string.decode("UTF-8").encode("UTF-16-BE") self.assertAllEqual(values, utf16expected) @@ -280,20 +280,20 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-16-BE", output_encoding="UTF-8") - values = self.evaluate(outputs) + values = sess.run(outputs) # BOM is preserved in output self.assertAllEqual(values, b"\xef\xbb\xbfa") outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-16-LE", output_encoding="UTF-8") - values = self.evaluate(outputs) + values = sess.run(outputs) # mangled BOM and value from (incorrect) LE encoding self.assertAllEqual(values, b"\xef\xbf\xbe\xe6\x84\x80") bom_string = b"\xff\xfe\x61\x00" # Little-endian BOM with 'a' encoded outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-16-LE", output_encoding="UTF-8") - values = self.evaluate(outputs) + values = sess.run(outputs) self.assertAllEqual(values, b"\xef\xbb\xbfa") @parameterized.parameters( diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index de086860ea..a8a66a412d 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -438,15 +438,15 @@ class VariableScopeTest(test.TestCase): sess.run(v0) # We should be able to initialize and run v1 without initializing # v0, even if the variable was created with a control dep on v0. - self.evaluate(v1.initializer) - self.assertEqual(1, self.evaluate(v1)) + sess.run(v1.initializer) + self.assertEqual(1, sess.run(v1)) # v0 should still be uninitialized. with self.assertRaisesRegexp(errors.OpError, "uninitialized"): sess.run(v0) with self.assertRaisesRegexp(errors.OpError, "uninitialized"): sess.run(add) # If we initialize v0 we should be able to run 'add'. - self.evaluate(v0.initializer) + sess.run(v0.initializer) sess.run(add) # TODO(mihaimaruseac): Not converted to use wrap_function because of @@ -490,10 +490,10 @@ class VariableScopeTest(test.TestCase): v2 = var_dict["v2"] # We should be able to initialize and run v1 and v2 without initializing # v0, even if the variable was created with a control dep on v0. - self.evaluate(v1.initializer) - self.assertEqual([1], self.evaluate(v1)) - self.evaluate(v2.initializer) - self.assertEqual([2], self.evaluate(v2)) + sess.run(v1.initializer) + self.assertEqual([1], sess.run(v1)) + sess.run(v2.initializer) + self.assertEqual([2], sess.run(v2)) # v0 should still be uninitialized. with self.assertRaisesRegexp(errors.OpError, "uninitialized"): sess.run(v0) @@ -501,7 +501,7 @@ class VariableScopeTest(test.TestCase): with self.assertRaisesRegexp(errors.OpError, "uninitialized"): sess.run(add) # If we initialize v0 we should be able to run 'add'. - self.evaluate(v0.initializer) + sess.run(v0.initializer) sess.run(add) # TODO(mihaimaruseac): Not converted to use wrap_function because of diff --git a/tensorflow/python/kernel_tests/while_v2_test.py b/tensorflow/python/kernel_tests/while_v2_test.py index 48b32f06aa..0634dfa2d8 100644 --- a/tensorflow/python/kernel_tests/while_v2_test.py +++ b/tensorflow/python/kernel_tests/while_v2_test.py @@ -48,8 +48,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v < 8., lambda v: v * v, [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(self.evaluate(ret), 16.) - self.assertSequenceEqual(self.evaluate(grad), [32.]) + self.assertEqual(sess.run(ret), 16.) + self.assertSequenceEqual(sess.run(grad), [32.]) def testMultipleLoopVarsBasic(self): x = constant_op.constant(5.) @@ -65,8 +65,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): # Note: This is simply d_ret[0]/d_x since d_ret[1]/d_x is 0. grad = gradients_impl.gradients(ret, [x]) # [2*x*y] with self.cached_session() as sess: - self.assertSequenceEqual(self.evaluate(ret), [45., 3.]) - self.assertSequenceEqual(self.evaluate(grad), [9.]) + self.assertSequenceEqual(sess.run(ret), [45., 3.]) + self.assertSequenceEqual(sess.run(grad), [9.]) def testMultipleLoopVars(self): x = constant_op.constant(5.) @@ -88,13 +88,13 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grady_1 = gradients_impl.gradients(ret[1], [y]) # [x + 1] grady_2 = gradients_impl.gradients(ret, [y]) # [2*x*y + x**2 + x + 1] with self.cached_session() as sess: - self.assertSequenceEqual(self.evaluate(ret), [120., 23.]) - self.assertSequenceEqual(self.evaluate(gradx_0), [39.]) - self.assertSequenceEqual(self.evaluate(gradx_1), [4.]) - self.assertSequenceEqual(self.evaluate(gradx_2), [43.]) - self.assertSequenceEqual(self.evaluate(grady_0), [55.]) - self.assertSequenceEqual(self.evaluate(grady_1), [6.]) - self.assertSequenceEqual(self.evaluate(grady_2), [61.]) + self.assertSequenceEqual(sess.run(ret), [120., 23.]) + self.assertSequenceEqual(sess.run(gradx_0), [39.]) + self.assertSequenceEqual(sess.run(gradx_1), [4.]) + self.assertSequenceEqual(sess.run(gradx_2), [43.]) + self.assertSequenceEqual(sess.run(grady_0), [55.]) + self.assertSequenceEqual(sess.run(grady_1), [6.]) + self.assertSequenceEqual(sess.run(grady_2), [61.]) def testMultipleWhileLoops(self): x = constant_op.constant(2.) @@ -103,8 +103,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret2, [x]) # 4x**3 grad_grad = gradients_impl.gradients(grad, [x]) # 12x**2 with self.cached_session() as sess: - self.assertSequenceEqual(self.evaluate(grad), [32.]) - self.assertSequenceEqual(self.evaluate(grad_grad), [48.]) + self.assertSequenceEqual(sess.run(grad), [32.]) + self.assertSequenceEqual(sess.run(grad_grad), [48.]) def testDoubleDerivative(self): x = constant_op.constant(2.) @@ -112,9 +112,9 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret, [x]) # 4x**3 grad_grad = gradients_impl.gradients(grad, [x]) # 12x**2 with self.cached_session() as sess: - self.assertEqual(self.evaluate(ret), 16.) - self.assertSequenceEqual(self.evaluate(grad), [32.]) - self.assertSequenceEqual(self.evaluate(grad_grad), [48.]) + self.assertEqual(sess.run(ret), 16.) + self.assertSequenceEqual(sess.run(grad), [32.]) + self.assertSequenceEqual(sess.run(grad_grad), [48.]) def testPruning(self): x = constant_op.constant(1) @@ -157,8 +157,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v + y < 9., lambda v: v * 3., [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(self.evaluate(ret), 18.) - self.assertSequenceEqual(self.evaluate(grad), [9.]) + self.assertEqual(sess.run(ret), 18.) + self.assertSequenceEqual(sess.run(grad), [9.]) def testCaptureExternalTensorInBody(self): x = constant_op.constant(2.) @@ -166,8 +166,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v < 8., lambda v: v * y, [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(self.evaluate(ret), 18.) - self.assertSequenceEqual(self.evaluate(grad), [9.]) + self.assertEqual(sess.run(ret), 18.) + self.assertSequenceEqual(sess.run(grad), [9.]) def testLoopWithTensorListPushBack(self): x = constant_op.constant(2.) @@ -188,7 +188,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret[0], x) with self.cached_session() as sess: self.assertEqual(sess.run(ret[0]), 16.) - self.assertSequenceEqual(self.evaluate(grad), [32.]) + self.assertSequenceEqual(sess.run(grad), [32.]) def testDuplicateAccumulator(self): x = constant_op.constant(2.) @@ -222,7 +222,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret[0], x) with self.cached_session() as sess: self.assertEqual(sess.run(ret[0]), 16.) - self.assertSequenceEqual(self.evaluate(grad), [32.]) + self.assertSequenceEqual(sess.run(grad), [32.]) @parameterized.named_parameters( ("UnknownShape", None), @@ -315,9 +315,9 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): y0 = constant_op.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], name="elems") # map_fn uses TensorArray internally. r = functional_ops.map_fn(lambda x: math_ops.multiply(x, param), y0) - self.assertAllClose([2.0, 4.0, 6.0, 8.0, 10.0, 12.0], self.evaluate(r)) + self.assertAllClose([2.0, 4.0, 6.0, 8.0, 10.0, 12.0], sess.run(r)) r = gradients_impl.gradients(r, param)[0] - self.assertAllClose(21.0, self.evaluate(r)) + self.assertAllClose(21.0, sess.run(r)) def testNestedWhile(self): # Compute sum of geometric progression: n^0 + n^1 + ... + n^m @@ -334,8 +334,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): result = while_loop_v2(lambda i, _: i >= 0, Body, [m, sum_of_powers])[1] grad = gradients_impl.gradients(result, [n]) with self.cached_session() as sess: - self.assertEqual(self.evaluate(result), 364.) - self.assertSequenceEqual(self.evaluate(grad), [547.]) + self.assertEqual(sess.run(result), 364.) + self.assertSequenceEqual(sess.run(grad), [547.]) def testIdentityNodeInBody(self): @@ -348,8 +348,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v < 8., Body, [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(self.evaluate(ret), 16.) - self.assertSequenceEqual(self.evaluate(grad), [32.]) + self.assertEqual(sess.run(ret), 16.) + self.assertSequenceEqual(sess.run(grad), [32.]) def testNestedWhileAndTensorArray(self): n = constant_op.constant(3.0) diff --git a/tensorflow/python/kernel_tests/xent_op_test.py b/tensorflow/python/kernel_tests/xent_op_test.py index bd3142132c..c3c7f867a1 100644 --- a/tensorflow/python/kernel_tests/xent_op_test.py +++ b/tensorflow/python/kernel_tests/xent_op_test.py @@ -65,7 +65,7 @@ class XentTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: loss = nn_ops.softmax_cross_entropy_with_logits( labels=np_labels, logits=np_features, dim=dim) - tf_loss = self.evaluate(loss) + tf_loss = sess.run(loss) print("np_loss:", np_loss) print("tf_loss:", tf_loss) self.assertAllCloseAccordingToType(np_loss, tf_loss) @@ -280,7 +280,7 @@ class XentTest(test.TestCase): with self.session(use_gpu=True) as sess: loss = nn_ops.softmax_cross_entropy_with_logits( labels=labels, logits=features) - tf_loss = self.evaluate(loss) + tf_loss = sess.run(loss) self.assertAllEqual(np_loss, tf_loss) diff --git a/tensorflow/python/layers/convolutional_test.py b/tensorflow/python/layers/convolutional_test.py index d3200fa5b5..257fa27156 100644 --- a/tensorflow/python/layers/convolutional_test.py +++ b/tensorflow/python/layers/convolutional_test.py @@ -276,8 +276,8 @@ class ConvTest(test.TestCase): # Check the names of weights in order. self.assertTrue('kernel' in weights[0].name) self.assertTrue('bias' in weights[1].name) - self.evaluate(variables.global_variables_initializer()) - weights = self.evaluate(weights) + sess.run(variables.global_variables_initializer()) + weights = sess.run(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 3, 32))) # Check that the bias still got initialized to zeros. @@ -663,8 +663,8 @@ class SeparableConv2DTest(test.TestCase): self.assertTrue('depthwise_kernel' in weights[0].name) self.assertTrue('pointwise_kernel' in weights[1].name) self.assertTrue('bias' in weights[2].name) - self.evaluate(variables.global_variables_initializer()) - weights = self.evaluate(weights) + sess.run(variables.global_variables_initializer()) + weights = sess.run(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 3, 1))) self.assertAllClose(weights[1], np.ones((1, 1, 3, 32))) @@ -902,8 +902,8 @@ class Conv2DTransposeTest(test.TestCase): # Check the names of weights in order. self.assertTrue('kernel' in weights[0].name) self.assertTrue('bias' in weights[1].name) - self.evaluate(variables.global_variables_initializer()) - weights = self.evaluate(weights) + sess.run(variables.global_variables_initializer()) + weights = sess.run(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 32, 3))) # Check that the bias still got initialized to zeros. @@ -1084,8 +1084,8 @@ class Conv3DTransposeTest(test.TestCase): # Check the names of weights in order. self.assertTrue('kernel' in weights[0].name) self.assertTrue('bias' in weights[1].name) - self.evaluate(variables.global_variables_initializer()) - weights = self.evaluate(weights) + sess.run(variables.global_variables_initializer()) + weights = sess.run(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 3, 4, 32))) # Check that the bias still got initialized to zeros. diff --git a/tensorflow/python/layers/core_test.py b/tensorflow/python/layers/core_test.py index a61639b2db..0343bfa8bd 100644 --- a/tensorflow/python/layers/core_test.py +++ b/tensorflow/python/layers/core_test.py @@ -443,7 +443,7 @@ class DropoutTest(test.TestCase): dp = core_layers.Dropout(rate, name='dropout') inputs = array_ops.ones((5, 5)) dropped = dp.apply(inputs, training=True) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_output = sess.run(dropped, feed_dict={rate: 0.5}) self.assertAlmostEqual(0., np_output.min()) np_output = sess.run(dropped, feed_dict={rate: 0.0}) diff --git a/tensorflow/python/layers/normalization_test.py b/tensorflow/python/layers/normalization_test.py index febc3587fe..ba2bf10cf3 100644 --- a/tensorflow/python/layers/normalization_test.py +++ b/tensorflow/python/layers/normalization_test.py @@ -78,7 +78,7 @@ class BNTest(test.TestCase): if restore: saver.restore(sess, checkpoint_path) else: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np.random.seed(0) for _ in range(2): image_val = np.random.rand(*shape).astype(dtype.as_numpy_dtype) @@ -321,7 +321,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 4, 1)) @@ -337,7 +337,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 2)) std = np.std(np_inputs, axis=(0, 2)) variance = np.square(std) @@ -363,7 +363,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 3)) np_beta = np.reshape(np_beta, (1, 1, 3)) @@ -377,7 +377,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 1)) std = np.std(np_inputs, axis=(0, 1)) variance = np.square(std) @@ -404,7 +404,7 @@ class BNTest(test.TestCase): with self.session(use_gpu=True) as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 4, 1, 1)) np_beta = np.reshape(np_beta, (1, 4, 1, 1)) @@ -418,7 +418,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 2, 3)) std = np.std(np_inputs, axis=(0, 2, 3)) variance = np.square(std) @@ -444,7 +444,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 3, 1)) np_beta = np.reshape(np_beta, (1, 1, 3, 1)) @@ -458,7 +458,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 1, 3)) std = np.std(np_inputs, axis=(0, 1, 3)) variance = np.square(std) @@ -484,7 +484,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) @@ -498,7 +498,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -524,7 +524,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) @@ -538,7 +538,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -565,7 +565,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 4, 1, 1)) np_beta = np.reshape(np_beta, (1, 4, 1, 1)) @@ -579,7 +579,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 2, 3)) std = np.std(np_inputs, axis=(0, 2, 3)) variance = np.square(std) @@ -605,7 +605,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) @@ -620,7 +620,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -646,7 +646,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) @@ -659,7 +659,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -667,7 +667,7 @@ class BNTest(test.TestCase): self.assertAllClose(variance, moving_var, atol=1e-2) # Test inference with placeholder learning phase. - np_output = self.evaluate(outputs_infer) + np_output = sess.run(outputs_infer) # Verify that the axis is normalized during inference. normed_np_output = ((np_output - epsilon) * np_gamma) + np_beta @@ -696,7 +696,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([gamma, beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) @@ -710,7 +710,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. np_moving_mean, np_moving_var = sess.run([moving_mean, moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) np_mean = np.mean(np_inputs, axis=(0, 1, 2)) np_std = np.std(np_inputs, axis=(0, 1, 2)) np_variance = np.square(np_std) @@ -758,14 +758,14 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(100): np_output, _, _ = sess.run([outputs2] + updates, feed_dict={training: True}) # Verify that the statistics are updated during training. np_moving_mean, np_moving_var = sess.run([moving_mean, moving_variance]) - np_inputs = self.evaluate(inputs2) + np_inputs = sess.run(inputs2) np_mean = np.mean(np_inputs, axis=(0, 1, 2)) np_std = np.std(np_inputs, axis=(0, 1, 2)) np_variance = np.square(np_std) @@ -885,7 +885,7 @@ class BNTest(test.TestCase): renorm_mean = renorm_stddev = 0. renorm_weight = 0. with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -937,7 +937,7 @@ class BNTest(test.TestCase): moving_mean = 0. moving_variance = 1. with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) yt_val_train, adj_scale_val, adj_bias_val = sess.run( @@ -990,7 +990,7 @@ class BNTest(test.TestCase): renorm_mean = renorm_stddev = 0. renorm_weight = 0. with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) yt_val_train, adj_scale_val, adj_bias_val = sess.run( @@ -1040,7 +1040,7 @@ class BNTest(test.TestCase): out1.shape.as_list(), out2.shape.as_list()) with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) x = np.random.random(shape) y1, y2 = sess.run([out1, out2], feed_dict={inp: x}) @@ -1062,7 +1062,7 @@ class BNTest(test.TestCase): inp, virtual_batch_size=2) with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) x = np.random.random(np_shape) y = sess.run(out, feed_dict={inp: x}) @@ -1093,7 +1093,7 @@ class BNTest(test.TestCase): shape[1]]) with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -1146,7 +1146,7 @@ class BNTest(test.TestCase): shape[1:]) with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -1200,7 +1200,7 @@ class BNTest(test.TestCase): shape[1:]) with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -1256,7 +1256,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) @@ -1270,7 +1270,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=0, keepdims=True) std = np.std(np_inputs, axis=0, keepdims=True) variance = np.square(std) @@ -1296,7 +1296,7 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) @@ -1310,7 +1310,7 @@ class BNTest(test.TestCase): # Verify that the statistics are updated during training. moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = self.evaluate(inputs) + np_inputs = sess.run(inputs) mean = np.mean(np_inputs, axis=(0, 4), keepdims=True) std = np.std(np_inputs, axis=(0, 4), keepdims=True) variance = np.square(std) @@ -1350,7 +1350,7 @@ class BNTest(test.TestCase): shape[1:]) with self.session(use_gpu=True) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) diff --git a/tensorflow/python/ops/control_flow_ops_test.py b/tensorflow/python/ops/control_flow_ops_test.py index 260af95a3b..47675d3f34 100644 --- a/tensorflow/python/ops/control_flow_ops_test.py +++ b/tensorflow/python/ops/control_flow_ops_test.py @@ -209,7 +209,7 @@ class SwitchTestCase(test_util.TensorFlowTestCase): optimizer = momentum.MomentumOptimizer(0.1, 0.9) train_op = optimizer.minimize(cost) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(10): sess.run([train_op]) @@ -232,7 +232,7 @@ class SwitchTestCase(test_util.TensorFlowTestCase): cond, body, [constant_op.constant(0), constant_op.constant(0.0)]) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllEqual(10.0, self.evaluate(cost)) def doTestIndexedSlicesGradientInCondInWhileLoop(self, use_resource=False): @@ -269,7 +269,7 @@ class SwitchTestCase(test_util.TensorFlowTestCase): static_grads.indices) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllEqual(*sess.run([static_grads, dynamic_grads])) def testIndexedSlicesGradientInCondInWhileLoop(self): @@ -398,9 +398,9 @@ class CondTest(test_util.TensorFlowTestCase): pred=bool_var, true_fn=lambda: state_ops.assign(bool_var, False), false_fn=lambda: True) - self.evaluate(bool_var.initializer) - self.assertEquals(self.evaluate(cond_on_bool_var), False) - self.assertEquals(self.evaluate(cond_on_bool_var), True) + sess.run(bool_var.initializer) + self.assertEquals(sess.run(cond_on_bool_var), False) + self.assertEquals(sess.run(cond_on_bool_var), True) def testCondMissingArg1(self): with ops.Graph().as_default(): diff --git a/tensorflow/python/ops/gradients_test.py b/tensorflow/python/ops/gradients_test.py index a9058c4a34..262b62e013 100644 --- a/tensorflow/python/ops/gradients_test.py +++ b/tensorflow/python/ops/gradients_test.py @@ -365,7 +365,7 @@ class GradientsTest(test_util.TensorFlowTestCase): grads = gradients.gradients( [y], [x], unconnected_gradients="zero") with self.cached_session() as sess: - self.assertAllEqual([[0.0, 0.0], [0.0, 0.0]], self.evaluate(grads)[0]) + self.assertAllEqual([[0.0, 0.0], [0.0, 0.0]], sess.run(grads)[0]) def testUnconnectedGradientsZeroConnectedGradients(self): with ops.Graph().as_default(): @@ -374,7 +374,7 @@ class GradientsTest(test_util.TensorFlowTestCase): grad = gradients.gradients( [y], [x], unconnected_gradients="zero") with self.cached_session() as sess: - self.assertEquals(3.0, self.evaluate(grad)[0]) + self.assertEquals(3.0, sess.run(grad)[0]) def testUnknownUnconnectedGradientsValueGiven(self): with ops.Graph().as_default(): @@ -438,8 +438,8 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): grads = gradients.gradients(y, [x, b1]) with self.cached_session() as sess: - self.assertAllEqual([40.0], self.evaluate(grads)[0]) - self.assertAllEqual([10.0], self.evaluate(grads)[1]) + self.assertAllEqual([40.0], sess.run(grads)[0]) + self.assertAllEqual([10.0], sess.run(grads)[1]) def testFunctionGradientsWithGradFunc(self): g = ops.Graph() @@ -487,7 +487,7 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): f = Foo() with self.cached_session() as sess: - self.assertEqual(self.evaluate(f), 2.0) + self.assertEqual(sess.run(f), 2.0) def testGradientOfCaptured(self): with ops.Graph().as_default(): @@ -501,7 +501,7 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): f = Foo() with self.cached_session() as sess: - self.assertEqual(self.evaluate(f), 2.0) + self.assertEqual(sess.run(f), 2.0) def testCapturedResourceVariable(self): with ops.Graph().as_default(): @@ -515,8 +515,8 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): f = Foo() with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) - self.assertEqual(self.evaluate(f), 2.0) + sess.run(variables.global_variables_initializer()) + self.assertEqual(sess.run(f), 2.0) def testCapturedNested(self): with ops.Graph().as_default(): @@ -541,9 +541,9 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): x1_grad, x2_grad = Outer() with self.cached_session() as sess: # 1.0 + None + 2.0 + 1.0 = 4.0 - self.assertEqual(self.evaluate(x1_grad), 4.0) + self.assertEqual(sess.run(x1_grad), 4.0) # None + 1.0 + 1.0 + None = 2.0 - self.assertEqual(self.evaluate(x2_grad), 2.0) + self.assertEqual(sess.run(x2_grad), 2.0) def testCapturedFromFunction(self): with ops.Graph().as_default(): @@ -563,7 +563,7 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): z_grad = Outer() with self.cached_session() as sess: - self.assertEqual(self.evaluate(z_grad), 3.0) + self.assertEqual(sess.run(z_grad), 3.0) def testCapturedEagerTensors(self): # Test that we can handle captured eager tensors unrelated to the gradient @@ -873,7 +873,7 @@ class CustomGradientTest(test_util.TensorFlowTestCase): y = MyMultiply(x1, x2) dy = gradients.gradients(y, [x1, x2]) with session.Session() as sess: - self.assertAllEqual([3., 5.], self.evaluate(dy)) + self.assertAllEqual([3., 5.], sess.run(dy)) def testCustomGradientErrors(self): @@ -914,7 +914,7 @@ class CustomGradientTest(test_util.TensorFlowTestCase): for g in grads: self.assertTrue(g is not None) with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) dw = sess.run(math_ops.reduce_sum(grads[1])) self.assertEqual(12., dw) @@ -1074,7 +1074,7 @@ class TensorListGradientsTest(test_util.TensorFlowTestCase): grad = gradients.gradients(tl, a, grad_ys=grad_tl)[0] with self.cached_session() as sess: - self.assertEquals(self.evaluate(grad), 5.) + self.assertEquals(sess.run(grad), 5.) if __name__ == "__main__": diff --git a/tensorflow/python/ops/image_grad_test.py b/tensorflow/python/ops/image_grad_test.py index 0ea15b0d23..32c2f37c0b 100644 --- a/tensorflow/python/ops/image_grad_test.py +++ b/tensorflow/python/ops/image_grad_test.py @@ -44,7 +44,7 @@ class ResizeNearestNeighborOpTest(test.TestCase): out_shape[1:3]) self.assertEqual(out_shape, list(resize_out.get_shape())) - resize_out = self.evaluate(resize_out) + resize_out = sess.run(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) def testGradFromResizeToLargerInBothDims(self): @@ -113,7 +113,7 @@ class ResizeBilinearOpTest(test.TestCase): resize_out = image_ops.resize_bilinear(input_tensor, out_shape[1:3]) self.assertEqual(out_shape, list(resize_out.get_shape())) - resize_out = self.evaluate(resize_out) + resize_out = sess.run(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) def testGradFromResizeToLargerInBothDims(self): @@ -196,7 +196,7 @@ class ResizeBicubicOpTest(test.TestCase): align_corners=align_corners) self.assertEqual(out_shape, list(resize_out.get_shape())) - resize_out = self.evaluate(resize_out) + resize_out = sess.run(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) def testGradFromResizeToLargerInBothDims(self): @@ -273,7 +273,7 @@ class CropAndResizeOpTest(test.TestCase): constant_op.constant( crop_size, shape=[2])) self.assertEqual(crops_shape, list(crops.get_shape())) - crops = self.evaluate(crops) + crops = sess.run(crops) self.assertEqual(crops_shape, list(crops.shape)) def _randomUniformAvoidAnchors(self, low, high, anchors, radius, num_samples): diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index de82f4fc27..ac2d2698b6 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -488,11 +488,11 @@ class FlipImageBenchmark(test.Benchmark): trainable=False, dtype=dtypes.float32) run_op = image_ops.flip_left_right(inputs) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - self.evaluate(run_op) + sess.run(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -518,11 +518,11 @@ class FlipImageBenchmark(test.Benchmark): trainable=False, dtype=dtypes.float32) run_op = image_ops.random_flip_left_right(inputs) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - self.evaluate(run_op) + sess.run(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -548,11 +548,11 @@ class FlipImageBenchmark(test.Benchmark): trainable=False, dtype=dtypes.float32) run_op = image_ops.random_flip_left_right(inputs) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - self.evaluate(run_op) + sess.run(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -610,11 +610,11 @@ class AdjustHueBenchmark(test.Benchmark): delta = constant_op.constant(0.1, dtype=dtypes.float32) outputs = image_ops.adjust_hue(inputs, delta) run_op = control_flow_ops.group(outputs) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - self.evaluate(run_op) + sess.run(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -653,12 +653,12 @@ class AdjustSaturationBenchmark(test.Benchmark): delta = constant_op.constant(0.1, dtype=dtypes.float32) outputs = image_ops.adjust_saturation(inputs, delta) run_op = control_flow_ops.group(outputs) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in xrange(warmup_rounds): - self.evaluate(run_op) + sess.run(run_op) start = time.time() for _ in xrange(benchmark_rounds): - self.evaluate(run_op) + sess.run(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -698,7 +698,7 @@ class ResizeBilinearBenchmark(test.Benchmark): benchmark_op = control_flow_ops.group(*deps) with self.benchmark_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) results = self.run_op_benchmark( sess, benchmark_op, @@ -746,7 +746,7 @@ class ResizeBicubicBenchmark(test.Benchmark): benchmark_op = control_flow_ops.group(*deps) with self.benchmark_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) results = self.run_op_benchmark( sess, benchmark_op, @@ -803,7 +803,7 @@ class ResizeAreaBenchmark(test.Benchmark): benchmark_op = control_flow_ops.group(*deps) with self.benchmark_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) results = self.run_op_benchmark( sess, benchmark_op, @@ -4110,7 +4110,7 @@ class MultiscaleSSIMTest(test_util.TensorFlowTestCase): images = [ops.convert_to_tensor(x, dtype=dtypes.float32) for x in images] msssim_ops = [image_ops.ssim_multiscale(x, y, 1.0) for x, y in itertools.combinations(images, 2)] - msssim = self.evaluate(msssim_ops) + msssim = sess.run(msssim_ops) msssim = np.squeeze(msssim) self.assertTrue(np.all(msssim >= 0.0)) diff --git a/tensorflow/python/ops/init_ops_test.py b/tensorflow/python/ops/init_ops_test.py index 1f22248004..5693c3caaf 100644 --- a/tensorflow/python/ops/init_ops_test.py +++ b/tensorflow/python/ops/init_ops_test.py @@ -45,8 +45,8 @@ class InitializersTest(test.TestCase): output = variable.numpy() else: sess = ops.get_default_session() - self.evaluate(variable.initializer) - output = self.evaluate(variable) + sess.run(variable.initializer) + output = sess.run(variable) lim = 3e-2 if target_std is not None: self.assertGreater(lim, abs(output.std() - target_std)) diff --git a/tensorflow/python/ops/math_ops_test.py b/tensorflow/python/ops/math_ops_test.py index cd45b6f136..adcaa7abff 100644 --- a/tensorflow/python/ops/math_ops_test.py +++ b/tensorflow/python/ops/math_ops_test.py @@ -373,7 +373,7 @@ class AddNTest(test_util.TensorFlowTestCase): for i in range(0, num_inputs) ] addn = math_ops.add_n(input_vars) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) add_n_grad = gradients.gradients(addn, input_vars) self.assertAllEqual(np.repeat(1.0, num_inputs), # d/dx (x + y + ...) = 1 [g.eval() for g in add_n_grad]) @@ -461,7 +461,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): a = variables.Variable(2.) b = variables.Variable(4.) with self.cached_session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) c_grad = gradients.gradients(math_ops.divide(a, b), [a, b]) self.assertAllEqual([x.eval() for x in c_grad], [.25, -.125]) c_grad = gradients.gradients(math_ops.div(a, b), [a, b]) diff --git a/tensorflow/python/ops/nn_fused_batchnorm_test.py b/tensorflow/python/ops/nn_fused_batchnorm_test.py index 552b274b83..a6c582fcac 100644 --- a/tensorflow/python/ops/nn_fused_batchnorm_test.py +++ b/tensorflow/python/ops/nn_fused_batchnorm_test.py @@ -82,7 +82,7 @@ class BatchNormalizationTest(test.TestCase): epsilon=epsilon, data_format=data_format, is_training=False) - y_val = self.evaluate(y) + y_val = sess.run(y) y_ref = self._inference_ref(x, scale, offset, mean, var, epsilon, data_format) # An atol value of 1e-3 is too small for float16's, because some adjacent diff --git a/tensorflow/python/ops/parallel_for/gradients_test.py b/tensorflow/python/ops/parallel_for/gradients_test.py index 545c482df8..bbb46539ea 100644 --- a/tensorflow/python/ops/parallel_for/gradients_test.py +++ b/tensorflow/python/ops/parallel_for/gradients_test.py @@ -485,7 +485,7 @@ class GradientsTest(test.TestCase): with session.Session() as sess: init = variables.global_variables_initializer() sess.run(init) - pfor = self.evaluate(pfor_jacobian) + pfor = sess.run(pfor_jacobian) for i in range(4): while_i = sess.run(while_gradients[i]) self.assertAllClose(while_i, pfor[:, i, ...]) diff --git a/tensorflow/python/ops/quantized_conv_ops_test.py b/tensorflow/python/ops/quantized_conv_ops_test.py index 6b469a954f..f7fa264461 100644 --- a/tensorflow/python/ops/quantized_conv_ops_test.py +++ b/tensorflow/python/ops/quantized_conv_ops_test.py @@ -73,7 +73,7 @@ class Conv2DTest(test.TestCase): max_input=x1_max, min_filter=x2_min, max_filter=x2_max) - value = self.evaluate(conv) + value = sess.run(conv) quantized_output = value[0] output_min = value[1] output_max = value[2] diff --git a/tensorflow/python/ops/quantized_ops_test.py b/tensorflow/python/ops/quantized_ops_test.py index b81843d174..0f3b04e4ad 100644 --- a/tensorflow/python/ops/quantized_ops_test.py +++ b/tensorflow/python/ops/quantized_ops_test.py @@ -41,7 +41,7 @@ class QuantizedOpsTest(test.TestCase): x_min = 0.0 x_max = 255.0 op = array_ops.quantize(x, x_min, x_max, dtypes.quint8, mode="MIN_FIRST") - value = self.evaluate(op) + value = sess.run(op) self.assertArrayNear(expected_output, value.output, 0.1) def testDequantizeOp(self): @@ -52,7 +52,7 @@ class QuantizedOpsTest(test.TestCase): x_min = 0.0 x_max = 255.0 op = array_ops.dequantize(x, x_min, x_max, mode="MIN_FIRST") - value = self.evaluate(op) + value = sess.run(op) self.assertArrayNear(expected_output, value, 0.1) diff --git a/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py b/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py index c52db9e2a1..dcf1feaa69 100644 --- a/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py @@ -190,7 +190,7 @@ class RaggedGatherNdOpTest(test_util.TensorFlowTestCase, with self.test_session() as sess: if hasattr(expected, 'tolist'): expected = expected.tolist() - self.assertEqual(self.evaluate(result).tolist(), expected) + self.assertEqual(sess.run(result).tolist(), expected) def testRaggedGatherNdUnknownRankError(self): params = ragged.constant([['a', 'b'], ['c', 'd']]) diff --git a/tensorflow/python/profiler/model_analyzer_test.py b/tensorflow/python/profiler/model_analyzer_test.py index 8648f0b514..94c685274a 100644 --- a/tensorflow/python/profiler/model_analyzer_test.py +++ b/tensorflow/python/profiler/model_analyzer_test.py @@ -93,10 +93,10 @@ class PrintModelAnalysisTest(test.TestCase): config=self._no_rewrite_session_config()) as sess, ops.device(dev): x = lib.BuildSmallModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) pctx.trace_next_step() pctx.dump_next_step() - _ = self.evaluate(x) + _ = sess.run(x) pctx.profiler.profile_name_scope(options=opts) @@ -160,7 +160,7 @@ class PrintModelAnalysisTest(test.TestCase): ) as sess, ops.device('/device:CPU:0'): x = lib.BuildSmallModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -186,7 +186,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -220,9 +220,9 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) pctx.trace_next_step() - _ = self.evaluate(x) + _ = sess.run(x) tfprof_node = pctx.profiler.profile_python(options=opts) # pylint: disable=line-too-long @@ -281,7 +281,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -309,7 +309,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run( x, @@ -345,7 +345,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -391,7 +391,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run( x, @@ -424,7 +424,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run( x, @@ -490,7 +490,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -555,7 +555,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -587,10 +587,10 @@ class PrintModelAnalysisTest(test.TestCase): def _trainLoop(self, train_op, train_steps, time_dir, time_step, memory_dir, memory_step, profile_dir, dump_step): with session.Session(config=self._no_rewrite_session_config()) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # start from 1 because variable_initializer took one step. for i in range(1, train_steps + 1): - _ = self.evaluate(train_op) + _ = sess.run(train_op) if i in time_step: ret = gfile.ListDirectory(time_dir) self.assertEqual(len(ret), 1) diff --git a/tensorflow/python/profiler/profile_context_test.py b/tensorflow/python/profiler/profile_context_test.py index abbeb8bedf..107ad443c3 100644 --- a/tensorflow/python/profiler/profile_context_test.py +++ b/tensorflow/python/profiler/profile_context_test.py @@ -48,7 +48,7 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir()) as pctx: pctx.add_auto_profiling("op", options=opts, profile_steps=[15, 50, 100]) with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) total_steps = 101 for i in range(total_steps): sess.run(x) @@ -75,7 +75,7 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir(), debug=True): with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(10): sess.run(x) for f in gfile.ListDirectory(test.get_temp_dir()): @@ -96,7 +96,7 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir(), enabled=False) as pctx: with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(10): sess.run(x) self.assertTrue(pctx.profiler is None) @@ -105,7 +105,7 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir()) as pctx: with session.Session() as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for _ in range(10): sess.run(x) self.assertFalse(pctx.profiler is None) diff --git a/tensorflow/python/saved_model/loader_test.py b/tensorflow/python/saved_model/loader_test.py index 0b97a73441..648c1c5928 100644 --- a/tensorflow/python/saved_model/loader_test.py +++ b/tensorflow/python/saved_model/loader_test.py @@ -50,7 +50,7 @@ class SavedModelLoaderTest(test.TestCase): x = variables.VariableV1(5, name="x") y = variables.VariableV1(11, name="y") z = x + y - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) foo_sig_def = signature_def_utils.build_signature_def( {"foo_input": utils.build_tensor_info(x)}, @@ -138,7 +138,7 @@ class SavedModelLoaderTest(test.TestCase): y = variables.VariableV1(0, name="y") z = x * y - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # There are variables to restore, so a saver must be created. with self.assertRaises(ValueError): diff --git a/tensorflow/python/saved_model/saved_model_test.py b/tensorflow/python/saved_model/saved_model_test.py index e722b6ceae..a40ea7687f 100644 --- a/tensorflow/python/saved_model/saved_model_test.py +++ b/tensorflow/python/saved_model/saved_model_test.py @@ -61,7 +61,7 @@ class SavedModelTestBase(test.TestCase): def _init_and_validate_variable(self, sess, variable_name, variable_value): v = variables.VariableV1(variable_value, name=variable_name) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(variable_value, self.evaluate(v)) def _build_asset_collection(self, asset_file_name, asset_file_contents, @@ -389,7 +389,7 @@ class SavedModelTest(SavedModelTestBase): a = ops.get_default_graph().get_tensor_by_name(constant_5_name) b = constant_op.constant(6.0) c = a * b - self.assertEqual(30.0, self.evaluate(c)) + self.assertEqual(30.0, sess.run(c)) # Restore the graph with tag "bar". with self.session(graph=ops.Graph()) as sess: @@ -398,7 +398,7 @@ class SavedModelTest(SavedModelTestBase): a = ops.get_default_graph().get_tensor_by_name(constant_6_name) b = constant_op.constant(5.0) c = a * b - self.assertEqual(30.0, self.evaluate(c)) + self.assertEqual(30.0, sess.run(c)) def testNoOverwrite(self): export_dir = self._get_export_dir("test_no_overwrite") @@ -464,7 +464,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: v = variables.VariableV1(42, name="v") ops.add_to_collection("foo_vars", v) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(42, self.evaluate(v)) builder.add_meta_graph_and_variables(sess, ["foo"]) @@ -474,7 +474,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: v = variables.VariableV1(43, name="v") ops.add_to_collection("bar_vars", v) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(43, self.evaluate(v)) builder.add_meta_graph(["bar"]) @@ -802,7 +802,7 @@ class SavedModelTest(SavedModelTestBase): add_v1_v2 = math_ops.add(v1._ref(), v2._ref()) custom_main_op = control_flow_ops.group(state_ops.assign(v3, add_v1_v2)) - self.evaluate(custom_main_op) + sess.run(custom_main_op) builder.add_meta_graph_and_variables( sess, ["foo"], main_op=custom_main_op) @@ -836,7 +836,7 @@ class SavedModelTest(SavedModelTestBase): assign_v3 = state_ops.assign(v3, math_ops.add(v1, v2)) legacy_init_op = control_flow_ops.group(assign_v3, name="legacy_init_op") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) builder.add_meta_graph_and_variables( sess, ["foo"], legacy_init_op=legacy_init_op) @@ -879,7 +879,7 @@ class SavedModelTest(SavedModelTestBase): assign_v2 = state_ops.assign(v2, v1) init_op = control_flow_ops.group(assign_v2, name="init_op") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) ops.add_to_collection(key, control_flow_ops.no_op()) # ValueError should be raised since the LEGACY_INIT_OP_KEY collection @@ -902,10 +902,10 @@ class SavedModelTest(SavedModelTestBase): v2 = variables.VariableV1(2, name="v2") ops.add_to_collection("v", v2) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) train_op = state_ops.assign_add(v1, v2) - self.evaluate(train_op) + sess.run(train_op) # TODO(karmel): remove explicit call when in the public method. builder._add_train_op(train_op) builder.add_meta_graph_and_variables(sess, ["foo"]) @@ -931,10 +931,10 @@ class SavedModelTest(SavedModelTestBase): v2 = variables.VariableV1(2, name="v2") ops.add_to_collection("v", v2) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) train_op = control_flow_ops.group() - self.evaluate(train_op) + sess.run(train_op) # TODO(karmel): remove explicit call when in the public method. builder._add_train_op(train_op) builder.add_meta_graph_and_variables(sess, ["foo"]) @@ -960,11 +960,11 @@ class SavedModelTest(SavedModelTestBase): v2 = variables.VariableV1(2, name="v2") ops.add_to_collection("v", v2) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) builder.add_meta_graph_and_variables(sess, ["pre_foo"]) train_op = state_ops.assign_add(v1, v2) - self.evaluate(train_op) + sess.run(train_op) # TODO(karmel): remove explicit call when in the public method. builder._add_train_op(train_op) builder.add_meta_graph(["foo"]) @@ -1090,7 +1090,7 @@ class SavedModelTest(SavedModelTestBase): ops.add_to_collection("v", v3) ops.add_to_collection("init_op", init_op) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(1, ops.get_collection("v")[0].eval()) self.assertEqual(2, ops.get_collection("v")[1].eval()) @@ -1145,7 +1145,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: variables.VariableV1(1, name="v1") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) custom_saver = training.Saver(name="my_saver") builder.add_meta_graph_and_variables(sess, ["tag"], saver=custom_saver) @@ -1167,7 +1167,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: variables.VariableV1(1, name="v1") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) training.Saver(name="my_saver") builder.add_meta_graph_and_variables(sess, ["tag"]) @@ -1189,7 +1189,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: variables.VariableV1(1, name="v1") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) builder.add_meta_graph_and_variables(sess, ["tag_0"]) saver_1 = training.Saver() @@ -1298,7 +1298,7 @@ class SavedModelTest(SavedModelTestBase): real_num = variables.VariableV1(1.0, dtype=dtypes.float32, name="real") imag_num = variables.VariableV1(2.0, dtype=dtypes.float32, name="imag") math_ops.complex(real_num, imag_num, name="complex") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) builder.add_meta_graph_and_variables( sess, ["foo"], strip_default_attrs=True) @@ -1308,7 +1308,7 @@ class SavedModelTest(SavedModelTestBase): real_num = variables.VariableV1(1.0, dtype=dtypes.float32, name="real") imag_num = variables.VariableV1(2.0, dtype=dtypes.float32, name="imag") math_ops.complex(real_num, imag_num, name="complex") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) builder.add_meta_graph(["bar"], strip_default_attrs=False) # Save the SavedModel to disk in text format. @@ -1370,7 +1370,7 @@ class SavedModelTest(SavedModelTestBase): with session.Session(graph=ops.Graph()) as sess: variables.VariableV1(1.0, dtype=dtypes.float64, name="var") test_ops.test_attr(T=dtypes.float32, name="test_attr") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) builder.add_meta_graph_and_variables(sess, ["foo"]) # Save the SavedModel to disk in text format. diff --git a/tensorflow/python/saved_model/simple_save_test.py b/tensorflow/python/saved_model/simple_save_test.py index 0d0665072a..2d404dcea4 100644 --- a/tensorflow/python/saved_model/simple_save_test.py +++ b/tensorflow/python/saved_model/simple_save_test.py @@ -33,7 +33,7 @@ class SimpleSaveTest(test.TestCase): def _init_and_validate_variable(self, sess, variable_name, variable_value): v = variables.Variable(variable_value, name=variable_name) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(variable_value, self.evaluate(v)) return v diff --git a/tensorflow/python/tools/strip_unused_test.py b/tensorflow/python/tools/strip_unused_test.py index e906ff94ba..7cf0c3e3ed 100644 --- a/tensorflow/python/tools/strip_unused_test.py +++ b/tensorflow/python/tools/strip_unused_test.py @@ -50,7 +50,7 @@ class StripUnusedTest(test_util.TensorFlowTestCase): wanted_input_node, 2.0, name="output_node") math_ops.add(output_node, 2.0, name="later_node") sess = session.Session() - output = self.evaluate(output_node) + output = sess.run(output_node) self.assertNear(-4.0, output, 0.00001) graph_io.write_graph(sess.graph, self.get_temp_dir(), input_graph_name) @@ -113,7 +113,7 @@ class StripUnusedTest(test_util.TensorFlowTestCase): input_node1, input_node2, name="output_node") math_ops.add(output_node, 2.0, name="later_node") sess = session.Session() - output = self.evaluate(output_node) + output = sess.run(output_node) self.assertNear(6.0, output, 0.00001) graph_io.write_graph(sess.graph, self.get_temp_dir(), input_graph_name) diff --git a/tensorflow/python/training/basic_session_run_hooks_test.py b/tensorflow/python/training/basic_session_run_hooks_test.py index 13c9e9aa67..2d469634e0 100644 --- a/tensorflow/python/training/basic_session_run_hooks_test.py +++ b/tensorflow/python/training/basic_session_run_hooks_test.py @@ -243,7 +243,7 @@ class LoggingTensorHookTest(test.TestCase): tensors=[t.name], at_end=True) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) self.logged_message = '' for _ in range(3): mon_sess.run(train_op) @@ -261,7 +261,7 @@ class LoggingTensorHookTest(test.TestCase): tensors=[t.name], every_n_iter=10, at_end=at_end) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertRegexpMatches(str(self.logged_message), t.name) for _ in range(3): @@ -308,7 +308,7 @@ class LoggingTensorHookTest(test.TestCase): tensors={'foo': t}, every_n_iter=1) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertRegexpMatches(str(self.logged_message), 'foo') # in first run, elapsed time is None. @@ -322,7 +322,7 @@ class LoggingTensorHookTest(test.TestCase): tensors=[t.name], every_n_secs=1.0, at_end=at_end) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertRegexpMatches(str(self.logged_message), t.name) @@ -366,7 +366,7 @@ class LoggingTensorHookTest(test.TestCase): formatter=lambda items: 'qqq=%s' % items[t.name]) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertEqual(self.logged_message[0], 'qqq=42.0') @@ -921,7 +921,7 @@ class StepCounterHookTest(test.TestCase): hook = basic_session_run_hooks.StepCounterHook( summary_writer=summary_writer, every_n_steps=10) hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) with test.mock.patch.object(tf_logging, 'warning') as mock_log: for _ in range(30): @@ -950,7 +950,7 @@ class StepCounterHookTest(test.TestCase): summary_writer=summary_writer, every_n_steps=None, every_n_secs=0.1) hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) mon_sess.run(train_op) time.sleep(0.2) @@ -987,7 +987,7 @@ class StepCounterHookTest(test.TestCase): summary_writer=summary_writer, every_n_steps=1, every_n_secs=None) hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) mon_sess.run(train_op) mon_sess.run(train_op) @@ -1007,7 +1007,7 @@ class StepCounterHookTest(test.TestCase): with ops.Graph().as_default(), session_lib.Session() as sess: variables.get_or_create_global_step() train_op = training_util._increment_global_step(0) # keep same. - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) hook = basic_session_run_hooks.StepCounterHook( every_n_steps=1, every_n_secs=None) hook.begin() @@ -1034,7 +1034,7 @@ class StepCounterHookTest(test.TestCase): summary_writer=self.summary_writer, every_n_steps=every_n_steps) self.hook._set_steps_per_run(steps_per_run) self.hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) self.mon_sess = monitored_session._HookedSession(sess, [self.hook]) def test_steps_per_run_less_than_every_n_steps(self): @@ -1147,7 +1147,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(30): mon_sess.run(self.train_op) @@ -1179,7 +1179,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(10): mon_sess.run(self.train_op) @@ -1207,7 +1207,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(4): mon_sess.run(self.train_op) @@ -1242,7 +1242,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(8): mon_sess.run(self.train_op) @@ -1285,7 +1285,7 @@ class GlobalStepWaiterHookTest(test.TestCase): hook = basic_session_run_hooks.GlobalStepWaiterHook(wait_until_step=1000) hook.begin() with session_lib.Session() as sess: - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) waiter = threading.Thread( target=hook.before_run, args=(session_run_hook.SessionRunContext( @@ -1390,7 +1390,7 @@ class ResourceSummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - self.evaluate(variables_lib.global_variables_initializer()) + sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(30): mon_sess.run(self.train_op) diff --git a/tensorflow/python/training/checkpoint_ops_test.py b/tensorflow/python/training/checkpoint_ops_test.py index 21ad3df1c8..38d4acf85f 100644 --- a/tensorflow/python/training/checkpoint_ops_test.py +++ b/tensorflow/python/training/checkpoint_ops_test.py @@ -47,7 +47,7 @@ class LoadAndRemapWrappersTest(test.TestCase): with variable_scope.variable_scope('some_scope'): variable_scope.get_variable(name='embeddings', shape=[5, 16], initializer=initializer) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) saver = saver_lib.Saver() saver.save(sess, checkpoint_prefix, global_step=5) self.checkpoint_file = '{}-5'.format(checkpoint_prefix) diff --git a/tensorflow/python/training/input_test.py b/tensorflow/python/training/input_test.py index 31c2cc56c0..e5aac5da18 100644 --- a/tensorflow/python/training/input_test.py +++ b/tensorflow/python/training/input_test.py @@ -474,7 +474,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = self.evaluate(batched_fetch) + results = sess.run(batched_fetch) self.assertAllEqual(results[0], np.arange(i * batch_size, (i + 1) * batch_size)) self.assertAllEqual( @@ -539,7 +539,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) expected_results = np.arange(i * batch_size, (i + 1) * batch_size) max_len = expected_results[-1] self.assertAllEqual(results[0], expected_results) @@ -571,7 +571,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual(results[0], np.arange(i * batch_size, (i + 1) * batch_size)) self.assertAllEqual( @@ -610,7 +610,7 @@ class BatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertAllEqual(results[0], results[1].values) @@ -651,7 +651,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual(results[0], np.arange(i * batch_size, (i + 1) * batch_size)) self.assertAllEqual( @@ -667,7 +667,7 @@ class BatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra_elements. - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual(results[0], np.arange(num_batches * batch_size, num_batches * batch_size + extra_elements)) @@ -709,7 +709,7 @@ class BatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertAllEqual(results[0], results[1].values) @@ -721,7 +721,7 @@ class BatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra_elements. - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Last Batch: %s", results[0]) self.assertEqual(len(results[0]), extra_elements) self.assertAllEqual(results[0], results[1].values) @@ -827,7 +827,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual([0] * batch_size, np.mod(results[0], 2)) self.assertAllEqual([0] * batch_size, np.mod(results[1].values, 2)) self.assertAllEqual([b"string"] * batch_size, results[2]) @@ -1020,7 +1020,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = self.evaluate(batched_fetch) + results = sess.run(batched_fetch) self.assertEqual(3, len(results)) self.assertEqual(batch_size, len(results[0])) self.assertEqual(batch_size, len(results[2])) @@ -1116,7 +1116,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertEqual(2, len(results)) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[1]), batch_size) @@ -1201,7 +1201,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[2]), batch_size) @@ -1221,7 +1221,7 @@ class BatchJoinTest(test_lib.TestCase): [results[0][i] for i in which_b]) # Reached the final batch with 2 * extra_elements. - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Last Batch: %s", results[0]) self.assertEqual(len(results[0]), 2 * extra_elements) self.assertEqual(len(results[2]), 2 * extra_elements) @@ -1296,7 +1296,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[1]), batch_size) @@ -1316,7 +1316,7 @@ class BatchJoinTest(test_lib.TestCase): [results[0][i] for i in which_b]) # Reached the final batch with 2 * extra_elements. - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Last Batch: %s", results[0]) self.assertEqual(len(results[0]), 2 * extra_elements) self.assertEqual(len(results[1]), 2 * extra_elements) @@ -1410,7 +1410,7 @@ class BatchJoinTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual( [0] * batch_size, np.mod(results[0], 2),) @@ -1579,7 +1579,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = self.evaluate(batched_fetch) + results = sess.run(batched_fetch) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) self.assertAllEqual( @@ -1634,7 +1634,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for _ in range(num_batches): - results = self.evaluate(batched_fetch) + results = sess.run(batched_fetch) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) self.assertAllEqual( @@ -1645,7 +1645,7 @@ class ShuffleBatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra elements. - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual(results[1].dense_shape, [extra_elements, 1]) self.assertAllEqual(results[2], [b"string"] * extra_elements) all_counts.extend(results[0]) @@ -1687,7 +1687,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) @@ -1737,7 +1737,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) @@ -1749,7 +1749,7 @@ class ShuffleBatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra elements. - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual(results[0].shape, [extra_elements]) self.assertAllEqual(results[1].dense_shape, [extra_elements, 1]) self.assertAllEqual(results[2], [b"string"] * extra_elements) @@ -1817,7 +1817,7 @@ class ShuffleBatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual([0] * batch_size, np.mod(results[0], 2)) self.assertAllEqual([0] * batch_size, np.mod(results[1].values, 2)) self.assertAllEqual([b"string"] * batch_size, results[2]) @@ -1990,7 +1990,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = self.evaluate(batched_fetch) + results = sess.run(batched_fetch) self.assertEqual(3, len(results)) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[2]), batch_size) @@ -2082,7 +2082,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[2]), batch_size) @@ -2102,7 +2102,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): [results[0][i] for i in which_b]) # Reached end with 2 * extra_elements left - results = self.evaluate(batched) + results = sess.run(batched) self.assertEqual(len(results[0]), 2 * extra_elements) self.assertAllEqual(results[1].dense_shape, [2 * extra_elements, 1]) self.assertEqual(len(results[2]), 2 * extra_elements) @@ -2203,7 +2203,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = self.evaluate(batched) + results = sess.run(batched) self.assertAllEqual([0] * batch_size, np.mod(results[0], 2)) self.assertAllEqual([0] * batch_size, np.mod(results[1].values, 2)) self.assertAllEqual([b"string"] * batch_size, results[2]) diff --git a/tensorflow/python/training/monitored_session_test.py b/tensorflow/python/training/monitored_session_test.py index 2ceb387ec3..b828be4499 100644 --- a/tensorflow/python/training/monitored_session_test.py +++ b/tensorflow/python/training/monitored_session_test.py @@ -1170,7 +1170,7 @@ class HookedSessionTest(test.TestCase): mock_run = FakeSession(sess) mon_sess = monitored_session._HookedSession(sess=mock_run, hooks=[]) a_tensor = constant_op.constant([0], name='a_tensor') - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) output = mon_sess.run(fetches=a_tensor, feed_dict='a_feed', options='an_option', @@ -1189,7 +1189,7 @@ class HookedSessionTest(test.TestCase): mon_sess = monitored_session._HookedSession( sess=sess, hooks=[mock_hook, mock_hook2]) a_tensor = constant_op.constant([0], name='a_tensor') - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) mon_sess.run(a_tensor) for hook in [mock_hook, mock_hook2]: @@ -1214,7 +1214,7 @@ class HookedSessionTest(test.TestCase): mon_sess = monitored_session._HookedSession( sess=sess, hooks=[mock_hook, mock_hook2]) constant_op.constant([0], name='a_tensor') - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) mon_sess.run(fetches='a_tensor') self.assertFalse(mon_sess.should_stop()) @@ -1234,7 +1234,7 @@ class HookedSessionTest(test.TestCase): third_tensor = constant_op.constant([10], name='third_tensor') mock_hook.request = session_run_hook.SessionRunArgs([another_tensor]) mock_hook2.request = session_run_hook.SessionRunArgs([third_tensor]) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) output = mon_sess.run(fetches=a_tensor) self.assertEqual(output, [0]) @@ -1254,7 +1254,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={b_tensor: [10]}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertEqual(mon_sess.run(fetches=add_tensor), [15]) @@ -1272,7 +1272,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={b_tensor: [10]}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) feed_dict = {c_tensor: [20]} self.assertEqual( @@ -1293,7 +1293,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={a_tensor: [10]}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) with self.assertRaisesRegexp(RuntimeError, 'Same tensor is fed'): mon_sess.run(fetches=add_tensor) @@ -1311,7 +1311,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={b_tensor: [10]}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) with self.assertRaisesRegexp(RuntimeError, 'Same tensor is fed'): mon_sess.run(fetches=add_tensor, feed_dict={b_tensor: [10]}) diff --git a/tensorflow/python/training/moving_averages_test.py b/tensorflow/python/training/moving_averages_test.py index 41e9dcea84..8009e3c24e 100644 --- a/tensorflow/python/training/moving_averages_test.py +++ b/tensorflow/python/training/moving_averages_test.py @@ -274,14 +274,14 @@ class ExponentialMovingAverageTest(test.TestCase): self.assertEqual([], v1_avg.value().op.control_inputs) self.assertEqual([], v1_avg.value().op.control_inputs) # We should be able to initialize v1_avg before v0. - self.evaluate(v1_avg.initializer) - self.evaluate(v0.initializer) - self.assertEqual([10.0], self.evaluate(v1_avg)) + sess.run(v1_avg.initializer) + sess.run(v0.initializer) + self.assertEqual([10.0], sess.run(v1_avg)) # running ema_op should add to v0 (in addition to updating v1_avg) sess.run(assign_to_v1) - self.evaluate(ema_op) - self.assertEqual(1, self.evaluate(v0)) - self.assertEqual([17.5], self.evaluate(v1_avg)) + sess.run(ema_op) + self.assertEqual(1, sess.run(v0)) + self.assertEqual([17.5], sess.run(v1_avg)) @test_util.run_in_graph_and_eager_modes def testBasicEager(self): diff --git a/tensorflow/python/training/saver_test.py b/tensorflow/python/training/saver_test.py index 7bc0a178a4..eb2690985d 100644 --- a/tensorflow/python/training/saver_test.py +++ b/tensorflow/python/training/saver_test.py @@ -227,7 +227,7 @@ class SaverTest(test.TestCase): w1 = resource_variable_ops.ResourceVariable(1.0, name="w1") w2 = resource_variable_ops.ResourceVariable(2.0, name="w2") graph_saver = saver_module.Saver([w1, w2]) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) graph_saver.save(sess, graph_ckpt_prefix) with context.eager_mode(): @@ -260,7 +260,7 @@ class SaverTest(test.TestCase): w3 = resource_variable_ops.ResourceVariable(0.0, name="w3") w4 = resource_variable_ops.ResourceVariable(0.0, name="w4") graph_saver = saver_module.Saver([w3, w4]) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) graph_saver.restore(sess, eager_ckpt_prefix) self.assertAllEqual(w3.eval(), 3.0) self.assertAllEqual(w4.eval(), 4.0) @@ -326,7 +326,7 @@ class SaverTest(test.TestCase): with self.cached_session() as sess: # Initialize all variables - self.evaluate(init_all_op) + sess.run(init_all_op) # Check that the parameter nodes have been initialized. self.assertEqual(10.0, v0.eval()) @@ -376,7 +376,7 @@ class SaverTest(test.TestCase): with self.cached_session() as sess: tensor = sess.graph.get_tensor_by_name( save.saver_def.filename_tensor_name) - self.assertEqual(self.evaluate(tensor), filename) + self.assertEqual(sess.run(tensor), filename) def testInvalidPath(self): v0 = variables.VariableV1(0, name="v0") @@ -742,7 +742,7 @@ class SaverTest(test.TestCase): try: with self.cached_session() as sess: # Initialize all variables - self.evaluate(init_all_op) + sess.run(init_all_op) # Check that the parameter nodes have been initialized. self.assertEqual(10.0, v0.eval()) @@ -777,7 +777,7 @@ class SaverTest(test.TestCase): with self.cached_session() as sess: # Initialize all variables - self.evaluate(init_all_op) + sess.run(init_all_op) # Check that the parameter nodes have been initialized. self.assertEqual(10.0, v0.eval()) @@ -824,11 +824,11 @@ class SaverTest(test.TestCase): save_graph = ops_lib.Graph() with save_graph.as_default(), self.session(graph=save_graph) as sess: orig_vars = _model() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) save = saver_module.Saver(max_to_keep=1) variables.global_variables_initializer().run() save.save(sess, save_dir) - orig_vals = self.evaluate(orig_vars) + orig_vals = sess.run(orig_vars) restore_graph = ops_lib.Graph() with restore_graph.as_default(), self.session( @@ -836,7 +836,7 @@ class SaverTest(test.TestCase): restored_vars = _model() save = saver_module.Saver(max_to_keep=1) save.restore(sess, save_dir) - restored_vals = self.evaluate(restored_vars) + restored_vals = sess.run(restored_vars) for orig, restored in zip(orig_vals, restored_vals): self.assertAllEqual(orig, restored) @@ -1949,7 +1949,7 @@ class MetaGraphTest(test.TestCase): with self.cached_session() as sess: # Initializes all the variables. - self.evaluate(init_all_op) + sess.run(init_all_op) # Runs to logit. sess.run(logits) # Creates a saver. @@ -1991,7 +1991,7 @@ class MetaGraphTest(test.TestCase): ops_lib.add_to_collection("train_op", train_op) # Runs train_op. - self.evaluate(train_op) + sess.run(train_op) # Generates MetaGraphDef. saver_module.export_meta_graph(train_filename) @@ -2005,7 +2005,7 @@ class MetaGraphTest(test.TestCase): # Restores from checkpoint. new_saver.restore(sess, saver0_ckpt) train_op = ops_lib.get_collection("train_op")[0] - self.evaluate(train_op) + sess.run(train_op) def testGraphExtension(self): test_dir = self._get_test_dir("graph_extension") @@ -2037,7 +2037,7 @@ class MetaGraphTest(test.TestCase): # Generate a MetaGraphDef containing the while loop. with session.Session() as sess: - self.evaluate(init_op) + sess.run(init_op) sess.run(output) saver = saver_module.Saver() saver.save(sess, saver_ckpt) @@ -2053,8 +2053,8 @@ class MetaGraphTest(test.TestCase): no_constfold_config.graph_options.rewrite_options.constant_folding = ( rewriter_config_pb2.RewriterConfig.OFF) with session.Session(config=no_constfold_config) as sess: - self.evaluate(init_op) - expected_grad_value = self.evaluate(grad) + sess.run(init_op) + expected_grad_value = sess.run(grad) # Restore the MetaGraphDef into a new Graph. with ops_lib.Graph().as_default(): @@ -2070,8 +2070,8 @@ class MetaGraphTest(test.TestCase): init_op = variables.global_variables_initializer() with session.Session(config=no_constfold_config) as sess: - self.evaluate(init_op) - actual_grad_value = self.evaluate(grad) + sess.run(init_op) + actual_grad_value = sess.run(grad) self.assertEqual(expected_grad_value, actual_grad_value) def _testWhileLoopAndGradientSerDes(self, outer_body_fn): @@ -2209,7 +2209,7 @@ class MetaGraphTest(test.TestCase): logits=logit, name="cost") adam.AdamOptimizer().minimize(cost, name="optimize") saver = saver_module.Saver() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) saver.save(sess, filename) graph = ops_lib.Graph() @@ -2246,7 +2246,7 @@ class MetaGraphTest(test.TestCase): # Create a variable in graph_2 under scope "my_scope". variables.VariableV1(array_ops.zeros([10]), name="my_scope/my_var") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Restore the checkpoint into a different scope "subgraph_2". new_saver_2 = saver_module.import_meta_graph( filename + ".meta", graph=graph_2, import_scope="subgraph_2") @@ -2279,7 +2279,7 @@ class MetaGraphTest(test.TestCase): logits=logit, name="cost") adam.AdamOptimizer().minimize(cost, name="optimize") saver = saver_module.Saver() - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) saver.save(sess, filename) graph = ops_lib.Graph() @@ -2316,12 +2316,12 @@ class MetaGraphTest(test.TestCase): meta_graph_def, clear_devices=False, import_scope="new_model") # Device refers to GPU, which is not available here. with self.assertRaises(errors_impl.InvalidArgumentError): - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) with session.Session(graph=ops_lib.Graph()) as sess: saver_module.import_meta_graph( meta_graph_def, clear_devices=True, import_scope="new_model") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) sess.run(["new_model/optimize"], { "new_model/image:0": np.random.random([1, 784]), "new_model/label:0": np.random.randint( @@ -2348,7 +2348,7 @@ class MetaGraphTest(test.TestCase): with session.Session(graph=ops_lib.Graph()) as sess: saver_module.import_meta_graph(meta_graph_def, import_scope="new_model") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) sess.run(["new_model/optimize"], { "new_model/image:0": np.random.random([1, 784]), "new_model/label:0": np.random.randint( @@ -2374,7 +2374,7 @@ class MetaGraphTest(test.TestCase): meta_graph_def_from_graph_def]: with session.Session(graph=ops_lib.Graph()) as sess: saver_module.import_meta_graph(meta_graph_def, import_scope="new_model") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) for i in range(10): self.assertEqual(i * i, sess.run("new_model/output:0")) with self.assertRaises(errors.OutOfRangeError): @@ -2400,7 +2400,7 @@ class CheckpointReaderTest(test.TestCase): save_path = os.path.join(self.get_temp_dir(), "ckpt_for_debug_string" + str(self._WRITE_VERSION)) with self.cached_session() as sess: - self.evaluate(init_all_op) + sess.run(init_all_op) # Saves a checkpoint. save.save(sess, save_path) @@ -2546,7 +2546,7 @@ class ScopedGraphTest(test.TestCase): self.assertEqual(["biases:0", "weights:0"], sorted(var_list.keys())) with self.session(graph=graph) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) saver = saver_module.Saver(var_list=var_list, max_to_keep=1) saver.save(sess, os.path.join(test_dir, ckpt_filename), write_state=False) @@ -2611,7 +2611,7 @@ class ScopedGraphTest(test.TestCase): # Verify that we have restored weights1 and biases1. sess.run([weights1, biases1]) # Initialize the rest of the variables and run logits. - self.evaluate(init_rest_op) + sess.run(init_rest_op) sess.run(logits) # Verifies that we can save the subgraph under "hidden1" and restore it @@ -2640,7 +2640,7 @@ class ScopedGraphTest(test.TestCase): # Run the graph and save scoped checkpoint. with self.session(graph=graph1) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) _, var_list_1 = meta_graph.export_scoped_meta_graph( export_scope="hidden1") saver = saver_module.Saver(var_list=var_list_1, max_to_keep=1) @@ -2696,7 +2696,7 @@ class ScopedGraphTest(test.TestCase): # Run the graph and save scoped checkpoint. with self.session(graph=graph1) as sess: - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) _, var_list_1 = meta_graph.export_scoped_meta_graph( graph_def=graph1.as_graph_def(), export_scope="hidden1") saver = saver_module.Saver(var_list=var_list_1, max_to_keep=1) @@ -2964,7 +2964,7 @@ class CheckpointableCompatibilityTests(test.TestCase): a_saver = saver_module.Saver([a]) b_saver = saver_module.Saver([b]) with self.cached_session() as sess: - self.evaluate(a.initializer) + sess.run(a.initializer) save_path = a_saver.save(sess=sess, save_path=checkpoint_prefix) with self.assertRaisesRegexp( errors.NotFoundError, "Key b not found in checkpoint"): @@ -2986,7 +2986,7 @@ class CheckpointableCompatibilityTests(test.TestCase): a_saver = saver_module.Saver([a]) with self.session(graph=g) as sess: - self.evaluate(a.initializer) + sess.run(a.initializer) save_path = a_saver.save(sess=sess, save_path=checkpoint_prefix) with ops_lib.Graph().as_default() as g: diff --git a/tensorflow/python/training/server_lib_sparse_job_test.py b/tensorflow/python/training/server_lib_sparse_job_test.py index 8c2745b51a..1a6b44b90e 100644 --- a/tensorflow/python/training/server_lib_sparse_job_test.py +++ b/tensorflow/python/training/server_lib_sparse_job_test.py @@ -36,7 +36,7 @@ class SparseJobTest(test.TestCase): a = constant_op.constant(1.0) with session.Session(server.target) as sess: - self.assertEqual(1.0, self.evaluate(a)) + self.assertEqual(1.0, sess.run(a)) if __name__ == "__main__": diff --git a/tensorflow/python/training/supervisor_test.py b/tensorflow/python/training/supervisor_test.py index 9dc88d78cc..b734e9653e 100644 --- a/tensorflow/python/training/supervisor_test.py +++ b/tensorflow/python/training/supervisor_test.py @@ -100,7 +100,7 @@ class SupervisorTest(test.TestCase): sv = supervisor.Supervisor(logdir=logdir) sess = sv.prepare_or_wait_for_session("") for _ in xrange(10): - self.evaluate(my_op) + sess.run(my_op) sess.close() sv.stop() @@ -111,7 +111,7 @@ class SupervisorTest(test.TestCase): sv = supervisor.Supervisor(logdir=logdir) with sv.managed_session("") as sess: for _ in xrange(10): - self.evaluate(my_op) + sess.run(my_op) # Supervisor has been stopped. self.assertTrue(sv.should_stop()) @@ -128,7 +128,7 @@ class SupervisorTest(test.TestCase): if step == 1: raise RuntimeError("failing here") else: - self.evaluate(my_op) + sess.run(my_op) # Supervisor has been stopped. self.assertTrue(sv.should_stop()) self.assertEqual(1, last_step) @@ -146,7 +146,7 @@ class SupervisorTest(test.TestCase): raise errors_impl.OutOfRangeError(my_op.op.node_def, my_op.op, "all done") else: - self.evaluate(my_op) + sess.run(my_op) # Supervisor has been stopped. OutOfRangeError was not thrown. self.assertTrue(sv.should_stop()) self.assertEqual(3, last_step) @@ -335,7 +335,7 @@ class SupervisorTest(test.TestCase): sess = sv.prepare_or_wait_for_session( "", config=config_pb2.ConfigProto(device_count={"CPU": 2})) for _ in xrange(10): - self.evaluate(my_op) + sess.run(my_op) sess.close() sv.stop() diff --git a/tensorflow/python/training/warm_starting_util_test.py b/tensorflow/python/training/warm_starting_util_test.py index f1e719e6db..b575b8d364 100644 --- a/tensorflow/python/training/warm_starting_util_test.py +++ b/tensorflow/python/training/warm_starting_util_test.py @@ -49,7 +49,7 @@ class WarmStartingUtilTest(test.TestCase): return vocab_file def _write_checkpoint(self, sess): - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) saver = saver_lib.Saver() ckpt_prefix = os.path.join(self.get_temp_dir(), "model") saver.save(sess, ckpt_prefix, global_step=0) @@ -125,7 +125,7 @@ class WarmStartingUtilTest(test.TestCase): prev_tensor_name, var = ws_util._get_var_info(fruit_weights) checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllClose(prev_val, fruit_weights.eval(sess)) def testWarmStartVarPrevVarPartitioned(self): @@ -143,7 +143,7 @@ class WarmStartingUtilTest(test.TestCase): prev_tensor_name, var = ws_util._get_var_info(fruit_weights) checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllClose(prev_val, fruit_weights.eval(sess)) def testWarmStartVarCurrentVarPartitioned(self): @@ -162,7 +162,7 @@ class WarmStartingUtilTest(test.TestCase): prev_tensor_name, var = ws_util._get_var_info(fruit_weights) checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) fruit_weights = fruit_weights._get_variable_list() new_val = np.concatenate( [fruit_weights[0].eval(sess), fruit_weights[1].eval(sess)], axis=0) @@ -189,7 +189,7 @@ class WarmStartingUtilTest(test.TestCase): fruit_weights, prev_tensor_name="old_scope/fruit_weights") checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) fruit_weights = fruit_weights._get_variable_list() new_val = np.concatenate( [fruit_weights[0].eval(sess), fruit_weights[1].eval(sess)], axis=0) @@ -211,7 +211,7 @@ class WarmStartingUtilTest(test.TestCase): "fruit_weights", initializer=[[0.], [0.], [0.], [0.], [0.]]) ws_util._warm_start_var_with_vocab(fruit_weights, new_vocab_path, 5, self.get_temp_dir(), prev_vocab_path) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllClose([[2.], [1.5], [1.], [0.5], [0.]], fruit_weights.eval(sess)) @@ -236,7 +236,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllClose([[0.3, 0.5, 0.], [0.8, 1.0, 0.], [1.2, 1.5, 0.], [2.3, 2., 0.]], fruit_output_layer.eval(sess)) @@ -261,7 +261,7 @@ class WarmStartingUtilTest(test.TestCase): self.get_temp_dir(), prev_vocab_path, previous_vocab_size=2) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Old vocabulary limited to ['apple', 'banana']. self.assertAllClose([[0.], [0.], [1.], [0.5], [0.]], fruit_weights.eval(sess)) @@ -285,7 +285,7 @@ class WarmStartingUtilTest(test.TestCase): "fruit_weights", initializer=[[0.], [0.], [0.], [0.], [0.]]) ws_util._warm_start_var_with_vocab(fruit_weights, new_vocab_path, 5, self.get_temp_dir(), prev_vocab_path) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllClose([[2.], [1.5], [1.], [0.5], [0.]], fruit_weights.eval(sess)) @@ -312,7 +312,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertAllClose([[0.3, 0.5, 0.], [0.8, 1.0, 0.], [1.2, 1.5, 0.], [2.3, 2., 0.]], fruit_output_layer.eval(sess)) @@ -340,7 +340,7 @@ class WarmStartingUtilTest(test.TestCase): self.get_temp_dir(), prev_vocab_path, current_oov_buckets=1) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_weights, variables.PartitionedVariable)) fruit_weights_vars = fruit_weights._get_variable_list() @@ -372,7 +372,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_output_layer, variables.PartitionedVariable)) fruit_output_layer_vars = fruit_output_layer._get_variable_list() @@ -404,7 +404,7 @@ class WarmStartingUtilTest(test.TestCase): partitioner=lambda shape, dtype: [2, 1]) ws_util._warm_start_var_with_vocab(fruit_weights, new_vocab_path, 6, self.get_temp_dir(), prev_vocab_path) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_weights, variables.PartitionedVariable)) fruit_weights_vars = fruit_weights._get_variable_list() @@ -438,7 +438,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_output_layer, variables.PartitionedVariable)) fruit_output_layer_vars = fruit_output_layer._get_variable_list() @@ -463,7 +463,7 @@ class WarmStartingUtilTest(test.TestCase): shape=[10, 1], initializer=zeros()) ws_util.warm_start(self.get_temp_dir(), vars_to_warm_start=[var]) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started (init overridden to ones). self.assertAllEqual(var.eval(), prev_int_val) @@ -483,7 +483,7 @@ class WarmStartingUtilTest(test.TestCase): shape=[10, 1], initializer=zeros()) ws_util.warm_start(self.get_temp_dir(), vars_to_warm_start=["v1"]) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started (init overridden to ones). self.assertAllEqual(var.eval(), prev_int_val) @@ -519,7 +519,7 @@ class WarmStartingUtilTest(test.TestCase): # This warm-starts both v1 and v1/Momentum, but only # v2 (and not v2/Momentum). vars_to_warm_start=["v1", "v2[^/]"]) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify the selection of weights were correctly warm-started (init # overridden to ones). self.assertAllEqual(v1.eval(), prev_v1_val) @@ -542,7 +542,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_int], partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_int: [np.zeros([10, 1])]}, @@ -553,7 +553,7 @@ class WarmStartingUtilTest(test.TestCase): with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_int], partitioner) ws_util.warm_start(self.get_temp_dir(), vars_to_warm_start=".*sc_int.*") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_int: [prev_int_val]}, sess) @@ -571,7 +571,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_hash], partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_hash: [np.zeros([15, 1])]}, @@ -583,7 +583,7 @@ class WarmStartingUtilTest(test.TestCase): cols_to_vars = self._create_linear_model([sc_hash], partitioner) ws_util.warm_start( self.get_temp_dir(), vars_to_warm_start=".*sc_hash.*") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_hash: [prev_hash_val]}, sess) @@ -605,7 +605,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_vocab], partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [np.zeros([4, 1])]}, @@ -619,7 +619,7 @@ class WarmStartingUtilTest(test.TestCase): # vocab is assumed to be same as new vocab. ws_util.warm_start( self.get_temp_dir(), vars_to_warm_start=".*sc_vocab.*") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [prev_vocab_val]}, sess) @@ -641,7 +641,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_vocab], partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [np.zeros([4, 1])]}, @@ -657,7 +657,7 @@ class WarmStartingUtilTest(test.TestCase): # Explicitly provide the file prefix instead of just the dir. os.path.join(self.get_temp_dir(), "model-0"), vars_to_warm_start=".*sc_vocab.*") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [prev_vocab_val]}, sess) @@ -686,7 +686,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_vocab], partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [np.zeros([2, 1])]}, @@ -708,7 +708,7 @@ class WarmStartingUtilTest(test.TestCase): var_name_to_vocab_info={ "linear_model/sc_vocab/weights": vocab_info }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. 'banana' isn't in the # first two entries of the old vocabulary, so it's newly initialized. self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [[[1], [0]]]}, sess) @@ -729,7 +729,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([real_bucket], partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, @@ -741,7 +741,7 @@ class WarmStartingUtilTest(test.TestCase): cols_to_vars = self._create_linear_model([real_bucket], partitioner) ws_util.warm_start( self.get_temp_dir(), vars_to_warm_start=".*real_bucketized.*") - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {real_bucket: [prev_bucket_val]}, sess) @@ -800,7 +800,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model(all_linear_cols, partitioner) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Without warm-starting, all weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, { @@ -826,7 +826,7 @@ class WarmStartingUtilTest(test.TestCase): var_name_to_vocab_info={ "linear_model/sc_vocab/weights": vocab_info }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, { sc_int: [prev_int_val], @@ -865,7 +865,7 @@ class WarmStartingUtilTest(test.TestCase): "linear_model/sc_vocab/weights", initializer=[[0.5], [1.], [2.], [3.]]) self._write_checkpoint(sess) - prev_keys_val = self.evaluate(sc_keys_weights) + prev_keys_val = sess.run(sc_keys_weights) def _partitioner(shape, dtype): # pylint:disable=unused-argument # Partition each var into 2 equal slices. @@ -892,7 +892,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[sc_keys]): "some_other_name" }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # sc_hash should not be warm-started. Var corresponding to sc_vocab # should be correctly warm-started after vocab remapping. @@ -933,7 +933,7 @@ class WarmStartingUtilTest(test.TestCase): "linear_model/sc_vocab/weights", initializer=[[0.5], [1.], [2.], [3.]]) self._write_checkpoint(sess) - prev_keys_val = self.evaluate(sc_keys_weights) + prev_keys_val = sess.run(sc_keys_weights) # New graph, new session with warm-starting. with ops.Graph().as_default() as g: @@ -955,7 +955,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[sc_keys]): "some_other_name" }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # sc_hash should not be warm-started. Var corresponding to sc_vocab # should be correctly warm-started after vocab remapping. @@ -1024,7 +1024,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[sc_keys]): "some_other_name" }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # sc_vocab should be correctly warm-started after vocab remapping, # and neither of the other two should be warm-started.. @@ -1091,7 +1091,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[emb_vocab_column]): vocab_info }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # emb_vocab_column should be correctly warm-started after vocab # remapping. Missing values are filled in with the EmbeddingColumn's @@ -1163,7 +1163,7 @@ class WarmStartingUtilTest(test.TestCase): var_name_to_vocab_info={ "linear_model/sc_vocab_embedding/embedding_weights": vocab_info }) - self.evaluate(variables.global_variables_initializer()) + sess.run(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # emb_vocab should be correctly warm-started after vocab remapping. # Missing values are filled in with the EmbeddingColumn's initializer. -- GitLab From f22eec10b6c30b6ce1b6a05f0ac4dc69e9b237f4 Mon Sep 17 00:00:00 2001 From: Mark Heffernan Date: Wed, 21 Nov 2018 11:17:40 -0800 Subject: [PATCH 211/672] Replace ProgramShape proto with a C++ class. Rename the protobuf message ProgramShape to ProgramShapeProto and create a new ProgramShape C++ class with an interface which mirrors the protobuf generated code interface. This CL is a step toward replacing Shape proto with a C++ class. ProgramShape needs to be migrated first because ProgramShape contains Shapes. PiperOrigin-RevId: 222435461 --- tensorflow/compiler/aot/codegen.cc | 19 +-- tensorflow/compiler/aot/codegen.h | 2 +- tensorflow/compiler/aot/codegen_test.cc | 16 +-- tensorflow/compiler/aot/codegen_test_h.golden | 10 +- tensorflow/compiler/aot/codegen_test_o.golden | Bin 712 -> 720 bytes tensorflow/compiler/aot/compile.cc | 4 +- tensorflow/compiler/aot/compile.h | 6 +- .../compiler/aot/tests/tfcompile_test.cc | 2 +- .../tf2xla/xla_compiled_cpu_function.h | 10 +- .../tf2xla/xla_jit_compiled_cpu_function.cc | 3 +- .../tf2xla/xla_jit_compiled_cpu_function.h | 6 +- .../xla_jit_compiled_cpu_function_test.cc | 2 +- tensorflow/compiler/xla/BUILD | 19 +++ tensorflow/compiler/xla/client/BUILD | 1 + tensorflow/compiler/xla/client/xla_builder.cc | 5 +- .../compiler/xla/client/xla_computation.cc | 2 +- .../compiler/xla/client/xla_computation.h | 1 + tensorflow/compiler/xla/layout_util.h | 1 + .../xla/python/local_computation_builder.cc | 9 +- .../xla/service/compile_only_service.cc | 6 +- tensorflow/compiler/xla/service/hlo.proto | 5 +- .../compiler/xla/service/hlo_computation.cc | 2 +- tensorflow/compiler/xla/service/hlo_module.cc | 4 +- .../compiler/xla/service/local_service.cc | 2 +- tensorflow/compiler/xla/service/service.cc | 12 +- tensorflow/compiler/xla/shape.cc | 62 ++++++++++ tensorflow/compiler/xla/shape.h | 108 +++++++++++++++++ tensorflow/compiler/xla/shape_test.cc | 112 ++++++++++++++++++ tensorflow/compiler/xla/shape_util.cc | 14 +++ tensorflow/compiler/xla/shape_util.h | 2 + tensorflow/compiler/xla/shape_util_test.cc | 31 ----- tensorflow/compiler/xla/tests/replay_test.cc | 9 +- tensorflow/compiler/xla/xla_data.proto | 2 +- .../compiler/xrt/kernels/xrt_compile_ops.cc | 11 +- tensorflow/compiler/xrt/tests/raw_api_test.cc | 10 +- tensorflow/compiler/xrt/xrt.proto | 4 +- 36 files changed, 408 insertions(+), 106 deletions(-) create mode 100644 tensorflow/compiler/xla/shape.cc create mode 100644 tensorflow/compiler/xla/shape.h create mode 100644 tensorflow/compiler/xla/shape_test.cc diff --git a/tensorflow/compiler/aot/codegen.cc b/tensorflow/compiler/aot/codegen.cc index b17bc658fa..697599f3bb 100644 --- a/tensorflow/compiler/aot/codegen.cc +++ b/tensorflow/compiler/aot/codegen.cc @@ -164,7 +164,8 @@ string RewriteWithName(const string& name, string code, } // Generate methods for args (inputs). -Status GenArgMethods(const tf2xla::Config& config, const xla::ProgramShape& ps, +Status GenArgMethods(const tf2xla::Config& config, + const xla::ProgramShapeProto& ps, const CompileResult& compile_result, string* methods) { size_t num_args = ps.parameters_size(); if (config.feed_size() != num_args) { @@ -204,7 +205,7 @@ Status GenArgMethods(const tf2xla::Config& config, const xla::ProgramShape& ps, // Generate methods for results (outputs). Status GenResultMethods(const tf2xla::Config& config, - const xla::ProgramShape& ps, string* methods) { + const xla::ProgramShapeProto& ps, string* methods) { if (ps.result().element_type() != xla::TUPLE) { // The XlaCompiler we use to build the xla computation always generates a // tuple result, and we rely on this to simplify code generation. @@ -336,7 +337,7 @@ Status GenerateHeader(const CodegenOpts& opts, const tf2xla::Config& config, ExtractEntryParamBufferInfos(buffer_infos); std::vector buffer_infos_for_temps = ExtractTempBufferInfos(buffer_infos); - const xla::ProgramShape& ps = compile_result.program_shape; + const xla::ProgramShapeProto& ps = compile_result.program_shape; string methods_arg, methods_result; TF_RETURN_IF_ERROR(GenArgMethods(config, ps, compile_result, &methods_arg)); TF_RETURN_IF_ERROR(GenResultMethods(config, ps, &methods_result)); @@ -548,8 +549,8 @@ class {{CLASS}} : public tensorflow::XlaCompiledCpuFunction { static const char** StaticResultNames() {{RESULT_NAMES_CODE}} // Shape of the args and results. - static const xla::ProgramShape* StaticProgramShape() { - static const xla::ProgramShape* kShape = {{PROGRAM_SHAPE_SHIM_EXPRESSION}}; + static const xla::ProgramShapeProto* StaticProgramShape() { + static const xla::ProgramShapeProto* kShape = {{PROGRAM_SHAPE_SHIM_EXPRESSION}}; return kShape; } @@ -615,11 +616,11 @@ static string CreateUniqueIdentifier(const CodegenOpts& opts, Status GenerateMetadata(const CodegenOpts& opts, const CompileResult& compile_result, MetadataResult* metadata_result) { - std::unique_ptr program_shape; + std::unique_ptr program_shape; if (opts.gen_program_shape) { program_shape = - absl::make_unique(compile_result.program_shape); + absl::make_unique(compile_result.program_shape); // The parameter names are currently meaningless, and redundant with the // rest of our metadata, so clear them out to avoid confusion and save @@ -631,8 +632,8 @@ Status GenerateMetadata(const CodegenOpts& opts, // a shim that evaluates to nullptr, which is what we want. ProtobufToEmbed program_shape_protobuf{ - CreateUniqueIdentifier(opts, "ProgramShape"), "xla::ProgramShape", - program_shape.get()}; + CreateUniqueIdentifier(opts, "ProgramShapeProto"), + "xla::ProgramShapeProto", program_shape.get()}; ProtobufToEmbed hlo_profile_printer_data_protobuf{ CreateUniqueIdentifier(opts, "HloProfilePrinterData"), diff --git a/tensorflow/compiler/aot/codegen.h b/tensorflow/compiler/aot/codegen.h index 90410c46a8..9485e86b10 100644 --- a/tensorflow/compiler/aot/codegen.h +++ b/tensorflow/compiler/aot/codegen.h @@ -57,7 +57,7 @@ struct MetadataResult { std::vector header_variable_decls; // program_shape_access_shim is a C++ expression that constructs the - // xla::ProgramShape instance for the CompileResult passed to + // xla::ProgramShapeProto instance for the CompileResult passed to // GenerateMetadata. string program_shape_access_shim; diff --git a/tensorflow/compiler/aot/codegen_test.cc b/tensorflow/compiler/aot/codegen_test.cc index bb288d2300..c1788ca32a 100644 --- a/tensorflow/compiler/aot/codegen_test.cc +++ b/tensorflow/compiler/aot/codegen_test.cc @@ -181,13 +181,15 @@ TEST(CodegenTest, Golden) { BufferInfo::MakeEntryParameter(/*size=*/96, /*param_number=*/1), BufferInfo::MakeTempBuffer(3), BufferInfo::MakeTempBuffer(120)}, 5, {})); - compile_result.program_shape = xla::ShapeUtil::MakeProgramShape( - { - xla::ShapeUtil::MakeShape(xla::F32, {1, 2}), - xla::ShapeUtil::MakeShape(xla::S64, {3, 4}), - }, - xla::ShapeUtil::MakeTupleShape( - {xla::ShapeUtil::MakeShape(xla::U32, {5, 6})})); + compile_result.program_shape = + xla::ShapeUtil::MakeProgramShape( + { + xla::ShapeUtil::MakeShape(xla::F32, {1, 2}), + xla::ShapeUtil::MakeShape(xla::S64, {3, 4}), + }, + xla::ShapeUtil::MakeTupleShape( + {xla::ShapeUtil::MakeShape(xla::U32, {5, 6})})) + .ToProto(); compile_result.entry_point = "entry_point"; compile_result.pointer_size = 8; diff --git a/tensorflow/compiler/aot/codegen_test_h.golden b/tensorflow/compiler/aot/codegen_test_h.golden index e4d8a02877..a2cdab5d1a 100644 --- a/tensorflow/compiler/aot/codegen_test_h.golden +++ b/tensorflow/compiler/aot/codegen_test_h.golden @@ -22,7 +22,7 @@ extern "C" void entry_point( void* result, const xla::ExecutableRunOptions* run_options, const void** args, void** temps, tensorflow::int64* profile_counters); -extern "C" char __tfcompile_foo_bar_MyClass_ProgramShape_protobuf_array_contents[]; +extern "C" char __tfcompile_foo_bar_MyClass_ProgramShapeProto_protobuf_array_contents[]; namespace foo { @@ -253,10 +253,10 @@ class MyClass : public tensorflow::XlaCompiledCpuFunction { } // Shape of the args and results. - static const xla::ProgramShape* StaticProgramShape() { - static const xla::ProgramShape* kShape = []() { - xla::ProgramShape* proto = new xla::ProgramShape; - proto->ParseFromArray(&__tfcompile_foo_bar_MyClass_ProgramShape_protobuf_array_contents[0], 52); + static const xla::ProgramShapeProto* StaticProgramShape() { + static const xla::ProgramShapeProto* kShape = []() { + xla::ProgramShapeProto* proto = new xla::ProgramShapeProto; + proto->ParseFromArray(&__tfcompile_foo_bar_MyClass_ProgramShapeProto_protobuf_array_contents[0], 52); return proto; }(); return kShape; diff --git a/tensorflow/compiler/aot/codegen_test_o.golden b/tensorflow/compiler/aot/codegen_test_o.golden index eb001c5d45bdfefc76629d7303d89f5480432235..ce8e5ec8c96a2c3696f14b8eea206d648182ecb5 100644 GIT binary patch delta 82 zcmX@XdVzI<24lcP&2+}ti4)^k1B&uX@+ZEZ$-%(DP{hE%z&tsSQF!tKMh?cV$txM- g8Ji|^GTF2GGB7YOf@KnzG+3(`7#Ntqyah}e0OJr9Qvd(} delta 49 zcmcb>dV+O=2BXJB&2+|yi4)@{ewoRbJ9#3bJY(zRjg0Y(wUY&z>=`{K2Qt|+mQJ3? GWDfwepb$g= diff --git a/tensorflow/compiler/aot/compile.cc b/tensorflow/compiler/aot/compile.cc index 2b5f97b34c..3bc99ef7e6 100644 --- a/tensorflow/compiler/aot/compile.cc +++ b/tensorflow/compiler/aot/compile.cc @@ -56,8 +56,8 @@ Status CompileXla(xla::CompileOnlyClient* client, return errors::Unknown("Couldn't get XLA program shape: ", pshape_or.status().error_message()); } - compile_result->program_shape = *pshape_or.ValueOrDie(); - xla::ProgramShape* pshape = &compile_result->program_shape; + compile_result->program_shape = pshape_or.ValueOrDie()->ToProto(); + xla::ProgramShapeProto* pshape = &compile_result->program_shape; std::vector arg_layouts; arg_layouts.reserve(pshape->parameters_size()); for (int i = 0; i < pshape->parameters_size(); ++i) { diff --git a/tensorflow/compiler/aot/compile.h b/tensorflow/compiler/aot/compile.h index e03c5b1aa7..ee7bb26fab 100644 --- a/tensorflow/compiler/aot/compile.h +++ b/tensorflow/compiler/aot/compile.h @@ -33,9 +33,9 @@ namespace tfcompile { struct CompileResult { // Contains object file and meta-info. std::unique_ptr aot; - xla::ProgramShape program_shape; // Static shape of args and results. - string entry_point; // Name of generated function. - int pointer_size = 0; // Size of a pointer in bytes. + xla::ProgramShapeProto program_shape; // Static shape of args and results. + string entry_point; // Name of generated function. + int pointer_size = 0; // Size of a pointer in bytes. }; // CompileGraph compiles the graph_def into an object file containing a function diff --git a/tensorflow/compiler/aot/tests/tfcompile_test.cc b/tensorflow/compiler/aot/tests/tfcompile_test.cc index f10852c785..711feed8f3 100644 --- a/tensorflow/compiler/aot/tests/tfcompile_test.cc +++ b/tensorflow/compiler/aot/tests/tfcompile_test.cc @@ -526,7 +526,7 @@ TEST(TFCompileTest, ProgramShape) { // muladd has the program shape defined. MatMulAndAddComp muladd; - const xla::ProgramShape* muladd_shape = muladd.ProgramShape(); + const xla::ProgramShapeProto* muladd_shape = muladd.ProgramShape(); ASSERT_TRUE(muladd_shape != nullptr); ASSERT_EQ(muladd_shape->parameters_size(), 2); EXPECT_TRUE(ShapeUtil::Compatible(muladd_shape->parameters(0), f32_2x2)); diff --git a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h index 66206909a9..a1d359e97c 100644 --- a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h +++ b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h @@ -26,7 +26,7 @@ limitations under the License. // Forward-declare, rather than include, to reduce code size for users that // never use this functionality. namespace xla { -class ProgramShape; +class ProgramShapeProto; class HloProfilePrinterData; } @@ -84,7 +84,7 @@ class XlaCompiledCpuFunction { void set_result_names(const char** result_names) { result_names_ = result_names; } - void set_program_shape(const xla::ProgramShape* program_shape) { + void set_program_shape(const xla::ProgramShapeProto* program_shape) { program_shape_ = program_shape; } const xla::HloProfilePrinterData* hlo_profile_printer_data() const { @@ -122,7 +122,7 @@ class XlaCompiledCpuFunction { const char** result_names_ = nullptr; // [Optional] Arg and result shapes. - const xla::ProgramShape* program_shape_ = nullptr; + const xla::ProgramShapeProto* program_shape_ = nullptr; // [Optional] Profile printer data. Null if profiling is disabled. const xla::HloProfilePrinterData* hlo_profile_printer_data_ = nullptr; @@ -264,7 +264,7 @@ class XlaCompiledCpuFunction { // Returns the shape of the args and results. May return nullptr if the // program shape isn't available. - const xla::ProgramShape* ProgramShape() const { return program_shape_; } + const xla::ProgramShapeProto* ProgramShape() const { return program_shape_; } bool hlo_profiling_enabled() const { return hlo_profile_printer_data_ != nullptr; @@ -305,7 +305,7 @@ class XlaCompiledCpuFunction { // Optional metadata. const char** arg_names_ = nullptr; const char** result_names_ = nullptr; - const xla::ProgramShape* program_shape_ = nullptr; + const xla::ProgramShapeProto* program_shape_ = nullptr; const xla::HloProfilePrinterData* hlo_profile_printer_data_ = nullptr; }; diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc index 86a78ee429..fabbcd04fe 100644 --- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc +++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc @@ -133,7 +133,8 @@ XlaJitCompiledCpuFunction::Compile( jit->executable_ = std::move(executable); jit->buffer_infos_ = std::move(buffer_infos); jit->arg_index_table_ = std::move(arg_index_table); - jit->program_shape_ = std::move(program_shape); + jit->program_shape_ = + absl::make_unique(program_shape->ToProto()); jit->static_data_.set_raw_function(raw_function); jit->static_data_.set_buffer_infos(jit->buffer_infos_.data()); jit->static_data_.set_num_buffers(jit->buffer_infos_.size()); diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h index d3c8f22a80..a539205717 100644 --- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h +++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h @@ -80,8 +80,10 @@ class XlaJitCompiledCpuFunction { std::vector arg_names_; std::vector result_names_; - // The backing data for the program shape. - std::unique_ptr program_shape_; + // The backing data for the program shape. The proto form of program shape is + // used because the program shape is serialized and embedded in the object + // file. + std::unique_ptr program_shape_; }; } // namespace tensorflow diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc index 6d49298a6f..4496255d00 100644 --- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc +++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc @@ -116,7 +116,7 @@ TEST(XlaJitCompiledCpuFunction, Sum) { // Check program shape. using xla::ShapeUtil; const xla::Shape s32 = ShapeUtil::MakeShape(xla::S32, {}); - const xla::ProgramShape* program_shape = function.ProgramShape(); + const xla::ProgramShapeProto* program_shape = function.ProgramShape(); ASSERT_TRUE(program_shape != nullptr); ASSERT_EQ(program_shape->parameters_size(), 2); EXPECT_TRUE(ShapeUtil::Compatible(program_shape->parameters(0), s32)); diff --git a/tensorflow/compiler/xla/BUILD b/tensorflow/compiler/xla/BUILD index d914e97b6b..4360e08579 100644 --- a/tensorflow/compiler/xla/BUILD +++ b/tensorflow/compiler/xla/BUILD @@ -226,12 +226,14 @@ cc_library( "index_util.cc", "layout_util.cc", "primitive_util.cc", + "shape.cc", "shape_util.cc", ], hdrs = [ "index_util.h", "layout_util.h", "primitive_util.h", + "shape.h", "shape_util.h", ], visibility = ["//visibility:public"], @@ -254,6 +256,23 @@ cc_library( ], ) +tf_cc_test( + name = "shape_test", + srcs = ["shape_test.cc"], + deps = [ + ":shape_util", + ":status_macros", + ":test", + ":test_helpers", + ":types", + ":util", + ":xla_data_proto", + "//tensorflow/core:lib", + "//tensorflow/core:test_main", + "@com_google_absl//absl/strings", + ], +) + tf_cc_test( name = "shape_util_test", srcs = ["shape_util_test.cc"], diff --git a/tensorflow/compiler/xla/client/BUILD b/tensorflow/compiler/xla/client/BUILD index 42da0ebf49..e1f3674c4f 100644 --- a/tensorflow/compiler/xla/client/BUILD +++ b/tensorflow/compiler/xla/client/BUILD @@ -191,6 +191,7 @@ cc_library( hdrs = ["xla_computation.h"], visibility = ["//visibility:public"], deps = [ + "//tensorflow/compiler/xla:shape_util", "//tensorflow/compiler/xla:status_macros", "//tensorflow/compiler/xla:util", "//tensorflow/compiler/xla:xla_data_proto", diff --git a/tensorflow/compiler/xla/client/xla_builder.cc b/tensorflow/compiler/xla/client/xla_builder.cc index f508ffb9c9..8a33b3930f 100644 --- a/tensorflow/compiler/xla/client/xla_builder.cc +++ b/tensorflow/compiler/xla/client/xla_builder.cc @@ -288,7 +288,8 @@ StatusOr XlaBuilder::Build(int64 root_id) { HloComputationProto entry; SetProtoIdAndName(&entry, name_, kNameSeparator, GetNextId()); - TF_ASSIGN_OR_RETURN(*entry.mutable_program_shape(), GetProgramShape(root_id)); + TF_ASSIGN_OR_RETURN(ProgramShape program_shape, GetProgramShape(root_id)); + *entry.mutable_program_shape() = program_shape.ToProto(); entry.set_root_id(root_id); for (auto& instruction : instructions_) { @@ -2372,7 +2373,7 @@ StatusOr XlaBuilder::BuildConstantSubGraph( SetProtoIdAndName(&entry, StrCat(name_, "_compute_constant"), kNameSeparator, GetNextId()); entry.set_root_id(root->id()); - ProgramShape* program_shape = entry.mutable_program_shape(); + ProgramShapeProto* program_shape = entry.mutable_program_shape(); *program_shape->mutable_result() = root->shape(); // We use std::set to keep the instruction ids in ascending order (which is diff --git a/tensorflow/compiler/xla/client/xla_computation.cc b/tensorflow/compiler/xla/client/xla_computation.cc index c9870b65b9..f317892c12 100644 --- a/tensorflow/compiler/xla/client/xla_computation.cc +++ b/tensorflow/compiler/xla/client/xla_computation.cc @@ -25,7 +25,7 @@ namespace xla { StatusOr XlaComputation::GetProgramShape() const { TF_RET_CHECK(proto_.has_host_program_shape()); - return proto_.host_program_shape(); + return ProgramShape(proto_.host_program_shape()); } StatusOr> XlaComputation::Snapshot() const { diff --git a/tensorflow/compiler/xla/client/xla_computation.h b/tensorflow/compiler/xla/client/xla_computation.h index 71598ef8b2..3ccbfb28bd 100644 --- a/tensorflow/compiler/xla/client/xla_computation.h +++ b/tensorflow/compiler/xla/client/xla_computation.h @@ -19,6 +19,7 @@ limitations under the License. #include #include "tensorflow/compiler/xla/service/hlo.pb.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/status_macros.h" #include "tensorflow/compiler/xla/xla_data.pb.h" diff --git a/tensorflow/compiler/xla/layout_util.h b/tensorflow/compiler/xla/layout_util.h index 6e0390763d..6c298e5725 100644 --- a/tensorflow/compiler/xla/layout_util.h +++ b/tensorflow/compiler/xla/layout_util.h @@ -21,6 +21,7 @@ limitations under the License. #include #include "absl/types/span.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/status.h" #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" diff --git a/tensorflow/compiler/xla/python/local_computation_builder.cc b/tensorflow/compiler/xla/python/local_computation_builder.cc index 4d2a37cfac..2768ed618d 100644 --- a/tensorflow/compiler/xla/python/local_computation_builder.cc +++ b/tensorflow/compiler/xla/python/local_computation_builder.cc @@ -487,12 +487,13 @@ StatusOr LocalComputation::CompileForXrt( xrt::XLAComputation c; auto config = c.mutable_config(); - auto shapes = config->mutable_program_shape(); + ProgramShape shapes; for (auto& shape : argument_shapes) { - *shapes->add_parameters() = shape; + *shapes.add_parameters() = shape; } - TF_ASSIGN_OR_RETURN(*shapes->mutable_result(), GetReturnValueShape()); - LayoutUtil::SetToDefaultLayout(shapes); + TF_ASSIGN_OR_RETURN(*shapes.mutable_result(), GetReturnValueShape()); + LayoutUtil::SetToDefaultLayout(&shapes); + *config->mutable_program_shape() = shapes.ToProto(); auto snapshot = computation().Snapshot().ValueOrDie(); *c.mutable_hlo_snapshot() = *snapshot; diff --git a/tensorflow/compiler/xla/service/compile_only_service.cc b/tensorflow/compiler/xla/service/compile_only_service.cc index 67132274c0..0237f16673 100644 --- a/tensorflow/compiler/xla/service/compile_only_service.cc +++ b/tensorflow/compiler/xla/service/compile_only_service.cc @@ -86,15 +86,15 @@ CompileOnlyService::CompileAheadOfTime( Executable::DumpToDirectory(per_host_path, filename, hlo_snapshot)); } - const auto& program_shape = instance.computation.host_program_shape(); ExecutionOptions execution_options; *execution_options.mutable_debug_options() = debug_options; *execution_options.mutable_shape_with_output_layout() = *instance.result_layout; TF_ASSIGN_OR_RETURN( std::unique_ptr module_config, - CreateModuleConfig(program_shape, instance.argument_layouts, - &execution_options)); + CreateModuleConfig( + ProgramShape(instance.computation.host_program_shape()), + instance.argument_layouts, &execution_options)); TF_ASSIGN_OR_RETURN( std::unique_ptr hlo_module, diff --git a/tensorflow/compiler/xla/service/hlo.proto b/tensorflow/compiler/xla/service/hlo.proto index 913d4c34b4..c62c935af7 100644 --- a/tensorflow/compiler/xla/service/hlo.proto +++ b/tensorflow/compiler/xla/service/hlo.proto @@ -205,7 +205,8 @@ message HloComputationProto { repeated HloInstructionProto instructions = 2; // The program shape (with layout) of this computation. - xla.ProgramShape program_shape = 4; + + xla.ProgramShapeProto program_shape = 4; // The id of this computation. int64 id = 5; @@ -297,7 +298,7 @@ message HloModuleProto { repeated HloComputationProto computations = 3; // The host program shape (with layout) of the entry computation. - xla.ProgramShape host_program_shape = 4; + xla.ProgramShapeProto host_program_shape = 4; // The id of this module. int64 id = 5; diff --git a/tensorflow/compiler/xla/service/hlo_computation.cc b/tensorflow/compiler/xla/service/hlo_computation.cc index 65bd251dd8..d06c2207cb 100644 --- a/tensorflow/compiler/xla/service/hlo_computation.cc +++ b/tensorflow/compiler/xla/service/hlo_computation.cc @@ -499,7 +499,7 @@ HloComputationProto HloComputation::ToProto() const { proto.add_instructions()->Swap(&instruction_proto); } proto.set_root_id(root_instruction()->unique_id()); - *proto.mutable_program_shape() = ComputeProgramShape(); + *proto.mutable_program_shape() = ComputeProgramShape().ToProto(); return proto; } diff --git a/tensorflow/compiler/xla/service/hlo_module.cc b/tensorflow/compiler/xla/service/hlo_module.cc index 59f44475df..a01853fe1f 100644 --- a/tensorflow/compiler/xla/service/hlo_module.cc +++ b/tensorflow/compiler/xla/service/hlo_module.cc @@ -240,7 +240,7 @@ HloModuleProto HloModule::ToProto() const { *proto.mutable_schedule() = schedule().ToProto().ValueOrDie(); } *proto.mutable_host_program_shape() = - entry_computation_layout().ComputeProgramShape(); + entry_computation_layout().ComputeProgramShape().ToProto(); *proto.mutable_input_output_alias() = input_output_alias_config().ToProto(); *proto.mutable_dynamic_parameter_binding() = dynamic_parameter_binding().ToProto(); @@ -371,7 +371,7 @@ StatusOr HloModule::CreateModuleConfigFromProto( << "No program shape found in the proto"; const auto& program_shape = module.host_program_shape(); - HloModuleConfig module_config(program_shape); + HloModuleConfig module_config(ProgramShape{program_shape}); module_config.set_debug_options(debug_options); // The module config is constructed with default layouts regardless of what is diff --git a/tensorflow/compiler/xla/service/local_service.cc b/tensorflow/compiler/xla/service/local_service.cc index 2180ac845d..5c105908f3 100644 --- a/tensorflow/compiler/xla/service/local_service.cc +++ b/tensorflow/compiler/xla/service/local_service.cc @@ -145,7 +145,7 @@ StatusOr> LocalService::CompileExecutable( const ExecutableBuildOptions& build_options) { const HloModuleProto& proto = computation.proto(); TF_RET_CHECK(proto.has_host_program_shape()); - const ProgramShape& program_shape = proto.host_program_shape(); + ProgramShape program_shape(proto.host_program_shape()); // Validate incoming layouts. if (argument_layouts.size() != program_shape.parameters_size()) { diff --git a/tensorflow/compiler/xla/service/service.cc b/tensorflow/compiler/xla/service/service.cc index 13fd6bc009..c4b0a5c080 100644 --- a/tensorflow/compiler/xla/service/service.cc +++ b/tensorflow/compiler/xla/service/service.cc @@ -658,9 +658,9 @@ Status Service::ExecuteGraphParallel(const ExecuteGraphParallelRequest* arg, // replica 0. TF_ASSIGN_OR_RETURN( std::unique_ptr module_config, - CreateModuleConfig(request.computation().host_program_shape(), - replicated_arguments.front(), - request.execution_options())); + CreateModuleConfig( + ProgramShape{request.computation().host_program_shape()}, + replicated_arguments.front(), request.execution_options())); VLOG(3) << "ExecuteGraphParallel created HloModuleConfig computation layout: " << module_config->entry_computation_layout().ToString(); @@ -824,7 +824,7 @@ Status Service::Compile(const CompileRequest* arg, CompileResponse* result) { [](const Shape& shape) { return &shape; }); TF_ASSIGN_OR_RETURN( std::unique_ptr module_config, - CreateModuleConfig(arg->computation().host_program_shape(), + CreateModuleConfig(ProgramShape{arg->computation().host_program_shape()}, argument_shapes, &arg->execution_options())); VLOG(3) << "Compile created HloModuleConfig computation layout: " << module_config->entry_computation_layout().ToString(); @@ -1072,7 +1072,7 @@ Status Service::ComputeConstantGraph(const ComputeConstantGraphRequest* arg, "constant computation may not depend on any parameters."); } - ProgramShape program_shape = arg->computation().host_program_shape(); + ProgramShape program_shape(arg->computation().host_program_shape()); TF_DCHECK_OK(ShapeUtil::ValidateShape(program_shape.result())); if (arg->has_output_layout()) { TF_RETURN_IF_ERROR(LayoutUtil::ValidateLayoutForShape( @@ -1116,7 +1116,7 @@ Status Service::GetComputationGraphStats( return InvalidArgument("Program shape may not be empty."); } - HloModuleConfig config(arg->computation().host_program_shape()); + HloModuleConfig config(ProgramShape{arg->computation().host_program_shape()}); config.set_debug_options(arg->debug_options()); TF_ASSIGN_OR_RETURN(std::unique_ptr module, CreateModuleFromProto(arg->computation(), config)); diff --git a/tensorflow/compiler/xla/shape.cc b/tensorflow/compiler/xla/shape.cc new file mode 100644 index 0000000000..d209389c74 --- /dev/null +++ b/tensorflow/compiler/xla/shape.cc @@ -0,0 +1,62 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/compiler/xla/shape.h" + +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "tensorflow/compiler/xla/shape_util.h" + +namespace xla { + +ProgramShape::ProgramShape(const ProgramShapeProto& program_shape_proto) { + for (const Shape& shape : program_shape_proto.parameters()) { + *add_parameters() = shape; + } + *mutable_result() = program_shape_proto.result(); + for (const string& name : program_shape_proto.parameter_names()) { + add_parameter_names(name); + } +} + +ProgramShapeProto ProgramShape::ToProto() const { + ProgramShapeProto proto; + for (const Shape& shape : parameters()) { + *proto.add_parameters() = shape; + } + *proto.mutable_result() = result(); + for (const string& name : parameter_names()) { + proto.add_parameter_names(name); + } + return proto; +} + +string ProgramShape::ToString() const { + std::vector parameter_strings(parameters_size()); + for (int i = 0; i < parameters_size(); ++i) { + parameter_strings[i] = absl::StrCat( + i < parameter_names_size() ? parameter_names(i) : "(unknown)", ": ", + ShapeUtil::HumanString(parameters(i))); + } + return absl::StrCat("(", absl::StrJoin(parameter_strings, ", "), ") -> ", + ShapeUtil::HumanString(result())); +} + +std::ostream& operator<<(std::ostream& out, const ProgramShape& program_shape) { + out << program_shape.ToString() << "\n"; + return out; +} + +} // namespace xla diff --git a/tensorflow/compiler/xla/shape.h b/tensorflow/compiler/xla/shape.h new file mode 100644 index 0000000000..c3aecb1736 --- /dev/null +++ b/tensorflow/compiler/xla/shape.h @@ -0,0 +1,108 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_COMPILER_XLA_SHAPE_H_ +#define TENSORFLOW_COMPILER_XLA_SHAPE_H_ + +#include +#include + +#include "absl/types/optional.h" +#include "tensorflow/compiler/xla/types.h" +#include "tensorflow/compiler/xla/xla_data.pb.h" +#include "tensorflow/core/platform/types.h" + +namespace xla { + +// Shape of the parameters and output of an XLA computation. This is analogous +// to a traditional function signature. +class ProgramShape { + public: + ProgramShape() = default; + + // Creates a ProgramShape from a ProgramShapeProto protobuf. + explicit ProgramShape(const ProgramShapeProto& program_shape_proto); + + // Returns a proto representation of the object. + ProgramShapeProto ToProto() const; + + string ToString() const; + + // The following methods mirror the protobuf generated code interface for the + // message ProgramShapeProto. This enabled easy migration of this data + // structure from a proto to a proper C++ class. + // TODO(b/29771030): Replace or augment these methods with a more ergonomic + // interface. + + // Methods for accessing and manipulating the Shape of the parameters. + int parameters_size() const { return parameters_.size(); } + const Shape& parameters(int index) const { return parameters_.at(index); } + Shape* mutable_parameters(int index) { return ¶meters_.at(index); } + Shape* add_parameters() { + parameters_.emplace_back(); + return ¶meters_.back(); + } + void clear_parameters() { parameters_.clear(); } + const std::vector& parameters() const { return parameters_; } + std::vector* mutable_parameters() { return ¶meters_; } + + // Methods for accessing and manipulating the Shape of the result. + const Shape& result() const { return result_; } + Shape* mutable_result() { return &result_; } + void clear_result() { result_.Clear(); } + + // Methods for accessing and manipulating the names of the parameters. + int parameter_names_size() const { return parameter_names_.size(); } + const string& parameter_names(int index) const { + return parameter_names_.at(index); + } + void set_parameter_names(int index, const string& value) { + parameter_names_.at(index) = value; + } + string* mutable_parameter_names(int index) { + return ¶meter_names_.at(index); + } + void add_parameter_names(const string& value) { + parameter_names_.push_back(value); + } + string* add_parameter_names() { + parameter_names_.push_back(""); + return ¶meter_names_.back(); + } + void clear_parameter_names() { parameter_names_.clear(); } + const std::vector& parameter_names() const { + return parameter_names_; + } + std::vector* mutable_parameter_names() { return ¶meter_names_; } + + string ShortDebugString() const { return ToProto().ShortDebugString(); } + string DebugString() const { return ToProto().DebugString(); } + + private: + // The shapes of the parameters of the computation represented by this object. + std::vector parameters_; + + // The names of the parameters of the computation represented by this object. + std::vector parameter_names_; + + // The shape of the result of the computation represented by this object. + Shape result_; +}; + +std::ostream& operator<<(std::ostream& out, const ProgramShape& program_shape); + +} // namespace xla + +#endif // TENSORFLOW_COMPILER_XLA_SHAPE_H_ diff --git a/tensorflow/compiler/xla/shape_test.cc b/tensorflow/compiler/xla/shape_test.cc new file mode 100644 index 0000000000..cc3a5eb1d6 --- /dev/null +++ b/tensorflow/compiler/xla/shape_test.cc @@ -0,0 +1,112 @@ +/* Copyright 2017 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/compiler/xla/shape.h" + +#include +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "tensorflow/compiler/xla/layout_util.h" +#include "tensorflow/compiler/xla/shape_util.h" +#include "tensorflow/compiler/xla/status_macros.h" +#include "tensorflow/compiler/xla/test.h" +#include "tensorflow/compiler/xla/test_helpers.h" +#include "tensorflow/compiler/xla/types.h" +#include "tensorflow/compiler/xla/util.h" +#include "tensorflow/compiler/xla/xla_data.pb.h" + +namespace xla { +namespace { + +TEST(ShapeTest, ProgramShapeToFromProto) { + ProgramShape program_shape; + *program_shape.add_parameters() = ShapeUtil::MakeShape(F32, {1, 2, 3}); + *program_shape.add_parameters() = ShapeUtil::MakeTokenShape(); + *program_shape.add_parameters() = ShapeUtil::MakeShape(S64, {}); + *program_shape.add_parameters() = ShapeUtil::MakeTupleShape( + {ShapeUtil::MakeShape(S32, {}), + ShapeUtil::MakeTupleShape({ShapeUtil::MakeTokenShape()}), + ShapeUtil::MakeShape(F32, {42, 42})}); + + *program_shape.mutable_result() = ShapeUtil::MakeShape(F32, {7}); + + program_shape.add_parameter_names("foo"); + program_shape.add_parameter_names("bar"); + program_shape.add_parameter_names("baz"); + program_shape.add_parameter_names("qux qux"); + + // Create a copy of the program shape by round-tripping through a proto. + ProgramShape program_shape_copy(program_shape.ToProto()); + ASSERT_EQ(program_shape.parameters_size(), + program_shape_copy.parameters_size()); + for (int i = 0; i < program_shape.parameters_size(); ++i) { + EXPECT_TRUE(ShapeUtil::Equal(program_shape.parameters(i), + program_shape_copy.parameters(i))); + } + + EXPECT_TRUE( + ShapeUtil::Equal(program_shape.result(), program_shape_copy.result())); + + ASSERT_EQ(program_shape.parameter_names_size(), + program_shape_copy.parameter_names_size()); + for (int i = 0; i < program_shape.parameter_names_size(); ++i) { + EXPECT_EQ(program_shape.parameter_names(i), + program_shape_copy.parameter_names(i)); + } +} + +TEST(ShapeTest, ProgramShapeToString) { + Shape opaque = ShapeUtil::MakeOpaqueShape(); + Shape token = ShapeUtil::MakeTokenShape(); + Shape scalar = ShapeUtil::MakeShape(F32, {}); + Shape matrix = ShapeUtil::MakeShape(U32, {1, 2}); + Shape matrix2 = ShapeUtil::MakeShapeWithLayout(S32, {3, 4}, {0, 1}); + Shape tuple = ShapeUtil::MakeTupleShape({opaque, scalar, matrix, matrix2}); + Shape nested_tuple = ShapeUtil::MakeTupleShape({tuple, matrix, token}); + + ProgramShape prog = ShapeUtil::MakeProgramShape( + {opaque, scalar, matrix, matrix2, tuple, nested_tuple}, nested_tuple); + EXPECT_EQ( + "((unknown): opaque[], " + "(unknown): f32[], " + "(unknown): u32[1,2], " + "(unknown): s32[3,4], " + "(unknown): (opaque[], f32[], u32[1,2], s32[3,4]), " + "(unknown): ((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])) " + "-> " + "((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", + ShapeUtil::HumanString(prog)); + + prog.add_parameter_names("arg0"); + prog.add_parameter_names("scalar"); + prog.add_parameter_names("matrix"); + prog.add_parameter_names("matrix2"); + prog.add_parameter_names("tuple"); + prog.add_parameter_names("nested_tuple"); + EXPECT_EQ( + "(arg0: opaque[], " + "scalar: f32[], " + "matrix: u32[1,2], " + "matrix2: s32[3,4], " + "tuple: (opaque[], f32[], u32[1,2], s32[3,4]), " + "nested_tuple: ((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], " + "token[])) " + "-> " + "((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", + ShapeUtil::HumanString(prog)); +} + +} // namespace +} // namespace xla diff --git a/tensorflow/compiler/xla/shape_util.cc b/tensorflow/compiler/xla/shape_util.cc index 7d011bfc65..b05ec209cc 100644 --- a/tensorflow/compiler/xla/shape_util.cc +++ b/tensorflow/compiler/xla/shape_util.cc @@ -563,6 +563,20 @@ StatusOr StringToPrimitiveType(const string& name) { HumanString(program_shape.result())); } +/* static */ string ShapeUtil::HumanString( + const ProgramShapeProto& program_shape_proto) { + std::vector parameters; + for (auto& shape : program_shape_proto.parameters()) { + const int i = parameters.size(); + parameters.push_back(StrCat(i < program_shape_proto.parameter_names_size() + ? program_shape_proto.parameter_names(i) + : "(unknown)", + ": ", HumanString(shape))); + } + return StrCat("(", absl::StrJoin(parameters, ", "), ") -> ", + HumanString(program_shape_proto.result())); +} + namespace { // Parses shapes with simple recursive descent structure -- consumes from the // front of s and passes that view recursively as required. diff --git a/tensorflow/compiler/xla/shape_util.h b/tensorflow/compiler/xla/shape_util.h index 7f72e57d00..3796c5be5d 100644 --- a/tensorflow/compiler/xla/shape_util.h +++ b/tensorflow/compiler/xla/shape_util.h @@ -28,6 +28,7 @@ limitations under the License. #include "absl/types/span.h" #include "tensorflow/compiler/xla/layout_util.h" #include "tensorflow/compiler/xla/primitive_util.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/status_macros.h" #include "tensorflow/compiler/xla/statusor.h" #include "tensorflow/compiler/xla/types.h" @@ -239,6 +240,7 @@ class ShapeUtil { // // (param_name: f32[42x12], ...) -> f32[24x42] static string HumanString(const ProgramShape& program_shape); + static string HumanString(const ProgramShapeProto& program_shape_proto); // Parses a ShapeUtil::HumanString-format shape string back into a shape // object. diff --git a/tensorflow/compiler/xla/shape_util_test.cc b/tensorflow/compiler/xla/shape_util_test.cc index 11b493323c..ce6330a0dc 100644 --- a/tensorflow/compiler/xla/shape_util_test.cc +++ b/tensorflow/compiler/xla/shape_util_test.cc @@ -575,37 +575,6 @@ TEST(ShapeUtilTest, HumanString) { "((opaque[], f32[], u32[1,2]{1,0}, s32[3,4]{0,1}), u32[1,2]{1,0}, " "token[])", ShapeUtil::HumanStringWithLayout(nested_tuple)); - - ProgramShape prog = ShapeUtil::MakeProgramShape( - {opaque, scalar, matrix, matrix2, tuple, nested_tuple}, nested_tuple); - EXPECT_EQ( - "((unknown): opaque[], " - "(unknown): f32[], " - "(unknown): u32[1,2], " - "(unknown): s32[3,4], " - "(unknown): (opaque[], f32[], u32[1,2], s32[3,4]), " - "(unknown): ((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])) " - "-> " - "((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", - ShapeUtil::HumanString(prog)); - - prog.add_parameter_names("arg0"); - prog.add_parameter_names("scalar"); - prog.add_parameter_names("matrix"); - prog.add_parameter_names("matrix2"); - prog.add_parameter_names("tuple"); - prog.add_parameter_names("nested_tuple"); - EXPECT_EQ( - "(arg0: opaque[], " - "scalar: f32[], " - "matrix: u32[1,2], " - "matrix2: s32[3,4], " - "tuple: (opaque[], f32[], u32[1,2], s32[3,4]), " - "nested_tuple: ((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], " - "token[])) " - "-> " - "((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", - ShapeUtil::HumanString(prog)); } TEST(ShapeUtilTest, ForEachSubshapeArray) { diff --git a/tensorflow/compiler/xla/tests/replay_test.cc b/tensorflow/compiler/xla/tests/replay_test.cc index 5cf87e565b..34c7dc7c46 100644 --- a/tensorflow/compiler/xla/tests/replay_test.cc +++ b/tensorflow/compiler/xla/tests/replay_test.cc @@ -55,7 +55,8 @@ TEST_F(ReplayTest, TwoPlusTwoReplay) { client_->GetComputationShape(computation).ConsumeValueOrDie(); std::unique_ptr replayed_shape = client_->GetComputationShape(replayed).ConsumeValueOrDie(); - ASSERT_TRUE(protobuf_util::ProtobufEquals(*original_shape, *replayed_shape)); + ASSERT_TRUE(protobuf_util::ProtobufEquals(original_shape->ToProto(), + replayed_shape->ToProto())); // Run it. Literal literal = @@ -87,7 +88,8 @@ XLA_TEST_F(ReplayTest, XPlusYReplayWithParameters) { client_->GetComputationShape(computation).ConsumeValueOrDie(); std::unique_ptr replayed_shape = client_->GetComputationShape(replayed).ConsumeValueOrDie(); - ASSERT_TRUE(protobuf_util::ProtobufEquals(*original_shape, *replayed_shape)); + ASSERT_TRUE(protobuf_util::ProtobufEquals(original_shape->ToProto(), + replayed_shape->ToProto())); // Run it. std::unique_ptr x_data = @@ -133,7 +135,8 @@ TEST_F(ReplayTest, MapPlusTwoOverR1) { client_->GetComputationShape(computation).ConsumeValueOrDie(); std::unique_ptr replayed_shape = client_->GetComputationShape(replayed).ConsumeValueOrDie(); - ASSERT_TRUE(protobuf_util::ProtobufEquals(*original_shape, *replayed_shape)); + ASSERT_TRUE(protobuf_util::ProtobufEquals(original_shape->ToProto(), + replayed_shape->ToProto())); // Run it. Literal literal = diff --git a/tensorflow/compiler/xla/xla_data.proto b/tensorflow/compiler/xla/xla_data.proto index 683ccc40f1..27ef86ab2e 100644 --- a/tensorflow/compiler/xla/xla_data.proto +++ b/tensorflow/compiler/xla/xla_data.proto @@ -183,7 +183,7 @@ message Shape { // Shape of the parameters and output of a computation (like a traditional // function signature). -message ProgramShape { +message ProgramShapeProto { repeated Shape parameters = 1; Shape result = 2; repeated string parameter_names = 3; diff --git a/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc b/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc index dc62cf7a6b..db43aeaafe 100644 --- a/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc +++ b/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc @@ -174,11 +174,12 @@ void XRTCompileOp::Compute(OpKernelContext* ctx) { ctx->set_output(0, handle_output); xla::LocalExecutable* executable = entry->get().get_executable(); - xla::ProgramShape program_shape = executable->executable() - ->module() - .config() - .entry_computation_layout() - .ComputeProgramShape(); + xla::ProgramShapeProto program_shape = executable->executable() + ->module() + .config() + .entry_computation_layout() + .ComputeProgramShape() + .ToProto(); Tensor program_shape_output(DT_STRING, TensorShape({1})); program_shape_output.vec()(0) = program_shape.SerializeAsString(); ctx->set_output(1, program_shape_output); diff --git a/tensorflow/compiler/xrt/tests/raw_api_test.cc b/tensorflow/compiler/xrt/tests/raw_api_test.cc index 25464b5554..7e73db98f7 100644 --- a/tensorflow/compiler/xrt/tests/raw_api_test.cc +++ b/tensorflow/compiler/xrt/tests/raw_api_test.cc @@ -411,7 +411,7 @@ TEST(RawApiTest, CompileAndExecute) { auto expected = xla::LiteralUtil::CreateR1({27.0f, 21.0f}); EXPECT_TRUE(CompareLiteralToLiteralProto(expected, response)); - xla::ProgramShape program_shape; + xla::ProgramShapeProto program_shape; EXPECT_TRUE(program_shape.ParseFromString(outputs[1].vec()(0))); EXPECT_EQ(program_shape.parameters_size(), 2); } @@ -465,7 +465,7 @@ TEST(RawApiTest, CompileAndExecuteWithArgumentVector) { auto expected = xla::LiteralUtil::CreateR1({27.0f, 21.0f}); EXPECT_TRUE(CompareLiteralToLiteralProto(expected, response)); - xla::ProgramShape program_shape; + xla::ProgramShapeProto program_shape; EXPECT_TRUE(program_shape.ParseFromString(outputs[1].vec()(0))); EXPECT_EQ(program_shape.parameters_size(), 2); } @@ -510,7 +510,7 @@ TEST(RawApiTest, CompileWithXlaReturnShapes) { TF_EXPECT_OK(session.Run(tensorflow::ClientSession::FeedType(), {c_handle.program_shape}, {release}, &outputs)); - xla::ProgramShape program_shape; + xla::ProgramShapeProto program_shape; EXPECT_TRUE(program_shape.ParseFromString(outputs[0].vec()(0))); EXPECT_EQ(program_shape.parameters_size(), 1); @@ -520,7 +520,7 @@ TEST(RawApiTest, CompileWithXlaReturnShapes) { << xla::ShapeUtil::HumanStringWithLayout(program_shape.result()); xla::ProgramShape xla_program_shape = - XlaCompiledProgramShape(xla_computation, *shapes); + XlaCompiledProgramShape(xla_computation, xla::ProgramShape(*shapes)); EXPECT_TRUE(xla::LayoutUtil::Equal( xla::ShapeUtil::GetSubshape(program_shape.parameters(0), {0}).layout(), xla::ShapeUtil::GetSubshape(xla_program_shape.parameters(0), {0}) @@ -739,7 +739,7 @@ TEST(RawApiTest, CompileAndExecuteWithS64Argument) { auto expected = xla::LiteralUtil::CreateR0(15123899); EXPECT_TRUE(CompareLiteralToLiteralProto(expected, response)); - xla::ProgramShape program_shape; + xla::ProgramShapeProto program_shape; EXPECT_TRUE(program_shape.ParseFromString(outputs[1].vec()(0))); EXPECT_EQ(program_shape.parameters_size(), 2); EXPECT_TRUE( diff --git a/tensorflow/compiler/xrt/xrt.proto b/tensorflow/compiler/xrt/xrt.proto index 6ab77fbaaf..ae44f71740 100644 --- a/tensorflow/compiler/xrt/xrt.proto +++ b/tensorflow/compiler/xrt/xrt.proto @@ -36,11 +36,11 @@ message XLAComputationConfig { tensorflow.tf2xla.HostComputeMetadata host_compute_metadata = 3; // The arg/result shapes for the whole computation. - xla.ProgramShape program_shape = 4; + xla.ProgramShapeProto program_shape = 4; // The arg/result shapes for each core of a model-parallel // computation. per_core_args_and_result_shapes is optional for a // single-core computation. - repeated xla.ProgramShape per_core_program_shape = 5; + repeated xla.ProgramShapeProto per_core_program_shape = 5; // Describes how replicated computation instances should be assigned to // devices. There are num_cores_per_replica computations, and each one will be // sent and executed to the set of replica device numbers described in the -- GitLab From 722ef17a0ed80bad61baac084a8c8cfc7bddbe3f Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 21 Nov 2018 11:19:37 -0800 Subject: [PATCH 212/672] Use a non-trivial benchmark for kernel_tests/benchmark_test.py Otherwise XLA constant folds the computation resulting in allocator_maximum_num_bytes_* getting a value of 0. At least that's what I think is happening, I have not dug beyond confirming that the failure goes away with this change. PiperOrigin-RevId: 222435753 --- tensorflow/python/kernel_tests/benchmark_test.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/kernel_tests/benchmark_test.py b/tensorflow/python/kernel_tests/benchmark_test.py index 5777a5d097..bffa5e6e8f 100644 --- a/tensorflow/python/kernel_tests/benchmark_test.py +++ b/tensorflow/python/kernel_tests/benchmark_test.py @@ -21,9 +21,12 @@ import json import os import random +import numpy as np + from tensorflow.core.util import test_log_pb2 from tensorflow.python.client import session -from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.ops import array_ops from tensorflow.python.platform import benchmark from tensorflow.python.platform import gfile from tensorflow.python.platform import test @@ -64,11 +67,17 @@ class TestReportingBenchmark(test.Benchmark): "other_key": "string"}) def benchmark_times_an_op(self): + input_size = 5 with session.Session(config=benchmark.benchmark_config()) as sess: - a = constant_op.constant(0.0) + a = array_ops.placeholder(dtype=dtypes.float32, shape=(input_size)) a_plus_a = a + a return self.run_op_benchmark( - sess, a_plus_a, min_iters=1000, store_trace=True, name="op_benchmark") + sess, + a_plus_a, + feed_dict={a: np.arange(input_size)}, + min_iters=1000, + store_trace=True, + name="op_benchmark") class BenchmarkTest(test.TestCase): -- GitLab From dde1c81ae4998fd521d082009cb4bb0ed56e2f5b Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 21 Nov 2018 11:40:12 -0800 Subject: [PATCH 213/672] Change API for io.parse_example and io.parse_single_example for TF 2.0. PiperOrigin-RevId: 222439043 --- tensorflow/python/ops/parsing_ops.py | 264 +++++++++++++++++- .../tools/api/golden/v2/tensorflow.io.pbtxt | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 6 + 3 files changed, 269 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/ops/parsing_ops.py b/tensorflow/python/ops/parsing_ops.py index 484caf0179..7a11096d4f 100644 --- a/tensorflow/python/ops/parsing_ops.py +++ b/tensorflow/python/ops/parsing_ops.py @@ -363,7 +363,7 @@ def _prepend_none_dimension(features): return features -@tf_export("io.parse_example", v1=["io.parse_example", "parse_example"]) +@tf_export(v1=["io.parse_example", "parse_example"]) def parse_example(serialized, features, name=None, example_names=None): # pylint: disable=line-too-long """Parses `Example` protos into a `dict` of tensors. @@ -574,6 +574,223 @@ def parse_example(serialized, features, name=None, example_names=None): Returns: A `dict` mapping feature keys to `Tensor` and `SparseTensor` values. + Raises: + ValueError: if any feature is invalid. + """ + return parse_example_v2(serialized, features, example_names, name) + + +@tf_export("io.parse_example", v1=[]) +def parse_example_v2(serialized, features, example_names=None, name=None): + # pylint: disable=line-too-long + """Parses `Example` protos into a `dict` of tensors. + + Parses a number of serialized [`Example`](https://www.tensorflow.org/code/tensorflow/core/example/example.proto) + protos given in `serialized`. We refer to `serialized` as a batch with + `batch_size` many entries of individual `Example` protos. + + `example_names` may contain descriptive names for the corresponding serialized + protos. These may be useful for debugging purposes, but they have no effect on + the output. If not `None`, `example_names` must be the same length as + `serialized`. + + This op parses serialized examples into a dictionary mapping keys to `Tensor` + and `SparseTensor` objects. `features` is a dict from keys to `VarLenFeature`, + `SparseFeature`, and `FixedLenFeature` objects. Each `VarLenFeature` + and `SparseFeature` is mapped to a `SparseTensor`, and each + `FixedLenFeature` is mapped to a `Tensor`. + + Each `VarLenFeature` maps to a `SparseTensor` of the specified type + representing a ragged matrix. Its indices are `[batch, index]` where `batch` + identifies the example in `serialized`, and `index` is the value's index in + the list of values associated with that feature and example. + + Each `SparseFeature` maps to a `SparseTensor` of the specified type + representing a Tensor of `dense_shape` `[batch_size] + SparseFeature.size`. + Its `values` come from the feature in the examples with key `value_key`. + A `values[i]` comes from a position `k` in the feature of an example at batch + entry `batch`. This positional information is recorded in `indices[i]` as + `[batch, index_0, index_1, ...]` where `index_j` is the `k-th` value of + the feature in the example at with key `SparseFeature.index_key[j]`. + In other words, we split the indices (except the first index indicating the + batch entry) of a `SparseTensor` by dimension into different features of the + `Example`. Due to its complexity a `VarLenFeature` should be preferred over a + `SparseFeature` whenever possible. + + Each `FixedLenFeature` `df` maps to a `Tensor` of the specified type (or + `tf.float32` if not specified) and shape `(serialized.size(),) + df.shape`. + + `FixedLenFeature` entries with a `default_value` are optional. With no default + value, we will fail if that `Feature` is missing from any example in + `serialized`. + + Each `FixedLenSequenceFeature` `df` maps to a `Tensor` of the specified type + (or `tf.float32` if not specified) and shape + `(serialized.size(), None) + df.shape`. + All examples in `serialized` will be padded with `default_value` along the + second dimension. + + Examples: + + For example, if one expects a `tf.float32` `VarLenFeature` `ft` and three + serialized `Example`s are provided: + + ``` + serialized = [ + features + { feature { key: "ft" value { float_list { value: [1.0, 2.0] } } } }, + features + { feature []}, + features + { feature { key: "ft" value { float_list { value: [3.0] } } } + ] + ``` + + then the output will look like: + + ```python + {"ft": SparseTensor(indices=[[0, 0], [0, 1], [2, 0]], + values=[1.0, 2.0, 3.0], + dense_shape=(3, 2)) } + ``` + + If instead a `FixedLenSequenceFeature` with `default_value = -1.0` and + `shape=[]` is used then the output will look like: + + ```python + {"ft": [[1.0, 2.0], [3.0, -1.0]]} + ``` + + Given two `Example` input protos in `serialized`: + + ``` + [ + features { + feature { key: "kw" value { bytes_list { value: [ "knit", "big" ] } } } + feature { key: "gps" value { float_list { value: [] } } } + }, + features { + feature { key: "kw" value { bytes_list { value: [ "emmy" ] } } } + feature { key: "dank" value { int64_list { value: [ 42 ] } } } + feature { key: "gps" value { } } + } + ] + ``` + + And arguments + + ``` + example_names: ["input0", "input1"], + features: { + "kw": VarLenFeature(tf.string), + "dank": VarLenFeature(tf.int64), + "gps": VarLenFeature(tf.float32), + } + ``` + + Then the output is a dictionary: + + ```python + { + "kw": SparseTensor( + indices=[[0, 0], [0, 1], [1, 0]], + values=["knit", "big", "emmy"] + dense_shape=[2, 2]), + "dank": SparseTensor( + indices=[[1, 0]], + values=[42], + dense_shape=[2, 1]), + "gps": SparseTensor( + indices=[], + values=[], + dense_shape=[2, 0]), + } + ``` + + For dense results in two serialized `Example`s: + + ``` + [ + features { + feature { key: "age" value { int64_list { value: [ 0 ] } } } + feature { key: "gender" value { bytes_list { value: [ "f" ] } } } + }, + features { + feature { key: "age" value { int64_list { value: [] } } } + feature { key: "gender" value { bytes_list { value: [ "f" ] } } } + } + ] + ``` + + We can use arguments: + + ``` + example_names: ["input0", "input1"], + features: { + "age": FixedLenFeature([], dtype=tf.int64, default_value=-1), + "gender": FixedLenFeature([], dtype=tf.string), + } + ``` + + And the expected output is: + + ```python + { + "age": [[0], [-1]], + "gender": [["f"], ["f"]], + } + ``` + + An alternative to `VarLenFeature` to obtain a `SparseTensor` is + `SparseFeature`. For example, given two `Example` input protos in + `serialized`: + + ``` + [ + features { + feature { key: "val" value { float_list { value: [ 0.5, -1.0 ] } } } + feature { key: "ix" value { int64_list { value: [ 3, 20 ] } } } + }, + features { + feature { key: "val" value { float_list { value: [ 0.0 ] } } } + feature { key: "ix" value { int64_list { value: [ 42 ] } } } + } + ] + ``` + + And arguments + + ``` + example_names: ["input0", "input1"], + features: { + "sparse": SparseFeature( + index_key="ix", value_key="val", dtype=tf.float32, size=100), + } + ``` + + Then the output is a dictionary: + + ```python + { + "sparse": SparseTensor( + indices=[[0, 3], [0, 20], [1, 42]], + values=[0.5, -1.0, 0.0] + dense_shape=[2, 100]), + } + ``` + + Args: + serialized: A vector (1-D Tensor) of strings, a batch of binary + serialized `Example` protos. + features: A `dict` mapping feature keys to `FixedLenFeature`, + `VarLenFeature`, and `SparseFeature` values. + example_names: A vector (1-D Tensor) of strings (optional), the names of + the serialized protos in the batch. + name: A name for this operation (optional). + + Returns: + A `dict` mapping feature keys to `Tensor` and `SparseTensor` values. + Raises: ValueError: if any feature is invalid. """ @@ -764,8 +981,7 @@ def _process_raw_parameters(names, dense_defaults, sparse_keys, sparse_types, dense_shapes_as_proto, dense_shapes) -@tf_export("io.parse_single_example", - v1=["io.parse_single_example", "parse_single_example"]) +@tf_export(v1=["io.parse_single_example", "parse_single_example"]) def parse_single_example(serialized, features, name=None, example_names=None): """Parses a single `Example` proto. @@ -795,6 +1011,48 @@ def parse_single_example(serialized, features, name=None, example_names=None): Returns: A `dict` mapping feature keys to `Tensor` and `SparseTensor` values. + Raises: + ValueError: if any feature is invalid. + """ + return parse_single_example_v2_unoptimized( + serialized, features, example_names, name + ) + + +# TODO(b/70890287): Combine the implementation of this op and +# `parse_single_example_v2()` after 1/10/2018. +@tf_export("io.parse_single_example", v1=[]) +def parse_single_example_v2_unoptimized( + serialized, features, example_names=None, name=None + ): + """Parses a single `Example` proto. + + Similar to `parse_example`, except: + + For dense tensors, the returned `Tensor` is identical to the output of + `parse_example`, except there is no batch dimension, the output shape is the + same as the shape given in `dense_shape`. + + For `SparseTensor`s, the first (batch) column of the indices matrix is removed + (the indices matrix is a column vector), the values vector is unchanged, and + the first (`batch_size`) entry of the shape vector is removed (it is now a + single element vector). + + One might see performance advantages by batching `Example` protos with + `parse_example` instead of using this function directly. + + Args: + serialized: A scalar string Tensor, a single serialized Example. + See `_parse_single_example_raw` documentation for more details. + features: A `dict` mapping feature keys to `FixedLenFeature` or + `VarLenFeature` values. + example_names: (Optional) A scalar string Tensor, the associated name. + See `_parse_single_example_raw` documentation for more details. + name: A name for this operation (optional). + + Returns: + A `dict` mapping feature keys to `Tensor` and `SparseTensor` values. + Raises: ValueError: if any feature is invalid. """ diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt index 1de2fc9e5d..d32529876f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt @@ -122,7 +122,7 @@ tf_module { } member_method { name: "parse_example" - argspec: "args=[\'serialized\', \'features\', \'name\', \'example_names\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + argspec: "args=[\'serialized\', \'features\', \'example_names\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "parse_sequence_example" @@ -130,7 +130,7 @@ tf_module { } member_method { name: "parse_single_example" - argspec: "args=[\'serialized\', \'features\', \'name\', \'example_names\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + argspec: "args=[\'serialized\', \'features\', \'example_names\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "parse_single_sequence_example" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index aab7aa8af5..f756bb80bc 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -312,6 +312,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.strings.length": ["input", "name", "unit"], "tf.transpose": ["a", "perm", "name", "conjugate"], "tf.tuple": ["tensors", "name", "control_inputs"], + "tf.io.parse_example": [ + "serialized", "features", "name", "example_names" + ], + "tf.io.parse_single_example": [ + "serialized", "features", "name", "example_names" + ], "tf.while_loop": [ "cond", "body", "loop_vars", "shape_invariants", "parallel_iterations", "back_prop", "swap_memory", "name", -- GitLab From aaad174baa41472d996c91866883f16d67a844cf Mon Sep 17 00:00:00 2001 From: Jeremy Lau Date: Wed, 21 Nov 2018 11:51:09 -0800 Subject: [PATCH 214/672] TPUEstimator: Run tpu.initialize_system in a separate graph. This speeds up initialization by avoiding unnecessary graph processing. PiperOrigin-RevId: 222440544 --- tensorflow/contrib/tpu/BUILD | 1 + .../contrib/tpu/python/tpu/tpu_estimator.py | 31 +++++++++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tensorflow/contrib/tpu/BUILD b/tensorflow/contrib/tpu/BUILD index a0a9cb3f31..8264462a06 100644 --- a/tensorflow/contrib/tpu/BUILD +++ b/tensorflow/contrib/tpu/BUILD @@ -78,6 +78,7 @@ py_library( "//tensorflow/python:init_ops", "//tensorflow/python:math_ops", "//tensorflow/python:platform", + "//tensorflow/python:session", "//tensorflow/python:state_ops", "//tensorflow/python:summary", "//tensorflow/python:summary_ops_v2", diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 932367f4dd..9525121ebb 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -45,6 +45,7 @@ from tensorflow.contrib.training.python.training import hparam from tensorflow.core.framework import variable_pb2 from tensorflow.core.framework.summary_pb2 import Summary from tensorflow.core.protobuf import config_pb2 +from tensorflow.python.client import session as tf_session from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest as data_nest from tensorflow.python.estimator import estimator as estimator_lib @@ -412,12 +413,15 @@ class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): enqueue_ops, dequeue_ops, run_infeed_loop_on_coordinator=True, - rendezvous=None): + rendezvous=None, + master=None, + session_config=None): self._master_job = ctx.master_job self._enqueue_ops = enqueue_ops self._dequeue_ops = dequeue_ops self._rendezvous = rendezvous - + self._master = master + self._session_config = session_config self._run_infeed_loop_on_coordinator = run_infeed_loop_on_coordinator self._initial_infeed_sleep_secs = ( ctx.config.tpu_config.initial_infeed_sleep_secs) @@ -429,11 +433,10 @@ class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): def begin(self): logging.info('TPU job name %s', self._master_job) self._iterations_per_loop_var = _create_or_get_iterations_per_loop() + self._init_ops = [] if self._should_initialize_tpu: - self._init_ops = [tpu.initialize_system(job=self._master_job)] self._finalize_ops = [tpu.shutdown_system(job=self._master_job)] else: - self._init_ops = [] self._finalize_ops = [] summary_writer_init_ops = contrib_summary.summary_writer_initializer_op() @@ -475,11 +478,17 @@ class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): return _OpQueueContext(name=name, target=target, args=args) def after_create_session(self, session, coord): - logging.info('Init TPU system') - start = time.time() + if self._should_initialize_tpu: + logging.info('Init TPU system') + start = time.time() + with ops.Graph().as_default(): + with tf_session.Session( + self._master, config=self._session_config) as sess: + sess.run(tpu.initialize_system(job=self._master_job)) + logging.info('Initialized TPU in %d seconds', time.time() - start) + session.run(self._init_ops, options=config_pb2.RunOptions(timeout_in_ms=5 * 60 * 1000)) - logging.info('Initialized TPU in %d seconds', time.time() - start) self._infeed_controller = self._create_infeed_controller( name='InfeedController', target=self._run_infeed, args=(session,)) @@ -2564,6 +2573,8 @@ class TPUEstimator(estimator_lib.Estimator): run_infeed_loop_on_coordinator=( run_infeed_loop_on_coordinator), rendezvous=self._rendezvous[mode], + master=self._config.master, + session_config=self._session_config, ), InstallSignalHandlerHook() ]) @@ -2666,8 +2677,10 @@ class TPUEstimator(estimator_lib.Estimator): eval_update_ops + host_ops, run_infeed_loop_on_coordinator=( run_infeed_loop_on_coordinator), - rendezvous=self._rendezvous[mode]), - ] + input_hooks + rendezvous=self._rendezvous[mode], + master=self._config.master, + session_config=self._session_config, + )] + input_hooks if eval_hooks: hooks.extend(eval_hooks) -- GitLab From 5ce7e6476417a92a3c7455b898c5fb3632c9ccf7 Mon Sep 17 00:00:00 2001 From: Mark Heffernan Date: Wed, 21 Nov 2018 12:32:22 -0800 Subject: [PATCH 215/672] Add AddDependency HLO instruction. The AddDependency HLO instruction takes a data operand and a token operand. The output is the data operand. When used with AfterAll (which has been extended in the CL to accept non-token operands), this enables ordering of instructions which do produce or accept tokens (ie, non-side-effecting ops). This new functionality is intentionally not exposed in the XlaBuilder interface because the ordering of non-side-effecting operations is fragile to some optimizations. Rather this new op will be used to replace existing uses of control dependencies which are to be removed. The uses of these new ordering ops will be late in the optimization pipeline and will avoid the more problematic optimization interactions. See go/xla-side-effect-semantics for further details. PiperOrigin-RevId: 222445994 --- tensorflow/compiler/xla/client/xla_builder.cc | 9 ++ .../compiler/xla/client/xla_builder_test.cc | 9 ++ .../compiler/xla/g3doc/operation_semantics.md | 16 +++ .../compiler/xla/service/cpu/ir_emitter.cc | 13 +- .../compiler/xla/service/cpu/ir_emitter.h | 3 +- .../compiler/xla/service/dfs_hlo_visitor.h | 1 + .../service/dfs_hlo_visitor_with_default.h | 3 + .../compiler/xla/service/gpu/ir_emitter.cc | 12 ++ .../compiler/xla/service/gpu/ir_emitter.h | 1 + .../xla/service/gpu/ir_emitter_unnested.cc | 2 +- .../xla/service/gpu/ir_emitter_unnested.h | 2 +- .../compiler/xla/service/hlo_cost_analysis.cc | 15 +++ .../compiler/xla/service/hlo_cost_analysis.h | 1 + .../xla/service/hlo_dataflow_analysis.cc | 18 +++ .../xla/service/hlo_dataflow_analysis.h | 1 + .../xla/service/hlo_dataflow_analysis_test.cc | 24 ++++ .../compiler/xla/service/hlo_evaluator.cc | 11 +- .../compiler/xla/service/hlo_evaluator.h | 4 +- .../compiler/xla/service/hlo_graph_dumper.cc | 1 + .../compiler/xla/service/hlo_instruction.cc | 17 +++ .../compiler/xla/service/hlo_instruction.h | 3 + tensorflow/compiler/xla/service/hlo_opcode.h | 3 +- tensorflow/compiler/xla/service/hlo_parser.cc | 9 ++ .../compiler/xla/service/hlo_parser_test.cc | 31 +++++ .../compiler/xla/service/hlo_verifier.cc | 8 +- .../compiler/xla/service/hlo_verifier.h | 1 + .../xla/service/instruction_fusion.cc | 6 +- .../compiler/xla/service/layout_assignment.cc | 1 + .../xla/service/logical_buffer_analysis.cc | 7 ++ .../xla/service/logical_buffer_analysis.h | 1 + .../compiler/xla/service/shape_inference.cc | 11 -- .../compiler/xla/service/shape_inference.h | 7 -- .../xla/service/tuple_points_to_analysis.cc | 7 ++ .../xla/service/tuple_points_to_analysis.h | 1 + .../service/tuple_points_to_analysis_test.cc | 16 +++ tensorflow/compiler/xla/tests/BUILD | 1 + .../compiler/xla/tests/token_hlo_test.cc | 111 ++++++++++++++---- 37 files changed, 336 insertions(+), 51 deletions(-) diff --git a/tensorflow/compiler/xla/client/xla_builder.cc b/tensorflow/compiler/xla/client/xla_builder.cc index 8a33b3930f..f17bc456a6 100644 --- a/tensorflow/compiler/xla/client/xla_builder.cc +++ b/tensorflow/compiler/xla/client/xla_builder.cc @@ -1320,6 +1320,15 @@ XlaOp XlaBuilder::AfterAll(absl::Span tokens) { if (tokens.empty()) { return InvalidArgument("AfterAll requires at least one operand"); } + for (int i = 0; i < tokens.size(); ++i) { + const XlaOp& operand = tokens[i]; + TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); + if (!ShapeUtil::IsToken(operand_shape)) { + return InvalidArgument( + "All operands to AfterAll must be tokens; operand %d has shape %s", + i, ShapeUtil::HumanString(operand_shape)); + } + } HloInstructionProto instr; *instr.mutable_shape() = ShapeUtil::MakeTokenShape(); return AddInstruction(std::move(instr), HloOpcode::kAfterAll, tokens); diff --git a/tensorflow/compiler/xla/client/xla_builder_test.cc b/tensorflow/compiler/xla/client/xla_builder_test.cc index 8aa85c3cd6..e534fb67fd 100644 --- a/tensorflow/compiler/xla/client/xla_builder_test.cc +++ b/tensorflow/compiler/xla/client/xla_builder_test.cc @@ -446,5 +446,14 @@ TEST_F(XlaBuilderTest, ProtoMatches) { EXPECT_EQ(c0_string, c1_string); } +TEST_F(XlaBuilderTest, AfterAllWithNonTokenOperands) { + XlaBuilder b(TestName()); + AfterAll(&b, {CreateToken(&b), ConstantR0(&b, 1.0)}); + Status status = b.Build().status(); + ASSERT_IS_NOT_OK(status); + EXPECT_THAT(status.error_message(), + ::testing::HasSubstr("All operands to AfterAll must be tokens")); +} + } // namespace } // namespace xla diff --git a/tensorflow/compiler/xla/g3doc/operation_semantics.md b/tensorflow/compiler/xla/g3doc/operation_semantics.md index 73a9db75f6..bc87a60c6e 100644 --- a/tensorflow/compiler/xla/g3doc/operation_semantics.md +++ b/tensorflow/compiler/xla/g3doc/operation_semantics.md @@ -13,6 +13,22 @@ arbitrary-dimensional array. For convenience, special cases have more specific and familiar names; for example a *vector* is a 1-dimensional array and a *matrix* is a 2-dimensional array. +## AfterAll + +See also +[`XlaBuilder::AfterAll`](https://www.tensorflow.org/code/tensorflow/compiler/xla/client/xla_builder.h). + +AfterAll takes a variadic number of tokens and produces a single token. Tokens +are primitive types which can be threaded between side-effecting operations to +enforce ordering. `AfterAll` can be used as a join of tokens for ordering a +operation after a set operations. + + `AfterAll(operands)` + +Arguments | Type | Semantics +---------- | ------- | ------------------------- +`operands` | `XlaOp` | variadic number of tokens + ## AllToAll See also diff --git a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc index cf97a8bde0..4032c2da2f 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_emitter.cc +++ b/tensorflow/compiler/xla/service/cpu/ir_emitter.cc @@ -2565,10 +2565,17 @@ Status IrEmitter::HandleConditional(HloInstruction* conditional) { return Status::OK(); } -Status IrEmitter::HandleAfterAll(HloInstruction* gen_token) { - TF_RET_CHECK(ByteSizeOf(gen_token->shape()) == 0); +Status IrEmitter::HandleAfterAll(HloInstruction* after_all) { + TF_RET_CHECK(ByteSizeOf(after_all->shape()) == 0); // No code to generate, but we need to emit an address for book-keeping. - TF_RETURN_IF_ERROR(EmitTargetAddressForOp(gen_token)); + TF_RETURN_IF_ERROR(EmitTargetAddressForOp(after_all)); + return Status::OK(); +} + +Status IrEmitter::HandleAddDependency(HloInstruction* add_dependency) { + // AddDedendency just forwards its zero-th operand. + emitted_value_[add_dependency] = + GetEmittedValueFor(add_dependency->operand(0)); return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/cpu/ir_emitter.h b/tensorflow/compiler/xla/service/cpu/ir_emitter.h index f529c613a3..559a8162a2 100644 --- a/tensorflow/compiler/xla/service/cpu/ir_emitter.h +++ b/tensorflow/compiler/xla/service/cpu/ir_emitter.h @@ -159,7 +159,8 @@ class IrEmitter : public DfsHloVisitorWithDefault, Status HandleConcatenate(HloInstruction* concatenate) override; Status HandleConditional(HloInstruction* conditional) override; Status HandleScatter(HloInstruction* scatter) override; - Status HandleAfterAll(HloInstruction* gen_token) override; + Status HandleAfterAll(HloInstruction* after_all) override; + Status HandleAddDependency(HloInstruction* add_dependency) override; Status HandleRng(HloInstruction* rng) override; Status FinishVisit(HloInstruction* root) override; diff --git a/tensorflow/compiler/xla/service/dfs_hlo_visitor.h b/tensorflow/compiler/xla/service/dfs_hlo_visitor.h index d637128322..e84bf00153 100644 --- a/tensorflow/compiler/xla/service/dfs_hlo_visitor.h +++ b/tensorflow/compiler/xla/service/dfs_hlo_visitor.h @@ -251,6 +251,7 @@ class DfsHloVisitorBase { virtual Status HandleBatchNormGrad(HloInstructionPtr hlo) = 0; + virtual Status HandleAddDependency(HloInstructionPtr add_dependency) = 0; virtual Status HandleAfterAll(HloInstructionPtr token) = 0; // Invoked to inform the visitor that the traversal has completed, and that diff --git a/tensorflow/compiler/xla/service/dfs_hlo_visitor_with_default.h b/tensorflow/compiler/xla/service/dfs_hlo_visitor_with_default.h index e57184f639..80ea5be298 100644 --- a/tensorflow/compiler/xla/service/dfs_hlo_visitor_with_default.h +++ b/tensorflow/compiler/xla/service/dfs_hlo_visitor_with_default.h @@ -206,6 +206,9 @@ class DfsHloVisitorWithDefaultBase Status HandleGetDimensionSize(HloInstructionPtr get_size) override { return DefaultAction(get_size); } + Status HandleAddDependency(HloInstructionPtr add_dependency) override { + return DefaultAction(add_dependency); + } // Invoked to inform the visitor that the traversal has completed, and that // the root was "root". diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter.cc b/tensorflow/compiler/xla/service/gpu/ir_emitter.cc index 7fcdd805ed..31591914cc 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter.cc +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter.cc @@ -97,6 +97,18 @@ Status IrEmitter::HandleBitcast(HloInstruction* bitcast) { return Status::OK(); } +Status IrEmitter::HandleAddDependency(HloInstruction* add_dependency) { + VLOG(2) << "HandleAddDependency: " << add_dependency->ToString(); + const HloInstruction* operand = add_dependency->operand(0); + // Add_Dependency is a no-op, but we still want to bind it to an llvm::Value + // sometimes, e.g., when it's operand is a constant or a bitcast of a + // constant. + if (bindings_.BoundToIrValue(*operand)) { + bindings_.BindHloToIrValue(*add_dependency, GetBasePointer(*operand)); + } + return Status::OK(); +} + Status IrEmitter::HandleGetTupleElement(HloInstruction* get_tuple_element) { auto operand = get_tuple_element->operand(0); CHECK(bindings_.BoundToIrValue(*operand)); diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter.h b/tensorflow/compiler/xla/service/gpu/ir_emitter.h index 56c3f45200..2da46c0169 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter.h +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter.h @@ -100,6 +100,7 @@ class IrEmitter : public DfsHloVisitorWithDefault, Status HandleBatchNormInference(HloInstruction* batch_norm) override; Status HandleBatchNormTraining(HloInstruction* batch_norm) override; Status HandleBatchNormGrad(HloInstruction* batch_norm) override; + Status HandleAddDependency(HloInstruction* add_dependency) override; Status FinishVisit(HloInstruction* root) override { return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc index ebd73f3a91..52f0ba7aa7 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc @@ -2398,7 +2398,7 @@ Status IrEmitterUnnested::HandleCrossReplicaSum(HloInstruction* crs) { return Status::OK(); } -Status IrEmitterUnnested::HandleAfterAll(HloInstruction* gen_token) { +Status IrEmitterUnnested::HandleAfterAll(HloInstruction* after_all) { return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h index 97a1e10455..e09ed657a8 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h @@ -171,7 +171,7 @@ class IrEmitterUnnested : public IrEmitter { Status HandleSort(HloInstruction* sort) override; Status HandleTupleSelect(HloInstruction* tuple_select) override; Status HandleCrossReplicaSum(HloInstruction* crs) override; - Status HandleAfterAll(HloInstruction* gen_token) override; + Status HandleAfterAll(HloInstruction* after_all) override; Status EmitTargetElementLoop( const HloInstruction& hlo, diff --git a/tensorflow/compiler/xla/service/hlo_cost_analysis.cc b/tensorflow/compiler/xla/service/hlo_cost_analysis.cc index fdfb38b858..df7d3826db 100644 --- a/tensorflow/compiler/xla/service/hlo_cost_analysis.cc +++ b/tensorflow/compiler/xla/service/hlo_cost_analysis.cc @@ -419,6 +419,21 @@ Status HloCostAnalysis::HandleTranspose(const HloInstruction*) { } Status HloCostAnalysis::HandleAfterAll(const HloInstruction*) { + // This instruction is used to enforce ordering at compile time. No code is + // emitted. + current_should_compute_bottleneck_time_ = false; + current_properties_[kBytesAccessedKey] = 0; + current_properties_[kOptimalSecondsKey] = 0; + return Status::OK(); +} + +Status HloCostAnalysis::HandleAddDependency( + const HloInstruction* add_dependency) { + // This instruction is used to enforce ordering at compile time. No code is + // emitted. + current_should_compute_bottleneck_time_ = false; + current_properties_[kBytesAccessedKey] = 0; + current_properties_[kOptimalSecondsKey] = 0; return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/hlo_cost_analysis.h b/tensorflow/compiler/xla/service/hlo_cost_analysis.h index 8ced9d776e..33983119c9 100644 --- a/tensorflow/compiler/xla/service/hlo_cost_analysis.h +++ b/tensorflow/compiler/xla/service/hlo_cost_analysis.h @@ -101,6 +101,7 @@ class HloCostAnalysis : public ConstDfsHloVisitor { Status HandleBroadcast(const HloInstruction* broadcast) override; Status HandlePad(const HloInstruction* pad) override; Status HandleReshape(const HloInstruction* reshape) override; + Status HandleAddDependency(const HloInstruction* add_dependency) override; Status HandleAfterAll(const HloInstruction* token) override; Status HandleTranspose(const HloInstruction* transpose) override; Status HandleWhile(const HloInstruction* xla_while) override; diff --git a/tensorflow/compiler/xla/service/hlo_dataflow_analysis.cc b/tensorflow/compiler/xla/service/hlo_dataflow_analysis.cc index 5dcf6bc985..3ed3d3c11c 100644 --- a/tensorflow/compiler/xla/service/hlo_dataflow_analysis.cc +++ b/tensorflow/compiler/xla/service/hlo_dataflow_analysis.cc @@ -466,6 +466,21 @@ bool HloDataflowAnalysis::UpdateDomainValueSet(HloInstruction* domain) { return changed; } +bool HloDataflowAnalysis::UpdateAddDependencyValueSet( + HloInstruction* add_dependency) { + // AddDependency just forwards the value of its zero-th operand. + CHECK_EQ(add_dependency->opcode(), HloOpcode::kAddDependency); + const InstructionValueSet& operand_set = + GetInstructionValueSet(add_dependency->operand(0)); + InstructionValueSet& add_dependency_set = + GetInstructionValueSet(add_dependency); + if (operand_set != add_dependency_set) { + add_dependency_set = operand_set; + return true; + } + return false; +} + bool HloDataflowAnalysis::UpdateGetTupleElementValueSet(HloInstruction* gte) { CHECK_EQ(gte->opcode(), HloOpcode::kGetTupleElement); bool changed = false; @@ -622,6 +637,8 @@ bool HloDataflowAnalysis::UpdateInstructionValueSet( HloInstruction* instruction) { // Recompute from operands. switch (instruction->opcode()) { + case HloOpcode::kAddDependency: + return UpdateAddDependencyValueSet(instruction); case HloOpcode::kBitcast: return UpdateBitcastValueSet(instruction); case HloOpcode::kDomain: @@ -795,6 +812,7 @@ Status HloDataflowAnalysis::InitializeInstructionValueSets() { define_all_values(); } break; + case HloOpcode::kAddDependency: case HloOpcode::kWhile: case HloOpcode::kCall: case HloOpcode::kConditional: diff --git a/tensorflow/compiler/xla/service/hlo_dataflow_analysis.h b/tensorflow/compiler/xla/service/hlo_dataflow_analysis.h index abac398c04..ece17fc4c3 100644 --- a/tensorflow/compiler/xla/service/hlo_dataflow_analysis.h +++ b/tensorflow/compiler/xla/service/hlo_dataflow_analysis.h @@ -193,6 +193,7 @@ class HloDataflowAnalysis { bool UpdateSendValueSet(HloInstruction* send); bool UpdateTupleValueSet(HloInstruction* tuple); bool UpdateWhileValueSet(HloInstruction* xla_while); + bool UpdateAddDependencyValueSet(HloInstruction* add_dependency); // Propagate the dataflow through the module. void Propagate(); diff --git a/tensorflow/compiler/xla/service/hlo_dataflow_analysis_test.cc b/tensorflow/compiler/xla/service/hlo_dataflow_analysis_test.cc index e8eb7066f9..f7a1f19a6f 100644 --- a/tensorflow/compiler/xla/service/hlo_dataflow_analysis_test.cc +++ b/tensorflow/compiler/xla/service/hlo_dataflow_analysis_test.cc @@ -1877,6 +1877,30 @@ TEST_P(HloDataflowAnalysisTest, NestedConditionals) { } } +TEST_P(HloDataflowAnalysisTest, AddDependency) { + string module_string = R"( +HloModule AddDependency +ENTRY %AddDependency (p: f32[3]) -> f32[3] { + %p = f32[3] parameter(0) + %token = token[] after-all() + ROOT %add_dep = f32[3] add-dependency(f32[3] %p, token[] %token) +} +)"; + TF_ASSERT_OK_AND_ASSIGN( + std::unique_ptr module, + ParseHloString(module_string, GetModuleConfigForTest())); + + TF_ASSERT_OK_AND_ASSIGN(std::unique_ptr analysis, + HloDataflowAnalysis::Run(*module)); + const HloInstruction* root = module->entry_computation()->root_instruction(); + EXPECT_EQ(root->opcode(), HloOpcode::kAddDependency); + + // The after-all and parameter should define a value. Add-dependency should + // not. + EXPECT_EQ(analysis->values().size(), 2); + EXPECT_FALSE(analysis->ValueIsDefinedAt(root)); +} + INSTANTIATE_TEST_CASE_P(HloDataflowAnalysisInstantiation, HloDataflowAnalysisTest, ::testing::Values(false, true)); diff --git a/tensorflow/compiler/xla/service/hlo_evaluator.cc b/tensorflow/compiler/xla/service/hlo_evaluator.cc index 9783f0574f..51a3fba176 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator.cc +++ b/tensorflow/compiler/xla/service/hlo_evaluator.cc @@ -1046,8 +1046,15 @@ Status HloEvaluator::HandleBroadcast(HloInstruction* broadcast) { return Status::OK(); } -Status HloEvaluator::HandleAfterAll(HloInstruction* token) { - evaluated_[token] = LiteralUtil::CreateToken(); +Status HloEvaluator::HandleAfterAll(HloInstruction* after_all) { + evaluated_[after_all] = LiteralUtil::CreateToken(); + return Status::OK(); +} + +Status HloEvaluator::HandleAddDependency(HloInstruction* add_dependency) { + // AddDedendency just forwards its zero-th operand. + evaluated_[add_dependency] = + GetEvaluatedLiteralFor(add_dependency->operand(0)).Clone(); return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/hlo_evaluator.h b/tensorflow/compiler/xla/service/hlo_evaluator.h index d751f40fff..d847900010 100644 --- a/tensorflow/compiler/xla/service/hlo_evaluator.h +++ b/tensorflow/compiler/xla/service/hlo_evaluator.h @@ -180,7 +180,9 @@ class HloEvaluator : public DfsHloVisitorWithDefault { Status HandleBroadcast(HloInstruction* broadcast) override; - Status HandleAfterAll(HloInstruction* token) override; + Status HandleAfterAll(HloInstruction* after_all) override; + + Status HandleAddDependency(HloInstruction* add_dependency) override; Status HandleSort(HloInstruction* sort) override; diff --git a/tensorflow/compiler/xla/service/hlo_graph_dumper.cc b/tensorflow/compiler/xla/service/hlo_graph_dumper.cc index 05cc1593e4..7e9e94ca5f 100644 --- a/tensorflow/compiler/xla/service/hlo_graph_dumper.cc +++ b/tensorflow/compiler/xla/service/hlo_graph_dumper.cc @@ -987,6 +987,7 @@ ColorScheme HloDotDumper::GetInstructionColor(const HloInstruction* instr) { case HloOpcode::kGetTupleElement: case HloOpcode::kTrace: case HloOpcode::kAfterAll: + case HloOpcode::kAddDependency: case HloOpcode::kTuple: return kWhite; case HloOpcode::kBroadcast: diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index cd95052580..1e3881c34f 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -855,6 +855,16 @@ HloInstruction::CreateCollectivePermute( new HloInstruction(HloOpcode::kAfterAll, ShapeUtil::MakeTokenShape())); } +/* static */ std::unique_ptr +HloInstruction::CreateAddDependency(HloInstruction* data_operand, + HloInstruction* token_operand) { + auto instruction = absl::WrapUnique( + new HloInstruction(HloOpcode::kAddDependency, data_operand->shape())); + instruction->AppendOperand(data_operand); + instruction->AppendOperand(token_operand); + return instruction; +} + /* static */ std::unique_ptr HloInstruction::CreateWhile( const Shape& shape, HloComputation* condition, HloComputation* body, HloInstruction* init) { @@ -1394,6 +1404,10 @@ std::unique_ptr HloInstruction::CloneWithNewOperands( clone = CreateAfterAll(new_operands); } break; + case HloOpcode::kAddDependency: + CHECK_EQ(new_operands.size(), 2); + clone = CreateAddDependency(new_operands[0], new_operands[1]); + break; } // SetupDerivedInstruction will setup the precision_config_ field. SetupDerivedInstruction(clone.get()); @@ -1680,6 +1694,7 @@ bool HloInstruction::IdenticalSlowPath( // This opcode has complex or special behavior so just return false. case HloOpcode::kAfterAll: + case HloOpcode::kAddDependency: return false; // Remaining instructions with special values. @@ -2467,6 +2482,8 @@ Status HloInstruction::Visit(DfsHloVisitorBase* visitor) { return visitor->HandleDomain(this); case HloOpcode::kAfterAll: return visitor->HandleAfterAll(this); + case HloOpcode::kAddDependency: + return visitor->HandleAddDependency(this); case HloOpcode::kIota: return visitor->HandleIota(this); case HloOpcode::kGetDimensionSize: diff --git a/tensorflow/compiler/xla/service/hlo_instruction.h b/tensorflow/compiler/xla/service/hlo_instruction.h index 95ad29235a..87748a771a 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.h +++ b/tensorflow/compiler/xla/service/hlo_instruction.h @@ -770,6 +770,9 @@ class HloInstruction { static std::unique_ptr CreateGetDimensionSize( const Shape& shape, HloInstruction* operand, int64 dimension); + static std::unique_ptr CreateAddDependency( + HloInstruction* data_operand, HloInstruction* token_operand); + // Returns the opcode for this instruction. HloOpcode opcode() const { return opcode_; } diff --git a/tensorflow/compiler/xla/service/hlo_opcode.h b/tensorflow/compiler/xla/service/hlo_opcode.h index 70c7d70b41..127cfd165a 100644 --- a/tensorflow/compiler/xla/service/hlo_opcode.h +++ b/tensorflow/compiler/xla/service/hlo_opcode.h @@ -47,6 +47,8 @@ namespace xla { #define HLO_OPCODE_LIST(V) \ V(kAbs, "abs") \ V(kAdd, "add") \ + V(kAddDependency, "add-dependency") \ + V(kAfterAll, "after-all", kHloOpcodeIsVariadic) \ V(kAllToAll, "all-to-all") \ V(kAtan2, "atan2") \ V(kBatchNormGrad, "batch-norm-grad") \ @@ -84,7 +86,6 @@ namespace xla { V(kGather, "gather") \ V(kGe, "greater-than-or-equal-to", kHloOpcodeIsComparison) \ V(kGetDimensionSize, "get-dimension-size") \ - V(kAfterAll, "after-all", kHloOpcodeIsVariadic) \ V(kGetTupleElement, "get-tuple-element") \ V(kGt, "greater-than", kHloOpcodeIsComparison) \ V(kImag, "imag") \ diff --git a/tensorflow/compiler/xla/service/hlo_parser.cc b/tensorflow/compiler/xla/service/hlo_parser.cc index 4bf287a9ed..9b5bb5d0bd 100644 --- a/tensorflow/compiler/xla/service/hlo_parser.cc +++ b/tensorflow/compiler/xla/service/hlo_parser.cc @@ -850,6 +850,15 @@ bool HloParser::ParseInstructionRhs(HloComputation::Builder* builder, } break; } + case HloOpcode::kAddDependency: { + if (!ParseOperands(&operands, /*expected_size=*/2) || + !ParseAttributes(attrs)) { + return false; + } + instruction = builder->AddInstruction( + HloInstruction::CreateAddDependency(operands[0], operands[1])); + break; + } case HloOpcode::kSort: { optional> dimensions; attrs["dimensions"] = {/*required=*/true, AttrTy::kBracedInt64List, diff --git a/tensorflow/compiler/xla/service/hlo_parser_test.cc b/tensorflow/compiler/xla/service/hlo_parser_test.cc index 88682e55fb..f13f7504ee 100644 --- a/tensorflow/compiler/xla/service/hlo_parser_test.cc +++ b/tensorflow/compiler/xla/service/hlo_parser_test.cc @@ -1241,7 +1241,38 @@ ENTRY Sort { } )" + }, +// AfterAll with multiple operands +{ +"AfterAllWithMultipleOperands", +R"(HloModule AfterAllWithMultipleOperands + +ENTRY AfterAllWithMultipleOperands { + p0 = f32[] parameter(0) + token0 = token[] after-all() + token1 = token[] after-all() + ROOT after-all = token[] after-all(p0, token0, token1) } + +)" +}, +// AddDependency +// A dependency chain is created from 'neg' to 'exp' using tokens. +{ +"AddDependency", +R"(HloModule AddDependency + +ENTRY AddDependency { + p = f32[] parameter(0) + neg = f32[] negate(p) + token = token[] after-all(neg) + p_after_token = f32[] add-dependency(p, token) + exp = f32[] exponential(p_after_token) + ROOT sum = f32[] add(neg, exp) +} + +)" +}, }); // clang-format on } diff --git a/tensorflow/compiler/xla/service/hlo_verifier.cc b/tensorflow/compiler/xla/service/hlo_verifier.cc index 60d8a511b5..017549ce1b 100644 --- a/tensorflow/compiler/xla/service/hlo_verifier.cc +++ b/tensorflow/compiler/xla/service/hlo_verifier.cc @@ -753,7 +753,13 @@ Status ShapeVerifier::HandleAfterAll(HloInstruction* token) { for (const HloInstruction* operand : token->operands()) { operand_shapes.push_back(&operand->shape()); } - return CheckShape(token, ShapeInference::InferAfterAllShape(operand_shapes)); + return CheckShape(token, ShapeUtil::MakeTokenShape()); +} + +Status ShapeVerifier::HandleAddDependency(HloInstruction* add_dependency) { + TF_RETURN_IF_ERROR(CheckOperandCount(add_dependency, 2)); + TF_RETURN_IF_ERROR(CheckIsTokenOperand(add_dependency, 1)); + return CheckShape(add_dependency, add_dependency->operand(0)->shape()); } Status ShapeVerifier::HandleGetDimensionSize(HloInstruction* get_size) { diff --git a/tensorflow/compiler/xla/service/hlo_verifier.h b/tensorflow/compiler/xla/service/hlo_verifier.h index 9fbfd6a21c..e4d0c3d695 100644 --- a/tensorflow/compiler/xla/service/hlo_verifier.h +++ b/tensorflow/compiler/xla/service/hlo_verifier.h @@ -95,6 +95,7 @@ class ShapeVerifier : public DfsHloVisitor { Status HandleScatter(HloInstruction* scatter) override; Status HandleAfterAll(HloInstruction* token) override; Status HandleGetDimensionSize(HloInstruction* get_size) override; + Status HandleAddDependency(HloInstruction* add_dependency) override; Status FinishVisit(HloInstruction*) override { return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/instruction_fusion.cc b/tensorflow/compiler/xla/service/instruction_fusion.cc index 7f2d7e7cff..2297edcbe1 100644 --- a/tensorflow/compiler/xla/service/instruction_fusion.cc +++ b/tensorflow/compiler/xla/service/instruction_fusion.cc @@ -103,7 +103,6 @@ bool IsAlwaysDuplicable(const HloInstruction& instruction) { case HloOpcode::kShiftRightLogical: case HloOpcode::kSlice: case HloOpcode::kSubtract: - case HloOpcode::kAfterAll: case HloOpcode::kTranspose: case HloOpcode::kTuple: case HloOpcode::kTupleSelect: @@ -116,7 +115,10 @@ bool IsAlwaysDuplicable(const HloInstruction& instruction) { case HloOpcode::kSin: return ShapeUtil::ElementIsComplex(instruction.shape()); - // Expensive instructions. + // Expensive instructions or unusual instructions for which fusion is + // nonsensical. + case HloOpcode::kAddDependency: + case HloOpcode::kAfterAll: case HloOpcode::kAtan2: case HloOpcode::kBatchNormGrad: case HloOpcode::kBatchNormInference: diff --git a/tensorflow/compiler/xla/service/layout_assignment.cc b/tensorflow/compiler/xla/service/layout_assignment.cc index a904119222..eddef850cf 100644 --- a/tensorflow/compiler/xla/service/layout_assignment.cc +++ b/tensorflow/compiler/xla/service/layout_assignment.cc @@ -2000,6 +2000,7 @@ bool LayoutAssignment::InstructionCanChangeLayout( switch (instruction->opcode()) { case HloOpcode::kAbs: case HloOpcode::kAdd: + case HloOpcode::kAddDependency: case HloOpcode::kAnd: case HloOpcode::kAtan2: case HloOpcode::kBitcastConvert: diff --git a/tensorflow/compiler/xla/service/logical_buffer_analysis.cc b/tensorflow/compiler/xla/service/logical_buffer_analysis.cc index ec52a24d78..972a5b9ced 100644 --- a/tensorflow/compiler/xla/service/logical_buffer_analysis.cc +++ b/tensorflow/compiler/xla/service/logical_buffer_analysis.cc @@ -113,6 +113,13 @@ Status LogicalBufferAnalysis::HandleGetTupleElement(HloInstruction*) { return Status::OK(); } +Status LogicalBufferAnalysis::HandleAddDependency( + HloInstruction* add_dependency) { + // AddDependency just forwards the value of its zero-th operand and does not + // create buffers. + return Status::OK(); +} + Status LogicalBufferAnalysis::HandleCopy(HloInstruction* copy) { // The top-level buffer (index={}) for kCopy is newly created, but all other // buffers (in the case of a tuple shape) come from the operand diff --git a/tensorflow/compiler/xla/service/logical_buffer_analysis.h b/tensorflow/compiler/xla/service/logical_buffer_analysis.h index 81f524d84a..7ffca943d0 100644 --- a/tensorflow/compiler/xla/service/logical_buffer_analysis.h +++ b/tensorflow/compiler/xla/service/logical_buffer_analysis.h @@ -64,6 +64,7 @@ class LogicalBufferAnalysis : public DfsHloVisitorWithDefault { Status HandleRecvDone(HloInstruction* recv_done) override; Status HandleSend(HloInstruction* send) override; Status HandleTupleSelect(HloInstruction* tuple_select) override; + Status HandleAddDependency(HloInstruction* add_dependency) override; // A map from the buffer ID to the logical buffer std::vector> logical_buffers_; diff --git a/tensorflow/compiler/xla/service/shape_inference.cc b/tensorflow/compiler/xla/service/shape_inference.cc index 2bfc1676bd..528d5c0ecc 100644 --- a/tensorflow/compiler/xla/service/shape_inference.cc +++ b/tensorflow/compiler/xla/service/shape_inference.cc @@ -391,17 +391,6 @@ StatusOr InferWindowOutputShape(const Shape& base_shape, return ShapeUtil::MakeShape(element_type, new_dimensions); } -/* static */ StatusOr ShapeInference::InferAfterAllShape( - absl::Span arg_shapes) { - for (const Shape* arg_shape : arg_shapes) { - if (arg_shape->element_type() != TOKEN) { - return InvalidArgument( - "Operands of token instructions must be TOKEN types."); - } - } - return ShapeUtil::MakeTokenShape(); -} - /* static */ StatusOr ShapeInference::InferConvertShape( const Shape& operand_shape, PrimitiveType new_element_type) { auto old_element_type = operand_shape.element_type(); diff --git a/tensorflow/compiler/xla/service/shape_inference.h b/tensorflow/compiler/xla/service/shape_inference.h index 31ef4b2e41..d94385a04d 100644 --- a/tensorflow/compiler/xla/service/shape_inference.h +++ b/tensorflow/compiler/xla/service/shape_inference.h @@ -232,13 +232,6 @@ class ShapeInference { static StatusOr InferConcatOpShape( absl::Span arg_shapes, int64 dimension); - // Infers the shape produced by a kAfterAll. Trivially this shape is always a - // TOKEN shape. However, ShapeInference serves two purposes: inferring shapes - // and checking operand shapes. This method verifies that the operand shapes - // are all TOKENs. - static StatusOr InferAfterAllShape( - absl::Span arg_shapes); - // Helper that validates the given operand shape can be converted to the // target output_shape via a convert instruction -- the requirement is that // the shape is identical except for the element type. diff --git a/tensorflow/compiler/xla/service/tuple_points_to_analysis.cc b/tensorflow/compiler/xla/service/tuple_points_to_analysis.cc index 96f3055c98..50d51eaeb7 100644 --- a/tensorflow/compiler/xla/service/tuple_points_to_analysis.cc +++ b/tensorflow/compiler/xla/service/tuple_points_to_analysis.cc @@ -280,6 +280,13 @@ Status TuplePointsToAnalysis::HandleDomain(HloInstruction* domain) { return Status::OK(); } +Status TuplePointsToAnalysis::HandleAddDependency( + HloInstruction* add_dependency) { + // AddDependency just forwards the value of its zero-th operand. + CreateCopiedPointsToSet(add_dependency, add_dependency->operand(0)); + return Status::OK(); +} + Status TuplePointsToAnalysis::HandleRecvDone(HloInstruction* recv_done) { // RecvDone aliases its input (Recv) tuple element {0} to element {0} of its // output. The other indices ({} and {1}) define their own buffers. diff --git a/tensorflow/compiler/xla/service/tuple_points_to_analysis.h b/tensorflow/compiler/xla/service/tuple_points_to_analysis.h index bcfcb388f9..0a1d5649d6 100644 --- a/tensorflow/compiler/xla/service/tuple_points_to_analysis.h +++ b/tensorflow/compiler/xla/service/tuple_points_to_analysis.h @@ -252,6 +252,7 @@ class TuplePointsToAnalysis : public DfsHloVisitorWithDefault { Status HandleRecvDone(HloInstruction* recv_done) override; Status HandleSend(HloInstruction* send) override; Status HandleTupleSelect(HloInstruction* tuple_select) override; + Status HandleAddDependency(HloInstruction* add_dependency) override; string ToString() const; diff --git a/tensorflow/compiler/xla/service/tuple_points_to_analysis_test.cc b/tensorflow/compiler/xla/service/tuple_points_to_analysis_test.cc index 10ef2d38fa..561762b5d4 100644 --- a/tensorflow/compiler/xla/service/tuple_points_to_analysis_test.cc +++ b/tensorflow/compiler/xla/service/tuple_points_to_analysis_test.cc @@ -264,6 +264,22 @@ TEST_F(TuplePointsToAnalysisTest, GetTupleElement) { UnorderedElementsAre(inner_tuple)); } +TEST_F(TuplePointsToAnalysisTest, AddDependency) { + auto builder = HloComputation::Builder(TestName()); + auto constant = builder.AddInstruction( + HloInstruction::CreateConstant(LiteralUtil::CreateR0(1.0))); + auto token = builder.AddInstruction(HloInstruction::CreateToken()); + auto add_dependency = builder.AddInstruction( + HloInstruction::CreateAddDependency(constant, token)); + BuildModuleAndRunAnalysis(builder.Build()); + + auto& points_to_set = points_to_analysis_->GetPointsToSet(add_dependency); + EXPECT_EQ(1, points_to_set.size()); + EXPECT_FALSE(points_to_set.IsAmbiguous()); + EXPECT_TRUE(points_to_set.IsDistinct()); + ExpectHasTopLevelBuffers(points_to_set.CreateFlattenedSet(), {constant}); +} + TEST_F(TuplePointsToAnalysisTest, DuplicatedElement) { // Create a tuple which contains duplicate elements. auto builder = HloComputation::Builder(TestName()); diff --git a/tensorflow/compiler/xla/tests/BUILD b/tensorflow/compiler/xla/tests/BUILD index 20493a354c..0105e4a226 100644 --- a/tensorflow/compiler/xla/tests/BUILD +++ b/tensorflow/compiler/xla/tests/BUILD @@ -1291,6 +1291,7 @@ xla_test( "enable_for_xla_interpreter", ], deps = [ + "//tensorflow/compiler/xla/service:hlo_parser", "//tensorflow/compiler/xla/service:hlo_verifier", "//tensorflow/compiler/xla/tests:hlo_test_base", "//tensorflow/compiler/xla/tests:xla_internal_test_main", diff --git a/tensorflow/compiler/xla/tests/token_hlo_test.cc b/tensorflow/compiler/xla/tests/token_hlo_test.cc index a2b7c26331..601c6b0693 100644 --- a/tensorflow/compiler/xla/tests/token_hlo_test.cc +++ b/tensorflow/compiler/xla/tests/token_hlo_test.cc @@ -16,6 +16,7 @@ limitations under the License. #include #include "absl/strings/str_cat.h" +#include "tensorflow/compiler/xla/service/hlo_parser.h" #include "tensorflow/compiler/xla/service/hlo_verifier.h" #include "tensorflow/compiler/xla/tests/hlo_test_base.h" #include "tensorflow/compiler/xla/tests/test_macros.h" @@ -108,26 +109,6 @@ XLA_TEST_F(TokenHloTest, InvalidTupleTokenShapedEntryParameter) { ::testing::HasSubstr("Entry parameter 0 is or contains a token shape")); } -XLA_TEST_F(TokenHloTest, InvalidOperandToTokenInstruction) { - std::unique_ptr module = CreateNewUnverifiedModule(); - auto builder = HloComputation::Builder(TestName()); - auto param = builder.AddInstruction( - HloInstruction::CreateParameter(0, ShapeUtil::MakeShape(F32, {}), "p0")); - builder.AddInstruction(HloInstruction::CreateAfterAll({param})); - builder.AddInstruction( - HloInstruction::CreateConstant(LiteralUtil::CreateR0(123))); - module->AddEntryComputation(builder.Build()); - - Status status = - HloVerifier(/*layout_sensitive=*/false, /*allow_mixed_precision=*/false) - .Run(module.get()) - .status(); - ASSERT_IS_NOT_OK(status); - EXPECT_THAT(status.error_message(), - ::testing::HasSubstr( - "Operands of token instructions must be TOKEN types")); -} - XLA_TEST_F(TokenHloTest, TokenInWhileLoop) { // Thread a token around a while loop. Token is created and consumed by a // AfterAll instruction in the while body. @@ -220,5 +201,95 @@ ENTRY %TokenInConditional (param.3: pred[]) -> s32[] { } } +XLA_TEST_F(TokenHloTest, AddDependency) { + string module_string = R"( +HloModule AddDependency, is_scheduled=true + +// Computes (p0 + 42) * (-p1) +// where there is a dependency from the add to the negation using a token +// with after-all and add-dependency instructions. +ENTRY %AddDependency (p0: f32[], p1: f32[]) -> f32[] { + %p0 = f32[] parameter(0) + %p1 = f32[] parameter(1) + + %forty_two = f32[] constant(42.0) + %add = f32[] add(f32[] %p0, f32[] %forty_two) + %token = token[] after-all(f32[] %add) + %p1_after_token = f32[] add-dependency(f32[] %p1, token[] %token) + %neg = f32[] negate(f32[] %p1_after_token) + ROOT %product = f32[] multiply(f32[] %add, f32[] %neg) +} +)"; + TF_ASSERT_OK_AND_ASSIGN( + std::unique_ptr module, + ParseHloString(module_string, GetModuleConfigForTest())); + auto p0 = LiteralUtil::CreateR0(10.0); + auto p1 = LiteralUtil::CreateR0(3.0); + auto expected = LiteralUtil::CreateR0(-156.0); + EXPECT_EQ(expected, ExecuteNoHloPasses(std::move(module), {&p0, &p1})); +} + +XLA_TEST_F(TokenHloTest, AddDependencyOfConstant) { + string module_string = R"( +HloModule AddDependencyOfConstant, is_scheduled=true + +ENTRY %AddDependency (p0: f32[]) -> f32[] { + %p0 = f32[] parameter(0) + %forty_two = f32[] constant(42.0) + %token = token[] after-all(f32[] %p0) + %forty_two_after_token = f32[] add-dependency(f32[] %forty_two, token[] %token) + ROOT %product = f32[] multiply(f32[] %p0, f32[] %forty_two_after_token) +} +)"; + TF_ASSERT_OK_AND_ASSIGN( + std::unique_ptr module, + ParseHloString(module_string, GetModuleConfigForTest())); + auto p0 = LiteralUtil::CreateR0(10.0); + auto expected = LiteralUtil::CreateR0(420.0); + EXPECT_EQ(expected, ExecuteNoHloPasses(std::move(module), {&p0})); +} + +XLA_TEST_F(TokenHloTest, AddDependencyAsRoot) { + string module_string = R"( +HloModule AddDependencyAsRoot, is_scheduled=true +ENTRY %AddDependency (p: f32[3]) -> f32[3] { + %p = f32[3] parameter(0) + %neg = f32[3] negate(f32[3] %p) + %token = token[] after-all() + ROOT %add_dep = f32[3] add-dependency(f32[3] %neg, token[] %token) +} +)"; + TF_ASSERT_OK_AND_ASSIGN( + std::unique_ptr module, + ParseHloString(module_string, GetModuleConfigForTest())); + auto input = LiteralUtil::CreateR1({1.0, 3.0, 7.0}); + auto expected = LiteralUtil::CreateR1({-1.0, -3.0, -7.0}); + EXPECT_EQ(expected, ExecuteNoHloPasses(std::move(module), {&input})); +} + +XLA_TEST_F(TokenHloTest, TupleShapedAddDependency) { + string module_string = R"( +HloModule TupleShapedAddDependency, is_scheduled=true +ENTRY %TupleShapedAddDependency (p0: f32[3], p1: f32[3]) -> f32[3] { + %p0 = f32[3] parameter(0) + %p1 = f32[3] parameter(1) + %forty_two = f32[] constant(42.0) + %token = token[] after-all() + %tuple = (f32[3], token[], f32[3], f32[]) tuple(f32[3] %p0, token[] %token, f32[3] %p1, f32[] %forty_two) + %add_dep = (f32[3], token[], f32[3], f32[]) add-dependency((f32[3], token[], f32[3], f32[]) %tuple, token[] %token) + %elem0 = f32[3] get-tuple-element((f32[3], token[], f32[3], f32[]) %add_dep), index=0 + %elem2 = f32[3] get-tuple-element((f32[3], token[], f32[3], f32[]) %add_dep), index=2 + ROOT %diff = f32[3] subtract(f32[3] %elem0, f32[3] %elem2) +} +)"; + TF_ASSERT_OK_AND_ASSIGN( + std::unique_ptr module, + ParseHloString(module_string, GetModuleConfigForTest())); + auto p0 = LiteralUtil::CreateR1({3.0, 3.0, 47.0}); + auto p1 = LiteralUtil::CreateR1({1.0, -2.0, 2.0}); + auto expected = LiteralUtil::CreateR1({2.0, 5.0, 45.0}); + EXPECT_EQ(expected, ExecuteNoHloPasses(std::move(module), {&p0, &p1})); +} + } // namespace } // namespace xla -- GitLab From b255e5c1dc458ea153c565abb228863754b4203b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 12:33:50 -0800 Subject: [PATCH 216/672] Clean up memory management in testing/tflite_driver PiperOrigin-RevId: 222446170 --- tensorflow/lite/testing/tflite_driver.cc | 11 +++++------ tensorflow/lite/testing/tflite_driver.h | 14 +++++++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tensorflow/lite/testing/tflite_driver.cc b/tensorflow/lite/testing/tflite_driver.cc index 3a0febb780..27e3a3770b 100644 --- a/tensorflow/lite/testing/tflite_driver.cc +++ b/tensorflow/lite/testing/tflite_driver.cc @@ -147,9 +147,10 @@ TfLiteDriver::TfLiteDriver(bool use_nnapi, const string& delegate_name) } TfLiteDriver::~TfLiteDriver() { - for (TfLiteTensor* t : tensors_to_deallocate_) { - free(t->data.raw); + for (auto t : tensors_to_deallocate_) { + DeallocateStringTensor(t.second); } + interpreter_.reset(); } void TfLiteDriver::AllocateTensors() { @@ -242,12 +243,10 @@ void TfLiteDriver::SetInput(int id, const string& csv_values) { case kTfLiteString: { string s = absl::HexStringToBytes(csv_values); - tensor->data.raw = reinterpret_cast(malloc(s.size())); - tensor->bytes = s.size(); + DeallocateStringTensor(tensors_to_deallocate_[id]); + AllocateStringTensor(id, s.size(), tensor); memcpy(tensor->data.raw, s.data(), s.size()); - // We must remember to free the memory we allocated above. - tensors_to_deallocate_.push_back(tensor); break; } default: diff --git a/tensorflow/lite/testing/tflite_driver.h b/tensorflow/lite/testing/tflite_driver.h index d8b40565ba..1da0533c57 100644 --- a/tensorflow/lite/testing/tflite_driver.h +++ b/tensorflow/lite/testing/tflite_driver.h @@ -49,6 +49,18 @@ class TfLiteDriver : public TestRunner { string ReadOutput(int id) override { return "no-op"; } private: + void DeallocateStringTensor(TfLiteTensor* t) { + if (t) { + free(t->data.raw); + t->data.raw = nullptr; + } + } + void AllocateStringTensor(int id, size_t num_bytes, TfLiteTensor* t) { + t->data.raw = reinterpret_cast(malloc(num_bytes)); + t->bytes = num_bytes; + tensors_to_deallocate_[id] = t; + } + void ResetLSTMStateTensors(); class Expectation; @@ -59,7 +71,7 @@ class TfLiteDriver : public TestRunner { std::unique_ptr interpreter_; std::map> expected_output_; bool must_allocate_tensors_ = true; - std::vector tensors_to_deallocate_; + std::map tensors_to_deallocate_; }; } // namespace testing -- GitLab From 781a8f2e2093c38ff8e7dff94eb432cd948e54b0 Mon Sep 17 00:00:00 2001 From: Katherine Wu Date: Wed, 21 Nov 2018 12:34:35 -0800 Subject: [PATCH 217/672] Remove pywrap_tensorflow from available symbols in Tensorflow v2 PiperOrigin-RevId: 222446280 --- tensorflow/api_template.__init__.py | 2 -- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 4 ---- tensorflow/tools/compatibility/tf_upgrade_v2.py | 1 + 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tensorflow/api_template.__init__.py b/tensorflow/api_template.__init__.py index 2efb8846c6..59b07e15b8 100644 --- a/tensorflow/api_template.__init__.py +++ b/tensorflow/api_template.__init__.py @@ -21,8 +21,6 @@ from __future__ import print_function as _print_function import os as _os # pylint: disable=g-bad-import-order -from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import - from tensorflow.python.tools import component_api_helper as _component_api_helper _component_api_helper.package_hook( parent_package_str=__name__, diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 873c41a390..1b496bde47 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -304,10 +304,6 @@ tf_module { name: "ones_initializer" mtype: "" } - member { - name: "pywrap_tensorflow" - mtype: "" - } member { name: "qint16" mtype: "" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index f756bb80bc..c7bf73ba68 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -243,6 +243,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.multinomial": "tf.random.categorical", "tf.random.multinomial": "tf.random.categorical", "tf.load_file_system_library": "tf.load_library", + "tf.pywrap_tensorflow": "tf.compat.v1.pywrap_tensorflow", }) # pylint: enable=line-too-long -- GitLab From bd258fe6d5761e864d07fbef52cd0835387be221 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Wed, 21 Nov 2018 12:37:15 -0800 Subject: [PATCH 218/672] Removed mentions of tf.get_partitioned_variable_list PiperOrigin-RevId: 222446589 --- tensorflow/python/ops/partitioned_variables.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 5ba1d46a66..98a95f9f58 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -96,7 +96,7 @@ def variable_axis_size_partitioner( Returns: A partition function usable as the `partitioner` argument to - `variable_scope`, `get_variable`, and `get_partitioned_variable_list`. + `variable_scope` and `get_variable`. Raises: ValueError: If any of the byte counts are non-positive. @@ -175,7 +175,7 @@ def min_max_variable_partitioner(max_partitions=1, axis=0, Returns: A partition function usable as the `partitioner` argument to - `variable_scope`, `get_variable`, and `get_partitioned_variable_list`. + `variable_scope` and `get_variable`. """ def _partitioner(shape, dtype): @@ -228,7 +228,7 @@ def fixed_size_partitioner(num_shards, axis=0): Returns: A partition function usable as the `partitioner` argument to - `variable_scope`, `get_variable`, and `get_partitioned_variable_list`. + `variable_scope` and `get_variable`. """ def _partitioner(shape, **unused_args): partitions_list = [1] * len(shape) -- GitLab From a300c1de46dd71f07432d6368a1c2c48c4b69428 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 12:47:04 -0800 Subject: [PATCH 219/672] Remove the duplication of Convolution code, and rename TFLITE_USE_APPLE_ACCELERATE_FOR_CONV to TF_LITE_USE_CBLAS. PiperOrigin-RevId: 222447851 --- tensorflow/lite/kernels/conv.cc | 16 +-- tensorflow/lite/kernels/internal/BUILD | 2 - .../kernels/internal/optimized/cblas_conv.h | 109 ------------------ .../internal/optimized/cblas_reference.h | 69 ----------- .../internal/optimized/optimized_ops.h | 55 +++++++-- .../lite/tools/make/targets/ios_makefile.inc | 2 +- 6 files changed, 47 insertions(+), 206 deletions(-) delete mode 100644 tensorflow/lite/kernels/internal/optimized/cblas_conv.h delete mode 100644 tensorflow/lite/kernels/internal/optimized/cblas_reference.h diff --git a/tensorflow/lite/kernels/conv.cc b/tensorflow/lite/kernels/conv.cc index 0c14b9eb65..1fd870be93 100644 --- a/tensorflow/lite/kernels/conv.cc +++ b/tensorflow/lite/kernels/conv.cc @@ -24,7 +24,6 @@ limitations under the License. #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/kernels/eigen_support.h" #include "tensorflow/lite/kernels/gemm_support.h" -#include "tensorflow/lite/kernels/internal/optimized/cblas_conv.h" #include "tensorflow/lite/kernels/internal/optimized/multithreaded_conv.h" #include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h" #include "tensorflow/lite/kernels/internal/quantization_util.h" @@ -491,11 +490,10 @@ void EvalFloat(TfLiteContext* context, TfLiteNode* node, CalculateActivationRange(params->activation, &output_activation_min, &output_activation_max); KernelType effective_kernel_type; - if ((kernel_type == kMultithreadOptimized || - kernel_type == kCblasOptimized) && + if ((kernel_type == kMultithreadOptimized) && (params->dilation_width_factor != 1 || params->dilation_height_factor != 1)) { - // kMultithreadOptimized and kCblasOptimized do not support dilation. + // kMultithreadOptimized does not support dilation. // Therefore, fallback to optimized. effective_kernel_type = kGenericOptimized; } else { @@ -521,6 +519,7 @@ void EvalFloat(TfLiteContext* context, TfLiteNode* node, GetTensorData(im2col)); break; } + case kCblasOptimized: case kGenericOptimized: { optimized_ops::Conv(op_params, GetTensorShape(input), GetTensorData(input), GetTensorShape(filter), @@ -546,15 +545,6 @@ void EvalFloat(TfLiteContext* context, TfLiteNode* node, GetTensorData(im2col)); break; } - case kCblasOptimized: { - cblas_ops::Conv(op_params, GetTensorShape(input), - GetTensorData(input), GetTensorShape(filter), - GetTensorData(filter), GetTensorShape(bias), - GetTensorData(bias), GetTensorShape(output), - GetTensorData(output), GetTensorShape(im2col), - GetTensorData(im2col)); - break; - } } } diff --git a/tensorflow/lite/kernels/internal/BUILD b/tensorflow/lite/kernels/internal/BUILD index 6d9690ea46..7d2653f0a1 100644 --- a/tensorflow/lite/kernels/internal/BUILD +++ b/tensorflow/lite/kernels/internal/BUILD @@ -234,8 +234,6 @@ cc_library( cc_library( name = "optimized", hdrs = [ - "optimized/cblas_conv.h", - "optimized/cblas_reference.h", "optimized/eigen_spatial_convolutions.h", "optimized/eigen_tensor_reduced_instantiations_oss.h", "optimized/multithreaded_conv.h", diff --git a/tensorflow/lite/kernels/internal/optimized/cblas_conv.h b/tensorflow/lite/kernels/internal/optimized/cblas_conv.h deleted file mode 100644 index 5377205050..0000000000 --- a/tensorflow/lite/kernels/internal/optimized/cblas_conv.h +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_CBLAS_CONV_H_ -#define TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_CBLAS_CONV_H_ - -// The Conv implementation based on CBLAS interface. This is only used on iOS -// for now, utilizing Apple's Accelerate framework. - -#if TFLITE_USE_APPLE_ACCELERATE_FOR_CONV -#include -#else -#include "tensorflow/lite/kernels/internal/optimized/cblas_reference.h" -#endif - -#include "tensorflow/lite/kernels/internal/optimized/multithreaded_conv.h" -#include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h" - -namespace tflite { -namespace cblas_ops { - -inline void Conv(const ConvParams& params, const RuntimeShape& input_shape, - const float* input_data, const RuntimeShape& filter_shape, - const float* filter_data, const RuntimeShape& bias_shape, - const float* bias_data, const RuntimeShape& output_shape, - float* output_data, const RuntimeShape& im2col_shape, - float* im2col_data) { - const int stride_width = params.stride_width; - const int stride_height = params.stride_height; - const int pad_width = params.padding_values.width; - const int pad_height = params.padding_values.height; - const int dilation_width_factor = params.dilation_width_factor; - const int dilation_height_factor = params.dilation_height_factor; - const float output_activation_min = params.float_activation_min; - const float output_activation_max = params.float_activation_max; - TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); - TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); - TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); - gemmlowp::ScopedProfilingLabel label("Conv/cblas"); - - const float* gemm_input_data = nullptr; - const RuntimeShape* gemm_input_shape = nullptr; - const int filter_width = filter_shape.Dims(2); - const int filter_height = filter_shape.Dims(1); - const bool need_im2col = stride_width != 1 || stride_height != 1 || - filter_width != 1 || filter_height != 1; - if (need_im2col) { - TFLITE_DCHECK(im2col_data); - ConvParams op_params; - op_params.padding_type = PaddingType::kSame; - op_params.padding_values.width = pad_width; - op_params.padding_values.height = pad_height; - op_params.stride_width = stride_width; - op_params.stride_height = stride_height; - op_params.dilation_width_factor = dilation_width_factor; - op_params.dilation_height_factor = dilation_height_factor; - optimized_ops::Im2col(op_params, filter_height, filter_width, 0, - input_shape, input_data, im2col_shape, im2col_data); - - gemm_input_data = im2col_data; - gemm_input_shape = &im2col_shape; - } else { - TFLITE_DCHECK(!im2col_data); - gemm_input_data = input_data; - gemm_input_shape = &input_shape; - } - - // The following code computes matrix multiplication c = a * transponse(b) - // with CBLAS, where: - // * `a` is a matrix with dimensions (m, k). - // * `b` is a matrix with dimensions (n, k), so transpose(b) is (k, n). - // * `c` is a matrix with dimensions (m, n). - // The naming of variables are aligned with CBLAS specification here. - const float* a = gemm_input_data; - const float* b = filter_data; - float* c = output_data; - const int gemm_input_dims = gemm_input_shape->DimensionsCount(); - int m = FlatSizeSkipDim(*gemm_input_shape, gemm_input_dims - 1); - int n = output_shape.Dims(3); - int k = gemm_input_shape->Dims(gemm_input_dims - 1); - // The stride of matrix a, b and c respectively. - int stride_a = k; - int stride_b = k; - int stride_c = n; - - cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, n, k, 1.0f, a, - stride_a, b, stride_b, 0.0f, c, stride_c); - - optimized_ops::AddBiasAndEvalActivationFunction( - output_activation_min, output_activation_max, bias_shape, bias_data, - output_shape, output_data); -} - -} // namespace cblas_ops -} // namespace tflite - -#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_CBLAS_CONV_H_ diff --git a/tensorflow/lite/kernels/internal/optimized/cblas_reference.h b/tensorflow/lite/kernels/internal/optimized/cblas_reference.h deleted file mode 100644 index fa07578612..0000000000 --- a/tensorflow/lite/kernels/internal/optimized/cblas_reference.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_CBLAS_REFERENCE_H_ -#define TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_CBLAS_REFERENCE_H_ - -#include "tensorflow/lite/kernels/internal/compatibility.h" - -// The reference implementation for a small subset of CBLAS interface. -// This is only used for testing CBLAS implementation, and should never be used -// in production code. - -namespace tflite { -namespace cblas_ops { - -// The following code follows the original CBLAS specification, and it might -// conflict with the TensorFlow naming convention. -// TODO(ycling): Find another way to test CBLAS with bazel, without writing -// a reference implementation by ourselves. -enum CBLAS_ORDER { CblasRowMajor = 0, CblasColMajor = 1 }; - -enum CBLAS_TRANSPOSE { CblasNoTrans = 0, CblasTrans = 1, CblasConjTrans = 2 }; - -// A reference implementation for matrix multiplication. -// The following code computes, c = a * transponse(b) matrix multiplication -// with CBLAS, where: -// * `a` is a matrix with dimensions (m, k). -// * `b` is a matrix with dimensions (n, k), so transpose(b) is (k, n). -// * `c` is a matrix with dimensions (m, n). -// The naming of variables is aligned with CBLAS specification here. -void cblas_sgemm(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE trans_a, - const enum CBLAS_TRANSPOSE trans_b, const int m, const int n, - const int k, const float alpha, const float *a, - const int stride_a, const float *b, const int stride_b, - const float beta, float *c, const int stride_c) { - TFLITE_DCHECK(order == CblasRowMajor); - TFLITE_DCHECK(trans_a == CblasNoTrans); - TFLITE_DCHECK(trans_b == CblasTrans); - TFLITE_DCHECK(beta == 0.0f); - for (int row = 0; row < m; ++row) { - for (int col = 0; col < n; ++col) { - // If `beta` non-zero, multiple it with the original values in output. - // Otherwise, ignore the original value in output completely. - float value = 0.0f; - for (int idx = 0; idx < k; ++idx) { - value += alpha * a[stride_a * row + idx] * b[stride_b * col + idx]; - } - c[stride_c * row + col] = value; - } - } -} - -} // namespace cblas_ops -} // namespace tflite - -#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_CBLAS_REFERENCE_H_ diff --git a/tensorflow/lite/kernels/internal/optimized/optimized_ops.h b/tensorflow/lite/kernels/internal/optimized/optimized_ops.h index e2329c79c7..df335e9e92 100644 --- a/tensorflow/lite/kernels/internal/optimized/optimized_ops.h +++ b/tensorflow/lite/kernels/internal/optimized/optimized_ops.h @@ -25,6 +25,10 @@ limitations under the License. #include #include +#if defined(TF_LITE_USE_CBLAS) && defined(__APPLE__) +#include +#endif + #include "third_party/eigen3/Eigen/Core" #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "fixedpoint/fixedpoint.h" @@ -1868,18 +1872,45 @@ inline void Conv(const ConvParams& params, const RuntimeShape& input_shape, gemm_input_shape = &input_shape; } - const auto im2col_matrix_map = - MapAsMatrixWithLastDimAsRows(gemm_input_data, *gemm_input_shape); - const auto filter_matrix_map = - MapAsMatrixWithFirstDimAsCols(filter_data, filter_shape); - auto output_matrix_map = - MapAsMatrixWithLastDimAsRows(output_data, output_shape); - - Gemm(filter_matrix_map.transpose(), im2col_matrix_map, &output_matrix_map); - - AddBiasAndEvalActivationFunction(output_activation_min, output_activation_max, - bias_shape, bias_data, output_shape, - output_data); + // The following code computes matrix multiplication c = a * transponse(b) + // with CBLAS, where: + // * `a` is a matrix with dimensions (m, k). + // * `b` is a matrix with dimensions (n, k), so transpose(b) is (k, n). + // * `c` is a matrix with dimensions (m, n). + // The naming of variables are aligned with CBLAS specification here. + const float* a = gemm_input_data; + const float* b = filter_data; + float* c = output_data; + const int gemm_input_dims = gemm_input_shape->DimensionsCount(); + int m = FlatSizeSkipDim(*gemm_input_shape, gemm_input_dims - 1); + int n = output_shape.Dims(3); + int k = gemm_input_shape->Dims(gemm_input_dims - 1); + +#if defined(TF_LITE_USE_CBLAS) && defined(__APPLE__) + // The stride of matrix a, b and c respectively. + int stride_a = k; + int stride_b = k; + int stride_c = n; + + cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, m, n, k, 1.0f, a, + stride_a, b, stride_b, 0.0f, c, stride_c); +#else + // When an optimized CBLAS implementation is not available, fall back + // to using Eigen. + typedef Eigen::Matrix + Matrix; + typedef Eigen::Map MatrixRef; + typedef Eigen::Map ConstMatrixRef; + + MatrixRef matrix_c(c, m, n); + ConstMatrixRef matrix_a(a, m, k); + ConstMatrixRef matrix_b(b, n, k); + matrix_c.noalias() = matrix_a * matrix_b.transpose(); +#endif // defined(TF_LITE_USE_CBLAS) && defined(__APPLE__) + + optimized_ops::AddBiasAndEvalActivationFunction( + output_activation_min, output_activation_max, bias_shape, bias_data, + output_shape, output_data); } inline void HybridConv(const ConvParams& params, float* scaling_factors_ptr, diff --git a/tensorflow/lite/tools/make/targets/ios_makefile.inc b/tensorflow/lite/tools/make/targets/ios_makefile.inc index 7f36b8ecef..ae9276f9a6 100644 --- a/tensorflow/lite/tools/make/targets/ios_makefile.inc +++ b/tensorflow/lite/tools/make/targets/ios_makefile.inc @@ -22,7 +22,7 @@ ifeq ($(TARGET), ios) TARGET_ARCH := x86_64 CXXFLAGS += -miphoneos-version-min=$(MIN_SDK_VERSION) \ -DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK \ - -DTFLITE_USE_APPLE_ACCELERATE_FOR_CONV \ + -DTF_LITE_USE_CBLAS \ -fembed-bitcode \ -Wno-c++11-narrowing \ -mno-thumb \ -- GitLab From 32e55164f691ff1f61a57a7bf36d414cb7ac7968 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 12:54:21 -0800 Subject: [PATCH 220/672] Update Google Cloud Bigtable C++ Client to the v0.3.0 release. PiperOrigin-RevId: 222448784 --- .../test_kernels/bigtable_test_client.cc | 33 +++++++++++++++++++ .../test_kernels/bigtable_test_client.h | 19 +++++++++++ tensorflow/workspace.bzl | 8 ++--- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.cc b/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.cc index f083ce6f44..e95dc57718 100644 --- a/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.cc +++ b/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.cc @@ -366,6 +366,39 @@ BigtableTestClient::MutateRows( return MakeUnique(request.entries_size()); } +std::unique_ptr> +BigtableTestClient::AsyncMutateRow( + grpc::ClientContext* context, + google::bigtable::v2::MutateRowRequest const& request, + grpc::CompletionQueue* cq) { + LOG(WARNING) << "Call to InMemoryDataClient::" << __func__ + << "(); this will likely cause a crash!"; + return nullptr; +} + +std::unique_ptr<::grpc::ClientAsyncReaderInterface< + ::google::bigtable::v2::SampleRowKeysResponse>> +BigtableTestClient::AsyncSampleRowKeys( + ::grpc::ClientContext* context, + const ::google::bigtable::v2::SampleRowKeysRequest& request, + ::grpc::CompletionQueue* cq, void* tag) { + LOG(WARNING) << "Call to InMemoryDataClient::" << __func__ + << "(); this will likely cause a crash!"; + return nullptr; +} + +std::unique_ptr<::grpc::ClientAsyncReaderInterface< + ::google::bigtable::v2::MutateRowsResponse>> +BigtableTestClient::AsyncMutateRows( + ::grpc::ClientContext* context, + const ::google::bigtable::v2::MutateRowsRequest& request, + ::grpc::CompletionQueue* cq, void* tag) { + LOG(WARNING) << "Call to InMemoryDataClient::" << __func__ + << "(); this will likely cause a crash!"; + return nullptr; +} + std::shared_ptr BigtableTestClient::Channel() { LOG(WARNING) << "Call to InMemoryDataClient::Channel(); this will likely " "cause a crash!"; diff --git a/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.h b/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.h index dac2b16a21..c4a1f06bc5 100644 --- a/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.h +++ b/tensorflow/contrib/bigtable/kernels/test_kernels/bigtable_test_client.h @@ -61,6 +61,25 @@ class BigtableTestClient : public ::google::cloud::bigtable::DataClient { MutateRows(grpc::ClientContext* context, google::bigtable::v2::MutateRowsRequest const& request) override; + std::unique_ptr> + AsyncMutateRow(grpc::ClientContext* context, + google::bigtable::v2::MutateRowRequest const& request, + grpc::CompletionQueue* cq) override; + + std::unique_ptr<::grpc::ClientAsyncReaderInterface< + ::google::bigtable::v2::SampleRowKeysResponse>> + AsyncSampleRowKeys( + ::grpc::ClientContext* context, + const ::google::bigtable::v2::SampleRowKeysRequest& request, + ::grpc::CompletionQueue* cq, void* tag) override; + + std::unique_ptr<::grpc::ClientAsyncReaderInterface< + ::google::bigtable::v2::MutateRowsResponse>> + AsyncMutateRows(::grpc::ClientContext* context, + const ::google::bigtable::v2::MutateRowsRequest& request, + ::grpc::CompletionQueue* cq, void* tag) override; + std::shared_ptr Channel() override; private: diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 5c58bb1080..7ad094c507 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -179,15 +179,15 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "com_github_googlecloudplatform_google_cloud_cpp", - sha256 = "fdd3b3aecce60987e5525e55bf3a21d68a8695320bd5b980775af6507eec3944", - strip_prefix = "google-cloud-cpp-14760a86c4ffab9943b476305c4fe927ad95db1c", + sha256 = "3ade2072e6588ff56c0434abe6c63aa5f3f2d56be15a299bafc7e9cdf0a12c17", + strip_prefix = "google-cloud-cpp-0.3.0", system_build_file = clean_dep("//third_party/systemlibs:google_cloud_cpp.BUILD"), system_link_files = { "//third_party/systemlibs:google_cloud_cpp.google.cloud.bigtable.BUILD": "google/cloud/bigtable/BUILD", }, urls = [ - "https://mirror.bazel.build/github.com/GoogleCloudPlatform/google-cloud-cpp/archive/14760a86c4ffab9943b476305c4fe927ad95db1c.tar.gz", - "https://github.com/GoogleCloudPlatform/google-cloud-cpp/archive/14760a86c4ffab9943b476305c4fe927ad95db1c.tar.gz", + "https://mirror.bazel.build/github.com/GoogleCloudPlatform/google-cloud-cpp/archive/v0.3.0.tar.gz", + "https://github.com/GoogleCloudPlatform/google-cloud-cpp/archive/v0.3.0.tar.gz", ], ) -- GitLab From dd3b98867f9809023ce975bcd3e96dba4021d7bb Mon Sep 17 00:00:00 2001 From: Sami Kama Date: Wed, 21 Nov 2018 13:19:46 -0800 Subject: [PATCH 221/672] Re-apply buildifier --- tensorflow/core/BUILD | 114 +++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 41d3f6eab8..52d3f8f2b9 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -1349,63 +1349,63 @@ cc_library( name = "all_kernels_statically_linked", visibility = ["//visibility:private"], deps = [ - "//tensorflow/core/kernels:array", - "//tensorflow/core/kernels:audio", - "//tensorflow/core/kernels:batch_kernels", - "//tensorflow/core/kernels:bincount_op", - "//tensorflow/core/kernels:boosted_trees_ops", - "//tensorflow/core/kernels:candidate_sampler_ops", - "//tensorflow/core/kernels:checkpoint_ops", - "//tensorflow/core/kernels:collective_ops", - "//tensorflow/core/kernels:control_flow_ops", - "//tensorflow/core/kernels:ctc_ops", - "//tensorflow/core/kernels:cudnn_rnn_kernels", - "//tensorflow/core/kernels:data_flow", - "//tensorflow/core/kernels:dataset_ops", - "//tensorflow/core/kernels:decode_proto_op", - "//tensorflow/core/kernels:encode_proto_op", - "//tensorflow/core/kernels:fake_quant_ops", - "//tensorflow/core/kernels:function_ops", - "//tensorflow/core/kernels:functional_ops", - "//tensorflow/core/kernels:grappler", - "//tensorflow/core/kernels:histogram_op", - "//tensorflow/core/kernels:image", - "//tensorflow/core/kernels:io", - "//tensorflow/core/kernels:linalg", - "//tensorflow/core/kernels:list_kernels", - "//tensorflow/core/kernels:lookup", - "//tensorflow/core/kernels:logging", - "//tensorflow/core/kernels:manip", - "//tensorflow/core/kernels:math", - "//tensorflow/core/kernels:multinomial_op", - "//tensorflow/core/kernels:nn", - "//tensorflow/core/kernels:parameterized_truncated_normal_op", - "//tensorflow/core/kernels:parsing", - "//tensorflow/core/kernels:partitioned_function_ops", - "//tensorflow/core/kernels:ragged_ops", - "//tensorflow/core/kernels:random_ops", - "//tensorflow/core/kernels:random_poisson_op", - "//tensorflow/core/kernels:remote_fused_graph_ops", - "//tensorflow/core/kernels:required", - "//tensorflow/core/kernels:resource_variable_ops", - "//tensorflow/core/kernels:rpc_op", - "//tensorflow/core/kernels:scoped_allocator_ops", - "//tensorflow/core/kernels:sdca_ops", - "//tensorflow/core/kernels:searchsorted_op", - "//tensorflow/core/kernels:set_kernels", - "//tensorflow/core/kernels:sparse", - "//tensorflow/core/kernels:state", - "//tensorflow/core/kernels:stateless_random_ops", - "//tensorflow/core/kernels:string", - "//tensorflow/core/kernels:summary_kernels", - "//tensorflow/core/kernels:training_ops", - "//tensorflow/core/kernels:word2vec_kernels", - ] + tf_additional_cloud_kernel_deps() + - select({ - "//tensorflow:no_nccl_support": [], - "//tensorflow:windows": [], - "//conditions:default": ["//tensorflow/core/kernels:nccl_kernels"], - }) + if_not_windows([ + "//tensorflow/core/kernels:array", + "//tensorflow/core/kernels:audio", + "//tensorflow/core/kernels:batch_kernels", + "//tensorflow/core/kernels:bincount_op", + "//tensorflow/core/kernels:boosted_trees_ops", + "//tensorflow/core/kernels:candidate_sampler_ops", + "//tensorflow/core/kernels:checkpoint_ops", + "//tensorflow/core/kernels:collective_ops", + "//tensorflow/core/kernels:control_flow_ops", + "//tensorflow/core/kernels:ctc_ops", + "//tensorflow/core/kernels:cudnn_rnn_kernels", + "//tensorflow/core/kernels:data_flow", + "//tensorflow/core/kernels:dataset_ops", + "//tensorflow/core/kernels:decode_proto_op", + "//tensorflow/core/kernels:encode_proto_op", + "//tensorflow/core/kernels:fake_quant_ops", + "//tensorflow/core/kernels:function_ops", + "//tensorflow/core/kernels:functional_ops", + "//tensorflow/core/kernels:grappler", + "//tensorflow/core/kernels:histogram_op", + "//tensorflow/core/kernels:image", + "//tensorflow/core/kernels:io", + "//tensorflow/core/kernels:linalg", + "//tensorflow/core/kernels:list_kernels", + "//tensorflow/core/kernels:lookup", + "//tensorflow/core/kernels:logging", + "//tensorflow/core/kernels:manip", + "//tensorflow/core/kernels:math", + "//tensorflow/core/kernels:multinomial_op", + "//tensorflow/core/kernels:nn", + "//tensorflow/core/kernels:parameterized_truncated_normal_op", + "//tensorflow/core/kernels:parsing", + "//tensorflow/core/kernels:partitioned_function_ops", + "//tensorflow/core/kernels:ragged_ops", + "//tensorflow/core/kernels:random_ops", + "//tensorflow/core/kernels:random_poisson_op", + "//tensorflow/core/kernels:remote_fused_graph_ops", + "//tensorflow/core/kernels:required", + "//tensorflow/core/kernels:resource_variable_ops", + "//tensorflow/core/kernels:rpc_op", + "//tensorflow/core/kernels:scoped_allocator_ops", + "//tensorflow/core/kernels:sdca_ops", + "//tensorflow/core/kernels:searchsorted_op", + "//tensorflow/core/kernels:set_kernels", + "//tensorflow/core/kernels:sparse", + "//tensorflow/core/kernels:state", + "//tensorflow/core/kernels:stateless_random_ops", + "//tensorflow/core/kernels:string", + "//tensorflow/core/kernels:summary_kernels", + "//tensorflow/core/kernels:training_ops", + "//tensorflow/core/kernels:word2vec_kernels", + ] + tf_additional_cloud_kernel_deps() + + select({ + "//tensorflow:no_nccl_support": [], + "//tensorflow:windows": [], + "//conditions:default": ["//tensorflow/core/kernels:nccl_kernels"], + }) + if_not_windows([ "//tensorflow/core/kernels:fact_op", "//tensorflow/core/kernels:array_not_windows", "//tensorflow/core/kernels:math_not_windows", -- GitLab From 12ef5a5fe9a95739f8cbc6c74f89b2959d2d2286 Mon Sep 17 00:00:00 2001 From: Yu-Cheng Ling Date: Wed, 21 Nov 2018 13:22:44 -0800 Subject: [PATCH 222/672] Revert TFLite examples to use tensorflow/contrib/lite The CocoaPod didn't catch up with the changes which moves TFLite out of contrib/ directory. Reverting for now. --- .../examples/ios/camera/CameraExampleViewController.h | 4 ++-- .../examples/ios/camera/CameraExampleViewController.mm | 8 ++++---- .../lite/examples/ios/simple/RunModelViewController.mm | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tensorflow/lite/examples/ios/camera/CameraExampleViewController.h b/tensorflow/lite/examples/ios/camera/CameraExampleViewController.h index 6bc94e9502..fb5800e86d 100644 --- a/tensorflow/lite/examples/ios/camera/CameraExampleViewController.h +++ b/tensorflow/lite/examples/ios/camera/CameraExampleViewController.h @@ -17,8 +17,8 @@ #include -#include "tensorflow/lite/kernels/register.h" -#include "tensorflow/lite/model.h" +#include "tensorflow/contrib/lite/kernels/register.h" +#include "tensorflow/contrib/lite/model.h" @interface CameraExampleViewController : UIViewController { diff --git a/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm b/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm index 1e6725592b..996cff2616 100644 --- a/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm +++ b/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm @@ -23,10 +23,10 @@ #include #include -#include "tensorflow/lite/kernels/register.h" -#include "tensorflow/lite/model.h" -#include "tensorflow/lite/string_util.h" -#include "tensorflow/lite/op_resolver.h" +#include "tensorflow/contrib/lite/kernels/register.h" +#include "tensorflow/contrib/lite/model.h" +#include "tensorflow/contrib/lite/string_util.h" +#include "tensorflow/contrib/lite/op_resolver.h" #define LOG(x) std::cerr diff --git a/tensorflow/lite/examples/ios/simple/RunModelViewController.mm b/tensorflow/lite/examples/ios/simple/RunModelViewController.mm index e5764944f6..650c73f732 100644 --- a/tensorflow/lite/examples/ios/simple/RunModelViewController.mm +++ b/tensorflow/lite/examples/ios/simple/RunModelViewController.mm @@ -22,10 +22,10 @@ #include #include -#include "tensorflow/lite/kernels/register.h" -#include "tensorflow/lite/model.h" -#include "tensorflow/lite/string_util.h" -#include "tensorflow/lite/op_resolver.h" +#include "tensorflow/contrib/lite/kernels/register.h" +#include "tensorflow/contrib/lite/model.h" +#include "tensorflow/contrib/lite/string_util.h" +#include "tensorflow/contrib/lite/op_resolver.h" #include "ios_image_load.h" -- GitLab From 2dc24d1cf094d2a63fcf14a65d8f20691880f6a1 Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Wed, 21 Nov 2018 13:20:44 -0800 Subject: [PATCH 223/672] [JAX] Support Python 3 in JAX. Notable changes: * __builtins__ -> six.moves.builtins * xrange -> six.moves.xrange * reduce -> six.moves.reduce * map/filter return generators, so add explicit list() calls around many to avoid a semantic change. Probably too conservative, but it's easier to add them everywhere than work out which are strictly necessary. * no long in Python 3 * raise TypeError, x -> raise TypeError(x) * gen.next() -> next(gen) * string / bytes * no tuple destructuring in lambda arguments. * / and np.divide changed semantics, use // and np.floor_divide. PiperOrigin-RevId: 222451919 --- tensorflow/compiler/xla/python/xla_client.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tensorflow/compiler/xla/python/xla_client.py b/tensorflow/compiler/xla/python/xla_client.py index 92b0685dbb..995d2b64dc 100644 --- a/tensorflow/compiler/xla/python/xla_client.py +++ b/tensorflow/compiler/xla/python/xla_client.py @@ -26,6 +26,9 @@ import os import numpy as np +import six +from six.moves import xrange + from tensorflow.compiler.xla import xla_data_pb2 from tensorflow.compiler.xla.python import pywrap_xla as c_api from tensorflow.compiler.xla.service import hlo_pb2 @@ -322,6 +325,9 @@ class Shape(object): def __ne__(self, other): return not self == other + def __hash__(self): + return hash((self._dtype, self._dimensions, self._minor_to_major)) + def __repr__(self): return ('xla_client.Shape(_dtype={!r}, _dimensions={!r}, ' '_is_tuple={!r}, _minor_to_major={!r})').format( @@ -541,6 +547,8 @@ class LocalComputation(object): ] result_shape = result_shape.map_leaves(layout_fn) + argument_shapes = list(argument_shapes) + compile_options = compile_options or CompileOptions() compile_options.result_shape = result_shape if self._backend.backend_type == BackendType.XRT: @@ -1380,6 +1388,8 @@ def initialize_platform_name(platform_name): Raises: A runtime exception if the XLA service has already been initialized. """ + if six.PY3: + platform_name = platform_name.encode('utf-8') c_api.InitializePlatformName(platform_name) -- GitLab From a2bda5a8b45a08dbd6c0580a0290777741c32d29 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 21 Nov 2018 13:27:53 -0800 Subject: [PATCH 224/672] Add Sigmoid, Tanh ops and unit tests. --- .../contrib/tensorrt/convert/convert_graph.cc | 2 + .../contrib/tensorrt/convert/convert_nodes.cc | 40 +++++++++- .../tensorrt/convert/convert_nodes_test.cc | 77 +++++++++++++++++++ 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 21f505b7fe..589db56758 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -96,6 +96,8 @@ Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node) { "MaxPool", "BiasAdd", "Relu", + "Sigmoid", + "Tanh", "Add", "Mul", "Sub", diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 631c2575c0..b1fa6a51d4 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -1977,13 +1977,43 @@ tensorflow::Status ConvertPool(OpConverterParams* params) { } tensorflow::Status ConvertActivation(OpConverterParams* params) { - const nvinfer1::ITensor* tensor = params->inputs.at(0).tensor(); + const auto& inputs = params->inputs; + const auto& node_def = params->node_def; + if (inputs.size() != 1) { + return tensorflow::errors::InvalidArgument( + node_def.op(), " expects one input, at ", node_def.name()); + } + if (!inputs.at(0).is_tensor()) { + return tensorflow::errors::Unimplemented( + node_def.op(), " is only implemented for tensors, at ", node_def.name()); + } + static const std::unordered_map ops{ + {"Relu", nvinfer1::ActivationType::kRELU}, + {"Sigmoid", nvinfer1::ActivationType::kSIGMOID}, + {"Tanh", nvinfer1::ActivationType::kTANH}, + }; + auto op_pair = ops.find(node_def.op()); + if (op_pair == ops.end()) { + return tensorflow::errors::Unimplemented( + "Activation op: ", node_def.op(), " not supported at: ", + node_def.name()); + } + if (params->validation_only) return tensorflow::Status::OK(); + + // Start conversion. + const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); nvinfer1::IActivationLayer* layer = params->converter->network()->addActivation( *const_cast(tensor), - nvinfer1::ActivationType::kRELU); - TFTRT_RETURN_ERROR_IF_NULLPTR(layer, params->node_def.name()); + op_pair->second); + TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); nvinfer1::ITensor* output_tensor = layer->getOutput(0); + // Set quantization range for output of Sigmoid, Tanh. + if (node_def.op() == "Sigmoid") { + params->converter->ProvideQuantizationRange(output_tensor, 0.0f, 1.0f); + } else if (node_def.op() == "Tanh") { + params->converter->ProvideQuantizationRange(output_tensor, -1.0f, 1.0f); + } params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); return tensorflow::Status::OK(); } @@ -3093,6 +3123,9 @@ static void RegisterValidatableOpConverters( {"Add", "Mul", "Sub", "Div", "RealDiv", "Maximum", "Minimum"}) { (*registration)[binary_op_type] = ConvertBinary; } + for (auto activation_op_type : {"Relu", "Sigmoid", "Tanh"}) { + (*registration)[activation_op_type] = ConvertActivation; + } } void TrtNodeValidator::RegisterOpValidators() { @@ -3104,7 +3137,6 @@ void Converter::RegisterOpConverters() { op_registry_["Conv2D"] = ConvertConv2D; op_registry_["DepthwiseConv2dNative"] = ConvertConv2DDepthwise; - op_registry_["Relu"] = ConvertActivation; op_registry_["MaxPool"] = ConvertPool; op_registry_["AvgPool"] = ConvertPool; // TODO(ben,jie): this is a temp hack. diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 603c4f7b5e..92697e2f87 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -1964,6 +1964,83 @@ TEST_F(OpConverterTest, ConvertRelu6) { } } +TEST_F(OpConverterTest, ConvertActivation) { + { + // Input list is empty, should fail. + NodeDef node_def = MakeNodeDef("my_act", "Relu", {}); + RunValidationAndConversion( + node_def, error::INVALID_ARGUMENT, + "Relu expects one input, at my_act"); + } + { + // Input is weights, should fail. + Reset(); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto relu = ops::Relu(s.WithOpName("my_act"), input); + const NodeDef& node_def = relu.operation.node()->def(); + AddTestWeights("input", {1, 2, 3}, {-3, -2, -1, 0, 1, 2}); + RunValidationAndConversion( + node_def, error::UNIMPLEMENTED, + "Relu is only implemented for tensors, at my_act"); + } + + // Get nodedef for activation layer. + auto get_act_nodedef = [](std::string op_name) -> NodeDef { + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + if (op_name == "Relu") { + auto act = ops::Relu(s.WithOpName("my_act"), input); + return act.operation.node()->def(); + } else if (op_name == "Sigmoid") { + auto act = ops::Sigmoid(s.WithOpName("my_act"), input); + return act.operation.node()->def(); + } else if (op_name == "Tanh") { + auto act = ops::Tanh(s.WithOpName("my_act"), input); + return act.operation.node()->def(); + } + EXPECT_TRUE(false); + return MakeNodeDef("my_act", "Relu", {}); + }; + // Get expected output for activation layer. + auto get_act_output = [](std::string op_name, float input) -> float { + if (op_name == "Relu") { + return (input > 0.0f) ? input : 0.0f; + } else if (op_name == "Sigmoid") { + return 1.0f / (1.0f + std::exp(-input)); + } else if (op_name == "Tanh") { + return std::tanh(input); + } + EXPECT_TRUE(false); + return input; + }; + + { + // Ok. + for (std::string op_name : {"Relu", "Sigmoid", "Tanh"}) { + Reset(); + NodeDef node_def = get_act_nodedef(op_name); + AddTestTensor("input", {1, 2, 3}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_act", &output)); + EXPECT_TRUE(output.is_tensor()); + EXPECT_TRUE(TrtDimsEqualsArray({1, 2, 3}, output.tensor()->getDimensions())) + << output.DebugString(); + + const std::vector input_data = {-100, -2, -1, 0, 1, 100}; + std::vector output_data(6); + BuildAndRun("input", input_data, "my_act", &output_data); + for (int i = 0; i < input_data.size(); i++) { + const float expected_output = get_act_output(op_name, input_data[i]); + EXPECT_FLOAT_EQ(output_data[i], expected_output) + << op_name << "(" << input_data[i] << ") should be equal to " + << expected_output; + } + } + } +} + } // namespace convert } // namespace tensorrt } // namespace tensorflow -- GitLab From 92f59bf4c3d88b9553c7f0fae17d9fff6fbf13ad Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 13:45:54 -0800 Subject: [PATCH 225/672] Slightly improve toco error messages. PiperOrigin-RevId: 222455209 --- tensorflow/lite/toco/tooling_util.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/lite/toco/tooling_util.cc b/tensorflow/lite/toco/tooling_util.cc index 084169548e..611add9daf 100644 --- a/tensorflow/lite/toco/tooling_util.cc +++ b/tensorflow/lite/toco/tooling_util.cc @@ -1035,10 +1035,10 @@ void CheckEachArray(const Model& model) { if (colon_pos != string::npos) { CHECK_EQ(name.substr(colon_pos + 1).find_first_not_of("0123456789"), string::npos) - << "Array name must only have digits after colon"; + << "Array '" << name << "' has non-digit characters after colon."; } - CHECK_GT(colon_pos, 0) - << "First character of array name must not be a colon."; + CHECK_GT(colon_pos, 0) << "Array '" << name + << "' must not start with a colon."; } } -- GitLab From da2d9779e0e4706b5df96c3cc71f81132445a8af Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 21 Nov 2018 13:58:59 -0800 Subject: [PATCH 226/672] Add square op and unit tests --- .../contrib/tensorrt/convert/convert_graph.cc | 1 + .../contrib/tensorrt/convert/convert_nodes.cc | 43 +++++++++++++++++++ .../tensorrt/convert/convert_nodes_test.cc | 42 ++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 21f505b7fe..74499a0298 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -129,6 +129,7 @@ Status TrtCandidateSelector::IsTensorRTCandidate(const tensorflow::Node* node) { "Max", "Min", "Relu6", + "Square", }; bool is_supported_op_type = (candidate_ops.count(node->type_string()) || diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 631c2575c0..6de3aba4d7 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -2496,6 +2496,48 @@ tensorflow::Status ConvertUnary(OpConverterParams* params) { return tensorflow::Status::OK(); } +tensorflow::Status ConvertSquare(OpConverterParams* params) { + const auto& inputs = params->inputs; + const auto& node_def = params->node_def; + if (inputs.size() != 1) { + return tensorflow::errors::InvalidArgument( + "Square expects one input, at ", node_def.name()); + } + if (inputs.at(0).is_weights()) { + return tensorflow::errors::Unimplemented( + "Square is only implemented for tensors, at ", node_def.name()); + } + if (params->validation_only) return Status::OK(); + + // Constant 2 with same rank as input + nvinfer1::Dims dims = inputs.at(0).GetTrtDims(); + for (int i = 0; i < dims.nbDims; i++) { + dims.d[i] = 1; + } + TRT_ShapedWeights weights = params->weight_store->GetTempWeights( + tensorflow::DataType::DT_FLOAT, dims); + auto weights_ptr = static_cast(const_cast( + weights.GetValues())); + weights_ptr[0] = 2.f; + nvinfer1::IConstantLayer* const2_layer = + params->converter->network()->addConstant(dims, weights.GetTrtWeights()); + TFTRT_RETURN_ERROR_IF_NULLPTR(const2_layer, node_def.name()); + + // ElementWise Pow Operation + const nvinfer1::ITensor* tensor_l = inputs.at(0).tensor(); + const nvinfer1::ITensor* tensor_r = const2_layer->getOutput(0); + nvinfer1::IElementWiseLayer* layer = + params->converter->network()->addElementWise( + *const_cast(tensor_l), + *const_cast(tensor_r), + nvinfer1::ElementWiseOperation::kPOW); + TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); + nvinfer1::ITensor* output_tensor = layer->getOutput(0); + + params->outputs->push_back(TRT_TensorOrWeights(output_tensor)); + return tensorflow::Status::OK(); +} + tensorflow::Status ConvertReduce(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; @@ -3083,6 +3125,7 @@ static void RegisterValidatableOpConverters( (*registration)["Reshape"] = ConvertReshape; (*registration)["MatMul"] = ConvertMatMul; (*registration)["Relu6"] = ConvertRelu6; + (*registration)["Square"] = ConvertSquare; for (auto quantization_op_type : {"QuantizeAndDequantizeV2", "QuantizeAndDequantizeV3", diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 603c4f7b5e..312375a661 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -1964,6 +1964,48 @@ TEST_F(OpConverterTest, ConvertRelu6) { } } +TEST_F(OpConverterTest, ConvertSquare) { + { + // Input list is empty, should fail. + NodeDef node_def = MakeNodeDef("my_square", "Square", {}); + RunValidationAndConversion( + node_def, error::INVALID_ARGUMENT, + "Square expects one input, at my_square"); + } + + // Get the NodeDef for Square. + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto square = ops::Square(s.WithOpName("my_square"), input); + const NodeDef& node_def = square.operation.node()->def(); + + { + // Input is weights, should fail. + Reset(); + AddTestWeights("input", {1, 2, 3}, {1, 2, 3, 4, -5, 6}); + RunValidationAndConversion(node_def, error::UNIMPLEMENTED, + "Square is only implemented for tensors, at my_square"); + } + { + // Input is tensor, Ok. + Reset(); + AddTestTensor("input", {1, 2, 3}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_square", &output)); + EXPECT_TRUE(output.is_tensor()); + EXPECT_TRUE(TrtDimsEqualsArray({1, 2, 3}, output.tensor()->getDimensions())) + << output.DebugString(); + + std::vector output_data(6); + std::vector expected_output_data = {1, 4, 9, 16, 25, 36}; + BuildAndRun("input", {1, 2, 3, 4, -5, 6}, "my_square", &output_data); + for (int i = 0; i < output_data.size(); i++) { + EXPECT_FLOAT_EQ(output_data[i], expected_output_data[i]); + } + } +} + } // namespace convert } // namespace tensorrt } // namespace tensorflow -- GitLab From 9c17bfba4885cf95ae7f2ec3ede96520d2bbfe59 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 21 Nov 2018 13:57:32 -0800 Subject: [PATCH 227/672] Change l2_normalize API for TF 2.0. PiperOrigin-RevId: 222456684 --- tensorflow/python/ops/nn_impl.py | 29 +++++++++++++++++-- .../api/golden/v2/tensorflow.linalg.pbtxt | 2 +- .../tools/api/golden/v2/tensorflow.math.pbtxt | 2 +- .../tools/api/golden/v2/tensorflow.nn.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 9 ++++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index 9cf53f191a..6591da5be8 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -329,7 +329,7 @@ def swish(features): return features * math_ops.sigmoid(features) -@tf_export("math.l2_normalize", "linalg.l2_normalize", "nn.l2_normalize") +@tf_export(v1=["math.l2_normalize", "linalg.l2_normalize", "nn.l2_normalize"]) @deprecated_args(None, "dim is deprecated, use axis instead", "dim") def l2_normalize(x, axis=None, epsilon=1e-12, name=None, dim=None): """Normalizes along dimension `axis` using an L2 norm. @@ -350,11 +350,36 @@ def l2_normalize(x, axis=None, epsilon=1e-12, name=None, dim=None): name: A name for this operation (optional). dim: Deprecated alias for axis. + Returns: + A `Tensor` with the same shape as `x`. + """ + axis = deprecated_argument_lookup("axis", axis, "dim", dim) + return l2_normalize_v2(x, axis, epsilon, name) + + +@tf_export("math.l2_normalize", "linalg.l2_normalize", "nn.l2_normalize", v1=[]) +def l2_normalize_v2(x, axis=None, epsilon=1e-12, name=None): + """Normalizes along dimension `axis` using an L2 norm. + + For a 1-D tensor with `axis = 0`, computes + + output = x / sqrt(max(sum(x**2), epsilon)) + + For `x` with more dimensions, independently normalizes each 1-D slice along + dimension `axis`. + + Args: + x: A `Tensor`. + axis: Dimension along which to normalize. A scalar or a vector of + integers. + epsilon: A lower bound value for the norm. Will use `sqrt(epsilon)` as the + divisor if `norm < sqrt(epsilon)`. + name: A name for this operation (optional). + Returns: A `Tensor` with the same shape as `x`. """ with ops.name_scope(name, "l2_normalize", [x]) as name: - axis = deprecated_argument_lookup("axis", axis, "dim", dim) x = ops.convert_to_tensor(x, name="x") square_sum = math_ops.reduce_sum(math_ops.square(x), axis, keepdims=True) x_inv_norm = math_ops.rsqrt(math_ops.maximum(square_sum, epsilon)) diff --git a/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt index d8259aa775..a3599bfa80 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.linalg.pbtxt @@ -118,7 +118,7 @@ tf_module { } member_method { name: "l2_normalize" - argspec: "args=[\'x\', \'axis\', \'epsilon\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'1e-12\', \'None\', \'None\'], " + argspec: "args=[\'x\', \'axis\', \'epsilon\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'1e-12\', \'None\'], " } member_method { name: "logdet" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt index 5215cfbab0..c10361f90d 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt @@ -198,7 +198,7 @@ tf_module { } member_method { name: "l2_normalize" - argspec: "args=[\'x\', \'axis\', \'epsilon\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'1e-12\', \'None\', \'None\'], " + argspec: "args=[\'x\', \'axis\', \'epsilon\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'1e-12\', \'None\'], " } member_method { name: "lbeta" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index e550b2d754..035a6c76f6 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -170,7 +170,7 @@ tf_module { } member_method { name: "l2_normalize" - argspec: "args=[\'x\', \'axis\', \'epsilon\', \'name\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'1e-12\', \'None\', \'None\'], " + argspec: "args=[\'x\', \'axis\', \'epsilon\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'1e-12\', \'None\'], " } member_method { name: "leaky_relu" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index c7bf73ba68..a018b5713f 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -114,6 +114,15 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.random.stateless_multinomial": { "output_dtype": "dtype", }, + "tf.linalg.l2_normalize": { + "dim": "axis", + }, + "tf.math.l2_normalize": { + "dim": "axis", + }, + "tf.nn.l2_normalize": { + "dim": "axis", + }, "tf.sparse.concat": [ "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" ], -- GitLab From 4b4517491d0f8a3033b11e64cb57cbb5873f638e Mon Sep 17 00:00:00 2001 From: Amit Patankar Date: Wed, 21 Nov 2018 14:11:38 -0800 Subject: [PATCH 228/672] Remove fixed_size_partitioner(num_shards, axis) from the v2 API. PiperOrigin-RevId: 222458768 --- tensorflow/python/ops/partitioned_variables.py | 2 +- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 4 ---- tensorflow/tools/compatibility/renames_v2.py | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 98a95f9f58..816317da10 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -218,7 +218,7 @@ def min_max_variable_partitioner(max_partitions=1, axis=0, return _partitioner -@tf_export("fixed_size_partitioner") +@tf_export(v1=["fixed_size_partitioner"]) def fixed_size_partitioner(num_shards, axis=0): """Partitioner to specify a fixed number of shards along given axis. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 1b496bde47..7f69a888bf 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -660,10 +660,6 @@ tf_module { name: "fill" argspec: "args=[\'dims\', \'value\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "fixed_size_partitioner" - argspec: "args=[\'num_shards\', \'axis\'], varargs=None, keywords=None, defaults=[\'0\'], " - } member_method { name: "floor" argspec: "args=[\'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index a93b7d68bd..0c1a4890be 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -167,6 +167,7 @@ renames = { 'tf.fft': 'tf.signal.fft', 'tf.fft2d': 'tf.signal.fft2d', 'tf.fft3d': 'tf.signal.fft3d', + 'tf.fixed_size_partitioner': 'tf.compat.v1.fixed_size_partitioner', 'tf.floordiv': 'tf.math.floordiv', 'tf.get_collection': 'tf.compat.v1.get_collection', 'tf.get_collection_ref': 'tf.compat.v1.get_collection_ref', -- GitLab From 8f7007823cd337ab2721219ca8eb95b150d8617d Mon Sep 17 00:00:00 2001 From: RJ Ryan Date: Wed, 21 Nov 2018 14:17:51 -0800 Subject: [PATCH 229/672] Internal change. PiperOrigin-RevId: 222459567 --- tensorflow/compiler/tf2xla/python/BUILD | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tensorflow/compiler/tf2xla/python/BUILD b/tensorflow/compiler/tf2xla/python/BUILD index c9f486edc8..fef97b98c3 100644 --- a/tensorflow/compiler/tf2xla/python/BUILD +++ b/tensorflow/compiler/tf2xla/python/BUILD @@ -1,11 +1,13 @@ licenses(["notice"]) # Apache 2.0 +package_group( + name = "friends", + includes = ["//tensorflow:internal"], +) + package( default_visibility = [ - "//learning/deepmind/public/wavenet/python:__subpackages__", - "//learning/deepmind/research/alphastar:__subpackages__", - "//learning/tfx:__subpackages__", - "//tensorflow:internal", + ":friends", ], ) -- GitLab From 1f9055ceb744d18059ca4cb56d0be78226763857 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Wed, 21 Nov 2018 14:21:51 -0800 Subject: [PATCH 230/672] [tf.data] Properly guard access to shared state with a mutex. PiperOrigin-RevId: 222460077 --- tensorflow/core/kernels/data/map_and_batch_dataset_op.cc | 5 ++++- tensorflow/core/kernels/data/parallel_map_iterator.cc | 5 ++++- tensorflow/python/data/experimental/kernel_tests/BUILD | 1 - 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc b/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc index 72a401e99b..f389ff12c5 100644 --- a/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc +++ b/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc @@ -566,7 +566,10 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { RecordStart(ctx.get()); auto stop_cleanup = gtl::MakeCleanup([this, &ctx]() { RecordStop(ctx.get()); }); - new_calls.reserve(num_parallel_calls_->value); + { + tf_shared_lock l(*mu_); // mu_ == num_parallel_calls_->mu + new_calls.reserve(num_parallel_calls_->value); + } auto busy = [this]() EXCLUSIVE_LOCKS_REQUIRED(*mu_) -> bool { int64 num_parallel_calls = num_parallel_calls_->value; int64 max_batch_results = diff --git a/tensorflow/core/kernels/data/parallel_map_iterator.cc b/tensorflow/core/kernels/data/parallel_map_iterator.cc index ec1c923843..5d6c12ede9 100644 --- a/tensorflow/core/kernels/data/parallel_map_iterator.cc +++ b/tensorflow/core/kernels/data/parallel_map_iterator.cc @@ -252,7 +252,10 @@ class ParallelMapIterator : public DatasetBaseIterator { RecordStart(ctx.get()); auto cleanup = gtl::MakeCleanup([this, ctx] { RecordStop(ctx.get()); }); std::vector> new_calls; - new_calls.reserve(num_parallel_calls_->value); + { + tf_shared_lock l(*mu_); // mu_ == num_parallel_calls_->mu + new_calls.reserve(num_parallel_calls_->value); + } auto busy = [this]() EXCLUSIVE_LOCKS_REQUIRED(*mu_) -> bool { int64 num_parallel_calls = num_parallel_calls_->value; return num_calls_ >= num_parallel_calls || diff --git a/tensorflow/python/data/experimental/kernel_tests/BUILD b/tensorflow/python/data/experimental/kernel_tests/BUILD index 6a387f55bd..a7c306817c 100644 --- a/tensorflow/python/data/experimental/kernel_tests/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/BUILD @@ -620,7 +620,6 @@ py_test( srcs_version = "PY2AND3", tags = [ "no_pip", - "notsan", ], deps = [ ":reader_dataset_ops_test_base", -- GitLab From a7f51164e664198d4e37563b33df34ef66e8f826 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Wed, 21 Nov 2018 14:22:00 -0800 Subject: [PATCH 231/672] Fixed AttributeError in variable_scope.__exit__ The error was triggered by testPartitionConcatenatesAlongCorrectAxisResource when ran w/o wrapping. PiperOrigin-RevId: 222460094 --- tensorflow/python/kernel_tests/variable_scope_test.py | 5 ++++- tensorflow/python/ops/variable_scope.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index a8a66a412d..6267b01a29 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -308,7 +308,6 @@ class VariableScopeTest(test.TestCase): self.evaluate(variables_lib.global_variables_initializer()) self.assertAllEqual(self.evaluate(x.value()), self.evaluate(y.value())) - # TODO(alive): support variable partitioning/caching in eager mode. # TODO(mihaimaruseac): Not converted to use wrap_function because of # InvalidArgumentError: /job:moo/replica:0/task:0/device:CPU:0 unknown device. def testVarScopeCachingDevice(self): @@ -1467,6 +1466,10 @@ class VariableScopeWithPartitioningTest(test.TestCase): def testPartitionConcatenatesAlongCorrectAxisResource(self): self._testPartitionConcatenatesAlongCorrectAxis(use_resource=True) + def testPartitionConcatenatesAlongCorrectAxisResourceInEager(self): + with context.eager_mode(): + self._testPartitionConcatenatesAlongCorrectAxis(use_resource=True) + class VariableScopeWithCustomGetterTest(test.TestCase): diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 4f210e3b12..1b122ceffd 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -2231,8 +2231,8 @@ class variable_scope(object): try: return self._enter_scope_uncached() - except: - if not self._building_function: + except Exception: + if self._in_graph_mode and not self._building_function: if self._graph_context_manager is not None: self._graph_context_manager.__exit__(*sys.exc_info()) raise -- GitLab From 78ef03f348fa4005890693f51349e714d9aeef5a Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Wed, 21 Nov 2018 14:36:21 -0800 Subject: [PATCH 232/672] Disable flaky performance test. PiperOrigin-RevId: 222461831 --- tensorflow/python/keras/layers/unified_rnn_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/keras/layers/unified_rnn_test.py b/tensorflow/python/keras/layers/unified_rnn_test.py index 744d51824b..8dc6a070bd 100644 --- a/tensorflow/python/keras/layers/unified_rnn_test.py +++ b/tensorflow/python/keras/layers/unified_rnn_test.py @@ -288,7 +288,7 @@ class RNNTest(test.TestCase): 'Normal LSTM', (total_duration / epoch)) return total_duration / epoch - def test_performance_with_standard_cudnn_impl(self): + def DISABLED_test_performance_with_standard_cudnn_impl(self): if not test.is_gpu_available(): self.skipTest('performance test will only run on GPU') -- GitLab From fa5590b4ad9353a57289e2b537417ad4eee26c74 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Wed, 21 Nov 2018 14:45:09 -0800 Subject: [PATCH 233/672] [tf.data] Options-related changes. This CL: - refactors all options classes to use a shared options utility - introduces `tf.data.experimental.ThreadingOptions` options for threading configuration and surfaces it through `experimental_threading` of `tf.data.Options` PiperOrigin-RevId: 222462977 --- ...rimentalMaxIntraOpParallelismDataset.pbtxt | 13 ++ ...ExperimentalPrivateThreadPoolDataset.pbtxt | 13 ++ .../experimental/threadpool_dataset_op.cc | 217 +++++++++++++++++ .../core/ops/experimental_dataset_ops.cc | 16 ++ .../python/data/experimental/__init__.py | 2 + .../optimization/latency_all_edges_test.py | 3 +- .../kernel_tests/override_threadpool_test.py | 87 ++++--- .../kernel_tests/stats_dataset_ops_test.py | 18 +- tensorflow/python/data/experimental/ops/BUILD | 37 +-- .../data/experimental/ops/stats_options.py | 78 +++---- .../experimental/ops/threading_options.py | 50 ++++ .../data/kernel_tests/dataset_ops_test.py | 2 +- tensorflow/python/data/ops/BUILD | 3 + tensorflow/python/data/ops/dataset_ops.py | 221 ++++++++++-------- tensorflow/python/data/util/BUILD | 17 ++ tensorflow/python/data/util/options.py | 131 +++++++++++ tensorflow/python/data/util/options_test.py | 96 ++++++++ .../golden/v1/tensorflow.data.-options.pbtxt | 5 + ...low.data.experimental.-stats-options.pbtxt | 3 +- ...data.experimental.-threading-options.pbtxt | 18 ++ .../v1/tensorflow.data.experimental.pbtxt | 4 + .../golden/v2/tensorflow.data.-options.pbtxt | 5 + ...low.data.experimental.-stats-options.pbtxt | 3 +- ...data.experimental.-threading-options.pbtxt | 18 ++ .../v2/tensorflow.data.experimental.pbtxt | 4 + 25 files changed, 865 insertions(+), 199 deletions(-) create mode 100644 tensorflow/core/api_def/base_api/api_def_ExperimentalMaxIntraOpParallelismDataset.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_ExperimentalPrivateThreadPoolDataset.pbtxt create mode 100644 tensorflow/python/data/experimental/ops/threading_options.py create mode 100644 tensorflow/python/data/util/options.py create mode 100644 tensorflow/python/data/util/options_test.py create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.data.experimental.-threading-options.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-threading-options.pbtxt diff --git a/tensorflow/core/api_def/base_api/api_def_ExperimentalMaxIntraOpParallelismDataset.pbtxt b/tensorflow/core/api_def/base_api/api_def_ExperimentalMaxIntraOpParallelismDataset.pbtxt new file mode 100644 index 0000000000..a18aa378ff --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_ExperimentalMaxIntraOpParallelismDataset.pbtxt @@ -0,0 +1,13 @@ +op { + graph_op_name: "ExperimentalMaxIntraOpParallelismDataset" + in_arg { + name: "max_intra_op_parallelism" + description: <

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

99!M?g{`dLyC`1MkP!eG8uE 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
![](images/xla_array_layout_figure2.png) + +Figure 2
+ +Figure 2 shows how an array of size 4x8 is tiled by two levels of tiling (first +2x4 then 2x1). We represent this repeated tiling as (2,4)(2,1). Each color +indicates a 2x4 tile and each red border box is a 2x1 tile. The numbers +indicates the linear index in memory of that element in the tiled format. This +format matches the format used for BF16 on TPU, except that the initial tile is +bigger, namely the tiling is (8,128)(2,1), where the purpose of the second +tiling by 2x1 is to collect together two 16 bit values to form one 32 bit value +in a way that aligns with the architecture of a TPU. + +Note that a second or later tile can refer to both the minor within-tile +dimensions, which just rearranges data within the tile, as in this example with +(8,128)(2,1), but can also refer to the major cross-tile dimensions from the +prior tiling. + +# Combining dimensions using tiles + +XLA's tiling also supports combining dimensions. For example, it can combine +dimensions in F32[2,7,8,11,10]{4,3,2,1,0} into F32[112,110]{1,0} first before +tiling it with (2,3). The tile used is (∗,∗,2,∗,3). Here an +asterisk in a tile implies taking that dimension and combining it with the next +more minor dimension. Multiple adjacent dimensions can be subsumed together into +one dimension. A subsumed dimension is represented by a tile value of -1 in that +dimension of the tile, which is not otherwise valid in a tile as a dimension +size. + +More precisely, if dimension i of the shape is eliminated via an asterisk in the +tile, then before the prior definition of tiling is applied, that dimension is +removed from both the shape being tiled and the tile vector, and what was +dimension i-1 of the shape has its array bound increased from di-1 to +didi-1. This step is repeated for each asterisk in the +tile vector. diff --git a/tensorflow/compiler/xla/layout_util.cc b/tensorflow/compiler/xla/layout_util.cc index 2398470dd4..dbb81381ac 100644 --- a/tensorflow/compiler/xla/layout_util.cc +++ b/tensorflow/compiler/xla/layout_util.cc @@ -460,6 +460,13 @@ std::ostream& operator<<(std::ostream& out, const Layout& layout) { } hash_value = Hash64Combine(hash_value, layout.max_sparse_elements()); + for (Tile tile : layout.tiles()) { + for (int64 tile_dim : tile.dimensions()) { + hash_value = Hash64Combine(hash_value, hash()(tile_dim)); + } + } + hash_value = Hash64Combine(hash_value, layout.element_size_in_bits()); + return hash_value; } diff --git a/tensorflow/compiler/xla/shape_util.cc b/tensorflow/compiler/xla/shape_util.cc index 82662b1dbb..b95fabf488 100644 --- a/tensorflow/compiler/xla/shape_util.cc +++ b/tensorflow/compiler/xla/shape_util.cc @@ -121,6 +121,23 @@ bool CompareShapes(const Shape& lhs, const Shape& rhs, bool compare_layouts, VLOG(3) << "CompareShapes: lhs layout != rhs layout"; return false; } + + const auto& lhs_tiles = lhs.layout().tiles(); + const auto& rhs_tiles = rhs.layout().tiles(); + if (lhs_tiles.size() != rhs_tiles.size()) { + return false; + } + for (int64 i = 0; i < lhs_tiles.size(); i++) { + if (!absl::c_equal(lhs_tiles[i].dimensions(), + rhs_tiles[i].dimensions())) { + return false; + } + } + + if (lhs.layout().element_size_in_bits() != + rhs.layout().element_size_in_bits()) { + return false; + } } } diff --git a/tensorflow/compiler/xla/xla_data.proto b/tensorflow/compiler/xla/xla_data.proto index 013673dd9e..85ec83437a 100644 --- a/tensorflow/compiler/xla/xla_data.proto +++ b/tensorflow/compiler/xla/xla_data.proto @@ -108,6 +108,16 @@ enum Format { SPARSE = 2; } +// Describes a tile used in tiling-based layout. Refer to +// g3doc/layout_with_tiling.md for details about tiling-based layout. +message Tile { + // Number of elements in each dimension of the tile. It's ordered from the + // most major dimension of the tile to the most minor dimension of the tile. + // The dimensions correspond to a suffix of the dimensions of the shape being + // tiled. + repeated int64 dimensions = 1; +} + // A layout describes how the array is placed in (1D) memory space. This // includes the minor-to-major ordering of dimensions within a shape. // @@ -138,6 +148,20 @@ message Layout { // memory. This field must be unset unless the format is SPARSE. int64 max_sparse_elements = 5; + // A sequence of tiles, starting from the tile that's applied first to the + // Shape. + // + // TODO(b/119839262): implement tiling in each backend or add Unimplemented + // error. + repeated Tile tiles = 6; + + // Bit size of each element. If the size is bigger than what the element + // type requires, the value is stored in the least significant + // bits and the additional most significant bits are filled with 0's. + // + // TODO(b/119839262): implement in each backend or add Unimplemented error. + int64 element_size_in_bits = 7; + // Important: if any field is added, be sure to modify ShapeUtil::Equal() and // LayoutUtil::Hash appropriately to account for the new field. } -- GitLab From d3125a94f3b160ae4bb1ca48ef4c67cc65071c8c Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 11:23:59 -0800 Subject: [PATCH 552/672] Constructing a single scalar tensor requires multiple steps currently. - Construct a tensor - Fetch tf data - Copy into tf-data - Convert to a TFE_Tensor. This is a fast-path version that collapses all those steps into a single call. This call path requires no TF_Status checking. PiperOrigin-RevId: 223379214 --- tensorflow/c/c_api_experimental.cc | 10 ++++++++++ tensorflow/c/c_api_experimental.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc index 69de4cb711..0c593185db 100644 --- a/tensorflow/c/c_api_experimental.cc +++ b/tensorflow/c/c_api_experimental.cc @@ -8870,3 +8870,13 @@ void TF_InitMain(const char* usage, int* argc, char*** argv) { int TF_PickUnusedPortOrDie() { return tensorflow::internal::PickUnusedPortOrDie(); } + +TFE_TensorHandle* TFE_NewTensorHandleFromScalar(TF_DataType dtype_arg, + void* data, size_t len) { + auto dtype = static_cast(dtype_arg); + DCHECK(tensorflow::DataTypeCanUseMemcpy(dtype)); + + tensorflow::Tensor tensor(dtype, tensorflow::TensorShape({})); + std::memcpy(tensorflow::TensorCApi::Buffer(tensor)->data(), data, len); + return new TFE_TensorHandle(tensor, nullptr, nullptr); +} diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h index c04cd441bf..80c8bfe594 100644 --- a/tensorflow/c/c_api_experimental.h +++ b/tensorflow/c/c_api_experimental.h @@ -241,6 +241,11 @@ TF_CAPI_EXPORT void TF_InitMain(const char* usage, int* argc, char*** argv); // in tests only.) TF_CAPI_EXPORT int TF_PickUnusedPortOrDie(); +// Fast path method that makes constructing a single scalar tensor require less +// overhead and copies. +TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_NewTensorHandleFromScalar( + TF_DataType dtype, void* scalar, size_t len); + #ifdef __cplusplus } /* end extern "C" */ #endif -- GitLab From 143307d680bf17154bdca86d7ad9b3f364f273a6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 11:25:55 -0800 Subject: [PATCH 553/672] internal change PiperOrigin-RevId: 223379551 --- .../TFLiteBenchmark.xcodeproj/project.pbxproj | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tensorflow/lite/tools/benchmark/ios/TFLiteBenchmark/TFLiteBenchmark.xcodeproj/project.pbxproj b/tensorflow/lite/tools/benchmark/ios/TFLiteBenchmark/TFLiteBenchmark.xcodeproj/project.pbxproj index 958936a660..a5f5bfbbda 100644 --- a/tensorflow/lite/tools/benchmark/ios/TFLiteBenchmark/TFLiteBenchmark.xcodeproj/project.pbxproj +++ b/tensorflow/lite/tools/benchmark/ios/TFLiteBenchmark/TFLiteBenchmark.xcodeproj/project.pbxproj @@ -20,7 +20,7 @@ /* Begin PBXFileReference section */ 6FE7579920D59CE500F01636 /* benchmark_params.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = benchmark_params.json; sourceTree = ""; }; - 6FE7579C20D5A5E000F01636 /* benchmark-lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "benchmark-lib.a"; path = "$SRCROOT/../../../../../../../tensorflow/lite/tools/make/gen/lib/benchmark-lib.a"; sourceTree = ""; }; + 6FE7579C20D5A5E000F01636 /* benchmark-lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "benchmark-lib.a"; path = "$SRCROOT/../../../../../../tensorflow/lite/tools/make/gen/lib/benchmark-lib.a"; sourceTree = ""; }; 6FE7579E20D5A6A700F01636 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 6FE757A020D5AB8000F01636 /* mobilenet_v1_1.0_224.tflite */ = {isa = PBXFileReference; lastKnownFileType = file; path = mobilenet_v1_1.0_224.tflite; sourceTree = ""; }; 6FE93FF820D592D8008C9FE4 /* TFLiteBenchmark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TFLiteBenchmark.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -309,19 +309,19 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; "HEADER_SEARCH_PATHS[arch=*]" = ( - $SRCROOT/../../../../../../../, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/eigen, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/gemmlowp, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/neon_2_sse, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/farmhash/src, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/flatbuffers/include, + $SRCROOT/../../../../../../, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/eigen, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/gemmlowp, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/neon_2_sse, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/farmhash/src, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/flatbuffers/include, ); INFOPLIST_FILE = TFLiteBenchmark/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - "LIBRARY_SEARCH_PATHS[arch=*]" = $SRCROOT/../../../../../../../tensorflow/lite/tools/make/gen/lib; + "LIBRARY_SEARCH_PATHS[arch=*]" = $SRCROOT/../../../../../../tensorflow/lite/tools/make/gen/lib; PRODUCT_BUNDLE_IDENTIFIER = example.TFLiteBenchmark; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; @@ -335,19 +335,19 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; "HEADER_SEARCH_PATHS[arch=*]" = ( - $SRCROOT/../../../../../../../, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/eigen, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/gemmlowp, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/neon_2_sse, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/farmhash/src, - $SRCROOT/../../../../../../../tensorflow/lite/tools/make/downloads/flatbuffers/include, + $SRCROOT/../../../../../../, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/eigen, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/gemmlowp, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/neon_2_sse, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/farmhash/src, + $SRCROOT/../../../../../../tensorflow/lite/tools/make/downloads/flatbuffers/include, ); INFOPLIST_FILE = TFLiteBenchmark/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - "LIBRARY_SEARCH_PATHS[arch=*]" = $SRCROOT/../../../../../../../tensorflow/lite/tools/make/gen/lib; + "LIBRARY_SEARCH_PATHS[arch=*]" = $SRCROOT/../../../../../../tensorflow/lite/tools/make/gen/lib; PRODUCT_BUNDLE_IDENTIFIER = example.TFLiteBenchmark; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; -- GitLab From 4aef7dde40a3ffb1871d9a58aafec20711e7131f Mon Sep 17 00:00:00 2001 From: "Joshua V. Dillon" Date: Thu, 29 Nov 2018 11:35:53 -0800 Subject: [PATCH 554/672] Enable user specifiable Keras symbolic tensors. This allows users to plumb through Keras objects which are convertible to tf.Tensors. (This functionality is similar to `tf.register_tensor_conversion_function`.) PiperOrigin-RevId: 223381634 --- tensorflow/python/keras/BUILD | 11 ++ tensorflow/python/keras/utils/tf_utils.py | 44 +++++- .../python/keras/utils/tf_utils_test.py | 134 ++++++++++++++++++ 3 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 tensorflow/python/keras/utils/tf_utils_test.py diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index 69e18ea55f..48cdbf1e66 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -596,6 +596,17 @@ py_test( ], ) +py_test( + name = "tf_utils_test", + size = "small", + srcs = ["utils/tf_utils_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":keras", + "//tensorflow/python:client_testlib", + ], +) + py_test( name = "io_utils_test", size = "small", diff --git a/tensorflow/python/keras/utils/tf_utils.py b/tensorflow/python/keras/utils/tf_utils.py index 6b7c6c34a2..7b4c9e7239 100644 --- a/tensorflow/python/keras/utils/tf_utils.py +++ b/tensorflow/python/keras/utils/tf_utils.py @@ -161,6 +161,9 @@ def are_all_symbolic_tensors(tensors): return all(is_symbolic_tensor(tensor) for tensor in tensors) +_user_convertible_tensor_types = set() + + def is_symbolic_tensor(tensor): """Returns whether a tensor is symbolic (from a TF graph) or an eager tensor. @@ -176,9 +179,40 @@ def is_symbolic_tensor(tensor): if isinstance(tensor, variables.Variable): return not context.executing_eagerly() if isinstance(tensor, (ops.Tensor, sparse_tensor.SparseTensor)): - try: - _ = tensor.graph - return True - except AttributeError: - return False + return hasattr(tensor, 'graph') + if isinstance(tensor, tuple(_user_convertible_tensor_types)): + return hasattr(ops.convert_to_tensor(tensor), 'graph') return False + + +def register_symbolic_tensor_type(cls): + """Allows users to specify types regarded as symbolic `Tensor`s. + + Used in conjunction with `tf.register_tensor_conversion_function`, calling + `tf.keras.utils.register_symbolic_tensor_type(cls)` allows non-`Tensor` + objects to be plumbed through Keras layers. + + Example: + + ```python + # One-time setup. + class Foo(object): + def __init__(self, input_): + self._input = input_ + def value(self): + return tf.constant(42.) + + tf.register_tensor_conversion_function( + Foo, lambda x, *args, **kwargs: x.value()) + + tf.keras.utils.register_symbolic_tensor_type(Foo) + + # User-land. + layer = tf.keras.layers.Lambda(lambda input_: Foo(input_)) + ``` + + Arguments: + cls: A `class` type which shall be regarded as a symbolic `Tensor`. + """ + global _user_convertible_tensor_types + _user_convertible_tensor_types.add(cls) diff --git a/tensorflow/python/keras/utils/tf_utils_test.py b/tensorflow/python/keras/utils/tf_utils_test.py new file mode 100644 index 0000000000..9833a49299 --- /dev/null +++ b/tensorflow/python/keras/utils/tf_utils_test.py @@ -0,0 +1,134 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for Keras TF utils.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python import keras +from tensorflow.python.eager import context +from tensorflow.python.framework import ops +from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util +from tensorflow.python.keras.utils import tf_utils +from tensorflow.python.ops import variables +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class TestIsSymbolicTensor(test.TestCase): + + def test_default_behavior(self): + if context.executing_eagerly(): + self.assertFalse(tf_utils.is_symbolic_tensor( + variables.Variable(name='blah', initial_value=0.))) + self.assertFalse(tf_utils.is_symbolic_tensor( + ops.convert_to_tensor(0.))) + self.assertFalse(tf_utils.is_symbolic_tensor( + sparse_tensor.SparseTensor( + indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]))) + else: + self.assertTrue(tf_utils.is_symbolic_tensor( + variables.Variable(name='blah', initial_value=0.))) + self.assertTrue(tf_utils.is_symbolic_tensor( + ops.convert_to_tensor(0.))) + self.assertTrue(tf_utils.is_symbolic_tensor( + sparse_tensor.SparseTensor( + indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]))) + + def test_works_with_registered(self): + + class CustomClass(object): + + def value(self): + return ops.convert_to_tensor(42.) + + ops.register_tensor_conversion_function( + CustomClass, lambda value, **_: value.value()) + + tf_utils.register_symbolic_tensor_type(CustomClass) + + if context.executing_eagerly(): + self.assertFalse(tf_utils.is_symbolic_tensor( + variables.Variable(name='blah', initial_value=0.))) + self.assertFalse(tf_utils.is_symbolic_tensor( + ops.convert_to_tensor(0.))) + self.assertFalse(tf_utils.is_symbolic_tensor( + sparse_tensor.SparseTensor( + indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]))) + self.assertFalse(tf_utils.is_symbolic_tensor(CustomClass())) + else: + self.assertTrue(tf_utils.is_symbolic_tensor( + variables.Variable(name='blah', initial_value=0.))) + self.assertTrue(tf_utils.is_symbolic_tensor( + ops.convert_to_tensor(0.))) + self.assertTrue(tf_utils.is_symbolic_tensor( + sparse_tensor.SparseTensor( + indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]))) + self.assertTrue(tf_utils.is_symbolic_tensor(CustomClass())) + + def test_enables_nontensor_plumbing(self): + # Setup. + + class Foo(object): + + def __init__(self, input_): + self._input = input_ + self.value = ops.convert_to_tensor(42.) + + ops.register_tensor_conversion_function( + Foo, lambda x, *args, **kwargs: x.value) + tf_utils.register_symbolic_tensor_type(Foo) + + class PlumbingLayer(keras.layers.Lambda): + + def __init__(self, fn, **kwargs): + def _fn(*fargs, **fkwargs): + d = fn(*fargs, **fkwargs) + x = ops.convert_to_tensor(d) + d.shape = x.shape + d.get_shape = x.get_shape + return d, x + super(PlumbingLayer, self).__init__(_fn, **kwargs) + self._enter_dunder_call = False + + def __call__(self, inputs, *args, **kwargs): + self._enter_dunder_call = True + d, _ = super(PlumbingLayer, self).__call__(inputs, *args, **kwargs) + self._enter_dunder_call = False + return d + + def call(self, inputs, *args, **kwargs): + d, v = super(PlumbingLayer, self).call(inputs, *args, **kwargs) + if self._enter_dunder_call: + return d, v + return d + + # User-land. + model = keras.Sequential([ + keras.layers.InputLayer([]), + PlumbingLayer(Foo), # Makes a `Foo` object. + ]) + # Let's ensure Keras graph history is preserved by composing the models. + model = keras.Model(model.inputs, model(model.outputs)) + # Now we instantiate the model and verify we have a `Foo` object, not a + # `Tensor`. + y = model(ops.convert_to_tensor(7.)) + self.assertIsInstance(y, Foo) + + +if __name__ == '__main__': + test.main() -- GitLab From e19faa08c54a564dd8663cf18722f29977b81a17 Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Thu, 29 Nov 2018 11:38:43 -0800 Subject: [PATCH 555/672] Fix tf.function on functools.partial objects Needed some unwrapping in autograph. PiperOrigin-RevId: 223382148 --- tensorflow/python/autograph/impl/api.py | 11 ++++++++++ tensorflow/python/autograph/impl/api_test.py | 21 +++++++++++++++++++ .../python/autograph/impl/conversion.py | 8 ++++++- tensorflow/python/eager/def_function_test.py | 7 +++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/autograph/impl/api.py b/tensorflow/python/autograph/impl/api.py index 69674b2be3..19a472064a 100644 --- a/tensorflow/python/autograph/impl/api.py +++ b/tensorflow/python/autograph/impl/api.py @@ -195,6 +195,17 @@ def converted_call(f, owner, options, *args, **kwargs): if not options.internal_convert_user_code: return f(*args, **kwargs) + # Unwrap functools.partial objects + # TODO(allenl, mdan): Consider sharing unwrapping logic with tf_inspect. + while isinstance(f, functools.partial): + args = f.args + args + new_kwargs = {} + if f.keywords is not None: + new_kwargs.update(f.keywords) + new_kwargs.update(kwargs) + kwargs = new_kwargs + f = f.func + if tf_inspect.isfunction(f) or tf_inspect.ismethod(f): # Regular functions target_entity = f diff --git a/tensorflow/python/autograph/impl/api_test.py b/tensorflow/python/autograph/impl/api_test.py index 44cb99d657..a0fa501fb8 100644 --- a/tensorflow/python/autograph/impl/api_test.py +++ b/tensorflow/python/autograph/impl/api_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import functools import gc import numpy as np @@ -210,6 +211,26 @@ class ApiTest(test.TestCase): constant_op.constant(-1)) self.assertEqual(1, self.evaluate(x)) + def test_converted_call_functools_partial(self): + + def test_fn(x, y, z): + if x < 0: + return -x, -y, -z + return x, y, z + + x = api.converted_call( + functools.partial(test_fn, constant_op.constant(-1), z=-3), + None, converter.ConversionOptions(), + constant_op.constant(-2)) + self.assertEqual((1, 2, 3), self.evaluate(x)) + + x = api.converted_call( + functools.partial( + functools.partial(test_fn, constant_op.constant(-1)), z=-3), + None, converter.ConversionOptions(), + constant_op.constant(-2)) + self.assertEqual((1, 2, 3), self.evaluate(x)) + def test_converted_call_method_explicit_owner(self): # TODO(mdan): Implement. pass diff --git a/tensorflow/python/autograph/impl/conversion.py b/tensorflow/python/autograph/impl/conversion.py index 3dfc12eb76..055769c73a 100644 --- a/tensorflow/python/autograph/impl/conversion.py +++ b/tensorflow/python/autograph/impl/conversion.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import functools import imp import gast @@ -72,7 +73,12 @@ def is_whitelisted_for_graph(o): Returns: Boolean """ - m = tf_inspect.getmodule(o) + if isinstance(o, functools.partial): + # tf_inspect.getmodule(functools.partial(...)) otherwise returns None since + # functools.partial objects do not have a __module__ attribute. + m = functools + else: + m = tf_inspect.getmodule(o) for prefix, in config.DEFAULT_UNCOMPILED_MODULES: if m.__name__.startswith(prefix): return True diff --git a/tensorflow/python/eager/def_function_test.py b/tensorflow/python/eager/def_function_test.py index 54991344b7..da85735c47 100644 --- a/tensorflow/python/eager/def_function_test.py +++ b/tensorflow/python/eager/def_function_test.py @@ -17,6 +17,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import functools from tensorflow.python.eager import backprop from tensorflow.python.eager import def_function @@ -207,6 +208,12 @@ class DefFunctionTest(test.TestCase): m1 = MyModel() self.assertAllEqual(m1.apply(3.0), 6.0) + def test_functools_partial(self): + self.assertAllClose( + 3., + def_function.function(functools.partial(lambda x, y: x + y, 1.))( + constant_op.constant(2.))) + def test_optimizer(self): x = constant_op.constant([[3., 4.]]) y = constant_op.constant([2.]) -- GitLab From ba4761a4499a89fbfad3610d996ec3bae582d2c6 Mon Sep 17 00:00:00 2001 From: Kay Zhu Date: Thu, 29 Nov 2018 11:47:31 -0800 Subject: [PATCH 556/672] [XLA] Change BroadcastInDim interface to take a span of output dimension sizes instead of a shape. PiperOrigin-RevId: 223383859 --- .../compiler/tf2xla/kernels/permute_op.cc | 3 +- .../compiler/tf2xla/kernels/resampler_ops.cc | 32 +++----- .../tf2xla/kernels/xla_broadcast_helper_op.cc | 7 +- tensorflow/compiler/tf2xla/lib/broadcast.cc | 6 +- tensorflow/compiler/xla/client/xla_builder.cc | 29 ++++--- tensorflow/compiler/xla/client/xla_builder.h | 8 +- .../compiler/xla/client/xla_builder_test.cc | 4 +- .../xla/python/local_computation_builder.cc | 75 +++++++++---------- .../xla/python/local_computation_builder.h | 3 +- tensorflow/compiler/xla/python/xla_client.py | 3 +- .../xla/tests/broadcast_simple_test.cc | 17 ++--- 11 files changed, 89 insertions(+), 98 deletions(-) diff --git a/tensorflow/compiler/tf2xla/kernels/permute_op.cc b/tensorflow/compiler/tf2xla/kernels/permute_op.cc index 94b51e1a58..71920bf5c1 100644 --- a/tensorflow/compiler/tf2xla/kernels/permute_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/permute_op.cc @@ -75,8 +75,7 @@ class DataFormatVecPermuteOp : public XlaOpKernel { } auto keys = xla::ConstantR1(builder, absl::Span(dst_indices)); if (input_rank == 2) { - keys = xla::BroadcastInDim( - keys, xla::ShapeUtil::MakeShape(xla::S32, {4, 2}), {0}); + keys = xla::BroadcastInDim(keys, {4, 2}, {0}); } auto sorted = xla::Sort(keys, {ctx->Input(0)}, 0); auto output = xla::GetTupleElement(sorted, 1); diff --git a/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc b/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc index 8a8f33c8f3..769e0cd140 100644 --- a/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc @@ -67,11 +67,8 @@ XlaOp BilinearWeights(XlaOpKernelContext* ctx, XlaOp ratio, std::vector last_two_dims_indices = {(broadcast_dims_size - 2), (broadcast_dims_size - 1)}; - xla::Shape broadcast_shape = - xla::ShapeUtil::MakeShape(xla_type, broadcast_dims); - auto broadcast_first_term = - xla::BroadcastInDim(first_term, broadcast_shape, last_two_dims_indices); + xla::BroadcastInDim(first_term, broadcast_dims, last_two_dims_indices); // Ratio is of the same dimension as warp, which is [batch, dim_0,... dim_n, // 2], we broadcast ratio tensor to 'broadcast_dim' by keeping the @@ -82,7 +79,7 @@ XlaOp BilinearWeights(XlaOpKernelContext* ctx, XlaOp ratio, ratio_broadcast_indices.erase(ratio_broadcast_indices.end() - 2); auto broadcast_ratio = - xla::BroadcastInDim(ratio, broadcast_shape, ratio_broadcast_indices); + xla::BroadcastInDim(ratio, broadcast_dims, ratio_broadcast_indices); auto first_term_subtract_weights = broadcast_first_term - broadcast_ratio; @@ -93,7 +90,7 @@ XlaOp BilinearWeights(XlaOpKernelContext* ctx, XlaOp ratio, sign_change = xla::ConvertElementType(sign_change, xla_type); auto broadcast_sign_change = - xla::BroadcastInDim(sign_change, broadcast_shape, last_two_dims_indices); + xla::BroadcastInDim(sign_change, broadcast_dims, last_two_dims_indices); auto flipped = first_term_subtract_weights * broadcast_sign_change; @@ -229,21 +226,19 @@ XlaOp CalculateGradData(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio, std::vector weights_with_channels_dims = reshaped_weights_dims; weights_with_channels_dims.push_back(data_channels); - auto weights_with_channels_shape = - xla::ShapeUtil::MakeShape(warp_type, weights_with_channels_dims); std::vector reshaped_weights_indices(reshaped_weights_dims.size()); std::iota(reshaped_weights_indices.begin(), reshaped_weights_indices.end(), 0); // The dimension is [batch, dim_0, ..., dim_n, 2, 2, data_channel]. auto broadcast_reshaped_weights = xla::BroadcastInDim( - reshaped_weights, weights_with_channels_shape, reshaped_weights_indices); + reshaped_weights, weights_with_channels_dims, reshaped_weights_indices); std::vector grad_output_indices(warp_dims_without_last_dims.size()); std::iota(grad_output_indices.begin(), grad_output_indices.end(), 0); grad_output_indices.push_back(weights_with_channels_dims.size() - 1); XlaOp broadcast_grad_output = xla::BroadcastInDim( - grad_output, weights_with_channels_shape, grad_output_indices); + grad_output, weights_with_channels_dims, grad_output_indices); auto grad_output_multiply_weights = broadcast_grad_output * broadcast_reshaped_weights; @@ -291,13 +286,10 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio, std::vector warp_dims_without_last_dims(warp_dims.begin(), warp_dims.end() - 1); + // With dimension [batch, dim_0, ...dim_n, 4] std::vector neighbor_broadcast_dims = warp_dims_without_last_dims; neighbor_broadcast_dims.push_back(4); - // With dimension [batch, dim_0, ...dim_n, 4] - auto neighbor_broadcast_shape = - xla::ShapeUtil::MakeShape(data_type, neighbor_broadcast_dims); - // The dimension is [batch, dim_0, ... dim_n, 4, data_channels] auto neighbors_data = Gather2by2Neighbors( ctx->builder(), data, gather_indices, data_channels, warp_shape.dims()); @@ -323,7 +315,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio, xla::BroadcastInDim( xla::ConvertElementType( xla::ConstantR1(ctx->builder(), {0, 0, -1, 1}), data_type), - neighbor_broadcast_shape, {last_warp_dim}), + neighbor_broadcast_dims, {last_warp_dim}), neighbors_data, dot_dims, /*precision_config=*/nullptr); // img_cxfy - img_fxfy @@ -331,7 +323,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio, xla::BroadcastInDim( xla::ConvertElementType( xla::ConstantR1(ctx->builder(), {-1, 1, 0, 0}), data_type), - neighbor_broadcast_shape, {last_warp_dim}), + neighbor_broadcast_dims, {last_warp_dim}), neighbors_data, dot_dims, /*precision_config=*/nullptr); // img_cxcy - img_cxfy @@ -339,7 +331,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio, xla::BroadcastInDim( xla::ConvertElementType( xla::ConstantR1(ctx->builder(), {0, -1, 0, 1}), data_type), - neighbor_broadcast_shape, {last_warp_dim}), + neighbor_broadcast_dims, {last_warp_dim}), neighbors_data, dot_dims, /*precision_config=*/nullptr); // img_fxcy - img_fxfy @@ -347,7 +339,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio, xla::BroadcastInDim( xla::ConvertElementType( xla::ConstantR1(ctx->builder(), {-1, 0, 1, 0}), data_type), - neighbor_broadcast_shape, {last_warp_dim}), + neighbor_broadcast_dims, {last_warp_dim}), neighbors_data, dot_dims, /*precision_config=*/nullptr); // Slice out x and y. @@ -491,13 +483,11 @@ class ResamplerOp : public XlaOpKernel { auto warp_dims = warp_shape.dim_sizes(); std::vector result_dims(warp_dims.begin(), warp_dims.end() - 1); result_dims.push_back(data_channels); - xla::Shape broadcasted_shape = - xla::ShapeUtil::MakeShape(xla::PrimitiveType::PRED, result_dims); std::vector broadcasted_dims(warp_dims.size() - 1); std::iota(broadcasted_dims.begin(), broadcasted_dims.end(), 0); auto broadcasted_is_in_bound = - xla::BroadcastInDim(is_in_bound, broadcasted_shape, broadcasted_dims); + xla::BroadcastInDim(is_in_bound, result_dims, broadcasted_dims); // Set out of bound samples to zero. auto zeros = diff --git a/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc b/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc index a9f88a6df2..ad8e707e11 100644 --- a/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc @@ -89,13 +89,10 @@ class XlaBroadcastHelperOp : public XlaOpKernel { lhs_shape.DebugString(), " and ", rhs_shape.DebugString())); broadcast_shape[dim] = min_rank_shape->dim_size(i); } - xla::PrimitiveType type = context->input_xla_type(0); - xla::Shape broadcast_xla_shape = - xla::ShapeUtil::MakeShape(type, broadcast_shape); if (broadcast_lhs) { - lhs = xla::BroadcastInDim(lhs, broadcast_xla_shape, broadcast_dims); + lhs = xla::BroadcastInDim(lhs, broadcast_shape, broadcast_dims); } else { - rhs = xla::BroadcastInDim(rhs, broadcast_xla_shape, broadcast_dims); + rhs = xla::BroadcastInDim(rhs, broadcast_shape, broadcast_dims); } context->SetOutput(0, lhs); context->SetOutput(1, rhs); diff --git a/tensorflow/compiler/tf2xla/lib/broadcast.cc b/tensorflow/compiler/tf2xla/lib/broadcast.cc index 3e402ef855..be31f11668 100644 --- a/tensorflow/compiler/tf2xla/lib/broadcast.cc +++ b/tensorflow/compiler/tf2xla/lib/broadcast.cc @@ -80,10 +80,8 @@ xla::StatusOr BroadcastTo(xla::XlaOp input, broadcast_dim = broadcast_shape_size - broadcast_dim - 1; } absl::c_reverse(broadcast_shape); - xla::XlaOp output = xla::BroadcastInDim( - input, - xla::ShapeUtil::MakeShape(input_shape.element_type(), broadcast_shape), - broadcast_dims); + xla::XlaOp output = + xla::BroadcastInDim(input, broadcast_shape, broadcast_dims); if (broadcast_shape != output_dims) { output = xla::Reshape(output, output_dims); } diff --git a/tensorflow/compiler/xla/client/xla_builder.cc b/tensorflow/compiler/xla/client/xla_builder.cc index 0630f3cf66..60df2ec395 100644 --- a/tensorflow/compiler/xla/client/xla_builder.cc +++ b/tensorflow/compiler/xla/client/xla_builder.cc @@ -573,27 +573,35 @@ XlaOp XlaBuilder::Broadcast(const XlaOp& operand, } XlaOp XlaBuilder::BroadcastInDim( - const XlaOp& operand, const Shape& shape, + const XlaOp& operand, const absl::Span out_dim_size, const absl::Span broadcast_dimensions) { return ReportErrorOrReturn([&]() -> StatusOr { TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_RETURN_IF_ERROR(ShapeInference::InferBroadcastShape(operand_shape, shape, - broadcast_dimensions) + // Output shape, in the case of degenerate broadcast, the out_dim_size is + // not necessarily the same as the dimension sizes of the output shape. + const auto& output_shape = + ShapeUtil::MakeShape(operand_shape.element_type(), out_dim_size); + + TF_RETURN_IF_ERROR(ShapeInference::InferBroadcastShape( + operand_shape, output_shape, broadcast_dimensions) .status()); - std::vector in_dim_size(ShapeUtil::Rank(shape)); - absl::c_copy(shape.dimensions(), in_dim_size.begin()); + std::vector in_dim_size(out_dim_size.begin(), out_dim_size.end()); for (int i = 0; i < broadcast_dimensions.size(); i++) { in_dim_size[broadcast_dimensions[i]] = operand_shape.dimensions(i); } const auto& in_dim_shape = - ShapeUtil::MakeShape(shape.element_type(), in_dim_size); + ShapeUtil::MakeShape(operand_shape.element_type(), in_dim_size); TF_ASSIGN_OR_RETURN( XlaOp in_dim_broadcast, InDimBroadcast(in_dim_shape, operand, broadcast_dimensions)); - if (ShapeUtil::Equal(in_dim_shape, shape)) { + + // If broadcast is not degenerate, return broadcasted result. + if (ShapeUtil::Equal(in_dim_shape, output_shape)) { return in_dim_broadcast; } - return AddBroadcastSequence(shape, in_dim_broadcast); + + // Otherwise handle degenerate broadcast case. + return AddBroadcastSequence(output_shape, in_dim_broadcast); }); } @@ -2665,9 +2673,10 @@ XlaOp Broadcast(const XlaOp& operand, absl::Span broadcast_sizes) { return operand.builder()->Broadcast(operand, broadcast_sizes); } -XlaOp BroadcastInDim(const XlaOp& operand, const Shape& shape, +XlaOp BroadcastInDim(const XlaOp& operand, + const absl::Span out_dim_size, const absl::Span broadcast_dimensions) { - return operand.builder()->BroadcastInDim(operand, shape, + return operand.builder()->BroadcastInDim(operand, out_dim_size, broadcast_dimensions); } diff --git a/tensorflow/compiler/xla/client/xla_builder.h b/tensorflow/compiler/xla/client/xla_builder.h index 78c90dbccc..098efb60f9 100644 --- a/tensorflow/compiler/xla/client/xla_builder.h +++ b/tensorflow/compiler/xla/client/xla_builder.h @@ -323,7 +323,8 @@ class XlaBuilder { XlaOp Broadcast(const XlaOp& operand, absl::Span broadcast_sizes); - XlaOp BroadcastInDim(const XlaOp& operand, const Shape& shape, + XlaOp BroadcastInDim(const XlaOp& operand, + const absl::Span out_dim_size, const absl::Span broadcast_dimensions); XlaOp Pad(const XlaOp& operand, const XlaOp& padding_value, @@ -824,7 +825,7 @@ class XlaBuilder { absl::Span broadcast_sizes); friend XlaOp BroadcastInDim( - const XlaOp& operand, const Shape& shape, + const XlaOp& operand, const absl::Span out_dim_size, const absl::Span broadcast_dimensions); friend XlaOp Pad(const XlaOp& operand, const XlaOp& padding_value, @@ -1217,7 +1218,8 @@ XlaOp Broadcast(const XlaOp& operand, absl::Span broadcast_sizes); // will generate output // {{1 , 1}, // {2 , 2}} -XlaOp BroadcastInDim(const XlaOp& operand, const Shape& shape, +XlaOp BroadcastInDim(const XlaOp& operand, + const absl::Span out_dim_size, const absl::Span broadcast_dimensions); // Enqueues a pad operation onto the computation that pads the given value on diff --git a/tensorflow/compiler/xla/client/xla_builder_test.cc b/tensorflow/compiler/xla/client/xla_builder_test.cc index e534fb67fd..b3f5be300d 100644 --- a/tensorflow/compiler/xla/client/xla_builder_test.cc +++ b/tensorflow/compiler/xla/client/xla_builder_test.cc @@ -267,7 +267,7 @@ TEST_F(XlaBuilderTest, BinopHasInDimAndDegenerateBroadcast) { TEST_F(XlaBuilderTest, BroadcastInDim) { XlaBuilder b(TestName()); auto x = Parameter(&b, 0, ShapeUtil::MakeShape(F32, {2, 3}), "x"); - BroadcastInDim(x, ShapeUtil::MakeShape(F32, {2, 4, 3}), + BroadcastInDim(x, {2, 4, 3}, /*broadcast_dimensions=*/{0, 2}); TF_ASSERT_OK_AND_ASSIGN(auto module, BuildHloModule(&b)); auto root = module->entry_computation()->root_instruction(); @@ -277,7 +277,7 @@ TEST_F(XlaBuilderTest, BroadcastInDim) { TEST_F(XlaBuilderTest, BroadcastInDimWithDegeneratedDim) { XlaBuilder b(TestName()); auto x = Parameter(&b, 0, ShapeUtil::MakeShape(F32, {2, 1, 4}), "x"); - BroadcastInDim(x, ShapeUtil::MakeShape(F32, {2, 3, 4}), + BroadcastInDim(x, {2, 3, 4}, /*broadcast_dimensions=*/{0, 1, 2}); TF_ASSERT_OK_AND_ASSIGN(auto module, BuildHloModule(&b)); EXPECT_THAT(module->entry_computation()->root_instruction(), diff --git a/tensorflow/compiler/xla/python/local_computation_builder.cc b/tensorflow/compiler/xla/python/local_computation_builder.cc index 2768ed618d..c0b57e7d26 100644 --- a/tensorflow/compiler/xla/python/local_computation_builder.cc +++ b/tensorflow/compiler/xla/python/local_computation_builder.cc @@ -323,42 +323,41 @@ StatusOr CompiledLocalComputation::Execute( GetReplicaCount()); for (int replica = 0; replica < GetReplicaCount(); ++replica) { - pool.Schedule( - [this, client, replica, &argument_handles, &results] { - StatusOr device_ordinal_status = - client->ReplicaNumberToDeviceOrdinal(replica); - if (!device_ordinal_status.ok()) { - results[replica] = device_ordinal_status.status(); - return; - } - const int device_ordinal = device_ordinal_status.ValueOrDie(); - VLOG(3) << "Replica " << replica - << " mapped to device ordinal for execution: " - << device_ordinal; - - std::vector argument_buffers; - argument_buffers.reserve(argument_handles.size()); - for (auto& handle : argument_handles) { - argument_buffers.push_back(handle->shaped_buffer()); - } - - DeviceAssignment device_assignment = - client->backend() - .computation_placer() - ->AssignDevices(GetReplicaCount(), /*computation_count=*/1) - .ConsumeValueOrDie(); - - ExecutableRunOptions options; - options.set_device_ordinal(device_ordinal); - options.set_allocator(client->backend().memory_allocator()); - options.set_intra_op_thread_pool( - client->backend().eigen_intra_op_thread_pool_device()); - options.set_device_assignment(&device_assignment); - StatusOr result_buffer_status = - executable_->Run(argument_buffers, options); - - results[replica] = std::move(result_buffer_status); - }); + pool.Schedule([this, client, replica, &argument_handles, &results] { + StatusOr device_ordinal_status = + client->ReplicaNumberToDeviceOrdinal(replica); + if (!device_ordinal_status.ok()) { + results[replica] = device_ordinal_status.status(); + return; + } + const int device_ordinal = device_ordinal_status.ValueOrDie(); + VLOG(3) << "Replica " << replica + << " mapped to device ordinal for execution: " + << device_ordinal; + + std::vector argument_buffers; + argument_buffers.reserve(argument_handles.size()); + for (auto& handle : argument_handles) { + argument_buffers.push_back(handle->shaped_buffer()); + } + + DeviceAssignment device_assignment = + client->backend() + .computation_placer() + ->AssignDevices(GetReplicaCount(), /*computation_count=*/1) + .ConsumeValueOrDie(); + + ExecutableRunOptions options; + options.set_device_ordinal(device_ordinal); + options.set_allocator(client->backend().memory_allocator()); + options.set_intra_op_thread_pool( + client->backend().eigen_intra_op_thread_pool_device()); + options.set_device_assignment(&device_assignment); + StatusOr result_buffer_status = + executable_->Run(argument_buffers, options); + + results[replica] = std::move(result_buffer_status); + }); } } @@ -585,9 +584,9 @@ LocalOp LocalComputationBuilder::Broadcast( } LocalOp LocalComputationBuilder::BroadcastInDim( - const LocalOp& operand, const Shape& shape, + const LocalOp& operand, absl::Span out_dim_sizes, absl::Span broadcast_dimensions) { - return xla::BroadcastInDim(operand.op(), shape, broadcast_dimensions); + return xla::BroadcastInDim(operand.op(), out_dim_sizes, broadcast_dimensions); } LocalOp LocalComputationBuilder::Pad(const LocalOp& operand, diff --git a/tensorflow/compiler/xla/python/local_computation_builder.h b/tensorflow/compiler/xla/python/local_computation_builder.h index 9e617c48bd..c9b7ae824a 100644 --- a/tensorflow/compiler/xla/python/local_computation_builder.h +++ b/tensorflow/compiler/xla/python/local_computation_builder.h @@ -282,7 +282,8 @@ class LocalComputationBuilder { LocalOp Broadcast(const LocalOp& operand, absl::Span broadcast_sizes); - LocalOp BroadcastInDim(const LocalOp& operand, const Shape& shape, + LocalOp BroadcastInDim(const LocalOp& operand, + absl::Span out_dim_sizes, absl::Span broadcast_dimensions); LocalOp Pad(const LocalOp& operand, const LocalOp& padding_value, diff --git a/tensorflow/compiler/xla/python/xla_client.py b/tensorflow/compiler/xla/python/xla_client.py index 5994e55387..e5fba0d7ac 100644 --- a/tensorflow/compiler/xla/python/xla_client.py +++ b/tensorflow/compiler/xla/python/xla_client.py @@ -778,8 +778,7 @@ class ComputationBuilder(object): Returns: A LocalOp representing the added broadcast-in-dimensions op. """ - xla_shape = Shape.array_shape(self.GetShape(operand).element_type(), shape) - return self._client.BroadcastInDim(operand, xla_shape, broadcast_dimensions) + return self._client.BroadcastInDim(operand, shape, broadcast_dimensions) def Concatenate(self, operands, dimension): """Enqueues a concatenate operation onto the computation. diff --git a/tensorflow/compiler/xla/tests/broadcast_simple_test.cc b/tensorflow/compiler/xla/tests/broadcast_simple_test.cc index dde19fb65d..702fb32adf 100644 --- a/tensorflow/compiler/xla/tests/broadcast_simple_test.cc +++ b/tensorflow/compiler/xla/tests/broadcast_simple_test.cc @@ -161,8 +161,7 @@ XLA_TEST_F(BroadcastSimpleTest, 1DTo2D) { XLA_TEST_F(BroadcastSimpleTest, 1DTo2D_WithDimsUsual) { XlaBuilder b(TestName()); - BroadcastInDim(ConstantR1(&b, {1, 2}), - ShapeUtil::MakeShape(F32, {2, 2}), {1}); + BroadcastInDim(ConstantR1(&b, {1, 2}), {2, 2}, {1}); Array2D expected(2, 2); expected(0, 0) = 1; @@ -175,8 +174,7 @@ XLA_TEST_F(BroadcastSimpleTest, 1DTo2D_WithDimsUsual) { XLA_TEST_F(BroadcastSimpleTest, 1DTo2D_WithDimsTranspose) { XlaBuilder b(TestName()); - BroadcastInDim(ConstantR1(&b, {1, 2}), - ShapeUtil::MakeShape(F32, {2, 2}), {0}); + BroadcastInDim(ConstantR1(&b, {1, 2}), {2, 2}, {0}); Array2D expected(2, 2); expected(0, 0) = 1; @@ -189,8 +187,8 @@ XLA_TEST_F(BroadcastSimpleTest, 1DTo2D_WithDimsTranspose) { XLA_TEST_F(BroadcastSimpleTest, 2DTo3D_WithDims) { XlaBuilder b(TestName()); - BroadcastInDim(ConstantR2(&b, {{1.0, 5.0}, {2.0, 6.0}}), - ShapeUtil::MakeShape(F32, {2, 2, 2}), {0, 1}); + BroadcastInDim(ConstantR2(&b, {{1.0, 5.0}, {2.0, 6.0}}), {2, 2, 2}, + {0, 1}); Array3D expected(2, 2, 2); expected(0, 0, 0) = 1.0; @@ -207,8 +205,8 @@ XLA_TEST_F(BroadcastSimpleTest, 2DTo3D_WithDims) { XLA_TEST_F(BroadcastSimpleTest, 2DTo3D_WithDimsNotPossibleWithBroadCast) { XlaBuilder b(TestName()); - BroadcastInDim(ConstantR2(&b, {{1.0, 5.0}, {2.0, 6.0}}), - ShapeUtil::MakeShape(F32, {2, 2, 2}), {0, 2}); + BroadcastInDim(ConstantR2(&b, {{1.0, 5.0}, {2.0, 6.0}}), {2, 2, 2}, + {0, 2}); Array3D expected(2, 2, 2); expected(0, 0, 0) = 1.0; @@ -225,8 +223,7 @@ XLA_TEST_F(BroadcastSimpleTest, 2DTo3D_WithDimsNotPossibleWithBroadCast) { XLA_TEST_F(BroadcastSimpleTest, 1DTo2D_WithDimsNotPossibleWithBroadCast) { XlaBuilder b(TestName()); - BroadcastInDim(ConstantR1(&b, {1, 2}), - ShapeUtil::MakeShape(F32, {3, 2}), {1}); + BroadcastInDim(ConstantR1(&b, {1, 2}), {3, 2}, {1}); Array2D expected(3, 2); expected(0, 0) = 1; -- GitLab From f1668a718e287b1178f3a3903602d52a2820607e Mon Sep 17 00:00:00 2001 From: Robert Neale Date: Thu, 29 Nov 2018 11:53:20 -0800 Subject: [PATCH 557/672] Add new unicode_encode op, which encodes integer codepoints into the desired unicode formatted string. RELNOTES: Add new unicode_encode op. PiperOrigin-RevId: 223384812 --- tensorflow/core/BUILD | 6 +- .../base_api/api_def_UnicodeEncode.pbtxt | 73 +++++ tensorflow/core/kernels/BUILD | 4 +- tensorflow/core/kernels/unicode_ops.cc | 154 +++++++-- tensorflow/core/ops/string_ops.cc | 36 +++ tensorflow/python/__init__.py | 1 + tensorflow/python/kernel_tests/BUILD | 15 + .../kernel_tests/unicode_encode_op_test.py | 301 ++++++++++++++++++ tensorflow/python/ops/ragged/BUILD | 16 + tensorflow/python/ops/ragged/__init__.py | 1 + .../python/ops/ragged/ragged_string_ops.py | 119 +++++++ .../api/golden/v1/tensorflow.strings.pbtxt | 4 + .../api/golden/v2/tensorflow.strings.pbtxt | 4 + 13 files changed, 702 insertions(+), 32 deletions(-) create mode 100644 tensorflow/core/api_def/base_api/api_def_UnicodeEncode.pbtxt create mode 100644 tensorflow/python/kernel_tests/unicode_encode_op_test.py create mode 100644 tensorflow/python/ops/ragged/ragged_string_ops.py diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 97628a2561..c268605711 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -1117,7 +1117,11 @@ tf_gen_op_libs( op_lib_names = [ "string_ops", ], - deps = ["@com_google_absl//absl/strings"], + deps = [ + ":lib_internal", + ":lib_proto_parsing", + "@com_google_absl//absl/strings", + ], ) tf_gen_op_libs( diff --git a/tensorflow/core/api_def/base_api/api_def_UnicodeEncode.pbtxt b/tensorflow/core/api_def/base_api/api_def_UnicodeEncode.pbtxt new file mode 100644 index 0000000000..26f7865860 --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_UnicodeEncode.pbtxt @@ -0,0 +1,73 @@ +op { + graph_op_name: "UnicodeEncode" + visibility: HIDDEN + endpoint { + name: "UnicodeEncode" + } + in_arg { + name: "input_values" + description: < +#include +#include #include #include +#include +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "unicode/appendable.h" // TF:icu +#include "unicode/schriter.h" // TF:icu +#include "unicode/uchar.h" // TF:icu #include "unicode/ucnv.h" // TF:icu #include "unicode/ucnv_err.h" // TF:icu #include "unicode/umachine.h" // TF:icu @@ -23,18 +31,58 @@ limitations under the License. #include "unicode/unistr.h" // TF:icu #include "unicode/uset.h" // TF:icu #include "unicode/utypes.h" // TF:icu +#include "tensorflow/core/framework/kernel_def_builder.h" +#include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" #include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/framework/tensor_shape.h" +#include "tensorflow/core/framework/tensor_types.h" +#include "tensorflow/core/framework/types.h" +#include "tensorflow/core/kernels/bounds_check.h" #include "tensorflow/core/kernels/string_util.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/lib/core/stringpiece.h" +#include "tensorflow/core/platform/types.h" #include "tensorflow/core/util/bcast.h" #include "tensorflow/core/util/ptr_util.h" namespace tensorflow { - namespace { +void Encode(const UnicodeEncoding encoding, const icu::UnicodeString& in, + string* out) { + if (encoding == UnicodeEncoding::UTF8) { + out->clear(); + in.toUTF8String(*out); + } else if (encoding == UnicodeEncoding::UTF16BE) { + // TODO(gbillock): consider using the + // extract(char *dest, int32_t destCapacity, UConverter *cnv) + // for UTF16/32 + out->clear(); // subtle: must come before reserve() + out->reserve(2 * in.length() + 1); + const char16_t* buf = in.getBuffer(); + for (int i = 0; i < in.length(); ++i) { + // Emit big-endian encoding for UTF-16 always. + out->push_back((buf[i] & 0xFF00) >> 8); + out->push_back(buf[i] & 0x00FF); + } + } else if (encoding == UnicodeEncoding::UTF32BE) { + out->clear(); // subtle: must come before reserve() + out->reserve(4 * in.countChar32() + 1); + icu::StringCharacterIterator it(in); + UChar32 ch; + while (it.hasNext()) { + ch = it.next32PostInc(); + out->push_back((ch & 0xFF000000) >> 24); + out->push_back((ch & 0x00FF0000) >> 16); + out->push_back((ch & 0x0000FF00) >> 8); + out->push_back((ch & 0x000000FF)); + } + } +} + // This error callback is only useful for finding illegal encoding errors when // we want to be strict -- otherwise illegal encodings are replaced on read // with 0xFFFD and signaled to the callback. @@ -183,8 +231,10 @@ Status GetErrorOptions(OpKernelConstruction* ctx, ErrorOptions* out) { "replacement_char out of unicode codepoint range"); } - TF_RETURN_IF_ERROR(ctx->GetAttr("replace_control_characters", - &(out->replace_control_chars))); + if (ctx->HasAttr("replace_control_characters")) { + TF_RETURN_IF_ERROR(ctx->GetAttr("replace_control_characters", + &(out->replace_control_chars))); + } return Status::OK(); } @@ -289,33 +339,7 @@ class UnicodeTranscodeOp : public OpKernel { found_any_format_error, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - if (output_encoding_ == UnicodeEncoding::UTF8) { - s->clear(); - source.toUTF8String(*s); - } else if (output_encoding_ == UnicodeEncoding::UTF16BE) { - // TODO(gbillock): consider using the - // extract(char *dest, int32_t destCapacity, UConverter *cnv) - // for UTF16/32 - s->clear(); // subtle: must come before reserve() - s->reserve(2 * source.length() + 1); - const char16_t* buf = source.getBuffer(); - for (int i = 0; i < source.length(); ++i) { - // Emit big-endian encoding for UTF-16 always. - s->push_back((buf[i] & 0xFF00) >> 8); - s->push_back(buf[i] & 0x00FF); - } - } else if (output_encoding_ == UnicodeEncoding::UTF32BE) { - s->clear(); // subtle: must come before reserve() - s->reserve(4 * source.countChar32() + 1); - for (int i = 0; i < source.countChar32(); ++i) { - // Emit big-endian encoding for UTF-32 always. - UChar32 ch = source.char32At(i); - s->push_back((ch & 0xFF000000) >> 24); - s->push_back((ch & 0x00FF0000) >> 16); - s->push_back((ch & 0x0000FF00) >> 8); - s->push_back((ch & 0x000000FF)); - } - } + Encode(output_encoding_, source, s); } string input_encoding_; @@ -443,4 +467,74 @@ class UnicodeDecodeWithOffsetsOp : public OpKernel { REGISTER_KERNEL_BUILDER(Name("UnicodeDecodeWithOffsets").Device(DEVICE_CPU), UnicodeDecodeWithOffsetsOp); +class UnicodeEncodeOp : public OpKernel { + public: + explicit UnicodeEncodeOp(OpKernelConstruction* ctx) : OpKernel(ctx) { + string encoding_tmp; + OP_REQUIRES_OK(ctx, ctx->GetAttr("output_encoding", &encoding_tmp)); + OP_REQUIRES_OK(ctx, ParseUnicodeEncoding(encoding_tmp, &encoding_)); + OP_REQUIRES_OK(ctx, GetErrorOptions(ctx, &error_options_)); + } + + /** + * Encodes Unicode codepoints into the desired string representation. + * + * We lose a dimension while encoding, since a series of integer codepoints is + * encoded into a single string. + * + * This accepts two input tensors: a rank 1 tensor of code point values and + * a single rank 1 tensor of splits which determine where each string begins + * and ends from the provided code points. + */ + void Compute(OpKernelContext* context) override { + // Get inputs + const Tensor& input_tensor = context->input(0); + const auto input_tensor_flat = input_tensor.flat(); + const Tensor& input_splits = context->input(1); + const auto input_splits_flat = input_splits.flat(); + + // Since we limit to a 2-D input (inner_values of rank 1 and a single splits + // tensor), our output dimension will be 1 with it's size equal to the + // number of splits (outer dimension or ragged tensor). + TensorShape output_shape({input_splits.dim_size(0) - 1}); + Tensor* output_tensor; + OP_REQUIRES_OK(context, context->allocate_output("output", output_shape, + &output_tensor)); + auto output_tensor_flat = output_tensor->flat(); + + // Use a single index over the flattened input values tensor. + int idx = 0; + // Loop through our split dimension to create a new string at each split. + for (int i = 1; i < input_splits_flat.size(); ++i) { + icu::UnicodeString unicode_string; + icu::UnicodeStringAppendable appendable_unicode_string(unicode_string); + for (; idx < input_splits_flat(i); ++idx) { + int32 code_point = input_tensor_flat(idx); + // Check for invalid code point + if (code_point > UCHAR_MAX_VALUE || code_point < UCHAR_MIN_VALUE) { + if (error_options_.error_on_malformatting) { + context->CtxFailure(errors::InvalidArgument( + "Code point value out of valid Unicode range.")); + return; + } else if (!error_options_.elide_replacement) { + code_point = error_options_.subst; + } + } + appendable_unicode_string.appendCodePoint(code_point); + } + // Encode our string and save in the output. + string result; + Encode(encoding_, unicode_string, &result); + output_tensor_flat(i - 1) = result; + } + } + + private: + UnicodeEncoding encoding_; + ErrorOptions error_options_; +}; + +REGISTER_KERNEL_BUILDER(Name("UnicodeEncode").Device(DEVICE_CPU), + UnicodeEncodeOp); + } // namespace tensorflow diff --git a/tensorflow/core/ops/string_ops.cc b/tensorflow/core/ops/string_ops.cc index fbecff11df..8ea74f1d43 100644 --- a/tensorflow/core/ops/string_ops.cc +++ b/tensorflow/core/ops/string_ops.cc @@ -13,13 +13,24 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +#include +#include + #include "absl/strings/str_split.h" #include "tensorflow/core/framework/common_shape_fns.h" #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/shape_inference.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/lib/strings/strcat.h" +#include "tensorflow/core/platform/types.h" namespace tensorflow { +namespace shape_inference { +class InferenceContext; +} // namespace shape_inference + using shape_inference::DimensionHandle; using shape_inference::InferenceContext; using shape_inference::ShapeHandle; @@ -250,6 +261,31 @@ REGISTER_OP("UnicodeScript") .Output("output: int32") .SetShapeFn(shape_inference::UnchangedShape); +REGISTER_OP("UnicodeEncode") + .Input("input_values: int32") + .Input("input_splits: int64") + .Attr("errors: {'ignore', 'replace', 'strict'} = 'replace'") + .Attr("output_encoding: {'UTF-8', 'UTF-16-BE', 'UTF-32-BE'}") + .Attr("replacement_char: int = 65533") // 0xFFFD unicode replacement char + .Output("output: string") + .SetShapeFn([](InferenceContext* c) { + // Check rank of inner values + ShapeHandle input_inner_values_shape = c->input(0); + ShapeHandle unused; + TF_RETURN_IF_ERROR(c->WithRank(input_inner_values_shape, 1, &unused)); + + // Check rank of input_splits + ShapeHandle splits_shape = c->input(1); + TF_RETURN_IF_ERROR(c->WithRank(splits_shape, 1, &unused)); + + // Output shape is a 1-D tensor with size equal to number of splits. + std::vector dims(1); + TF_RETURN_IF_ERROR(c->Subtract(c->Dim(splits_shape, 0), 1, &dims[0])); + c->set_output(0, c->MakeShape(dims)); + + return Status::OK(); + }); + REGISTER_OP("UnicodeTranscode") .Input("input: string") .Output("output: string") diff --git a/tensorflow/python/__init__.py b/tensorflow/python/__init__.py index 3b462c7de8..547043030b 100644 --- a/tensorflow/python/__init__.py +++ b/tensorflow/python/__init__.py @@ -86,6 +86,7 @@ from tensorflow.python.ops import image_ops as image from tensorflow.python.ops import manip_ops as manip from tensorflow.python.ops import metrics from tensorflow.python.ops import nn +from tensorflow.python.ops import ragged from tensorflow.python.ops import sets from tensorflow.python.ops.distributions import distributions from tensorflow.python.ops.linalg import linalg diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index de06ec622a..97ac21b8ad 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -1157,6 +1157,21 @@ cuda_py_test( ], ) +tf_py_test( + name = "unicode_encode_op_test", + size = "small", + srcs = ["unicode_encode_op_test.py"], + additional_deps = [ + "@absl_py//absl/testing:parameterized", + "//third_party/py/numpy", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:errors", + "//tensorflow/python/ops/ragged:ragged_factory_ops", + "//tensorflow/python/ops/ragged:ragged_string_ops", + ], +) + tf_py_test( name = "unicode_transcode_op_test", size = "small", diff --git a/tensorflow/python/kernel_tests/unicode_encode_op_test.py b/tensorflow/python/kernel_tests/unicode_encode_op_test.py new file mode 100644 index 0000000000..a5a5c2017c --- /dev/null +++ b/tensorflow/python/kernel_tests/unicode_encode_op_test.py @@ -0,0 +1,301 @@ +# Copyright 2016 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for UnicodeEncode op from ragged_string_ops.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl.testing import parameterized +import numpy as np + +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import errors_impl as errors +from tensorflow.python.framework import ops +from tensorflow.python.ops.ragged import ragged_factory_ops +from tensorflow.python.ops.ragged import ragged_string_ops +from tensorflow.python.platform import test + + +class UnicodeEncodeOpTest(test.TestCase, parameterized.TestCase): + + def testScalar(self): + with self.cached_session(): + with self.assertRaises(ValueError): + ragged_string_ops.unicode_encode(72, "UTF-8") + with self.cached_session(): + with self.assertRaises(ValueError): + ragged_string_ops.unicode_encode(constant_op.constant(72), "UTF-8") + + def testRequireParams(self): + with self.cached_session(): + with self.assertRaises(TypeError): + ragged_string_ops.unicode_encode() + with self.cached_session(): + with self.assertRaises(TypeError): + ragged_string_ops.unicode_encode(72) + with self.cached_session(): + with self.assertRaises(TypeError): + ragged_string_ops.unicode_encode(encoding="UTF-8") + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testStrictErrors(self, encoding): + test_value = np.array([72, 101, 2147483647, -1, 111], np.int32) + with self.cached_session(): + with self.assertRaises(errors.InvalidArgumentError): + ragged_string_ops.unicode_encode(test_value, encoding, "strict").eval() + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testIgnoreErrors(self, encoding): + test_value = np.array([72, 101, 2147483647, -1, 111], np.int32) + expected_value = u"Heo".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding, + "ignore") + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testReplaceErrors(self, encoding): + test_value = np.array([72, 101, 2147483647, -1, 111], np.int32) + expected_value = u"He\U0000fffd\U0000fffdo".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding, + "replace") + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + # Test custom replacement character + test_value = np.array([72, 101, 2147483647, -1, 111], np.int32) + expected_value = u"Heooo".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding, + "replace", 111) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + # Verify "replace" is default + test_value = np.array([72, 101, 2147483647, -1, 111], np.int32) + expected_value = u"He\U0000fffd\U0000fffdo".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + # Replacement_char must be within range + test_value = np.array([72, 101, 2147483647, -1, 111], np.int32) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding, + "replace", 1114112) + with self.cached_session(): + with self.assertRaises(errors.InvalidArgumentError): + unicode_encode_op.eval() + + # -- regular Tensor tests -- # + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testVector(self, encoding): + test_value = np.array([72, 101, 108, 108, 111], np.int32) + expected_value = u"Hello".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + test_value = np.array([72, 101, 195, 195, 128516], np.int32) + expected_value = u"He\xc3\xc3\U0001f604".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + # Single character string + test_value = np.array([72], np.int32) + expected_value = u"H".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + test_value = np.array([128516], np.int32) + expected_value = u"\U0001f604".encode(encoding) + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(result, bytes) + self.assertAllEqual(result, expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testMatrix(self, encoding): + test_value = np.array( + [[72, 128516, 108, 108, 111], [87, 128516, 114, 108, 100]], np.int32) + expected_value = [ + u"H\U0001f604llo".encode(encoding), u"W\U0001f604rld".encode(encoding) + ] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(unicode_encode_op, ops.Tensor) + self.assertAllEqual(result, expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def test3DimMatrix(self, encoding): + test_value = constant_op.constant( + [[[72, 101, 108, 108, 111], [87, 111, 114, 108, 100]], + [[102, 105, 120, 101, 100], [119, 111, 114, 100, 115]], + [[72, 121, 112, 101, 114], [99, 117, 98, 101, 46]]], np.int32) + expected_value = [[u"Hello".encode(encoding), u"World".encode(encoding)], + [u"fixed".encode(encoding), u"words".encode(encoding)], + [u"Hyper".encode(encoding), u"cube.".encode(encoding)]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(unicode_encode_op, ops.Tensor) + self.assertAllEqual(result, expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def test4DimMatrix(self, encoding): + test_value = constant_op.constant( + [[[[72, 101, 108, 108, 111]], [[87, 111, 114, 108, 100]]], + [[[102, 105, 120, 101, 100]], [[119, 111, 114, 100, 115]]], + [[[72, 121, 112, 101, 114]], [[99, 117, 98, 101, 46]]]], np.int32) + expected_value = [[[u"Hello".encode(encoding)], + [u"World".encode(encoding)]], + [[u"fixed".encode(encoding)], + [u"words".encode(encoding)]], + [[u"Hyper".encode(encoding)], + [u"cube.".encode(encoding)]]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(unicode_encode_op, ops.Tensor) + self.assertAllEqual(result, expected_value) + + # -- Ragged Tensor tests -- # + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testRaggedMatrix(self, encoding): + test_value = ragged_factory_ops.constant( + [[72, 195, 108, 108, 111], [87, 128516, 114, 108, 100, 46]], np.int32) + expected_value = [ + u"H\xc3llo".encode(encoding), u"W\U0001f604rld.".encode(encoding) + ] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertIsInstance(unicode_encode_op, ops.Tensor) + self.assertAllEqual(result, expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def test3DimMatrixWithRagged2ndDim(self, encoding): + test_value = ragged_factory_ops.constant( + [[[72, 101, 108, 108, 111], [87, 111, 114, 108, 100]], + [[102, 105, 120, 101, 100]], + [[72, 121, 112, 101, 114], [119, 111, 114, 100, 115], + [99, 117, 98, 101, 46]]], np.int32) + expected_value = [[u"Hello".encode(encoding), u"World".encode(encoding)], + [u"fixed".encode(encoding)], + [ + u"Hyper".encode(encoding), u"words".encode(encoding), + u"cube.".encode(encoding) + ]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertEqual(unicode_encode_op.ragged_rank, 1) + self.assertAllEqual(result.tolist(), expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def test3DimMatrixWithRagged3rdDim(self, encoding): + test_value = ragged_factory_ops.constant( + [[[72, 101, 108, 108, 111], [87, 111, 114, 108, 100, 46]], + [[68, 111, 110, 39, 116], [119, 195, 114, 114, 121, 44, 32, 98, 101]], + [[128516], []]], np.int32) + expected_value = [[u"Hello".encode(encoding), u"World.".encode(encoding)], + [ + u"Don't".encode(encoding), + u"w\xc3rry, be".encode(encoding) + ], [u"\U0001f604".encode(encoding), u"".encode(encoding)]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertEqual(unicode_encode_op.ragged_rank, 1) + self.assertAllEqual(result.tolist(), expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def test3DimMatrixWithRagged2ndAnd3rdDim(self, encoding): + test_value = ragged_factory_ops.constant( + [[[72, 101, 108, 108, 111], [87, 111, 114, 108, 100, 46]], [], + [[128516]]], np.int32) + expected_value = [[u"Hello".encode(encoding), u"World.".encode(encoding)], + [], [u"\U0001f604".encode(encoding)]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertEqual(unicode_encode_op.ragged_rank, 1) + self.assertAllEqual(result.tolist(), expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def test4DimRaggedMatrix(self, encoding): + test_value = ragged_factory_ops.constant( + [[[[72, 101, 108, 108, 111], [87, 111, 114, 108, 100]]], + [[[]], [[72, 121, 112, 101]]]], np.int32) + expected_value = [[[u"Hello".encode(encoding), u"World".encode(encoding)]], + [[u"".encode(encoding)], [u"Hype".encode(encoding)]]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertEqual(unicode_encode_op.ragged_rank, 2) + self.assertAllEqual(result.tolist(), expected_value) + + @parameterized.parameters("UTF-8", "UTF-16-BE", "UTF-32-BE") + def testRaggedMatrixWithMultiDimensionInnerValues(self, encoding): + test_inner_values = constant_op.constant([[[72, 101, 108, 108, 111], + [87, 111, 114, 108, 100]], + [[102, 105, 120, 101, 100], + [119, 111, 114, 100, 115]], + [[72, 121, 112, 101, 114], + [99, 117, 98, 101, 46]]]) + test_row_splits = [ + constant_op.constant([0, 2, 3], dtype=np.int64), + constant_op.constant([0, 1, 1, 3], dtype=np.int64) + ] + test_value = ragged_factory_ops.from_nested_row_splits(test_inner_values, + test_row_splits) + expected_value = [[[[u"Hello".encode(encoding), u"World".encode(encoding)]], + []], + [[[u"fixed".encode(encoding), u"words".encode(encoding)], + [u"Hyper".encode(encoding), + u"cube.".encode(encoding)]]]] + unicode_encode_op = ragged_string_ops.unicode_encode(test_value, encoding) + with self.cached_session(): + result = unicode_encode_op.eval() + self.assertEqual(unicode_encode_op.ragged_rank, 2) + self.assertAllEqual(result.tolist(), expected_value) + # These next two assertions don't necessarily need to be here as they test + # internal representations and we already verified the value is correct. + self.assertAllEqual(len(result.nested_row_splits), len(test_row_splits)) + self.assertEqual(unicode_encode_op.inner_values.shape.ndims, + test_inner_values.shape.ndims - 1) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/ops/ragged/BUILD b/tensorflow/python/ops/ragged/BUILD index 8608bda647..e335c5cb6f 100644 --- a/tensorflow/python/ops/ragged/BUILD +++ b/tensorflow/python/ops/ragged/BUILD @@ -32,6 +32,7 @@ py_library( ":ragged_map_ops", ":ragged_math_ops", ":ragged_operators", + ":ragged_string_ops", ":ragged_tensor", ":ragged_tensor_shape", ":ragged_tensor_value", @@ -180,6 +181,21 @@ py_library( ], ) +py_library( + name = "ragged_string_ops", + srcs = ["ragged_string_ops.py"], + srcs_version = "PY2AND3", + deps = [ + ":ragged_array_ops", + ":ragged_conversion_ops", + ":ragged_factory_ops", + ":ragged_tensor", + "//tensorflow/python:array_ops", + "//tensorflow/python:math_ops", + "//tensorflow/python:util", + ], +) + py_library( name = "ragged_tensor", srcs = ["ragged_tensor.py"], diff --git a/tensorflow/python/ops/ragged/__init__.py b/tensorflow/python/ops/ragged/__init__.py index 3e802485a3..1b2a7be95f 100644 --- a/tensorflow/python/ops/ragged/__init__.py +++ b/tensorflow/python/ops/ragged/__init__.py @@ -156,6 +156,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.ops.ragged import ragged_operators +from tensorflow.python.ops.ragged import ragged_string_ops from tensorflow.python.ops.ragged.ragged_array_ops import batch_gather from tensorflow.python.ops.ragged.ragged_array_ops import boolean_mask diff --git a/tensorflow/python/ops/ragged/ragged_string_ops.py b/tensorflow/python/ops/ragged/ragged_string_ops.py new file mode 100644 index 0000000000..cdcdbdff07 --- /dev/null +++ b/tensorflow/python/ops/ragged/ragged_string_ops.py @@ -0,0 +1,119 @@ +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== +"""Ragged operations for working with string Tensors.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import gen_string_ops +from tensorflow.python.ops.ragged import ragged_conversion_ops +from tensorflow.python.ops.ragged import ragged_factory_ops +from tensorflow.python.ops.ragged import ragged_tensor +from tensorflow.python.util.tf_export import tf_export + + +# pylint: disable=redefined-builtin +@tf_export("strings.unicode_encode") +def unicode_encode(input, output_encoding, errors="replace", + replacement_char=65533, name=None): + r"""Encodes each sequence of Unicode code points in `input` into a string. + + `result[i1...iN]` is the string formed by concatenating the Unicode + codepoints `input[1...iN, :]`, encoded using `output_encoding`. + + Args: + input: An `N+1` dimensional potentially ragged integer tensor with + shape `[D1...DN, num_chars]`. + output_encoding: Unicode encoding that should be used to encode each + codepoint sequence. Can be `"UTF-8"`, `"UTF-16-BE"`, or `"UTF-32-BE"`. + errors: Specifies the response when an invalid codepoint is encountered + (optional). One of: + * `'replace'`: Replace invalid codepoint with the + `replacement_char`. (default) + * `'ignore'`: Skip invalid codepoints. + * `'strict'`: Raise an exception for any invalid codepoint. + replacement_char: The replacement character codepoint to be used in place of + any invalid input when `errors='replace'`. Any valid unicode codepoint may + be used. The default value is the default unicode replacement character + which is 0xFFFD (U+65533). + name: A name for the operation (optional). + + Returns: + A `N` dimensional `string` tensor with shape `[D1...DN]`. + + #### Example: + ```python + >>> input = [[71, 246, 246, 100, 110, 105, 103, 104, 116], [128522]] + >>> unicode_encode(input, 'UTF8') + ['G\xc3\xb6\xc3\xb6dnight', '\xf0\x9f\x98\x8a'] + ``` + """ + with ops.name_scope(name, "UnicodeEncode", [input]): + input_tensor = ragged_factory_ops.convert_to_tensor_or_ragged_tensor(input) + if input_tensor.shape.ndims is None: + raise ValueError("Rank of input_tensor must be statically known.") + if ragged_tensor.is_ragged(input_tensor): + if input_tensor.inner_values.shape.ndims > 1: + # If the inner_values of our ragged tensor is multi-dimensional, we can + # process it separately and our output will have the same nested splits + # as our input. + return input_tensor.with_inner_values( + unicode_encode(input_tensor.inner_values, output_encoding, errors, + replacement_char)) + elif input_tensor.ragged_rank > 1: + # Recursively process the values of the ragged tensor. + return input_tensor.with_values( + unicode_encode(input_tensor.values, output_encoding, errors, + replacement_char)) + else: + # Our ragged tensor is of the correct shape (rank 1 inner_values tensor + # with ragged_rank of 1) so we can process it as normal. + return gen_string_ops.unicode_encode( + input_values=input_tensor.values, + input_splits=input_tensor.row_splits, + output_encoding=output_encoding, + errors=errors, + replacement_char=replacement_char) + else: + if input_tensor.shape.ndims == 2: + # The input tensor is of the correct 2-D shape, it's just not ragged. + return unicode_encode(ragged_conversion_ops.from_tensor(input_tensor), + output_encoding, errors, replacement_char) + elif input_tensor.shape.ndims > 2: + # We need to initially flatten the input tensor to 2-D, and then can + # reshape the output of our processed flattened tensor. + flat_input_tensor = array_ops.reshape( + input_tensor, + array_ops.stack([-1, array_ops.shape(input_tensor)[-1]])) + flat_output_tensor = unicode_encode(flat_input_tensor, output_encoding, + errors, replacement_char) + return array_ops.reshape(flat_output_tensor, input_tensor.shape[:-1]) + elif input_tensor.shape.ndims == 0: + raise ValueError("input_tensor's rank must be at least 1.") + else: + # Our input tensor is rank 1, so we create a ragged tensor with an added + # dimension to create the correct input shape & type, and then remove + # the additional dimension from the output and return the string scalar. + ragged_input_tensor = ragged_factory_ops.from_row_splits( + input_tensor, + array_ops.stack([0, array_ops.shape(input_tensor, + out_type=dtypes.int64)[0]])) + output_tensor = unicode_encode(ragged_input_tensor, output_encoding, + errors, replacement_char) + return array_ops.reshape(output_tensor, []) diff --git a/tensorflow/tools/api/golden/v1/tensorflow.strings.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.strings.pbtxt index 03144cbe70..a1cd581a86 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.strings.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.strings.pbtxt @@ -52,6 +52,10 @@ tf_module { name: "to_number" argspec: "args=[\'string_tensor\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " } + member_method { + name: "unicode_encode" + argspec: "args=[\'input\', \'output_encoding\', \'errors\', \'replacement_char\', \'name\'], varargs=None, keywords=None, defaults=[\'replace\', \'65533\', \'None\'], " + } member_method { name: "unicode_script" argspec: "args=[\'input\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt index f2f4879fe8..f6e32ed08c 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt @@ -52,6 +52,10 @@ tf_module { name: "to_number" argspec: "args=[\'input\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " } + member_method { + name: "unicode_encode" + argspec: "args=[\'input\', \'output_encoding\', \'errors\', \'replacement_char\', \'name\'], varargs=None, keywords=None, defaults=[\'replace\', \'65533\', \'None\'], " + } member_method { name: "unicode_script" argspec: "args=[\'input\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " -- GitLab From 4dac3ae470e40153a4253dee9e83bb28aabba55c Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Thu, 29 Nov 2018 11:54:56 -0800 Subject: [PATCH 558/672] Add publicly available corpus for decode_bmp_fuzz. PiperOrigin-RevId: 223385117 --- tensorflow/core/kernels/fuzzing/BUILD | 2 ++ .../012e3ad384a4a1165f8498b5c94ba0d32a73e187 | Bin 0 -> 420 bytes .../055d77f7810048caa28323f6eb552a53d156040b | Bin 0 -> 594 bytes .../131e251bfb82c681cb075d32b99f18fceaca115d | Bin 0 -> 287 bytes .../1399ab0bd9f2c91d270cb43251bdc5729bef3526 | Bin 0 -> 1684 bytes .../16a6ce88f66d2e9686c8354cad8ba915cf0c11de | Bin 0 -> 207 bytes .../185097ed0588195164619ea930ddd8274a5f32ad | Bin 0 -> 3648 bytes .../27711a87e06a50c81571c27c3aa403a6ad5dc55c | Bin 0 -> 2218 bytes .../decode_bmp/298c3787ad1722b22569cbc405c464d2 | Bin 0 -> 4234 bytes .../decode_bmp/2b95ba6d8141ce0d29ff279770903922 | Bin 0 -> 4234 bytes .../321fb3d758b86e37fc340ae2b09b8ed9fa73a4cb | Bin 0 -> 4234 bytes .../331a98b4e4c87840efea69223766ebd0e1736542 | Bin 0 -> 420 bytes .../352d73f841223ecb630b5836585d2ba7b0f9d883 | Bin 0 -> 2249 bytes .../decode_bmp/3a84f409d4c117edfdebc508cd23e8fc | Bin 0 -> 3194 bytes .../3ef5cc982c0b45f69a26fd0f7d376415fdebabd1 | Bin 0 -> 220 bytes .../401c7de8e122018a0e17f57c93db7ee49ab0e906 | Bin 0 -> 865 bytes .../52fee71bb8c9c79068e1fe580677ad739a2d0415 | Bin 0 -> 361 bytes .../57b11507813d5727b7789354d888eda83d5f3d86 | Bin 0 -> 2846 bytes .../57dff0fa53ee0ef24a43cca6ab0523bfdc1f720d | Bin 0 -> 864 bytes .../5c42d3df0dc400a7a4175b8d4eec6cc8ee2437b2 | Bin 0 -> 2246 bytes .../5cca20637ae75fddad9370ee930837baef8aeb43 | Bin 0 -> 4234 bytes .../5d34bc9cef0c844b9c5ebe948145c4ca11b5ca09 | Bin 0 -> 2639 bytes .../5e162fe883bd12fb1c4131d4e0c979a12bd15eac | Bin 0 -> 76 bytes .../5e83f8faab9c1a51a33d5e29edbb9dcec23c6092 | Bin 0 -> 1412 bytes .../decode_bmp/61b29dc2fcef7b6fbe3e0cc88769a7ef | Bin 0 -> 3194 bytes .../6361eca190157ece389665ee523ccc3aefcd957f | Bin 0 -> 3708 bytes .../65150515ab3b11d657519b22bb887d74e94b2d7f | Bin 0 -> 4234 bytes .../656f38ef6dcd58c6a909d61db11f777def69c394 | Bin 0 -> 1406 bytes .../66e0d2cafd592bf9d61ad900fade8ee530d5f3d7 | Bin 0 -> 203 bytes .../6b5b42cb105a2c4c5fd6034e9885cbe457f1b50c | Bin 0 -> 361 bytes .../722ed0197cb92ecbf9745edb38275e7a9aaf322f | Bin 0 -> 454 bytes .../77bdd2efdf328366cbbf3c5688768dc0a88d02b1 | Bin 0 -> 16 bytes .../7841bfa002c05c61d5a5d9241f214cc17a336166 | Bin 0 -> 864 bytes .../decode_bmp/7899e22fc83f6be28e9130c4a1c91a48 | Bin 0 -> 4234 bytes .../7dddccaebd16ae0c26daeffc42df50f529891119 | Bin 0 -> 2249 bytes .../8157442eee4bbfdd9716e264b11085d61a9955b7 | Bin 0 -> 48 bytes .../81ff28ed63d5435ddc4c8771dd5d40aa658cbbe0 | Bin 0 -> 2052 bytes .../820c8c0d33c18f6c4d9edd314e91289186931ad0 | Bin 0 -> 1318 bytes .../849e9d7cee1c52105242327086997296e452b981 | Bin 0 -> 1237 bytes .../84ddb92c63e0fad7018f6069daf8779ce11501e2 | Bin 0 -> 1167 bytes .../86bc3d5dbb9313137502080e58551edd2e649c70 | Bin 0 -> 929 bytes .../87d94d88fe29d277c76e1a52042b02c092d5ae14 | Bin 0 -> 420 bytes .../8c4646f3357945c4e19a59ff79fffe3c874dbf16 | Bin 0 -> 189 bytes .../90632bc6dee4eb836f3d7db1d16446a9c8510080 | Bin 0 -> 3895 bytes .../94d06016aa949e8e7203217e4cc6625ded7f4244 | Bin 0 -> 3102 bytes .../9875819b9e5783e7489c29a81cc9d4279209956a | Bin 0 -> 22 bytes .../9c1cc734114b29aac6c51782d5c17e9dbe1faca2 | Bin 0 -> 3194 bytes .../decode_bmp/9d2961871eeb201ef8a6f5503d8a8b62 | Bin 0 -> 3194 bytes .../9f39e11cdd88344a4894b678e5a04a810880064d | Bin 0 -> 972 bytes .../a350588a6dabe4376a066aed44ef8786d8e752e7 | Bin 0 -> 861 bytes .../a6101a79919d444e1fc50aefab5837c39e3f4a19 | Bin 0 -> 1237 bytes .../a9c8793f8fb063bec839ee1280406fe5396545e5 | Bin 0 -> 420 bytes .../ad4e9d2234e8599bdf12607c6b8cab4edae82c4e | Bin 0 -> 420 bytes .../decode_bmp/b90b6830917919e94186d312f06481bd | Bin 0 -> 3194 bytes .../b98fd4cb1d7031240414301c19b03097c0035c6b | Bin 0 -> 857 bytes .../ba976fcdb4daf092ef17ce43bf2b78d9d8bc2aeb | Bin 0 -> 2262 bytes .../bc112b571eafee0f5a031f3c9cce6244216d128d | Bin 0 -> 4234 bytes .../decode_bmp/c42b981c28a1715c375050f6fcf53f1d | Bin 0 -> 3194 bytes .../c6049874b33eadb016fccf0c5fa66e556ae069b9 | Bin 0 -> 3194 bytes .../c8697bf2369f6ab85f501376c4d93bb8a56974a3 | Bin 0 -> 420 bytes .../c8daf283e0aef2fd7b630c0430e05dc28f24ecf6 | Bin 0 -> 220 bytes .../cacff56e1af4b8fde912822da06b10fb8c545a19 | Bin 0 -> 1033 bytes .../decode_bmp/ce4dcc22b1d595c49a25121c0b580104 | Bin 0 -> 4234 bytes .../d0cd71dbf039fd64cf42eff30da92a71a919226a | Bin 0 -> 587 bytes .../d5ce626ac3264bed6af5580e341a89406857cbb9 | Bin 0 -> 1760 bytes .../d77ada02e9bc8c24b2711eca6a8f52ae356bfc21 | Bin 0 -> 361 bytes .../d7eb9c5a0f9803df4c00390793b8ab57bd7c9484 | Bin 0 -> 3792 bytes .../dc1efccdeec17e151a1ec8228c09ab61c3040b33 | Bin 0 -> 35 bytes .../decode_bmp/dcea22c66c60088165a2f1772036473f | Bin 0 -> 4234 bytes .../de539ae7442fa05dafcfe1a021f0186ef74a2b0e | Bin 0 -> 103 bytes .../e2306b1d6b88d0ccc4e2c3a9edb07462a5a32215 | Bin 0 -> 110 bytes .../e2778da0240fdd15ef5844905d81c4e05f34a8bd | Bin 0 -> 3194 bytes .../e6642e9266875f9d908942e534bf898103a2c794 | Bin 0 -> 2186 bytes .../ec6cdb929c08d8daf2bd7fc185fbf4d787b45120 | Bin 0 -> 1942 bytes .../ed8636357f79439b6a03eb14469b686cc401a1c9 | Bin 0 -> 3895 bytes .../ee313e9acecb5c688ce8c9bb10e70e136fbb9c6d | Bin 0 -> 3616 bytes .../ef689af320e7d9e22231109faae2e8149cb86e1c | Bin 0 -> 834 bytes .../fda6b9a9f6ffdf4765c00465619c7ceb3f7db2e4 | Bin 0 -> 1136 bytes .../ffe829bb0adac20d9c0756f68a22d1255e4fdb54 | Bin 0 -> 3194 bytes 79 files changed, 2 insertions(+) create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/012e3ad384a4a1165f8498b5c94ba0d32a73e187 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/055d77f7810048caa28323f6eb552a53d156040b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/131e251bfb82c681cb075d32b99f18fceaca115d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/1399ab0bd9f2c91d270cb43251bdc5729bef3526 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/16a6ce88f66d2e9686c8354cad8ba915cf0c11de create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/185097ed0588195164619ea930ddd8274a5f32ad create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/27711a87e06a50c81571c27c3aa403a6ad5dc55c create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/298c3787ad1722b22569cbc405c464d2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/2b95ba6d8141ce0d29ff279770903922 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/321fb3d758b86e37fc340ae2b09b8ed9fa73a4cb create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/331a98b4e4c87840efea69223766ebd0e1736542 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/352d73f841223ecb630b5836585d2ba7b0f9d883 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/3a84f409d4c117edfdebc508cd23e8fc create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/3ef5cc982c0b45f69a26fd0f7d376415fdebabd1 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/401c7de8e122018a0e17f57c93db7ee49ab0e906 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/52fee71bb8c9c79068e1fe580677ad739a2d0415 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/57b11507813d5727b7789354d888eda83d5f3d86 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/57dff0fa53ee0ef24a43cca6ab0523bfdc1f720d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5c42d3df0dc400a7a4175b8d4eec6cc8ee2437b2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5cca20637ae75fddad9370ee930837baef8aeb43 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5d34bc9cef0c844b9c5ebe948145c4ca11b5ca09 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5e162fe883bd12fb1c4131d4e0c979a12bd15eac create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5e83f8faab9c1a51a33d5e29edbb9dcec23c6092 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/61b29dc2fcef7b6fbe3e0cc88769a7ef create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/6361eca190157ece389665ee523ccc3aefcd957f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/65150515ab3b11d657519b22bb887d74e94b2d7f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/656f38ef6dcd58c6a909d61db11f777def69c394 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/66e0d2cafd592bf9d61ad900fade8ee530d5f3d7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/6b5b42cb105a2c4c5fd6034e9885cbe457f1b50c create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/722ed0197cb92ecbf9745edb38275e7a9aaf322f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/77bdd2efdf328366cbbf3c5688768dc0a88d02b1 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7841bfa002c05c61d5a5d9241f214cc17a336166 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7899e22fc83f6be28e9130c4a1c91a48 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7dddccaebd16ae0c26daeffc42df50f529891119 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/8157442eee4bbfdd9716e264b11085d61a9955b7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/81ff28ed63d5435ddc4c8771dd5d40aa658cbbe0 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/820c8c0d33c18f6c4d9edd314e91289186931ad0 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/849e9d7cee1c52105242327086997296e452b981 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/84ddb92c63e0fad7018f6069daf8779ce11501e2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/86bc3d5dbb9313137502080e58551edd2e649c70 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/87d94d88fe29d277c76e1a52042b02c092d5ae14 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/8c4646f3357945c4e19a59ff79fffe3c874dbf16 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/90632bc6dee4eb836f3d7db1d16446a9c8510080 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/94d06016aa949e8e7203217e4cc6625ded7f4244 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9875819b9e5783e7489c29a81cc9d4279209956a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9c1cc734114b29aac6c51782d5c17e9dbe1faca2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9d2961871eeb201ef8a6f5503d8a8b62 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9f39e11cdd88344a4894b678e5a04a810880064d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a350588a6dabe4376a066aed44ef8786d8e752e7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a6101a79919d444e1fc50aefab5837c39e3f4a19 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a9c8793f8fb063bec839ee1280406fe5396545e5 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ad4e9d2234e8599bdf12607c6b8cab4edae82c4e create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/b90b6830917919e94186d312f06481bd create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/b98fd4cb1d7031240414301c19b03097c0035c6b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ba976fcdb4daf092ef17ce43bf2b78d9d8bc2aeb create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/bc112b571eafee0f5a031f3c9cce6244216d128d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c42b981c28a1715c375050f6fcf53f1d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c6049874b33eadb016fccf0c5fa66e556ae069b9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c8697bf2369f6ab85f501376c4d93bb8a56974a3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c8daf283e0aef2fd7b630c0430e05dc28f24ecf6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/cacff56e1af4b8fde912822da06b10fb8c545a19 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ce4dcc22b1d595c49a25121c0b580104 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d0cd71dbf039fd64cf42eff30da92a71a919226a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d5ce626ac3264bed6af5580e341a89406857cbb9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d77ada02e9bc8c24b2711eca6a8f52ae356bfc21 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d7eb9c5a0f9803df4c00390793b8ab57bd7c9484 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/dc1efccdeec17e151a1ec8228c09ab61c3040b33 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/dcea22c66c60088165a2f1772036473f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/de539ae7442fa05dafcfe1a021f0186ef74a2b0e create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e2306b1d6b88d0ccc4e2c3a9edb07462a5a32215 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e2778da0240fdd15ef5844905d81c4e05f34a8bd create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e6642e9266875f9d908942e534bf898103a2c794 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ec6cdb929c08d8daf2bd7fc185fbf4d787b45120 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ed8636357f79439b6a03eb14469b686cc401a1c9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ee313e9acecb5c688ce8c9bb10e70e136fbb9c6d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ef689af320e7d9e22231109faae2e8149cb86e1c create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/fda6b9a9f6ffdf4765c00465619c7ceb3f7db2e4 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ffe829bb0adac20d9c0756f68a22d1255e4fdb54 diff --git a/tensorflow/core/kernels/fuzzing/BUILD b/tensorflow/core/kernels/fuzzing/BUILD index 7d59beb09b..3ea9dd0638 100644 --- a/tensorflow/core/kernels/fuzzing/BUILD +++ b/tensorflow/core/kernels/fuzzing/BUILD @@ -42,6 +42,8 @@ tf_ops_fuzz_target_lib("encode_jpeg") tf_ops_fuzz_target_lib("decode_bmp") +tf_oss_fuzz_corpus("decode_bmp") + tf_ops_fuzz_target_lib("decode_png") tf_ops_fuzz_target_lib("decode_wav") diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/012e3ad384a4a1165f8498b5c94ba0d32a73e187 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/012e3ad384a4a1165f8498b5c94ba0d32a73e187 new file mode 100644 index 0000000000000000000000000000000000000000..7a1b8966c21c74f1e0a3f3af4240551bc10ef36c GIT binary patch literal 420 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~uS=>LC)|Ns9pP-+as kP$&1GVh9VF{Ey%`Aeb-~6N~|J1}+Tp3&b-p)kBE}09IruQUCw| literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/055d77f7810048caa28323f6eb552a53d156040b b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/055d77f7810048caa28323f6eb552a53d156040b new file mode 100644 index 0000000000000000000000000000000000000000..24f658497f182188a6cbf431e1ff810ca268e709 GIT binary patch literal 594 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= h#sB~RXBbdSwXmSCM~HIvf6C(r8ejjRG@L>c0084c$3*}D literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/131e251bfb82c681cb075d32b99f18fceaca115d b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/131e251bfb82c681cb075d32b99f18fceaca115d new file mode 100644 index 0000000000000000000000000000000000000000..a2d8f84cab77d805ae2582fb551fe2f074b2cfbb GIT binary patch literal 287 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)FoPjT0F3`LFhCFk0|OfaBg21& p|Nqf3h7c=;5+p4csxb|OtA>~ZR{+uq=Ro8@Lbxzdo(7r6001>fj5z=R literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/1399ab0bd9f2c91d270cb43251bdc5729bef3526 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/1399ab0bd9f2c91d270cb43251bdc5729bef3526 new file mode 100644 index 0000000000000000000000000000000000000000..6206dab82b1e4a3d96ee4ae276006183349aa8e6 GIT binary patch literal 1684 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=QG0cn@L{ zjhWC@{{R1<0fM0vjQd{!A`IuF%cJrc85l`Y54V;`^YN)ibqPL|RIm)M@wm+=!Hu{L z8L$v0)6?X*7dfCv)z3zTJGsF*iVTgIj{D9)6=R5v|NY28h0LBkn_TM#*+d2gkeLr2JOIR>AL^_88{gj7>8U~;7KP8EYuID;S@fj iei=<41k(WXPz$4P@G^~{-|&^Tu(}WCE@&LXxOnOR4FCU+V(NtfuE2K0B|&>}c=UoIntIVqJ(EE0qCaND ZAL;Lj@*jz@$H+*chEe6CAutj{003P%43hu= literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/298c3787ad1722b22569cbc405c464d2 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/298c3787ad1722b22569cbc405c464d2 new file mode 100644 index 0000000000000000000000000000000000000000..af1091428d59645a8158218a953fbd60e0c463d8 GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lje u6pyMM4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVCGApih??guRZ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/2b95ba6d8141ce0d29ff279770903922 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/2b95ba6d8141ce0d29ff279770903922 new file mode 100644 index 0000000000000000000000000000000000000000..fd711cb0e51bb10d84902b03d3a27c086ec8dfbc GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXBfq!VKABoM$^D(8W>FjqiJ9?4UDFN(KIlc21e7sXc`zz1EXnRSf>F18>suz literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/321fb3d758b86e37fc340ae2b09b8ed9fa73a4cb b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/321fb3d758b86e37fc340ae2b09b8ed9fa73a4cb new file mode 100644 index 0000000000000000000000000000000000000000..6748826bd88a8ff6616536e0badb9b5d5184d9cb GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXBa`4sE`MR2YNV-@<&5pGz5lt2#l<%5Eb$u^B4e#p1@B4 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/352d73f841223ecb630b5836585d2ba7b0f9d883 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/352d73f841223ecb630b5836585d2ba7b0f9d883 new file mode 100644 index 0000000000000000000000000000000000000000..932e78b3547e36ee7892f97135b7ac16d03bdff8 GIT binary patch literal 2249 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)H3=9lx zP#Tr`|Ns9VR1pRyG(N-s|NloZ&M^2sxWWeH8k}y0$0M8pQjUgipz-mkrLCMj=_&6I u>5kt^TThVghf(*8hS_Ku_|H7l!r&X}WzTR$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#LR0vE6pV(z eXb6mkz-S1JhQMeDjE2By2#kinXb6m$5C8zfulSMx literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/3ef5cc982c0b45f69a26fd0f7d376415fdebabd1 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/3ef5cc982c0b45f69a26fd0f7d376415fdebabd1 new file mode 100644 index 0000000000000000000000000000000000000000..286949bc56a4fd135b6d645c2f6f6543fb54cefe GIT binary patch literal 220 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lje V6vNg2|Nox>jNu{-KM+h*762#p4;}yj literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/401c7de8e122018a0e17f57c93db7ee49ab0e906 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/401c7de8e122018a0e17f57c93db7ee49ab0e906 new file mode 100644 index 0000000000000000000000000000000000000000..8d5c7d136e51b0b71a574de271c1d076ad118ec7 GIT binary patch literal 865 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo?^*kifve@SoxTf5I56R*+_f z|6meio|Ah}F^Fa$$0=Zq5VQV+*$i;wAY7tICUjNA_-#0QI9=h@Pei(;l74iX(ESdQ2LPU}wmtv= literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/52fee71bb8c9c79068e1fe580677ad739a2d0415 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/52fee71bb8c9c79068e1fe580677ad739a2d0415 new file mode 100644 index 0000000000000000000000000000000000000000..f77ffec08653f23af6ec36d2bc3851d37a15a7ef GIT binary patch literal 361 qcmZ?rt>R$-gDM6Fh8!@9HUtx1V;S+vVoLI33Jq2fC*Ljs1_l7r3LC)|Ns9pP-+as zP$&1GVh9Td>3}KD1QP-|gBZ*J*8$b}p9TPGG;JwP+8RF~rV|r`!$r;TNr?lJRECqK s!zD?R<&WVMkyP}HH5JVw(kQZ`584D6x_XHW914^T>!_q4Tn4*V04VKEwg3PC literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/57dff0fa53ee0ef24a43cca6ab0523bfdc1f720d b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/57dff0fa53ee0ef24a43cca6ab0523bfdc1f720d new file mode 100644 index 0000000000000000000000000000000000000000..109ab7948ff737251655b35d801b7a147107da71 GIT binary patch literal 864 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= j#sB~RXCMWm>&ML}#nd6Gb_mDfkP2^7(&v8$P;v$UzN)0q literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5c42d3df0dc400a7a4175b8d4eec6cc8ee2437b2 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5c42d3df0dc400a7a4175b8d4eec6cc8ee2437b2 new file mode 100644 index 0000000000000000000000000000000000000000..bf9772902653f1b4bf258c4268937e18f9abbcf8 GIT binary patch literal 2246 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXBfq!VKABoM$-W4X#iAojD{QO;YQyuBfh%%Kga;H1K^ijs|@k SQMa9Ye}wsWwBJTy`T+ozM*H;u literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5d34bc9cef0c844b9c5ebe948145c4ca11b5ca09 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5d34bc9cef0c844b9c5ebe948145c4ca11b5ca09 new file mode 100644 index 0000000000000000000000000000000000000000..e5621aa3d1ba240abb65a521507762d520d1d4bf GIT binary patch literal 2639 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)H3=9lx zAo~Bn0g&~CFcZ3h|Ns9pjAC42@O?CFNX`N1DGVDQkqn_MIwnC}aZPt|x?6~rnE#;h z2iiSUx1Z7y9$GYF7^48LDHs?S7#TE(s41{z02+u9$U=$)UoEtTd?{O)G)##F__%X$-uyf;vSfL@g!LW2GrmHYk{c; JNizIr002{=H%$Nl literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5e162fe883bd12fb1c4131d4e0c979a12bd15eac b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5e162fe883bd12fb1c4131d4e0c979a12bd15eac new file mode 100644 index 0000000000000000000000000000000000000000..eea39d6b2f856ab8f1debf18d4d99543076a1b9a GIT binary patch literal 76 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVEgVBle3U=U{LVn9{{=YZ5GFbF6x000~| B2EhOT literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5e83f8faab9c1a51a33d5e29edbb9dcec23c6092 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/5e83f8faab9c1a51a33d5e29edbb9dcec23c6092 new file mode 100644 index 0000000000000000000000000000000000000000..fabcbdbe3d4b0e2b8f1de3bf0c7a388369d11547 GIT binary patch literal 1412 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= v#sB~RXBa`4sE`MR2YNUS5`Od`aR*^%fKoMKRfAT=|3RDx25q1XC5Hh3R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#LR0vE6pV%d zT|(d=5}=}m|Ni~^`}gnf-@kwU{P_b6e*XOV`}gm^fB*jb_m4u0{{H>@>({TZU%!6* z`0?%Ax39tA?c28>KYslB_3N)+zyALHOSTn%|Ni~)TM>1B074 zZ$5bN;N{DgA3uKl@#6=1RzM7Y|Ni}xCr_?lzkce}seSwQ?Er&)`}UnWb?W-{>rb9M zdH?=B8CLxJ_wU!QUmrhyeDdVUl`B^c95}FM&6?S>XHNiw*|TS_S+nNAfdf~rTzT^3 z$;Xc$fBpJJQe6D~`}gbDuPsOLO>G$v7A3uJ4@ZiCzQ>WIfS<}(ck(`|D?d@$32HxJ@$;rtb9UW`d ztT}b+)Pn~PK7Rc8`}c1mBl_RJe?NczeEat8&6_v(?b|nd_UyvKLT_(x0|NsEFfcGM z@b>mDEG(Qod-lG4`)=O6`S$JGpFe*R8ASj7{rmCb$LrUxuU)&gW5A^@R(22@cIA$KTYHJ|NsBAPM@^S zUl1?+`0;~AXjeW%te|QA0 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/65150515ab3b11d657519b22bb887d74e94b2d7f b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/65150515ab3b11d657519b22bb887d74e94b2d7f new file mode 100644 index 0000000000000000000000000000000000000000..567c645c00ee0e47ca2a840c7a115f68ae889e3d GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lje z6jP{{gF^kI+MyvZ4@!?xqaiR@LLfdqo?-6XxnK-p4;FU~ggZv_=Rkz|sGayi0F);O zB7fezd6VJ6g9i*C`r5T?3?K|*!^H5pnG!h#1qFsDPo6MbzkZ$J)TvVp`}XZ)*s)^= z7=zd#F_0Wc4M;5|c45;CGWW`rD+~t?9AH?pW(~va*|QlYOqc-1AT~%0BnMIhQj5(D za>YR53-TMt{H05mGIVrwFccORGNh%YfiZ{;5(CMB)PU52^pI;Gx;{|cg2ET%N02?q z$;k}f-rfxM_V!>5VuQp$av(JzwIDs{=8(e&rE`#9KyeHTXOLe(_L&))GJxV4gbfS~ z!0rLbfz*K1g7kp&l4B>b9#9?wrEySN1I0He%t8JJ*~`br#{j}0Hb@L42T}u43(^D9 zi)*isvp{Bo%mvI}G<$Zik@u|Z-WIglEVT96))UUKY2)&mMdP*{S(6co0g zFb0J`D9l0jf-r~;5(CMB)PU52^nmpGBO6908#^gaRr>cBJ; literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/656f38ef6dcd58c6a909d61db11f777def69c394 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/656f38ef6dcd58c6a909d61db11f777def69c394 new file mode 100644 index 0000000000000000000000000000000000000000..e1cdb4e5bf9d55e87b4495ab8db931f269e22d61 GIT binary patch literal 1406 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hgs~F? z4|VNhBWx!`1rvlqkpKVxXTZRJ{xg6@!E*aC<-y`$74(rqIF~s0W4e!#fq|VqZY3pH zKrSLhJwCPHL55L?LE7=zG05d`=1`0Tj+sC}UMCteLJ}lDwaum6Je;Y3XdnN9g#zV{ IAu_oD0K3URi2wiq literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/66e0d2cafd592bf9d61ad900fade8ee530d5f3d7 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/66e0d2cafd592bf9d61ad900fade8ee530d5f3d7 new file mode 100644 index 0000000000000000000000000000000000000000..73e53b460ec81a8accdf2b6601dfcd8679465b6a GIT binary patch literal 203 zcmZ?r?Gj)B11AOsh8hM21_dZ)WKdvW2FVC8FbH#l82GW1uR|3NL`f9`149nf7?5#{ U3=;nt{{JTdGmxMbVy;s>07X?zX8-^I literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/6b5b42cb105a2c4c5fd6034e9885cbe457f1b50c b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/6b5b42cb105a2c4c5fd6034e9885cbe457f1b50c new file mode 100644 index 0000000000000000000000000000000000000000..f29b9b217184c4cc8496f1f711caec0c7c632ca4 GIT binary patch literal 361 vcmZ?rt>R$-gDM6Fh8!@9HUtx1V;S+vVoLI33gHl8!68mJVJF`%0R{#D)hGiy literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/722ed0197cb92ecbf9745edb38275e7a9aaf322f b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/722ed0197cb92ecbf9745edb38275e7a9aaf322f new file mode 100644 index 0000000000000000000000000000000000000000..3b0c338ce203a0fd72936ae40120f140aae712b4 GIT binary patch literal 454 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRMU5OYkr-2y=s33=9m+u?!3hT?`BiHBe!2>-x_Cib4Qhx|fdt literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7899e22fc83f6be28e9130c4a1c91a48 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7899e22fc83f6be28e9130c4a1c91a48 new file mode 100644 index 0000000000000000000000000000000000000000..7e3b1990ad7c09a19fcef334aee9545a31d05380 GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXBfq!VKABoNJ|6%{{3S>#`Fk3kbQsu{$=?6`!~bSpFbIX{P+RJAT~%0BnMJM z3%7vG{`Kn@!`H8089sje$nf^(?1hojS#^Z{I$K z9Xob_F^CNk1IdBZfYgHYfb>%022fmr!V}~tkhxc`TwyqH-~hv#HES4V&z{XNVZsD3 z2C+e6AUTj4kXn!)kY11(_N3kqXUScAeGiY; z1xjO}v<9*d6y_idVuQp$av(JzwIDqpy&y9{W|4zIc?Xn-KzRw2r$BiNl*d5!fcy%I zZx9BtL1G{|kQ$I$kRFg;kQwCI4blS&H&7V@@&~9)0hKKv^Fe+Dg)=CvfiQ>-5(CMB z)PU52^nmn&%mA51E(Wh2_*Is0O zAag+Gf&2stS5Vx7(ibR?fiQ>-5(CMB)PU52^dOr-DH~)SC_F)N3bF%~wn6zDgh6bO z7)TDJ2Bel!`>^Q;#U;pWP?`qiE08}y7{msNf#g7Hu<50?7|0%EOl|W=%_FTnJQ`j@ GGQ0p83n_j8 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7dddccaebd16ae0c26daeffc42df50f529891119 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/7dddccaebd16ae0c26daeffc42df50f529891119 new file mode 100644 index 0000000000000000000000000000000000000000..0329a2826a89961de414d0e3c51a7c81ea02d8ef GIT binary patch literal 2249 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)H3=9lx zP#Tr`|Ns9VR1pRyG(N-s|NloZ&M^2sxWWeH8k}y0$0M8pQjUgipz-mkrLCMj=_&8e qpm99uZl`Tvj=E<7m^^Kge2UJ#*qmQ0?NR9|(PXPeno-R$-gDM6Fh8zY41_dZ)WH68bOEB;-FbH!)FarQ#>jKRH literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/81ff28ed63d5435ddc4c8771dd5d40aa658cbbe0 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/81ff28ed63d5435ddc4c8771dd5d40aa658cbbe0 new file mode 100644 index 0000000000000000000000000000000000000000..6390e6b2b30b9e4512b191b72f0bed8d4005c0cd GIT binary patch literal 2052 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvm@&!u~BACz>{Qv)-flMq$rap4*BS#-E1FHYf z1Ca_|aPpmkCtjFA0WJV`I+|0!VpOo7TIN900kw=9H3v22jfTf)c#NijA(#e01^8gW E0O*=DI{*Lx literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/820c8c0d33c18f6c4d9edd314e91289186931ad0 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/820c8c0d33c18f6c4d9edd314e91289186931ad0 new file mode 100644 index 0000000000000000000000000000000000000000..0084212a656bd4f97a2ba22f4d7ced7f8746946f GIT binary patch literal 1318 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)H3=9lx zP#Tr`|Ns9VR1pRyG(N-s|NlwBBq=7vU>d2tK_hdC3J21Hb|76kyzFKsDs~2upT7+v Qw@@|gNHz?VWnh5;07lzV5gei*#z10w6nBH2^dE~54V|b- zg4xQ@aIJ#U5ch%&_>RPecmOO6VPYzWir>ZqPUDdyQECH3Jw6wGgSrTxnxP|ChcmV{qZ28;it+<8qQx261MBqmpXoQq7=&aQtAf J^FIS92muIShqC|x literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/86bc3d5dbb9313137502080e58551edd2e649c70 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/86bc3d5dbb9313137502080e58551edd2e649c70 new file mode 100644 index 0000000000000000000000000000000000000000..a9ef2b5a50b36814ecaada8813a5f4b056f17ce8 GIT binary patch literal 929 zcmZ?r?Gj*MU|?ck=we`Cs9|7WP=I1a1_cIY1_lNO0R{$PZU%N?ZV(5K|1&T^5J<$y zJ*XH&GeC`FAZQ%ONU#nl0Ws@8ga+;Xb>BW|3ml;=;Cm` z6G#OF!^J>cLIFgCk04fqoq=pLP1raLMGqxpz7vCQ7dX(U;KF~%X5dd1$SRq^sS4Rq Nl(QKrH(~%y004$l0dN2S literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/87d94d88fe29d277c76e1a52042b02c092d5ae14 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/87d94d88fe29d277c76e1a52042b02c092d5ae14 new file mode 100644 index 0000000000000000000000000000000000000000..83de83f4eb59e2cfea819e1fdee97b3f6aec525c GIT binary patch literal 420 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH$I<>coVF)$c{1i<(|0|Nwscuwv? j#UPp#%!H=+Kg0k3^vA6D>?FlS5OYZI0#P9kGLHcOQzODN literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/8c4646f3357945c4e19a59ff79fffe3c874dbf16 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/8c4646f3357945c4e19a59ff79fffe3c874dbf16 new file mode 100644 index 0000000000000000000000000000000000000000..fa47e75a6323a989daa16e2a482a44f9ab2f2705 GIT binary patch literal 189 zcmZ?r?Gj)BgDwUJh8hM21_cOCsmx2v%}kCj$7 KjfELh%m4tnA|Rds literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/90632bc6dee4eb836f3d7db1d16446a9c8510080 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/90632bc6dee4eb836f3d7db1d16446a9c8510080 new file mode 100644 index 0000000000000000000000000000000000000000..e739e858b860e774e3cdf9142de13206f508d2ea GIT binary patch literal 3895 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXMkWR1>+7OdT_a%lYtQuphGAG;fY}2-Ar+0GBeQI6MqS~`91-8db^i2`>5!6 zDjG$|5Buq87a_Nxm$@)Lp2C=rk@S~`IhrbTe0)5^+_`hX7{sQEp&&z8K?DN>1B`}p zVbsl=HyIv0c)$RnuU)&w0KyhIhPZ+LWzs_*#)G3C2`}Q&H*s%kQ zL2Qs1NDib1q?X$DgUr2h_pj zK;aAW8_4{nOP4ZqbaXHj78Ww3rKN!}hz$}0$$`{>)PnR7WjGOvKyeESUyvU`_9Q1K zGkAM@GuYePgE5E=5(CMB)PU52^blb*K_#HH4e|>pjzQrJ@+-(bGeZ*wP&|XMfq?%d8jxC$9*|yw77$PX%44834oYjF_y&bJ$loA)`S|!4Kp4aZiGk!mYCvj1dO&&! z7*9|dWCqAAkeMK}L3V)b0@(?&8-zh@kQhh~qz0rGqz9yzpaldJfWi3zWw|_JI5f3U3ewu|Z-WIglEVT96*7(VS44A_`QdfXWt- z`5-@n!Wk6TAPi!I#6WT&H6XPVS%yV3D4s#)g8T*wUr-!_(isSY*dQ^G97qjFEfyoF ZA_NLoP~3uOP#One5E~{&6-$P#Apju*$>0D0 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/94d06016aa949e8e7203217e4cc6625ded7f4244 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/94d06016aa949e8e7203217e4cc6625ded7f4244 new file mode 100644 index 0000000000000000000000000000000000000000..c989a76df155ff09d69d2a765d6e097928b8344f GIT binary patch literal 3102 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXP_4zq28uf@Zz%vBaTPo0wYN9h2IF3qhsMfj}X59|3AZT>iCJM`~&h6dVxF2 t9}R)g5E#TEK-2aR3#dpKJQy_^{zJfDRMFwilfwZh^fx3di6YT#0suAS7!d#f literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9875819b9e5783e7489c29a81cc9d4279209956a b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9875819b9e5783e7489c29a81cc9d4279209956a new file mode 100644 index 0000000000000000000000000000000000000000..6ff64a7d2bab262cee2e8b6bebf65af9aafda630 GIT binary patch literal 22 XcmZ?r?Gj)BgDwUJh8hrylYs#MB7Oon literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9c1cc734114b29aac6c51782d5c17e9dbe1faca2 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9c1cc734114b29aac6c51782d5c17e9dbe1faca2 new file mode 100644 index 0000000000000000000000000000000000000000..2d1d8576a29b050160e63a142b48927db9540b8d GIT binary patch literal 3194 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B32=N)iKi7 nx>4IkLttcvz?q@oZJnXu$Wb?rhQMeDjE2By2#kin&R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#LR0vkmVkkQ zftJSqA2lC;@X|Vb@Y_BrI~oE6Lx9#vbkuzOQGiw*jB-aqU^E0qLtr!nMo0(%056#1 AQvd(} literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9f39e11cdd88344a4894b678e5a04a810880064d b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/9f39e11cdd88344a4894b678e5a04a810880064d new file mode 100644 index 0000000000000000000000000000000000000000..8f712aea9ff2d6e930f0269002f9e9d1a0caa016 GIT binary patch literal 972 zcmZ?r?Gj*MU|?ck=we`Cs9|7WP=I1a1_cIY1_lNO0R{$PZU|;zU|<9Zfi*xF{}~t{ z2*h=A4=M)Hq+lj=#sB~RXCMMQ;ZcM~3S>6AjWp!r_6yjH47lY9_yOdP!G!&(>t5=b UMo}o!Fm<3C4NeneI2K|K0OV@Q4gdfE literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a350588a6dabe4376a066aed44ef8786d8e752e7 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a350588a6dabe4376a066aed44ef8786d8e752e7 new file mode 100644 index 0000000000000000000000000000000000000000..b7ad89078b5fc1b96e811aa117cc11c7f4f0467b GIT binary patch literal 861 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)HL|~Bd zNJjtv{~xAF491`i{r^7$$Z%3I>6SYX*1||w$*2nQLx6}x3`)UB7C@3NH0dFwUN$5( NXiT*9geHrX3jm2YMWFxy literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a6101a79919d444e1fc50aefab5837c39e3f4a19 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a6101a79919d444e1fc50aefab5837c39e3f4a19 new file mode 100644 index 0000000000000000000000000000000000000000..173c941952bf798f796a9ef4c751d1e6e6e3a09c GIT binary patch literal 1237 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B32=N)iKi7 Tx>4IkLtxN`zyM}Zs#*;Imdpe4 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a9c8793f8fb063bec839ee1280406fe5396545e5 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/a9c8793f8fb063bec839ee1280406fe5396545e5 new file mode 100644 index 0000000000000000000000000000000000000000..644560ced96b56c960032d7df08b3730053bc3ea GIT binary patch literal 420 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+ljA j#s3-P|Nm$B55bJTAvBCXRA{L4iE%DbA^-n>Jp%&({h7bD literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ad4e9d2234e8599bdf12607c6b8cab4edae82c4e b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ad4e9d2234e8599bdf12607c6b8cab4edae82c4e new file mode 100644 index 0000000000000000000000000000000000000000..f1826b06e88c9ca21599abaee7481ae2f07ee840 GIT binary patch literal 420 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+ljA U#s3-p{~z+01TPR3@*wjV0QXD57ytkO literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/b90b6830917919e94186d312f06481bd b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/b90b6830917919e94186d312f06481bd new file mode 100644 index 0000000000000000000000000000000000000000..2da6be376f2af7b9cefc00d5b0d096c7e68fea69 GIT binary patch literal 3194 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B39w3y3r6A d4S~@R7!85Z5Eu=C(GVC7fzc2c4S``70sxg!1ML6+ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/b98fd4cb1d7031240414301c19b03097c0035c6b b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/b98fd4cb1d7031240414301c19b03097c0035c6b new file mode 100644 index 0000000000000000000000000000000000000000..b84b57bb53177764b84b10a75624dfe949ddbe81 GIT binary patch literal 857 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~uS=>LC)|Ns9p;5Nn< zX3qcj|Np=F^8df^H>e2^3SR$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B39w3y3r6A z4FRMOh>wq-3kLD=@kqi{VBWlW^TC4$H*em&1_p30Fllu3x|Y@{oF95`^` z%9Sfmo;)Gj@S8VpUcY|*z<~oxmoDw-=qM~KOap_$!orS@j-^YN9yoB|`t|EKZ{8%& ziU$uKoH})C&6+hG9UaNZ$==@H_F&-c?VX&Q+|kjoX3d&Yr%pY1@PG{S+oS%Y#{&ub--4f literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c6049874b33eadb016fccf0c5fa66e556ae069b9 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c6049874b33eadb016fccf0c5fa66e556ae069b9 new file mode 100644 index 0000000000000000000000000000000000000000..4863878ca02ca42e550f521cb1ba5b8bd7046ecc GIT binary patch literal 3194 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B32=N)iKi7 zy5V9Q$8hlo?ffxF6FluaJZkc22#kina18-ay8!Gr4KO)MjD`T2A;3qbzEN$%DFgsk Cq6AI= literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c8697bf2369f6ab85f501376c4d93bb8a56974a3 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c8697bf2369f6ab85f501376c4d93bb8a56974a3 new file mode 100644 index 0000000000000000000000000000000000000000..30aacc2f98820e139b1495c9c1527f9119dec97b GIT binary patch literal 420 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=QG0VEF%^ e;XmaVWbA*^&B13inMP8@JGk6MRLFyZfdK%8dhO`| literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c8daf283e0aef2fd7b630c0430e05dc28f24ecf6 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/c8daf283e0aef2fd7b630c0430e05dc28f24ecf6 new file mode 100644 index 0000000000000000000000000000000000000000..b831633f02b50870db441110db29e03331decdaf GIT binary patch literal 220 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvWW?&$wfPq1nn}LBr078S=VDrGle+C8!0`Z*O dgNhj#-h-G(7$W~4A_7qYX0w4wA_yj2Y5?yJ4;}yj literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/cacff56e1af4b8fde912822da06b10fb8c545a19 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/cacff56e1af4b8fde912822da06b10fb8c545a19 new file mode 100644 index 0000000000000000000000000000000000000000..ff492d29d76ce94f0fb8db9a0b6c481c407b205b GIT binary patch literal 1033 zcmZ?r?Gj*MU|?ck=we`Cs9|7WP=I1a1_cIY1_lNO0R{$PZU}brt>OU*F)&myFfimm zRf2RdGDtuqcpxf4Iv@fJ3{LJr#V|IpG!wB3QPllsV1OWyC?RYAGyMNg7A8v*5tcFj zXJC{jLLIH_r>D862mv)53LuVzCR+yLk}W7TKrtkF{D<%er4WcJR1za$l9PyN5Xq>n MB*=q?0Nf!A01)5EJOBUy literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ce4dcc22b1d595c49a25121c0b580104 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ce4dcc22b1d595c49a25121c0b580104 new file mode 100644 index 0000000000000000000000000000000000000000..ea776fb0a94b79362822f76bfa1f0d9364a09c4a GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lje z6pyMM4S~@R7!3hzArK!Q&oFoHTrdW)v8kbj*v*?a86G@%zyPAJUAx8r!XP$Gj23o+ z%v4ZNV0iN63B&d4*BMToI>oSW-#&&NJ9dCEhz$}0$$`{>)PnR-6NAjXa^(ucfddB^ z)~s2>FnjiFh6xiUfH8;-5(CMB)PU4d({51sg8T+Df9cYt3>_UE426Y-3~6a;U<_h| z#6WT&H6XPhJ=AgoC~iUF3-Tk#p5)|Y25)a~277yZFb1(fVjww?8jxC$9%|SRO4}g6 zfZ`Yw&LF>n>@zShU;xE42!q%lF_0Wc4M;6W4@fViZUE&mP#OoNHBfwm!W`spkiC3- zd<-BAVuQp$av(JzwIDqpy+hr8P#A*35)`JOumy!ND6BzY4)Qk$gV-Q3kQ_)2NG(VY zNH3-S2k8f;B~Y3Ir7chz1En>PeV{N0VGtW629g7*0jUM)0qLa%2Kfb)r$BiNl*d5! zfcy%IZx9BtL1G{|kQ$I$kREE-4Ko8&rhv*8koh1#g2EY;)<77<28n^>Kx#m0Vfv^= zgW?%vF34}7@CC&&D4l~ahz$}0$$`{>)Kbe{baO!A3W{404a#F63}VB?(ACq54@%ph W{0+h&Hm&R#HFq=wMnhoOh5!H`xLMo) literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d0cd71dbf039fd64cf42eff30da92a71a919226a b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d0cd71dbf039fd64cf42eff30da92a71a919226a new file mode 100644 index 0000000000000000000000000000000000000000..b9dc5d0f4ee4edb8d45ae3e5ed182f57e5d4e5db GIT binary patch literal 587 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Am|Nk@m$ATHyAku_MCb$wP z3!8D&7E{LJWHdV%A?}J`KnodEWzaAJg%$pAV))MhMlg%9h8n8b*h7}OYQ7V4$3I;5 Np#=*#ApV0r2>^j|C42w? literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d5ce626ac3264bed6af5580e341a89406857cbb9 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d5ce626ac3264bed6af5580e341a89406857cbb9 new file mode 100644 index 0000000000000000000000000000000000000000..b17294ec90a31bc77f439f7baae0d897bf860ec4 GIT binary patch literal 1760 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B32=N)iKi7 vx>4I;AuveO1I&4&^k@iR3jsE4f}>(&g#c#dgUy&9{~-XI983&XrNsaMI1~R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#!mE%Guk4VP Lbn@*IU|;|MCshR( literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d7eb9c5a0f9803df4c00390793b8ab57bd7c9484 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/d7eb9c5a0f9803df4c00390793b8ab57bd7c9484 new file mode 100644 index 0000000000000000000000000000000000000000..531427a99c0f1bbef21f35fa90027a7d662b39ec GIT binary patch literal 3792 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)H+#rHT z%!ID)|Ns9C2>kCmf{iRbY}iDFJSYs%!)XZdL1~GUbVPyIU`Y_45yK|!AmtPK`sq7L z9>rldz9=A0PKP*ULrfJ>IiBdUc8GZ%&AHG@2TgRib6JPG2S@$KI~oKu41p)40~)%9 S=0*?CdXVP9Hfq6$4FLd&N(T-A literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/dc1efccdeec17e151a1ec8228c09ab61c3040b33 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/dc1efccdeec17e151a1ec8228c09ab61c3040b33 new file mode 100644 index 0000000000000000000000000000000000000000..5a5c1c30eb0d70bea1562137328ac2d74871e43d GIT binary patch literal 35 jcmZ?rt>R$-gDM6Fh8zY41_K5L1_e0=21W)6us8z%KuiLI literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/dcea22c66c60088165a2f1772036473f b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/dcea22c66c60088165a2f1772036473f new file mode 100644 index 0000000000000000000000000000000000000000..44d2ebfb3d0f37c6355fe4e44c27f7457ebee63c GIT binary patch literal 4234 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+lj= z#sB~RXBa39a?3#34YGICeue>y`@s@pA(|D$*`1V%$( RGz3ONU^E0qLtsRO003l9=92&b literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/de539ae7442fa05dafcfe1a021f0186ef74a2b0e b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/de539ae7442fa05dafcfe1a021f0186ef74a2b0e new file mode 100644 index 0000000000000000000000000000000000000000..f9a8f33443d84d5494b23e5b3317015f10b0496a GIT binary patch literal 103 zcmZ?r?Gj)BgDwUJwHgKn1_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~weGcf#z@SNO(ia{(C J(?9|+3;@+b2*dyY literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e2306b1d6b88d0ccc4e2c3a9edb07462a5a32215 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e2306b1d6b88d0ccc4e2c3a9edb07462a5a32215 new file mode 100644 index 0000000000000000000000000000000000000000..71bf61cebe4e69dc71714916d804d979824a7d0b GIT binary patch literal 110 zcmZ?r?c!wsgDwUJh8hM21_dZ)WKdvWW?*2@6<}Zx=7wOfLJ0AnfdPU*TqpOSVi1iF JJ2Cin0RZon2yOrX literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e2778da0240fdd15ef5844905d81c4e05f34a8bd b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e2778da0240fdd15ef5844905d81c4e05f34a8bd new file mode 100644 index 0000000000000000000000000000000000000000..1bad15905ffd4776122e34df11873b390abee72a GIT binary patch literal 3194 zcmZ?rt>R$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B32=N)iKi7 zx>4IkLtyxaz*j6@JcC7S&aW) F1pwWl2DbnJ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e6642e9266875f9d908942e534bf898103a2c794 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/e6642e9266875f9d908942e534bf898103a2c794 new file mode 100644 index 0000000000000000000000000000000000000000..f9d9de9c9c21f18a6eb88afb89f4450d4fd6771f GIT binary patch literal 2186 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)HxbZg( zDJFE0|Ns9p{Qv)(0YZb=Lmh*>0`?S$F^a)KK~|iSrHO(72WbVn7Q`6E;Gm#)98hN8 heiGfxz%W`u4Yq_n=qrLM%ryEPBi#+QP#vu90RU(y=d1t# literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ec6cdb929c08d8daf2bd7fc185fbf4d787b45120 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ec6cdb929c08d8daf2bd7fc185fbf4d787b45120 new file mode 100644 index 0000000000000000000000000000000000000000..782a0925210623c0d6e33ba7c885435bb19654d3 GIT binary patch literal 1942 zcmZ?r?Gj*MU|?ck=we`Cs9|7WP=I1a1_cIY1_lNO0R{$PZU}brt>OU*F)&myFfimm zRf2RdGDtuqcpxf4Iv@fJ3{LJr#V|Gl1H=FS+W-ImXBc>V`SNA*oPp$-0cG+IsO@yI z{Qox^S@Q%ppplKF89VUVgS@r85lqaT2xSK48&lxq6i`gvIfdx jaDXvJ>A@2M<)k_Vnr1N4B8B251oY!}CKI|8ey0Hd2er#3 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ed8636357f79439b6a03eb14469b686cc401a1c9 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ed8636357f79439b6a03eb14469b686cc401a1c9 new file mode 100644 index 0000000000000000000000000000000000000000..efd9312d94dde30707099125b0280be21f6b2101 GIT binary patch literal 3895 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+An=KKu*8K4NncXAIZ2GOKo zCUnLB|Nm!zU?>IS4k3Ezx*Q((LnyRq>}HB1lbM0uf%%t!o9`2lC)vHWkQ__0KC;|F zmL}{Dq@q!T{Jx)#b`f$5dYKF58( x#a>nq@o=ufbpQ9!a2!;%3&rW~H)b3YYbM13F#=kdm?bvxB8(8F>=24dBmi&wrSbp( literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ee313e9acecb5c688ce8c9bb10e70e136fbb9c6d b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ee313e9acecb5c688ce8c9bb10e70e136fbb9c6d new file mode 100644 index 0000000000000000000000000000000000000000..03e09e28193a513347433ee41f005f0926329d20 GIT binary patch literal 3616 zcmZ?r?Gj)RU|?Wi=we`Cs9|7WPyl1FI7k>xoPmLnL4ko8BqPAUAj}QHATAXDXJCLJ z5Z}o?s2D_(f|<}2|NsA=0f9@&1;~a_gFWCOK@Cq3VFpsz<5$hVz`%hXccXktLI9jE zDKP-5mkmnOmqO%OXu2WO`UW!f;nLQKOM)cvFp^Z0qj=C3!O-YLDVB$x7&%cwgdV&_ z;9$>)g#!VI2vjO6!It|mN-FG08@nhm^&|N@i7|at&1m?JrUAO80Z>p6z3L9Vj6*9@ O!O~!{|6meCfLH*NS(IV` literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ef689af320e7d9e22231109faae2e8149cb86e1c b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ef689af320e7d9e22231109faae2e8149cb86e1c new file mode 100644 index 0000000000000000000000000000000000000000..f8688710452dafe40fb247674471ea9f642b3778 GIT binary patch literal 834 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo+Aq{}~t{2*h`C4=M)Hq+ljw z#UP9R|NqZG3P#qCpG}IXAhq~SLzV@p9-26~G>Mq-9wg}l6z0?oX9_%qR$-gDM6Fh8zY41_dZ)WRL)hGw?7l2y;U)M1X<8$vvnT#wM0#B32=N)iKi7 lx}j{F3auRfgH{GN(8^%?o2y2ul`Pmb$Y2+yrl=zx!vHe$1`z-N literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ffe829bb0adac20d9c0756f68a22d1255e4fdb54 b/tensorflow/core/kernels/fuzzing/corpus/decode_bmp/ffe829bb0adac20d9c0756f68a22d1255e4fdb54 new file mode 100644 index 0000000000000000000000000000000000000000..e24c09dacce1b52dc3737b1d921920846b627b2f GIT binary patch literal 3194 zcmZ?r?Gj)BgDwUJh8hM21_dZ)WKdvW2FVC8FbH!)Fo=t(10)L71Z55`3hH7e1_qEH z(cA{|G6NHuAjALv|4G8=`f>9~H5s3J+_sF$&?E$qvH=4_0s{jBaj66?2SK!gG&B4M zlOVS`xd#=4Xa;C%Wq_nsQ1T>{Bf;9h24OJ{DoG4QaW24@R Date: Thu, 29 Nov 2018 11:59:37 -0800 Subject: [PATCH 559/672] Ensure run_deprecated_v1 only works when tf2 is enabled PiperOrigin-RevId: 223385893 --- tensorflow/python/framework/test_util.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index fc97a2275c..155e45d16c 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -50,6 +50,7 @@ from tensorflow.core.framework import graph_pb2 from tensorflow.core.protobuf import config_pb2 from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python import pywrap_tensorflow +from tensorflow.python import tf2 from tensorflow.python.client import device_lib from tensorflow.python.client import session from tensorflow.python.eager import context @@ -1026,7 +1027,10 @@ def run_deprecated_v1(func=None): raise ValueError("`run_deprecated_v1` only supports test methods.") def decorated(self, *args, **kwargs): - with context.graph_mode(): + if tf2.enabled(): + with context.graph_mode(): + f(self, *args, **kwargs) + else: f(self, *args, **kwargs) return decorated -- GitLab From ed1683498b553b69b2246ac2ed614253be10869b Mon Sep 17 00:00:00 2001 From: Yu-Cheng Ling Date: Thu, 29 Nov 2018 12:02:06 -0800 Subject: [PATCH 560/672] Fix the broken TFLite makefile PiperOrigin-RevId: 223386342 --- tensorflow/lite/tools/make/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tensorflow/lite/tools/make/Makefile b/tensorflow/lite/tools/make/Makefile index 06a1f36105..363a069d5e 100644 --- a/tensorflow/lite/tools/make/Makefile +++ b/tensorflow/lite/tools/make/Makefile @@ -114,6 +114,10 @@ ifeq ($(BUILD_TYPE),micro) CORE_CC_EXCLUDE_SRCS += \ tensorflow/lite/mmap_allocation.cc \ tensorflow/lite/nnapi_delegate.cc +else +CORE_CC_EXCLUDE_SRCS += \ +tensorflow/contrib/lite/mmap_allocation_disabled.cc \ +tensorflow/contrib/lite/nnapi_delegate_disabled.cc endif # Filter out all the excluded files. TF_LITE_CC_SRCS := $(filter-out $(CORE_CC_EXCLUDE_SRCS), $(CORE_CC_ALL_SRCS)) -- GitLab From 20179793c2c96bbcbbaaf400b247e35aa81d9deb Mon Sep 17 00:00:00 2001 From: Rohan Jain Date: Thu, 29 Nov 2018 12:11:14 -0800 Subject: [PATCH 561/672] Applying kernel priorities to datasets that have both CPU and GPU implementations. This makes sure that placer would prefer the CPU kernel over the GPU kernel if no with tf.device(..) is specified. This is necessary for creating dataset kernels as we go (i.e. in the __init__ methods of the Dataset class). PiperOrigin-RevId: 223388100 --- .../core/kernels/data/generator_dataset_op.cc | 10 ++-- tensorflow/core/kernels/data/iterator_ops.cc | 58 +++++++++++-------- tensorflow/core/kernels/data/optional_ops.cc | 28 +++++---- .../core/kernels/data/prefetch_dataset_op.cc | 5 +- 4 files changed, 59 insertions(+), 42 deletions(-) diff --git a/tensorflow/core/kernels/data/generator_dataset_op.cc b/tensorflow/core/kernels/data/generator_dataset_op.cc index c089bfc45f..48697ec6c8 100644 --- a/tensorflow/core/kernels/data/generator_dataset_op.cc +++ b/tensorflow/core/kernels/data/generator_dataset_op.cc @@ -182,11 +182,13 @@ void GeneratorDatasetOp::MakeDataset(OpKernelContext* ctx, } namespace { -REGISTER_KERNEL_BUILDER(Name("GeneratorDataset").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("GeneratorDataset").Device(DEVICE_CPU).Priority(2), + GeneratorDatasetOp); +REGISTER_KERNEL_BUILDER(Name("GeneratorDataset") + .Device(DEVICE_GPU) + .HostMemory("handle") + .Priority(1), GeneratorDatasetOp); -REGISTER_KERNEL_BUILDER( - Name("GeneratorDataset").Device(DEVICE_GPU).HostMemory("handle"), - GeneratorDatasetOp); } // namespace } // namespace data diff --git a/tensorflow/core/kernels/data/iterator_ops.cc b/tensorflow/core/kernels/data/iterator_ops.cc index c50af846f9..cb7477f9e2 100644 --- a/tensorflow/core/kernels/data/iterator_ops.cc +++ b/tensorflow/core/kernels/data/iterator_ops.cc @@ -1272,50 +1272,60 @@ class DeserializeIteratorOp : public OpKernel { REGISTER_KERNEL_BUILDER(Name("Iterator").Device(DEVICE_CPU), IteratorHandleOp); -REGISTER_KERNEL_BUILDER(Name("IteratorV2").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("IteratorV2").Device(DEVICE_CPU).Priority(2), IteratorHandleOp); -REGISTER_KERNEL_BUILDER(Name("IteratorV2").Device(DEVICE_GPU), +REGISTER_KERNEL_BUILDER(Name("IteratorV2").Device(DEVICE_GPU).Priority(1), IteratorHandleOp); -REGISTER_KERNEL_BUILDER(Name("MakeIterator").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("MakeIterator").Device(DEVICE_CPU).Priority(2), MakeIteratorOp); REGISTER_KERNEL_BUILDER( - Name("MakeIterator").Device(DEVICE_GPU).HostMemory("dataset"), + Name("MakeIterator").Device(DEVICE_GPU).Priority(1).HostMemory("dataset"), MakeIteratorOp); -REGISTER_KERNEL_BUILDER(Name("AnonymousIterator").Device(DEVICE_CPU), - AnonymousIteratorHandleOp); -REGISTER_KERNEL_BUILDER(Name("AnonymousIterator").Device(DEVICE_GPU), - AnonymousIteratorHandleOp); +REGISTER_KERNEL_BUILDER( + Name("AnonymousIterator").Device(DEVICE_CPU).Priority(2), + AnonymousIteratorHandleOp); +REGISTER_KERNEL_BUILDER( + Name("AnonymousIterator").Device(DEVICE_GPU).Priority(1), + AnonymousIteratorHandleOp); REGISTER_KERNEL_BUILDER(Name("DatasetToSingleElement").Device(DEVICE_CPU), ToSingleElementOp); REGISTER_KERNEL_BUILDER(Name("ReduceDataset").Device(DEVICE_CPU), ReduceDatasetOp); REGISTER_KERNEL_BUILDER(Name("OneShotIterator").Device(DEVICE_CPU), OneShotIteratorOp); -REGISTER_KERNEL_BUILDER(Name("IteratorGetNext").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("IteratorGetNext").Device(DEVICE_CPU).Priority(2), IteratorGetNextOp); -REGISTER_KERNEL_BUILDER(Name("IteratorGetNext").Device(DEVICE_GPU), +REGISTER_KERNEL_BUILDER(Name("IteratorGetNext").Device(DEVICE_GPU).Priority(1), IteratorGetNextOp); -REGISTER_KERNEL_BUILDER(Name("IteratorGetNextSync").Device(DEVICE_CPU), - IteratorGetNextSyncOp); -REGISTER_KERNEL_BUILDER(Name("IteratorGetNextSync").Device(DEVICE_GPU), - IteratorGetNextSyncOp); -REGISTER_KERNEL_BUILDER(Name("IteratorGetNextAsOptional").Device(DEVICE_CPU), - IteratorGetNextAsOptionalOp); -REGISTER_KERNEL_BUILDER(Name("IteratorGetNextAsOptional").Device(DEVICE_GPU), - IteratorGetNextAsOptionalOp); -REGISTER_KERNEL_BUILDER(Name("IteratorToStringHandle").Device(DEVICE_CPU), - IteratorToStringHandleOp); +REGISTER_KERNEL_BUILDER( + Name("IteratorGetNextSync").Device(DEVICE_CPU).Priority(2), + IteratorGetNextSyncOp); +REGISTER_KERNEL_BUILDER( + Name("IteratorGetNextSync").Device(DEVICE_GPU).Priority(1), + IteratorGetNextSyncOp); +REGISTER_KERNEL_BUILDER( + Name("IteratorGetNextAsOptional").Device(DEVICE_CPU).Priority(2), + IteratorGetNextAsOptionalOp); +REGISTER_KERNEL_BUILDER( + Name("IteratorGetNextAsOptional").Device(DEVICE_GPU).Priority(1), + IteratorGetNextAsOptionalOp); +REGISTER_KERNEL_BUILDER( + Name("IteratorToStringHandle").Device(DEVICE_CPU).Priority(2), + IteratorToStringHandleOp); REGISTER_KERNEL_BUILDER(Name("IteratorToStringHandle") .Device(DEVICE_GPU) - .HostMemory("string_handle"), + .HostMemory("string_handle") + .Priority(1), IteratorToStringHandleOp); REGISTER_KERNEL_BUILDER(Name("IteratorFromStringHandle").Device(DEVICE_CPU), IteratorFromStringHandleOp); -REGISTER_KERNEL_BUILDER(Name("IteratorFromStringHandleV2").Device(DEVICE_CPU), - IteratorFromStringHandleOp); +REGISTER_KERNEL_BUILDER( + Name("IteratorFromStringHandleV2").Device(DEVICE_CPU).Priority(2), + IteratorFromStringHandleOp); REGISTER_KERNEL_BUILDER(Name("IteratorFromStringHandleV2") .Device(DEVICE_GPU) - .HostMemory("string_handle"), + .HostMemory("string_handle") + .Priority(1), IteratorFromStringHandleOp); REGISTER_KERNEL_BUILDER(Name("SerializeIterator").Device(DEVICE_CPU), SerializeIteratorOp); diff --git a/tensorflow/core/kernels/data/optional_ops.cc b/tensorflow/core/kernels/data/optional_ops.cc index bee857f53c..d8a7f21c5f 100644 --- a/tensorflow/core/kernels/data/optional_ops.cc +++ b/tensorflow/core/kernels/data/optional_ops.cc @@ -127,23 +127,27 @@ class OptionalGetValueOp : public OpKernel { std::vector output_shapes_; }; -REGISTER_KERNEL_BUILDER(Name("OptionalNone").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("OptionalNone").Device(DEVICE_CPU).Priority(2), OptionalNoneOp); -REGISTER_KERNEL_BUILDER(Name("OptionalNone").Device(DEVICE_GPU), +REGISTER_KERNEL_BUILDER(Name("OptionalNone").Device(DEVICE_GPU).Priority(1), OptionalNoneOp); -REGISTER_KERNEL_BUILDER(Name("OptionalFromValue").Device(DEVICE_CPU), - OptionalFromValueOp); -REGISTER_KERNEL_BUILDER(Name("OptionalFromValue").Device(DEVICE_GPU), - OptionalFromValueOp); +REGISTER_KERNEL_BUILDER( + Name("OptionalFromValue").Device(DEVICE_CPU).Priority(2), + OptionalFromValueOp); +REGISTER_KERNEL_BUILDER( + Name("OptionalFromValue").Device(DEVICE_GPU).Priority(1), + OptionalFromValueOp); -REGISTER_KERNEL_BUILDER(Name("OptionalHasValue").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("OptionalHasValue").Device(DEVICE_CPU).Priority(2), OptionalHasValueOp); -REGISTER_KERNEL_BUILDER( - Name("OptionalHasValue").Device(DEVICE_GPU).HostMemory("has_value"), - OptionalHasValueOp); -REGISTER_KERNEL_BUILDER(Name("OptionalGetValue").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("OptionalHasValue") + .Device(DEVICE_GPU) + .HostMemory("has_value") + .Priority(1), + OptionalHasValueOp); +REGISTER_KERNEL_BUILDER(Name("OptionalGetValue").Device(DEVICE_CPU).Priority(2), OptionalGetValueOp); -REGISTER_KERNEL_BUILDER(Name("OptionalGetValue").Device(DEVICE_GPU), +REGISTER_KERNEL_BUILDER(Name("OptionalGetValue").Device(DEVICE_GPU).Priority(1), OptionalGetValueOp); static Status OptionalDeviceCopy( diff --git a/tensorflow/core/kernels/data/prefetch_dataset_op.cc b/tensorflow/core/kernels/data/prefetch_dataset_op.cc index 960373b74f..9e518131eb 100644 --- a/tensorflow/core/kernels/data/prefetch_dataset_op.cc +++ b/tensorflow/core/kernels/data/prefetch_dataset_op.cc @@ -391,13 +391,14 @@ void PrefetchDatasetOp::MakeDataset(OpKernelContext* ctx, DatasetBase* input, } namespace { -REGISTER_KERNEL_BUILDER(Name("PrefetchDataset").Device(DEVICE_CPU), +REGISTER_KERNEL_BUILDER(Name("PrefetchDataset").Device(DEVICE_CPU).Priority(2), PrefetchDatasetOp); REGISTER_KERNEL_BUILDER(Name("PrefetchDataset") .Device(DEVICE_GPU) .HostMemory("buffer_size") .HostMemory("input_dataset") - .HostMemory("handle"), + .HostMemory("handle") + .Priority(1), PrefetchDatasetOp); } // namespace -- GitLab From 74230d7295e25b0ff9d4f78aa2dc02281a487fad Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Thu, 29 Nov 2018 12:20:59 -0800 Subject: [PATCH 562/672] Update distribution strategy library `get_loss_reduction()` function to check for V2 Loss Reduction Enum. PiperOrigin-RevId: 223389700 --- .../python/distribute/distribute_lib.py | 3 +- tensorflow/python/keras/losses.py | 5 ++- tensorflow/python/keras/losses_test.py | 25 ++++++------ tensorflow/python/keras/utils/losses_utils.py | 38 ++++--------------- tensorflow/python/ops/losses/losses_impl.py | 24 ++++++++++++ .../tensorflow.keras.losses.-reduction.pbtxt | 4 +- .../v2/tensorflow.losses.-reduction.pbtxt | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 6 +++ 8 files changed, 59 insertions(+), 50 deletions(-) diff --git a/tensorflow/python/distribute/distribute_lib.py b/tensorflow/python/distribute/distribute_lib.py index 2213499be0..eddd6ff8b1 100644 --- a/tensorflow/python/distribute/distribute_lib.py +++ b/tensorflow/python/distribute/distribute_lib.py @@ -81,7 +81,8 @@ class UpdateContext(object): def get_loss_reduction(): """`tf.distribute.ReduceOp` corresponding to the last loss reduction.""" loss_reduction = ops.get_default_graph()._last_loss_reduction # pylint: disable=protected-access - if loss_reduction == losses_impl.Reduction.SUM: + if (loss_reduction == losses_impl.Reduction.SUM or + loss_reduction == losses_impl.ReductionV2.SUM): return reduce_util.ReduceOp.SUM return reduce_util.ReduceOp.MEAN diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index 1bd9f729c5..83318d6c57 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -28,7 +28,6 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object from tensorflow.python.keras.utils.losses_utils import compute_weighted_loss -from tensorflow.python.keras.utils.losses_utils import ReductionV2 from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn from tensorflow.python.ops.losses import losses_impl @@ -56,7 +55,9 @@ class Loss(object): name: Optional name for the op. """ - def __init__(self, reduction=ReductionV2.SUM_OVER_BATCH_SIZE, name=None): + def __init__(self, + reduction=losses_impl.ReductionV2.SUM_OVER_BATCH_SIZE, + name=None): self.reduction = reduction self.name = name diff --git a/tensorflow/python/keras/losses_test.py b/tensorflow/python/keras/losses_test.py index d80b272b12..b5e9a24c99 100644 --- a/tensorflow/python/keras/losses_test.py +++ b/tensorflow/python/keras/losses_test.py @@ -27,6 +27,7 @@ from tensorflow.python import keras from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import test_util +from tensorflow.python.ops.losses import losses_impl from tensorflow.python.platform import test try: @@ -146,9 +147,9 @@ class MeanSquaredErrorTest(test.TestCase): def test_config(self): mse_obj = keras.losses.MeanSquaredError( - reduction=keras.losses.ReductionV2.SUM, name='mse_1') + reduction=losses_impl.ReductionV2.SUM, name='mse_1') self.assertEqual(mse_obj.name, 'mse_1') - self.assertEqual(mse_obj.reduction, keras.losses.ReductionV2.SUM) + self.assertEqual(mse_obj.reduction, losses_impl.ReductionV2.SUM) def test_all_correct_unweighted(self): mse_obj = keras.losses.MeanSquaredError() @@ -214,7 +215,7 @@ class MeanSquaredErrorTest(test.TestCase): def test_no_reduction(self): mse_obj = keras.losses.MeanSquaredError( - reduction=keras.losses.ReductionV2.NONE) + reduction=losses_impl.ReductionV2.NONE) y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3), @@ -225,7 +226,7 @@ class MeanSquaredErrorTest(test.TestCase): def test_sum_reduction(self): mse_obj = keras.losses.MeanSquaredError( - reduction=keras.losses.ReductionV2.SUM) + reduction=losses_impl.ReductionV2.SUM) y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3), @@ -239,9 +240,9 @@ class MeanAbsoluteErrorTest(test.TestCase): def test_config(self): mae_obj = keras.losses.MeanAbsoluteError( - reduction=keras.losses.ReductionV2.SUM, name='mae_1') + reduction=losses_impl.ReductionV2.SUM, name='mae_1') self.assertEqual(mae_obj.name, 'mae_1') - self.assertEqual(mae_obj.reduction, keras.losses.ReductionV2.SUM) + self.assertEqual(mae_obj.reduction, losses_impl.ReductionV2.SUM) def test_all_correct_unweighted(self): mae_obj = keras.losses.MeanAbsoluteError() @@ -307,7 +308,7 @@ class MeanAbsoluteErrorTest(test.TestCase): def test_no_reduction(self): mae_obj = keras.losses.MeanAbsoluteError( - reduction=keras.losses.ReductionV2.NONE) + reduction=losses_impl.ReductionV2.NONE) y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3), @@ -318,7 +319,7 @@ class MeanAbsoluteErrorTest(test.TestCase): def test_sum_reduction(self): mae_obj = keras.losses.MeanAbsoluteError( - reduction=keras.losses.ReductionV2.SUM) + reduction=losses_impl.ReductionV2.SUM) y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3), @@ -332,9 +333,9 @@ class MeanAbsolutePercentageErrorTest(test.TestCase): def test_config(self): mape_obj = keras.losses.MeanAbsolutePercentageError( - reduction=keras.losses.ReductionV2.SUM, name='mape_1') + reduction=losses_impl.ReductionV2.SUM, name='mape_1') self.assertEqual(mape_obj.name, 'mape_1') - self.assertEqual(mape_obj.reduction, keras.losses.ReductionV2.SUM) + self.assertEqual(mape_obj.reduction, losses_impl.ReductionV2.SUM) def test_unweighted(self): mape_obj = keras.losses.MeanAbsolutePercentageError() @@ -389,9 +390,9 @@ class MeanSquaredLogarithmicErrorTest(test.TestCase): def test_config(self): msle_obj = keras.losses.MeanSquaredLogarithmicError( - reduction=keras.losses.ReductionV2.SUM, name='mape_1') + reduction=losses_impl.ReductionV2.SUM, name='mape_1') self.assertEqual(msle_obj.name, 'mape_1') - self.assertEqual(msle_obj.reduction, keras.losses.ReductionV2.SUM) + self.assertEqual(msle_obj.reduction, losses_impl.ReductionV2.SUM) def test_unweighted(self): msle_obj = keras.losses.MeanSquaredLogarithmicError() diff --git a/tensorflow/python/keras/utils/losses_utils.py b/tensorflow/python/keras/utils/losses_utils.py index d11d785356..fc4b4ac7df 100644 --- a/tensorflow/python/keras/utils/losses_utils.py +++ b/tensorflow/python/keras/utils/losses_utils.py @@ -25,31 +25,7 @@ from tensorflow.python.ops import confusion_matrix from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import weights_broadcast_ops -from tensorflow.python.util.tf_export import tf_export - - -@tf_export('losses.Reduction', 'keras.losses.Reduction', v1=[]) -class ReductionV2(object): - """Types of loss reduction. - - Contains the following values: - `NONE`: Un-reduced weighted losses with the same shape as input. - `SUM`: Scalar sum of weighted losses. - `SUM_OVER_BATCH_SIZE`: Scalar `SUM` divided by number of elements in losses. - """ - - NONE = None - SUM = 'sum' - SUM_OVER_BATCH_SIZE = 'sum_over_batch_size' - - @classmethod - def all(cls): - return (cls.NONE, cls.SUM, cls.SUM_OVER_BATCH_SIZE) - - @classmethod - def validate(cls, key): - if key not in cls.all(): - raise ValueError('Invalid Reduction Key %s.' % key) +from tensorflow.python.ops.losses import losses_impl def squeeze_or_expand_dimensions(y_pred, y_true, sample_weight): @@ -144,21 +120,21 @@ def _num_elements(losses): return math_ops.cast(array_ops.size(losses, name=scope), dtype=losses.dtype) -def _reduce_weighted_loss(weighted_losses, - reduction=ReductionV2.SUM_OVER_BATCH_SIZE): +def _reduce_weighted_loss( + weighted_losses, reduction=losses_impl.ReductionV2.SUM_OVER_BATCH_SIZE): """Reduces the individual weighted loss measurements.""" - if reduction == ReductionV2.NONE: + if reduction == losses_impl.ReductionV2.NONE: loss = weighted_losses else: loss = math_ops.reduce_sum(weighted_losses) - if reduction == ReductionV2.SUM_OVER_BATCH_SIZE: + if reduction == losses_impl.ReductionV2.SUM_OVER_BATCH_SIZE: loss = _safe_mean(loss, _num_elements(weighted_losses)) return loss def compute_weighted_loss(losses, sample_weight=None, - reduction=ReductionV2.SUM_OVER_BATCH_SIZE, + reduction=losses_impl.ReductionV2.SUM_OVER_BATCH_SIZE, name=None): """Computes the weighted loss. @@ -177,7 +153,7 @@ def compute_weighted_loss(losses, Weighted loss `Tensor` of the same type as `losses`. If `reduction` is `NONE`, this has the same shape as `losses`; otherwise, it is scalar. """ - ReductionV2.validate(reduction) + losses_impl.ReductionV2.validate(reduction) if sample_weight is None: sample_weight = 1.0 with ops.name_scope(name, 'weighted_loss', (losses, sample_weight)): diff --git a/tensorflow/python/ops/losses/losses_impl.py b/tensorflow/python/ops/losses/losses_impl.py index 1b470937d4..9e9de62e6c 100644 --- a/tensorflow/python/ops/losses/losses_impl.py +++ b/tensorflow/python/ops/losses/losses_impl.py @@ -33,6 +33,30 @@ from tensorflow.python.util.deprecation import deprecated_argument_lookup from tensorflow.python.util.tf_export import tf_export +@tf_export("losses.Reduction", "keras.losses.Reduction", v1=[]) +class ReductionV2(object): + """Types of loss reduction. + + Contains the following values: + `NONE`: Un-reduced weighted losses with the same shape as input. + `SUM`: Scalar sum of weighted losses. + `SUM_OVER_BATCH_SIZE`: Scalar `SUM` divided by number of elements in losses. + """ + + NONE = "none" + SUM = "sum" + SUM_OVER_BATCH_SIZE = "sum_over_batch_size" + + @classmethod + def all(cls): + return (cls.NONE, cls.SUM, cls.SUM_OVER_BATCH_SIZE) + + @classmethod + def validate(cls, key): + if key not in cls.all(): + raise ValueError("Invalid Reduction Key %s." % key) + + @tf_export(v1=["losses.Reduction"]) class Reduction(object): """Types of loss reduction. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt index 031d9b171f..f20ed26e2e 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt @@ -1,10 +1,10 @@ path: "tensorflow.keras.losses.Reduction" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "NONE" - mtype: "" + mtype: "" } member { name: "SUM" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt index ad72e3194a..6a44e4ce66 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt @@ -1,10 +1,10 @@ path: "tensorflow.losses.Reduction" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "NONE" - mtype: "" + mtype: "" } member { name: "SUM" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index f8c1f4111f..83ef73b8fa 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -437,6 +437,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.compat.v1.data.Iterator", "tf.nn.fused_batch_norm": "tf.compat.v1.nn.fused_batch_norm", + "tf.losses.Reduction.MEAN": + "tf.compat.v1.losses.Reduction.MEAN", + "tf.losses.Reduction.SUM_BY_NONZERO_WEIGHTS": + "tf.compat.v1.losses.Reduction.SUM_BY_NONZERO_WEIGHTS", + "tf.losses.Reduction.SUM_OVER_NONZERO_WEIGHTS": + "tf.compat.v1.losses.Reduction.SUM_OVER_NONZERO_WEIGHTS", } # pylint: enable=line-too-long -- GitLab From 6b61ad6ab2d0ce8c9e0c218f8d3571ce498e3fc8 Mon Sep 17 00:00:00 2001 From: Andy Ly Date: Thu, 29 Nov 2018 12:25:41 -0800 Subject: [PATCH 563/672] Add test cases for constant folding cast(const(foo)). PiperOrigin-RevId: 223390529 --- .../optimizers/constant_folding_test.cc | 326 +++++++++++------- 1 file changed, 208 insertions(+), 118 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/constant_folding_test.cc b/tensorflow/core/grappler/optimizers/constant_folding_test.cc index f6fdb32e98..192f48272f 100644 --- a/tensorflow/core/grappler/optimizers/constant_folding_test.cc +++ b/tensorflow/core/grappler/optimizers/constant_folding_test.cc @@ -14,10 +14,12 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/grappler/optimizers/constant_folding.h" +#include "tensorflow/cc/ops/array_ops.h" #include "tensorflow/cc/ops/array_ops_internal.h" #include "tensorflow/cc/ops/standard_ops.h" #include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/tensor_testutil.h" +#include "tensorflow/core/framework/types.pb.h" #include "tensorflow/core/grappler/grappler_item.h" #include "tensorflow/core/grappler/utils.h" #include "tensorflow/core/grappler/utils/grappler_test.h" @@ -72,9 +74,9 @@ class ConstantFoldingTest : public GrapplerTest { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); item.fetch = {"mul1", "mul2", "add1", "add2"}; - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(7, output.node_size()); @@ -132,9 +134,9 @@ TEST_F(ConstantFoldingTest, SimpleFolding) { item.fetch.push_back("d"); TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(1, output.node_size()); @@ -178,9 +180,9 @@ TEST_F(ConstantFoldingTest, AddTree) { item.fetch = {"add_parent", "mul_parent", "addmul_parent"}; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // We expect the following rewrite(s) to occur: @@ -276,13 +278,11 @@ TEST_F(ConstantFoldingTest, ConvPushDownTest) { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding fold(nullptr); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = fold.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); - std::cout << output.DebugString() << std::endl; - EXPECT_EQ(5, output.node_size()); int found = 0; for (const auto& node : output.node()) { @@ -366,9 +366,9 @@ TEST_F(ConstantFoldingTest, NeutralElement) { TF_CHECK_OK(s.ToGraphDef(&item.graph)); item.fetch = {"stack", "matmul3", "matmul4"}; - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); const string suffix = @@ -521,9 +521,9 @@ TEST_F(ConstantFoldingTest, StrengthReduce_Reciprocal) { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); item.fetch = {"div_f", "div_i", "realdiv"}; - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(8, output.node_size()); @@ -611,9 +611,9 @@ TEST_F(ConstantFoldingTest, NeutralElement_PartialShape_UnknownOutputShape) { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(15, output.node_size()); @@ -683,9 +683,9 @@ TEST_F(ConstantFoldingTest, NeutralElement_PartialShape_KnownOutputShape) { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(10, output.node_size()); @@ -741,9 +741,9 @@ TEST_F(ConstantFoldingTest, CreateConstNodes) { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(24, output.node_size()); @@ -790,9 +790,9 @@ TEST_F(ConstantFoldingTest, FoldingNodeWithTwoOutputs) { item.fetch.push_back("f"); TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(2, output.node_size()); @@ -831,9 +831,9 @@ TEST_F(ConstantFoldingTest, ControlDependencies) { item.fetch.push_back("e"); TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::vector expected_nodes = {"dflt", "p1", "p2", "e"}; @@ -874,9 +874,9 @@ TEST_F(ConstantFoldingTest, ControlDependenciesEmptyFetch) { GrapplerItem item; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::vector expected_nodes = {"dflt", "p1", "p2", "c", @@ -932,9 +932,9 @@ TEST_F(ConstantFoldingTest, ControlDependenciesDeduplicate) { TF_CHECK_OK(scope.ToGraphDef(&item.graph)); auto tensors_expected = EvaluateNodes(item.graph, item.fetch); EXPECT_EQ(1, tensors_expected.size()); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::vector expected_nodes = {"dflt", "p1", "p2", "i2"}; @@ -1009,9 +1009,9 @@ TEST_F(ConstantFoldingTest, VariableNumberOfOutputs) { } item.fetch = outputs; - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int constant_folded = 0; @@ -1047,9 +1047,9 @@ TEST_F(ConstantFoldingTest, ShapeMaterialization) { item.fetch.push_back("p2"); TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -1097,9 +1097,9 @@ TEST_F(ConstantFoldingTest, ShapeMaterializationEmptyFetch) { GrapplerItem item; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -1163,9 +1163,9 @@ TEST_F(ConstantFoldingTest, ShapeMaterializationShapeN) { GrapplerItem item; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; for (const auto& node : output.node()) { @@ -1235,9 +1235,9 @@ TEST_F(ConstantFoldingTest, ShapeMaterializationShapeN_MultipleOutputs) { item.fetch.push_back("ia"); item.fetch.push_back("ib"); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -1307,9 +1307,9 @@ TEST_F(ConstantFoldingTest, SwitchNodesEmptyFetch) { GrapplerItem item; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::set present_nodes = {"v_in", "v_ctrl", @@ -1409,9 +1409,9 @@ TEST_F(ConstantFoldingTest, SwitchNodes) { TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::set present_nodes = {"v_in", "v_ctrl", "switch", "i", @@ -1505,9 +1505,9 @@ TEST_F(ConstantFoldingTest, MergeNodes) { item.fetch = {"out1", "idx1", "out2", "idx2", "out3", "idx3", "out4", "idx4"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(19, output.node_size()); @@ -1590,9 +1590,9 @@ TEST_F(ConstantFoldingTest, SplitRemoval) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1636,9 +1636,9 @@ TEST_F(ConstantFoldingTest, SplitVRemoval) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1686,9 +1686,9 @@ TEST_F(ConstantFoldingTest, TransposeOnSize1DimsRemoval) { item.fetch = {"out1"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1723,9 +1723,9 @@ TEST_F(ConstantFoldingTest, RandomShuffleOnScalarRemoval) { item.fetch = {"out1", "out2"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1769,9 +1769,9 @@ TEST_F(ConstantFoldingTest, ReverseOnSize1DimsRemoval) { item.fetch = {"out1"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1805,9 +1805,9 @@ TEST_F(ConstantFoldingTest, SliceWithSameDimensionRemoval) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1852,9 +1852,9 @@ TEST_F(ConstantFoldingTest, SliceWithSameDimensionRemoval) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1901,9 +1901,9 @@ TEST_F(ConstantFoldingTest, StridedSliceWithSameDimensionRemoval) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -1959,9 +1959,9 @@ TEST_F(ConstantFoldingTest, StridedSliceWithSameDimensionRemoval) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2012,9 +2012,9 @@ TEST_F(ConstantFoldingTest, TileWithMultipliesBeingOne) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2045,9 +2045,9 @@ TEST_F(ConstantFoldingTest, MergeConcat) { item.fetch = {"c2"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2075,9 +2075,9 @@ TEST_F(ConstantFoldingTest, MergeConcat_SameInput) { item.fetch = {"c2"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2106,9 +2106,9 @@ TEST_F(ConstantFoldingTest, MergeConcat_ConcatWithConst) { item.fetch = {"c2"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2137,9 +2137,9 @@ TEST_F(ConstantFoldingTest, MergeConcat_AxisMismatch) { item.fetch = {"c2"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2175,9 +2175,9 @@ TEST_F(ConstantFoldingTest, PaddingWithZeroSize) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2221,9 +2221,9 @@ TEST_F(ConstantFoldingTest, SqueezeWithAllDimesionsGreaterThanOne) { item.fetch = {"out"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef got; - Status status = optimizer.Optimize(nullptr, item, &got); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &got); TF_EXPECT_OK(status); GraphDef want; @@ -2269,9 +2269,9 @@ TEST_F(ConstantFoldingTest, NoOpReduction) { item.fetch = {"s", "p2"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -2338,9 +2338,9 @@ TEST_F(ConstantFoldingTest, SingleElementEmptyAxisReduction) { item.fetch = {"mean_1", "mean_2", "mean_3", "mean_4", "mean_5"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Ensure Mean node is optimized to Reshape. @@ -2433,9 +2433,9 @@ TEST_F(ConstantFoldingTest, NoOpReshape) { item.fetch = {"s1", "s2", "s3", "s4"}; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -2495,9 +2495,9 @@ TEST_F(ConstantFoldingTest, Packing) { GrapplerItem item; TF_CHECK_OK(scope.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); const std::vector fetch_nodes = {"i1", "i2"}; @@ -2538,9 +2538,9 @@ TEST_F(ConstantFoldingTest, MaterializeBroadcastGradientArgs) { GrapplerItem item; TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::vector fetch_nodes = {"o1", "o2", "p1", "p2"}; @@ -2552,7 +2552,7 @@ TEST_F(ConstantFoldingTest, MaterializeBroadcastGradientArgs) { // Run a second time to make sure the optimization is idempotent. item.graph.Swap(&output); - status = optimizer.Optimize(nullptr, item, &output); + status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -2619,14 +2619,14 @@ TEST_F(ConstantFoldingTest, MaterializeBroadcastGradientArgs_InfiniteLoop) { auto tensors_expected = EvaluateNodes(item.graph, fetch_nodes, {{"a", a_t}}); EXPECT_EQ(fetch_nodes.size(), tensors_expected.size()); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Run a second time to make sure the optimization is idempotent. item.graph.Swap(&output); - status = optimizer.Optimize(nullptr, item, &output); + status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(11, output.node_size()); @@ -2711,14 +2711,14 @@ TEST_F(ConstantFoldingTest, MaterializeReductionIndices) { // Use aggressive mode to force the shape inference to propagate placeholder // shapes. ConstantFolding optimizer(RewriterConfig::AGGRESSIVE, - nullptr /* cpu_device */); + /*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Run a second time to make sure the optimization is idempotent. item.graph.Swap(&output); - status = optimizer.Optimize(nullptr, item, &output); + status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); int found = 0; @@ -2767,9 +2767,9 @@ TEST_F(ConstantFoldingTest, MaterializeReductionIndices_NotFullReduction) { // Use aggressive mode to force the shape inference to propagate placeholder // shapes. ConstantFolding optimizer(RewriterConfig::AGGRESSIVE, - nullptr /* cpu_device */); + /*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); CompareGraphs(item.graph, output); @@ -2788,9 +2788,9 @@ TEST_F(ConstantFoldingTest, LargeConstant) { TF_CHECK_OK(scope.ToGraphDef(&item.graph)); item.fetch.push_back("out"); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Make sure the diag node hasn't been folded, since it would use too much @@ -2833,9 +2833,9 @@ TEST_F(ConstantFoldingTest, SwitchIdenticalInputs) { item.fetch.push_back("id_true"); TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(6, output.node_size()); @@ -2925,9 +2925,9 @@ TEST_F(ConstantFoldingTest, PartialFolding_AssociativeAndCommutative) { TF_CHECK_OK(s.ToGraphDef(&item.graph)); item.fetch = {"stack"}; - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(16, output.node_size()); @@ -3017,13 +3017,13 @@ TEST_F(ConstantFoldingTest, PartialFolding_Concat) { auto tensors_expected = EvaluateNodes(item.graph, {"concat0"}); EXPECT_EQ(1, tensors_expected.size()); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Run the optimizer twice to make sure the rewrite is idempotent. item.graph.Swap(&output); - status = optimizer.Optimize(nullptr, item, &output); + status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(21, output.node_size()); @@ -3090,9 +3090,9 @@ TEST_F(ConstantFoldingTest, PartialFolding_IdentityN) { item.fetch.push_back("add0"); item.fetch.push_back("add1"); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(8, output.node_size()); for (const auto& node : output.node()) { @@ -3152,9 +3152,9 @@ TEST_F(ConstantFoldingTest, TrivialPack) { TF_CHECK_OK(scope.ToGraphDef(&item.graph)); item.fetch = {"stack", "stack_no_axis"}; - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(7, output.node_size()); int found = 0; @@ -3234,13 +3234,13 @@ TEST_F(ConstantFoldingTest, Enter) { item.fetch.push_back("id3"); item.fetch.push_back("id4"); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Run the optimizer twice to make sure the rewrite is idempotent. item.graph.Swap(&output); - status = optimizer.Optimize(nullptr, item, &output); + status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(9, output.node_size()); @@ -3289,13 +3289,13 @@ TEST_F(ConstantFoldingTest, TensorArraySize) { auto tensors_expected = EvaluateNodes(item.graph, {"dynamic_sz", "static_sz"}); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); // Run the optimizer twice to make sure the rewrite is idempotent. item.graph.Swap(&output); - status = optimizer.Optimize(nullptr, item, &output); + status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(8, output.node_size()); @@ -3327,9 +3327,9 @@ TEST_F(ConstantFoldingTest, FoldingPreservesDenormalFlushing) { item.fetch.push_back("c"); TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); EXPECT_EQ(1, output.node_size()); @@ -3363,9 +3363,9 @@ TEST_F(ConstantFoldingTest, EvaluatingLargeConstantNoFoldingMergingLoop) { item.fetch.push_back("result"); TF_CHECK_OK(s.ToGraphDef(&item.graph)); - ConstantFolding optimizer(nullptr /* cpu_device */); + ConstantFolding optimizer(/*cpu_device=*/nullptr); GraphDef output; - Status status = optimizer.Optimize(nullptr, item, &output); + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); TF_EXPECT_OK(status); std::vector fetch = {"result"}; @@ -3376,6 +3376,96 @@ TEST_F(ConstantFoldingTest, EvaluatingLargeConstantNoFoldingMergingLoop) { EXPECT_EQ(tensors_expected[0].shape(), tensors[0].shape()); } +class ConstantFoldingCastConstTest : public GrapplerTest { + protected: + void ConstantFoldingCastConst(bool fetch_const, bool fetch_cast, + bool fetch_const_child, bool fetch_cast_child) { + if (!fetch_const && !fetch_cast && !fetch_const_child && + !fetch_cast_child) { + return; + } + + tensorflow::Scope s = tensorflow::Scope::NewRootScope(); + CreateCastConstGraph(s); + GrapplerItem item; + int expected_output_size = SetFetch(&item, fetch_const, fetch_cast, + fetch_const_child, fetch_cast_child); + TF_CHECK_OK(s.ToGraphDef(&item.graph)); + + GraphDef output = ConstantFoldingOptimize(item); + EXPECT_EQ(expected_output_size, output.node_size()); + + EvaluateAndCompareUnoptimized(item.graph, output, item.fetch); + } + + private: + void CreateCastConstGraph(const tensorflow::Scope& s) { + Output const1 = ops::Const(s.WithOpName("const1"), 2, {5, 5}); + Output cast = ops::Cast(s.WithOpName("cast"), const1, DT_FLOAT); + Output const1_child = ops::Identity(s.WithOpName("const1_child"), const1); + Output cast_child = ops::Identity(s.WithOpName("cast_child"), cast); + } + + int SetFetch(GrapplerItem* item, bool fetch_const, bool fetch_cast, + bool fetch_const_child, bool fetch_cast_child) { + int expected_output_size = 0; + if (fetch_const) { + item->fetch.push_back("const1"); + expected_output_size++; + } + if (fetch_cast) { + item->fetch.push_back("cast"); + expected_output_size++; + } + if (fetch_const_child) { + item->fetch.push_back("const1_child"); + expected_output_size++; + } + if (fetch_cast_child) { + item->fetch.push_back("cast_child"); + expected_output_size++; + } + return expected_output_size; + } + + GraphDef ConstantFoldingOptimize(const GrapplerItem& item) { + ConstantFolding optimizer(/*cpu_device=*/nullptr); + GraphDef output; + Status status = optimizer.Optimize(/*cluster=*/nullptr, item, &output); + TF_EXPECT_OK(status); + return output; + } + + void EvaluateAndCompareUnoptimized(const GraphDef& unoptimized_graph, + const GraphDef& optimized_graph, + const std::vector& fetch_nodes) { + auto tensors_expected = EvaluateNodes(unoptimized_graph, fetch_nodes); + auto tensors = EvaluateNodes(optimized_graph, fetch_nodes); + ASSERT_EQ(fetch_nodes.size(), tensors_expected.size()); + ASSERT_EQ(fetch_nodes.size(), tensors.size()); + for (int i = 0; i < fetch_nodes.size(); i++) { + if (fetch_nodes[i] == "const1" || fetch_nodes[i] == "const1_child") { + test::ExpectTensorEqual(tensors_expected[i], tensors[i]); + } else { + test::ExpectTensorEqual(tensors_expected[i], tensors[i]); + } + } + } +}; + +TEST_F(ConstantFoldingCastConstTest, CastConstFolding) { + for (bool fetch_const : {false, true}) { + for (bool fetch_cast : {false, true}) { + for (bool fetch_const_child : {false, true}) { + for (bool fetch_cast_child : {false, true}) { + ConstantFoldingCastConst(fetch_const, fetch_cast, fetch_const_child, + fetch_cast_child); + } + } + } + } +} + } // namespace } // namespace grappler } // namespace tensorflow -- GitLab From d1198909057c635de2bae3e1c4fb8505466ee325 Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Thu, 29 Nov 2018 12:39:54 -0800 Subject: [PATCH 564/672] Naming for valid scope name in eager mode. PiperOrigin-RevId: 223392695 --- tensorflow/python/ops/data_flow_ops.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/ops/data_flow_ops.py b/tensorflow/python/ops/data_flow_ops.py index bb08dbaea1..2030332e4e 100644 --- a/tensorflow/python/ops/data_flow_ops.py +++ b/tensorflow/python/ops/data_flow_ops.py @@ -171,7 +171,10 @@ class QueueBase(object): self._names = None self._queue_ref = queue_ref if context.executing_eagerly(): - self._name = context.context().scope_name + if context.context().scope_name: + self._name = context.context().scope_name + else: + self._name = "Empty" self._resource_deleter = resource_variable_ops.EagerResourceDeleter( queue_ref, None) else: -- GitLab From c53aa864f9e2f2be89892feeab19877f6107bb9e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 12:56:25 -0800 Subject: [PATCH 565/672] Update ops-related pbtxt files. PiperOrigin-RevId: 223395339 --- .../core/ops/compat/ops_history.v1.pbtxt | 47 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 47 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index ba0bf553d0..414964ad3f 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -77282,6 +77282,53 @@ op { } } } +op { + name: "UnicodeEncode" + input_arg { + name: "input_values" + type: DT_INT32 + } + input_arg { + name: "input_splits" + type: DT_INT64 + } + output_arg { + name: "output" + type: DT_STRING + } + attr { + name: "errors" + type: "string" + default_value { + s: "replace" + } + allowed_values { + list { + s: "ignore" + s: "replace" + s: "strict" + } + } + } + attr { + name: "output_encoding" + type: "string" + allowed_values { + list { + s: "UTF-8" + s: "UTF-16-BE" + s: "UTF-32-BE" + } + } + } + attr { + name: "replacement_char" + type: "int" + default_value { + i: 65533 + } + } +} op { name: "UnicodeScript" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index bae50a7139..eae87da6b5 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -37163,6 +37163,53 @@ op { } } } +op { + name: "UnicodeEncode" + input_arg { + name: "input_values" + type: DT_INT32 + } + input_arg { + name: "input_splits" + type: DT_INT64 + } + output_arg { + name: "output" + type: DT_STRING + } + attr { + name: "errors" + type: "string" + default_value { + s: "replace" + } + allowed_values { + list { + s: "ignore" + s: "replace" + s: "strict" + } + } + } + attr { + name: "output_encoding" + type: "string" + allowed_values { + list { + s: "UTF-8" + s: "UTF-16-BE" + s: "UTF-32-BE" + } + } + } + attr { + name: "replacement_char" + type: "int" + default_value { + i: 65533 + } + } +} op { name: "UnicodeScript" input_arg { -- GitLab From 06025ed0f91cc1c75b391f31099b6975904382a1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 13:00:01 -0800 Subject: [PATCH 566/672] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 223395920 --- tensorflow/go/op/wrappers.go | 208 +++++++++++++++++------------------ 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index 02a1335149..406382977b 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -5716,6 +5716,77 @@ func MapUnstage(scope *Scope, key tf.Output, indices tf.Output, dtypes []tf.Data return values } +// MapPeekAttr is an optional argument to MapPeek. +type MapPeekAttr func(optionalAttr) + +// MapPeekCapacity sets the optional capacity attribute to value. +// If not specified, defaults to 0 +// +// REQUIRES: value >= 0 +func MapPeekCapacity(value int64) MapPeekAttr { + return func(m optionalAttr) { + m["capacity"] = value + } +} + +// MapPeekMemoryLimit sets the optional memory_limit attribute to value. +// If not specified, defaults to 0 +// +// REQUIRES: value >= 0 +func MapPeekMemoryLimit(value int64) MapPeekAttr { + return func(m optionalAttr) { + m["memory_limit"] = value + } +} + +// MapPeekContainer sets the optional container attribute to value. +// If not specified, defaults to "" +func MapPeekContainer(value string) MapPeekAttr { + return func(m optionalAttr) { + m["container"] = value + } +} + +// MapPeekSharedName sets the optional shared_name attribute to value. +// If not specified, defaults to "" +func MapPeekSharedName(value string) MapPeekAttr { + return func(m optionalAttr) { + m["shared_name"] = value + } +} + +// Op peeks at the values at the specified key. If the +// +// underlying container does not contain this key +// this op will block until it does. +func MapPeek(scope *Scope, key tf.Output, indices tf.Output, dtypes []tf.DataType, optional ...MapPeekAttr) (values []tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{"dtypes": dtypes} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "MapPeek", + Input: []tf.Input{ + key, indices, + }, + Attrs: attrs, + } + op := scope.AddOperation(opspec) + if scope.Err() != nil { + return + } + var idx int + var err error + if values, idx, err = makeOutputList(op, idx, "values"); err != nil { + scope.UpdateErr("MapPeek", err) + return + } + return values +} + // Compute the regularized incomplete beta integral \\(I_x(a, b)\\). // // The regularized incomplete beta integral is defined as: @@ -6539,21 +6610,6 @@ func Sin(scope *Scope, x tf.Output) (y tf.Output) { return op.Output(0) } -// Computes the complementary error function of `x` element-wise. -func Erfc(scope *Scope, x tf.Output) (y tf.Output) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "Erfc", - Input: []tf.Input{ - x, - }, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - // Computes Psi, the derivative of Lgamma (the log of the absolute value of // // `Gamma(x)`), element-wise. @@ -13842,6 +13898,39 @@ func StatelessRandomNormal(scope *Scope, shape tf.Output, seed tf.Output, option return op.Output(0) } +// Computes the complementary error function of `x` element-wise. +func Erfc(scope *Scope, x tf.Output) (y tf.Output) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "Erfc", + Input: []tf.Input{ + x, + }, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + +// Returns the number of tensors in the input tensor list. +// +// input_handle: the input list +// length: the number of tensors in the list +func TensorListLength(scope *Scope, input_handle tf.Output) (length tf.Output) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "TensorListLength", + Input: []tf.Input{ + input_handle, + }, + } + op := scope.AddOperation(opspec) + return op.Output(0) +} + // Determine the script codes of a given tensor of Unicode integer code points. // // This operation converts Unicode code points to script codes corresponding to @@ -25573,77 +25662,6 @@ func Roll(scope *Scope, input tf.Output, shift tf.Output, axis tf.Output) (outpu return op.Output(0) } -// MapPeekAttr is an optional argument to MapPeek. -type MapPeekAttr func(optionalAttr) - -// MapPeekCapacity sets the optional capacity attribute to value. -// If not specified, defaults to 0 -// -// REQUIRES: value >= 0 -func MapPeekCapacity(value int64) MapPeekAttr { - return func(m optionalAttr) { - m["capacity"] = value - } -} - -// MapPeekMemoryLimit sets the optional memory_limit attribute to value. -// If not specified, defaults to 0 -// -// REQUIRES: value >= 0 -func MapPeekMemoryLimit(value int64) MapPeekAttr { - return func(m optionalAttr) { - m["memory_limit"] = value - } -} - -// MapPeekContainer sets the optional container attribute to value. -// If not specified, defaults to "" -func MapPeekContainer(value string) MapPeekAttr { - return func(m optionalAttr) { - m["container"] = value - } -} - -// MapPeekSharedName sets the optional shared_name attribute to value. -// If not specified, defaults to "" -func MapPeekSharedName(value string) MapPeekAttr { - return func(m optionalAttr) { - m["shared_name"] = value - } -} - -// Op peeks at the values at the specified key. If the -// -// underlying container does not contain this key -// this op will block until it does. -func MapPeek(scope *Scope, key tf.Output, indices tf.Output, dtypes []tf.DataType, optional ...MapPeekAttr) (values []tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{"dtypes": dtypes} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "MapPeek", - Input: []tf.Input{ - key, indices, - }, - Attrs: attrs, - } - op := scope.AddOperation(opspec) - if scope.Err() != nil { - return - } - var idx int - var err error - if values, idx, err = makeOutputList(op, idx, "values"); err != nil { - scope.UpdateErr("MapPeek", err) - return - } - return values -} - // Looks up keys in a table, outputs the corresponding values. // // The tensor `keys` must of the same type as the keys of the table. @@ -26838,24 +26856,6 @@ func MergeSummary(scope *Scope, inputs []tf.Output) (summary tf.Output) { return op.Output(0) } -// Returns the number of tensors in the input tensor list. -// -// input_handle: the input list -// length: the number of tensors in the list -func TensorListLength(scope *Scope, input_handle tf.Output) (length tf.Output) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "TensorListLength", - Input: []tf.Input{ - input_handle, - }, - } - op := scope.AddOperation(opspec) - return op.Output(0) -} - // The shape of the elements of the given list, as a tensor. // // input_handle: the list -- GitLab From 886fab08090cb9048e5cb6169b1e8ab260f650a1 Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Thu, 29 Nov 2018 13:11:43 -0800 Subject: [PATCH 567/672] [XLA] Update doc for collective permute. PiperOrigin-RevId: 223398050 --- .../compiler/xla/g3doc/operation_semantics.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tensorflow/compiler/xla/g3doc/operation_semantics.md b/tensorflow/compiler/xla/g3doc/operation_semantics.md index df74a9b3af..e0807518bc 100644 --- a/tensorflow/compiler/xla/g3doc/operation_semantics.md +++ b/tensorflow/compiler/xla/g3doc/operation_semantics.md @@ -418,6 +418,33 @@ then v12 == f32[8x3] {{10, 11, 12}, ``` +## CollectivePermute + +See also +[`XlaBuilder::CollectivePermute`](https://www.tensorflow.org/code/tensorflow/compiler/xla/client/xla_builder.h). + +CollectivePermute is a collective operation that sends and receives data cross +replicas. + + `CollectivePermute(operand, source_target_pairs)` + +| Arguments | Type | Semantics | +| --------------------- | ----------------------- | -------------------------- | +| `operand` | `XlaOp` | n dimensional input array | +| `source_target_pairs` | `` vector | A list of | +: : : (source_replica_id, : +: : : target_replica_id) pairs. : +: : : For each pair, the operand : +: : : is sent from source : +: : : replica to target replica. : + +Note that there are the following restrictions on the `source_target_pair`: + +- Any two pairs should not have the same target replica id, and they should + not have the same source replica id. +- If a replica id is not a target in any pair, then the output on that replica + is a tensor consists of 0(s) with the same shape as the input. + ## Concatenate See also -- GitLab From 23ddb5c69a6c98e8654b6114b1aa33606460638a Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Thu, 29 Nov 2018 13:16:22 -0800 Subject: [PATCH 568/672] Move to do into comment. PiperOrigin-RevId: 223398784 --- tensorflow/lite/python/op_hint.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/lite/python/op_hint.py b/tensorflow/lite/python/op_hint.py index 718b23075d..8d7f9316bf 100644 --- a/tensorflow/lite/python/op_hint.py +++ b/tensorflow/lite/python/op_hint.py @@ -104,9 +104,9 @@ class OpHint(object): that make up the pseudo op. A similar process is done to any output that is to be exported from the current op. - TODO(aselle): When TensorFlow functions functionality works for arbitrary - constructs, this mechanism can be retired and changed to use python defun's. """ + # TODO(aselle): When TensorFlow functions functionality works for arbitrary + # constructs, this mechanism can be retired and changed to use python defun's. # Attr constants that are used for representation in the GraphDef. These # will be used on every Identity op that is involved in a total OpHint. -- GitLab From a1f87073027572737b275401202726f736350206 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Thu, 29 Nov 2018 13:19:39 -0800 Subject: [PATCH 569/672] Extracted ~logically independent bits from `_VarStore._get_partitioned_variables` PiperOrigin-RevId: 223399274 --- tensorflow/python/ops/variable_scope.py | 142 ++++++++++++------------ 1 file changed, 74 insertions(+), 68 deletions(-) diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index ad81862a58..ccce9e2f93 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -648,8 +648,6 @@ class _VariableStore(object): """ initializing_from_value = initializer is not None and isinstance( initializer, ops.Tensor) - reuse_without_partition = reuse and not partitioner - if name in self._vars: raise ValueError( "A partitioner was provided, but an unpartitioned version of the " @@ -660,30 +658,9 @@ class _VariableStore(object): if initializing_from_value: shape = shape.merge_with(initializer.get_shape()) - if not reuse_without_partition: - if not shape.is_fully_defined(): - raise ValueError("Shape of a new partitioned variable (%s) must be " - "fully defined, but instead was %s." % (name, shape)) - - if shape.ndims < 1: - raise ValueError("A partitioned Variable must have rank at least 1, " - "shape: %s" % shape) - - partitions = partitioner(shape=shape, dtype=dtype) - - if not isinstance(partitions, collections_lib.Sequence): - raise ValueError("Partitioner must return a sequence, but saw: %s" - % partitions) - - if len(partitions) != shape.ndims: - raise ValueError( - "Partitioner returned a partition list that does not match the " - "Variable's rank: %s vs. %s" % (partitions, shape)) - - if any(p < 1 for p in partitions): - raise ValueError( - "Partitioner returned zero partitions for some axes: %s" % - partitions) + partitions = None + if not reuse or partitioner: + partitions = _call_partitioner(partitioner, shape, dtype) if name in self._partitioned_vars: if reuse is False: @@ -705,7 +682,7 @@ class _VariableStore(object): % (name, dtype.name, existing_var.dtype.name)) # pylint: disable=protected-access - if (not reuse_without_partition and + if (partitions is not None and existing_var._get_partitions() != partitions): raise ValueError( "Trying to reuse partitioned variable %s, but specified partitions " @@ -720,14 +697,7 @@ class _VariableStore(object): "created with tf.get_variable(). Did you mean to set " "reuse=False or reuse=tf.AUTO_REUSE in VarScope?" % name) - slice_dim, slice_shape = _compute_slice_dim_and_shape( - shape.as_list(), partitions) - - vs = [] - num_slices = partitions[slice_dim] - num_slices_with_excess = shape.dims[slice_dim].value % num_slices - - slice_offset = [0] * shape.ndims + slice_dim, num_slices = _get_slice_dim_and_num_slices(partitions) if "%s/part_0" % name in self._vars: if "%s/part_%d" % (name, num_slices - 1) not in self._vars: @@ -743,15 +713,14 @@ class _VariableStore(object): "%s/part_0 was found, but so was the extra shard %s/part_%d." % (num_slices, name, name, num_slices)) - for i in xrange(num_slices): - var_shape = slice_shape[:] - var_offset = slice_offset[:] + vs = [] + for i, (var_offset, var_shape) in enumerate(_iter_slices( + shape.as_list(), + num_slices, + slice_dim + )): partition_info = _PartitionInfo( full_shape=shape.as_list(), var_offset=var_offset) - if i < num_slices_with_excess: - var_shape[slice_dim] += 1 - slice_offset[slice_dim] += var_shape[slice_dim] - var_full_name = "%s/part_%d" % (name, i) with ops.name_scope(var_full_name + "/PartitionedInitializer"): # Create the tensor to initialize the variable with default value. @@ -2400,34 +2369,71 @@ def variable_op_scope(values, yield scope -def _compute_slice_dim_and_shape(full_shape, slicing): - """Computes which dimension is being sliced and the typical slice shape.""" - - slice_shape = [0] * len(full_shape) - slice_dim = None - for dim, num_slices in enumerate(slicing): - dim_size = full_shape[dim] - if num_slices <= 0 or dim_size < num_slices: - raise ValueError("Cannot create %d slices for size %d. shape: %s, " - "slicing: %s" % - (num_slices, full_shape[dim], full_shape, slicing)) - if num_slices == 1: - # Not slicing in this dimension. - slice_shape[dim] = dim_size - elif slice_dim is not None: - # We only support slicing along one of the dimensions. - raise ValueError("Can only slice a variable along one dimension: " - "shape: %s, slicing: %s" % (full_shape, slicing)) - else: - # Note: We will add any extras onto the last slice, later. - slice_dim = dim - slice_shape[dim] = dim_size // num_slices +def _call_partitioner(partitioner, shape, dtype): + """Call partitioner validating its inputs/output. - # Degenerate case: If "slicing" was all ones, pretend we are slicing along - # the first dimension. - if slice_dim is None: + Args: + partitioner: a function mapping `Tensor` shape and dtype to a + list of partitions. + shape: shape of the `Tensor` to partition, must have at least two + dimensions. + dtype: dtype of the elements in the `Tensor`. + + Returns: + A list with elements >=1 and exactly one >1. The index of that + element corresponds to the partitioning axis. + """ + if not shape.is_fully_defined(): + raise ValueError("Shape of a new partitioned variable must be " + "fully defined, but instead was %s." % (shape,)) + if shape.ndims < 1: + raise ValueError("A partitioned Variable must have rank at least 1, " + "shape: %s" % shape) + + slicing = partitioner(shape=shape, dtype=dtype) + if not isinstance(slicing, collections_lib.Sequence): + raise ValueError("Partitioner must return a sequence, but saw: %s" + % slicing) + if len(slicing) != shape.ndims: + raise ValueError( + "Partitioner returned a partition list that does not match the " + "Variable's rank: %s vs. %s" % (slicing, shape)) + if any(p < 1 for p in slicing): + raise ValueError( + "Partitioner returned zero partitions for some axes: %s" % + slicing) + if sum(p > 1 for p in slicing) > 1: + raise ValueError( + "Can only slice a variable along one dimension: " + "shape: %s, partitioning: %s" % (shape, slicing)) + return slicing + + +# TODO(slebedev): could be inlined, but +# `_VariableStore._get_partitioned_variable` is too complex even +# without this logic. +def _get_slice_dim_and_num_slices(slicing): + """Get slicing dimension and number of slices from the partitioner output.""" + for slice_dim, num_slices in enumerate(slicing): + if num_slices > 1: + break + else: + # Degenerate case: no partitioning applied. slice_dim = 0 - return slice_dim, slice_shape + num_slices = 1 + return slice_dim, num_slices + + +def _iter_slices(full_shape, num_slices, slice_dim): + """Slices a given a shape along the specified dimension.""" + num_slices_with_excess = full_shape[slice_dim] % num_slices + offset = [0] * len(full_shape) + min_slice_len = full_shape[slice_dim] // num_slices + for i in xrange(num_slices): + shape = full_shape[:] + shape[slice_dim] = min_slice_len + bool(i < num_slices_with_excess) + yield offset[:], shape + offset[slice_dim] += shape[slice_dim] def _get_trainable_value(synchronization, trainable): -- GitLab From 825621b3ca15c1b6b96195544e3259d2fa72e5de Mon Sep 17 00:00:00 2001 From: Ruoxin Sang Date: Thu, 29 Nov 2018 13:20:43 -0800 Subject: [PATCH 570/672] Make sure Keras sequential clone doesn't create unnecessary placeholders as well. PiperOrigin-RevId: 223399456 --- tensorflow/python/keras/models.py | 9 ++++++--- tensorflow/python/keras/models_test.py | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/keras/models.py b/tensorflow/python/keras/models.py index 4813b8061e..2637191bb7 100644 --- a/tensorflow/python/keras/models.py +++ b/tensorflow/python/keras/models.py @@ -211,14 +211,17 @@ def _clone_sequential_model(model, input_tensors=None): # Use model._layers to ensure that all layers are cloned. The model's layers # property will exclude the initial InputLayer (if it exists) in the model, # resulting in a different Sequential model structure. - layers = [clone(layer) for layer in model._layers] if input_tensors is None: + layers = [clone(layer) for layer in model._layers] return Sequential(layers=layers, name=model.name) else: # If input tensors are provided, the original model's InputLayer is # overwritten with a different InputLayer. - if isinstance(layers[0], InputLayer): - layers = layers[1:] + layers = [ + clone(layer) + for layer in model._layers + if not isinstance(layer, InputLayer) + ] if len(generic_utils.to_list(input_tensors)) != 1: raise ValueError('To clone a `Sequential` model, we expect ' ' at most one tensor ' diff --git a/tensorflow/python/keras/models_test.py b/tensorflow/python/keras/models_test.py index 23321a2d16..c68c80f0cc 100644 --- a/tensorflow/python/keras/models_test.py +++ b/tensorflow/python/keras/models_test.py @@ -235,7 +235,8 @@ class TestModelCloning(test.TestCase): def test_sequential_cloning_does_not_create_unnecessary_placeholders(self): with ops.Graph().as_default(): - model = keras.models.Sequential([keras.layers.Dense(4)]) + model = keras.models.Sequential() + model.add(keras.layers.Dense(4, input_shape=(4,))) graph = ops.Graph() with graph.as_default(): x = array_ops.ones((10, 4)) -- GitLab From fd7b50ee620ab2e363c1d473c166225d103dddfb Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 13:29:05 -0800 Subject: [PATCH 571/672] Automated rollback of commit 5f111d5a6c78f7afcd3ccbabf6e272800caceb9d PiperOrigin-RevId: 223400918 --- .../keras/layers/cudnn_recurrent_test.py | 686 +++++++++--------- 1 file changed, 334 insertions(+), 352 deletions(-) diff --git a/tensorflow/python/keras/layers/cudnn_recurrent_test.py b/tensorflow/python/keras/layers/cudnn_recurrent_test.py index 1f195f3119..cc93364aae 100644 --- a/tensorflow/python/keras/layers/cudnn_recurrent_test.py +++ b/tensorflow/python/keras/layers/cudnn_recurrent_test.py @@ -31,76 +31,64 @@ from tensorflow.python.platform import test from tensorflow.python.training.rmsprop import RMSPropOptimizer -@test_util.run_all_in_graph_and_eager_modes class CuDNNTest(test.TestCase, parameterized.TestCase): + @test_util.run_in_graph_and_eager_modes def test_cudnn_rnn_basics(self): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: - for return_sequences in [True, False]: - with keras.utils.CustomObjectScope({ - 'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, - 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM - }): - testing_utils.layer_test( - layer_class, - kwargs={ - 'units': units, - 'return_sequences': return_sequences - }, - input_shape=(num_samples, timesteps, input_size)) - for go_backwards in [True, False]: - with keras.utils.CustomObjectScope({ - 'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, - 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM - }): - testing_utils.layer_test( - layer_class, - kwargs={ - 'units': units, - 'go_backwards': go_backwards - }, - input_shape=(num_samples, timesteps, input_size)) - + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: + for return_sequences in [True, False]: + with keras.utils.CustomObjectScope( + {'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, + 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM}): + testing_utils.layer_test( + layer_class, + kwargs={'units': units, + 'return_sequences': return_sequences}, + input_shape=(num_samples, timesteps, input_size)) + for go_backwards in [True, False]: + with keras.utils.CustomObjectScope( + {'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, + 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM}): + testing_utils.layer_test( + layer_class, + kwargs={'units': units, + 'go_backwards': go_backwards}, + input_shape=(num_samples, timesteps, input_size)) + + @test_util.run_in_graph_and_eager_modes def test_trainability(self): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - units = 2 - for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: - layer = layer_class(units) - layer.build((None, None, input_size)) - self.assertEqual(len(layer.weights), 3) - self.assertEqual(len(layer.trainable_weights), 3) - self.assertEqual(len(layer.non_trainable_weights), 0) - layer.trainable = False - self.assertEqual(len(layer.weights), 3) - self.assertEqual(len(layer.non_trainable_weights), 3) - self.assertEqual(len(layer.trainable_weights), 0) - layer.trainable = True - self.assertEqual(len(layer.weights), 3) - self.assertEqual(len(layer.trainable_weights), 3) - self.assertEqual(len(layer.non_trainable_weights), 0) + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + units = 2 + for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: + layer = layer_class(units) + layer.build((None, None, input_size)) + self.assertEqual(len(layer.weights), 3) + self.assertEqual(len(layer.trainable_weights), 3) + self.assertEqual(len(layer.non_trainable_weights), 0) + layer.trainable = False + self.assertEqual(len(layer.weights), 3) + self.assertEqual(len(layer.non_trainable_weights), 3) + self.assertEqual(len(layer.trainable_weights), 0) + layer.trainable = True + self.assertEqual(len(layer.weights), 3) + self.assertEqual(len(layer.trainable_weights), 3) + self.assertEqual(len(layer.non_trainable_weights), 0) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_regularizer(self, layer_class): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - if test.is_gpu_available(cuda_only=True): - with test_util.use_gpu(): + with self.session(use_gpu=True): input_size = 10 timesteps = 6 units = 2 @@ -131,140 +119,132 @@ class CuDNNTest(test.TestCase, parameterized.TestCase): ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_return_state(self, layer_class): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 - - inputs = keras.Input(batch_shape=(num_samples, timesteps, input_size)) - layer = layer_class(units, return_state=True, stateful=True) - outputs = layer(inputs) - _, state = outputs[0], outputs[1:] - self.assertEqual(len(state), num_states) - model = keras.models.Model(inputs, state[0]) - - inputs = np.random.random((num_samples, timesteps, input_size)) - state = model.predict(inputs) - np.testing.assert_allclose( - keras.backend.eval(layer.states[0]), state, atol=1e-4) + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 + + inputs = keras.Input(batch_shape=(num_samples, timesteps, input_size)) + layer = layer_class(units, return_state=True, stateful=True) + outputs = layer(inputs) + _, state = outputs[0], outputs[1:] + self.assertEqual(len(state), num_states) + model = keras.models.Model(inputs, state[0]) + + inputs = np.random.random((num_samples, timesteps, input_size)) + state = model.predict(inputs) + np.testing.assert_allclose( + keras.backend.eval(layer.states[0]), state, atol=1e-4) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_time_major_input(self, layer_class): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - - model = keras.models.Sequential() - model.add( - keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) - layer = layer_class(units, time_major=True, return_sequences=True) - model.add(layer) - model.add( - keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) - model.compile(loss='categorical_crossentropy', optimizer='adam') - model.fit( - np.ones((num_samples, timesteps, input_size)), - np.ones((num_samples, timesteps, units))) - out = model.predict(np.ones((num_samples, timesteps, input_size))) - self.assertEqual(out.shape, (num_samples, timesteps, units)) + if test.is_gpu_available(cuda_only=True): + with self.test_session(use_gpu=True): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + + model = keras.models.Sequential() + model.add( + keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) + layer = layer_class(units, time_major=True, return_sequences=True) + model.add(layer) + model.add( + keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) + model.compile(loss='categorical_crossentropy', optimizer='adam') + model.fit( + np.ones((num_samples, timesteps, input_size)), + np.ones((num_samples, timesteps, units))) + out = model.predict(np.ones((num_samples, timesteps, input_size))) + self.assertEqual(out.shape, (num_samples, timesteps, units)) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_specify_initial_state_keras_tensor(self, layer_class): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 - - inputs = keras.Input((timesteps, input_size)) - initial_state = [keras.Input((units,)) for _ in range(num_states)] - layer = layer_class(units) - if len(initial_state) == 1: - output = layer(inputs, initial_state=initial_state[0]) - else: - output = layer(inputs, initial_state=initial_state) - self.assertIn(initial_state[0], layer._inbound_nodes[0].input_tensors) - - model = keras.models.Model([inputs] + initial_state, output) - model.compile(loss='categorical_crossentropy', optimizer='adam') - - inputs = np.random.random((num_samples, timesteps, input_size)) - initial_state = [ - np.random.random((num_samples, units)) for _ in range(num_states) - ] - targets = np.random.random((num_samples, units)) - model.fit([inputs] + initial_state, targets) + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 + + inputs = keras.Input((timesteps, input_size)) + initial_state = [keras.Input((units,)) for _ in range(num_states)] + layer = layer_class(units) + if len(initial_state) == 1: + output = layer(inputs, initial_state=initial_state[0]) + else: + output = layer(inputs, initial_state=initial_state) + self.assertIn(initial_state[0], layer._inbound_nodes[0].input_tensors) + + model = keras.models.Model([inputs] + initial_state, output) + model.compile(loss='categorical_crossentropy', optimizer='adam') + + inputs = np.random.random((num_samples, timesteps, input_size)) + initial_state = [ + np.random.random((num_samples, units)) for _ in range(num_states) + ] + targets = np.random.random((num_samples, units)) + model.fit([inputs] + initial_state, targets) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_statefulness(self, layer_class): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - - model = keras.models.Sequential() - model.add( - keras.layers.Embedding( - 10, - input_size, - input_length=timesteps, - batch_input_shape=(num_samples, timesteps))) - layer = layer_class( - units, return_sequences=False, stateful=True, weights=None) - model.add(layer) - model.compile(optimizer='sgd', loss='mse') - out1 = model.predict(np.ones((num_samples, timesteps))) - self.assertEqual(out1.shape, (num_samples, units)) - - # train once so that the states change - model.train_on_batch( - np.ones((num_samples, timesteps)), np.ones((num_samples, units))) - out2 = model.predict(np.ones((num_samples, timesteps))) - - # if the state is not reset, output should be different - self.assertNotEqual(out1.max(), out2.max()) - - # check that output changes after states are reset - # (even though the model itself didn't change) - layer.reset_states() - out3 = model.predict(np.ones((num_samples, timesteps))) - self.assertNotEqual(out2.max(), out3.max()) - - # check that container-level reset_states() works - model.reset_states() - out4 = model.predict(np.ones((num_samples, timesteps))) - self.assertAllClose(out3, out4, atol=1e-5) - - # check that the call to `predict` updated the states - out5 = model.predict(np.ones((num_samples, timesteps))) - self.assertNotEqual(out4.max(), out5.max()) + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + + model = keras.models.Sequential() + model.add( + keras.layers.Embedding( + 10, + input_size, + input_length=timesteps, + batch_input_shape=(num_samples, timesteps))) + layer = layer_class( + units, return_sequences=False, stateful=True, weights=None) + model.add(layer) + model.compile(optimizer='sgd', loss='mse') + out1 = model.predict(np.ones((num_samples, timesteps))) + self.assertEqual(out1.shape, (num_samples, units)) + + # train once so that the states change + model.train_on_batch( + np.ones((num_samples, timesteps)), np.ones((num_samples, units))) + out2 = model.predict(np.ones((num_samples, timesteps))) + + # if the state is not reset, output should be different + self.assertNotEqual(out1.max(), out2.max()) + + # check that output changes after states are reset + # (even though the model itself didn't change) + layer.reset_states() + out3 = model.predict(np.ones((num_samples, timesteps))) + self.assertNotEqual(out2.max(), out3.max()) + + # check that container-level reset_states() works + model.reset_states() + out4 = model.predict(np.ones((num_samples, timesteps))) + self.assertAllClose(out3, out4, atol=1e-5) + + # check that the call to `predict` updated the states + out5 = model.predict(np.ones((num_samples, timesteps))) + self.assertNotEqual(out4.max(), out5.max()) @parameterized.named_parameters( *test_util.generate_combinations_with_testcase_name( @@ -274,51 +254,49 @@ class CuDNNTest(test.TestCase, parameterized.TestCase): def test_load_weights_between_noncudnn_rnn(self, rnn_type, to_cudnn, bidirectional, implementation, model_nest_level, model_type): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - timesteps = 6 - input_shape = (timesteps, input_size) - units = 2 - num_samples = 32 - inputs = np.random.random((num_samples, timesteps, input_size)) - - rnn_layer_kwargs = { - 'recurrent_activation': 'sigmoid', - # ensure biases are non-zero and properly converted - 'bias_initializer': 'random_uniform', - 'implementation': implementation - } - if rnn_type == 'LSTM': - rnn_layer_class = keras.layers.LSTM - cudnn_rnn_layer_class = keras.layers.CuDNNLSTM - else: - rnn_layer_class = keras.layers.GRU - cudnn_rnn_layer_class = keras.layers.CuDNNGRU - rnn_layer_kwargs['reset_after'] = True - - layer = rnn_layer_class(units, **rnn_layer_kwargs) - if bidirectional: - layer = keras.layers.Bidirectional(layer) - - cudnn_layer = cudnn_rnn_layer_class(units) - if bidirectional: - cudnn_layer = keras.layers.Bidirectional(cudnn_layer) - - model = self._make_nested_model(input_shape, layer, model_nest_level, - model_type) - cudnn_model = self._make_nested_model(input_shape, cudnn_layer, - model_nest_level, model_type) - - if to_cudnn: - self._convert_model_weights(model, cudnn_model) - else: - self._convert_model_weights(cudnn_model, model) - - self.assertAllClose( - model.predict(inputs), cudnn_model.predict(inputs), atol=1e-4) + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + timesteps = 6 + input_shape = (timesteps, input_size) + units = 2 + num_samples = 32 + inputs = np.random.random((num_samples, timesteps, input_size)) + + rnn_layer_kwargs = { + 'recurrent_activation': 'sigmoid', + # ensure biases are non-zero and properly converted + 'bias_initializer': 'random_uniform', + 'implementation': implementation + } + if rnn_type == 'LSTM': + rnn_layer_class = keras.layers.LSTM + cudnn_rnn_layer_class = keras.layers.CuDNNLSTM + else: + rnn_layer_class = keras.layers.GRU + cudnn_rnn_layer_class = keras.layers.CuDNNGRU + rnn_layer_kwargs['reset_after'] = True + + layer = rnn_layer_class(units, **rnn_layer_kwargs) + if bidirectional: + layer = keras.layers.Bidirectional(layer) + + cudnn_layer = cudnn_rnn_layer_class(units) + if bidirectional: + cudnn_layer = keras.layers.Bidirectional(cudnn_layer) + + model = self._make_nested_model(input_shape, layer, model_nest_level, + model_type) + cudnn_model = self._make_nested_model(input_shape, cudnn_layer, + model_nest_level, model_type) + + if to_cudnn: + self._convert_model_weights(model, cudnn_model) + else: + self._convert_model_weights(cudnn_model, model) + + self.assertAllClose(model.predict(inputs), cudnn_model.predict(inputs), + atol=1e-4) def _make_nested_model(self, input_shape, layer, level=1, model_type='func'): # example: make_nested_seq_model((1,), Dense(10), level=2).summary() @@ -356,145 +334,149 @@ class CuDNNTest(test.TestCase, parameterized.TestCase): to_cudnn): # Similar test as test_load_weights_between_noncudnn_rnn() but has different # rank of input due to usage of TimeDistributed. Issue: #10356. - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_size = 10 - steps = 6 - timesteps = 6 - input_shape = (timesteps, steps, input_size) - units = 2 - num_samples = 32 - inputs = np.random.random((num_samples, timesteps, steps, input_size)) - - rnn_layer_kwargs = { - 'recurrent_activation': 'sigmoid', - # ensure biases are non-zero and properly converted - 'bias_initializer': 'random_uniform', - } - if rnn_type == 'LSTM': - rnn_layer_class = keras.layers.LSTM - cudnn_rnn_layer_class = keras.layers.CuDNNLSTM - else: - rnn_layer_class = keras.layers.GRU - cudnn_rnn_layer_class = keras.layers.CuDNNGRU - rnn_layer_kwargs['reset_after'] = True - - layer = rnn_layer_class(units, **rnn_layer_kwargs) - layer = keras.layers.TimeDistributed(layer) - - cudnn_layer = cudnn_rnn_layer_class(units) - cudnn_layer = keras.layers.TimeDistributed(cudnn_layer) - - model = self._make_nested_model(input_shape, layer) - cudnn_model = self._make_nested_model(input_shape, cudnn_layer) - - if to_cudnn: - self._convert_model_weights(model, cudnn_model) - else: - self._convert_model_weights(cudnn_model, model) - - self.assertAllClose( - model.predict(inputs), cudnn_model.predict(inputs), atol=1e-4) - + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_size = 10 + steps = 6 + timesteps = 6 + input_shape = (timesteps, steps, input_size) + units = 2 + num_samples = 32 + inputs = np.random.random((num_samples, timesteps, steps, input_size)) + + rnn_layer_kwargs = { + 'recurrent_activation': 'sigmoid', + # ensure biases are non-zero and properly converted + 'bias_initializer': 'random_uniform', + } + if rnn_type == 'LSTM': + rnn_layer_class = keras.layers.LSTM + cudnn_rnn_layer_class = keras.layers.CuDNNLSTM + else: + rnn_layer_class = keras.layers.GRU + cudnn_rnn_layer_class = keras.layers.CuDNNGRU + rnn_layer_kwargs['reset_after'] = True + + layer = rnn_layer_class(units, **rnn_layer_kwargs) + layer = keras.layers.TimeDistributed(layer) + + cudnn_layer = cudnn_rnn_layer_class(units) + cudnn_layer = keras.layers.TimeDistributed(cudnn_layer) + + model = self._make_nested_model(input_shape, layer) + cudnn_model = self._make_nested_model(input_shape, cudnn_layer) + + if to_cudnn: + self._convert_model_weights(model, cudnn_model) + else: + self._convert_model_weights(cudnn_model, model) + + self.assertAllClose(model.predict(inputs), cudnn_model.predict(inputs), + atol=1e-4) + + @test_util.run_in_graph_and_eager_modes def test_cudnnrnn_bidirectional(self): - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - rnn = keras.layers.CuDNNGRU - samples = 2 - dim = 2 - timesteps = 2 - output_dim = 2 - mode = 'concat' - - x = np.random.random((samples, timesteps, dim)) - target_dim = 2 * output_dim if mode == 'concat' else output_dim - y = np.random.random((samples, target_dim)) - - # test with Sequential model - model = keras.Sequential() - model.add( - keras.layers.Bidirectional( - rnn(output_dim), merge_mode=mode, input_shape=(None, dim))) - model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) - - # test config - model.get_config() - model = keras.models.model_from_json(model.to_json()) - model.summary() - - # test stacked bidirectional layers - model = keras.Sequential() - model.add( - keras.layers.Bidirectional( - rnn(output_dim, return_sequences=True), - merge_mode=mode, - input_shape=(None, dim))) - model.add(keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode)) - model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) - - # test with functional API - inputs = keras.Input((timesteps, dim)) - outputs = keras.layers.Bidirectional( - rnn(output_dim), merge_mode=mode)( - inputs) - model = keras.Model(inputs, outputs) - model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) - - # Bidirectional and stateful - inputs = keras.Input(batch_shape=(1, timesteps, dim)) - outputs = keras.layers.Bidirectional( - rnn(output_dim, stateful=True), merge_mode=mode)( - inputs) - model = keras.Model(inputs, outputs) - model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + rnn = keras.layers.CuDNNGRU + samples = 2 + dim = 2 + timesteps = 2 + output_dim = 2 + mode = 'concat' + + x = np.random.random((samples, timesteps, dim)) + target_dim = 2 * output_dim if mode == 'concat' else output_dim + y = np.random.random((samples, target_dim)) + + # test with Sequential model + model = keras.Sequential() + model.add( + keras.layers.Bidirectional( + rnn(output_dim), merge_mode=mode, input_shape=(None, dim))) + model.compile( + loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) + + # test config + model.get_config() + model = keras.models.model_from_json(model.to_json()) + model.summary() + + # test stacked bidirectional layers + model = keras.Sequential() + model.add( + keras.layers.Bidirectional( + rnn(output_dim, return_sequences=True), + merge_mode=mode, + input_shape=(None, dim))) + model.add(keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode)) + model.compile( + loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) + + # test with functional API + inputs = keras.Input((timesteps, dim)) + outputs = keras.layers.Bidirectional( + rnn(output_dim), merge_mode=mode)( + inputs) + model = keras.Model(inputs, outputs) + model.compile( + loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) + + # Bidirectional and stateful + inputs = keras.Input(batch_shape=(1, timesteps, dim)) + outputs = keras.layers.Bidirectional( + rnn(output_dim, stateful=True), merge_mode=mode)( + inputs) + model = keras.Model(inputs, outputs) + model.compile( + loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) def test_preprocess_weights_for_loading_gru_incompatible(self): """Test loading weights between incompatible layers. Should fail fast with an exception. """ - if not test.is_gpu_available(cuda_only=True): - self.skipTest('No CUDA GPU available') - - with test_util.use_gpu(): - input_shape = (3, 5) - - def gru(cudnn=False, **kwargs): - layer_class = keras.layers.CuDNNGRU if cudnn else keras.layers.GRU - return layer_class(2, input_shape=input_shape, **kwargs) - - def get_layer_weights(layer): - layer.build(input_shape=input_shape) - return layer.get_weights() - - def assert_not_compatible(src, dest, message): - with self.assertRaises(ValueError) as ex: - keras.engine.saving.preprocess_weights_for_loading( - dest, get_layer_weights(src)) - self.assertIn(message, str(ex.exception)) - - assert_not_compatible( - gru(), gru(cudnn=True), - 'GRU(reset_after=False) is not compatible with CuDNNGRU') - assert_not_compatible( - gru(cudnn=True), gru(), - 'CuDNNGRU is not compatible with GRU(reset_after=False)') - assert_not_compatible( - gru(), gru(reset_after=True), - 'GRU(reset_after=False) is not compatible with ' - 'GRU(reset_after=True)') - assert_not_compatible( - gru(reset_after=True), gru(), - 'GRU(reset_after=True) is not compatible with ' - 'GRU(reset_after=False)') + if test.is_gpu_available(cuda_only=True): + with self.session(use_gpu=True): + input_shape = (3, 5) + + def gru(cudnn=False, **kwargs): + layer_class = keras.layers.CuDNNGRU if cudnn else keras.layers.GRU + return layer_class(2, input_shape=input_shape, **kwargs) + + def get_layer_weights(layer): + layer.build(input_shape=input_shape) + return layer.get_weights() + + def assert_not_compatible(src, dest, message): + with self.assertRaises(ValueError) as ex: + keras.engine.saving.preprocess_weights_for_loading( + dest, + get_layer_weights(src)) + self.assertIn(message, str(ex.exception)) + + assert_not_compatible( + gru(), + gru(cudnn=True), + 'GRU(reset_after=False) is not compatible with CuDNNGRU') + assert_not_compatible( + gru(cudnn=True), + gru(), + 'CuDNNGRU is not compatible with GRU(reset_after=False)') + assert_not_compatible( + gru(), + gru(reset_after=True), + 'GRU(reset_after=False) is not compatible with ' + 'GRU(reset_after=True)') + assert_not_compatible( + gru(reset_after=True), + gru(), + 'GRU(reset_after=True) is not compatible with ' + 'GRU(reset_after=False)') if __name__ == '__main__': -- GitLab From a26f3b05986eaec30fa3d9547decbaa9607291dd Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Thu, 29 Nov 2018 13:30:32 -0800 Subject: [PATCH 572/672] Moves ClusterResolvers into tensorflow.python.distribute in preparation for TensorFlow 2.0 PiperOrigin-RevId: 223401165 --- tensorflow/contrib/cluster_resolver/BUILD | 162 +------ .../contrib/cluster_resolver/__init__.py | 16 +- .../cluster_resolver_initialization_test.py | 53 +++ .../python/training/__init__.py | 41 +- .../python/training/cluster_resolver.py | 368 +-------------- .../python/training/gce_cluster_resolver.py | 199 +------- .../training/kubernetes_cluster_resolver.py | 161 +------ .../python/training/slurm_cluster_resolver.py | 215 +-------- .../training/tfconfig_cluster_resolver.py | 159 +------ .../python/training/tpu_cluster_resolver.py | 414 +---------------- tensorflow/contrib/tpu/BUILD | 4 +- tensorflow/python/BUILD | 13 + tensorflow/python/distribute/BUILD | 1 + .../python/distribute/cluster_resolver/BUILD | 180 ++++++++ .../distribute}/cluster_resolver/README.md | 0 .../distribute/cluster_resolver}/README.slurm | 0 .../distribute/cluster_resolver/__init__.py | 57 +++ .../cluster_resolver/cluster_resolver.py | 374 ++++++++++++++++ .../cluster_resolver_test.py | 4 +- .../cluster_resolver/gce_cluster_resolver.py | 206 +++++++++ .../gce_cluster_resolver_test.py | 4 +- .../kubernetes_cluster_resolver.py | 173 +++++++ .../kubernetes_cluster_resolver_test.py | 2 +- .../slurm_cluster_resolver.py | 226 ++++++++++ .../slurm_cluster_resolver_test.py | 2 +- .../tfconfig_cluster_resolver.py | 171 +++++++ .../tfconfig_cluster_resolver_test.py | 2 +- .../cluster_resolver/tpu_cluster_resolver.py | 423 ++++++++++++++++++ .../tpu_cluster_resolver_test.py | 2 +- 29 files changed, 2014 insertions(+), 1618 deletions(-) create mode 100644 tensorflow/contrib/cluster_resolver/cluster_resolver_initialization_test.py create mode 100644 tensorflow/python/distribute/cluster_resolver/BUILD rename tensorflow/{contrib => python/distribute}/cluster_resolver/README.md (100%) rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/README.slurm (100%) create mode 100644 tensorflow/python/distribute/cluster_resolver/__init__.py create mode 100644 tensorflow/python/distribute/cluster_resolver/cluster_resolver.py rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/cluster_resolver_test.py (98%) create mode 100644 tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver.py rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/gce_cluster_resolver_test.py (98%) create mode 100644 tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver.py rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/kubernetes_cluster_resolver_test.py (98%) create mode 100644 tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver.py rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/slurm_cluster_resolver_test.py (98%) create mode 100644 tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver.py rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/tfconfig_cluster_resolver_test.py (98%) create mode 100644 tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver.py rename tensorflow/{contrib/cluster_resolver/python/training => python/distribute/cluster_resolver}/tpu_cluster_resolver_test.py (99%) diff --git a/tensorflow/contrib/cluster_resolver/BUILD b/tensorflow/contrib/cluster_resolver/BUILD index 9e1867ea9d..f944b7f884 100644 --- a/tensorflow/contrib/cluster_resolver/BUILD +++ b/tensorflow/contrib/cluster_resolver/BUILD @@ -21,173 +21,25 @@ py_library( py_library( name = "cluster_resolver_py", - srcs = [ + srcs = glob([ "__init__.py", - "python/training/__init__.py", - ], + "python/training/*.py", + ]), srcs_version = "PY2AND3", visibility = ["//visibility:public"], - deps = [ - ":base_cluster_resolver_py", - ":gce_cluster_resolver_py", - ":kubernetes_cluster_resolver_py", - ":slurm_cluster_resolver_py", - ":tfconfig_cluster_resolver_py", - ":tpu_cluster_resolver_py", - "//tensorflow/python:util", - ], -) - -py_library( - name = "base_cluster_resolver_py", - srcs = ["python/training/cluster_resolver.py"], - srcs_version = "PY2AND3", - deps = [ - "//tensorflow/python:training", - ], -) - -py_library( - name = "gce_cluster_resolver_py", - srcs = ["python/training/gce_cluster_resolver.py"], - srcs_version = "PY2AND3", - deps = [ - ":base_cluster_resolver_py", - "//tensorflow/python:training", - ], -) - -py_library( - name = "tfconfig_cluster_resolver_py", - srcs = ["python/training/tfconfig_cluster_resolver.py"], - srcs_version = "PY2AND3", - deps = [ - ":base_cluster_resolver_py", - "//tensorflow/python:training", - ], -) - -py_library( - name = "tpu_cluster_resolver_py", - srcs = ["python/training/tpu_cluster_resolver.py"], - srcs_version = "PY2AND3", - deps = [ - ":base_cluster_resolver_py", - "//tensorflow/python:training", - ], -) - -py_library( - name = "slurm_cluster_resolver_py", - srcs = ["python/training/slurm_cluster_resolver.py"], - srcs_version = "PY2AND3", - deps = [ - ":base_cluster_resolver_py", - "//tensorflow/python:training", - ], -) - -py_library( - name = "kubernetes_cluster_resolver_py", - srcs = ["python/training/kubernetes_cluster_resolver.py"], - srcs_version = "PY2AND3", - deps = [ - ":base_cluster_resolver_py", - "//tensorflow/python:training", - ], -) - -tf_py_test( - name = "base_cluster_resolver_py_test", - srcs = ["python/training/cluster_resolver_test.py"], - additional_deps = [ - ":cluster_resolver_py", - "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_for_generated_wrappers", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:platform_test", - "//tensorflow/python:training", - ], - main = "python/training/cluster_resolver_test.py", -) - -tf_py_test( - name = "gce_cluster_resolver_py_test", - size = "small", - srcs = ["python/training/gce_cluster_resolver_test.py"], - additional_deps = [ - ":cluster_resolver_py", - ":gce_cluster_resolver_py", - "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_for_generated_wrappers", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:platform_test", - "//tensorflow/python:training", - ], - main = "python/training/gce_cluster_resolver_test.py", -) - -tf_py_test( - name = "tfconfig_cluster_resolver_py_test", - size = "small", - srcs = ["python/training/tfconfig_cluster_resolver_test.py"], - additional_deps = [ - ":tfconfig_cluster_resolver_py", - "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_for_generated_wrappers", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:platform_test", - "//tensorflow/python:training", - ], - grpc_enabled = True, - main = "python/training/tfconfig_cluster_resolver_test.py", -) - -tf_py_test( - name = "tpu_cluster_resolver_py_test", - size = "small", - srcs = ["python/training/tpu_cluster_resolver_test.py"], - additional_deps = [ - ":tpu_cluster_resolver_py", - "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_for_generated_wrappers", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:platform_test", - "//tensorflow/python:training", - ], - grpc_enabled = True, - main = "python/training/tpu_cluster_resolver_test.py", -) - -tf_py_test( - name = "slurm_cluster_resolver_py_test", - size = "small", - srcs = ["python/training/slurm_cluster_resolver_test.py"], - additional_deps = [ - ":cluster_resolver_py", - ":slurm_cluster_resolver_py", - "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_for_generated_wrappers", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:platform_test", - "//tensorflow/python:training", - ], - main = "python/training/slurm_cluster_resolver_test.py", - tags = [], + deps = ["//tensorflow/python/distribute/cluster_resolver:cluster_resolver_lib"], ) tf_py_test( - name = "kubernetes_cluster_resolver_py_test", - size = "small", - srcs = ["python/training/kubernetes_cluster_resolver_test.py"], + name = "cluster_resolver_initialization_test", + srcs = ["cluster_resolver_initialization_test.py"], additional_deps = [ ":cluster_resolver_py", - ":kubernetes_cluster_resolver_py", "//tensorflow/python:client_testlib", "//tensorflow/python:framework_for_generated_wrappers", "//tensorflow/python:framework_test_lib", "//tensorflow/python:platform_test", "//tensorflow/python:training", ], - main = "python/training/kubernetes_cluster_resolver_test.py", + main = "cluster_resolver_initialization_test.py", ) diff --git a/tensorflow/contrib/cluster_resolver/__init__.py b/tensorflow/contrib/cluster_resolver/__init__.py index ab0746ab83..390b3e7550 100644 --- a/tensorflow/contrib/cluster_resolver/__init__.py +++ b/tensorflow/contrib/cluster_resolver/__init__.py @@ -20,14 +20,14 @@ from __future__ import division from __future__ import print_function # pylint: disable=wildcard-import,unused-import -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import SimpleClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import UnionClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.gce_cluster_resolver import GceClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.kubernetes_cluster_resolver import KubernetesClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.slurm_cluster_resolver import SlurmClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.tfconfig_cluster_resolver import TFConfigClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.tpu_cluster_resolver import TPUClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import SimpleClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import UnionClusterResolver +from tensorflow.python.distribute.cluster_resolver.gce_cluster_resolver import GceClusterResolver +from tensorflow.python.distribute.cluster_resolver.kubernetes_cluster_resolver import KubernetesClusterResolver +from tensorflow.python.distribute.cluster_resolver.slurm_cluster_resolver import SlurmClusterResolver +from tensorflow.python.distribute.cluster_resolver.tfconfig_cluster_resolver import TFConfigClusterResolver +from tensorflow.python.distribute.cluster_resolver.tpu_cluster_resolver import TPUClusterResolver # pylint: enable=wildcard-import,unused-import from tensorflow.python.util.all_util import remove_undocumented diff --git a/tensorflow/contrib/cluster_resolver/cluster_resolver_initialization_test.py b/tensorflow/contrib/cluster_resolver/cluster_resolver_initialization_test.py new file mode 100644 index 0000000000..01ff1478c6 --- /dev/null +++ b/tensorflow/contrib/cluster_resolver/cluster_resolver_initialization_test.py @@ -0,0 +1,53 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests to ensure ClusterResolvers are usable via the old contrib path.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.contrib.cluster_resolver import SimpleClusterResolver +from tensorflow.contrib.cluster_resolver.python.training import cluster_resolver +from tensorflow.contrib.cluster_resolver.python.training import UnionClusterResolver +from tensorflow.python.platform import test +from tensorflow.python.training import server_lib + + +class ClusterResolverInitializationTest(test.TestCase): + + def testCreateSimpleClusterResolverFromLib(self): + base_cluster_spec = server_lib.ClusterSpec({ + "ps": ["ps0:2222", "ps1:2222"], + "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] + }) + cluster_resolver.SimpleClusterResolver(base_cluster_spec) + + def testCreateSimpleClusterResolver(self): + base_cluster_spec = server_lib.ClusterSpec({ + "ps": ["ps0:2222", "ps1:2222"], + "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] + }) + SimpleClusterResolver(base_cluster_spec) + + def testCreateUnionClusterResolver(self): + base_cluster_spec = server_lib.ClusterSpec({ + "ps": ["ps0:2222", "ps1:2222"], + "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] + }) + simple_cr = SimpleClusterResolver(base_cluster_spec) + UnionClusterResolver(simple_cr) + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/contrib/cluster_resolver/python/training/__init__.py b/tensorflow/contrib/cluster_resolver/python/training/__init__.py index 6d9120a3b9..10d93549eb 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/__init__.py +++ b/tensorflow/contrib/cluster_resolver/python/training/__init__.py @@ -18,11 +18,36 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import SimpleClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import UnionClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.gce_cluster_resolver import GceClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.kubernetes_cluster_resolver import KubernetesClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.slurm_cluster_resolver import SlurmClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.tfconfig_cluster_resolver import TFConfigClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.tpu_cluster_resolver import TPUClusterResolver +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. + +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import SimpleClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import UnionClusterResolver +from tensorflow.python.distribute.cluster_resolver.gce_cluster_resolver import GceClusterResolver +from tensorflow.python.distribute.cluster_resolver.kubernetes_cluster_resolver import KubernetesClusterResolver +from tensorflow.python.distribute.cluster_resolver.slurm_cluster_resolver import SlurmClusterResolver +from tensorflow.python.distribute.cluster_resolver.tfconfig_cluster_resolver import TFConfigClusterResolver +from tensorflow.python.distribute.cluster_resolver.tpu_cluster_resolver import TPUClusterResolver + +from tensorflow.python.util.all_util import remove_undocumented + +_allowed_symbols = [ + 'cluster_resolver', + 'gce_cluster_resolver', + 'kubernetes_cluster_resolver', + 'slurm_cluster_resolver', + 'tfconfig_cluster_resolver', + 'tpu_cluster_resolver', + 'ClusterResolver', + 'SimpleClusterResolver', + 'UnionClusterResolver', + 'GceClusterResolver', + 'KubernetesClusterResolver', + 'TFConfigClusterResolver', + 'TPUClusterResolver', + 'SlurmClusterResolver', +] + +remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/cluster_resolver/python/training/cluster_resolver.py b/tensorflow/contrib/cluster_resolver/python/training/cluster_resolver.py index 7774ac0e12..99840fb516 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/cluster_resolver.py +++ b/tensorflow/contrib/cluster_resolver/python/training/cluster_resolver.py @@ -1,4 +1,4 @@ -# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# Copyright 2018 The TensorFlow Authors. 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. @@ -12,363 +12,29 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Cluster Resolvers are used for dynamic cluster IP/hostname resolution.""" +"""Stub file for ClusterResolver to maintain backwards compatibility.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import abc +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. -import six +# pylint: disable=unused-import +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import SimpleClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import UnionClusterResolver +# pylint: enable=unused-import -from tensorflow.python.training.server_lib import ClusterSpec +from tensorflow.python.util.all_util import remove_undocumented +_allowed_symbols = [ + 'ClusterResolver', + 'SimpleClusterResolver', + 'UnionClusterResolver', +] -def format_master_url(master, rpc_layer=None): - if rpc_layer: - return '%s://%s' % (rpc_layer, master) - else: - return master +remove_undocumented(__name__, _allowed_symbols) - -@six.add_metaclass(abc.ABCMeta) -class ClusterResolver(object): - """Abstract class for all implementations of ClusterResolvers. - - This defines the skeleton for all implementations of ClusterResolvers. - ClusterResolvers are a way for TensorFlow to communicate with various cluster - management systems (e.g. GCE, AWS, etc...). - - By letting TensorFlow communicate with these systems, we will be able to - automatically discover and resolve IP addresses for various TensorFlow - workers. This will eventually allow us to automatically recover from - underlying machine failures and scale TensorFlow worker clusters up and down. - - Note to Implementors: In addition to these abstract methods, you must also - implement the task_type, task_index, and rpc_layer attributes. You may choose - to implement them either as properties with getters or setters or directly - set the attributes. - - - task_type is the name of the server's current named job (e.g. 'worker', - 'ps' in a distributed parameterized training job). - - task_index is the ordinal index of the server within the task type. - - rpc_layer is the protocol used by TensorFlow to communicate with other - TensorFlow servers in a distributed environment. - """ - - @abc.abstractmethod - def cluster_spec(self): - """Retrieve the current state of the cluster and returns a ClusterSpec. - - Returns: - A ClusterSpec representing the state of the cluster at the moment this - function is called. - - Implementors of this function must take care in ensuring that the - ClusterSpec returned is up-to-date at the time of calling this function. - This usually means retrieving the information from the underlying cluster - management system every time this function is invoked and reconstructing - a cluster_spec, rather than attempting to cache anything. - """ - raise NotImplementedError() - - @abc.abstractmethod - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Retrieves the name or URL of the session master. - - Args: - task_type: (Optional) The type of the TensorFlow task of the master. - task_index: (Optional) The index of the TensorFlow task of the master. - rpc_layer: (Optional) The RPC protocol for the given cluster. - - Returns: - The name or URL of the session master. - - Implementors of this function must take care in ensuring that the master - returned is up-to-date at the time to calling this function. This usually - means retrieving the master every time this function is invoked. - """ - raise NotImplementedError() - - @abc.abstractmethod - def num_accelerators_per_worker(self, session_config=None): - """Returns the number of accelerator cores per worker. - - This returns the number of accelerator cores (such as GPUs and TPUs) - available per worker. If workers only has CPU cores available, then this - should return 0. This method will query the master for this information - if it is not otherwise known. - - Args: - session_config: (Optional) Configuration for starting a new session to - query how many accelerator cores it has. - """ - raise NotImplementedError() - - @abc.abstractproperty - def environment(self): - """Returns the current environment which TensorFlow is running in.""" - raise NotImplementedError() - - -class SimpleClusterResolver(ClusterResolver): - """Simple implementation of ClusterResolver that accepts a ClusterSpec.""" - - def __init__(self, cluster_spec, master='', task_type=None, task_index=None, - environment='', num_accelerators_per_worker=0, - rpc_layer=None): - """Creates a SimpleClusterResolver from a ClusterSpec.""" - super(SimpleClusterResolver, self).__init__() - - self._task_type = task_type - self._task_index = task_index - self._environment = environment - self._num_accelerators_per_worker = num_accelerators_per_worker - self._rpc_layer = rpc_layer - - if not isinstance(cluster_spec, ClusterSpec): - raise TypeError('cluster_spec must be a ClusterSpec.') - self._cluster_spec = cluster_spec - - if not isinstance(master, str): - raise TypeError('master must be a string.') - self._master = master - - def cluster_spec(self): - """Returns the ClusterSpec passed into the constructor.""" - return self._cluster_spec - - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Returns the master address to use when creating a session. - - Args: - task_type: (Optional) The type of the TensorFlow task of the master. - task_index: (Optional) The index of the TensorFlow task of the master. - rpc_layer: (Optional) The RPC used by distributed TensorFlow. - - Returns: - The name or URL of the session master. - - If a task_type and task_index is given, this will override the `master` - string passed into the initialization function. - """ - if task_type is not None and task_index is not None: - master = self.cluster_spec().task_address(task_type, task_index) - else: - master = self._master - - return format_master_url(master, rpc_layer=rpc_layer or self._rpc_layer) - - @property - def task_type(self): - return self._task_type - - @property - def task_index(self): - return self._task_index - - @task_type.setter - def task_type(self, task_type): - self._task_type = task_type - - @task_index.setter - def task_index(self, task_index): - self._task_index = task_index - - @property - def environment(self): - return self._environment - - def num_accelerators_per_worker(self, session_config=None): - """Returns the number of accelerator cores per worker. - - Args: - session_config: Unused. The SimpleClusterResolver does not do automatic - detection of accelerators, so a TensorFlow session will never be - created, and thus a `session_config` is never necessary here, and will - be ignored. - """ - del session_config - return self._num_accelerators_per_worker - - @property - def rpc_layer(self): - return self._rpc_layer - - @rpc_layer.setter - def rpc_layer(self, rpc_layer): - self._rpc_layer = rpc_layer - - -class UnionClusterResolver(ClusterResolver): - """Performs a union on underlying ClusterResolvers. - - This class performs a union given two or more existing ClusterResolvers. It - merges the underlying ClusterResolvers, and returns one unified ClusterSpec - when cluster_spec is called. The details of the merge function is - documented in the cluster_spec function. - - For additional Cluster Resolver properties such as task type, task index, - rpc layer, environment, etc..., we will return the value from the first - ClusterResolver in the union. - """ - - def __init__(self, *args, **kwargs): - """Initializes a UnionClusterResolver with other ClusterResolvers. - - Args: - *args: `ClusterResolver` objects to be unionized. - **kwargs: - rpc_layer - (Optional) Override value for the RPC layer used by - TensorFlow. - task_type - (Optional) Override value for the current task type. - task_index - (Optional) Override value for the current task index. - - Raises: - TypeError: If any argument is not a subclass of `ClusterResolvers`. - ValueError: If there are no arguments passed. - """ - super(UnionClusterResolver, self).__init__() - - self._rpc_layer = kwargs.pop('rpc_layer', None) - self._task_type = kwargs.pop('task_type', None) - self._task_index = kwargs.pop('task_index', None) - - if kwargs: - raise ValueError('Unexpected kwargs provided {!r}'.format(kwargs)) - - if not args: - raise ValueError('At least one ClusterResolver is required.') - - for cluster_resolver in args: - if not isinstance(cluster_resolver, ClusterResolver): - raise TypeError('All arguments must be a sub-class of ' - '`ClusterResolver.`') - self._cluster_resolvers = args - - def cluster_spec(self): - """Returns a union of all the ClusterSpecs from the ClusterResolvers. - - Returns: - A ClusterSpec containing host information merged from all the underlying - ClusterResolvers. - - Raises: - KeyError: If there are conflicting keys detected when merging two or - more dictionaries, this exception is raised. - - Note: If there are multiple ClusterResolvers exposing ClusterSpecs with the - same job name, we will merge the list/dict of workers. - - If *all* underlying ClusterSpecs expose the set of workers as lists, we will - concatenate the lists of workers, starting with the list of workers from - the first ClusterResolver passed into the constructor. - - If *any* of the ClusterSpecs expose the set of workers as a dict, we will - treat all the sets of workers as dicts (even if they are returned as lists) - and will only merge them into a dict if there is no conflicting keys. If - there is a conflicting key, we will raise a `KeyError`. - """ - - merged_cluster = {} - - # We figure out whether it is all lists for a particular job, or whether - # there are dicts inside. - for cluster_resolver in self._cluster_resolvers: - cluster_spec = cluster_resolver.cluster_spec() - cluster_dict = cluster_spec.as_dict() - - for job_name, tasks in cluster_dict.items(): - if job_name in merged_cluster: - # If we see a dict, then we write a dict out regardless. - if isinstance(tasks, dict): - merged_cluster[job_name] = {} - else: - # We take whichever type is present. - if isinstance(tasks, list): - merged_cluster[job_name] = [] - else: - merged_cluster[job_name] = {} - - # We then do the merge as appropriate in merged_cluster[job]. - for cluster_resolver in self._cluster_resolvers: - cluster_spec = cluster_resolver.cluster_spec() - cluster_dict = cluster_spec.as_dict() - - for job_name, tasks in cluster_dict.items(): - if isinstance(merged_cluster[job_name], list): - # We all have lists, we can just concatenate and be done. - merged_cluster[job_name].extend(tasks) - else: - if isinstance(tasks, list): - # We convert to a dictionary if the type is a list. - task_dict = dict(zip(range(0, len(tasks)), tasks)) - else: - # We can simply make a copy (for update) and be done. - task_dict = tasks.copy() - - # We detect if there are duplicates, and raise an error if so. - task_keys = set(task_dict) - merged_keys = set(merged_cluster[job_name].keys()) - intersected_keys = task_keys.intersection(merged_keys) - if intersected_keys: - raise KeyError('Duplicate keys detected when merging two ' - 'ClusterSpecs: %s' % repr(intersected_keys)) - - # We do the merge after all the processing. - merged_cluster[job_name].update(task_dict) - - return ClusterSpec(merged_cluster) - - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Returns the master address to use when creating a session. - - This usually returns the master from the first ClusterResolver passed in, - but you can override this by specifying the task_type and task_index. - - Args: - task_type: (Optional) The type of the TensorFlow task of the master. - task_index: (Optional) The index of the TensorFlow task of the master. - rpc_layer: (Optional) The RPC protocol for the given cluster. - - Returns: - The name or URL of the session master. - """ - if task_type is not None and task_index is not None: - master = self.cluster_spec().task_address(task_type, task_index) - return format_master_url(master, rpc_layer or self._rpc_layer) - - return self._cluster_resolvers[0].master(rpc_layer=rpc_layer) - - @property - def task_type(self): - return self._task_type or self._cluster_resolvers[0].task_type - - @property - def task_index(self): - return self._task_index or self._cluster_resolvers[0].task_index - - @task_type.setter - def task_type(self, task_type): - self._task_type = task_type - - @task_index.setter - def task_index(self, task_index): - self._task_index = task_index - - @property - def environment(self): - return self._cluster_resolvers[0].environment - - def num_accelerators_per_worker(self, session_config=None): - return self._cluster_resolvers[0].num_accelerators_per_worker( - session_config) - - @property - def rpc_layer(self): - return self._rpc_layer or self._cluster_resolvers[0].rpc_layer - - @rpc_layer.setter - def rpc_layer(self, rpc_layer): - self._rpc_layer = rpc_layer diff --git a/tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver.py b/tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver.py index 195b68959b..55e61155c6 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver.py +++ b/tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver.py @@ -1,4 +1,4 @@ -# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# Copyright 2018 The TensorFlow Authors. 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. @@ -12,197 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Implementation of Cluster Resolvers for GCE Instance Groups.""" +"""Stub file for GceClusterResolver to maintain backwards compatibility.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.python.training.server_lib import ClusterSpec +# pylint: disable=unused-import +from tensorflow.python.distribute.cluster_resolver.gce_cluster_resolver import GceClusterResolver +# pylint: enable=unused-import -_GOOGLE_API_CLIENT_INSTALLED = True -try: - from googleapiclient import discovery # pylint: disable=g-import-not-at-top - from oauth2client.client import GoogleCredentials # pylint: disable=g-import-not-at-top -except ImportError: - _GOOGLE_API_CLIENT_INSTALLED = False +from tensorflow.python.util.all_util import remove_undocumented +_allowed_symbols = [ + 'GceClusterResolver', +] -def _format_master_url(master, rpc_layer=None): - return '%s://%s' % (rpc_layer, master) if rpc_layer else master - - -class GceClusterResolver(ClusterResolver): - """Cluster Resolver for Google Compute Engine. - - This is an implementation of cluster resolvers for the Google Compute Engine - instance group platform. By specifying a project, zone, and instance group, - this will retrieve the IP address of all the instances within the instance - group and return a Cluster Resolver object suitable for use for distributed - TensorFlow. - """ - - def __init__(self, - project, - zone, - instance_group, - port, - task_type='worker', - task_index=0, - rpc_layer='grpc', - num_accelerators_per_worker=0, - credentials='default', - service=None): - """Creates a new GceClusterResolver object. - - This takes in a few parameters and creates a GceClusterResolver project. It - will then use these parameters to query the GCE API for the IP addresses of - each instance in the instance group. - - Args: - project: Name of the GCE project. - zone: Zone of the GCE instance group. - instance_group: Name of the GCE instance group. - port: Port of the listening TensorFlow server (default: 8470) - task_type: Name of the TensorFlow job this GCE instance group of VM - instances belong to. - task_index: The task index for this particular VM, within the GCE - instance group. In particular, every single instance should be assigned - a unique ordinal index within an instance group manually so that they - can be distinguished from each other. - rpc_layer: The RPC layer TensorFlow should use to communicate across - instances. - num_accelerators_per_worker: Number of accelerators (GPUs) present per - instance. - credentials: GCE Credentials. If nothing is specified, this defaults to - GoogleCredentials.get_application_default(). - service: The GCE API object returned by the googleapiclient.discovery - function. (Default: discovery.build('compute', 'v1')). If you specify a - custom service object, then the credentials parameter will be ignored. - - Raises: - ImportError: If the googleapiclient is not installed. - """ - self._project = project - self._zone = zone - self._instance_group = instance_group - self._task_type = task_type - self._task_index = task_index - self._rpc_layer = rpc_layer - self._port = port - self._credentials = credentials - - if credentials == 'default': - if _GOOGLE_API_CLIENT_INSTALLED: - self._credentials = GoogleCredentials.get_application_default() - - if service is None: - if not _GOOGLE_API_CLIENT_INSTALLED: - raise ImportError('googleapiclient must be installed before using the ' - 'GCE cluster resolver') - self._service = discovery.build( - 'compute', 'v1', - credentials=self._credentials) - else: - self._service = service - - def cluster_spec(self): - """Returns a ClusterSpec object based on the latest instance group info. - - This returns a ClusterSpec object for use based on information from the - specified instance group. We will retrieve the information from the GCE APIs - every time this method is called. - - Returns: - A ClusterSpec containing host information retrieved from GCE. - """ - request_body = {'instanceState': 'RUNNING'} - request = self._service.instanceGroups().listInstances( - project=self._project, - zone=self._zone, - instanceGroups=self._instance_group, - body=request_body, - orderBy='name') - - worker_list = [] - - while request is not None: - response = request.execute() - - items = response['items'] - for instance in items: - instance_name = instance['instance'].split('/')[-1] - - instance_request = self._service.instances().get( - project=self._project, - zone=self._zone, - instance=instance_name) - - if instance_request is not None: - instance_details = instance_request.execute() - ip_address = instance_details['networkInterfaces'][0]['networkIP'] - instance_url = '%s:%s' % (ip_address, self._port) - worker_list.append(instance_url) - - request = self._service.instanceGroups().listInstances_next( - previous_request=request, - previous_response=response) - - worker_list.sort() - return ClusterSpec({self._task_type: worker_list}) - - def master(self, task_type=None, task_index=None, rpc_layer=None): - task_type = task_type if task_type is not None else self._task_type - task_index = task_index if task_index is not None else self._task_index - - if task_type is not None and task_index is not None: - master = self.cluster_spec().task_address(task_type, task_index) - if rpc_layer or self._rpc_layer: - return '%s://%s' % (rpc_layer or self._rpc_layer, master) - else: - return master - - return '' - - @property - def task_type(self): - return self._task_type - - @property - def task_index(self): - return self._task_index - - @task_type.setter - def task_type(self, task_type): - raise RuntimeError( - 'You cannot reset the task_type of the GceClusterResolver after it has ' - 'been created.') - - @task_index.setter - def task_index(self, task_index): - self._task_index = task_index - - @property - def environment(self): - """Returns the current environment which TensorFlow is running in. - - For users in the GCE environment, the environment property is always an - empty string, and Google users will not use this ClusterResolver for running - on internal systems. - """ - return '' - - @property - def rpc_layer(self): - return self._rpc_layer - - @rpc_layer.setter - def rpc_layer(self, rpc_layer): - self._rpc_layer = rpc_layer - - def num_accelerators_per_worker(self, session_config=None): - del session_config # Unused, since this is set manually in __init__. - return self._num_accelerators_per_worker - +remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver.py b/tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver.py index eab1359a5b..a8eaf33629 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver.py +++ b/tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver.py @@ -12,162 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Implementation of Cluster Resolvers for Kubernetes.""" +"""Stub file for KubernetesClusterResolver for backwards compatibility.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import format_master_url -from tensorflow.python.client import device_lib -from tensorflow.python.training import server_lib +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. -_KUBERNETES_API_CLIENT_INSTALLED = True -try: - from kubernetes import client as k8sclient # pylint: disable=g-import-not-at-top - from kubernetes import config as k8sconfig # pylint: disable=g-import-not-at-top -except ImportError: - _KUBERNETES_API_CLIENT_INSTALLED = False +# pylint: disable=unused-import +from tensorflow.python.distribute.cluster_resolver.kubernetes_cluster_resolver import KubernetesClusterResolver +# pylint: enable=unused-import +from tensorflow.python.util.all_util import remove_undocumented -class KubernetesClusterResolver(ClusterResolver): - """Cluster Resolver for Kubernetes. +_allowed_symbols = [ + 'KubernetesClusterResolver', +] - This is an implementation of cluster resolvers for Kubernetes. When given the - the Kubernetes namespace and label selector for pods, we will retrieve the - pod IP addresses of all running pods matching the selector, and return a - ClusterSpec based on that information. - """ +remove_undocumented(__name__, _allowed_symbols) - def __init__(self, - job_to_label_mapping=None, - tf_server_port=8470, - rpc_layer='grpc', - override_client=None): - """Initializes a new KubernetesClusterResolver. - - This initializes a new Kubernetes Cluster Resolver. The Cluster Resolver - will attempt to talk to the Kubernetes master to retrieve all the instances - of pods matching a label selector. - - Args: - job_to_label_mapping: A mapping of TensorFlow jobs to label selectors. - This allows users to specify many TensorFlow jobs in one Cluster - Resolver, and each job can have pods belong with different label - selectors. For example, a sample mapping might be - ``` - {'worker': ['job-name=worker-cluster-a', 'job-name=worker-cluster-b'], - 'ps': ['job-name=ps-1', 'job-name=ps-2']} - ``` - tf_server_port: The port the TensorFlow server is listening on. - rpc_layer: (Optional) The RPC layer TensorFlow should use to communicate - between tasks in Kubernetes. Defaults to 'grpc'. - override_client: The Kubernetes client (usually automatically retrieved - using `from kubernetes import client as k8sclient`). If you pass this - in, you are responsible for setting Kubernetes credentials manually. - - Raises: - ImportError: If the Kubernetes Python client is not installed and no - `override_client` is passed in. - RuntimeError: If autoresolve_task is not a boolean or a callable. - """ - if _KUBERNETES_API_CLIENT_INSTALLED: - k8sconfig.load_kube_config() - - if not job_to_label_mapping: - job_to_label_mapping = {'worker': ['job-name=tensorflow']} - - if not override_client and not _KUBERNETES_API_CLIENT_INSTALLED: - raise ImportError('The Kubernetes Python client must be installed before' - 'using the Kubernetes Cluster Resolver. To install the' - 'Kubernetes Python client, run `pip install ' - 'kubernetes` on your command line.') - - self._job_to_label_mapping = job_to_label_mapping - self._tf_server_port = tf_server_port - self._override_client = override_client - - self.task_type = None - self.task_index = None - self.rpc_layer = rpc_layer - - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Returns the master address to use when creating a session. - - You must have set the task_type and task_index object properties before - calling this function, or pass in the `task_type` and `task_index` - parameters when using this function. If you do both, the function parameters - will override the object properties. - - Args: - task_type: (Optional) The type of the TensorFlow task of the master. - task_index: (Optional) The index of the TensorFlow task of the master. - rpc_layer: (Optional) The RPC protocol for the given cluster. - - Returns: - The name or URL of the session master. - """ - if task_type is not None and task_index is not None: - return format_master_url( - self.cluster_spec().task_address(task_type, task_index), - rpc_layer or self.rpc_layer) - - if self.task_type is not None and self.task_index is not None: - return format_master_url( - self.cluster_spec().task_address(self.task_type, self.task_index), - rpc_layer or self.rpc_layer) - - return '' - - def cluster_spec(self): - """Returns a ClusterSpec object based on the latest info from Kubernetes. - - We retrieve the information from the Kubernetes master every time this - method is called. - - Returns: - A ClusterSpec containing host information returned from Kubernetes. - - Raises: - RuntimeError: If any of the pods returned by the master is not in the - `Running` phase. - """ - if not self._override_client: - k8sconfig.load_kube_config() - - client = self._override_client or k8sclient.CoreV1Api() - cluster_map = {} - - for tf_job in self._job_to_label_mapping: - all_pods = [] - for selector in self._job_to_label_mapping[tf_job]: - ret = client.list_pod_for_all_namespaces(label_selector=selector) - selected_pods = [] - - # Sort the list by the name to make sure it doesn't change call to call. - for pod in sorted(ret.items, key=lambda x: x.metadata.name): - if pod.status.phase == 'Running': - selected_pods.append( - '%s:%s' % (pod.status.host_ip, self._tf_server_port)) - else: - raise RuntimeError('Pod "%s" is not running; phase: "%s"' % - (pod.metadata.name, pod.status.phase)) - all_pods.extend(selected_pods) - cluster_map[tf_job] = all_pods - - return server_lib.ClusterSpec(cluster_map) - - @property - def environment(self): - """Returns the current environment which TensorFlow is running in. - - For users in the Cloud environment, the environment property is always an - empty string, and Google users will not use this ClusterResolver for running - on internal systems. - """ - return '' - - def num_accelerators_per_worker(self, session_config=None): - local_devices = device_lib.list_local_devices(session_config) - return len([d for d in local_devices if d.device_type == 'GPU']) diff --git a/tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver.py b/tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver.py index f590ecead9..fcd2a846ee 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver.py +++ b/tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver.py @@ -12,215 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Implementation of Cluster Resolvers for Slurm workload manager.""" +"""Stub file for SlurmClusterResolver to maintain backwards compatibility.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import collections -import os -import subprocess +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.python.training.server_lib import ClusterSpec +# pylint: disable=unused-import +from tensorflow.python.distribute.cluster_resolver.slurm_cluster_resolver import SlurmClusterResolver +# pylint: enable=unused-import +from tensorflow.python.util.all_util import remove_undocumented -class SlurmClusterResolver(ClusterResolver): - """Cluster Resolver for system with Slurm workload manager. +_allowed_symbols = [ + 'SlurmClusterResolver', +] - This is an implementation of cluster resolvers for Slurm clusters. This allows - the specification of jobs and task counts, number of tasks per node, number of - GPUs on each node and number of GPUs for each task, It retrieves system - attributes by Slurm environment variables, resolves allocated computing node - names, construct a cluster and return a Cluster Resolver object which an be - use for distributed TensorFlow. - """ - - def _resolve_hostnames(self): - """Resolve host names of nodes allocated in current jobs. - - Returns: - A list of node names as strings. - """ - hostlist = (subprocess.check_output(['scontrol', 'show', 'hostname']). - decode('utf-8').strip().split('\n')) - return hostlist - - def __init__(self, - jobs, - port_base=8888, - gpus_per_node=1, - gpus_per_task=1, - tasks_per_node=None, - auto_set_gpu=True, - rpc_layer='grpc'): - """Creates a new SlurmClusterResolver object. - - This takes in parameters and creates a SlurmClusterResolver object. It uses - those parameters to check which nodes will processes reside and resolves - their hostnames. With the number of the GPUs on each node and number of GPUs - for each task it offsets the port number for each processes and allocate - GPUs to tasks by setting environment variables. The resolver currently - supports homogeneous tasks and default Slurm process allocation. - - Args: - jobs: Dictionary with job names as key and number of tasks in the job as - value - port_base: The first port number to start with for processes on a node. - gpus_per_node: Number of GPUs available on each node. - gpus_per_task: Number of GPUs to be used for each task. - tasks_per_node: Number of tasks to run on each node, if not set defaults - to Slurm's output environment variable SLURM_NTASKS_PER_NODE. - auto_set_gpu: Set the visible CUDA devices automatically while resolving - the cluster by setting CUDA_VISIBLE_DEVICES environment variable. - Defaults to True. - rpc_layer: (Optional) The protocol TensorFlow uses to communicate between - nodes. Defaults to 'grpc'. - - Returns: - A ClusterResolver object which can be used with distributed TensorFlow. - - Raises: - RuntimeError: If requested more GPUs per node then available or requested - more tasks then assigned tasks. - """ - - # check if launched by mpirun - if 'OMPI_COMM_WORLD_RANK' in os.environ: - self._rank = int(os.environ['OMPI_COMM_WORLD_RANK']) - num_tasks = int(os.environ['OMPI_COMM_WORLD_SIZE']) - else: - self._rank = int(os.environ['SLURM_PROCID']) - num_tasks = int(os.environ['SLURM_NTASKS']) - - self._jobs = collections.OrderedDict(sorted(jobs.items())) - self._port_base = port_base - - # user specification overrides SLURM specification - if tasks_per_node is not None: - self._tasks_per_node = tasks_per_node - elif tasks_per_node is None and 'SLURM_NTASKS_PER_NODE' in os.environ: - self._tasks_per_node = int(os.environ['SLURM_NTASKS_PER_NODE']) - else: - raise RuntimeError('Neither `tasks_per_node` or ' - 'SLURM_NTASKS_PER_NODE is set.') - - self._gpus_per_node = gpus_per_node - self._gpus_per_task = gpus_per_task - - self._auto_set_gpu = auto_set_gpu - self.task_type = None - self.task_index = None - self.rpc_layer = rpc_layer - - self._gpu_allocation = [] - self._cluster_allocation = {} - - if self._tasks_per_node * self._gpus_per_task > self._gpus_per_node: - raise RuntimeError('Requested more GPUs per node then available.') - - if sum(self._jobs.values()) != num_tasks: - raise RuntimeError('Requested more tasks then assigned tasks.') - - def cluster_spec(self): - """Returns a ClusterSpec object based on the latest instance group info. - - This returns a ClusterSpec object for use based on information from the - specified initialization parameters and Slurm environment variables. The - cluster specification is resolved each time this function is called. The - resolver extract hostnames of nodes by scontrol and pack tasks in that - order until a node a has number of tasks that is equal to specification. - GPUs on nodes are allocated to tasks by specification through setting - CUDA_VISIBLE_DEVICES environment variable. - - Returns: - A ClusterSpec containing host information retrieved from Slurm's - environment variables. - """ - hostlist = self._resolve_hostnames() - - task_list = [] - self._gpu_allocation = [] - self._cluster_allocation = {} - - for host in hostlist: - for port_offset, gpu_offset in zip( - range(self._tasks_per_node), - range(0, self._gpus_per_node, self._gpus_per_task)): - - host_addr = '%s:%d' % (host, self._port_base + port_offset) - task_list.append(host_addr) - gpu_id_list = [] - - for gpu_id in range(gpu_offset, gpu_offset + self._gpus_per_task): - gpu_id_list.append(str(gpu_id)) - - self._gpu_allocation.append(','.join(gpu_id_list)) - - cluster_rank_offset_start = 0 - cluster_rank_offset_end = 0 - - for task_type, num_tasks in self._jobs.items(): - cluster_rank_offset_end = cluster_rank_offset_start + num_tasks - - self._cluster_allocation[task_type] = ( - task_list[cluster_rank_offset_start:cluster_rank_offset_end]) - - if cluster_rank_offset_start <= self._rank < cluster_rank_offset_end: - self.task_type = task_type - self.task_index = self._rank - cluster_rank_offset_start - - cluster_rank_offset_start = cluster_rank_offset_end - - if self._auto_set_gpu is True: - os.environ['CUDA_VISIBLE_DEVICES'] = self._gpu_allocation[self._rank] - - return ClusterSpec(self._cluster_allocation) - - def get_task_info(self): - """Returns job name and task_index for the process which calls this. - - This returns the job name and task index for the process which calls this - function according to its rank and cluster specification. The job name and - task index are set after a cluster is constructed by cluster_spec otherwise - defaults to None. - - Returns: - A string specifying job name the process belongs to and an integner - specifying the task index the process belongs to in that job. - """ - return self.task_type, self.task_index - - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Returns the master string for connecting to a TensorFlow master. - - Args: - task_type: (Optional) Overrides the default auto-selected task type. - task_index: (Optional) Overrides the default auto-slected task index. - rpc_layer: (Optional) Overrides the default RPC protocol TensorFlow uses - to communicate across nodes. - - Returns: - A connection string for connecting to a TensorFlow master. - """ - task_type = task_type if task_type is not None else self.task_type - task_index = task_index if task_index is not None else self.task_index - rpc_layer = rpc_layer or self.rpc_layer - master = self.cluster_spec().task_address(task_type, task_index) - - return '%s://%s' % (rpc_layer, master) if rpc_layer else master - - @property - def environment(self): - """Returns the current environment which TensorFlow is running in. - - For users in the Slurm environment, the environment property is always an - empty string, and Google users will not use this ClusterResolver for running - on internal systems. - """ - return '' - - def num_accelerators_per_worker(self, session_config=None): - del session_config # Unused, since this is set in __init__ manually. - return self._gpus_per_node +remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver.py b/tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver.py index 95aad0de13..9db7f47dcb 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver.py +++ b/tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver.py @@ -12,160 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Implementation of Cluster Resolvers for TF_CONFIG Environment Variables.""" - +"""Stub file for TFConfigClusterResolver to maintain backwards compatibility.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import json -import os - -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.python.training.server_lib import ClusterSpec - -_TF_CONFIG_ENV = 'TF_CONFIG' -_SESSION_MASTER_KEY = 'session_master' -_RPC_LAYER_KEY = 'rpc_layer' -_TASK_KEY = 'task' - - -def format_master_url(master, rpc_layer=None): - if rpc_layer: - return '%s://%s' % (rpc_layer, master) - else: - return master - - -def _load_tf_config(): - return json.loads(os.environ.get(_TF_CONFIG_ENV, '{}')) - - -def _get_value_in_tfconfig(key, default=None): - tf_config = _load_tf_config() - return tf_config[key] if key in tf_config else default - - -class TFConfigClusterResolver(ClusterResolver): - """Implementation of a ClusterResolver which reads the TF_CONFIG EnvVar.""" - - def __init__(self, - task_type=None, - task_index=None, - rpc_layer=None, - environment=None, - num_accelerators_per_worker=0): - """Creates a new TFConfigClusterResolver. - - Args: - task_type: (String, optional) Overrides the task type specified in the - TF_CONFIG environment variable. - task_index: (Integer, optional) Overrides the task index specified in the - TF_CONFIG environment variable. - rpc_layer: (String, optional) Overrides the rpc layer TensorFlow uses. - environment: (String, optional) Overrides the environment TensorFlow - operates in. - num_accelerators_per_worker: (Integer, optional) Specifies the number of - accelerators (e.g. GPUs, TPUs, others) that each node has. - """ - - self._task_type = task_type - self._task_index = task_index - self._rpc_layer = rpc_layer - self._environment = environment - self._num_accelerators_per_worker = num_accelerators_per_worker - - @property - def task_type(self): - if self._task_type is None: - task_info = _get_value_in_tfconfig(_TASK_KEY, {}) - return task_info['type'] if 'type' in task_info else None - else: - return self._task_type - - @property - def task_index(self): - if self._task_type is None: - task_info = _get_value_in_tfconfig(_TASK_KEY, {}) - return task_info['index'] if 'index' in task_info else None - else: - return self._task_index - - @task_type.setter - def task_type(self, task_type): - self._task_type = task_type - - @task_index.setter - def task_index(self, task_index): - self._task_index = task_index - - @property - def environment(self): - return self._environment - - @property - def rpc_layer(self): - if self._rpc_layer is None: - return _get_value_in_tfconfig(_RPC_LAYER_KEY) - else: - return self._rpc_layer - - @rpc_layer.setter - def rpc_layer(self, rpc_layer): - self._rpc_layer = rpc_layer - - def num_accelerators_per_worker(self, session_config=None): - # TODO(frankchn): Connect to server (w/ session_config) in the future. - del session_config # Unused, we do not connect to another server here. - return self._num_accelerators_per_worker - - def cluster_spec(self): - """Returns a ClusterSpec based on the TF_CONFIG environment variable. - - Returns: - A ClusterSpec with information from the TF_CONFIG environment variable. - """ - tf_config = _load_tf_config() - if 'cluster' not in tf_config: - return ClusterSpec({}) - return ClusterSpec(tf_config['cluster']) - - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Returns the master address to use when creating a TensorFlow session. - - Args: - task_type: (String, optional) Overrides and sets the task_type of the - master. - task_index: (Integer, optional) Overrides and sets the task id of the - master. - rpc_layer: (String, optional) Overrides and sets the protocol over which - TensorFlow nodes communicate with each other. - - Returns: - The address of the master. +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. - Raises: - RuntimeError: If the task_type or task_id is not specified and the - `TF_CONFIG` environment variable does not contain a task section. - """ +# pylint: disable=unused-import +from tensorflow.python.distribute.cluster_resolver.tfconfig_cluster_resolver import TFConfigClusterResolver +# pylint: enable=unused-import - # If `session_master` is set, just use that. - session_master = _get_value_in_tfconfig(_SESSION_MASTER_KEY) - if session_master is not None: - return session_master +from tensorflow.python.util.all_util import remove_undocumented - # Return an empty string if we are the only job in the ClusterSpec. - cluster_spec = self.cluster_spec() - if (not cluster_spec.jobs or - (len(cluster_spec.jobs) == 1 and - len(cluster_spec.job_tasks(cluster_spec.jobs[0])) == 1)): - return '' +_allowed_symbols = [ + 'TFConfigClusterResolver', +] - # We try to auto-detect the task type and id, but uses the user-supplied one - # where available - task_type = task_type if task_type is not None else self.task_type - task_index = task_index if task_index is not None else self.task_index +remove_undocumented(__name__, _allowed_symbols) - return format_master_url(cluster_spec.task_address(task_type, task_index), - self.rpc_layer) diff --git a/tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver.py b/tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver.py index d5537a4100..3a1eaccd06 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver.py +++ b/tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver.py @@ -1,4 +1,4 @@ -# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# Copyright 2018 The TensorFlow Authors. 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. @@ -12,412 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Implementation of Cluster Resolvers for Cloud TPUs.""" +"""Stub file for TPUClusterResolver to maintain backwards compatibility.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import os +# This file (and all files in this directory in general) is a backwards +# compatibility shim that exists to re-export ClusterResolvers such that +# existing OSS code will not be broken. -from six.moves.urllib.request import Request -from six.moves.urllib.request import urlopen +# pylint: disable=unused-import +from tensorflow.python.distribute.cluster_resolver.tpu_cluster_resolver import TPUClusterResolver +# pylint: enable=unused-import -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import ClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import format_master_url -from tensorflow.python.training import server_lib -from tensorflow.python.util import compat +from tensorflow.python.util.all_util import remove_undocumented -_GOOGLE_API_CLIENT_INSTALLED = True -try: - from googleapiclient import discovery # pylint: disable=g-import-not-at-top - from oauth2client.client import GoogleCredentials # pylint: disable=g-import-not-at-top -except ImportError: - _GOOGLE_API_CLIENT_INSTALLED = False +_allowed_symbols = [ + 'TPUClusterResolver', +] - -_GKE_ENV_VARIABLE = 'KUBE_GOOGLE_CLOUD_TPU_ENDPOINTS' -_ENDPOINTS_SEPARATOR = ',' -_DEFAULT_ENV_VARIABLE = 'TPU_NAME' -_DISCOVERY_SERVICE_URL_ENV_VARIABLE = 'TPU_API_DISCOVERY_URL' - - -class TPUClusterResolver(ClusterResolver): - """Cluster Resolver for Google Cloud TPUs. - - This is an implementation of cluster resolvers for the Google Cloud TPU - service. As Cloud TPUs are in alpha, you will need to specify a API definition - file for this to consume, in addition to a list of Cloud TPUs in your Google - Cloud Platform project. - """ - - def _tpuService(self): - """Creates a new Cloud TPU API object. - - This works around an issue where the underlying HTTP connection sometimes - times out when the script has been running for too long. Other methods in - this object calls this method to get a new API object whenever they need - to communicate with the Cloud API. - - Returns: - A Google Cloud TPU API object. - """ - if self._service: - return self._service - - credentials = self._credentials - if credentials is None or credentials == 'default': - credentials = GoogleCredentials.get_application_default() - - if self._discovery_url: - return discovery.build( - 'tpu', 'v1alpha1', - credentials=credentials, - discoveryServiceUrl=self._discovery_url) - else: - return discovery.build( - 'tpu', 'v1alpha1', - credentials=credentials) - - def _requestComputeMetadata(self, path): - req = Request('http://metadata/computeMetadata/v1/%s' % path, - headers={'Metadata-Flavor': 'Google'}) - resp = urlopen(req) - return compat.as_bytes(resp.read()) - - def _shouldResolve(self): - if isinstance(self._should_resolve_override, bool): - return self._should_resolve_override - if (self._tpu == compat.as_bytes('') or - self._tpu == compat.as_bytes('local') or - self._tpu.startswith(compat.as_bytes('/bns')) or - self._tpu.startswith(compat.as_bytes('localhost:')) or - self._tpu.startswith(compat.as_bytes('grpc://'))): - return False - return True - - @staticmethod - def _inGke(): - """When running in GKE, the environment variable will be set.""" - return _GKE_ENV_VARIABLE in os.environ - - @staticmethod - def _gkeEndpoints(): - return os.environ[_GKE_ENV_VARIABLE] - - @staticmethod - def _envVarFallback(): - if _DEFAULT_ENV_VARIABLE in os.environ: - return os.environ[_DEFAULT_ENV_VARIABLE] - return None - - @staticmethod - def _environmentDiscoveryUrl(): - return os.environ.get(_DISCOVERY_SERVICE_URL_ENV_VARIABLE) - - def __init__(self, - tpu=None, - zone=None, - project=None, - job_name='worker', - coordinator_name=None, - coordinator_address=None, - credentials='default', - service=None, - discovery_url=None): - """Creates a new TPUClusterResolver object. - - The ClusterResolver will then use the parameters to query the Cloud TPU APIs - for the IP addresses and ports of each Cloud TPU listed. - - Args: - tpu: Either a string, or a list of strings corresponding to the TPUs to - use. If the single string is the empty string, the string 'local', or a - string that begins with 'grpc://' or '/bns', then it is assumed to not - correspond with a Cloud TPU and will instead be passed as the session - master and no ClusterSpec propagation will be done. - zone: Zone where the TPUs are located. If omitted or empty, we will assume - that the zone of the TPU is the same as the zone of the GCE VM, which we - will try to discover from the GCE metadata service. - project: Name of the GCP project containing Cloud TPUs. If omitted or - empty, we will try to discover the project name of the GCE VM from the - GCE metadata service. - job_name: Name of the TensorFlow job the TPUs belong to. - coordinator_name: The name to use for the coordinator. Set to None if the - coordinator should not be included in the computed ClusterSpec. - coordinator_address: The address of the coordinator (typically an ip:port - pair). If set to None, a TF server will be started. If coordinator_name - is None, a TF server will not be started even if coordinator_address is - None. - credentials: GCE Credentials. If None, then we use default credentials - from the oauth2client - service: The GCE API object returned by the googleapiclient.discovery - function. If you specify a custom service object, then the credentials - parameter will be ignored. - discovery_url: A URL template that points to the location of - the discovery service. It should have two parameters {api} and - {apiVersion} that when filled in produce an absolute URL to the - discovery document for that service. The environment variable - 'TPU_API_DISCOVERY_URL' will override this. - - Raises: - ImportError: If the googleapiclient is not installed. - ValueError: If no TPUs are specified. - """ - if isinstance(tpu, list): - if not tpu: - raise ValueError('At least one TPU must be specified.') - if len(tpu) != 1: - raise NotImplementedError( - 'Using multiple TPUs in a single session is not yet implemented') - tpu = tpu[0] - - in_gke = self._inGke() - # When using GKE with Cloud TPUs, the env variable will be set. - if tpu is None: - if in_gke: - tpu = self._gkeEndpoints() - else: - tpu = self._envVarFallback() - - if tpu is None: - raise ValueError('Please provide a TPU Name to connect to.') - - self._tpu = compat.as_bytes(tpu) # self._tpu is always bytes - - # By default the task_type is 'worker` and the task_index is 0 (which is the - # first worker in the task). - self.task_type = job_name - self.task_index = 0 - - if tpu.startswith('grpc://'): - # Cloud environment, where we are using GRPC to communicate to TPUs. - self._environment = '' - elif tpu == 'local' or not tpu: - # Google environment, where the TPU is attached to the host. - self._environment = 'google' - elif tpu.startswith('/bns'): - # Google environment, where we reach the TPU through BNS. - self._environment = 'google' - - # If TPU is in the Google environment or exists locally, we don't use any - # RPC layer. - if tpu.startswith('/bns') or tpu == 'local' or not tpu: - self.rpc_layer = None - else: - self.rpc_layer = 'grpc' - - # Setting this overrides the return value of self._shouldResolve() - self._should_resolve_override = None - - # We strip out the protocol if it is included, and override the - # shouldResolve function to never resolve. We are adding the protocol back - # in later in self.master(). - if self.rpc_layer is not None and tpu.startswith(self.rpc_layer + '://'): - tpu = tpu[len(self.rpc_layer + '://'):] - self._tpu = tpu - self._should_resolve_override = False - - # Whether we should actually attempt to contact Cloud APIs - should_resolve = self._shouldResolve() - - # We error out if we are in a non-Cloud environment which cannot talk to the - # Cloud APIs using the standard class and a special object is not passed in. - self._service = service - if (self._service is None and should_resolve and - not _GOOGLE_API_CLIENT_INSTALLED): - raise ImportError('googleapiclient and oauth2client must be installed ' - 'before using the TPU cluster resolver. Execute: ' - '`pip install --upgrade google-api-python-client` ' - 'and `pip install --upgrade oauth2client` to ' - 'install with pip.') - - # We save user-passed credentials, unless the user didn't pass in anything. - self._credentials = credentials - if (credentials == 'default' and should_resolve and - _GOOGLE_API_CLIENT_INSTALLED): - self._credentials = None - - # Automatically detect project and zone if unspecified. - if not project and should_resolve: - project = compat.as_str( - self._requestComputeMetadata('project/project-id')) - if not zone and should_resolve: - zone_path = compat.as_str(self._requestComputeMetadata('instance/zone')) - zone = zone_path.split('/')[-1] - self._project = project - self._zone = zone - - self._discovery_url = self._environmentDiscoveryUrl() or discovery_url - - self._coordinator_name = coordinator_name - if (coordinator_name and not coordinator_address and - (should_resolve or in_gke)): - self._start_local_server() - else: - self._coordinator_address = coordinator_address - - def master(self, task_type=None, task_index=None, rpc_layer=None): - """Get the Master string to be used for the session. - - In the normal case, this returns the grpc path (grpc://1.2.3.4:8470) of - first instance in the ClusterSpec returned by the cluster_spec function. - - If a non-TPU name is used when constructing a TPUClusterResolver, that will - be returned instead (e.g. If the tpus argument's value when constructing - this TPUClusterResolver was 'grpc://10.240.1.2:8470', - 'grpc://10.240.1.2:8470' will be returned). - - Args: - task_type: (Optional, string) The type of the TensorFlow task of the - master. - task_index: (Optional, integer) The index of the TensorFlow task of the - master. - rpc_layer: (Optional, string) The RPC protocol TensorFlow should use to - communicate with TPUs. - - Returns: - string, the connection string to use when creating a session. - - Raises: - ValueError: If none of the TPUs specified exists. - """ - if self._shouldResolve(): - # We are going to communicate with the Cloud TPU APIs to get a Cluster. - cluster_spec = self.cluster_spec() - if task_type is not None and task_index is not None: - # task_type and task_index is from the function parameter - master = cluster_spec.task_address(task_type, task_index) - elif self.task_type is not None and self.task_index is not None: - # task_type and task_index is from the object - master = cluster_spec.task_address(self.task_type, self.task_index) - else: - # by default we take the first item in the cluster with the right name - job_tasks = cluster_spec.job_tasks(self.task_type) - if not job_tasks: - raise ValueError('No TPUs with the specified names exist.') - master = job_tasks[0] - else: - if isinstance(self._tpu, (bytes, bytearray)): - master = self._tpu.split(compat.as_bytes(_ENDPOINTS_SEPARATOR))[0] - else: - master = self._tpu.split(_ENDPOINTS_SEPARATOR)[0] - return format_master_url(master, rpc_layer or self.rpc_layer) - - def get_master(self): - return self.master() - - def get_job_name(self): - if self._shouldResolve(): - return self.task_type - - def cluster_spec(self): - """Returns a ClusterSpec object based on the latest TPU information. - - We retrieve the information from the GCE APIs every time this method is - called. - - Returns: - A ClusterSpec containing host information returned from Cloud TPUs. - - Raises: - RuntimeError: If the provided TPU is not healthy. - """ - ############################################################################ - # There are 5 potential cases this code must handle: - # 1. [Normal case.] We should resolve the TPU name to a set of tasks, and - # a. Create a ClusterSpec that includes the coordinator job - # b. Create a ClusterSpec without the coordinator job. - # 2. [GKE / No API Access.] We should not resolve the TPU name to a set of - # tasks and - # a. Create a ClusterSpec with the coordinator - # b. Create a ClusterSpec without the coordinator - # 3. [Other (legacy non-gRPC).] We should return an empty ClusterSpec. - ############################################################################ - - if self._shouldResolve(): - # Case 1. - full_name = 'projects/%s/locations/%s/nodes/%s' % ( - self._project, self._zone, compat.as_text(self._tpu)) - service = self._tpuService() - request = service.projects().locations().nodes().get(name=full_name) - response = request.execute() - - if 'state' in response and response['state'] != 'READY': - raise RuntimeError('TPU "%s" is not yet ready; state: "%s"' % - (compat.as_text(self._tpu), response['state'])) - - if 'health' in response and response['health'] != 'HEALTHY': - raise RuntimeError('TPU "%s" is unhealthy: "%s"' % - (compat.as_text(self._tpu), response['health'])) - - if 'networkEndpoints' in response: - worker_list = [ - '%s:%s' % (endpoint['ipAddress'], endpoint['port']) - for endpoint in response['networkEndpoints'] - ] - else: - # Fall back to the deprecated response format - instance_url = '%s:%s' % (response['ipAddress'], response['port']) - worker_list = [instance_url] - - cluster_spec = {self.task_type: worker_list} - else: - if self.rpc_layer is None: - # Case 3. - return None - # Case 2. - tpus = [] - for tpu in self._tpu.split(_ENDPOINTS_SEPARATOR): - # We are working around the fact that GKE environment variable that is - # supplied to us has the protocol string embedded in it, but we want - # to strip it out for the ClusterSpec. - if (self.rpc_layer is not None and - tpu.startswith(self.rpc_layer + '://')): - tpus.append(tpu[len(self.rpc_layer + '://'):]) - else: - tpus.append(tpu) - cluster_spec = {self.task_type: tpus} - - if self._coordinator_address: - # {1, 2}.a - cluster_spec[self._coordinator_name] = [self._coordinator_address] - - return server_lib.ClusterSpec(cluster_spec) - - def num_accelerators_per_worker(self, session_config=None): - """Returns the number of TPU cores per worker. - - This defaults to 8 for all current TPU configurations, and we do not need - to query any remote systems for this. - - Args: - session_config: Unused. Not currently necessary to query anything as this - number is 8 for all TPU configurations. - """ - del session_config # Unused. Not necessary to query anything. - return 8 - - @property - def environment(self): - """Returns the current environment which TensorFlow is running in.""" - return self._environment - - def _start_local_server(self): - address = self._requestComputeMetadata('instance/network-interfaces/0/ip') - self._server = server_lib.Server( - { - 'local': ['0.0.0.0:0'] - }, protocol='grpc', config=None, start=True) - # self._server.target is of the form: grpc://ipaddress:port - target = compat.as_bytes(self._server.target) - splits = target.split(compat.as_bytes(':')) - assert len(splits) == 3, self._server.target - assert splits[0] == compat.as_bytes('grpc'), self._server.target - self._coordinator_port = compat.as_text(splits[2]) - self._coordinator_address = '%s:%s' % ( - address, compat.as_text(self._coordinator_port)) - - def __deepcopy__(self, memo): - # TODO(b/73668574): Remove this once RunConfig avoids performing deepcopy. - return self +remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/contrib/tpu/BUILD b/tensorflow/contrib/tpu/BUILD index 999274018b..05d2ebd2e8 100644 --- a/tensorflow/contrib/tpu/BUILD +++ b/tensorflow/contrib/tpu/BUILD @@ -216,7 +216,7 @@ py_library( ], deps = [ ":tpu_lib", - "//tensorflow/contrib/cluster_resolver:tpu_cluster_resolver_py", + "//tensorflow/contrib/cluster_resolver:cluster_resolver_py", "//tensorflow/contrib/distribute", "//tensorflow/contrib/framework:framework_py", "//tensorflow/contrib/tpu/proto:compilation_result_proto_py", @@ -264,7 +264,7 @@ py_library( ":tpu_py", "//tensorflow/compiler/xla/experimental/xla_sharding", "//tensorflow/compiler/xla/python_api:xla_shape", - "//tensorflow/contrib/cluster_resolver:tpu_cluster_resolver_py", + "//tensorflow/contrib/cluster_resolver:cluster_resolver_py", "//tensorflow/contrib/compiler:xla", "//tensorflow/contrib/tpu/proto:compilation_result_proto_py", "//tensorflow/contrib/tpu/proto:optimization_parameters_proto_py", diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 6e4945e6fd..92aac5fc0a 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -3534,6 +3534,19 @@ py_library( ], ) +# Dependency added and used by ClusterResolvers to avoid circular dependency between keras, distribute, and training. +py_library( + name = "training_server_lib", + srcs = ["training/server_lib.py"], + srcs_version = "PY2AND3", + deps = [ + ":framework", + ":pywrap_tensorflow", + ":util", + "//tensorflow/core:protos_all_py", + ], +) + py_library( name = "saveable_object", srcs = ["training/saveable_object.py"], diff --git a/tensorflow/python/distribute/BUILD b/tensorflow/python/distribute/BUILD index ec438d00f0..2d9a1764db 100644 --- a/tensorflow/python/distribute/BUILD +++ b/tensorflow/python/distribute/BUILD @@ -124,6 +124,7 @@ py_library( "//tensorflow/python:util", "//tensorflow/python:variable_scope", "//tensorflow/python/data", + "//tensorflow/python/distribute/cluster_resolver:cluster_resolver_lib", "//tensorflow/python/ops/losses", "//tensorflow/tools/docs:doc_controls", ], diff --git a/tensorflow/python/distribute/cluster_resolver/BUILD b/tensorflow/python/distribute/cluster_resolver/BUILD new file mode 100644 index 0000000000..360a2993cd --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/BUILD @@ -0,0 +1,180 @@ +# Description: Operations defined for Cluster Resolvers + +load("//tensorflow:tensorflow.bzl", "tf_py_test") + +package( + default_visibility = [ + "//tensorflow:__subpackages__", + ], +) + +licenses(["notice"]) # Apache 2.0 + +py_library( + name = "cluster_resolver_lib", + srcs = [ + "__init__.py", + ], + srcs_version = "PY2AND3", + visibility = ["//visibility:public"], + deps = [ + ":base_cluster_resolver_py", + ":gce_cluster_resolver_py", + ":kubernetes_cluster_resolver_py", + ":slurm_cluster_resolver_py", + ":tfconfig_cluster_resolver_py", + ":tpu_cluster_resolver_py", + "//tensorflow/python:util", + ], +) + +py_library( + name = "base_cluster_resolver_py", + srcs = ["cluster_resolver.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:training_server_lib", + ], +) + +py_library( + name = "gce_cluster_resolver_py", + srcs = ["gce_cluster_resolver.py"], + srcs_version = "PY2AND3", + deps = [ + ":base_cluster_resolver_py", + "//tensorflow/python:training_server_lib", + ], +) + +py_library( + name = "tfconfig_cluster_resolver_py", + srcs = ["tfconfig_cluster_resolver.py"], + srcs_version = "PY2AND3", + deps = [ + ":base_cluster_resolver_py", + "//tensorflow/python:training_server_lib", + ], +) + +py_library( + name = "tpu_cluster_resolver_py", + srcs = ["tpu_cluster_resolver.py"], + srcs_version = "PY2AND3", + deps = [ + ":base_cluster_resolver_py", + "//tensorflow/python:training_server_lib", + ], +) + +py_library( + name = "slurm_cluster_resolver_py", + srcs = ["slurm_cluster_resolver.py"], + srcs_version = "PY2AND3", + deps = [ + ":base_cluster_resolver_py", + "//tensorflow/python:training_server_lib", + ], +) + +py_library( + name = "kubernetes_cluster_resolver_py", + srcs = ["kubernetes_cluster_resolver.py"], + srcs_version = "PY2AND3", + deps = [ + ":base_cluster_resolver_py", + "//tensorflow/python:training_server_lib", + ], +) + +tf_py_test( + name = "base_cluster_resolver_py_test", + srcs = ["cluster_resolver_test.py"], + additional_deps = [ + ":base_cluster_resolver_py", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "//tensorflow/python:training_server_lib", + ], + main = "cluster_resolver_test.py", +) + +tf_py_test( + name = "gce_cluster_resolver_py_test", + size = "small", + srcs = ["gce_cluster_resolver_test.py"], + additional_deps = [ + ":gce_cluster_resolver_py", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "//tensorflow/python:training_server_lib", + ], + main = "gce_cluster_resolver_test.py", +) + +tf_py_test( + name = "tfconfig_cluster_resolver_py_test", + size = "small", + srcs = ["tfconfig_cluster_resolver_test.py"], + additional_deps = [ + ":tfconfig_cluster_resolver_py", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "//tensorflow/python:training_server_lib", + ], + grpc_enabled = True, + main = "tfconfig_cluster_resolver_test.py", +) + +tf_py_test( + name = "tpu_cluster_resolver_py_test", + size = "small", + srcs = ["tpu_cluster_resolver_test.py"], + additional_deps = [ + ":tpu_cluster_resolver_py", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "//tensorflow/python:training_server_lib", + ], + grpc_enabled = True, + main = "tpu_cluster_resolver_test.py", +) + +tf_py_test( + name = "slurm_cluster_resolver_py_test", + size = "small", + srcs = ["slurm_cluster_resolver_test.py"], + additional_deps = [ + ":slurm_cluster_resolver_py", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "//tensorflow/python:training_server_lib", + ], + main = "slurm_cluster_resolver_test.py", + tags = [], +) + +tf_py_test( + name = "kubernetes_cluster_resolver_py_test", + size = "small", + srcs = ["kubernetes_cluster_resolver_test.py"], + additional_deps = [ + ":kubernetes_cluster_resolver_py", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "//tensorflow/python:training_server_lib", + ], + main = "kubernetes_cluster_resolver_test.py", +) diff --git a/tensorflow/contrib/cluster_resolver/README.md b/tensorflow/python/distribute/cluster_resolver/README.md similarity index 100% rename from tensorflow/contrib/cluster_resolver/README.md rename to tensorflow/python/distribute/cluster_resolver/README.md diff --git a/tensorflow/contrib/cluster_resolver/python/training/README.slurm b/tensorflow/python/distribute/cluster_resolver/README.slurm similarity index 100% rename from tensorflow/contrib/cluster_resolver/python/training/README.slurm rename to tensorflow/python/distribute/cluster_resolver/README.slurm diff --git a/tensorflow/python/distribute/cluster_resolver/__init__.py b/tensorflow/python/distribute/cluster_resolver/__init__.py new file mode 100644 index 0000000000..ef87f59b7f --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/__init__.py @@ -0,0 +1,57 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Library Imports for Cluster Resolvers.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.distribute.cluster_resolver import cluster_resolver +from tensorflow.python.distribute.cluster_resolver import gce_cluster_resolver +from tensorflow.python.distribute.cluster_resolver import kubernetes_cluster_resolver +from tensorflow.python.distribute.cluster_resolver import slurm_cluster_resolver +from tensorflow.python.distribute.cluster_resolver import tfconfig_cluster_resolver +from tensorflow.python.distribute.cluster_resolver import tpu_cluster_resolver + +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import SimpleClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import UnionClusterResolver +from tensorflow.python.distribute.cluster_resolver.gce_cluster_resolver import GceClusterResolver +from tensorflow.python.distribute.cluster_resolver.kubernetes_cluster_resolver import KubernetesClusterResolver +from tensorflow.python.distribute.cluster_resolver.slurm_cluster_resolver import SlurmClusterResolver +from tensorflow.python.distribute.cluster_resolver.tfconfig_cluster_resolver import TFConfigClusterResolver +from tensorflow.python.distribute.cluster_resolver.tpu_cluster_resolver import TPUClusterResolver + +from tensorflow.python.util.all_util import remove_undocumented + +_allowed_symbols = [ + 'cluster_resolver', + 'gce_cluster_resolver', + 'kubernetes_cluster_resolver', + 'slurm_cluster_resolver', + 'tfconfig_cluster_resolver', + 'tpu_cluster_resolver', + 'ClusterResolver', + 'SimpleClusterResolver', + 'UnionClusterResolver', + 'GceClusterResolver', + 'KubernetesClusterResolver', + 'TFConfigClusterResolver', + 'TPUClusterResolver', + 'SlurmClusterResolver', +] + +remove_undocumented(__name__, _allowed_symbols) + diff --git a/tensorflow/python/distribute/cluster_resolver/cluster_resolver.py b/tensorflow/python/distribute/cluster_resolver/cluster_resolver.py new file mode 100644 index 0000000000..7774ac0e12 --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/cluster_resolver.py @@ -0,0 +1,374 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Cluster Resolvers are used for dynamic cluster IP/hostname resolution.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import abc + +import six + +from tensorflow.python.training.server_lib import ClusterSpec + + +def format_master_url(master, rpc_layer=None): + if rpc_layer: + return '%s://%s' % (rpc_layer, master) + else: + return master + + +@six.add_metaclass(abc.ABCMeta) +class ClusterResolver(object): + """Abstract class for all implementations of ClusterResolvers. + + This defines the skeleton for all implementations of ClusterResolvers. + ClusterResolvers are a way for TensorFlow to communicate with various cluster + management systems (e.g. GCE, AWS, etc...). + + By letting TensorFlow communicate with these systems, we will be able to + automatically discover and resolve IP addresses for various TensorFlow + workers. This will eventually allow us to automatically recover from + underlying machine failures and scale TensorFlow worker clusters up and down. + + Note to Implementors: In addition to these abstract methods, you must also + implement the task_type, task_index, and rpc_layer attributes. You may choose + to implement them either as properties with getters or setters or directly + set the attributes. + + - task_type is the name of the server's current named job (e.g. 'worker', + 'ps' in a distributed parameterized training job). + - task_index is the ordinal index of the server within the task type. + - rpc_layer is the protocol used by TensorFlow to communicate with other + TensorFlow servers in a distributed environment. + """ + + @abc.abstractmethod + def cluster_spec(self): + """Retrieve the current state of the cluster and returns a ClusterSpec. + + Returns: + A ClusterSpec representing the state of the cluster at the moment this + function is called. + + Implementors of this function must take care in ensuring that the + ClusterSpec returned is up-to-date at the time of calling this function. + This usually means retrieving the information from the underlying cluster + management system every time this function is invoked and reconstructing + a cluster_spec, rather than attempting to cache anything. + """ + raise NotImplementedError() + + @abc.abstractmethod + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Retrieves the name or URL of the session master. + + Args: + task_type: (Optional) The type of the TensorFlow task of the master. + task_index: (Optional) The index of the TensorFlow task of the master. + rpc_layer: (Optional) The RPC protocol for the given cluster. + + Returns: + The name or URL of the session master. + + Implementors of this function must take care in ensuring that the master + returned is up-to-date at the time to calling this function. This usually + means retrieving the master every time this function is invoked. + """ + raise NotImplementedError() + + @abc.abstractmethod + def num_accelerators_per_worker(self, session_config=None): + """Returns the number of accelerator cores per worker. + + This returns the number of accelerator cores (such as GPUs and TPUs) + available per worker. If workers only has CPU cores available, then this + should return 0. This method will query the master for this information + if it is not otherwise known. + + Args: + session_config: (Optional) Configuration for starting a new session to + query how many accelerator cores it has. + """ + raise NotImplementedError() + + @abc.abstractproperty + def environment(self): + """Returns the current environment which TensorFlow is running in.""" + raise NotImplementedError() + + +class SimpleClusterResolver(ClusterResolver): + """Simple implementation of ClusterResolver that accepts a ClusterSpec.""" + + def __init__(self, cluster_spec, master='', task_type=None, task_index=None, + environment='', num_accelerators_per_worker=0, + rpc_layer=None): + """Creates a SimpleClusterResolver from a ClusterSpec.""" + super(SimpleClusterResolver, self).__init__() + + self._task_type = task_type + self._task_index = task_index + self._environment = environment + self._num_accelerators_per_worker = num_accelerators_per_worker + self._rpc_layer = rpc_layer + + if not isinstance(cluster_spec, ClusterSpec): + raise TypeError('cluster_spec must be a ClusterSpec.') + self._cluster_spec = cluster_spec + + if not isinstance(master, str): + raise TypeError('master must be a string.') + self._master = master + + def cluster_spec(self): + """Returns the ClusterSpec passed into the constructor.""" + return self._cluster_spec + + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Returns the master address to use when creating a session. + + Args: + task_type: (Optional) The type of the TensorFlow task of the master. + task_index: (Optional) The index of the TensorFlow task of the master. + rpc_layer: (Optional) The RPC used by distributed TensorFlow. + + Returns: + The name or URL of the session master. + + If a task_type and task_index is given, this will override the `master` + string passed into the initialization function. + """ + if task_type is not None and task_index is not None: + master = self.cluster_spec().task_address(task_type, task_index) + else: + master = self._master + + return format_master_url(master, rpc_layer=rpc_layer or self._rpc_layer) + + @property + def task_type(self): + return self._task_type + + @property + def task_index(self): + return self._task_index + + @task_type.setter + def task_type(self, task_type): + self._task_type = task_type + + @task_index.setter + def task_index(self, task_index): + self._task_index = task_index + + @property + def environment(self): + return self._environment + + def num_accelerators_per_worker(self, session_config=None): + """Returns the number of accelerator cores per worker. + + Args: + session_config: Unused. The SimpleClusterResolver does not do automatic + detection of accelerators, so a TensorFlow session will never be + created, and thus a `session_config` is never necessary here, and will + be ignored. + """ + del session_config + return self._num_accelerators_per_worker + + @property + def rpc_layer(self): + return self._rpc_layer + + @rpc_layer.setter + def rpc_layer(self, rpc_layer): + self._rpc_layer = rpc_layer + + +class UnionClusterResolver(ClusterResolver): + """Performs a union on underlying ClusterResolvers. + + This class performs a union given two or more existing ClusterResolvers. It + merges the underlying ClusterResolvers, and returns one unified ClusterSpec + when cluster_spec is called. The details of the merge function is + documented in the cluster_spec function. + + For additional Cluster Resolver properties such as task type, task index, + rpc layer, environment, etc..., we will return the value from the first + ClusterResolver in the union. + """ + + def __init__(self, *args, **kwargs): + """Initializes a UnionClusterResolver with other ClusterResolvers. + + Args: + *args: `ClusterResolver` objects to be unionized. + **kwargs: + rpc_layer - (Optional) Override value for the RPC layer used by + TensorFlow. + task_type - (Optional) Override value for the current task type. + task_index - (Optional) Override value for the current task index. + + Raises: + TypeError: If any argument is not a subclass of `ClusterResolvers`. + ValueError: If there are no arguments passed. + """ + super(UnionClusterResolver, self).__init__() + + self._rpc_layer = kwargs.pop('rpc_layer', None) + self._task_type = kwargs.pop('task_type', None) + self._task_index = kwargs.pop('task_index', None) + + if kwargs: + raise ValueError('Unexpected kwargs provided {!r}'.format(kwargs)) + + if not args: + raise ValueError('At least one ClusterResolver is required.') + + for cluster_resolver in args: + if not isinstance(cluster_resolver, ClusterResolver): + raise TypeError('All arguments must be a sub-class of ' + '`ClusterResolver.`') + self._cluster_resolvers = args + + def cluster_spec(self): + """Returns a union of all the ClusterSpecs from the ClusterResolvers. + + Returns: + A ClusterSpec containing host information merged from all the underlying + ClusterResolvers. + + Raises: + KeyError: If there are conflicting keys detected when merging two or + more dictionaries, this exception is raised. + + Note: If there are multiple ClusterResolvers exposing ClusterSpecs with the + same job name, we will merge the list/dict of workers. + + If *all* underlying ClusterSpecs expose the set of workers as lists, we will + concatenate the lists of workers, starting with the list of workers from + the first ClusterResolver passed into the constructor. + + If *any* of the ClusterSpecs expose the set of workers as a dict, we will + treat all the sets of workers as dicts (even if they are returned as lists) + and will only merge them into a dict if there is no conflicting keys. If + there is a conflicting key, we will raise a `KeyError`. + """ + + merged_cluster = {} + + # We figure out whether it is all lists for a particular job, or whether + # there are dicts inside. + for cluster_resolver in self._cluster_resolvers: + cluster_spec = cluster_resolver.cluster_spec() + cluster_dict = cluster_spec.as_dict() + + for job_name, tasks in cluster_dict.items(): + if job_name in merged_cluster: + # If we see a dict, then we write a dict out regardless. + if isinstance(tasks, dict): + merged_cluster[job_name] = {} + else: + # We take whichever type is present. + if isinstance(tasks, list): + merged_cluster[job_name] = [] + else: + merged_cluster[job_name] = {} + + # We then do the merge as appropriate in merged_cluster[job]. + for cluster_resolver in self._cluster_resolvers: + cluster_spec = cluster_resolver.cluster_spec() + cluster_dict = cluster_spec.as_dict() + + for job_name, tasks in cluster_dict.items(): + if isinstance(merged_cluster[job_name], list): + # We all have lists, we can just concatenate and be done. + merged_cluster[job_name].extend(tasks) + else: + if isinstance(tasks, list): + # We convert to a dictionary if the type is a list. + task_dict = dict(zip(range(0, len(tasks)), tasks)) + else: + # We can simply make a copy (for update) and be done. + task_dict = tasks.copy() + + # We detect if there are duplicates, and raise an error if so. + task_keys = set(task_dict) + merged_keys = set(merged_cluster[job_name].keys()) + intersected_keys = task_keys.intersection(merged_keys) + if intersected_keys: + raise KeyError('Duplicate keys detected when merging two ' + 'ClusterSpecs: %s' % repr(intersected_keys)) + + # We do the merge after all the processing. + merged_cluster[job_name].update(task_dict) + + return ClusterSpec(merged_cluster) + + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Returns the master address to use when creating a session. + + This usually returns the master from the first ClusterResolver passed in, + but you can override this by specifying the task_type and task_index. + + Args: + task_type: (Optional) The type of the TensorFlow task of the master. + task_index: (Optional) The index of the TensorFlow task of the master. + rpc_layer: (Optional) The RPC protocol for the given cluster. + + Returns: + The name or URL of the session master. + """ + if task_type is not None and task_index is not None: + master = self.cluster_spec().task_address(task_type, task_index) + return format_master_url(master, rpc_layer or self._rpc_layer) + + return self._cluster_resolvers[0].master(rpc_layer=rpc_layer) + + @property + def task_type(self): + return self._task_type or self._cluster_resolvers[0].task_type + + @property + def task_index(self): + return self._task_index or self._cluster_resolvers[0].task_index + + @task_type.setter + def task_type(self, task_type): + self._task_type = task_type + + @task_index.setter + def task_index(self, task_index): + self._task_index = task_index + + @property + def environment(self): + return self._cluster_resolvers[0].environment + + def num_accelerators_per_worker(self, session_config=None): + return self._cluster_resolvers[0].num_accelerators_per_worker( + session_config) + + @property + def rpc_layer(self): + return self._rpc_layer or self._cluster_resolvers[0].rpc_layer + + @rpc_layer.setter + def rpc_layer(self, rpc_layer): + self._rpc_layer = rpc_layer diff --git a/tensorflow/contrib/cluster_resolver/python/training/cluster_resolver_test.py b/tensorflow/python/distribute/cluster_resolver/cluster_resolver_test.py similarity index 98% rename from tensorflow/contrib/cluster_resolver/python/training/cluster_resolver_test.py rename to tensorflow/python/distribute/cluster_resolver/cluster_resolver_test.py index b94c9612b5..b5448faec6 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/cluster_resolver_test.py +++ b/tensorflow/python/distribute/cluster_resolver/cluster_resolver_test.py @@ -18,8 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import SimpleClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import UnionClusterResolver +from tensorflow.python.distribute.cluster_resolver import SimpleClusterResolver +from tensorflow.python.distribute.cluster_resolver import UnionClusterResolver from tensorflow.python.platform import test from tensorflow.python.training import server_lib diff --git a/tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver.py b/tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver.py new file mode 100644 index 0000000000..b167bc8fc8 --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver.py @@ -0,0 +1,206 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Implementation of Cluster Resolvers for GCE Instance Groups.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.training.server_lib import ClusterSpec + +_GOOGLE_API_CLIENT_INSTALLED = True +try: + from googleapiclient import discovery # pylint: disable=g-import-not-at-top + from oauth2client.client import GoogleCredentials # pylint: disable=g-import-not-at-top +except ImportError: + _GOOGLE_API_CLIENT_INSTALLED = False + + +def _format_master_url(master, rpc_layer=None): + return '%s://%s' % (rpc_layer, master) if rpc_layer else master + + +class GceClusterResolver(ClusterResolver): + """Cluster Resolver for Google Compute Engine. + + This is an implementation of cluster resolvers for the Google Compute Engine + instance group platform. By specifying a project, zone, and instance group, + this will retrieve the IP address of all the instances within the instance + group and return a Cluster Resolver object suitable for use for distributed + TensorFlow. + """ + + def __init__(self, + project, + zone, + instance_group, + port, + task_type='worker', + task_index=0, + rpc_layer='grpc', + num_accelerators_per_worker=0, + credentials='default', + service=None): + """Creates a new GceClusterResolver object. + + This takes in a few parameters and creates a GceClusterResolver project. It + will then use these parameters to query the GCE API for the IP addresses of + each instance in the instance group. + + Args: + project: Name of the GCE project. + zone: Zone of the GCE instance group. + instance_group: Name of the GCE instance group. + port: Port of the listening TensorFlow server (default: 8470) + task_type: Name of the TensorFlow job this GCE instance group of VM + instances belong to. + task_index: The task index for this particular VM, within the GCE + instance group. In particular, every single instance should be assigned + a unique ordinal index within an instance group manually so that they + can be distinguished from each other. + rpc_layer: The RPC layer TensorFlow should use to communicate across + instances. + num_accelerators_per_worker: Number of accelerators (GPUs) present per + instance. + credentials: GCE Credentials. If nothing is specified, this defaults to + GoogleCredentials.get_application_default(). + service: The GCE API object returned by the googleapiclient.discovery + function. (Default: discovery.build('compute', 'v1')). If you specify a + custom service object, then the credentials parameter will be ignored. + + Raises: + ImportError: If the googleapiclient is not installed. + """ + self._project = project + self._zone = zone + self._instance_group = instance_group + self._task_type = task_type + self._task_index = task_index + self._rpc_layer = rpc_layer + self._port = port + self._credentials = credentials + + if credentials == 'default': + if _GOOGLE_API_CLIENT_INSTALLED: + self._credentials = GoogleCredentials.get_application_default() + + if service is None: + if not _GOOGLE_API_CLIENT_INSTALLED: + raise ImportError('googleapiclient must be installed before using the ' + 'GCE cluster resolver') + self._service = discovery.build( + 'compute', 'v1', + credentials=self._credentials) + else: + self._service = service + + def cluster_spec(self): + """Returns a ClusterSpec object based on the latest instance group info. + + This returns a ClusterSpec object for use based on information from the + specified instance group. We will retrieve the information from the GCE APIs + every time this method is called. + + Returns: + A ClusterSpec containing host information retrieved from GCE. + """ + request_body = {'instanceState': 'RUNNING'} + request = self._service.instanceGroups().listInstances( + project=self._project, + zone=self._zone, + instanceGroups=self._instance_group, + body=request_body, + orderBy='name') + + worker_list = [] + + while request is not None: + response = request.execute() + + items = response['items'] + for instance in items: + instance_name = instance['instance'].split('/')[-1] + + instance_request = self._service.instances().get( + project=self._project, + zone=self._zone, + instance=instance_name) + + if instance_request is not None: + instance_details = instance_request.execute() + ip_address = instance_details['networkInterfaces'][0]['networkIP'] + instance_url = '%s:%s' % (ip_address, self._port) + worker_list.append(instance_url) + + request = self._service.instanceGroups().listInstances_next( + previous_request=request, + previous_response=response) + + worker_list.sort() + return ClusterSpec({self._task_type: worker_list}) + + def master(self, task_type=None, task_index=None, rpc_layer=None): + task_type = task_type if task_type is not None else self._task_type + task_index = task_index if task_index is not None else self._task_index + + if task_type is not None and task_index is not None: + master = self.cluster_spec().task_address(task_type, task_index) + if rpc_layer or self._rpc_layer: + return '%s://%s' % (rpc_layer or self._rpc_layer, master) + else: + return master + + return '' + + @property + def task_type(self): + return self._task_type + + @property + def task_index(self): + return self._task_index + + @task_type.setter + def task_type(self, task_type): + raise RuntimeError( + 'You cannot reset the task_type of the GceClusterResolver after it has ' + 'been created.') + + @task_index.setter + def task_index(self, task_index): + self._task_index = task_index + + @property + def environment(self): + """Returns the current environment which TensorFlow is running in. + + For users in the GCE environment, the environment property is always an + empty string, and Google users will not use this ClusterResolver for running + on internal systems. + """ + return '' + + @property + def rpc_layer(self): + return self._rpc_layer + + @rpc_layer.setter + def rpc_layer(self, rpc_layer): + self._rpc_layer = rpc_layer + + def num_accelerators_per_worker(self, session_config=None): + del session_config # Unused, since this is set manually in __init__. + return self._num_accelerators_per_worker diff --git a/tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver_test.py b/tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver_test.py similarity index 98% rename from tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver_test.py rename to tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver_test.py index c691552e86..d4f0660c92 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/gce_cluster_resolver_test.py +++ b/tensorflow/python/distribute/cluster_resolver/gce_cluster_resolver_test.py @@ -18,8 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import UnionClusterResolver -from tensorflow.contrib.cluster_resolver.python.training.gce_cluster_resolver import GceClusterResolver +from tensorflow.python.distribute.cluster_resolver import GceClusterResolver +from tensorflow.python.distribute.cluster_resolver import UnionClusterResolver from tensorflow.python.platform import test from tensorflow.python.training import server_lib diff --git a/tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver.py b/tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver.py new file mode 100644 index 0000000000..041c081540 --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver.py @@ -0,0 +1,173 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Implementation of Cluster Resolvers for Kubernetes.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.client import device_lib +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import format_master_url +from tensorflow.python.training import server_lib + +_KUBERNETES_API_CLIENT_INSTALLED = True +try: + from kubernetes import client as k8sclient # pylint: disable=g-import-not-at-top + from kubernetes import config as k8sconfig # pylint: disable=g-import-not-at-top +except ImportError: + _KUBERNETES_API_CLIENT_INSTALLED = False + + +class KubernetesClusterResolver(ClusterResolver): + """Cluster Resolver for Kubernetes. + + This is an implementation of cluster resolvers for Kubernetes. When given the + the Kubernetes namespace and label selector for pods, we will retrieve the + pod IP addresses of all running pods matching the selector, and return a + ClusterSpec based on that information. + """ + + def __init__(self, + job_to_label_mapping=None, + tf_server_port=8470, + rpc_layer='grpc', + override_client=None): + """Initializes a new KubernetesClusterResolver. + + This initializes a new Kubernetes Cluster Resolver. The Cluster Resolver + will attempt to talk to the Kubernetes master to retrieve all the instances + of pods matching a label selector. + + Args: + job_to_label_mapping: A mapping of TensorFlow jobs to label selectors. + This allows users to specify many TensorFlow jobs in one Cluster + Resolver, and each job can have pods belong with different label + selectors. For example, a sample mapping might be + ``` + {'worker': ['job-name=worker-cluster-a', 'job-name=worker-cluster-b'], + 'ps': ['job-name=ps-1', 'job-name=ps-2']} + ``` + tf_server_port: The port the TensorFlow server is listening on. + rpc_layer: (Optional) The RPC layer TensorFlow should use to communicate + between tasks in Kubernetes. Defaults to 'grpc'. + override_client: The Kubernetes client (usually automatically retrieved + using `from kubernetes import client as k8sclient`). If you pass this + in, you are responsible for setting Kubernetes credentials manually. + + Raises: + ImportError: If the Kubernetes Python client is not installed and no + `override_client` is passed in. + RuntimeError: If autoresolve_task is not a boolean or a callable. + """ + if _KUBERNETES_API_CLIENT_INSTALLED: + k8sconfig.load_kube_config() + + if not job_to_label_mapping: + job_to_label_mapping = {'worker': ['job-name=tensorflow']} + + if not override_client and not _KUBERNETES_API_CLIENT_INSTALLED: + raise ImportError('The Kubernetes Python client must be installed before' + 'using the Kubernetes Cluster Resolver. To install the' + 'Kubernetes Python client, run `pip install ' + 'kubernetes` on your command line.') + + self._job_to_label_mapping = job_to_label_mapping + self._tf_server_port = tf_server_port + self._override_client = override_client + + self.task_type = None + self.task_index = None + self.rpc_layer = rpc_layer + + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Returns the master address to use when creating a session. + + You must have set the task_type and task_index object properties before + calling this function, or pass in the `task_type` and `task_index` + parameters when using this function. If you do both, the function parameters + will override the object properties. + + Args: + task_type: (Optional) The type of the TensorFlow task of the master. + task_index: (Optional) The index of the TensorFlow task of the master. + rpc_layer: (Optional) The RPC protocol for the given cluster. + + Returns: + The name or URL of the session master. + """ + if task_type is not None and task_index is not None: + return format_master_url( + self.cluster_spec().task_address(task_type, task_index), + rpc_layer or self.rpc_layer) + + if self.task_type is not None and self.task_index is not None: + return format_master_url( + self.cluster_spec().task_address(self.task_type, self.task_index), + rpc_layer or self.rpc_layer) + + return '' + + def cluster_spec(self): + """Returns a ClusterSpec object based on the latest info from Kubernetes. + + We retrieve the information from the Kubernetes master every time this + method is called. + + Returns: + A ClusterSpec containing host information returned from Kubernetes. + + Raises: + RuntimeError: If any of the pods returned by the master is not in the + `Running` phase. + """ + if not self._override_client: + k8sconfig.load_kube_config() + + client = self._override_client or k8sclient.CoreV1Api() + cluster_map = {} + + for tf_job in self._job_to_label_mapping: + all_pods = [] + for selector in self._job_to_label_mapping[tf_job]: + ret = client.list_pod_for_all_namespaces(label_selector=selector) + selected_pods = [] + + # Sort the list by the name to make sure it doesn't change call to call. + for pod in sorted(ret.items, key=lambda x: x.metadata.name): + if pod.status.phase == 'Running': + selected_pods.append( + '%s:%s' % (pod.status.host_ip, self._tf_server_port)) + else: + raise RuntimeError('Pod "%s" is not running; phase: "%s"' % + (pod.metadata.name, pod.status.phase)) + all_pods.extend(selected_pods) + cluster_map[tf_job] = all_pods + + return server_lib.ClusterSpec(cluster_map) + + @property + def environment(self): + """Returns the current environment which TensorFlow is running in. + + For users in the Cloud environment, the environment property is always an + empty string, and Google users will not use this ClusterResolver for running + on internal systems. + """ + return '' + + def num_accelerators_per_worker(self, session_config=None): + local_devices = device_lib.list_local_devices(session_config) + return len([d for d in local_devices if d.device_type == 'GPU']) diff --git a/tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver_test.py b/tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver_test.py similarity index 98% rename from tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver_test.py rename to tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver_test.py index c63a98af6c..a9750fa60b 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/kubernetes_cluster_resolver_test.py +++ b/tensorflow/python/distribute/cluster_resolver/kubernetes_cluster_resolver_test.py @@ -18,7 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.cluster_resolver.python.training import KubernetesClusterResolver +from tensorflow.python.distribute.cluster_resolver import KubernetesClusterResolver from tensorflow.python.platform import test from tensorflow.python.training import server_lib diff --git a/tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver.py b/tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver.py new file mode 100644 index 0000000000..fd3c6d6a18 --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver.py @@ -0,0 +1,226 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Implementation of Cluster Resolvers for Slurm workload manager.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections +import os +import subprocess + +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.training.server_lib import ClusterSpec + + +class SlurmClusterResolver(ClusterResolver): + """Cluster Resolver for system with Slurm workload manager. + + This is an implementation of cluster resolvers for Slurm clusters. This allows + the specification of jobs and task counts, number of tasks per node, number of + GPUs on each node and number of GPUs for each task, It retrieves system + attributes by Slurm environment variables, resolves allocated computing node + names, construct a cluster and return a Cluster Resolver object which an be + use for distributed TensorFlow. + """ + + def _resolve_hostnames(self): + """Resolve host names of nodes allocated in current jobs. + + Returns: + A list of node names as strings. + """ + hostlist = (subprocess.check_output(['scontrol', 'show', 'hostname']). + decode('utf-8').strip().split('\n')) + return hostlist + + def __init__(self, + jobs, + port_base=8888, + gpus_per_node=1, + gpus_per_task=1, + tasks_per_node=None, + auto_set_gpu=True, + rpc_layer='grpc'): + """Creates a new SlurmClusterResolver object. + + This takes in parameters and creates a SlurmClusterResolver object. It uses + those parameters to check which nodes will processes reside and resolves + their hostnames. With the number of the GPUs on each node and number of GPUs + for each task it offsets the port number for each processes and allocate + GPUs to tasks by setting environment variables. The resolver currently + supports homogeneous tasks and default Slurm process allocation. + + Args: + jobs: Dictionary with job names as key and number of tasks in the job as + value + port_base: The first port number to start with for processes on a node. + gpus_per_node: Number of GPUs available on each node. + gpus_per_task: Number of GPUs to be used for each task. + tasks_per_node: Number of tasks to run on each node, if not set defaults + to Slurm's output environment variable SLURM_NTASKS_PER_NODE. + auto_set_gpu: Set the visible CUDA devices automatically while resolving + the cluster by setting CUDA_VISIBLE_DEVICES environment variable. + Defaults to True. + rpc_layer: (Optional) The protocol TensorFlow uses to communicate between + nodes. Defaults to 'grpc'. + + Returns: + A ClusterResolver object which can be used with distributed TensorFlow. + + Raises: + RuntimeError: If requested more GPUs per node then available or requested + more tasks then assigned tasks. + """ + + # check if launched by mpirun + if 'OMPI_COMM_WORLD_RANK' in os.environ: + self._rank = int(os.environ['OMPI_COMM_WORLD_RANK']) + num_tasks = int(os.environ['OMPI_COMM_WORLD_SIZE']) + else: + self._rank = int(os.environ['SLURM_PROCID']) + num_tasks = int(os.environ['SLURM_NTASKS']) + + self._jobs = collections.OrderedDict(sorted(jobs.items())) + self._port_base = port_base + + # user specification overrides SLURM specification + if tasks_per_node is not None: + self._tasks_per_node = tasks_per_node + elif tasks_per_node is None and 'SLURM_NTASKS_PER_NODE' in os.environ: + self._tasks_per_node = int(os.environ['SLURM_NTASKS_PER_NODE']) + else: + raise RuntimeError('Neither `tasks_per_node` or ' + 'SLURM_NTASKS_PER_NODE is set.') + + self._gpus_per_node = gpus_per_node + self._gpus_per_task = gpus_per_task + + self._auto_set_gpu = auto_set_gpu + self.task_type = None + self.task_index = None + self.rpc_layer = rpc_layer + + self._gpu_allocation = [] + self._cluster_allocation = {} + + if self._tasks_per_node * self._gpus_per_task > self._gpus_per_node: + raise RuntimeError('Requested more GPUs per node then available.') + + if sum(self._jobs.values()) != num_tasks: + raise RuntimeError('Requested more tasks then assigned tasks.') + + def cluster_spec(self): + """Returns a ClusterSpec object based on the latest instance group info. + + This returns a ClusterSpec object for use based on information from the + specified initialization parameters and Slurm environment variables. The + cluster specification is resolved each time this function is called. The + resolver extract hostnames of nodes by scontrol and pack tasks in that + order until a node a has number of tasks that is equal to specification. + GPUs on nodes are allocated to tasks by specification through setting + CUDA_VISIBLE_DEVICES environment variable. + + Returns: + A ClusterSpec containing host information retrieved from Slurm's + environment variables. + """ + hostlist = self._resolve_hostnames() + + task_list = [] + self._gpu_allocation = [] + self._cluster_allocation = {} + + for host in hostlist: + for port_offset, gpu_offset in zip( + range(self._tasks_per_node), + range(0, self._gpus_per_node, self._gpus_per_task)): + + host_addr = '%s:%d' % (host, self._port_base + port_offset) + task_list.append(host_addr) + gpu_id_list = [] + + for gpu_id in range(gpu_offset, gpu_offset + self._gpus_per_task): + gpu_id_list.append(str(gpu_id)) + + self._gpu_allocation.append(','.join(gpu_id_list)) + + cluster_rank_offset_start = 0 + cluster_rank_offset_end = 0 + + for task_type, num_tasks in self._jobs.items(): + cluster_rank_offset_end = cluster_rank_offset_start + num_tasks + + self._cluster_allocation[task_type] = ( + task_list[cluster_rank_offset_start:cluster_rank_offset_end]) + + if cluster_rank_offset_start <= self._rank < cluster_rank_offset_end: + self.task_type = task_type + self.task_index = self._rank - cluster_rank_offset_start + + cluster_rank_offset_start = cluster_rank_offset_end + + if self._auto_set_gpu is True: + os.environ['CUDA_VISIBLE_DEVICES'] = self._gpu_allocation[self._rank] + + return ClusterSpec(self._cluster_allocation) + + def get_task_info(self): + """Returns job name and task_index for the process which calls this. + + This returns the job name and task index for the process which calls this + function according to its rank and cluster specification. The job name and + task index are set after a cluster is constructed by cluster_spec otherwise + defaults to None. + + Returns: + A string specifying job name the process belongs to and an integner + specifying the task index the process belongs to in that job. + """ + return self.task_type, self.task_index + + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Returns the master string for connecting to a TensorFlow master. + + Args: + task_type: (Optional) Overrides the default auto-selected task type. + task_index: (Optional) Overrides the default auto-slected task index. + rpc_layer: (Optional) Overrides the default RPC protocol TensorFlow uses + to communicate across nodes. + + Returns: + A connection string for connecting to a TensorFlow master. + """ + task_type = task_type if task_type is not None else self.task_type + task_index = task_index if task_index is not None else self.task_index + rpc_layer = rpc_layer or self.rpc_layer + master = self.cluster_spec().task_address(task_type, task_index) + + return '%s://%s' % (rpc_layer, master) if rpc_layer else master + + @property + def environment(self): + """Returns the current environment which TensorFlow is running in. + + For users in the Slurm environment, the environment property is always an + empty string, and Google users will not use this ClusterResolver for running + on internal systems. + """ + return '' + + def num_accelerators_per_worker(self, session_config=None): + del session_config # Unused, since this is set in __init__ manually. + return self._gpus_per_node diff --git a/tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver_test.py b/tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver_test.py similarity index 98% rename from tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver_test.py rename to tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver_test.py index 7c76e133fe..076539d16f 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/slurm_cluster_resolver_test.py +++ b/tensorflow/python/distribute/cluster_resolver/slurm_cluster_resolver_test.py @@ -20,7 +20,7 @@ from __future__ import print_function import os -from tensorflow.contrib.cluster_resolver.python.training.slurm_cluster_resolver import SlurmClusterResolver +from tensorflow.python.distribute.cluster_resolver import SlurmClusterResolver from tensorflow.python.platform import test from tensorflow.python.training import server_lib diff --git a/tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver.py b/tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver.py new file mode 100644 index 0000000000..a3246e77f4 --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver.py @@ -0,0 +1,171 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Implementation of Cluster Resolvers for TF_CONFIG Environment Variables.""" + + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import json +import os + +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.training.server_lib import ClusterSpec + +_TF_CONFIG_ENV = 'TF_CONFIG' +_SESSION_MASTER_KEY = 'session_master' +_RPC_LAYER_KEY = 'rpc_layer' +_TASK_KEY = 'task' + + +def format_master_url(master, rpc_layer=None): + if rpc_layer: + return '%s://%s' % (rpc_layer, master) + else: + return master + + +def _load_tf_config(): + return json.loads(os.environ.get(_TF_CONFIG_ENV, '{}')) + + +def _get_value_in_tfconfig(key, default=None): + tf_config = _load_tf_config() + return tf_config[key] if key in tf_config else default + + +class TFConfigClusterResolver(ClusterResolver): + """Implementation of a ClusterResolver which reads the TF_CONFIG EnvVar.""" + + def __init__(self, + task_type=None, + task_index=None, + rpc_layer=None, + environment=None, + num_accelerators_per_worker=0): + """Creates a new TFConfigClusterResolver. + + Args: + task_type: (String, optional) Overrides the task type specified in the + TF_CONFIG environment variable. + task_index: (Integer, optional) Overrides the task index specified in the + TF_CONFIG environment variable. + rpc_layer: (String, optional) Overrides the rpc layer TensorFlow uses. + environment: (String, optional) Overrides the environment TensorFlow + operates in. + num_accelerators_per_worker: (Integer, optional) Specifies the number of + accelerators (e.g. GPUs, TPUs, others) that each node has. + """ + + self._task_type = task_type + self._task_index = task_index + self._rpc_layer = rpc_layer + self._environment = environment + self._num_accelerators_per_worker = num_accelerators_per_worker + + @property + def task_type(self): + if self._task_type is None: + task_info = _get_value_in_tfconfig(_TASK_KEY, {}) + return task_info['type'] if 'type' in task_info else None + else: + return self._task_type + + @property + def task_index(self): + if self._task_type is None: + task_info = _get_value_in_tfconfig(_TASK_KEY, {}) + return task_info['index'] if 'index' in task_info else None + else: + return self._task_index + + @task_type.setter + def task_type(self, task_type): + self._task_type = task_type + + @task_index.setter + def task_index(self, task_index): + self._task_index = task_index + + @property + def environment(self): + return self._environment + + @property + def rpc_layer(self): + if self._rpc_layer is None: + return _get_value_in_tfconfig(_RPC_LAYER_KEY) + else: + return self._rpc_layer + + @rpc_layer.setter + def rpc_layer(self, rpc_layer): + self._rpc_layer = rpc_layer + + def num_accelerators_per_worker(self, session_config=None): + # TODO(frankchn): Connect to server (w/ session_config) in the future. + del session_config # Unused, we do not connect to another server here. + return self._num_accelerators_per_worker + + def cluster_spec(self): + """Returns a ClusterSpec based on the TF_CONFIG environment variable. + + Returns: + A ClusterSpec with information from the TF_CONFIG environment variable. + """ + tf_config = _load_tf_config() + if 'cluster' not in tf_config: + return ClusterSpec({}) + return ClusterSpec(tf_config['cluster']) + + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Returns the master address to use when creating a TensorFlow session. + + Args: + task_type: (String, optional) Overrides and sets the task_type of the + master. + task_index: (Integer, optional) Overrides and sets the task id of the + master. + rpc_layer: (String, optional) Overrides and sets the protocol over which + TensorFlow nodes communicate with each other. + + Returns: + The address of the master. + + Raises: + RuntimeError: If the task_type or task_id is not specified and the + `TF_CONFIG` environment variable does not contain a task section. + """ + + # If `session_master` is set, just use that. + session_master = _get_value_in_tfconfig(_SESSION_MASTER_KEY) + if session_master is not None: + return session_master + + # Return an empty string if we are the only job in the ClusterSpec. + cluster_spec = self.cluster_spec() + if (not cluster_spec.jobs or + (len(cluster_spec.jobs) == 1 and + len(cluster_spec.job_tasks(cluster_spec.jobs[0])) == 1)): + return '' + + # We try to auto-detect the task type and id, but uses the user-supplied one + # where available + task_type = task_type if task_type is not None else self.task_type + task_index = task_index if task_index is not None else self.task_index + + return format_master_url(cluster_spec.task_address(task_type, task_index), + self.rpc_layer) diff --git a/tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver_test.py b/tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver_test.py similarity index 98% rename from tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver_test.py rename to tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver_test.py index 3db6d5447f..c20e51bc0b 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/tfconfig_cluster_resolver_test.py +++ b/tensorflow/python/distribute/cluster_resolver/tfconfig_cluster_resolver_test.py @@ -20,7 +20,7 @@ from __future__ import print_function import os -from tensorflow.contrib.cluster_resolver.python.training.tfconfig_cluster_resolver import TFConfigClusterResolver +from tensorflow.python.distribute.cluster_resolver import TFConfigClusterResolver from tensorflow.python.platform import test from tensorflow.python.training import server_lib diff --git a/tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver.py b/tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver.py new file mode 100644 index 0000000000..1956bd75a8 --- /dev/null +++ b/tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver.py @@ -0,0 +1,423 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Implementation of Cluster Resolvers for Cloud TPUs.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os + +from six.moves.urllib.request import Request +from six.moves.urllib.request import urlopen + +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import ClusterResolver +from tensorflow.python.distribute.cluster_resolver.cluster_resolver import format_master_url +from tensorflow.python.training import server_lib +from tensorflow.python.util import compat + +_GOOGLE_API_CLIENT_INSTALLED = True +try: + from googleapiclient import discovery # pylint: disable=g-import-not-at-top + from oauth2client.client import GoogleCredentials # pylint: disable=g-import-not-at-top +except ImportError: + _GOOGLE_API_CLIENT_INSTALLED = False + + +_GKE_ENV_VARIABLE = 'KUBE_GOOGLE_CLOUD_TPU_ENDPOINTS' +_ENDPOINTS_SEPARATOR = ',' +_DEFAULT_ENV_VARIABLE = 'TPU_NAME' +_DISCOVERY_SERVICE_URL_ENV_VARIABLE = 'TPU_API_DISCOVERY_URL' + + +class TPUClusterResolver(ClusterResolver): + """Cluster Resolver for Google Cloud TPUs. + + This is an implementation of cluster resolvers for the Google Cloud TPU + service. As Cloud TPUs are in alpha, you will need to specify a API definition + file for this to consume, in addition to a list of Cloud TPUs in your Google + Cloud Platform project. + """ + + def _tpuService(self): + """Creates a new Cloud TPU API object. + + This works around an issue where the underlying HTTP connection sometimes + times out when the script has been running for too long. Other methods in + this object calls this method to get a new API object whenever they need + to communicate with the Cloud API. + + Returns: + A Google Cloud TPU API object. + """ + if self._service: + return self._service + + credentials = self._credentials + if credentials is None or credentials == 'default': + credentials = GoogleCredentials.get_application_default() + + if self._discovery_url: + return discovery.build( + 'tpu', 'v1alpha1', + credentials=credentials, + discoveryServiceUrl=self._discovery_url) + else: + return discovery.build( + 'tpu', 'v1alpha1', + credentials=credentials) + + def _requestComputeMetadata(self, path): + req = Request('http://metadata/computeMetadata/v1/%s' % path, + headers={'Metadata-Flavor': 'Google'}) + resp = urlopen(req) + return compat.as_bytes(resp.read()) + + def _shouldResolve(self): + if isinstance(self._should_resolve_override, bool): + return self._should_resolve_override + if (self._tpu == compat.as_bytes('') or + self._tpu == compat.as_bytes('local') or + self._tpu.startswith(compat.as_bytes('/bns')) or + self._tpu.startswith(compat.as_bytes('localhost:')) or + self._tpu.startswith(compat.as_bytes('grpc://'))): + return False + return True + + @staticmethod + def _inGke(): + """When running in GKE, the environment variable will be set.""" + return _GKE_ENV_VARIABLE in os.environ + + @staticmethod + def _gkeEndpoints(): + return os.environ[_GKE_ENV_VARIABLE] + + @staticmethod + def _envVarFallback(): + if _DEFAULT_ENV_VARIABLE in os.environ: + return os.environ[_DEFAULT_ENV_VARIABLE] + return None + + @staticmethod + def _environmentDiscoveryUrl(): + return os.environ.get(_DISCOVERY_SERVICE_URL_ENV_VARIABLE) + + def __init__(self, + tpu=None, + zone=None, + project=None, + job_name='worker', + coordinator_name=None, + coordinator_address=None, + credentials='default', + service=None, + discovery_url=None): + """Creates a new TPUClusterResolver object. + + The ClusterResolver will then use the parameters to query the Cloud TPU APIs + for the IP addresses and ports of each Cloud TPU listed. + + Args: + tpu: Either a string, or a list of strings corresponding to the TPUs to + use. If the single string is the empty string, the string 'local', or a + string that begins with 'grpc://' or '/bns', then it is assumed to not + correspond with a Cloud TPU and will instead be passed as the session + master and no ClusterSpec propagation will be done. + zone: Zone where the TPUs are located. If omitted or empty, we will assume + that the zone of the TPU is the same as the zone of the GCE VM, which we + will try to discover from the GCE metadata service. + project: Name of the GCP project containing Cloud TPUs. If omitted or + empty, we will try to discover the project name of the GCE VM from the + GCE metadata service. + job_name: Name of the TensorFlow job the TPUs belong to. + coordinator_name: The name to use for the coordinator. Set to None if the + coordinator should not be included in the computed ClusterSpec. + coordinator_address: The address of the coordinator (typically an ip:port + pair). If set to None, a TF server will be started. If coordinator_name + is None, a TF server will not be started even if coordinator_address is + None. + credentials: GCE Credentials. If None, then we use default credentials + from the oauth2client + service: The GCE API object returned by the googleapiclient.discovery + function. If you specify a custom service object, then the credentials + parameter will be ignored. + discovery_url: A URL template that points to the location of + the discovery service. It should have two parameters {api} and + {apiVersion} that when filled in produce an absolute URL to the + discovery document for that service. The environment variable + 'TPU_API_DISCOVERY_URL' will override this. + + Raises: + ImportError: If the googleapiclient is not installed. + ValueError: If no TPUs are specified. + """ + if isinstance(tpu, list): + if not tpu: + raise ValueError('At least one TPU must be specified.') + if len(tpu) != 1: + raise NotImplementedError( + 'Using multiple TPUs in a single session is not yet implemented') + tpu = tpu[0] + + in_gke = self._inGke() + # When using GKE with Cloud TPUs, the env variable will be set. + if tpu is None: + if in_gke: + tpu = self._gkeEndpoints() + else: + tpu = self._envVarFallback() + + if tpu is None: + raise ValueError('Please provide a TPU Name to connect to.') + + self._tpu = compat.as_bytes(tpu) # self._tpu is always bytes + + # By default the task_type is 'worker` and the task_index is 0 (which is the + # first worker in the task). + self.task_type = job_name + self.task_index = 0 + + if tpu.startswith('grpc://'): + # Cloud environment, where we are using GRPC to communicate to TPUs. + self._environment = '' + elif tpu == 'local' or not tpu: + # Google environment, where the TPU is attached to the host. + self._environment = 'google' + elif tpu.startswith('/bns'): + # Google environment, where we reach the TPU through BNS. + self._environment = 'google' + + # If TPU is in the Google environment or exists locally, we don't use any + # RPC layer. + if tpu.startswith('/bns') or tpu == 'local' or not tpu: + self.rpc_layer = None + else: + self.rpc_layer = 'grpc' + + # Setting this overrides the return value of self._shouldResolve() + self._should_resolve_override = None + + # We strip out the protocol if it is included, and override the + # shouldResolve function to never resolve. We are adding the protocol back + # in later in self.master(). + if self.rpc_layer is not None and tpu.startswith(self.rpc_layer + '://'): + tpu = tpu[len(self.rpc_layer + '://'):] + self._tpu = tpu + self._should_resolve_override = False + + # Whether we should actually attempt to contact Cloud APIs + should_resolve = self._shouldResolve() + + # We error out if we are in a non-Cloud environment which cannot talk to the + # Cloud APIs using the standard class and a special object is not passed in. + self._service = service + if (self._service is None and should_resolve and + not _GOOGLE_API_CLIENT_INSTALLED): + raise ImportError('googleapiclient and oauth2client must be installed ' + 'before using the TPU cluster resolver. Execute: ' + '`pip install --upgrade google-api-python-client` ' + 'and `pip install --upgrade oauth2client` to ' + 'install with pip.') + + # We save user-passed credentials, unless the user didn't pass in anything. + self._credentials = credentials + if (credentials == 'default' and should_resolve and + _GOOGLE_API_CLIENT_INSTALLED): + self._credentials = None + + # Automatically detect project and zone if unspecified. + if not project and should_resolve: + project = compat.as_str( + self._requestComputeMetadata('project/project-id')) + if not zone and should_resolve: + zone_path = compat.as_str(self._requestComputeMetadata('instance/zone')) + zone = zone_path.split('/')[-1] + self._project = project + self._zone = zone + + self._discovery_url = self._environmentDiscoveryUrl() or discovery_url + + self._coordinator_name = coordinator_name + if (coordinator_name and not coordinator_address and + (should_resolve or in_gke)): + self._start_local_server() + else: + self._coordinator_address = coordinator_address + + def master(self, task_type=None, task_index=None, rpc_layer=None): + """Get the Master string to be used for the session. + + In the normal case, this returns the grpc path (grpc://1.2.3.4:8470) of + first instance in the ClusterSpec returned by the cluster_spec function. + + If a non-TPU name is used when constructing a TPUClusterResolver, that will + be returned instead (e.g. If the tpus argument's value when constructing + this TPUClusterResolver was 'grpc://10.240.1.2:8470', + 'grpc://10.240.1.2:8470' will be returned). + + Args: + task_type: (Optional, string) The type of the TensorFlow task of the + master. + task_index: (Optional, integer) The index of the TensorFlow task of the + master. + rpc_layer: (Optional, string) The RPC protocol TensorFlow should use to + communicate with TPUs. + + Returns: + string, the connection string to use when creating a session. + + Raises: + ValueError: If none of the TPUs specified exists. + """ + if self._shouldResolve(): + # We are going to communicate with the Cloud TPU APIs to get a Cluster. + cluster_spec = self.cluster_spec() + if task_type is not None and task_index is not None: + # task_type and task_index is from the function parameter + master = cluster_spec.task_address(task_type, task_index) + elif self.task_type is not None and self.task_index is not None: + # task_type and task_index is from the object + master = cluster_spec.task_address(self.task_type, self.task_index) + else: + # by default we take the first item in the cluster with the right name + job_tasks = cluster_spec.job_tasks(self.task_type) + if not job_tasks: + raise ValueError('No TPUs with the specified names exist.') + master = job_tasks[0] + else: + if isinstance(self._tpu, (bytes, bytearray)): + master = self._tpu.split(compat.as_bytes(_ENDPOINTS_SEPARATOR))[0] + else: + master = self._tpu.split(_ENDPOINTS_SEPARATOR)[0] + return format_master_url(master, rpc_layer or self.rpc_layer) + + def get_master(self): + return self.master() + + def get_job_name(self): + if self._shouldResolve(): + return self.task_type + + def cluster_spec(self): + """Returns a ClusterSpec object based on the latest TPU information. + + We retrieve the information from the GCE APIs every time this method is + called. + + Returns: + A ClusterSpec containing host information returned from Cloud TPUs. + + Raises: + RuntimeError: If the provided TPU is not healthy. + """ + ############################################################################ + # There are 5 potential cases this code must handle: + # 1. [Normal case.] We should resolve the TPU name to a set of tasks, and + # a. Create a ClusterSpec that includes the coordinator job + # b. Create a ClusterSpec without the coordinator job. + # 2. [GKE / No API Access.] We should not resolve the TPU name to a set of + # tasks and + # a. Create a ClusterSpec with the coordinator + # b. Create a ClusterSpec without the coordinator + # 3. [Other (legacy non-gRPC).] We should return an empty ClusterSpec. + ############################################################################ + + if self._shouldResolve(): + # Case 1. + full_name = 'projects/%s/locations/%s/nodes/%s' % ( + self._project, self._zone, compat.as_text(self._tpu)) + service = self._tpuService() + request = service.projects().locations().nodes().get(name=full_name) + response = request.execute() + + if 'state' in response and response['state'] != 'READY': + raise RuntimeError('TPU "%s" is not yet ready; state: "%s"' % + (compat.as_text(self._tpu), response['state'])) + + if 'health' in response and response['health'] != 'HEALTHY': + raise RuntimeError('TPU "%s" is unhealthy: "%s"' % + (compat.as_text(self._tpu), response['health'])) + + if 'networkEndpoints' in response: + worker_list = [ + '%s:%s' % (endpoint['ipAddress'], endpoint['port']) + for endpoint in response['networkEndpoints'] + ] + else: + # Fall back to the deprecated response format + instance_url = '%s:%s' % (response['ipAddress'], response['port']) + worker_list = [instance_url] + + cluster_spec = {self.task_type: worker_list} + else: + if self.rpc_layer is None: + # Case 3. + return None + # Case 2. + tpus = [] + for tpu in self._tpu.split(_ENDPOINTS_SEPARATOR): + # We are working around the fact that GKE environment variable that is + # supplied to us has the protocol string embedded in it, but we want + # to strip it out for the ClusterSpec. + if (self.rpc_layer is not None and + tpu.startswith(self.rpc_layer + '://')): + tpus.append(tpu[len(self.rpc_layer + '://'):]) + else: + tpus.append(tpu) + cluster_spec = {self.task_type: tpus} + + if self._coordinator_address: + # {1, 2}.a + cluster_spec[self._coordinator_name] = [self._coordinator_address] + + return server_lib.ClusterSpec(cluster_spec) + + def num_accelerators_per_worker(self, session_config=None): + """Returns the number of TPU cores per worker. + + This defaults to 8 for all current TPU configurations, and we do not need + to query any remote systems for this. + + Args: + session_config: Unused. Not currently necessary to query anything as this + number is 8 for all TPU configurations. + """ + del session_config # Unused. Not necessary to query anything. + return 8 + + @property + def environment(self): + """Returns the current environment which TensorFlow is running in.""" + return self._environment + + def _start_local_server(self): + address = self._requestComputeMetadata('instance/network-interfaces/0/ip') + self._server = server_lib.Server( + { + 'local': ['0.0.0.0:0'] + }, protocol='grpc', config=None, start=True) + # self._server.target is of the form: grpc://ipaddress:port + target = compat.as_bytes(self._server.target) + splits = target.split(compat.as_bytes(':')) + assert len(splits) == 3, self._server.target + assert splits[0] == compat.as_bytes('grpc'), self._server.target + self._coordinator_port = compat.as_text(splits[2]) + self._coordinator_address = '%s:%s' % ( + address, compat.as_text(self._coordinator_port)) + + def __deepcopy__(self, memo): + # TODO(b/73668574): Remove this once RunConfig avoids performing deepcopy. + return self diff --git a/tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver_test.py b/tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver_test.py similarity index 99% rename from tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver_test.py rename to tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver_test.py index 365bd52ee2..0f22ede3d9 100644 --- a/tensorflow/contrib/cluster_resolver/python/training/tpu_cluster_resolver_test.py +++ b/tensorflow/python/distribute/cluster_resolver/tpu_cluster_resolver_test.py @@ -20,7 +20,7 @@ from __future__ import print_function import os -from tensorflow.contrib.cluster_resolver.python.training.tpu_cluster_resolver import TPUClusterResolver +from tensorflow.python.distribute.cluster_resolver import TPUClusterResolver from tensorflow.python.platform import test from tensorflow.python.training import server_lib from tensorflow.python.util import compat -- GitLab From 94008f8c576c8e56e401ba9aee56137e43b6fa0e Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Thu, 29 Nov 2018 13:30:39 -0800 Subject: [PATCH 573/672] Make input ops test windows compatible by using path separator from os module. PiperOrigin-RevId: 223401186 --- tensorflow/python/distribute/input_ops_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/distribute/input_ops_test.py b/tensorflow/python/distribute/input_ops_test.py index 2689dbbec8..d5f41b7093 100644 --- a/tensorflow/python/distribute/input_ops_test.py +++ b/tensorflow/python/distribute/input_ops_test.py @@ -126,7 +126,7 @@ class AutoShardDatasetTest(test.TestCase): def testListfiles(self): filenames = self._createTFRecordFiles() - file_pattern = filenames[0].rsplit("/", 1)[0] + "/tf_record.*.txt" + file_pattern = filenames[0].rsplit(os.sep, 1)[0] + "/tf_record.*.txt" dataset = dataset_ops.Dataset.list_files(file_pattern, shuffle=False) dataset = dataset.flat_map(readers.TFRecordDataset) dataset = input_ops.auto_shard_dataset( -- GitLab From 7e70dc43172e1164672ad06be1fbf0361600a52c Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Thu, 29 Nov 2018 13:54:40 -0800 Subject: [PATCH 574/672] Fix relative path to current directory being empty case for windows file system CreateDir function. PiperOrigin-RevId: 223405610 --- tensorflow/core/platform/windows/windows_file_system.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow/core/platform/windows/windows_file_system.cc b/tensorflow/core/platform/windows/windows_file_system.cc index 6cf79634d7..993b9906b1 100644 --- a/tensorflow/core/platform/windows/windows_file_system.cc +++ b/tensorflow/core/platform/windows/windows_file_system.cc @@ -439,6 +439,9 @@ Status WindowsFileSystem::DeleteFile(const string& fname) { Status WindowsFileSystem::CreateDir(const string& name) { Status result; std::wstring ws_name = Utf8ToWideChar(name); + if (ws_name.empty()) { + return errors::AlreadyExists(name); + } if (_wmkdir(ws_name.c_str()) != 0) { result = IOError("Failed to create a directory: " + name, errno); } -- GitLab From 1f2eee4e233b050d9584e59f4702d5fabf76472b Mon Sep 17 00:00:00 2001 From: Katherine Wu Date: Thu, 29 Nov 2018 14:06:19 -0800 Subject: [PATCH 575/672] Add CosineProximity to metrics and losses PiperOrigin-RevId: 223407786 --- tensorflow/python/keras/losses.py | 34 +++++++++++++++ tensorflow/python/keras/losses_test.py | 57 +++++++++++++++++++++++++ tensorflow/python/keras/metrics.py | 37 ++++++++++++++++ tensorflow/python/keras/metrics_test.py | 33 ++++++++++++++ 4 files changed, 161 insertions(+) diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index 83318d6c57..6b8d560102 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -395,6 +395,40 @@ def cosine_proximity(y_true, y_pred): return -math_ops.reduce_sum(y_true * y_pred, axis=-1) +class CosineProximity(Loss): + """Computes the cosine distance between `y_true` and `y_pred`. + + Usage: + + ```python + cosine_loss = tf.losses.CosineProximity() + loss = cosine_loss([0., 1., 1.], [1., 0., 1.]) + print('Loss: ', loss.numpy()) # Loss: -0.5 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss=tf.losses.CosineProximity()) + ``` + """ + + def call(self, y_true, y_pred): + """Calculates the cosine proximity loss. + + Args: + y_true: Ground truth values. + y_pred: The predicted values. + + Returns: + Cosine distance loss. + """ + y_pred = ops.convert_to_tensor(y_pred) + y_true = math_ops.cast(y_true, y_pred.dtype) + return cosine_proximity(y_true, y_pred) + + # Aliases. mse = MSE = mean_squared_error diff --git a/tensorflow/python/keras/losses_test.py b/tensorflow/python/keras/losses_test.py index b5e9a24c99..cbf3c3524c 100644 --- a/tensorflow/python/keras/losses_test.py +++ b/tensorflow/python/keras/losses_test.py @@ -442,5 +442,62 @@ class MeanSquaredLogarithmicErrorTest(test.TestCase): self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) +@test_util.run_all_in_graph_and_eager_modes +class CosineProximityTest(test.TestCase): + + def test_config(self): + cosine_obj = keras.losses.CosineProximity( + reduction=losses_impl.ReductionV2.SUM, name='cosine_loss') + self.assertEqual(cosine_obj.name, 'cosine_loss') + self.assertEqual(cosine_obj.reduction, losses_impl.ReductionV2.SUM) + + def test_unweighted(self): + cosine_obj = keras.losses.CosineProximity() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = cosine_obj(y_true, y_pred) + self.assertAlmostEqual(self.evaluate(loss), -0.18722, 3) + + def test_scalar_weighted(self): + cosine_obj = keras.losses.CosineProximity() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = cosine_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), -0.43060, 3) + + def test_sample_weighted(self): + cosine_obj = keras.losses.CosineProximity() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + sample_weight = constant_op.constant([1.2, 3.4], shape=(2, 1)) + loss = cosine_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 0.15599, 3) + + def test_timestep_weighted(self): + cosine_obj = keras.losses.CosineProximity() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3, 1), + dtype=dtypes.float32) + sample_weight = constant_op.constant([3, 6, 5, 0, 4, 2], shape=(2, 3)) + loss = cosine_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), -2.0000, 3) + + def test_zero_weighted(self): + cosine_obj = keras.losses.CosineProximity() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = cosine_obj(y_true, y_pred, sample_weight=0) + self.assertAlmostEqual(self.evaluate(loss), 0., 3) + + if __name__ == '__main__': test.main() diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 0519493a0a..3c2682e4c6 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -1477,6 +1477,43 @@ class SpecificityAtSensitivity(SensitivitySpecificityBase): self.tn[min_index] + self.fp[min_index]) +class CosineProximity(MeanMetricWrapper): + """Computes the cosine distance between the labels and predictions. + + For example, if `y_true` is [0, 1, 1], and `y_pred` is [1, 0, 1], the cosine + proximity is -0.5. + + This metric keeps the average cosine distance between `predictions` and + `labels` over a stream of data. + + Usage: + ```python + m = tf.metrics.CosineProximity() + m.update_state([0, 1, 1], [1, 0, 1]) + print('Final result: ', m.result().numpy()) # Final result: -0.5 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile( + 'sgd', + loss='mse', + metrics=[tf.metrics.CosineProximity()]) + ``` + """ + + def __init__(self, name='cosine_proximity', dtype=None): + super(CosineProximity, self).__init__(cosine, name, dtype=dtype) + + @classmethod + def from_config(cls, config): + if 'fn' in config: + config.pop('fn') + return super(CosineProximity, cls).from_config(config) + + def accuracy(y_true, y_pred): y_pred.get_shape().assert_is_compatible_with(y_true.get_shape()) if y_true.dtype != y_pred.dtype: diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index 9a88391dc1..92398acd8e 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -1138,5 +1138,38 @@ class SpecificityAtSensitivityTest(test.TestCase, parameterized.TestCase): self.assertEqual(self.evaluate(s_obj.tn), 25.) +@test_util.run_all_in_graph_and_eager_modes +class CosineProximityTest(test.TestCase): + + def test_config(self): + cosine_obj = metrics.CosineProximity(name='my_cos', dtype=dtypes.int32) + self.assertEqual(cosine_obj.name, 'my_cos') + self.assertEqual(cosine_obj._dtype, dtypes.int32) + + def test_unweighted(self): + cosine_obj = metrics.CosineProximity() + self.evaluate(variables.variables_initializer(cosine_obj.variables)) + + y_true = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), + (1, 1, 1, 1, 0), (0, 0, 0, 0, 1))) + y_pred = constant_op.constant(((0, 0, 1, 1, 0), (1, 1, 1, 1, 1), + (0, 1, 0, 1, 0), (1, 1, 1, 1, 1))) + + update_op = cosine_obj.update_state(y_true, y_pred) + self.evaluate(update_op) + result = cosine_obj.result() + self.assertAllClose(-0.60723, result, atol=1e-5) + + def test_weighted(self): + cosine_obj = metrics.CosineProximity() + self.evaluate(variables.variables_initializer(cosine_obj.variables)) + y_true = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), + (1, 1, 1, 1, 0), (0, 0, 0, 0, 1))) + y_pred = constant_op.constant(((0, 0, 1, 1, 0), (1, 1, 1, 1, 1), + (0, 1, 0, 1, 0), (1, 1, 1, 1, 1))) + sample_weight = constant_op.constant((1., 1.5, 2., 2.5)) + result = cosine_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAllClose(-0.59916, self.evaluate(result), atol=1e-5) + if __name__ == '__main__': test.main() -- GitLab From 29574450f8701385b821f8b6701e19df1d41dbe5 Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Thu, 29 Nov 2018 14:17:23 -0800 Subject: [PATCH 576/672] Delegate EagerTensor __bool__ behavior directly to numpy. Numpy also casts non-bools to bool, so after this change EagerTensors that are not dtype bool can be converted to python bools. This also allows any shape EagerTensor with a single element to be converted to a python bool. PiperOrigin-RevId: 223409869 --- tensorflow/python/eager/tensor_test.py | 10 +++++++--- tensorflow/python/framework/ops.py | 8 +------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/eager/tensor_test.py b/tensorflow/python/eager/tensor_test.py index 8c9d5dabe7..25442ff048 100644 --- a/tensorflow/python/eager/tensor_test.py +++ b/tensorflow/python/eager/tensor_test.py @@ -175,9 +175,13 @@ class TFETensorTest(test_util.TensorFlowTestCase): self.assertEqual(dtypes.float64, t.dtype) def testBool(self): - t = _create_tensor(False) - if t: - self.assertFalse(True) + self.assertFalse(bool(_create_tensor(False))) + self.assertFalse(bool(_create_tensor([False]))) + self.assertFalse(bool(_create_tensor([[False]]))) + self.assertFalse(bool(_create_tensor([0]))) + self.assertFalse(bool(_create_tensor([0.]))) + self.assertTrue(bool(_create_tensor([1]))) + self.assertTrue(bool(_create_tensor([1.]))) def testIntDowncast(self): t = _create_tensor(3) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index bd798f9ffa..b5175d3c93 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -910,13 +910,7 @@ class _EagerTensorBase(Tensor): return self._copy(context.context(), "GPU:" + str(gpu_index)) def __bool__(self): - if self._shape_tuple() != (): # pylint: disable=g-explicit-bool-comparison - raise ValueError( - "Non-scalar tensor %s cannot be converted to boolean." % repr(self)) - if self.dtype != dtypes.bool: - raise ValueError( - "Non-boolean tensor %s cannot be converted to boolean." % repr(self)) - return bool(self.cpu().numpy()) + return bool(self.numpy()) def __nonzero__(self): return self.__bool__() -- GitLab From 675f415603ad0bb0217459672fffbbe798e01d84 Mon Sep 17 00:00:00 2001 From: Austin Anderson Date: Fri, 24 Aug 2018 17:01:55 -0700 Subject: [PATCH 577/672] Upgrade Dockerfile assembler system This is a big upgrade to the Dockerfile assembler I wrote a couple of months ago. The spec has changed, the script has been rewritten, and there are new features throughout: - The assembler can build and upload images to Docker Hub. - The assembler can also run tests (!), although the testing system is extremely rudimentary. It could be expanded with parallelism later, if execution time becomes a problem. - spec.yml is totally different, and now defines both dockerfiles and images. It handles the combinatorial explosion of multiple optional features without excessive duplication, unlike the previous spec format. - Partials are the same, but I dumped the extensive dockerfile documentation support because I don't think anyone would have used it. - Dockerfiles are handled under the same kind of system as images, which is neat. The new Dockerfiles aren't so duplicated. - I've upgraded the images with new tensorflow tutorial files (jupyter only) and fixed some others that didn't actually work. - I've improved the development documentation by suggesting aliases. - Added "static-dockerfiles" directory to track independent Dockerfiles. These changes should better support changes like #23194. --- tensorflow/tools/dockerfiles/.gitignore | 1 + tensorflow/tools/dockerfiles/README.md | 49 +- tensorflow/tools/dockerfiles/assembler.py | 904 ++++++++++-------- .../dockerfiles/cpu-devel-jupyter.Dockerfile | 63 +- .../dockerfiles/cpu-devel.Dockerfile | 46 +- .../dockerfiles/cpu-jupyter.Dockerfile | 52 +- .../dockerfiles/dockerfiles/cpu.Dockerfile | 35 +- ...ockerfile => gpu-devel-jupyter.Dockerfile} | 75 +- ...-devel.Dockerfile => gpu-devel.Dockerfile} | 58 +- ...yter.Dockerfile => gpu-jupyter.Dockerfile} | 61 +- .../{nvidia.Dockerfile => gpu.Dockerfile} | 44 +- .../partials/jupyter.partial.Dockerfile | 15 +- .../partials/tensorflow.partial.Dockerfile | 7 +- .../partials/test-import.partial.Dockerfile | 0 .../partials/ubuntu.partial.Dockerfile | 2 - .../{ => ubuntu}/bazel.partial.Dockerfile | 14 + .../cpu-devel.partial.Dockerfile} | 7 +- .../partials/ubuntu/cpu.partial.Dockerfile | 1 + .../nvidia-devel.partial.Dockerfile | 18 +- .../{ => ubuntu}/nvidia.partial.Dockerfile | 8 +- .../{ => ubuntu}/python.partial.Dockerfile | 5 +- .../ubuntu/test-devel.partial.Dockerfile | 0 .../ubuntu/version.partial.Dockerfile | 1 + tensorflow/tools/dockerfiles/spec.yml | 320 +++---- .../tools/dockerfiles/tests/build-cpu.sh | 22 + .../tools/dockerfiles/tests/build-gpu.sh | 20 + .../tools/dockerfiles/tests/import-gpu.sh | 2 + tensorflow/tools/dockerfiles/tests/import.sh | 3 + ...{assembler.Dockerfile => tools.Dockerfile} | 5 +- 29 files changed, 1018 insertions(+), 820 deletions(-) create mode 100644 tensorflow/tools/dockerfiles/.gitignore rename tensorflow/tools/dockerfiles/dockerfiles/{nvidia-devel-jupyter.Dockerfile => gpu-devel-jupyter.Dockerfile} (67%) rename tensorflow/tools/dockerfiles/dockerfiles/{nvidia-devel.Dockerfile => gpu-devel.Dockerfile} (76%) rename tensorflow/tools/dockerfiles/dockerfiles/{nvidia-jupyter.Dockerfile => gpu-jupyter.Dockerfile} (63%) rename tensorflow/tools/dockerfiles/dockerfiles/{nvidia.Dockerfile => gpu.Dockerfile} (69%) create mode 100644 tensorflow/tools/dockerfiles/partials/test-import.partial.Dockerfile delete mode 100644 tensorflow/tools/dockerfiles/partials/ubuntu.partial.Dockerfile rename tensorflow/tools/dockerfiles/partials/{ => ubuntu}/bazel.partial.Dockerfile (58%) rename tensorflow/tools/dockerfiles/partials/{ubuntu-devel.partial.Dockerfile => ubuntu/cpu-devel.partial.Dockerfile} (86%) create mode 100644 tensorflow/tools/dockerfiles/partials/ubuntu/cpu.partial.Dockerfile rename tensorflow/tools/dockerfiles/partials/{ => ubuntu}/nvidia-devel.partial.Dockerfile (78%) rename tensorflow/tools/dockerfiles/partials/{ => ubuntu}/nvidia.partial.Dockerfile (78%) rename tensorflow/tools/dockerfiles/partials/{ => ubuntu}/python.partial.Dockerfile (66%) create mode 100644 tensorflow/tools/dockerfiles/partials/ubuntu/test-devel.partial.Dockerfile create mode 100644 tensorflow/tools/dockerfiles/partials/ubuntu/version.partial.Dockerfile create mode 100755 tensorflow/tools/dockerfiles/tests/build-cpu.sh create mode 100755 tensorflow/tools/dockerfiles/tests/build-gpu.sh create mode 100755 tensorflow/tools/dockerfiles/tests/import-gpu.sh create mode 100755 tensorflow/tools/dockerfiles/tests/import.sh rename tensorflow/tools/dockerfiles/{assembler.Dockerfile => tools.Dockerfile} (95%) diff --git a/tensorflow/tools/dockerfiles/.gitignore b/tensorflow/tools/dockerfiles/.gitignore new file mode 100644 index 0000000000..d7efa472a9 --- /dev/null +++ b/tensorflow/tools/dockerfiles/.gitignore @@ -0,0 +1 @@ +dockerfiles/*.temp.Dockerfile diff --git a/tensorflow/tools/dockerfiles/README.md b/tensorflow/tools/dockerfiles/README.md index 7c8ca1d1c7..2ac68666d0 100644 --- a/tensorflow/tools/dockerfiles/README.md +++ b/tensorflow/tools/dockerfiles/README.md @@ -1,8 +1,12 @@ # TensorFlow Dockerfiles -This directory houses TensorFlow's Dockerfiles. **DO NOT EDIT THE DOCKERFILES -MANUALLY!** They are maintained by `assembler.py`, which builds Dockerfiles from -the files in `partials/` and the rules in `spec.yml`. See [the Contributing +This directory houses TensorFlow's Dockerfiles and the infrastructure used to +create and deploy them to [Docker +Hub](https://hub.docker.com/r/tensorflow/tensorflow). + +**DO NOT EDIT THE DOCKERFILES/ DIRECTORY MANUALLY!** The files within are +maintained by `assembler.py`, which builds Dockerfiles from the files in +`partials/` and the rules in `spec.yml`. See [the Contributing section](#contributing) for more information. These Dockerfiles are planned to replace the Dockerfiles used to generate @@ -20,10 +24,10 @@ $ docker build -f ./dockerfiles/cpu.Dockerfile -t tf . Each Dockerfile has its own set of available `--build-arg`s which are documented in the Dockerfile itself. -## Running +## Running Locally Built Images After building the image with the tag `tf` (for example), use `docker run` to -run the images. Examples are below. +run the images. Note for new Docker users: the `-v` and `-u` flags share directories between the Docker container and your machine, and very important. Without @@ -42,8 +46,10 @@ $ docker run -u $(id -u):$(id -g) -v $(pwd):/my-devel -it tf # GPU-based images (set up nvidia-docker2 first) $ docker run --runtime=nvidia -u $(id -u):$(id -g) -v $(pwd):/my-devel -it tf -# Images with Jupyter run on port 8888, and needs a volume for notebooks -$ docker run --user $(id -u):$(id -g) -p 8888:8888 -v $(pwd):/notebooks -it tf +# Images with Jupyter run on port 8888 and need a volume for your notebooks +# You can change $(PWD) to the full path to a directory if your notebooks +# live outside the current directory. +$ docker run --user $(id -u):$(id -g) -p 8888:8888 -v $(PWD):/tf/notebooks -it tf ``` These images do not come with the TensorFlow source code -- but the development @@ -60,11 +66,32 @@ You can use the `Dockerfile` in this directory to build an editing environment that has all of the Python dependencies you'll need: ```bash -$ docker build -t tf-assembler -f assembler.Dockerfile . +# Build the tools-helper image so you can run the assembler +$ docker build -t tf-tools -f tools.Dockerfile . # Set --user to set correct permissions on generated files -$ docker run --user $(id -u):$(id -g) -it -v $(pwd):/tf tf-assembler bash +$ docker run --user $(id -u):$(id -g) -it -v $(pwd):/tf tf-tools bash + +# Next you can make a handy alias depending on what you're doing. When building +# Docker images, you need to run as root with docker.sock mounted so that the +# container can run Docker commands. When assembling Dockerfiles, though, you'll +# want to run as your user so that new files have the right permissions. + +# If you're BUILDING OR DEPLOYING DOCKER IMAGES, run as root with docker.sock: +$ alias asm_images="docker run --rm -v $(pwd):/tf -v /var/run/docker.sock:/var/run/docker.sock tf-tools python3 assembler.py " + +# If you're REBUILDING OR ADDING DOCKERFILES, remove docker.sock and add -u: +$ alias asm_dockerfiles="docker run --rm -u $(id -u):$(id -g) -v $(pwd):/tf tf-tools python3 assembler.py " + +# Check flags +$ asm_dockerfiles --help + +# Assemble all of the Dockerfiles +$ asm_dockerfiles --release ubuntu-dockerfiles --construct_dockerfiles + +# Build all of the "nightly" images on your local machine: +$ asm_images --release nightly --build_images -# In the container... -/tf $ python3 ./assembler.py -o dockerfiles -s spec.yml +# Build version release for version 99.0, except "gpu" tags: +$ asm_images --release versioned --arg _TAG_PREFIX=99.0 --build_images --exclude_tags_matching '*.gpu.*' ``` diff --git a/tensorflow/tools/dockerfiles/assembler.py b/tensorflow/tools/dockerfiles/assembler.py index 9cdd9bb0cb..8d97e1d7dc 100644 --- a/tensorflow/tools/dockerfiles/assembler.py +++ b/tensorflow/tools/dockerfiles/assembler.py @@ -1,73 +1,140 @@ -# Copyright 2018 The TensorFlow Authors. 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. -# ============================================================================== -"""Assemble common TF Dockerfiles from many parts. - -This script constructs TF's Dockerfiles by aggregating partial -Dockerfiles. See README.md for usage examples. +"""Multipurpose TensorFlow Docker Helper. + +- Assembles Dockerfiles +- Builds images (and optionally runs image tests) +- Pushes images to Docker Hub (provided with credentials) + +Read README.md (in this directory) for instructions! """ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import collections import copy import errno +import itertools +import multiprocessing import os -import os.path import re import shutil -import textwrap +import sys from absl import app from absl import flags import cerberus +import docker import yaml FLAGS = flags.FLAGS +flags.DEFINE_string('hub_username', None, + 'Dockerhub username, only used with --upload_to_hub') + +flags.DEFINE_string( + 'hub_password', None, + ('Dockerhub password, only used with --upload_to_hub. Use from an env param' + 'so your password isn\'t in your history.')) + +flags.DEFINE_integer('hub_timeout', 3600, + 'Abort Hub upload if it takes longer than this.') + +flags.DEFINE_string( + 'repository', 'tensorflow', + 'Tag local images as {repository}:tag (in addition to the ' + 'hub_repository, if uploading to hub)') + +flags.DEFINE_string( + 'hub_repository', None, + 'Push tags to this Docker Hub repository, e.g. tensorflow/tensorflow') + +flags.DEFINE_boolean( + 'upload_to_hub', + False, + ('Push built images to Docker Hub (you must also provide --hub_username, ' + '--hub_password, and --hub_repository)'), + short_name='u', +) + +flags.DEFINE_boolean( + 'construct_dockerfiles', False, 'Do not build images', short_name='d') + flags.DEFINE_boolean( - 'dry_run', False, 'Do not actually generate Dockerfiles', short_name='n') + 'keep_temp_dockerfiles', + False, + 'Retain .temp.Dockerfiles created while building images.', + short_name='k') + +flags.DEFINE_boolean( + 'build_images', False, 'Do not build images', short_name='b') flags.DEFINE_string( - 'spec_file', - './spec.yml', - 'Path to a YAML specification file', - short_name='s') + 'run_tests_path', None, + ('Execute test scripts on generated Dockerfiles before pushing them. ' + 'Flag value must be a full path to the "tests" directory, which is usually' + ' $(realpath ./tests). A failed tests counts the same as a failed build.')) + +flags.DEFINE_boolean( + 'stop_on_failure', False, + ('Stop processing tags if any one build fails. If False or not specified, ' + 'failures are reported but do not affect the other images.')) + +flags.DEFINE_boolean( + 'dry_run', + False, + 'Do not build or deploy anything at all.', + short_name='n', +) + +flags.DEFINE_string( + 'exclude_tags_matching', + None, + ('Regular expression that skips processing on any tag it matches. Must ' + 'match entire string, e.g. ".*gpu.*" ignores all GPU tags.'), + short_name='x') + +flags.DEFINE_string( + 'only_tags_matching', + None, + ('Regular expression that skips processing on any tag it does not match. ' + 'Must match entire string, e.g. ".*gpu.*" includes only GPU tags.'), + short_name='i') flags.DEFINE_string( - 'output_dir', - './dockerfiles', ('Path to an output directory for Dockerfiles. ' - 'Will be created if it doesn\'t exist.'), + 'dockerfile_dir', + './dockerfiles', 'Path to an output directory for Dockerfiles.' + ' Will be created if it doesn\'t exist.' + ' Existing files in this directory will be deleted when new Dockerfiles' + ' are made.', short_name='o') flags.DEFINE_string( 'partial_dir', './partials', - 'Path to a directory containing foo.partial.Dockerfile partial files.', + 'Path to a directory containing foo.partial.Dockerfile partial files.' + ' can have subdirectories, e.g. "bar/baz.partial.Dockerfile".', short_name='p') -flags.DEFINE_boolean( - 'quiet_dry_run', - True, - 'Do not print contents of dry run Dockerfiles.', - short_name='q') +flags.DEFINE_multi_string( + 'release', [], + 'Set of releases to build and tag. Defaults to every release type.', + short_name='r') -flags.DEFINE_boolean( - 'validate', True, 'Validate generated Dockerfiles', short_name='c') +flags.DEFINE_multi_string( + 'arg', [], + ('Extra build arguments. These are used for expanding tag names if needed ' + '(e.g. --arg _TAG_PREFIX=foo) and for using as build arguments (unused ' + 'args will print a warning).'), + short_name='a') + +flags.DEFINE_string( + 'spec_file', + './spec.yml', + 'Path to the YAML specification file', + short_name='s') -# Schema to verify the contents of spec.yml with Cerberus. +# Schema to verify the contents of tag-spec.yml with Cerberus. # Must be converted to a dict from yaml to work. # Note: can add python references with e.g. # !!python/name:builtins.str @@ -76,478 +143,513 @@ SCHEMA_TEXT = """ header: type: string -partials: +slice_sets: type: dict keyschema: type: string valueschema: - type: dict - schema: - desc: - type: string - args: + type: list + schema: type: dict - keyschema: - type: string - valueschema: - anyof: - - type: [ boolean, number, string ] - - type: dict - schema: - default: - type: [ boolean, number, string ] - desc: - type: string - options: - type: list - schema: - type: string - -images: + schema: + add_to_name: + type: string + dockerfile_exclusive_name: + type: string + partials: + type: list + schema: + type: string + ispartial: true + test_runtime: + type: string + required: false + tests: + type: list + default: [] + schema: + type: string + args: + type: list + default: [] + schema: + type: string + isfullarg: true + +releases: + type: dict keyschema: type: string valueschema: type: dict schema: - desc: - type: string - arg-defaults: - type: list - schema: - anyof: - - type: dict - keyschema: - type: string - arg_in_use: true - valueschema: - type: string - - type: string - isimage: true - create-dockerfile: + is_dockerfiles: type: boolean - partials: + required: false + default: false + upload_images: + type: boolean + required: false + default: true + tag_specs: type: list + required: true schema: - anyof: - - type: dict - keyschema: - type: string - regex: image - valueschema: - type: string - isimage: true - - type: string - ispartial: true + type: string """ -class TfDockerValidator(cerberus.Validator): - """Custom Cerberus validator for TF dockerfile spec. +class TfDockerTagValidator(cerberus.Validator): + """Custom Cerberus validator for TF tag spec. Note: Each _validate_foo function's docstring must end with a segment describing its own validation schema, e.g. "The rule's arguments are...". If you add a new validator, you can copy/paste that section. """ - def _validate_ispartial(self, ispartial, field, value): - """Validate that a partial references an existing partial spec. + def __init__(self, *args, **kwargs): + # See http://docs.python-cerberus.org/en/stable/customize.html + if 'partials' in kwargs: + self.partials = kwargs['partials'] + super(cerberus.Validator, self).__init__(*args, **kwargs) + + def _validate_isvariant(self, isvariant, field, value): + """Validate that a variant references an existing variant spec. Args: - ispartial: Value of the rule, a bool + isvariant: Value of the rule, a bool field: The field being validated value: The field's value - The rule's arguments are validated against this schema: {'type': 'boolean'} """ - if ispartial and value not in self.root_document.get('partials', dict()): - self._error(field, '{} is not an existing partial.'.format(value)) + if isvariant and value not in self.root_document.get('variants', dict()): + self._error(field, '{} is not an existing variant.'.format(value)) - def _validate_isimage(self, isimage, field, value): - """Validate that an image references an existing partial spec. + def _validate_ispartial(self, ispartial, field, value): + """Validate that a partial references an existing partial spec. Args: - isimage: Value of the rule, a bool + ispartial: Value of the rule, a bool field: The field being validated value: The field's value - The rule's arguments are validated against this schema: {'type': 'boolean'} """ - if isimage and value not in self.root_document.get('images', dict()): - self._error(field, '{} is not an existing image.'.format(value)) + if ispartial and value not in self.partials: + self._error(field, + '{} is not present in the partials directory.'.format(value)) - def _validate_arg_in_use(self, arg_in_use, field, value): - """Validate that an arg references an existing partial spec's args. + def _validate_isfullarg(self, isfullarg, field, value): + """Validate that a string is either a FULL=arg or NOT. Args: - arg_in_use: Value of the rule, a bool + isfullarg: Value of the rule, a bool field: The field being validated value: The field's value - The rule's arguments are validated against this schema: {'type': 'boolean'} """ - if arg_in_use: - for partial in self.root_document.get('partials', dict()).values(): - if value in partial.get('args', tuple()): - return + if isfullarg and '=' not in value: + self._error(field, '{} should be of the form ARG=VALUE.'.format(value)) + if not isfullarg and '=' in value: + self._error(field, '{} should be of the form ARG (no =).'.format(value)) - self._error(field, '{} is not an arg used in any partial.'.format(value)) +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, flush=True, **kwargs) -def build_partial_description(partial_spec): - """Create the documentation lines for a specific partial. - Generates something like this: +def aggregate_all_slice_combinations(spec, slice_set_names): + """Figure out all of the variant groupings for a spec.""" + slice_sets = copy.deepcopy(spec['slice_sets']) - # This is the partial's description, from spec.yml. - # --build-arg ARG_NAME=argdefault - # this is one of the args. - # --build-arg ANOTHER_ARG=(some|choices) - # another arg. + for name in slice_set_names: + for slice_set in slice_sets[name]: + slice_set['set_name'] = name - Args: - partial_spec: A dict representing one of the partials from spec.yml. Doesn't - include the name of the partial; is a dict like { desc: ..., args: ... }. + slices_grouped_but_not_keyed = [slice_sets[name] for name in slice_set_names] + all_slice_combos = list(itertools.product(*slices_grouped_but_not_keyed)) + return all_slice_combos - Returns: - A commented string describing this partial. - """ - # Start from linewrapped desc field - lines = [] - wrapper = textwrap.TextWrapper( - initial_indent='# ', subsequent_indent='# ', width=80) - description = wrapper.fill(partial_spec.get('desc', '( no comments )')) - lines.extend(['#', description]) - - # Document each arg - for arg, arg_data in partial_spec.get('args', dict()).items(): - # Wrap arg description with comment lines - desc = arg_data.get('desc', '( no description )') - desc = textwrap.fill( - desc, - initial_indent='# ', - subsequent_indent='# ', - width=80, - drop_whitespace=False) - - # Document (each|option|like|this) - if 'options' in arg_data: - arg_options = ' ({})'.format('|'.join(arg_data['options'])) - else: - arg_options = '' +def build_name_from_slices(format_string, slices, args, is_dockerfile=False): + """Build the tag name (cpu-devel...) from a list of slices.""" + name_formatter = copy.deepcopy(args) + name_formatter.update({s['set_name']: s['add_to_name'] for s in slices}) + name_formatter.update({ + s['set_name']: s['dockerfile_exclusive_name'] + for s in slices + if is_dockerfile and 'dockerfile_exclusive_name' in s + }) + name = format_string.format(**name_formatter) + return name - # Add usage sample - arg_use = '# --build-arg {}={}{}'.format(arg, - arg_data.get('default', '(unset)'), - arg_options) - lines.extend([arg_use, desc]) - return '\n'.join(lines) +def update_args_dict(args_dict, updater): + """Update a dict of arg values with more values from a list or dict.""" + if isinstance(updater, list): + for arg in updater: + key, sep, value = arg.partition('=') + if sep == '=': + args_dict[key] = value + if isinstance(updater, dict): + for key, value in updater.items(): + args_dict[key] = value + return args_dict -def construct_contents(partial_specs, image_spec): - """Assemble the dockerfile contents for an image spec. +def get_slice_sets_and_required_args(slice_sets, tag_spec): + """Extract used-slice-sets and required CLI arguments from a spec string. - It assembles a concrete list of partial references into a single, large - string. - Also expands argument defaults, so that the resulting Dockerfile doesn't have - to be configured with --build-arg=... every time. That is, any ARG directive - will be updated with a new default value. + For example, {FOO}{bar}{bat} finds FOO, bar, and bat. Assuming bar and bat + are both named slice sets, FOO must be specified on the command line. Args: - partial_specs: The dict from spec.yml["partials"]. - image_spec: One of the dict values from spec.yml["images"]. + slice_sets: Dict of named slice sets + tag_spec: The tag spec string, e.g. {_FOO}{blep} Returns: - A string containing a valid Dockerfile based on the partials listed in - image_spec. + (used_slice_sets, required_args), a tuple of lists """ - processed_partial_strings = [] - for partial_name in image_spec['partials']: - # Apply image arg-defaults to existing arg defaults - partial_spec = copy.deepcopy(partial_specs[partial_name]) - args = partial_spec.get('args', dict()) - for k_v in image_spec.get('arg-defaults', []): - arg, value = list(k_v.items())[0] - if arg in args: - args[arg]['default'] = value - - # Read partial file contents - filename = partial_spec.get('file', partial_name) - partial_path = os.path.join(FLAGS.partial_dir, - '{}.partial.Dockerfile'.format(filename)) - with open(partial_path, 'r') as f_partial: - partial_contents = f_partial.read() - - # Replace ARG FOO=BAR with ARG FOO=[new-default] - for arg, arg_data in args.items(): - if 'default' in arg_data and arg_data['default']: - default = '={}'.format(arg_data['default']) - else: - default = '' - partial_contents = re.sub(r'ARG {}.*'.format(arg), 'ARG {}{}'.format( - arg, default), partial_contents) - - # Store updated partial contents - processed_partial_strings.append(partial_contents) - - # Join everything together - return '\n'.join(processed_partial_strings) - - -def mkdir_p(path): - """Create a directory and its parents, even if it already exists.""" - try: - os.makedirs(path) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - -def construct_documentation(header, partial_specs, image_spec): - """Assemble all of the documentation for a single dockerfile. - - Builds explanations of included partials and available build args. - - Args: - header: The string from spec.yml["header"]; will be commented and wrapped. - partial_specs: The dict from spec.yml["partials"]. - image_spec: The spec for the dockerfile being built. - - Returns: - A string containing a commented header that documents the contents of the - dockerfile. - - """ - # Comment and wrap header and image description - commented_header = '\n'.join( - [('# ' + l).rstrip() for l in header.splitlines()]) - commented_desc = '\n'.join( - ['# ' + l for l in image_spec.get('desc', '').splitlines()]) - partial_descriptions = [] - - # Build documentation for each partial in the image - for partial in image_spec['partials']: - # Copy partial data for default args unique to this image - partial_spec = copy.deepcopy(partial_specs[partial]) - args = partial_spec.get('args', dict()) - - # Overwrite any existing arg defaults - for k_v in image_spec.get('arg-defaults', []): - arg, value = list(k_v.items())[0] - if arg in args: - args[arg]['default'] = value - - # Build the description from new args - partial_description = build_partial_description(partial_spec) - partial_descriptions.append(partial_description) - - contents = [commented_header, '#', commented_desc] + partial_descriptions - return '\n'.join(contents) + '\n' - - -def normalize_partial_args(partial_specs): - """Normalize the shorthand form of a partial's args specification. - - Turns this: - - partial: - args: - SOME_ARG: arg_value + required_args = [] + used_slice_sets = [] + + extract_bracketed_words = re.compile(r'\{([^}]+)\}') + possible_args_or_slice_set_names = extract_bracketed_words.findall(tag_spec) + for name in possible_args_or_slice_set_names: + if name in slice_sets: + used_slice_sets.append(name) + else: + required_args.append(name) - Into this: + return (used_slice_sets, required_args) - partial: - args: - SOME_ARG: - default: arg_value - Args: - partial_specs: The dict from spec.yml["partials"]. This dict is modified in - place. +def gather_tag_args(slices, cli_input_args, required_args): + """Build a dictionary of all the CLI and slice-specified args for a tag.""" + args = dict() - Returns: - The modified contents of partial_specs. - - """ - for _, partial in partial_specs.items(): - args = partial.get('args', dict()) - for arg, value in args.items(): - if not isinstance(value, dict): - new_value = {'default': value} - args[arg] = new_value - - return partial_specs + for s in slices: + args = update_args_dict(args, s['args']) + args = update_args_dict(args, cli_input_args) + for arg in required_args: + if arg not in args: + eprint(('> Error: {} is not a valid variant, and also isn\'t an arg ' + 'provided on the command line. If it is an arg, please specify ' + 'it with --arg. If not, check the variants list.'.format(arg))) + exit(1) -def flatten_args_references(image_specs): - """Resolve all default-args in each image spec to a concrete dict. + return args - Turns this: - example-image: - arg-defaults: - - MY_ARG: ARG_VALUE +def gather_slice_list_items(slices, key): + """For a list of slices, get the flattened list of all of a certain key.""" + return list(itertools.chain(*[s[key] for s in slices if key in s])) - another-example: - arg-defaults: - - ANOTHER_ARG: ANOTHER_VALUE - - example_image - Into this: +def find_first_slice_value(slices, key): + """For a list of slices, get the first value for a certain key.""" + for s in slices: + if key in s: + return s[key] - example-image: - arg-defaults: - - MY_ARG: ARG_VALUE - another-example: - arg-defaults: - - ANOTHER_ARG: ANOTHER_VALUE - - MY_ARG: ARG_VALUE +def assemble_tags(spec, cli_args, enabled_releases, all_partials): + """Gather all the tags based on our spec. Args: - image_specs: A dict of image_spec dicts; should be the contents of the - "images" key in the global spec.yaml. This dict is modified in place and - then returned. + spec: Nested dict containing full Tag spec + cli_args: List of ARG=foo arguments to pass along to Docker build + enabled_releases: List of releases to parse. Empty list = all + all_partials: Dict of every partial, for reference Returns: - The modified contents of image_specs. + Dict of tags and how to build them """ - for _, image_spec in image_specs.items(): - too_deep = 0 - while str in map(type, image_spec.get('arg-defaults', [])) and too_deep < 5: - new_args = [] - for arg in image_spec['arg-defaults']: - if isinstance(arg, str): - new_args.extend(image_specs[arg]['arg-defaults']) - else: - new_args.append(arg) - - image_spec['arg-defaults'] = new_args - too_deep += 1 + tag_data = collections.defaultdict(list) - return image_specs + for name, release in spec['releases'].items(): + for tag_spec in release['tag_specs']: + if enabled_releases and name not in enabled_releases: + eprint('> Skipping release {}'.format(name)) + continue + used_slice_sets, required_cli_args = get_slice_sets_and_required_args( + spec['slice_sets'], tag_spec) -def flatten_partial_references(image_specs): - """Resolve all partial references in each image spec to a concrete list. + slice_combos = aggregate_all_slice_combinations(spec, used_slice_sets) + for slices in slice_combos: - Turns this: + tag_args = gather_tag_args(slices, cli_args, required_cli_args) + tag_name = build_name_from_slices(tag_spec, slices, tag_args, + release['is_dockerfiles']) + used_partials = gather_slice_list_items(slices, 'partials') + used_tests = gather_slice_list_items(slices, 'tests') + test_runtime = find_first_slice_value(slices, 'test_runtime') + dockerfile_contents = merge_partials(spec['header'], used_partials, + all_partials) - example-image: - partials: - - foo + tag_data[tag_name].append({ + 'release': name, + 'tag_spec': tag_spec, + 'is_dockerfiles': release['is_dockerfiles'], + 'upload_images': release['upload_images'], + 'cli_args': tag_args, + 'partials': used_partials, + 'tests': used_tests, + 'test_runtime': test_runtime, + 'dockerfile_contents': dockerfile_contents, + }) - another-example: - partials: - - bar - - image: example-image - - bat + return tag_data - Into this: - example-image: - partials: - - foo +def merge_partials(header, used_partials, all_partials): + """Merge all partial contents with their header.""" + used_partials = list(used_partials) + return '\n'.join([header] + [all_partials[u] for u in used_partials]) - another-example: - partials: - - bar - - foo - - bat - Args: - image_specs: A dict of image_spec dicts; should be the contents of the - "images" key in the global spec.yaml. This dict is modified in place and - then returned. - Returns: - The modified contents of image_specs. - """ - for _, image_spec in image_specs.items(): - too_deep = 0 - while dict in map(type, image_spec['partials']) and too_deep < 5: - new_partials = [] - for partial in image_spec['partials']: - if isinstance(partial, str): - new_partials.append(partial) - else: - new_partials.extend(image_specs[partial['image']]['partials']) +def upload_in_background(hub_repository, dock, image, tag): + """Upload a docker image (to be used by multiprocessing).""" + image.tag(hub_repository, tag=tag) + for line in list(dock.images.push(hub_repository, tag=tag, stream=True)): + print(line) - image_spec['partials'] = new_partials - too_deep += 1 - return image_specs +def mkdir_p(path): + """Create a directory and its parents, even if it already exists.""" + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise -def construct_dockerfiles(tf_spec): - """Generate a mapping of {"cpu": , ...}. +def gather_existing_partials(partial_path): + """Find and read all available partials. Args: - tf_spec: The full spec.yml loaded as a python object. + partial_path (string): read partials from this directory. Returns: - A string:string dict of short names ("cpu-devel") to Dockerfile contents. + Dict[string, string] of partial short names (like "ubuntu/python" or + "bazel") to the full contents of that partial. """ - names_to_contents = dict() - image_specs = tf_spec['images'] - image_specs = flatten_partial_references(image_specs) - image_specs = flatten_args_references(image_specs) - partial_specs = tf_spec['partials'] - partial_specs = normalize_partial_args(partial_specs) - - for name, image_spec in image_specs.items(): - if not image_spec.get('create-dockerfile', True): - continue - documentation = construct_documentation(tf_spec['header'], partial_specs, - image_spec) - contents = construct_contents(partial_specs, image_spec) - names_to_contents[name] = '\n'.join([documentation, contents]) - - return names_to_contents + partials = dict() + for path, _, files in os.walk(partial_path): + for name in files: + fullpath = os.path.join(path, name) + if '.partial.Dockerfile' not in fullpath: + eprint(('> Probably not a problem: skipping {}, which is not a ' + 'partial.').format(fullpath)) + continue + # partial_dir/foo/bar.partial.Dockerfile -> foo/bar + simple_name = fullpath[len(partial_path) + 1:-len('.partial.dockerfile')] + with open(fullpath, 'r') as f: + partial_contents = f.read() + partials[simple_name] = partial_contents + return partials def main(argv): if len(argv) > 1: - raise app.UsageError('Unexpected command line args found: {}'.format(argv)) + raise app.UsageError('Too many command-line arguments.') + # Read the full spec file, used for everything with open(FLAGS.spec_file, 'r') as spec_file: - tf_spec = yaml.load(spec_file) + tag_spec = yaml.load(spec_file) + + # Get existing partial contents + partials = gather_existing_partials(FLAGS.partial_dir) # Abort if spec.yaml is invalid - if FLAGS.validate: - schema = yaml.load(SCHEMA_TEXT) - v = TfDockerValidator(schema) - if not v.validate(tf_spec): - print('>> ERROR: {} is an invalid spec! The errors are:'.format( - FLAGS.spec_file)) - print(yaml.dump(v.errors, indent=2)) + schema = yaml.load(SCHEMA_TEXT) + v = TfDockerTagValidator(schema, partials=partials) + if not v.validate(tag_spec): + eprint('> Error: {} is an invalid spec! The errors are:'.format( + FLAGS.spec_file)) + eprint(yaml.dump(v.errors, indent=2)) + exit(1) + tag_spec = v.normalized(tag_spec) + + # Assemble tags and images used to build them + all_tags = assemble_tags(tag_spec, FLAGS.arg, FLAGS.release, partials) + + # Empty Dockerfile directory if building new Dockerfiles + if FLAGS.construct_dockerfiles: + eprint('> Emptying Dockerfile dir "{}"'.format(FLAGS.dockerfile_dir)) + shutil.rmtree(FLAGS.dockerfile_dir, ignore_errors=True) + mkdir_p(FLAGS.dockerfile_dir) + + # Set up Docker helper + dock = docker.from_env() + + # Login to Docker if uploading images + if FLAGS.upload_to_hub: + if not FLAGS.hub_username: + eprint('> Error: please set --hub_username when uploading to Dockerhub.') exit(1) - else: - print('>> WARNING: Not validating {}'.format(FLAGS.spec_file)) - - # Generate mapping of { "cpu-devel": "", ... } - names_to_contents = construct_dockerfiles(tf_spec) - - # Write each completed Dockerfile - if not FLAGS.dry_run: - print('>> Emptying destination dir "{}"'.format(FLAGS.output_dir)) - shutil.rmtree(FLAGS.output_dir, ignore_errors=True) - mkdir_p(FLAGS.output_dir) - else: - print('>> Skipping creation of {} (dry run)'.format(FLAGS.output_dir)) - for name, contents in names_to_contents.items(): - path = os.path.join(FLAGS.output_dir, name + '.Dockerfile') - if FLAGS.dry_run: - print('>> Skipping writing contents of {} (dry run)'.format(path)) - print(contents) - else: - mkdir_p(FLAGS.output_dir) - print('>> Writing {}'.format(path)) - with open(path, 'w') as f: - f.write(contents) + if not FLAGS.hub_repository: + eprint( + '> Error: please set --hub_repository when uploading to Dockerhub.') + exit(1) + if not FLAGS.hub_password: + eprint('> Error: please set --hub_password when uploading to Dockerhub.') + exit(1) + dock.login( + username=FLAGS.hub_username, + password=FLAGS.hub_password, + ) + + # Each tag has a name ('tag') and a definition consisting of the contents + # of its Dockerfile, its build arg list, etc. + failed_tags = [] + for tag, tag_defs in all_tags.items(): + for tag_def in tag_defs: + eprint('> Working on {}'.format(tag)) + + if FLAGS.exclude_tags_matching and re.match(FLAGS.exclude_tags_matching, + tag): + eprint('>> Excluded due to match against "{}".'.format( + FLAGS.exclude_tags_matching)) + continue + + if FLAGS.only_tags_matching and not re.match(FLAGS.only_tags_matching, + tag): + eprint('>> Excluded due to failure to match against "{}".'.format( + FLAGS.only_tags_matching)) + continue + + # Write releases marked "is_dockerfiles" into the Dockerfile directory + if FLAGS.construct_dockerfiles: + path = os.path.join(FLAGS.dockerfile_dir, tag + '.Dockerfile') + if tag_def['is_dockerfiles']: + eprint('>> Writing {}...'.format(path)) + if not FLAGS.dry_run: + with open(path, 'w') as f: + f.write(tag_def['dockerfile_contents']) + + # Don't build any images for dockerfile-only releases + if not FLAGS.build_images: + continue + + # Generate a temporary Dockerfile to use to build, since docker-py + # needs a filepath relative to the build context (i.e. the current + # directory) + dockerfile = os.path.join(FLAGS.dockerfile_dir, tag + '.temp.Dockerfile') + if not FLAGS.dry_run: + with open(dockerfile, 'w') as f: + f.write(tag_def['dockerfile_contents']) + eprint('>> (Temporary) writing {}...'.format(dockerfile)) + + repo_tag = '{}:{}'.format(FLAGS.repository, tag) + eprint('>> Building {} using build args:'.format(repo_tag)) + for arg, value in tag_def['cli_args'].items(): + eprint('>>> {}={}'.format(arg, value)) + + # Note that we are NOT using cache_from, which appears to limit + # available cache layers to those from explicitly specified layers. Many + # of our layers are similar between local builds, so we want to use the + # implied local build cache. + tag_failed = False + image, logs = None, [] + if not FLAGS.dry_run: + try: + image, logs = dock.images.build( + timeout=FLAGS.hub_timeout, + path='.', + dockerfile=dockerfile, + buildargs=tag_def['cli_args'], + tag=repo_tag) + + # Print logs after finishing + log_lines = [l.get('stream', '') for l in logs] + eprint(''.join(log_lines)) + + # Run tests if requested, and dump output + # Could be improved by backgrounding, but would need better + # multiprocessing support to track failures properly. + if FLAGS.run_tests_path: + if not tag_def['tests']: + eprint('>>> No tests to run.') + for test in tag_def['tests']: + eprint('>> Testing {}...'.format(test)) + container, = dock.containers.run( + image, + '/tests/' + test, + working_dir='/', + log_config={'type': 'journald'}, + detach=True, + stderr=True, + stdout=True, + volumes={FLAGS.run_tests_path: + {'bind': '/tests', 'mode': 'ro'}}, + runtime=tag_def['test_runtime']), + ret = container.wait() + code = ret['StatusCode'] + out = container.logs(stdout=True, stderr=False) + err = container.logs(stdout=False, stderr=True) + container.remove() + if out: + eprint('>>> Output stdout:') + eprint(out.decode('utf-8')) + else: + eprint('>>> No test standard out.') + if err: + eprint('>>> Output stderr:') + eprint(out.decode('utf-8')) + else: + eprint('>>> No test standard err.') + if code != 0: + eprint('>> {} failed tests with status: "{}"'.format( + repo_tag, code)) + failed_tags.append(tag) + tag_failed = True + if FLAGS.stop_on_failure: + eprint('>> ABORTING due to --stop_on_failure!') + exit(1) + else: + eprint('>> Tests look good!') + + except docker.errors.BuildError as e: + eprint('>> {} failed to build with message: "{}"'.format( + repo_tag, e.msg)) + eprint('>> Build logs follow:') + log_lines = [l.get('stream', '') for l in e.build_log] + eprint(''.join(log_lines)) + failed_tags.append(tag) + tag_failed = True + if FLAGS.stop_on_failure: + eprint('>> ABORTING due to --stop_on_failure!') + exit(1) + + # Clean temporary dockerfiles if they were created earlier + if not FLAGS.keep_temp_dockerfiles: + os.remove(dockerfile) + + # Upload new images to DockerHub as long as they built + passed tests + if FLAGS.upload_to_hub: + if not tag_def['upload_images']: + continue + if tag_failed: + continue + + eprint('>> Uploading to {}:{}'.format(FLAGS.hub_repository, tag)) + if not FLAGS.dry_run: + p = multiprocessing.Process( + target=upload_in_background, + args=(FLAGS.hub_repository, dock, image, tag)) + p.start() + + if failed_tags: + eprint( + '> Some tags failed to build or failed testing, check scrollback for ' + 'errors: {}'.format( + ','.join(failed_tags))) + exit(1) if __name__ == '__main__': diff --git a/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel-jupyter.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel-jupyter.Dockerfile index dab7178db3..ecc8fabcce 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel-jupyter.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel-jupyter.Dockerfile @@ -16,27 +16,12 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, CPU-only environment for developing changes for TensorFlow, with Jupyter included. -# -# Start from Ubuntu, with TF development packages (no GPU support) -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the latest version of Bazel and Python development tools. -# -# Configure TensorFlow's shell prompt and login tools. -# -# Launch Jupyter on execution instead of a bash prompt. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. ARG UBUNTU_VERSION=16.04 -FROM ubuntu:${UBUNTU_VERSION} + +FROM ubuntu:${UBUNTU_VERSION} AS base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -48,7 +33,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ - python-dev \ rsync \ software-properties-common \ unzip \ @@ -59,8 +43,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* + +ENV CI_BUILD_PYTHON python + -ARG USE_PYTHON_3_NOT_2=True +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -72,10 +59,13 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + RUN apt-get update && apt-get install -y \ build-essential \ curl \ @@ -84,6 +74,20 @@ RUN apt-get update && apt-get install -y \ ${PYTHON}-dev \ swig +RUN ${PIP} --no-cache-dir install \ + Pillow \ + h5py \ + keras_applications \ + keras_preprocessing \ + matplotlib \ + mock \ + numpy \ + scipy \ + sklearn \ + pandas \ + && test "${USE_PYTHON_3_NOT_2}" -eq 1 && true || ${PIP} --no-cache-dir install \ + enum34 + # Install bazel RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list && \ curl https://bazel.build/bazel-release.pub.gpg | apt-key add - && \ @@ -93,11 +97,18 @@ RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8 COPY bashrc /etc/bash.bashrc RUN chmod a+rwx /etc/bash.bashrc -RUN ${PIP} install jupyter +RUN ${PIP} install jupyter matplotlib -RUN mkdir /notebooks && chmod a+rwx /notebooks +RUN mkdir -p /tf/tensorflow-tutorials && chmod -R a+rwx /tf/ RUN mkdir /.local && chmod a+rwx /.local -WORKDIR /notebooks +RUN apt-get install -y --no-install-recommends wget +WORKDIR /tf/tensorflow-tutorials +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_classification.ipynb +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_text_classification.ipynb +RUN apt-get autoremove -y && apt-get remove -y wget +WORKDIR /tf EXPOSE 8888 -CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser --allow-root"] +RUN ${PYTHON} -m ipykernel.kernelspec + +CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root"] diff --git a/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel.Dockerfile index 68566ccc8a..2f4a3d6beb 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/cpu-devel.Dockerfile @@ -16,25 +16,12 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, CPU-only environment for developing changes for TensorFlow. -# -# Start from Ubuntu, with TF development packages (no GPU support) -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the latest version of Bazel and Python development tools. -# -# Configure TensorFlow's shell prompt and login tools. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. ARG UBUNTU_VERSION=16.04 -FROM ubuntu:${UBUNTU_VERSION} + +FROM ubuntu:${UBUNTU_VERSION} AS base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -46,7 +33,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ - python-dev \ rsync \ software-properties-common \ unzip \ @@ -57,8 +43,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* + +ENV CI_BUILD_PYTHON python + -ARG USE_PYTHON_3_NOT_2=True +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -70,10 +59,13 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + RUN apt-get update && apt-get install -y \ build-essential \ curl \ @@ -82,6 +74,20 @@ RUN apt-get update && apt-get install -y \ ${PYTHON}-dev \ swig +RUN ${PIP} --no-cache-dir install \ + Pillow \ + h5py \ + keras_applications \ + keras_preprocessing \ + matplotlib \ + mock \ + numpy \ + scipy \ + sklearn \ + pandas \ + && test "${USE_PYTHON_3_NOT_2}" -eq 1 && true || ${PIP} --no-cache-dir install \ + enum34 + # Install bazel RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list && \ curl https://bazel.build/bazel-release.pub.gpg | apt-key add - && \ diff --git a/tensorflow/tools/dockerfiles/dockerfiles/cpu-jupyter.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/cpu-jupyter.Dockerfile index f889ed6f91..166e255289 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/cpu-jupyter.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/cpu-jupyter.Dockerfile @@ -16,31 +16,14 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, CPU-only environment for using TensorFlow, with Jupyter included. -# -# Start from Ubuntu (no GPU support) -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the TensorFlow Python package. -# --build-arg TF_PACKAGE=tensorflow (tensorflow|tensorflow-gpu|tf-nightly|tf-nightly-gpu) -# The specific TensorFlow Python package to install -# -# Configure TensorFlow's shell prompt and login tools. -# -# Launch Jupyter on execution instead of a bash prompt. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. ARG UBUNTU_VERSION=16.04 -FROM ubuntu:${UBUNTU_VERSION} -ARG USE_PYTHON_3_NOT_2=True +FROM ubuntu:${UBUNTU_VERSION} as base + +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -52,21 +35,36 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + +# Options: +# tensorflow +# tensorflow-gpu +# tf-nightly +# tf-nightly-gpu ARG TF_PACKAGE=tensorflow RUN ${PIP} install ${TF_PACKAGE} COPY bashrc /etc/bash.bashrc RUN chmod a+rwx /etc/bash.bashrc -RUN ${PIP} install jupyter +RUN ${PIP} install jupyter matplotlib -RUN mkdir /notebooks && chmod a+rwx /notebooks +RUN mkdir -p /tf/tensorflow-tutorials && chmod -R a+rwx /tf/ RUN mkdir /.local && chmod a+rwx /.local -WORKDIR /notebooks +RUN apt-get install -y --no-install-recommends wget +WORKDIR /tf/tensorflow-tutorials +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_classification.ipynb +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_text_classification.ipynb +RUN apt-get autoremove -y && apt-get remove -y wget +WORKDIR /tf EXPOSE 8888 -CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser --allow-root"] +RUN ${PYTHON} -m ipykernel.kernelspec + +CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root"] diff --git a/tensorflow/tools/dockerfiles/dockerfiles/cpu.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/cpu.Dockerfile index 182a534bed..323f89155b 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/cpu.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/cpu.Dockerfile @@ -16,29 +16,14 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, CPU-only environment for using TensorFlow -# -# Start from Ubuntu (no GPU support) -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the TensorFlow Python package. -# --build-arg TF_PACKAGE=tensorflow (tensorflow|tensorflow-gpu|tf-nightly|tf-nightly-gpu) -# The specific TensorFlow Python package to install -# -# Configure TensorFlow's shell prompt and login tools. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. ARG UBUNTU_VERSION=16.04 -FROM ubuntu:${UBUNTU_VERSION} -ARG USE_PYTHON_3_NOT_2=True +FROM ubuntu:${UBUNTU_VERSION} as base + +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -50,10 +35,18 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + +# Options: +# tensorflow +# tensorflow-gpu +# tf-nightly +# tf-nightly-gpu ARG TF_PACKAGE=tensorflow RUN ${PIP} install ${TF_PACKAGE} diff --git a/tensorflow/tools/dockerfiles/dockerfiles/nvidia-devel-jupyter.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/gpu-devel-jupyter.Dockerfile similarity index 67% rename from tensorflow/tools/dockerfiles/dockerfiles/nvidia-devel-jupyter.Dockerfile rename to tensorflow/tools/dockerfiles/dockerfiles/gpu-devel-jupyter.Dockerfile index 17faa84a68..b77ba52f25 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/nvidia-devel-jupyter.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/gpu-devel-jupyter.Dockerfile @@ -16,28 +16,12 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, Nvidia-GPU-enabled environment for developing changes for TensorFlow, with Jupyter included. -# -# Start from Nvidia's Ubuntu base image with CUDA and CuDNN, with TF development -# packages. -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the latest version of Bazel and Python development tools. -# -# Configure TensorFlow's shell prompt and login tools. -# -# Launch Jupyter on execution instead of a bash prompt. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. ARG UBUNTU_VERSION=16.04 -FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} + +FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} as base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -60,6 +44,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ + python-dev \ rsync \ software-properties-common \ unzip \ @@ -82,11 +67,19 @@ RUN mkdir /usr/local/cuda-9.0/lib && \ ln -s /usr/lib/x86_64-linux-gnu/libnccl.so.2 /usr/local/cuda/lib/libnccl.so.2 && \ ln -s /usr/include/nccl.h /usr/local/cuda/include/nccl.h -# TODO(tobyboyd): Remove after license is excluded from BUILD file. -RUN gunzip /usr/share/doc/libnccl2/NCCL-SLA.txt.gz && \ - cp /usr/share/doc/libnccl2/NCCL-SLA.txt /usr/local/cuda/ +# Configure the build for our CUDA configuration. +ENV CI_BUILD_PYTHON python +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH +ENV TF_NEED_CUDA 1 +ENV TF_NEED_TENSORRT 1 +ENV TF_CUDA_COMPUTE_CAPABILITIES=3.5,5.2,6.0,6.1,7.0 +ENV TF_CUDA_VERSION=9.0 +ENV TF_CUDNN_VERSION=7 + +# NCCL 2.x +ENV TF_NCCL_VERSION=2 -ARG USE_PYTHON_3_NOT_2=True +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -98,10 +91,13 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + RUN apt-get update && apt-get install -y \ build-essential \ curl \ @@ -110,6 +106,20 @@ RUN apt-get update && apt-get install -y \ ${PYTHON}-dev \ swig +RUN ${PIP} --no-cache-dir install \ + Pillow \ + h5py \ + keras_applications \ + keras_preprocessing \ + matplotlib \ + mock \ + numpy \ + scipy \ + sklearn \ + pandas \ + && test "${USE_PYTHON_3_NOT_2}" -eq 1 && true || ${PIP} --no-cache-dir install \ + enum34 + # Install bazel RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list && \ curl https://bazel.build/bazel-release.pub.gpg | apt-key add - && \ @@ -119,11 +129,18 @@ RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8 COPY bashrc /etc/bash.bashrc RUN chmod a+rwx /etc/bash.bashrc -RUN ${PIP} install jupyter +RUN ${PIP} install jupyter matplotlib -RUN mkdir /notebooks && chmod a+rwx /notebooks +RUN mkdir -p /tf/tensorflow-tutorials && chmod -R a+rwx /tf/ RUN mkdir /.local && chmod a+rwx /.local -WORKDIR /notebooks +RUN apt-get install -y --no-install-recommends wget +WORKDIR /tf/tensorflow-tutorials +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_classification.ipynb +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_text_classification.ipynb +RUN apt-get autoremove -y && apt-get remove -y wget +WORKDIR /tf EXPOSE 8888 -CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser --allow-root"] +RUN ${PYTHON} -m ipykernel.kernelspec + +CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root"] diff --git a/tensorflow/tools/dockerfiles/dockerfiles/nvidia-devel.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/gpu-devel.Dockerfile similarity index 76% rename from tensorflow/tools/dockerfiles/dockerfiles/nvidia-devel.Dockerfile rename to tensorflow/tools/dockerfiles/dockerfiles/gpu-devel.Dockerfile index a3ba02a684..bcac1f7015 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/nvidia-devel.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/gpu-devel.Dockerfile @@ -16,26 +16,12 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, Nvidia-GPU-enabled environment for developing changes for TensorFlow. -# -# Start from Nvidia's Ubuntu base image with CUDA and CuDNN, with TF development -# packages. -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the latest version of Bazel and Python development tools. -# -# Configure TensorFlow's shell prompt and login tools. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. ARG UBUNTU_VERSION=16.04 -FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} + +FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} as base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -58,6 +44,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ + python-dev \ rsync \ software-properties-common \ unzip \ @@ -80,11 +67,19 @@ RUN mkdir /usr/local/cuda-9.0/lib && \ ln -s /usr/lib/x86_64-linux-gnu/libnccl.so.2 /usr/local/cuda/lib/libnccl.so.2 && \ ln -s /usr/include/nccl.h /usr/local/cuda/include/nccl.h -# TODO(tobyboyd): Remove after license is excluded from BUILD file. -RUN gunzip /usr/share/doc/libnccl2/NCCL-SLA.txt.gz && \ - cp /usr/share/doc/libnccl2/NCCL-SLA.txt /usr/local/cuda/ +# Configure the build for our CUDA configuration. +ENV CI_BUILD_PYTHON python +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH +ENV TF_NEED_CUDA 1 +ENV TF_NEED_TENSORRT 1 +ENV TF_CUDA_COMPUTE_CAPABILITIES=3.5,5.2,6.0,6.1,7.0 +ENV TF_CUDA_VERSION=9.0 +ENV TF_CUDNN_VERSION=7 + +# NCCL 2.x +ENV TF_NCCL_VERSION=2 -ARG USE_PYTHON_3_NOT_2=True +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -96,10 +91,13 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + RUN apt-get update && apt-get install -y \ build-essential \ curl \ @@ -108,6 +106,20 @@ RUN apt-get update && apt-get install -y \ ${PYTHON}-dev \ swig +RUN ${PIP} --no-cache-dir install \ + Pillow \ + h5py \ + keras_applications \ + keras_preprocessing \ + matplotlib \ + mock \ + numpy \ + scipy \ + sklearn \ + pandas \ + && test "${USE_PYTHON_3_NOT_2}" -eq 1 && true || ${PIP} --no-cache-dir install \ + enum34 + # Install bazel RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list && \ curl https://bazel.build/bazel-release.pub.gpg | apt-key add - && \ diff --git a/tensorflow/tools/dockerfiles/dockerfiles/nvidia-jupyter.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/gpu-jupyter.Dockerfile similarity index 63% rename from tensorflow/tools/dockerfiles/dockerfiles/nvidia-jupyter.Dockerfile rename to tensorflow/tools/dockerfiles/dockerfiles/gpu-jupyter.Dockerfile index fbdea4628a..9d7340abf3 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/nvidia-jupyter.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/gpu-jupyter.Dockerfile @@ -16,30 +16,13 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, Nvidia-GPU-enabled environment for using TensorFlow, with Jupyter included. -# -# NVIDIA with CUDA and CuDNN, no dev stuff -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the TensorFlow Python package. -# --build-arg TF_PACKAGE=tensorflow-gpu (tensorflow|tensorflow-gpu|tf-nightly|tf-nightly-gpu) -# The specific TensorFlow Python package to install -# -# Configure TensorFlow's shell prompt and login tools. -# -# Launch Jupyter on execution instead of a bash prompt. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. + +ARG UBUNTU_VERSION=16.04 -FROM nvidia/cuda:9.0-base-ubuntu16.04 +FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} as base -# Pick up some TF dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ cuda-command-line-tools-9-0 \ @@ -48,6 +31,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cuda-curand-9-0 \ cuda-cusolver-9-0 \ cuda-cusparse-9-0 \ + curl \ libcudnn7=7.2.1.38-1+cuda9.0 \ libnccl2=2.2.13-1+cuda9.0 \ libfreetype6-dev \ @@ -55,6 +39,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ + rsync \ software-properties-common \ unzip \ && \ @@ -66,7 +51,10 @@ RUN apt-get update && \ apt-get update && \ apt-get install libnvinfer4=4.1.2-1+cuda9.0 -ARG USE_PYTHON_3_NOT_2=True +# For CUDA profiling, TensorFlow requires CUPTI. +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH + +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -78,21 +66,36 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools -ARG TF_PACKAGE=tensorflow-gpu +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + +# Options: +# tensorflow +# tensorflow-gpu +# tf-nightly +# tf-nightly-gpu +ARG TF_PACKAGE=tensorflow RUN ${PIP} install ${TF_PACKAGE} COPY bashrc /etc/bash.bashrc RUN chmod a+rwx /etc/bash.bashrc -RUN ${PIP} install jupyter +RUN ${PIP} install jupyter matplotlib -RUN mkdir /notebooks && chmod a+rwx /notebooks +RUN mkdir -p /tf/tensorflow-tutorials && chmod -R a+rwx /tf/ RUN mkdir /.local && chmod a+rwx /.local -WORKDIR /notebooks +RUN apt-get install -y --no-install-recommends wget +WORKDIR /tf/tensorflow-tutorials +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_classification.ipynb +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_text_classification.ipynb +RUN apt-get autoremove -y && apt-get remove -y wget +WORKDIR /tf EXPOSE 8888 -CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser --allow-root"] +RUN ${PYTHON} -m ipykernel.kernelspec + +CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root"] diff --git a/tensorflow/tools/dockerfiles/dockerfiles/nvidia.Dockerfile b/tensorflow/tools/dockerfiles/dockerfiles/gpu.Dockerfile similarity index 69% rename from tensorflow/tools/dockerfiles/dockerfiles/nvidia.Dockerfile rename to tensorflow/tools/dockerfiles/dockerfiles/gpu.Dockerfile index e0312dbc29..e8e6ceafe2 100644 --- a/tensorflow/tools/dockerfiles/dockerfiles/nvidia.Dockerfile +++ b/tensorflow/tools/dockerfiles/dockerfiles/gpu.Dockerfile @@ -16,28 +16,13 @@ # THIS IS A GENERATED DOCKERFILE. # # This file was assembled from multiple pieces, whose use is documented -# below. Please refer to the the TensorFlow dockerfiles documentation for -# more information. Build args are documented as their default value. -# -# Ubuntu-based, Nvidia-GPU-enabled environment for using TensorFlow. -# -# NVIDIA with CUDA and CuDNN, no dev stuff -# --build-arg UBUNTU_VERSION=16.04 -# ( no description ) -# -# Python is required for TensorFlow and other libraries. -# --build-arg USE_PYTHON_3_NOT_2=True -# Install python 3 over Python 2 -# -# Install the TensorFlow Python package. -# --build-arg TF_PACKAGE=tensorflow-gpu (tensorflow|tensorflow-gpu|tf-nightly|tf-nightly-gpu) -# The specific TensorFlow Python package to install -# -# Configure TensorFlow's shell prompt and login tools. +# throughout. Please refer to the the TensorFlow dockerfiles documentation +# for more information. + +ARG UBUNTU_VERSION=16.04 -FROM nvidia/cuda:9.0-base-ubuntu16.04 +FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} as base -# Pick up some TF dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ cuda-command-line-tools-9-0 \ @@ -46,6 +31,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cuda-curand-9-0 \ cuda-cusolver-9-0 \ cuda-cusparse-9-0 \ + curl \ libcudnn7=7.2.1.38-1+cuda9.0 \ libnccl2=2.2.13-1+cuda9.0 \ libfreetype6-dev \ @@ -53,6 +39,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ + rsync \ software-properties-common \ unzip \ && \ @@ -64,7 +51,10 @@ RUN apt-get update && \ apt-get update && \ apt-get install libnvinfer4=4.1.2-1+cuda9.0 -ARG USE_PYTHON_3_NOT_2=True +# For CUDA profiling, TensorFlow requires CUPTI. +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH + +ARG USE_PYTHON_3_NOT_2 ARG _PY_SUFFIX=${USE_PYTHON_3_NOT_2:+3} ARG PYTHON=python${_PY_SUFFIX} ARG PIP=pip${_PY_SUFFIX} @@ -76,11 +66,19 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools -ARG TF_PACKAGE=tensorflow-gpu +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python + +# Options: +# tensorflow +# tensorflow-gpu +# tf-nightly +# tf-nightly-gpu +ARG TF_PACKAGE=tensorflow RUN ${PIP} install ${TF_PACKAGE} COPY bashrc /etc/bash.bashrc diff --git a/tensorflow/tools/dockerfiles/partials/jupyter.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/jupyter.partial.Dockerfile index 2c9b9f3f9a..51b22d1fdf 100644 --- a/tensorflow/tools/dockerfiles/partials/jupyter.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/jupyter.partial.Dockerfile @@ -1,8 +1,15 @@ -RUN ${PIP} install jupyter +RUN ${PIP} install jupyter matplotlib -RUN mkdir /notebooks && chmod a+rwx /notebooks +RUN mkdir -p /tf/tensorflow-tutorials && chmod -R a+rwx /tf/ RUN mkdir /.local && chmod a+rwx /.local -WORKDIR /notebooks +RUN apt-get install -y --no-install-recommends wget +WORKDIR /tf/tensorflow-tutorials +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_classification.ipynb +RUN wget https://raw.githubusercontent.com/tensorflow/docs/master/site/en/tutorials/keras/basic_text_classification.ipynb +RUN apt-get autoremove -y && apt-get remove -y wget +WORKDIR /tf EXPOSE 8888 -CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser --allow-root"] +RUN ${PYTHON} -m ipykernel.kernelspec + +CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root"] diff --git a/tensorflow/tools/dockerfiles/partials/tensorflow.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/tensorflow.partial.Dockerfile index 96e79547f0..76758bd147 100644 --- a/tensorflow/tools/dockerfiles/partials/tensorflow.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/tensorflow.partial.Dockerfile @@ -1,2 +1,7 @@ -ARG TF_PACKAGE +# Options: +# tensorflow +# tensorflow-gpu +# tf-nightly +# tf-nightly-gpu +ARG TF_PACKAGE=tensorflow RUN ${PIP} install ${TF_PACKAGE} diff --git a/tensorflow/tools/dockerfiles/partials/test-import.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/test-import.partial.Dockerfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tensorflow/tools/dockerfiles/partials/ubuntu.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu.partial.Dockerfile deleted file mode 100644 index 0a50735bf8..0000000000 --- a/tensorflow/tools/dockerfiles/partials/ubuntu.partial.Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -ARG UBUNTU_VERSION=16.04 -FROM ubuntu:${UBUNTU_VERSION} diff --git a/tensorflow/tools/dockerfiles/partials/bazel.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/bazel.partial.Dockerfile similarity index 58% rename from tensorflow/tools/dockerfiles/partials/bazel.partial.Dockerfile rename to tensorflow/tools/dockerfiles/partials/ubuntu/bazel.partial.Dockerfile index b08d8bdd14..156bb01991 100644 --- a/tensorflow/tools/dockerfiles/partials/bazel.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/bazel.partial.Dockerfile @@ -6,6 +6,20 @@ RUN apt-get update && apt-get install -y \ ${PYTHON}-dev \ swig +RUN ${PIP} --no-cache-dir install \ + Pillow \ + h5py \ + keras_applications \ + keras_preprocessing \ + matplotlib \ + mock \ + numpy \ + scipy \ + sklearn \ + pandas \ + && test "${USE_PYTHON_3_NOT_2}" -eq 1 && true || ${PIP} --no-cache-dir install \ + enum34 + # Install bazel RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list && \ curl https://bazel.build/bazel-release.pub.gpg | apt-key add - && \ diff --git a/tensorflow/tools/dockerfiles/partials/ubuntu-devel.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/cpu-devel.partial.Dockerfile similarity index 86% rename from tensorflow/tools/dockerfiles/partials/ubuntu-devel.partial.Dockerfile rename to tensorflow/tools/dockerfiles/partials/ubuntu/cpu-devel.partial.Dockerfile index bc79272276..901652cc28 100644 --- a/tensorflow/tools/dockerfiles/partials/ubuntu-devel.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/cpu-devel.partial.Dockerfile @@ -1,5 +1,4 @@ -ARG UBUNTU_VERSION=16.04 -FROM ubuntu:${UBUNTU_VERSION} +FROM ubuntu:${UBUNTU_VERSION} AS base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -11,7 +10,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ - python-dev \ rsync \ software-properties-common \ unzip \ @@ -22,3 +20,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* + +ENV CI_BUILD_PYTHON python + diff --git a/tensorflow/tools/dockerfiles/partials/ubuntu/cpu.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/cpu.partial.Dockerfile new file mode 100644 index 0000000000..d01b26e27f --- /dev/null +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/cpu.partial.Dockerfile @@ -0,0 +1 @@ +FROM ubuntu:${UBUNTU_VERSION} as base diff --git a/tensorflow/tools/dockerfiles/partials/nvidia-devel.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/nvidia-devel.partial.Dockerfile similarity index 78% rename from tensorflow/tools/dockerfiles/partials/nvidia-devel.partial.Dockerfile rename to tensorflow/tools/dockerfiles/partials/ubuntu/nvidia-devel.partial.Dockerfile index 45159f711f..48d457e40c 100644 --- a/tensorflow/tools/dockerfiles/partials/nvidia-devel.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/nvidia-devel.partial.Dockerfile @@ -1,5 +1,4 @@ -ARG UBUNTU_VERSION=16.04 -FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} +FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} as base RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ @@ -22,6 +21,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ + python-dev \ rsync \ software-properties-common \ unzip \ @@ -44,6 +44,14 @@ RUN mkdir /usr/local/cuda-9.0/lib && \ ln -s /usr/lib/x86_64-linux-gnu/libnccl.so.2 /usr/local/cuda/lib/libnccl.so.2 && \ ln -s /usr/include/nccl.h /usr/local/cuda/include/nccl.h -# TODO(tobyboyd): Remove after license is excluded from BUILD file. -RUN gunzip /usr/share/doc/libnccl2/NCCL-SLA.txt.gz && \ - cp /usr/share/doc/libnccl2/NCCL-SLA.txt /usr/local/cuda/ +# Configure the build for our CUDA configuration. +ENV CI_BUILD_PYTHON python +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH +ENV TF_NEED_CUDA 1 +ENV TF_NEED_TENSORRT 1 +ENV TF_CUDA_COMPUTE_CAPABILITIES=3.5,5.2,6.0,6.1,7.0 +ENV TF_CUDA_VERSION=9.0 +ENV TF_CUDNN_VERSION=7 + +# NCCL 2.x +ENV TF_NCCL_VERSION=2 diff --git a/tensorflow/tools/dockerfiles/partials/nvidia.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/nvidia.partial.Dockerfile similarity index 78% rename from tensorflow/tools/dockerfiles/partials/nvidia.partial.Dockerfile rename to tensorflow/tools/dockerfiles/partials/ubuntu/nvidia.partial.Dockerfile index 1064390af3..1dc8e43aad 100644 --- a/tensorflow/tools/dockerfiles/partials/nvidia.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/nvidia.partial.Dockerfile @@ -1,6 +1,5 @@ -FROM nvidia/cuda:9.0-base-ubuntu16.04 +FROM nvidia/cuda:9.0-base-ubuntu${UBUNTU_VERSION} as base -# Pick up some TF dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ cuda-command-line-tools-9-0 \ @@ -9,6 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cuda-curand-9-0 \ cuda-cusolver-9-0 \ cuda-cusparse-9-0 \ + curl \ libcudnn7=7.2.1.38-1+cuda9.0 \ libnccl2=2.2.13-1+cuda9.0 \ libfreetype6-dev \ @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpng12-dev \ libzmq3-dev \ pkg-config \ + rsync \ software-properties-common \ unzip \ && \ @@ -26,3 +27,6 @@ RUN apt-get update && \ apt-get install nvinfer-runtime-trt-repo-ubuntu1604-4.0.1-ga-cuda9.0 && \ apt-get update && \ apt-get install libnvinfer4=4.1.2-1+cuda9.0 + +# For CUDA profiling, TensorFlow requires CUPTI. +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH diff --git a/tensorflow/tools/dockerfiles/partials/python.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/python.partial.Dockerfile similarity index 66% rename from tensorflow/tools/dockerfiles/partials/python.partial.Dockerfile rename to tensorflow/tools/dockerfiles/partials/ubuntu/python.partial.Dockerfile index ee08af73a8..6af4731953 100644 --- a/tensorflow/tools/dockerfiles/partials/python.partial.Dockerfile +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/python.partial.Dockerfile @@ -10,6 +10,9 @@ RUN apt-get update && apt-get install -y \ ${PYTHON} \ ${PYTHON}-pip -RUN ${PIP} install --upgrade \ +RUN ${PIP} --no-cache-dir install --upgrade \ pip \ setuptools + +# Some TF tools expect a "python" binary +RUN ln -s $(which ${PYTHON}) /usr/local/bin/python diff --git a/tensorflow/tools/dockerfiles/partials/ubuntu/test-devel.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/test-devel.partial.Dockerfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tensorflow/tools/dockerfiles/partials/ubuntu/version.partial.Dockerfile b/tensorflow/tools/dockerfiles/partials/ubuntu/version.partial.Dockerfile new file mode 100644 index 0000000000..6ecd2b8b1a --- /dev/null +++ b/tensorflow/tools/dockerfiles/partials/ubuntu/version.partial.Dockerfile @@ -0,0 +1 @@ +ARG UBUNTU_VERSION=16.04 diff --git a/tensorflow/tools/dockerfiles/spec.yml b/tensorflow/tools/dockerfiles/spec.yml index 28bf9a55da..5049e8dcfb 100644 --- a/tensorflow/tools/dockerfiles/spec.yml +++ b/tensorflow/tools/dockerfiles/spec.yml @@ -1,195 +1,135 @@ -# ====== -# HEADER -# ====== -# -# This is commented-out and prepended to each generated Dockerfile. header: | - Copyright 2018 The TensorFlow Authors. 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. - ============================================================================ - - THIS IS A GENERATED DOCKERFILE. - - This file was assembled from multiple pieces, whose use is documented - below. Please refer to the the TensorFlow dockerfiles documentation for - more information. Build args are documented as their default value. - -# ======== -# PARTIALS -# ======== + # Copyright 2018 The TensorFlow Authors. 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. + # ============================================================================ + # + # THIS IS A GENERATED DOCKERFILE. + # + # This file was assembled from multiple pieces, whose use is documented + # throughout. Please refer to the the TensorFlow dockerfiles documentation + # for more information. + +# A combinatorial explosion of Docker images and Dockerfiles. +# Each "release" defines all of the ways to combine related but separate chunks +# of functionality ("slices") by listing all of the "slice sets" to use when +# building. # -# Represent and document pieces of a Dockerfile. Spec: -# -# name: the name of the partial, is referenced from the images section -# desc: A description, inserted later into the Dockerfile -# file: Alternative file prefix, e.g. file.partial.Dockerfile. The default is -# the name of the partial. -# args: A dict of ARGs in the Dockerfile; each entry has the format -# ARG_NAME: VALUE where VALUE is one of: -# - a dict: -# desc: Documentation for the arg -# default: Default value for the arg; is written to the Dockerfile -# options: List of strings, part of documentation -# - a concrete value: the same as a dictionary with default: [value]. - -partials: - ubuntu: - desc: Start from Ubuntu (no GPU support) - args: - UBUNTU_VERSION: 16.04 - - ubuntu-devel: - desc: Start from Ubuntu, with TF development packages (no GPU support) - args: - UBUNTU_VERSION: 16.04 - - bazel: - desc: Install the latest version of Bazel and Python development tools. - - nvidia: - desc: NVIDIA with CUDA and CuDNN, no dev stuff - args: - UBUNTU_VERSION: 16.04 - - nvidia-devel: - desc: > - Start from Nvidia's Ubuntu base image with CUDA and CuDNN, with TF - development packages. - args: - UBUNTU_VERSION: 16.04 +# For example, a release that uses {nightly}{py} would create 4 Dockerfiles +# (which could become images or concrete Dockerfiles), because the "nightly" +# and "py" slice sets both have two entries: +# +# - nightly (no -py2 because the Python 2 slice set has add_to_name: "" +# - nightly-py3 +# - nightly-gpu (similar) +# - nightly-gpu-py3 + +releases: + nightly: + tag_specs: + - "{nightly}{py}{jupyter}" + + versioned: + tag_specs: + - "{_TAG_PREFIX}{ubuntu}{py}{jupyter}" + + ubuntu-dockerfiles: + is_dockerfiles: true + upload_images: false + tag_specs: + - "{ubuntu}{jupyter}" + +slice_sets: + + py: + - add_to_name: "" + args: + - USE_PYTHON_3_NOT_2= + - add_to_name: "-py3" + args: + - USE_PYTHON_3_NOT_2=1 - python: - desc: Python is required for TensorFlow and other libraries. - args: - USE_PYTHON_3_NOT_2: - default: true - desc: Install python 3 over Python 2 - - tensorflow: - desc: Install the TensorFlow Python package. - args: - TF_PACKAGE: - default: tensorflow - options: - - tensorflow - - tensorflow-gpu - - tf-nightly - - tf-nightly-gpu - desc: The specific TensorFlow Python package to install - shell: - desc: Configure TensorFlow's shell prompt and login tools. jupyter: - desc: Launch Jupyter on execution instead of a bash prompt. - -# ====== -# IMAGES -# ====== -# -# Represent Dockerfiles. Spec: -# -# name: the name of the image, possibly referenced by other images -# desc: A description, inserted later into the Dockerfile -# create-dockerfile: Create a dockerfile based on this. Useful for creating -# extensible base images that don't need a file. Default is true. -# partials: List of VALUEs, where a VALUE is either: -# - the name of a partial, which inserts that partial into this image -# - image: [name of another image], which inserts the partials from that -# image into this image -# arg-defaults: List of VALUEs, where a VALUE is either: -# - ARG_NAME: VALUE, which sets the ARG_NAME to VALUE wherever it appears -# in this image's partials -# - [name of another image], which loads the default args from that image -images: - - nodev: - create-dockerfile: false - partials: - - python - - tensorflow - - shell - - dev: - create-dockerfile: false - partials: - - python - - bazel - - shell - - cpu: - desc: Ubuntu-based, CPU-only environment for using TensorFlow - partials: - - ubuntu - - image: nodev - - cpu-devel: - desc: > - Ubuntu-based, CPU-only environment for developing changes for - TensorFlow. - partials: - - ubuntu-devel - - image: dev + - add_to_name: "" + - add_to_name: "-jupyter" + partials: + - jupyter - nvidia: - desc: Ubuntu-based, Nvidia-GPU-enabled environment for using TensorFlow. - arg-defaults: - - TF_PACKAGE: tensorflow-gpu - partials: - - nvidia - - image: nodev - - nvidia-devel: - desc: > - Ubuntu-based, Nvidia-GPU-enabled environment for developing changes - for TensorFlow. - arg-defaults: - - TF_PACKAGE: tensorflow-gpu - partials: - - nvidia-devel - - image: dev - - cpu-jupyter: - desc: > - Ubuntu-based, CPU-only environment for using TensorFlow, with Jupyter - included. - partials: - - image: cpu - - jupyter - - cpu-devel-jupyter: - desc: > - Ubuntu-based, CPU-only environment for developing changes for - TensorFlow, with Jupyter included. - partials: - - image: cpu-devel - - jupyter - - nvidia-jupyter: - desc: > - Ubuntu-based, Nvidia-GPU-enabled environment for using TensorFlow, with - Jupyter included. - arg-defaults: - - nvidia - partials: - - image: nvidia - - jupyter - - nvidia-devel-jupyter: - desc: > - Ubuntu-based, Nvidia-GPU-enabled environment for developing changes for - TensorFlow, with Jupyter included. - arg-defaults: - - nvidia-devel - partials: - - image: nvidia-devel - - jupyter + ubuntu: + - add_to_name: "" + dockerfile_exclusive_name: "cpu" + partials: + - ubuntu/version + - ubuntu/cpu + - ubuntu/python + - tensorflow + - shell + - add_to_name: "-gpu" + dockerfile_exclusive_name: "gpu" + args: + - TF_PACKAGE=tensorflow-gpu + partials: + - ubuntu/version + - ubuntu/nvidia + - ubuntu/python + - tensorflow + - shell + tests: + - import-gpu.sh + test_runtime: nvidia + - add_to_name: "-devel" + dockerfile_exclusive_name: "cpu-devel" + partials: + - ubuntu/version + - ubuntu/cpu-devel + - ubuntu/python + - ubuntu/bazel + - shell + tests: + - build-cpu.sh + - add_to_name: "-gpu-devel" + dockerfile_exclusive_name: "gpu-devel" + partials: + - ubuntu/version + - ubuntu/nvidia-devel + - ubuntu/python + - ubuntu/bazel + - shell + tests: + - build-gpu.sh + test_runtime: nvidia + + nightly: + - add_to_name: "nightly" + partials: + - ubuntu/version + - ubuntu/cpu + - ubuntu/python + - tensorflow + - shell + args: + - TF_PACKAGE=tf-nightly + tests: + - import.sh + - add_to_name: "nightly-gpu" + partials: + - ubuntu/version + - ubuntu/nvidia + - ubuntu/python + - tensorflow + - shell + test_runtime: nvidia + tests: + - import-gpu.sh + args: + - TF_PACKAGE=tf-nightly-gpu diff --git a/tensorflow/tools/dockerfiles/tests/build-cpu.sh b/tensorflow/tools/dockerfiles/tests/build-cpu.sh new file mode 100755 index 0000000000..337239dc38 --- /dev/null +++ b/tensorflow/tools/dockerfiles/tests/build-cpu.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Download and build TensorFlow. +set -euxo pipefail +git clone --branch=master --depth=1 https://github.com/tensorflow/tensorflow.git /tensorflow +cd /tensorflow + +ln -s $(which ${PYTHON}) /usr/local/bin/python + +# For optimized builds appropriate for the hardware platform of your choosing, uncomment below... +# For ivy-bridge or sandy-bridge +# --copt=-march="ivybridge" \ +# for haswell, broadwell, or skylake +# --copt=-march="haswell" \ +tensorflow/tools/ci_build/builds/configured CPU \ + bazel build -c opt --copt=-mavx --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" \ + tensorflow/tools/pip_package:build_pip_package && \ + bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/pip && \ + pip --no-cache-dir install --upgrade /tmp/pip/tensorflow-*.whl && \ + rm -rf /tmp/pip && \ + rm -rf /root/.cache + diff --git a/tensorflow/tools/dockerfiles/tests/build-gpu.sh b/tensorflow/tools/dockerfiles/tests/build-gpu.sh new file mode 100755 index 0000000000..7a1e7ad340 --- /dev/null +++ b/tensorflow/tools/dockerfiles/tests/build-gpu.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Download and build TensorFlow. +set -euxo pipefail +git clone --branch=master --depth=1 https://github.com/tensorflow/tensorflow.git /tensorflow +cd /tensorflow + +ln -s $(which ${PYTHON}) /usr/local/bin/python + +ln -s /usr/local/cuda/lib64/stubs/libcuda.so /usr/local/cuda/lib64/stubs/libcuda.so.1 + +LD_LIBRARY_PATH=/usr/local/cuda/lib64/stubs:${LD_LIBRARY_PATH} \ +tensorflow/tools/ci_build/builds/configured GPU \ +bazel build -c opt --copt=-mavx --config=cuda \ + --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" \ + tensorflow/tools/pip_package:build_pip_package && \ +rm /usr/local/cuda/lib64/stubs/libcuda.so.1 && \ +bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/pip && \ +pip --no-cache-dir install --upgrade /tmp/pip/tensorflow-*.whl && \ +rm -rf /tmp/pip && \ +rm -rf /root/.cache diff --git a/tensorflow/tools/dockerfiles/tests/import-gpu.sh b/tensorflow/tools/dockerfiles/tests/import-gpu.sh new file mode 100755 index 0000000000..214e5ccf2c --- /dev/null +++ b/tensorflow/tools/dockerfiles/tests/import-gpu.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python -c 'import tensorflow as tf; tf.test.is_gpu_available() or exit(1)' diff --git a/tensorflow/tools/dockerfiles/tests/import.sh b/tensorflow/tools/dockerfiles/tests/import.sh new file mode 100755 index 0000000000..79998aad77 --- /dev/null +++ b/tensorflow/tools/dockerfiles/tests/import.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euxo pipefail +python -c 'import tensorflow as tf' diff --git a/tensorflow/tools/dockerfiles/assembler.Dockerfile b/tensorflow/tools/dockerfiles/tools.Dockerfile similarity index 95% rename from tensorflow/tools/dockerfiles/assembler.Dockerfile rename to tensorflow/tools/dockerfiles/tools.Dockerfile index 7a8e07fced..e8929295a5 100644 --- a/tensorflow/tools/dockerfiles/assembler.Dockerfile +++ b/tensorflow/tools/dockerfiles/tools.Dockerfile @@ -20,8 +20,9 @@ FROM debian:stretch LABEL maintainer="Austin Anderson " -RUN apt-get update && apt-get install -y python3 python3-pip bash -RUN pip3 install --upgrade pip setuptools pyyaml absl-py cerberus +RUN apt-get update && apt-get install -y python3 python3-pip bash curl +RUN curl -sSL https://get.docker.com/ | sh +RUN pip3 install --upgrade pip setuptools pyyaml absl-py cerberus docker WORKDIR /tf VOLUME ["/tf"] -- GitLab From a9f443cd1f053949391ace983f271b3aa2a54631 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Thu, 29 Nov 2018 14:20:55 -0800 Subject: [PATCH 578/672] Add publicly available corpus and dictionary for decode_png_fuzz. PiperOrigin-RevId: 223410548 --- tensorflow/core/kernels/fuzzing/BUILD | 5 ++ .../010dc3d4b05288fcc40de2721052b3dc699f1cb3 | Bin 0 -> 233 bytes .../0555cd5e9d99629819cc985285f80da0f00be1e9 | Bin 0 -> 474 bytes .../0a0352aa168803ff65455792d9f6ee555c3e7c3f | Bin 0 -> 232 bytes .../0ed54162df93ef8d00f993ce6b59ba422903d381 | Bin 0 -> 221 bytes .../1547b448171c700613c3946d730de496c9b9863f | Bin 0 -> 260 bytes .../17859046cbe4ac598a645173d679ce2a52c6afba | Bin 0 -> 525 bytes .../1df76c07817fbc3653a26f34d97658e9973627c2 | Bin 0 -> 666 bytes .../1f0717f8856d7782e3ab7992d3a72d783a018443 | Bin 0 -> 122 bytes .../23b911e4ce936def88bc9a46b8b433c0e83fba2a | Bin 0 -> 375 bytes .../25592201c3edff0578dbdac6b0e4f2be109ce151 | Bin 0 -> 329 bytes .../266fd8495e0b8eb64387c1a62264185e061fee73 | Bin 0 -> 360 bytes .../27f178cf415b4ff8671131ddf1d042dafac2fb3e | Bin 0 -> 677 bytes .../2a0bdc4d9cc5ea5bb21dd256d6ac96075376a94f | Bin 0 -> 246 bytes .../2e5d25add6adc68e0457b358c7a34abf3d41c938 | Bin 0 -> 165 bytes .../2e6c5b6a766dd5e9bd41eacfd0a36572bd2f7544 | Bin 0 -> 320 bytes .../2e9c935cf82f6ca640e9a9abc3c30a578ad46176 | Bin 0 -> 666 bytes .../2fcf1ed4477f7eaee028f5b3f9edeb5f1a737826 | Bin 0 -> 507 bytes .../3480713774f590908ca5dba16d121cdfb8fba62b | Bin 0 -> 665 bytes .../39289afcec60d98802b333e0fbb1da4d7aed4ce5 | Bin 0 -> 247 bytes .../3adc488e21d4aca7bed9422f0241a42d0f93e7d9 | Bin 0 -> 366 bytes .../3cbf274da522483dc991fad9df43a22ac4fb3173 | Bin 0 -> 474 bytes .../3d840cdff7f5ad16fe8bcb985ed4946c03459432 | Bin 0 -> 666 bytes .../3f1e6753c1fca958e859189857449746592158ea | Bin 0 -> 94 bytes .../3fa4075993cb0f9bfa8eea785174a2038a69aa1b | Bin 0 -> 343 bytes .../4023a373e977be58413e55350380310c5dd1fd6a | Bin 0 -> 241 bytes .../40caba69dce1cfc48e0e43184d2bfbc6daa4399a | Bin 0 -> 470 bytes .../41841e9561d8135945c1c1e55ab9e9a1e933653b | Bin 0 -> 247 bytes .../41d40f2d66fa43e34537385594ee9911e65deadf | Bin 0 -> 677 bytes .../421bd39810b50309a71adb2dadc3b19f01a52312 | Bin 0 -> 221 bytes .../446c305b2c0665736f94fb2b62dbdef445eff0cf | Bin 0 -> 174 bytes .../449cee952bb645f6f4241a6665d3c6028c073c7a | Bin 0 -> 374 bytes .../45520b07609978c5aa3516d803527438b93fbadb | Bin 0 -> 158 bytes .../4da74a34bcede234b0415f77fbd87d70bf9a777e | Bin 0 -> 94 bytes .../51db5d31d2c5300d34831d9f23bcdd0aff9a998b | Bin 0 -> 677 bytes .../5cde2a9167798cb77f10abbfb2640a5c357f99fc | Bin 0 -> 507 bytes .../5e352fc10ac476cfbe1d755f092e069820223249 | Bin 0 -> 169 bytes .../63661677dd1306cec4b5a565190e65adf2446e52 | Bin 0 -> 374 bytes .../65887ed3db382aab1d9485c500f4401318d303b9 | Bin 0 -> 224 bytes .../67b5181f8f0644597e9bde539e8f083b5cacd0e7 | Bin 0 -> 165 bytes .../74c9dcf7afee2a6cb1ab3a2c0de744d1b03c1466 | Bin 0 -> 307 bytes .../792181ca19e6ded261434e588bb7fc2a4816d4ce | Bin 0 -> 544 bytes .../79f0e2a475487f8fa69e68c1cc947c5851bda741 | Bin 0 -> 355 bytes .../7e5fcdfeb557ce379ed96925c68505eaac0112db | Bin 0 -> 315 bytes .../7eec7530acf34b3a96fa9189783453999f7b6838 | Bin 0 -> 671 bytes .../80114bf9781bffc9db411413d83541d8deaaf7c1 | Bin 0 -> 343 bytes .../80425fb92bb86627e854892f23823fa804e5fdc3 | Bin 0 -> 441 bytes .../821cdd6eeb919a8dd7f35289abbd583828dd4945 | Bin 0 -> 677 bytes .../83e1a31785285338b0ddb3334b0ed098e63dedde | Bin 0 -> 285 bytes .../8a4c8100dedd0fb5f2a8b468c678f7ad8269deeb | Bin 0 -> 666 bytes .../8ae8268c24dc866c1edb3826b93a1c75dbf74ff4 | Bin 0 -> 677 bytes .../90f72038cc627f34f074ea72eadbba87a5e3e288 | Bin 0 -> 677 bytes .../92b67faee4a49df2cdbed785e27b4a1cddcfffa3 | Bin 0 -> 507 bytes .../9463810467aacdc9923b2b20a2236116b760d75b | Bin 0 -> 258 bytes .../94d7c96aea32ad41ce643d35b951a6d8990b81d6 | Bin 0 -> 546 bytes .../98cc7e9fe87df914d89a0aef008930f27b3c26f5 | Bin 0 -> 311 bytes .../99172dfdb4f59aaced29c7681ac6e6ce8356e814 | Bin 0 -> 104 bytes .../9ae3b647d895af97fe872c0b1442df7b5b767160 | Bin 0 -> 332 bytes .../9d2b1d2121b0508a4fa8d1508adb9d05633fdac3 | Bin 0 -> 222 bytes .../a335af37917ccf0c8b11bb884a3a74f3f1d2a7c6 | Bin 0 -> 677 bytes .../a738609112d3a6772c50a71e2c3504ebc515b709 | Bin 0 -> 337 bytes .../a8cecab5d917da5a4729632a7a18c564d7e1607d | Bin 0 -> 258 bytes .../ade919ab2b4a458e806575c941dfe50ae3fd3621 | Bin 0 -> 677 bytes .../b1251621a5eb5e7fda9cac9baead1c993a285c36 | Bin 0 -> 277 bytes .../b1516b78c3dfe77eeb554985fd7344c0478fbbcb | Bin 0 -> 258 bytes .../b41241740f5f8ad2c1d408f7bb6a313bd863c158 | Bin 0 -> 133 bytes .../b799c8596523a7ebeb8e11ada08818c10f7eabfc | Bin 0 -> 582 bytes .../ba48d0521a111222dc95a3a997c7c92dea5f4443 | Bin 0 -> 249 bytes .../c01457c6889fb1b597d308363a36412c0b7f90e7 | Bin 0 -> 497 bytes .../c82ebc0d6688d104af04fd20d6d3da591dc391f7 | Bin 0 -> 198 bytes .../c9a03eb758dd84e954e3d70916e2311e8fd21f3c | Bin 0 -> 249 bytes .../cf892756b33578a54ab20044514e573328d2f1d7 | Bin 0 -> 249 bytes .../d3bc3f158a63f1d50b474addd3f7b3d17f23e8e9 | Bin 0 -> 507 bytes .../d4906950aa9d60ad09dc0f5413c3d88080c3bc37 | Bin 0 -> 262 bytes .../da31578a8068bad65e1c7a3d06e8f543a2a0bc65 | Bin 0 -> 332 bytes .../dd4a9b5d0740679c249fc884efc499433b29436b | Bin 0 -> 666 bytes .../deea4ecc6f0b2a6d89fd25ff76762299f21602fb | Bin 0 -> 677 bytes .../e1040c7ffcb39915e0f539018c81f9798924cba6 | Bin 0 -> 94 bytes .../e381dc85682cc33ad99f622b89d145b47f7d6392 | Bin 0 -> 485 bytes .../ea24498fc7a144fccc6f1665ebf7020df803dd1a | Bin 0 -> 677 bytes .../eaa5d677e797c07bac98c3c7051abad91852e7c6 | Bin 0 -> 507 bytes .../ed7871269315725535d8bffec7836c45a3fc5c26 | Bin 0 -> 527 bytes .../ee8460f4077064c5a2137075b48eba7d3db5c570 | Bin 0 -> 94 bytes .../ef09f26e0ee61329f84a9f589629a865ae9ee0a6 | Bin 0 -> 276 bytes .../f477da4d7d8ff2066041e1dd5ee4e833b7111a1a | Bin 0 -> 527 bytes .../f8a379b2498a4eb452a85791a49adf065dab59ae | Bin 0 -> 666 bytes .../fe67bccb06f2174523943cc684518fcf1f7f8046 | Bin 0 -> 80 bytes .../ff1e67d17c1c27ef0d97900d0ea276b563a64628 | Bin 0 -> 271 bytes .../fuzzing/dictionaries/decode_png.dict | 50 ++++++++++++++++++ .../fuzzing/tf_ops_fuzz_target_lib.bzl | 6 +++ 90 files changed, 61 insertions(+) create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/010dc3d4b05288fcc40de2721052b3dc699f1cb3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/0555cd5e9d99629819cc985285f80da0f00be1e9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/0a0352aa168803ff65455792d9f6ee555c3e7c3f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/0ed54162df93ef8d00f993ce6b59ba422903d381 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/1547b448171c700613c3946d730de496c9b9863f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/17859046cbe4ac598a645173d679ce2a52c6afba create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/1df76c07817fbc3653a26f34d97658e9973627c2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/1f0717f8856d7782e3ab7992d3a72d783a018443 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/23b911e4ce936def88bc9a46b8b433c0e83fba2a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/25592201c3edff0578dbdac6b0e4f2be109ce151 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/266fd8495e0b8eb64387c1a62264185e061fee73 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/27f178cf415b4ff8671131ddf1d042dafac2fb3e create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/2a0bdc4d9cc5ea5bb21dd256d6ac96075376a94f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/2e5d25add6adc68e0457b358c7a34abf3d41c938 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/2e6c5b6a766dd5e9bd41eacfd0a36572bd2f7544 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/2e9c935cf82f6ca640e9a9abc3c30a578ad46176 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/2fcf1ed4477f7eaee028f5b3f9edeb5f1a737826 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/3480713774f590908ca5dba16d121cdfb8fba62b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/39289afcec60d98802b333e0fbb1da4d7aed4ce5 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/3adc488e21d4aca7bed9422f0241a42d0f93e7d9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/3cbf274da522483dc991fad9df43a22ac4fb3173 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/3d840cdff7f5ad16fe8bcb985ed4946c03459432 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/3f1e6753c1fca958e859189857449746592158ea create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/3fa4075993cb0f9bfa8eea785174a2038a69aa1b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/4023a373e977be58413e55350380310c5dd1fd6a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/40caba69dce1cfc48e0e43184d2bfbc6daa4399a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/41841e9561d8135945c1c1e55ab9e9a1e933653b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/41d40f2d66fa43e34537385594ee9911e65deadf create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/421bd39810b50309a71adb2dadc3b19f01a52312 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/446c305b2c0665736f94fb2b62dbdef445eff0cf create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/449cee952bb645f6f4241a6665d3c6028c073c7a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/45520b07609978c5aa3516d803527438b93fbadb create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/4da74a34bcede234b0415f77fbd87d70bf9a777e create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/51db5d31d2c5300d34831d9f23bcdd0aff9a998b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/5cde2a9167798cb77f10abbfb2640a5c357f99fc create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/5e352fc10ac476cfbe1d755f092e069820223249 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/63661677dd1306cec4b5a565190e65adf2446e52 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/65887ed3db382aab1d9485c500f4401318d303b9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/67b5181f8f0644597e9bde539e8f083b5cacd0e7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/74c9dcf7afee2a6cb1ab3a2c0de744d1b03c1466 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/792181ca19e6ded261434e588bb7fc2a4816d4ce create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/79f0e2a475487f8fa69e68c1cc947c5851bda741 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/7e5fcdfeb557ce379ed96925c68505eaac0112db create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/7eec7530acf34b3a96fa9189783453999f7b6838 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/80114bf9781bffc9db411413d83541d8deaaf7c1 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/80425fb92bb86627e854892f23823fa804e5fdc3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/821cdd6eeb919a8dd7f35289abbd583828dd4945 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/83e1a31785285338b0ddb3334b0ed098e63dedde create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/8a4c8100dedd0fb5f2a8b468c678f7ad8269deeb create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/8ae8268c24dc866c1edb3826b93a1c75dbf74ff4 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/90f72038cc627f34f074ea72eadbba87a5e3e288 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/92b67faee4a49df2cdbed785e27b4a1cddcfffa3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/9463810467aacdc9923b2b20a2236116b760d75b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/94d7c96aea32ad41ce643d35b951a6d8990b81d6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/98cc7e9fe87df914d89a0aef008930f27b3c26f5 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/99172dfdb4f59aaced29c7681ac6e6ce8356e814 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/9ae3b647d895af97fe872c0b1442df7b5b767160 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/9d2b1d2121b0508a4fa8d1508adb9d05633fdac3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/a335af37917ccf0c8b11bb884a3a74f3f1d2a7c6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/a738609112d3a6772c50a71e2c3504ebc515b709 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/a8cecab5d917da5a4729632a7a18c564d7e1607d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ade919ab2b4a458e806575c941dfe50ae3fd3621 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/b1251621a5eb5e7fda9cac9baead1c993a285c36 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/b1516b78c3dfe77eeb554985fd7344c0478fbbcb create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/b41241740f5f8ad2c1d408f7bb6a313bd863c158 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/b799c8596523a7ebeb8e11ada08818c10f7eabfc create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ba48d0521a111222dc95a3a997c7c92dea5f4443 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/c01457c6889fb1b597d308363a36412c0b7f90e7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/c82ebc0d6688d104af04fd20d6d3da591dc391f7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/c9a03eb758dd84e954e3d70916e2311e8fd21f3c create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/cf892756b33578a54ab20044514e573328d2f1d7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/d3bc3f158a63f1d50b474addd3f7b3d17f23e8e9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/d4906950aa9d60ad09dc0f5413c3d88080c3bc37 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/da31578a8068bad65e1c7a3d06e8f543a2a0bc65 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/dd4a9b5d0740679c249fc884efc499433b29436b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/deea4ecc6f0b2a6d89fd25ff76762299f21602fb create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/e1040c7ffcb39915e0f539018c81f9798924cba6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/e381dc85682cc33ad99f622b89d145b47f7d6392 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ea24498fc7a144fccc6f1665ebf7020df803dd1a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/eaa5d677e797c07bac98c3c7051abad91852e7c6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ed7871269315725535d8bffec7836c45a3fc5c26 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ee8460f4077064c5a2137075b48eba7d3db5c570 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ef09f26e0ee61329f84a9f589629a865ae9ee0a6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/f477da4d7d8ff2066041e1dd5ee4e833b7111a1a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/f8a379b2498a4eb452a85791a49adf065dab59ae create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/fe67bccb06f2174523943cc684518fcf1f7f8046 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_png/ff1e67d17c1c27ef0d97900d0ea276b563a64628 create mode 100644 tensorflow/core/kernels/fuzzing/dictionaries/decode_png.dict diff --git a/tensorflow/core/kernels/fuzzing/BUILD b/tensorflow/core/kernels/fuzzing/BUILD index 3ea9dd0638..bb92057bb6 100644 --- a/tensorflow/core/kernels/fuzzing/BUILD +++ b/tensorflow/core/kernels/fuzzing/BUILD @@ -19,6 +19,7 @@ cc_library( load("//tensorflow/core/kernels/fuzzing:tf_ops_fuzz_target_lib.bzl", "tf_ops_fuzz_target_lib") load("//tensorflow/core/kernels/fuzzing:tf_ops_fuzz_target_lib.bzl", "tf_oss_fuzz_corpus") +load("//tensorflow/core/kernels/fuzzing:tf_ops_fuzz_target_lib.bzl", "tf_oss_fuzz_dict") tf_ops_fuzz_target_lib("identity") @@ -46,6 +47,10 @@ tf_oss_fuzz_corpus("decode_bmp") tf_ops_fuzz_target_lib("decode_png") +tf_oss_fuzz_corpus("decode_png") + +tf_oss_fuzz_dict("decode_png") + tf_ops_fuzz_target_lib("decode_wav") tf_ops_fuzz_target_lib("example_proto_fast_parsing") diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/010dc3d4b05288fcc40de2721052b3dc699f1cb3 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/010dc3d4b05288fcc40de2721052b3dc699f1cb3 new file mode 100644 index 0000000000000000000000000000000000000000..9dbc560e1e4b50f98060fdad36ae0f65f0c0c92b GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMg|53hG<6jNCpN5rX+877Y4?=UBXKk7#KJU zJR*x37`TN&n2}-D90>*n2KEw9Usv`=+_KCvj2F+=zF=TrknnVI4B@z*oUp)X#sB~R z?X5n}*LWmv#>9~R!FJCl^Rw$27#LJbTq8wbw&mT1`&oUSFRj5aA3`vHM3{Wo-kp;&6_uuE?wHu(NS1fn3k5tz~KMj!Glw$ zP9-NNdwYA^+uO&-$M4&>&%nT7?%cW8u3g))V+S7}pQ)i41H-)k|Nq~)#NNihz`&T~ z?e3zmIoq~@fq{Xuz$3Dlfq`2Xgc%uT&5>YWU|=ut^mS!_#4XD#!+7y*?F$A5hS{Dj zjv*GO?@qie)TAKLX1?Hw%7hb+2WtLr*IB;Ksrb_DW$%;H)1TirKH%q9Eu1c(=Kat( zCQdF-swJ)wB`Jv|saDBFsfi`23`Pcq7P^Lpx<-~EhK5$gW>$vA vx&{_j1_n+>i+fNsF8lNgD3Ux~{an^LB{Ts5Cf~1> literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/0a0352aa168803ff65455792d9f6ee555c3e7c3f b/tensorflow/core/kernels/fuzzing/corpus/decode_png/0a0352aa168803ff65455792d9f6ee555c3e7c3f new file mode 100644 index 0000000000000000000000000000000000000000..7918406ac4bc04196bf07a3e8804b0dbc946eaf3 GIT binary patch literal 232 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8K^*%(-a*g5{+V&DMD*fUIxIA%CyTes`S{|r5Q>UL&q z3G$n*s;Kh3+4R-d$Nw25EB^Ma58rj%zl!DCv@0$(HEzHCttDETl;(U(G}+jbZ2$iz E00B%iYybcN literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/0ed54162df93ef8d00f993ce6b59ba422903d381 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/0ed54162df93ef8d00f993ce6b59ba422903d381 new file mode 100644 index 0000000000000000000000000000000000000000..c294b3180f7d1c315466efacee0167a1685ba68f GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMg|53hG<6jNCpN5rX+877Y4?=UBXKk7#KJU zJR*x37`TN&n2}-D90>*n2KEw9Usv`=+_KCvj2F+=zF=Tr;PG^E4B@z*oFH+Bfq`KG z17o6Utvdq)gKCLuL`h0wNvc(HQEFmIDua=Mp@puYp{|i-h@qjCv6+>jv95uIm4Shi n(c&Hy4Y~O#nQ4`18jLKg3=AO}w#z>K0&=&ftDnm{r-UW|mDe*h literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/1547b448171c700613c3946d730de496c9b9863f b/tensorflow/core/kernels/fuzzing/corpus/decode_png/1547b448171c700613c3946d730de496c9b9863f new file mode 100644 index 0000000000000000000000000000000000000000..0eb3eff90d7fa0c03fc827b65da2e21050f27ebf GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8`~f~8t_&cc!@zKcfr0V= z|Nkp5Y=~xHU|>x0c6VXv&$t=Lz`(#+;1OBOz`!jG!i)^F=14FwFtC?+`ns||;+AEW zVZ3;@_5}k2gQTa6V~EE2|#*;m~HW%fq_A_#5JNM zC9x#cD!C{%u_Tqj$iUD-*U(Vc$TGyx(8}1%%FtNXz{1MFz{zNF4~mA|{FKbJN;C~d Z7FGs^5DnX9pMC-P#?#f$Wt~$(697lsLRI(6mBm220oUB7<)=FOWA9z1yR8ZYn>6yvd z?CFWQxrw$03_2i5kXISl{vDWD;GrYce_~0|$sDWs7gm&TiAK6!S){@8sl-YyfWw=& z)?zjf+vJ-Cb_+9CY~C57A;h_~=w`{IfMO{zVF5l~UOoX~F{yfgC3$HvL4F=CPEIZ! zenBy5`4k^T8F68LZVq-fHg*o~;L;?S1|J1!Q2`zfRu*Pv7FG@(0a0lMUnMz75k4+< z7A8hUCKh%sJ`qW|MV?Bs5<1poj5 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/1df76c07817fbc3653a26f34d97658e9973627c2 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/1df76c07817fbc3653a26f34d97658e9973627c2 new file mode 100644 index 0000000000000000000000000000000000000000..2b9721d742ad143de0881894c52407af1865b79b GIT binary patch literal 666 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33IqJ{>3ZJ-V*7zF{+8 a-lDmd+vQi?y07@7|NZef*AG1Ze-i*fJ=3-T literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/1f0717f8856d7782e3ab7992d3a72d783a018443 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/1f0717f8856d7782e3ab7992d3a72d783a018443 new file mode 100644 index 0000000000000000000000000000000000000000..e0c330f7f4ee396723fedbb530197cd890045730 GIT binary patch literal 122 zcmZ?wbhEHbRA5kG_{0DKj7$s+91IK$d<+Z>3JeSy3=9m4KUu(XivPJia}(23eG}6& zle5{=6LWJDZ4DT7K$0LM7??FUcHQ}BaLRM_UW;sxZT}NA`cy(R+*Yp3dA+Yd=X{Cg Ql^>>0YJ|V^voKf#0K+&TPXGV_ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/23b911e4ce936def88bc9a46b8b433c0e83fba2a b/tensorflow/core/kernels/fuzzing/corpus/decode_png/23b911e4ce936def88bc9a46b8b433c0e83fba2a new file mode 100644 index 0000000000000000000000000000000000000000..41fc2fe9516ecaf369c9093c5d815a709963c2b1 GIT binary patch literal 375 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo*B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)wL2e>vEG3_`mf5wh2KoC g{uB}ZaXV}J*68T#owxi~XU6J;UwFmK*YN))03-Q9g8%>k literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/25592201c3edff0578dbdac6b0e4f2be109ce151 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/25592201c3edff0578dbdac6b0e4f2be109ce151 new file mode 100644 index 0000000000000000000000000000000000000000..8b5755c4bc513368a2605e05c8b3117feadab086 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(1VrX+877l!}s{b%+wFfecy zctjR6FmMZlFeAgPIT8#E4D2PIzOL+#xMi7T7%!f!eZj!M@WRu@F~s8Z+ljt;hYUno z*n1vnZCh>Pa)3#Id)1vrr=48skF^BDUkF`v{UN$wO53qGi%=CY2Z19wyV531`111Q zUdacV3@h&R9cFm=!q8x$75l&O2LJ$veQW^4&synHWHwRc#YlT*Co z^0_^w$9AKd%|KnlWn&ZVCbneC1Sqq83u;`w;7xnn31R0o^85x+Eq1qW37#NuZ z6&;xkm9-cCzs0}XPyL+pDGGoEH0P|E*yt{kZt=SA`p5b)6OJB5&+P zpZ)p1^P0$>;}Z|_?wRrN!I~cxJA_@Ii|uy#cW3_uW@YQ?T+2@x^e$9no*w<8X#KRZ z@+q6y8_H+u|D<&=ZB&fb^{R7+0PacL$<%wXN@{8dG*F@1& z@pbEteEhvmwOVFR-=y6_`zMEGxZBBPxd_fVA~BI?P2Wcg6{9z@R#qA;Tc^bJRtuld z+gbXiu*iDXn_d5mBNwXtoVi}mwNNl|$MhLHvQ9FFJ3qZE*f8xc!_`pVwQpNQO{UHa zlf0?>kk3p?Wxd&g%@Cf9$4>24SQ+5OtD zA|mVN`RHqHc+|A@{?j&Y^?h{FJ32f1Hs{-QZ$7Ot-V}W83u;`w;7xnn3+I;nTd&+iJ6(1g^dLSIM~=&**H1S zm4H;BDdFPcMC+5ES6z5fT;>5at&U5cq$9ft!OtfkARTWj9H=Dlt`uM+O#oxa5;S9(9t608GyW#=>4KFNM literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/2e5d25add6adc68e0457b358c7a34abf3d41c938 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/2e5d25add6adc68e0457b358c7a34abf3d41c938 new file mode 100644 index 0000000000000000000000000000000000000000..ecf597f7365bf06492af4d53bca4166f5ecf744a GIT binary patch literal 165 zcmex=83u;`w;7xnn3+HTL^3loGqbR>ukC3pCfH1#+fWZF)4BQ+H3JeO2jDigRk1&Wb gFfuZr0M7qM7(@i%f-F$U|F;-8;CdJs?El{c0OisZZU6uP literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/2e6c5b6a766dd5e9bd41eacfd0a36572bd2f7544 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/2e6c5b6a766dd5e9bd41eacfd0a36572bd2f7544 new file mode 100644 index 0000000000000000000000000000000000000000..e5a18917e3744daf0f8d4eb5cbbb702daff21188 GIT binary patch literal 320 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8K^*%(-a*g5{+V&DMD*fUIxIA$UL&q z30k~-FH^O5Se%nnyyNn@J*CHX%f=?!O>D`O2~cL`VPIg0t6+#*fz!3f4#DXRmzo;4 l-~QGTuX_ukqg7;;IWAeWDP&%5X;PZ=Ezx9SPqO|0n*eW1JZb;{ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/2e9c935cf82f6ca640e9a9abc3c30a578ad46176 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/2e9c935cf82f6ca640e9a9abc3c30a578ad46176 new file mode 100644 index 0000000000000000000000000000000000000000..50be7f686b791d7aa08652159592311c728ec79f GIT binary patch literal 666 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33k5Ck-}M3-UYdzo}JpeeE#P(9VOEq+0e~jI7^7D%pEvvFBoh7mK$n?yt>qf`gG`5@z zu?WxPoUkaf^FY#5!7s8u=Jd__O>fN9Wj- zUpko95ih;}5m#T`yNUH`QQ4P0U9VL7W$NsiaC*ndC5CS#=bcVJeL7C+dvslEeZywH ayhU>@x67}(bzkvE|NG-}t{-^*|0V#zAJi%U literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/2fcf1ed4477f7eaee028f5b3f9edeb5f1a737826 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/2fcf1ed4477f7eaee028f5b3f9edeb5f1a737826 new file mode 100644 index 0000000000000000000000000000000000000000..00eba4c39a92d546e7b4f6f77b18e9d3ddaec399 GIT binary patch literal 507 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0cwE% z2N(o77!(*3m>C5bm;@P_1sVSzVUS{AU}R-vKn6_AENq+{|Bo=}3NSD+GO{xB!sQv6 zm{}ND*#w2yIXHzyBqS9L9mB$>FS~M8^#2hCaYhh8Hi?0end$!#1|>m824)6EW)^0c zBqIZpATx`QqM?#wqf_9-|F;-;n89L#4ECWtDXSvBZDg3!c%ppc2?kGwqbGWA9ntC7 zq4|7ev8aiV*TcwDi>6tHdK;doU}c&7fYEI0>XNm-5gl7PB89W6ybE$aJv+5``TY5B zZ=L2_-TT{?=cnoUZ*Mx|kIu0vzjQFIBVKy{Bd)%>cN6Q?qOvc0x?ZXD%hcI3;q;D^ uOAHw_=bcVJeL7C+dvslEeZywHyhU>@x67}(bzkvE|NG-}t{-^*|0V#7czSC9 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/3480713774f590908ca5dba16d121cdfb8fba62b b/tensorflow/core/kernels/fuzzing/corpus/decode_png/3480713774f590908ca5dba16d121cdfb8fba62b new file mode 100644 index 0000000000000000000000000000000000000000..af3afc499d820cdd966ec9a67d3ec6fb39b3e240 GIT binary patch literal 665 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0W5$W zix@)a{{aR;4h97V1!hJ;1|~s9WFu8IS=BCkN~QBMj;S3`|T+jLa;I ztWa4-CT3O^K{f_Jqb_NCpMkYZ;M`lCi#)bcHG4L=mGB61;3o_Ufmzvl zI@j`32E7XvnWsm;C|W6!D!y*rk&nOEsaDJE>6^4$X#eD}40k)ZEEmB!M83u;`w;7xnn3+HTL^3loGqbR83u;`w;7xnn3+HTL^3loGqbRN4+jqyHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0X*Qx z`}gnhNF${FA7BvVU{GLCU}h9#U=n0x7G(T?gh7IVftit!0U5Axa=nEe0NDMg}H9WhEgzrZ15X<(Pw|Y@4P0m=lI0KynAMRe6Z$+og5!Gr#mOFV3v#E NoFftwdDist0swI5K6d~B literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/3cbf274da522483dc991fad9df43a22ac4fb3173 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/3cbf274da522483dc991fad9df43a22ac4fb3173 new file mode 100644 index 0000000000000000000000000000000000000000..7f9c0c93ec9bc8f135e7f78010b275079e052b48 GIT binary patch literal 474 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0X*Qx z`}glb(vBbkAO3%UL6Cz%fkAl|_(^fnA70SkXX4DKN3H>HiT1F-Ar-6Bw94M#~8@FflVSFfl{5 zGcYhPG6^a=G8-y4F8qIsfd?ch$SlZU&oI>`!OT{@Y_SODd!%+Hh@!zisH^k~X zE7V2a*o!{<^L^(vkv+#J9_HOM*-v}13FI`^e$9n zo*w<8X#KRZ%~Q(R8_H+u|D<&=ZB&fa()gl%a7Ettfx$`RA J;F1#K0sve83u;`w;7xnm_agp0$v~rivk8lPd6q;H)jTBuqGuz zhEaes1QsyjlpsJ!_5{)-0I$ZZ_jW3wnrY*o^>vJb!yu??%Avi)&O2EA{+n! literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/3fa4075993cb0f9bfa8eea785174a2038a69aa1b b/tensorflow/core/kernels/fuzzing/corpus/decode_png/3fa4075993cb0f9bfa8eea785174a2038a69aa1b new file mode 100644 index 0000000000000000000000000000000000000000..5f9cec9ab5cb27973b8d8e71b47cf61601c0ee3d GIT binary patch literal 343 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8K^*%(-a*g5{+V&DMD*fUIxIA%CyTes`S{|r5Q>UL&q z30k~-FH^O5Se%nnyyNn@J*CHX%f=?!O>D`O2~cKzdB{mAu7V+M1yGxZy zH_fB78*g1xek$)CxYdZkZ?>wU%JXK^S6?6hXOOJ;+qXV=*Kz+UmT%LpxYX3R{r0z( ic->nN9jzj(%yG%0O(FAgOOw)^Z;2)wdy?({-vj_CR#v3| literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/4023a373e977be58413e55350380310c5dd1fd6a b/tensorflow/core/kernels/fuzzing/corpus/decode_png/4023a373e977be58413e55350380310c5dd1fd6a new file mode 100644 index 0000000000000000000000000000000000000000..385b8b0c35936d3b9c99facefccb33835569470b GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(1VrX+877l!}s{b%+wFfecy zctjR6FmMZlFeAgPIT8#E4D2PIzOL+#xMi7T7%!f!eZj!M@WRu@F~s8Z+ljt;hYUno z*n1vnZCh>Pa)3#Id)1wVD<}8O&FVdQ&MBb@0EH7l6aWAK literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/40caba69dce1cfc48e0e43184d2bfbc6daa4399a b/tensorflow/core/kernels/fuzzing/corpus/decode_png/40caba69dce1cfc48e0e43184d2bfbc6daa4399a new file mode 100644 index 0000000000000000000000000000000000000000..22f1649adc45eae591f46c4b1a1e0db6bf0cc82e GIT binary patch literal 470 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo*B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27AV-E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%o>I=< zuw$lPj>XfIZ{2~q%#J?`5AA!BGiT+j$kg2IoHw4y3+&DZWUO~!kN&GNap5=9t3O4A df85TRzBM}fdgm?w)tRw6;TK-<@-_Uw2>^SUawPx& literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/41841e9561d8135945c1c1e55ab9e9a1e933653b b/tensorflow/core/kernels/fuzzing/corpus/decode_png/41841e9561d8135945c1c1e55ab9e9a1e933653b new file mode 100644 index 0000000000000000000000000000000000000000..16c0c33b93dadec4fd326f2eff73a81d6c82f508 GIT binary patch literal 247 zcmex=83u;`w;7xnn3+HTL^3loGqbR%E-pdz#_!X@&6VB2S~=AVQR!NgDKm(T|fS3=-E@ZGh<7T i-)vPymFLZ-uf9J1&mdXxw{Ly;uH*hyEZ?SGaRC52$Sm^! literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/41d40f2d66fa43e34537385594ee9911e65deadf b/tensorflow/core/kernels/fuzzing/corpus/decode_png/41d40f2d66fa43e34537385594ee9911e65deadf new file mode 100644 index 0000000000000000000000000000000000000000..6e44f2adc7fd1343044613a087c1c3efdaef5081 GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Z@3 zOsp(|Yz*u|9Kwo5B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%ZYZC^ zUOrPV$Kq*LF=@#sLG^9xAJ}ew@-Sp7PXyzXUkop}CW@wtuUmKI z6TveIDLIwh{PTKI(C&eAu9 zMb^9C?D}UMxlrZj%=Lo!wF?o_?pi3AxFaduedAM%;$=<00RwtcB9%f<`#&I_cKr+kQW{%~!I_|$cFd++$H$>jRaFx~CqKf7Q1 fRYYXnJRg0n4Ud|(-hbN0t-g;gdh_x%{J#kRtRT^B literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/421bd39810b50309a71adb2dadc3b19f01a52312 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/421bd39810b50309a71adb2dadc3b19f01a52312 new file mode 100644 index 0000000000000000000000000000000000000000..131004b8943e997ec7ba3212f3ba0d555c4ba4d2 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMg|53hG<6jNCpN5rX+877Y4?=UBXKk7#KJU zJR*x37`TN&n2}-D90>*n2KEw9Usv`=+_KCvj2F+=zF=Tr;PG^E4B@z*oFH+Bfq`KG z17o6Utvdq)gKCLuL`h0wNvc(HQEFmIDua=Mp@puYp{|i-h@qjCv6+>jv95uIm4Shi l(c&H?4InpyT!p5=$im9N5Taqb?9(qG6`rnsF6*2Ung9jfFc<&; literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/446c305b2c0665736f94fb2b62dbdef445eff0cf b/tensorflow/core/kernels/fuzzing/corpus/decode_png/446c305b2c0665736f94fb2b62dbdef445eff0cf new file mode 100644 index 0000000000000000000000000000000000000000..1f2f90b3bc41f8daa93d2df651bf55b2a3ddc78b GIT binary patch literal 174 zcmZ?wbhEHbRA5kG_{_@y0*nj{%nSk`mI#9a149i11A}v@e{fM@FhduEK$q|T{|x{C z{|Cu4Fev_H0W%c;b9?3{rl83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8Mgu`#d+v2*;t#lQiQv1gbXam--Kwrm6Od9;S&*s}SHTdsf*P(>QGWXUR_aZY z=83u;`w;7xnn3+HTL^3loGqbR>ukC3pCfH1#+fWZF)4BQ+H3JeO2jDigRk1&Wb cFfuZr0M7qM7(@i%f-F$U|F;-8AbM^B09&>c8vp4~|yiM9p|Iv`1q1_ma% nmj0Ee-|{b>v*lLz=6id7^S3?nnD(r5*{f6A-f_=nWv~VSZx0_I literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/51db5d31d2c5300d34831d9f23bcdd0aff9a998b b/tensorflow/core/kernels/fuzzing/corpus/decode_png/51db5d31d2c5300d34831d9f23bcdd0aff9a998b new file mode 100644 index 0000000000000000000000000000000000000000..bcacbe623f8ca1ac88de8d3dfdce160de04f2f29 GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo*B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%p0f6B zi>S%enPHMQb-M#~nH_%?9@_V0#iS*l1l6~#e_*@$$-|JTJQ0jjelfh@nkbqozHZ%- zkH6QcR?F<^o3vYK|KzX?cRRT(7r{A4Bqs8#>HBD*V)RDV%1VP}>y)_GYT*-lJ4@db z7Fq9lv+JL6}whR^LY#y`!_EZ*#s~_vX_Y<4w`$a^|d@6`7iwo%6;sd4b*efQ@Q>SB)3-)PU+=u-zdAEkC;Y-IUcQF^Hvt?t)Up5o literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/5cde2a9167798cb77f10abbfb2640a5c357f99fc b/tensorflow/core/kernels/fuzzing/corpus/decode_png/5cde2a9167798cb77f10abbfb2640a5c357f99fc new file mode 100644 index 0000000000000000000000000000000000000000..2619e1d87638b8f37900a750dba325d075739ad1 GIT binary patch literal 507 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33>fd8gA)pN^CI9$nX3->{i4Z_!-K?eeQ`-Bj$3yzX<@4UVzpB literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/5e352fc10ac476cfbe1d755f092e069820223249 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/5e352fc10ac476cfbe1d755f092e069820223249 new file mode 100644 index 0000000000000000000000000000000000000000..cb55f03ee184e66592d578050dc44a7bf70fe4ac GIT binary patch literal 169 zcmex=83u;`w;7xnn3+HTL^3loGqbR83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8K^*%(-a*g5{+V&DMD*fUIxIA%CyTes`S{|q}b>U#EU z30k~-FH^O5Se%nnyyNn@J*CHX%f=?!O>D`O2~cKzdB{mAu7V+M#XkFQ`TaNEidKb` z@Go$9nd^Q0giD6W=}mdtuBWcvqw|Y4 w_pf64HtmW_O^w@ce`|@?y#>+HDzeHPmn_;8GB39@Db4woXtJ><+5Z1c0K?*R^#A|> literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/65887ed3db382aab1d9485c500f4401318d303b9 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/65887ed3db382aab1d9485c500f4401318d303b9 new file mode 100644 index 0000000000000000000000000000000000000000..776adbe8d4bfd9e9b2532525a8f3187d90453d93 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMg|53hG<6jNCpN5rX+877Y4?=UBXKk7#KJU zJR*x37`TN&n2}-D90>*n2KEw9Usv`=+_KCvj2F+=zF=Tr;P-TK4B@z*{DYr`r+GR9 z!>yO~jnhK{rZ6xtsFt`!l%yncTId=Y>Ka*w7#dm`n^_qe>l#>C r85lSjE$%_lkei>9nO2FW!N|hOz!0KgyX@01Ag6n}`njxgN@xNAZ`3xt literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/67b5181f8f0644597e9bde539e8f083b5cacd0e7 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/67b5181f8f0644597e9bde539e8f083b5cacd0e7 new file mode 100644 index 0000000000000000000000000000000000000000..5bee1d494a574bf8a675933d3045150b32395478 GIT binary patch literal 165 zcmex=83u;`w;7xnn3+HTL^3loGqbR>ukC3pCfH1#+fWZF)4BQ+H3JeO2jDigRk1&Wb fFfuZr0M7qM7(@i%f-F$U|F;-8V0u7S|Gx83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33KnUR4>kXewyo?)s383u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<|x3$GwAAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo5B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhTG@Cm)0rEdz0tarWH_0KqRp~}yh>ji(WQ>~WS(>H0i(EiC`8SZv+SuTQe zjz~=8S=0B?LdEEftd*4p%hoAzt<_kyyA}#2?np{^pL&up-1+HU!G>vn8Lo!ig)TH!okq|C;~^(U3a; literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/79f0e2a475487f8fa69e68c1cc947c5851bda741 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/79f0e2a475487f8fa69e68c1cc947c5851bda741 new file mode 100644 index 0000000000000000000000000000000000000000..885332337762ff92dd6a1ad00fe0a1694995a5c0 GIT binary patch literal 355 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33#!>I*e&HUM>`~I+q z2c?Jk`g&I0eDpW-Y@1EY%*4K6P2EXnU;R6Kvb1*gq`#BCOnR3qxq^X#`TtD-2xd8f literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/7e5fcdfeb557ce379ed96925c68505eaac0112db b/tensorflow/core/kernels/fuzzing/corpus/decode_png/7e5fcdfeb557ce379ed96925c68505eaac0112db new file mode 100644 index 0000000000000000000000000000000000000000..cc011aedc9b5234cb26140a73dc93a85c0e1c6c3 GIT binary patch literal 315 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8K^*%(-a*g5{+V&DMD*fUIxIA%CyTes`S{|q}b>U#EU z30k~-FH^O5Se%nnyyNn@J*CHX%f=?!O>D`O2~cKzdB{mAu7V+M#XkFQ`TaNEZcS2A ze)|1Z>P_?L?8aNyl%LAG2W~ZD@SClwsPeqo^wrnL{~07J{`Rd8-gVr+isjq1D=sxP mZomDlC0_RyL`SR0Dsx=2Xj90%+|r~p=Ubx5#-3#R|2F|$|5?2N literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/7eec7530acf34b3a96fa9189783453999f7b6838 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/7eec7530acf34b3a96fa9189783453999f7b6838 new file mode 100644 index 0000000000000000000000000000000000000000..7e3b6f564f0dc029247355c9a920245354f7cd1f GIT binary patch literal 671 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo*B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL`-27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%o>I=< zP(D*H$Kq+qx9&h)X2+j}hxR>LF=@#sLG^9xAJ}ew@-Sp7PXyzXUkop}CW@wtuUmKI z6T8f+14rNOdwN?dET@Cm)0 erEdz0tarWH_0KqRp~}yh>jhm41rw1I$qoQ?0h6@= literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/80114bf9781bffc9db411413d83541d8deaaf7c1 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/80114bf9781bffc9db411413d83541d8deaaf7c1 new file mode 100644 index 0000000000000000000000000000000000000000..4828092a8aa538f619fe0238f01041ec24187f0c GIT binary patch literal 343 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!Fj0%j5f(-wUFo-fR zGBTh7&i_XkWCa))S(uTfm>8K^*%(-a*g5{+V&DMD*fUIxIA%CyTes`S{|r5Q>UL&q z30k~-FH^O5Se%nnyyNn@J*CHX%f=?!O>D`O2~cKzdB{mAu7V+M1)C!l*P=T|MfvIX zTd6nAqq7@tT~mH4?;g0-h{12Rs-nvCX46++AOB~NtoYlvK6ux0|05d07Y$9;s5{u literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/80425fb92bb86627e854892f23823fa804e5fdc3 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/80425fb92bb86627e854892f23823fa804e5fdc3 new file mode 100644 index 0000000000000000000000000000000000000000..2ed0139989f994cef05524f606058404ebc7614a GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(1VrX+877l!}s{b%+wFfecy zctjR6FmMZlFeAgPIT8#E4D2PIzOL+#xMi7T7%!f!eZj!M@WRu@F~s8Z+ljt;hYUno z*n1vnZCh>Pa)3#Id)1wVPCL2MA8QGUzYx0U`a^WVl(u7W7NII)4gyDVcBPf&e|hihbcNbLPE;vrh4di6;rnY)BP4ZqN1R?B_XU53jBJeYs-m z4Xq8!*k=AnZFu+SXo>Q{ddIhJiIX4w>wjNr5}nIme^vb8+b^HrgzGy@NcTFKvfqD6 zP^8=gxr!xB9Gyoc%44oS?1@y-*)RF_S^VW*mi)cnclXBq)5*1_sp<*NBpo#FA92nC}Q!>*k(KHxYSQ!{XG;EiB`UMmx Mp00i_>zopr06f{Iz5oCK literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/821cdd6eeb919a8dd7f35289abbd583828dd4945 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/821cdd6eeb919a8dd7f35289abbd583828dd4945 new file mode 100644 index 0000000000000000000000000000000000000000..28925e3c80c2210e90461b82d950f63427bd5439 GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0cwE% z2N(o77!(*3m>C5bm;@P_1sVSzVUS>8U}j`wKn5(F9IXG3FsKVKFflPPGP5wULS-45 zm|0l_*%;V`ID{1qMU(;)3!DBQVGv_vL^FYb31qaKAOjOKBLfpNR67F$10$25q9e1R za^u4Pw-|Upl7h^F4E79DT{2#Od$m-Y(_&xkzcmb{9~b}qs>BuCqd2CrEW)=w+jJf)ny zp?s!Zj>XfIZ{2~q%#J?`5AA!hV$zaNg6iAWKd{~W!CO+4avja-qu4nd=2z4FwZ-B&EAgJ;@mE{PeD1!?eE)S3`Z*zHJdTnL0B}@}}-X zJ~JI%olV=eFLh4nJa0`PlBg3pY z5)2Fs>?NMQuI!JvWtn9dFP^P^!N9bP0l+XkK D`Qu0| literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/8a4c8100dedd0fb5f2a8b468c678f7ad8269deeb b/tensorflow/core/kernels/fuzzing/corpus/decode_png/8a4c8100dedd0fb5f2a8b468c678f7ad8269deeb new file mode 100644 index 0000000000000000000000000000000000000000..c6c8b7c717310177d1034ec4e1643afbdc6994bf GIT binary patch literal 666 zcmex=83u;`w;7xnm_agp0$v~rivk8lPd6q;H)jTBuqGuz zhEaes1QsyjlpsJ!_83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Z@3 zOsp(|Yz*u|9Kwo5B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%ZYZC^ zUOqF$;;CMa?$5w)%-xQKhxR>LF=@#sLG^9xAJ}ew@-Sp7PXyzXUkop}CW@wtuUmKI z6TveIDLIwh{PTKI(C&eAu9 zMb^9C?D}UMxlrZj%=LmO+869N_z*?A(3}7N8N%^scP$i5+>w;-KJ_GHxbxGyf(_ID zGF%PyUHi60)MV<+Fv**`5Bbb=baggu+rHG5W#a{V=LOQrQ$EBwf4DY9eCj&8y?1=p rWODsynC^D*pWUzhDk8FOo{zrPhDS|X?>}whR^LY#y?OZ>{@(-uuXWV< literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/90f72038cc627f34f074ea72eadbba87a5e3e288 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/90f72038cc627f34f074ea72eadbba87a5e3e288 new file mode 100644 index 0000000000000000000000000000000000000000..3f12cb5f6595439978754328620f1f8f0fb43291 GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo5B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%o>I=< zP(D*H$Kq+qx9&h)X2+j}hxR>LF=@#sLG^9xAJ}ew@-Sp7PXyzXUkop}CW@wtuUmKI z6TveIDLIwh{PTKI(C&eAu9 zMb^9C?D}UMxlrZj%=Ln83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0aAbl zNb&yz41ydC3JeO&jDieIf{e_9jQ@`?NHH)lvNAFt114q`HcpQJM;LSk7?>CtS($m^ z@{CN(EDWq{f*|uV zz7ZW;IwFO$s=NzwKRr9OclrGJZ*QIETiyHHmglGO`EPGJTWNX|Q*e)@Er)c5GR*7}Cce0huJT5gwLb?d(3 PkN)?^=UhMV{Qpe=OU-Nd literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/9463810467aacdc9923b2b20a2236116b760d75b b/tensorflow/core/kernels/fuzzing/corpus/decode_png/9463810467aacdc9923b2b20a2236116b760d75b new file mode 100644 index 0000000000000000000000000000000000000000..eec341bf2bd623f50bbb5e393f4aaa245bf15fec GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(20oEV=?n}EJOMr-uK)l4zyJUL|Nr0r z|1UYw^=~=@0|R4{x4R2N2dk_H0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+B?X zhVkOr+7}EA3{svhjv*44lM@t#41^YUbVgi0!OEVI%V@>G5K+x=WcTYmYZw?9R7+eV zN>dU`QmvA$QWHy38H@}JEp!bHb&V`T3=OS}&8!TKbqy@63=Eu%7WY6klz=tl=BH$) fRibGyvam8RglO0<`}7L~0|SGntDnm{r-UW|Mj}Xb literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/94d7c96aea32ad41ce643d35b951a6d8990b81d6 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/94d7c96aea32ad41ce643d35b951a6d8990b81d6 new file mode 100644 index 0000000000000000000000000000000000000000..776f17c6b218bd55751e740b35b3ad6f4097a288 GIT binary patch literal 546 zcmex=83u;`w;7xnn3+HTL^3loGqbS8u&}VOaImqlvT<^7 zadC2Ra&qzT^KfzVadUF=3i9&t3kV1baPbHU3keAG3kV2+3}FQ6WM<)DVc`(q=HwP2 z8T>!MAjrX>z@Wg)D9FGh$jB_n`2Prl1Oo#zBO?PcVBzFo{eOf(U4Vg!iHVV!g^?91 z%gAIXq7;}|*!2GhgBT+tnl=U|ka==~3{1?73{1>WJq!%Cj7)-xj?9M2jSK(ZV&DNu z3Ni~a*fUIZ$$0&Zje%W=Ls*d{ zUF40u=(9iHcU}|Ob9~}q-aRuuK3MakVu!G+^vff=|J~U?fmzvlI@j`32E7XvnIC5}VJLipO@&dc_0U7HZ*rWfd mOkDWQ^y*I$;UBlNrf-dozTSDue|2W8PWXjaynGG+Zvp^V6@Z%n literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/98cc7e9fe87df914d89a0aef008930f27b3c26f5 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/98cc7e9fe87df914d89a0aef008930f27b3c26f5 new file mode 100644 index 0000000000000000000000000000000000000000..d7296ca03c4fa909de8fb18d8dda7f9cc6bafce7 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8S^+*Gt_%zeMTNl(j0_A6 zBBB1l3=GcyK>)0rnL&VoL7>Z*p^Jf`hT(Ed?_LH52F4_BcNezAv>mk!3=EtF9+AZi z4BWyX%*Zfnjsyb(1AB?5uPgf_Zdqm-#*1fbUobE*7<#%mhG?8mPFP?rkdU-&_gt1n z?YxyHDGiDYLdwnztQ!_{U*IXp&^!Ei=N8^{!x%1x{N;K}g18n2FfcHvmbgZgq$HN4 zS|t~yCYGc!7#SE^=o%X88d-)I8d@2fSs5DZ8dz8v7&sX%?m^Lzo1c=IR*9y;$im9N X5Taqb?9(p{3=9mOu6{1-oD!M{@- zH#gDNfI$Z&2hzsCq%^00<>|Nli|2f4?b>`Vri-ubk;k-Woy#;9Yz>% literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/9ae3b647d895af97fe872c0b1442df7b5b767160 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/9ae3b647d895af97fe872c0b1442df7b5b767160 new file mode 100644 index 0000000000000000000000000000000000000000..9e2eff2c4ec0c6ac3ba6e5558cd0a881b4dbb042 GIT binary patch literal 332 zcmZ?wbhEHbRA5kG_`(1Je0+Qg3JL}W2KM&$-rnBv@$t#Y$!Te6g@uJ39UT)UOqe}; z_T0I1mo8npX3d%%J9g~bx9`A#1E)@%x^m^pwQJX|U%!6y=FJBW9z1#S1Y{g4R{Y5V z7Et`p?U|dHp6Z*Jo|&A@o}QSSn`mpmpaYVWWl&&XVBMsk(3g@qFJslZoY(sbbk3LL z9(TJe@x3B(y4Tb4jhsf)JXx4JeRL!lb)6^LNOZG4R$Q2pCfhzhj z=NhopH#WDncXs#c7ZjD0RaDg&B_^k)XJ+RbhlE8$#l)GodwTo&2b#G!x!5XMT3@+w Q^VaP3=IC>-rn)?@yW@_ zX=z@Cg@p_Z^Ex^@CQO(xd-m+PbLTEyx^&H&H9L0f*tc)rfddClojP^p%9U%^u3f)= z{pQV^4<0;t^5lu)PZp3J42u7`J#!P&Q+*TDGn2E~(-U)Z6KzcybQrQ;gXI|*cz$L^ zsJaTudR*aK%y(USB*n$V#3g0qS+^<6 W%E?L}z5n3hwVRKgJ~L8eum%7zgHT8S literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/a335af37917ccf0c8b11bb884a3a74f3f1d2a7c6 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/a335af37917ccf0c8b11bb884a3a74f3f1d2a7c6 new file mode 100644 index 0000000000000000000000000000000000000000..ce8245f2da2025b6c37911a22179c45d06b90f5e GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo*B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^rhmxq0`DXPg(o6 zMbu>K%rMEDy4``g%#J?`5AA!hV$zaNg6iAWKd{~W!CO+4avja-qu4nd=2z3k4H*B&EAgJ;@mE{PeD1!?eE)S3`Y~T=J05Oh;E|)3)tP zU0F6>uy*o3BYi)ScwDtbe zHg5HObkRFHJNh=~+jVa~tufvdeJ*Ft%2|=Ax!E~yJd+pLoe#)Z@4z1YS7qYDZ>Cp& fiU|L>oi%-HboBMkTmGvvV|BtWyyE3+_83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33C+; literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/a8cecab5d917da5a4729632a7a18c564d7e1607d b/tensorflow/core/kernels/fuzzing/corpus/decode_png/a8cecab5d917da5a4729632a7a18c564d7e1607d new file mode 100644 index 0000000000000000000000000000000000000000..31a0fe82b99e564781cf22c7de167c25fc4d5e37 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(20oEV=?n}EJOMr-uK)l4zyJUL|Nr0r z|1UYw^=~=@0|R4{x4R2N2dk_H0|NtRfk$L90|U1(2s1Lwnj^u$z`$PO>Fdh=h+B?X zhVkOr+7}EA3{svhjv*44lM@t#41^YUbVgi0!OEVI%V@>G5K+x=WcTYmYZw?9R7+eV zN>UO_Qmw3#Qxi*48H@}JEp!bHb&V`T3=OS}&8!TKbqy@63=Eu%7WbfN$jwj5Osixt hF)%hmXfU#{GBAW_*e?6@3j+fKgQu&X%Q~loCICg|NOb@J literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/ade919ab2b4a458e806575c941dfe50ae3fd3621 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/ade919ab2b4a458e806575c941dfe50ae3fd3621 new file mode 100644 index 0000000000000000000000000000000000000000..776f0b88dcca473db2eb6cb7ccfab99183260ce8 GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAORKzP7c=pM;O!v7?_xt7@1iZS)sDb zj7+R7f@}=zLL9=1Mj}dqiG@x7k1&WaGNPKmz`z7DT27FGiJ6gsi5aS$fq{XMNl?*| z*-*K0;s09hSHCV|9(}tAy(H}p)T^qUi8_Y z?>n!F>^VO1Fz=ojA0MpwQL#hV^|_d}%fCDOCon5pPv=^G%Aj|lBJ=d<7e(u*m2GY) zpTb@~Q!mHjX^QU8z;Ddmj)jNzJy|hn$tOYeZR;P{ZhrDGWGYVt$=xg7~!y5z_8jD44h-DcybQNyc#Jr*{P#ru}8O8tS|DZHuVM z)R|$DH+3KKnd#{2Y}&ScsVmFI3--`4l(QE(! literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/b1251621a5eb5e7fda9cac9baead1c993a285c36 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/b1251621a5eb5e7fda9cac9baead1c993a285c36 new file mode 100644 index 0000000000000000000000000000000000000000..ba6aa256542e6dc9a6d802784ab451ed6b93b141 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT85&=FTt_%ze416FN1_li# z1_llgpYi|y|8Y4dBN!MM7?Zr+UD(AEJ64nJa0`PlBg3pY5)2Fs>?NMQ zuI!JvWtn9dFP^P^!N9WN798;5k7nc9Fkzi)gUQpJ9ZMN} zH5lrdt^`eGU|>)!ag8WRNi0dVN-j!GEJP pa57rlgQ6ifKP5A*5>11Vg_VIJM8kI3r(Zz+@pScbS?83{1OVIYMZf?6 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/b1516b78c3dfe77eeb554985fd7344c0478fbbcb b/tensorflow/core/kernels/fuzzing/corpus/decode_png/b1516b78c3dfe77eeb554985fd7344c0478fbbcb new file mode 100644 index 0000000000000000000000000000000000000000..c4ec4ad4b9c4a38459c974e8718532bc8ff4d345 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(20oEV=?n}EJOMr-uK)l4zyJUL|Nr0r z|1UYw^=~=@0|R4{x4R2N2dk_H0|NtRfk$L90|U1(0~AOwFfg!}c>21sKjM~SmSMbj zw)O=B1A~;Oi(`ny<>UkfAp@bs9i0)EPq4CQ2GtVRh?11V zl2j|J2s5V_gFaD+2>3qs2Wa8glbfGSey*n2KEw9Usv`=+_KCvj2F+=zF=Tr;PG^E4B@z*oFH+Bfq`KG g17o6Utvdq)gKCLuL`h0wNvc(HQEH;gI;Vst04E83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$Atc-!cIKK>;ovAz>i_VSWJt0gxe#Af3!C94ssx0^FS30wja~ z2N(o77!(*3m>C5bm;@P_1sNC^8JGl_S%eG}l^h$L0w?~z#lXW1787K!XE?Q5NzA2a z-aN0BJce5wS}Hjwh4!SZiuksXVNT$hGATV}>|_4d5k7D=;P{r(uc<>coVEm~G(RXR&z z>5=J~S=WuQm~{4Whqf6u3=IC>-rn)?@yW@_ zX=z@Cg@p_Z^Ex^@CQO(xd-m+Pb2|h4+&a zGc!WfRnU`l@y{zBReWtsg(gy59IS_5G6=c*FJns75a3{C4mw%U*WmhGsZfKbwaM|} zgcz&t$0^C3CIYO?%&Z)|??3yN=G4?RG_|yKbeRTm=H0&k;Ni8KkDfj=Qe?0O0DvA} ATL1t6 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/c01457c6889fb1b597d308363a36412c0b7f90e7 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/c01457c6889fb1b597d308363a36412c0b7f90e7 new file mode 100644 index 0000000000000000000000000000000000000000..eff793b204a409edde4d0b601cb5e43e3fe1d088 GIT binary patch literal 497 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&335}@nBh{4Obmj| zEJBKofrW;R6G3`GTG8|}F@y99GBPkRF*7i-!Zb572r?-$8#*Qm1r|1b_MFuT5y(!iMt$+>UTX$i|yS(lV&q;-F|a(AIGB|>ubN+6q^@Y@9$Kd zrlh2#q)CYeLXWpcwuda2vuXXv&Lug)Sn=Mfa!pl!(X6s*QOW1~&5b@C zJ)U3sIDF~ln{Tbz4$l{>EK06Sdc0-Xo`902DLHp9MVLt%a2;XeVO%ZG{;mAkVL3gY v4ab!g0=$<$*^v2WL*0W{IXOG6R{fqC{F3YMe}?S%{_>|0Gdn)0rnL&VoL7>Z*p^Jf`hT(Ed?_LH52F4_BcNezAv>nzA3=EtF9+AZi z4BWyX%*Zfnjsyb(1AB?5uPgf_Zdqm-#*1fbUobE*7<#%mhG?8GNl7e8wMs5ZHMGz* oG}JY+3^6pcGP1BTFw`}$ure^%F8lNg0|Nttr>mdKI;Vst041?5UH||9 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/c9a03eb758dd84e954e3d70916e2311e8fd21f3c b/tensorflow/core/kernels/fuzzing/corpus/decode_png/c9a03eb758dd84e954e3d70916e2311e8fd21f3c new file mode 100644 index 0000000000000000000000000000000000000000..c23fb3da9ce10cfab5eed3382e34f887bb117942 GIT binary patch literal 249 zcmZ?wbhEHbRA5kG_`(1Jj0_A6EDU^nd<-HC3JMAa1_q{vX7={>3=IC>-rn)?@yW@_ zX=z@Cg@p_Z^Ex^@CQO(xd-m+Pb2|h4+&a zGc!WfRnU`l&Ce?yReWtsg(gy59IS_5G6=c*FJns75a3{C4mw%U*WmhGsZfKbwaM|} zgcz&t$0^C3CIYO?%&Z)|??3yN=G4?RG_|yKbeRTm=H0&k;Ni8KkDfj=Qe?0O0E0hY AWB>pF literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/cf892756b33578a54ab20044514e573328d2f1d7 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/cf892756b33578a54ab20044514e573328d2f1d7 new file mode 100644 index 0000000000000000000000000000000000000000..42f1f9a29827e46a86ee16dd90a8779e7bc927cb GIT binary patch literal 249 zcmZ?wbhEHbRA5kG_`(1Jj0_A6EDU^nd<-HC3JMAa1_q{vX7={>3=IC>-rn)?@yW@_ zX=z@Cg@p_Z^Ex^@CQO(xd-m+Pb2|h4+&a zGc!WfRnU`l&Ce?yReWtsg(gy59IS_5G6=c*FJns75a3{C4mw%U*WmhGsZfKbwaM|} zgcz&t$0^C3CIYO?%&Z)|??3yN=G4?RG_|yKbeRTm=H0&k;Ni8KkDfj=Qe?0O0E9+g AW&i*H literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/d3bc3f158a63f1d50b474addd3f7b3d17f23e8e9 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/d3bc3f158a63f1d50b474addd3f7b3d17f23e8e9 new file mode 100644 index 0000000000000000000000000000000000000000..6b1183f4ffaab6f8b429eeb7ce3640bd3df887d6 GIT binary patch literal 507 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0cwE% z2N(o77!(*3m>C5bm;@P_1sVSzVUS{AU}R-vKn6_AENq+{|Bo=}3NSD+GO{xB!sQv6 zm{}ND*#w2yIXHzyBqS9L9K*t=FS~M8^#2hCaYhh8Hi?0end$!#1|>m824)6EW)^0c zBqIZpATx`QqM?#wqf_9-|F;-;n89L#4ECWtDXSvBZDg3!c%ppc2?kGwqbGWA9ntC7 zq4|7ev8aiV*TcwDi>6tHdK;doU}c&7fYEI0>XNm-5gl7PB89W6ybE$aJv+5``TY5B zZ=L2_-TT{?=cnoUZ*Mx|kIu0vzjQFIBVKy{Bd)%>cN6Q?qOvc0x?ZXD%hcI3;q;D^ uOAHw_=bcVJeL7C+dvslEeZywHyhU>@x67}(bzkvE|NG-}t{-^*|0V#6gL-NJ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/d4906950aa9d60ad09dc0f5413c3d88080c3bc37 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/d4906950aa9d60ad09dc0f5413c3d88080c3bc37 new file mode 100644 index 0000000000000000000000000000000000000000..2d8fd3f3f0d34782904ba50077e62b6c82ef4f13 GIT binary patch literal 262 zcmZ?wbhEHbRA5kG_`(1Jj0_A6EDU^nd<-HC3JMAa1_q{vX7={>3=IC>-rn)?@yW@_ zX=(re|L0<0V07r{m@r|&?AiHAbLTEyx^#`+njJfK?Ay2Rz<~p&PMx}vp6Z*Jo|&A@ zo}QSSn;2=tpu>>$dSBkhLRRv?@4rOpE8t|XuuMGiGc!WfRnU`l@y{zB@_cPfg(gyb d9ITS!Vq)TwGV-k3lx5{)rH@J<4pZf}1^^ccI}!i@ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/da31578a8068bad65e1c7a3d06e8f543a2a0bc65 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/da31578a8068bad65e1c7a3d06e8f543a2a0bc65 new file mode 100644 index 0000000000000000000000000000000000000000..dc37f788a1acf12c1e252c880f26eb0a4f53809e GIT binary patch literal 332 zcmZ?wbhEHbRA5kG_`(1Je0+Qg3JL}W2KM&$-rnBv@$t#Y$!Te6g@uJ39UT)UOqe}; z_T0I1mo8npX3d%%J9g~bx9`A#1E)@%x^m^pwQJX|U%!6y=FJBW9z1#S1Y{g4R{Y5V z7Et`p?U|dHp6Z*Jo|&A@o}QSSn`mpmpaYTwIfa3BlY&BDO6I(bRqJwI?<>$bUy^&= z?Xtx8ip1$&Ps=xQ8cp+LVe0hJkz~|$o@gV{&H7kzVM>~K_mPDj3Id$1&Pkfb3?{cf z3Q!Q>Vn3SPbTC$lhm)0=iHVt&lSfe8MxR$yfSZGbiII_sg@ao_l-Hnt;^e8*XU?8$ zz*gVb+}hsR-K$?vR8m$^Rb!NxoSL4QoogHt77-N_XX5VZ?du83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&332(c zViBInIbl&|=YgcBf?s5R%;}r;%cC}2`dgLcr|kJ}Z=L2_-TT{?=cnoUZ*Mx|kIu0v zzjQFIBVKy{Bd)%>cN6Q?qOvc0x?ZXD%hcI3;q;D^OAOyg&O4oc`gEMs_vpIT`i9MX ad5h*+ZkJzm>%QWT{`be{TtD#q|4jg1iPPx- literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/deea4ecc6f0b2a6d89fd25ff76762299f21602fb b/tensorflow/core/kernels/fuzzing/corpus/decode_png/deea4ecc6f0b2a6d89fd25ff76762299f21602fb new file mode 100644 index 0000000000000000000000000000000000000000..6daa5452a159945afb1d5e072f3f5daa3a1cc2d6 GIT binary patch literal 677 zcmex=83u;`w;7xnn31R0o^85x+Eq1qW37#NuZ z6&;xkm9-cCzs0}XPyL+pDGGoEH0P|E*yt{kZt=SA`p5b)6OJB5&+P zpZ)p1^P0$>;}Z|_?wRrN!I~cxJA_@Ii|uy#cW3_uW@YQ?T+2@x^e$9no*w<8X#KRZ z%~Q(R8_H+u|D<&=ZB&fb^{R7+0PacL$<%wXN@{8dG*F@1& z@pbEteEhvmwOVFR-=y6_`zMEGxZBBPxd_fVA~BI?P2Wcg6{9z@R#qA;Tc^bJRtuld z+gbXiu*iDXn_d5mBNwXtoVi}mwNNl|$MhLHvQ9FFJ3qZE*f8xc!_`pVwQpNQO{UHa zlf0?>kk3p?Wxd&g%@Cf9$4>24SQ+5OtD zA|mVN`RHqHc+|A@{?j&Y^?h{FJ32f1Hs{-QZ$7Ot-V}WL&{)WX1)xbGWQFyGvCeQmyP-N~)x|AiUtH z6TB`hI(q2fl=ZH&RunFF5m_!*^)}(tB9F%&J&jj*EaPjp-O8|JTfiZrdh_yzBg)?{ zKmNzGj9Iy@`?HMYM}4!`%%2$wCzQ9?8Za<0sFt`!l%yncTId=Y z>Ka*w7#dm`n^_qe>l#>C85lSjE$%_lkei>9nO2FW!N|hOz!0KgyX@01p!oB2^>bP0 Hl+XkKwtKx6 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/ea24498fc7a144fccc6f1665ebf7020df803dd1a b/tensorflow/core/kernels/fuzzing/corpus/decode_png/ea24498fc7a144fccc6f1665ebf7020df803dd1a new file mode 100644 index 0000000000000000000000000000000000000000..ab99a8374aa80d829891b5670078d95b776a6957 GIT binary patch literal 677 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33kFf%eTAOjXo4%Yui7}NzAn3$LtnOPWFp|Xrj z%&aVeYz*u|9Kwo*B1(aYg-!pDFo-cSqM5+J1TtDqkb#Mrk%5UBs-1y>fssj2(UI9u zxpCqDTMRrPNkL{o27897E*Y=Cy;>^HX|b>N-x`L}kBk3)Rk$Hm*IA)1^2T2D*`Mz_ zuZiqAKJhT`o*5q>toc!~L)i7Xn6=BlJNqXvD_c+JT7Jr)ccCKl^yn8w>!+1%p0f6B zi>S%enPHMQb-M#~nH_%?9@_V0#iS*l1l6~#e_*@$$-|JTJQ0jjelfh@nkbqozHZ%- zkH6QcR?F<^o3vYK|KzX?cRRT(7r{A4Bqs8#>HBD*V)RDVD!8z8>y)_GYT*-lJ4@db z7Fq9lv+JL6&|x#S_AnU1c`rfu7o zy0UD%VDG#@T6xNcIOh-7rif2nXSer`&zelG{|wXJF8;IowO>U<*3I+L*V^!?Y3u!` zZQSbn=%ROYcJyt|x9i?~T4TH^`drSOm9rvKbF*{acqT8fJ0Fm--hn;(ugb)Q-%PLm f6cPS$J8SyZ=;-U6xBORU#_EJ$c*V=t@c$+Np0(E{ literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/eaa5d677e797c07bac98c3c7051abad91852e7c6 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/eaa5d677e797c07bac98c3c7051abad91852e7c6 new file mode 100644 index 0000000000000000000000000000000000000000..63ff2676ae32de1b7293ec4a8c34b550b2c22ad5 GIT binary patch literal 507 zcmex=83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33IqJ{>3ZJ-V*7zF{+8-lDmd+vQi?y07@7 O|NZef*AG1Ze-i+(N`bNf literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/ed7871269315725535d8bffec7836c45a3fc5c26 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/ed7871269315725535d8bffec7836c45a3fc5c26 new file mode 100644 index 0000000000000000000000000000000000000000..d2a4b9aafd7b745a50401a3ac94660ccc787f99a GIT binary patch literal 527 zcmZ?wbhEHbRA5kG_^Qmn$H%9jpkQENU~g~l?d_eMoSc@HR#;fr(a|ws!i3qgXD?m4 zbj_MIJ9g~Yw{PEp0|!o>I(6mBm220oUB7<)=FOWA9z1yR8ZYn>6yvd z?CFWQxrw$03_2i5kXISl{vDWD;GrYce_~0|$sDWs7gm&TiAK6!S){@8sl-YyfWw=& z)?zjf+vJ-Cb_+9CY~C57A;h_~=w`{IfMO{zVF5l~UOoX~F{yfgC3$HvL4F=CPEIZ! zenBy5`4k^T8F68LZVq-fHg*o~;L;?S1|J1!Q2`zfRu*Pv7FG@(0a0lMUnMz75k4+< z7A8hUCKh%sJ`qW|MV?Bs5<`dx z&&6rHv(55+^KL!8`Z|0=;?X`!#Z<1TT4C!FPA+JGSsB1|2yO yxVE$8&4Y`FkDot1IsMX_%+Jr##64~|yiM9p|It&a9>>v#c pOmZ##D^I`WUp!~at?teD_Wb5=d*m_gS?97>r?$Q0p3TZ&4FGT_A0_|* literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/ef09f26e0ee61329f84a9f589629a865ae9ee0a6 b/tensorflow/core/kernels/fuzzing/corpus/decode_png/ef09f26e0ee61329f84a9f589629a865ae9ee0a6 new file mode 100644 index 0000000000000000000000000000000000000000..2422f7cb3fefac0242fc41a5b1a5aec6c0ffc42e GIT binary patch literal 276 zcmex=83u;`w;7xnn3+I;nTd&+nTeU1g^dLSIM~=&**H14 zxHvgDIk|ZFdAPXwxH&m_1$p`S1q1{IxOjwwg#?881q1~CA7J3-P*h;J&B!Ro@c#&d zI0GXiBO?P6fN>a^7??Q(9oZEN|KDQZ0I9KOcr}Mxt7ju~9b1@W5dXwxfmIPN(o(87 z?B=S$5HRprHAzCIbY)cSjo?*@i4l{IJl=b@V2M$iwB%%lQz37XQmQv>`Bih;XH!$e soUc2hYL{PrxGHgmz=7v`eG3+7wMt3!aINMsV86*4DiOdwasL0C06X_f9smFU literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_png/f477da4d7d8ff2066041e1dd5ee4e833b7111a1a b/tensorflow/core/kernels/fuzzing/corpus/decode_png/f477da4d7d8ff2066041e1dd5ee4e833b7111a1a new file mode 100644 index 0000000000000000000000000000000000000000..2ec0b7ae29cea7c8aa406470f5ad812102ba207b GIT binary patch literal 527 zcmZ?wbhEHbRA5kG_^Qmn$H%9jpkQENU~g~l?d_eMoSc@HR#;fr(a|ws!i3qgXD?m4 zbj_MIJ9g~Yw{PEp0|!o>I(6mBm220oUB7<)=FOWA9z1yR8ZYn>6yvd z?CFWQxrw$03_2i5kXISl{vDWD;GrYce_~0|$sDWs7gm&TiAK6!S){@8sl-YyfWw=& z)?zjf+vJ-Cb_+9CY~C57A;h_~=w`{IfMO{zVF5l~UOoX~F{yfgC3$HvL4F=CPEIZ! zenBy5`4k^T8F68LZVq-fHg*nfeqnK$1|J1!Q2`zfRu*Pv7FG@(0a0lMUnMz75k4+< z7A8hUCKh%sJ`qW|MV?Bs5<`dx z&&6rHv(55+^Pb+i`Z|0=;?X`!#Z<1TT4C!FPA+JGSsB1|2yO yxVE$8&4Y`FkDot1IsMX_%+Jr##683u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+0LTzVkWOY64i**;0d7ui0g}Q0 z0}O&33IqJ{>3ZJ-V*7zF{+8 a-lDmd+vQi?y07@7|NZef*AG1Ze-i*g+{E-$-^BFH83u;`w;7xnn3+HTL^3loGqbRN4?hnVHy<}AC$AtcAHRTrpa2(-kg$+|Fu#C+!2bgb+#C!F3<`{lf(-wUFo-iS zGBPqUAOki|uK!0Elm!?VSlF1Dk>nVem|0la*ad}zMMT96#sA-8-~eg0XE?Qhfq_BR z?pBrfr{9roxBWGr{PmhY-DCG28QXPhjB`GHe6!Z<@$J~DJ&)DDgf=iRbnX4R=Gv{B xRlgp4EPN=w!M9BaE literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/dictionaries/decode_png.dict b/tensorflow/core/kernels/fuzzing/dictionaries/decode_png.dict new file mode 100644 index 0000000000..d795ae7f71 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/dictionaries/decode_png.dict @@ -0,0 +1,50 @@ +header_87a="87a" +header_89a="89a" +header_gif="GIF" +header_jfif="JFIF\x00" +header_jfxx="JFXX\x00" +header_png="\x89PNG\x0d\x0a\x1a\x0a" +marker_2c="," +marker_3b=";" +section_2101="!\x01\x12" +section_21f9="!\xf9\x04" +section_21fe="!\xfe" +section_21ff="!\xff\x11" +section_IDAT="IDAT" +section_IEND="IEND" +section_IHDR="IHDR" +section_PLTE="PLTE" +section_bKGD="bKGD" +section_cHRM="cHRM" +section_fRAc="fRAc" +section_ffc0="\xff\xc0" +section_ffc2="\xff\xc2" +section_ffc4="\xff\xc4" +section_ffd0="\xff\xd0" +section_ffd8="\xff\xd8" +section_ffd9="\xff\xd9" +section_ffda="\xff\xda" +section_ffdb="\xff\xdb" +section_ffdd="\xff\xdd" +section_ffe0="\xff\xe0" +section_ffe1="\xff\xe1" +section_fffe="\xff\xfe" +section_gAMA="gAMA" +section_gIFg="gIFg" +section_gIFt="gIFt" +section_gIFx="gIFx" +section_hIST="hIST" +section_iCCP="iCCP" +section_iTXt="iTXt" +section_oFFs="oFFs" +section_pCAL="pCAL" +section_pHYs="pHYs" +section_sBIT="sBIT" +section_sCAL="sCAL" +section_sPLT="sPLT" +section_sRGB="sRGB" +section_sTER="sTER" +section_tEXt="tEXt" +section_tIME="tIME" +section_tRNS="tRNS" +section_zTXt="zTXt" diff --git a/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl b/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl index ed54abb742..e932213359 100644 --- a/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl +++ b/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl @@ -17,3 +17,9 @@ def tf_oss_fuzz_corpus(name): name = name + "_corpus", srcs = native.glob(["corpus/" + name + "/*"]), ) + +def tf_oss_fuzz_dict(name): + native.filegroup( + name = name + "_dict", + srcs = native.glob(["dictionaries/" + name + ".dict"]), + ) -- GitLab From 41cc1de5cf929a7ec18a76df9a2e3916b19b6b6d Mon Sep 17 00:00:00 2001 From: Anna R Date: Thu, 29 Nov 2018 14:22:06 -0800 Subject: [PATCH 579/672] Support estimator names when generating renames_v2.py. PiperOrigin-RevId: 223410761 --- tensorflow/tools/compatibility/renames_v2.py | 2 +- .../tools/compatibility/tf_upgrade_v2_test.py | 39 ++++++++---- .../update/generate_v2_renames_map.py | 60 +++++++++++++++---- 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index dda7943821..5a27eb241c 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -603,7 +603,7 @@ renames = { 'tf.train.SingularMonitoredSession': 'tf.compat.v1.train.SingularMonitoredSession', 'tf.train.Supervisor': 'tf.compat.v1.train.Supervisor', 'tf.train.SyncReplicasOptimizer': 'tf.compat.v1.train.SyncReplicasOptimizer', - 'tf.train.VocabInfo': 'tf.compat.v1.train.VocabInfo', + 'tf.train.VocabInfo': 'tf.estimator.VocabInfo', 'tf.train.WorkerSessionCreator': 'tf.compat.v1.train.WorkerSessionCreator', 'tf.train.add_queue_runner': 'tf.compat.v1.train.add_queue_runner', 'tf.train.assert_global_step': 'tf.compat.v1.train.assert_global_step', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index 9c334451bf..dbddf170d6 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -36,6 +36,32 @@ from tensorflow.tools.compatibility import ast_edits from tensorflow.tools.compatibility import tf_upgrade_v2 +_TENSORFLOW_API_ATTR_V1 = ( + tf_export.API_ATTRS_V1[tf_export.TENSORFLOW_API_NAME].names) +_TENSORFLOW_API_ATTR = tf_export.API_ATTRS[tf_export.TENSORFLOW_API_NAME].names +_ESTIMATOR_API_ATTR_V1 = ( + tf_export.API_ATTRS_V1[tf_export.ESTIMATOR_API_NAME].names) +_ESTIMATOR_API_ATTR = tf_export.API_ATTRS[tf_export.ESTIMATOR_API_NAME].names + + +def get_v1_names(symbol): + names_v1 = [] + if hasattr(symbol, _TENSORFLOW_API_ATTR_V1): + names_v1.extend(getattr(symbol, _TENSORFLOW_API_ATTR_V1)) + if hasattr(symbol, _ESTIMATOR_API_ATTR_V1): + names_v1.extend(getattr(symbol, _ESTIMATOR_API_ATTR_V1)) + return names_v1 + + +def get_v2_names(symbol): + names_v2 = set() + if hasattr(symbol, _TENSORFLOW_API_ATTR): + names_v2.update(getattr(symbol, _TENSORFLOW_API_ATTR)) + if hasattr(symbol, _ESTIMATOR_API_ATTR): + names_v2.update(getattr(symbol, _ESTIMATOR_API_ATTR)) + return list(names_v2) + + class TestUpgrade(test_util.TensorFlowTestCase): """Test various APIs that have been changed in 2.0. @@ -79,32 +105,23 @@ class TestUpgrade(test_util.TensorFlowTestCase): return v2_symbols = set([]) - attr_v2 = tf_export.API_ATTRS[ - tf_export.TENSORFLOW_API_NAME].names def symbol_collector(unused_path, unused_parent, children): for child in children: _, attr = tf_decorator.unwrap(child[1]) - if not hasattr(attr, "__dict__"): - continue - api_names_v2 = attr.__dict__.get(attr_v2, []) + api_names_v2 = get_v2_names(attr) for name in api_names_v2: v2_symbols.add("tf." + name) visitor = public_api.PublicAPIVisitor(symbol_collector) traverse.traverse(tf.compat.v2, visitor) - attr_v1 = ( - tf_export.API_ATTRS_V1[tf_export.TENSORFLOW_API_NAME].names) - # Converts all symbols in the v1 namespace to the v2 namespace, raising # an error if the target of the conversion is not in the v2 namespace. def conversion_visitor(unused_path, unused_parent, children): for child in children: _, attr = tf_decorator.unwrap(child[1]) - if not hasattr(attr, "__dict__"): - continue - api_names = attr.__dict__.get(attr_v1, []) + api_names = get_v1_names(attr) for name in api_names: _, _, _, text = self._upgrade("tf." + name) if (text and diff --git a/tensorflow/tools/compatibility/update/generate_v2_renames_map.py b/tensorflow/tools/compatibility/update/generate_v2_renames_map.py index 554b42c171..19ad6c3a2a 100644 --- a/tensorflow/tools/compatibility/update/generate_v2_renames_map.py +++ b/tensorflow/tools/compatibility/update/generate_v2_renames_map.py @@ -72,6 +72,50 @@ _TENSORFLOW_CONSTANTS_ATTR_V1 = ( _TENSORFLOW_CONSTANTS_ATTR = ( tf_export.API_ATTRS[tf_export.TENSORFLOW_API_NAME].constants) +_ESTIMATOR_API_ATTR_V1 = ( + tf_export.API_ATTRS_V1[tf_export.ESTIMATOR_API_NAME].names) +_ESTIMATOR_API_ATTR = tf_export.API_ATTRS[tf_export.ESTIMATOR_API_NAME].names +_ESTIMATOR_CONSTANTS_ATTR_V1 = ( + tf_export.API_ATTRS_V1[tf_export.ESTIMATOR_API_NAME].constants) +_ESTIMATOR_CONSTANTS_ATTR = ( + tf_export.API_ATTRS[tf_export.ESTIMATOR_API_NAME].constants) + + +def get_v1_names(symbol): + names_v1 = [] + if hasattr(symbol, _TENSORFLOW_API_ATTR_V1): + names_v1.extend(getattr(symbol, _TENSORFLOW_API_ATTR_V1)) + if hasattr(symbol, _ESTIMATOR_API_ATTR_V1): + names_v1.extend(getattr(symbol, _ESTIMATOR_API_ATTR_V1)) + return names_v1 + + +def get_v2_names(symbol): + names_v2 = [] + if hasattr(symbol, _TENSORFLOW_API_ATTR): + names_v2.extend(getattr(symbol, _TENSORFLOW_API_ATTR)) + if hasattr(symbol, _ESTIMATOR_API_ATTR): + names_v2.extend(getattr(symbol, _ESTIMATOR_API_ATTR)) + return list(names_v2) + + +def get_v1_constants(module): + constants_v1 = [] + if hasattr(module, _TENSORFLOW_CONSTANTS_ATTR_V1): + constants_v1.extend(getattr(module, _TENSORFLOW_CONSTANTS_ATTR_V1)) + if hasattr(module, _ESTIMATOR_CONSTANTS_ATTR_V1): + constants_v1.extend(getattr(module, _ESTIMATOR_CONSTANTS_ATTR_V1)) + return constants_v1 + + +def get_v2_constants(module): + constants_v2 = [] + if hasattr(module, _TENSORFLOW_CONSTANTS_ATTR): + constants_v2.extend(getattr(module, _TENSORFLOW_CONSTANTS_ATTR)) + if hasattr(module, _ESTIMATOR_CONSTANTS_ATTR): + constants_v2.extend(getattr(module, _ESTIMATOR_CONSTANTS_ATTR)) + return constants_v2 + def get_canonical_name(v2_names, v1_name): if v2_names: @@ -87,9 +131,7 @@ def get_all_v2_names(): """Visitor that collects TF 2.0 names.""" for child in children: _, attr = tf_decorator.unwrap(child[1]) - if not hasattr(attr, '__dict__'): - continue - api_names_v2 = attr.__dict__.get(_TENSORFLOW_API_ATTR, []) + api_names_v2 = get_v2_names(attr) for name in api_names_v2: v2_names.add(name) @@ -107,10 +149,8 @@ def collect_constant_renames(): """ renames = set() for module in sys.modules.values(): - if not hasattr(module, _TENSORFLOW_CONSTANTS_ATTR_V1): - continue - constants_v1_list = getattr(module, _TENSORFLOW_CONSTANTS_ATTR_V1) - constants_v2_list = getattr(module, _TENSORFLOW_CONSTANTS_ATTR) + constants_v1_list = get_v1_constants(module) + constants_v2_list = get_v2_constants(module) # _tf_api_constants attribute contains a list of tuples: # (api_names_list, constant_name) @@ -146,10 +186,8 @@ def collect_function_renames(): """Visitor that collects rename strings to add to rename_line_set.""" for child in children: _, attr = tf_decorator.unwrap(child[1]) - if not hasattr(attr, '__dict__'): - continue - api_names_v1 = attr.__dict__.get(_TENSORFLOW_API_ATTR_V1, []) - api_names_v2 = attr.__dict__.get(_TENSORFLOW_API_ATTR, []) + api_names_v1 = get_v1_names(attr) + api_names_v2 = get_v2_names(attr) deprecated_api_names = set(api_names_v1) - set(api_names_v2) for name in deprecated_api_names: renames.add((name, get_canonical_name(api_names_v2, name))) -- GitLab From f299e057dbb01c45a2b699da2fbd8193e63cb059 Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Thu, 29 Nov 2018 14:26:27 -0800 Subject: [PATCH 580/672] Add make_dataset_iterator implementation to parameter server strategy and collective all reduce strategy. PiperOrigin-RevId: 223411477 --- .../python/collective_all_reduce_strategy.py | 15 +++++++++++---- .../python/parameter_server_strategy.py | 5 +++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py index 617a95f3c4..6e9f9facd0 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py @@ -24,6 +24,7 @@ from tensorflow.contrib.distribute.python import mirrored_strategy from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib from tensorflow.python.distribute import cross_device_utils +from tensorflow.python.distribute import device_util from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import multi_worker_util from tensorflow.python.distribute import values @@ -80,6 +81,7 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): ] else: local_devices = ["/device:CPU:0"] + self._worker_device = device_util.canonicalize("/device:CPU:0") self._collective_keys = cross_device_utils.CollectiveKeys() super(CollectiveAllReduceExtended, self).__init__( @@ -116,14 +118,14 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): self._is_chief = multi_worker_util.is_chief(cluster_spec, task_type, task_id) - worker_device = "/job:%s/task:%d" % (task_type, task_id) + self._worker_device = "/job:%s/task:%d" % (task_type, task_id) if num_gpus_per_worker: local_devices = [ - "%s/device:GPU:%d" % (worker_device, i) + "%s/device:GPU:%d" % (self._worker_device, i) for i in range(num_gpus_per_worker) ] else: - local_devices = [worker_device] + local_devices = [self._worker_device] self._collective_keys = cross_device_utils.CollectiveKeys() super(CollectiveAllReduceExtended, self).__init__( @@ -222,6 +224,11 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): return values.PerReplicaDataset( self._call_dataset_fn(dataset_fn), self._devices, True) + def _make_dataset_iterator(self, dataset): + worker_device_pairs = [(self._worker_device, self._devices)] + return values.DatasetIterator(dataset, worker_device_pairs, + self._num_replicas_in_sync) + def _make_input_fn_iterator( self, input_fn, @@ -238,7 +245,7 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): num_replicas_in_sync=self._num_replicas_in_sync) return values.InputFunctionIterator( - input_fn, [(self._default_device, self._devices)], [input_context]) + input_fn, [(self._worker_device, self._devices)], [input_context]) def _configure(self, session_config=None, diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy.py b/tensorflow/contrib/distribute/python/parameter_server_strategy.py index 75ee41c4cf..eaeb4d7030 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy.py @@ -237,6 +237,11 @@ class ParameterServerExtended(distribute_lib.DistributionStrategyExtended): return values.PerReplicaDataset( self._call_dataset_fn(dataset_fn), self._compute_devices, True) + def _make_dataset_iterator(self, dataset): + worker_device_pairs = [(self._worker_device, self._compute_devices)] + return values.DatasetIterator(dataset, worker_device_pairs, + self._num_replicas_in_sync) + def _make_input_fn_iterator( self, input_fn, -- GitLab From cac337447456cf0c0a2d3a362d02f4dbccf13bb3 Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Thu, 29 Nov 2018 14:28:01 -0800 Subject: [PATCH 581/672] Change underlying definitions of TFLite constants to be tf.dtypes. PiperOrigin-RevId: 223411751 --- tensorflow/lite/python/BUILD | 2 + tensorflow/lite/python/convert.py | 41 +++++++++++++++++-- tensorflow/lite/python/convert_test.py | 22 ++++++++++ tensorflow/lite/python/lite.py | 6 +-- tensorflow/lite/python/lite_constants.py | 25 ++++++----- tensorflow/lite/python/tflite_convert.py | 33 ++++++++++++--- .../golden/v1/tensorflow.lite.constants.pbtxt | 10 ++--- .../golden/v2/tensorflow.lite.constants.pbtxt | 20 --------- 8 files changed, 107 insertions(+), 52 deletions(-) diff --git a/tensorflow/lite/python/BUILD b/tensorflow/lite/python/BUILD index 017dd72f78..acf827892b 100644 --- a/tensorflow/lite/python/BUILD +++ b/tensorflow/lite/python/BUILD @@ -89,6 +89,7 @@ py_library( srcs_version = "PY2AND3", deps = [ "//tensorflow/lite/toco:toco_flags_proto_py", + "//tensorflow/python:dtypes", ], ) @@ -103,6 +104,7 @@ py_library( "//tensorflow/lite/toco:toco_flags_proto_py", "//tensorflow/lite/toco/python:tensorflow_wrap_toco", "//tensorflow/lite/toco/python:toco_from_protos", + "//tensorflow/python:dtypes", "//tensorflow/python:platform", ], ) diff --git a/tensorflow/lite/python/convert.py b/tensorflow/lite/python/convert.py index 9991fb2a73..756c9daabe 100644 --- a/tensorflow/lite/python/convert.py +++ b/tensorflow/lite/python/convert.py @@ -28,6 +28,8 @@ import tempfile as _tempfile from tensorflow.lite.python import lite_constants from tensorflow.lite.toco import model_flags_pb2 as _model_flags_pb2 from tensorflow.lite.toco import toco_flags_pb2 as _toco_flags_pb2 +from tensorflow.lite.toco import types_pb2 as _types_pb2 +from tensorflow.python.framework import dtypes from tensorflow.python.platform import resource_loader as _resource_loader from tensorflow.python.util import deprecation from tensorflow.python.util.lazy_loader import LazyLoader @@ -53,6 +55,18 @@ else: if _toco_from_proto_bin and not _os.path.exists(_toco_from_proto_bin): _toco_from_proto_bin = "toco_from_protos" + +# Map of tf.dtypes to TFLite types_flag_pb2. +_MAP_TF_TO_TFLITE_TYPES = { + dtypes.float32: _types_pb2.FLOAT, + dtypes.int32: _types_pb2.INT32, + dtypes.int64: _types_pb2.INT64, + dtypes.string: _types_pb2.STRING, + dtypes.uint8: _types_pb2.QUANTIZED_UINT8, + dtypes.complex64: _types_pb2.COMPLEX64 +} + + def _try_convert_to_unicode(output): if output is None: return u"" @@ -65,6 +79,24 @@ def _try_convert_to_unicode(output): return output +def convert_dtype_to_tflite_type(tf_dtype): + """Converts tf.dtype to TFLite proto type. + + Args: + tf_dtype: tf.dtype + + Raises: + ValueError: Unsupported tf.dtype. + + Returns: + types_flag_pb2. + """ + result = _MAP_TF_TO_TFLITE_TYPES.get(tf_dtype) + if result is None: + raise ValueError("Unsupported tf.dtype {0}".format(tf_dtype)) + return result + + class OpsSet(enum.Enum): """Enum class defining the sets of ops available to generate TFLite models. @@ -214,10 +246,10 @@ def build_toco_convert_protos(input_tensors, `foo.get_shape()` and `foo.dtype`. output_tensors: List of output tensors (only .name is used from this). inference_type: Target data type of real-number arrays in the output file. - Must be `{FLOAT, QUANTIZED_UINT8}`. (default FLOAT) + Must be `{tf.float32, tf.uint8}`. (default tf.float32) inference_input_type: Target data type of real-number input arrays. Allows for a different type for input arrays in the case of quantization. - Must be `{FLOAT, QUANTIZED_UINT8}`. (default `inference_type`) + Must be `{tf.float32, tf.uint8}`. (default `inference_type`) input_format: Type of data to read Currently must be `{TENSORFLOW_GRAPHDEF}`. (default TENSORFLOW_GRAPHDEF) input_shapes: Input array shape. It needs to be a list of the same length @@ -276,9 +308,10 @@ def build_toco_convert_protos(input_tensors, toco = _toco_flags_pb2.TocoFlags() toco.input_format = input_format toco.output_format = output_format - toco.inference_type = inference_type + toco.inference_type = convert_dtype_to_tflite_type(inference_type) if inference_input_type: - toco.inference_input_type = inference_input_type + toco.inference_input_type = convert_dtype_to_tflite_type( + inference_input_type) else: toco.inference_input_type = toco.inference_type toco.drop_control_dependency = drop_control_dependency diff --git a/tensorflow/lite/python/convert_test.py b/tensorflow/lite/python/convert_test.py index 7a0bce921b..40576e16db 100644 --- a/tensorflow/lite/python/convert_test.py +++ b/tensorflow/lite/python/convert_test.py @@ -23,6 +23,7 @@ from tensorflow.lite.python import convert from tensorflow.lite.python import lite_constants from tensorflow.lite.python import op_hint from tensorflow.lite.python.interpreter import Interpreter +from tensorflow.lite.toco import types_pb2 as _types_pb2 from tensorflow.python.client import session from tensorflow.python.framework import dtypes from tensorflow.python.framework import test_util @@ -329,6 +330,27 @@ class ConvertTestOpHint(test_util.TensorFlowTestCase): output_nodes=[op_hint._tensor_name_base(output.name)]), set(["agg", "Const", "Identity"])) + def testConvertDtype(self): + self.assertEqual( + convert.convert_dtype_to_tflite_type(lite_constants.FLOAT), + _types_pb2.FLOAT) + self.assertEqual( + convert.convert_dtype_to_tflite_type(dtypes.float32), _types_pb2.FLOAT) + self.assertEqual( + convert.convert_dtype_to_tflite_type(dtypes.int32), _types_pb2.INT32) + self.assertEqual( + convert.convert_dtype_to_tflite_type(dtypes.int64), _types_pb2.INT64) + self.assertEqual( + convert.convert_dtype_to_tflite_type(dtypes.string), _types_pb2.STRING) + self.assertEqual( + convert.convert_dtype_to_tflite_type(dtypes.uint8), + _types_pb2.QUANTIZED_UINT8) + self.assertEqual( + convert.convert_dtype_to_tflite_type(dtypes.complex64), + _types_pb2.COMPLEX64) + with self.assertRaises(ValueError): + convert.convert_dtype_to_tflite_type(dtypes.bool) + if __name__ == "__main__": test.main() diff --git a/tensorflow/lite/python/lite.py b/tensorflow/lite/python/lite.py index 5810553da2..1fb5618466 100644 --- a/tensorflow/lite/python/lite.py +++ b/tensorflow/lite/python/lite.py @@ -25,8 +25,6 @@ EXPERIMENTAL: APIs here are unstable and likely to change without notice. @@convert_op_hints_to_stubs @@build_toco_convert_protos -@@FLOAT -@@QUANTIZED_UINT8 @@TFLITE @@GRAPHVIZ_DOT @@ -78,10 +76,10 @@ class TFLiteConverter(object): Attributes: inference_type: Target data type of real-number arrays in the output file. - Must be `{FLOAT, QUANTIZED_UINT8}`. (default FLOAT) + Must be `{tf.float32, tf.uint8}`. (default tf.float32) inference_input_type: Target data type of real-number input arrays. Allows for a different type for input arrays in the case of quantization. - Must be `{FLOAT, QUANTIZED_UINT8}`. (default `inference_type`) + Must be `{tf.float32, tf.uint8}`. (default `inference_type`) output_format: Output file format. Currently must be `{TFLITE, GRAPHVIZ_DOT}`. (default TFLITE) quantized_input_stats: Dict of strings representing input tensor names diff --git a/tensorflow/lite/python/lite_constants.py b/tensorflow/lite/python/lite_constants.py index fdefc5e6cf..f5d6d10379 100644 --- a/tensorflow/lite/python/lite_constants.py +++ b/tensorflow/lite/python/lite_constants.py @@ -19,26 +19,25 @@ from __future__ import division from __future__ import print_function from tensorflow.lite.toco import toco_flags_pb2 as _toco_flags_pb2 -from tensorflow.lite.toco import types_pb2 as _types_pb2 +from tensorflow.python.framework import dtypes from tensorflow.python.util.all_util import remove_undocumented from tensorflow.python.util.tf_export import tf_export as _tf_export -# Enum types from the protobuf promoted to the API -FLOAT = _types_pb2.FLOAT -INT32 = _types_pb2.INT32 -INT64 = _types_pb2.INT64 -STRING = _types_pb2.STRING -QUANTIZED_UINT8 = _types_pb2.QUANTIZED_UINT8 -COMPLEX64 = _types_pb2.COMPLEX64 +FLOAT = dtypes.float32 +INT32 = dtypes.int32 +INT64 = dtypes.int64 +STRING = dtypes.string +QUANTIZED_UINT8 = dtypes.uint8 +COMPLEX64 = dtypes.complex64 TENSORFLOW_GRAPHDEF = _toco_flags_pb2.TENSORFLOW_GRAPHDEF TFLITE = _toco_flags_pb2.TFLITE GRAPHVIZ_DOT = _toco_flags_pb2.GRAPHVIZ_DOT -_tf_export("lite.constants.FLOAT").export_constant(__name__, "FLOAT") -_tf_export("lite.constants.INT32").export_constant(__name__, "INT32") -_tf_export("lite.constants.INT64").export_constant(__name__, "INT64") -_tf_export("lite.constants.STRING").export_constant(__name__, "STRING") -_tf_export("lite.constants.QUANTIZED_UINT8").export_constant( +_tf_export(v1=["lite.constants.FLOAT"]).export_constant(__name__, "FLOAT") +_tf_export(v1=["lite.constants.INT32"]).export_constant(__name__, "INT32") +_tf_export(v1=["lite.constants.INT64"]).export_constant(__name__, "INT64") +_tf_export(v1=["lite.constants.STRING"]).export_constant(__name__, "STRING") +_tf_export(v1=["lite.constants.QUANTIZED_UINT8"]).export_constant( __name__, "QUANTIZED_UINT8") _tf_export("lite.constants.TFLITE").export_constant(__name__, "TFLITE") _tf_export("lite.constants.GRAPHVIZ_DOT").export_constant( diff --git a/tensorflow/lite/python/tflite_convert.py b/tensorflow/lite/python/tflite_convert.py index 00ea6d722e..341b539bea 100644 --- a/tensorflow/lite/python/tflite_convert.py +++ b/tensorflow/lite/python/tflite_convert.py @@ -25,7 +25,6 @@ import sys from tensorflow.lite.python import lite from tensorflow.lite.python import lite_constants from tensorflow.lite.toco import toco_flags_pb2 as _toco_flags_pb2 -from tensorflow.lite.toco import types_pb2 as _types_pb2 from tensorflow.python.platform import app @@ -41,6 +40,27 @@ def _parse_set(values): return None +def _parse_inference_type(value, flag): + """Converts the inference type to the value of the constant. + + Args: + value: str representing the inference type. + flag: str representing the flag name. + + Returns: + tf.dtype. + + Raises: + ValueError: Unsupported value. + """ + if value == "FLOAT": + return lite_constants.FLOAT + if value == "QUANTIZED_UINT8": + return lite_constants.QUANTIZED_UINT8 + raise ValueError("Unsupported value for --{0}. Only FLOAT and " + "QUANTIZED_UINT8 are supported.".format(flag)) + + def _get_toco_converter(flags): """Makes a TFLiteConverter object based on the flags provided. @@ -101,10 +121,11 @@ def _convert_model(flags): # Create converter. converter = _get_toco_converter(flags) if flags.inference_type: - converter.inference_type = _types_pb2.IODataType.Value(flags.inference_type) + converter.inference_type = _parse_inference_type(flags.inference_type, + "inference_type") if flags.inference_input_type: - converter.inference_input_type = _types_pb2.IODataType.Value( - flags.inference_input_type) + converter.inference_input_type = _parse_inference_type( + flags.inference_input_type, "inference_input_type") if flags.output_format: converter.output_format = _toco_flags_pb2.FileFormat.Value( flags.output_format) @@ -115,7 +136,7 @@ def _convert_model(flags): # In quantized inference, mean_value has to be integer so that the real # value 0.0 is exactly representable. - if flags.inference_type == lite_constants.QUANTIZED_UINT8: + if converter.inference_type == lite_constants.QUANTIZED_UINT8: mean_values = _parse_array(flags.mean_values, type_fn=int) else: mean_values = _parse_array(flags.mean_values, type_fn=float) @@ -156,7 +177,7 @@ def _convert_model(flags): if flags.post_training_quantize: converter.post_training_quantize = flags.post_training_quantize - if flags.inference_type == lite_constants.QUANTIZED_UINT8: + if converter.inference_type == lite_constants.QUANTIZED_UINT8: print("--post_training_quantize quantizes a graph of inference_type " "FLOAT. Overriding inference type QUANTIZED_UINT8 to FLOAT.") converter.inference_type = lite_constants.FLOAT diff --git a/tensorflow/tools/api/golden/v1/tensorflow.lite.constants.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.lite.constants.pbtxt index 08845553e5..ef6c777665 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.lite.constants.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.lite.constants.pbtxt @@ -2,7 +2,7 @@ path: "tensorflow.lite.constants" tf_module { member { name: "FLOAT" - mtype: "" + mtype: "" } member { name: "GRAPHVIZ_DOT" @@ -10,19 +10,19 @@ tf_module { } member { name: "INT32" - mtype: "" + mtype: "" } member { name: "INT64" - mtype: "" + mtype: "" } member { name: "QUANTIZED_UINT8" - mtype: "" + mtype: "" } member { name: "STRING" - mtype: "" + mtype: "" } member { name: "TFLITE" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.lite.constants.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.lite.constants.pbtxt index 08845553e5..4d5c4893b4 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.lite.constants.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.lite.constants.pbtxt @@ -1,29 +1,9 @@ path: "tensorflow.lite.constants" tf_module { - member { - name: "FLOAT" - mtype: "" - } member { name: "GRAPHVIZ_DOT" mtype: "" } - member { - name: "INT32" - mtype: "" - } - member { - name: "INT64" - mtype: "" - } - member { - name: "QUANTIZED_UINT8" - mtype: "" - } - member { - name: "STRING" - mtype: "" - } member { name: "TFLITE" mtype: "" -- GitLab From 45573542df95999110be0690175bb82b2ed64ded Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Thu, 29 Nov 2018 14:35:25 -0800 Subject: [PATCH 582/672] [XLA] Add support for iota of PRED PiperOrigin-RevId: 223413074 --- .../xla/service/elemental_ir_emitter.cc | 6 ++++-- tensorflow/compiler/xla/tests/iota_test.cc | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/service/elemental_ir_emitter.cc b/tensorflow/compiler/xla/service/elemental_ir_emitter.cc index 00bb430206..6f1f95f2e9 100644 --- a/tensorflow/compiler/xla/service/elemental_ir_emitter.cc +++ b/tensorflow/compiler/xla/service/elemental_ir_emitter.cc @@ -2245,13 +2245,15 @@ llvm_ir::ElementGenerator ElementalIrEmitter::MakeElementGenerator( : iota->shape(); PrimitiveType component_element_type = component_shape.element_type(); llvm::Value* iota_result; - if (ShapeUtil::ElementIsIntegral(component_shape)) { + if (primitive_util::IsIntegralType(component_element_type) || + component_element_type == PRED) { iota_result = b_->CreateIntCast( elem_index_linear, llvm_ir::PrimitiveTypeToIrType(component_element_type, module_), /*isSigned=*/false); } else { - TF_RET_CHECK(ShapeUtil::ElementIsFloating(component_shape)) + TF_RET_CHECK( + primitive_util::IsFloatingPointType(component_element_type)) << component_element_type; llvm::Type* float_ir_type; if (component_element_type == BF16) { diff --git a/tensorflow/compiler/xla/tests/iota_test.cc b/tensorflow/compiler/xla/tests/iota_test.cc index 310f349592..65205f53dd 100644 --- a/tensorflow/compiler/xla/tests/iota_test.cc +++ b/tensorflow/compiler/xla/tests/iota_test.cc @@ -113,5 +113,26 @@ INSTANTIATE_TEST_CASE_P(IotaR3TestInstantiation, IotaR3Test, /*step=*/10), ::testing::Values(0, 1, 2))); +class IotaR3PredTest : public ClientLibraryTestBase, + public ::testing::WithParamInterface {}; + +TEST_P(IotaR3PredTest, DoIt) { + const auto element_type = PRED; + const int64 num_elements = 2; + const int64 iota_dim = GetParam(); + XlaBuilder builder(TestName() + "_" + PrimitiveType_Name(element_type)); + std::vector dimensions = {42, 19}; + dimensions.insert(dimensions.begin() + iota_dim, num_elements); + Iota(&builder, ShapeUtil::MakeShape(element_type, dimensions), iota_dim); + if (primitive_util::IsFloatingPointType(element_type)) { + ComputeAndCompare(&builder, {}, ErrorSpec{0.0001}); + } else { + ComputeAndCompare(&builder, {}); + } +} + +INSTANTIATE_TEST_CASE_P(IotaR3PredTestInstantiation, IotaR3PredTest, + ::testing::Values(0, 1, 2)); + } // namespace } // namespace xla -- GitLab From 18944dd7210dc2f1a13a34a6946b8a08084cda76 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Thu, 29 Nov 2018 14:45:44 -0800 Subject: [PATCH 583/672] [TF:XLA] Bump open source llvm revision to r347843 PiperOrigin-RevId: 223414920 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 016572a543..dde10ef73d 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -472,11 +472,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "llvm", build_file = clean_dep("//third_party/llvm:llvm.autogenerated.BUILD"), - sha256 = "6c9b98f745b1cf2a9ef34f6220d0f94620ee5c828151924299913f1822cd40d1", - strip_prefix = "llvm-9d5ac66dc1ff01dee56354344c9da0879f1bdc36", + sha256 = "f4791ba3e166918bca82df34e2f854e8e188d6055888c64cb28743fd43f2d0d7", + strip_prefix = "llvm-b2a42b2112a511a5077fd747fb21e45349cff08d", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/9d5ac66dc1ff01dee56354344c9da0879f1bdc36.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/9d5ac66dc1ff01dee56354344c9da0879f1bdc36.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/b2a42b2112a511a5077fd747fb21e45349cff08d.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/b2a42b2112a511a5077fd747fb21e45349cff08d.tar.gz", ], ) -- GitLab From 84f93b879e99b05bf92e610da75e4ed84c2a01ba Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Thu, 29 Nov 2018 15:00:18 -0800 Subject: [PATCH 584/672] [tf.data] Nesting `tf.data.Options()` optimization options under `experimental_optimization`. PiperOrigin-RevId: 223417385 --- .../python/data/experimental/__init__.py | 5 +- .../kernel_tests/optimization/BUILD | 9 ++ .../optimization/filter_fusion_test.py | 4 +- .../optimization/hoist_random_uniform_test.py | 7 +- .../optimization/map_and_batch_fusion_test.py | 4 +- .../map_and_filter_fusion_test.py | 7 +- .../optimization/map_fusion_test.py | 4 +- .../optimization/map_parallelization_test.py | 4 +- .../optimization/map_vectorization_test.py | 4 +- .../optimization/noop_elimination_test.py | 4 +- .../shuffle_and_repeat_fusion_test.py | 4 +- tensorflow/python/data/experimental/ops/BUILD | 10 ++ .../experimental/ops/optimization_options.py | 83 +++++++++++++++++ .../data/experimental/ops/stats_options.py | 2 +- .../experimental/ops/threading_options.py | 2 +- tensorflow/python/data/kernel_tests/BUILD | 1 + .../python/data/kernel_tests/dataset_test.py | 8 +- .../multi_device_iterator_test.py | 4 +- tensorflow/python/data/ops/BUILD | 1 + tensorflow/python/data/ops/dataset_ops.py | 91 ++++++------------- .../golden/v1/tensorflow.data.-options.pbtxt | 34 +------ ...a.experimental.-optimization-options.pbtxt | 46 ++++++++++ .../v1/tensorflow.data.experimental.pbtxt | 4 + .../golden/v2/tensorflow.data.-options.pbtxt | 34 +------ ...a.experimental.-optimization-options.pbtxt | 46 ++++++++++ .../v2/tensorflow.data.experimental.pbtxt | 4 + 26 files changed, 274 insertions(+), 152 deletions(-) create mode 100644 tensorflow/python/data/experimental/ops/optimization_options.py create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.data.experimental.-optimization-options.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-optimization-options.pbtxt diff --git a/tensorflow/python/data/experimental/__init__.py b/tensorflow/python/data/experimental/__init__.py index 8cec75b599..8a1048513a 100644 --- a/tensorflow/python/data/experimental/__init__.py +++ b/tensorflow/python/data/experimental/__init__.py @@ -25,6 +25,7 @@ See [Importing Data](https://tensorflow.org/guide/datasets) for an overview. @@Counter @@CheckpointInputPipelineHook @@CsvDataset +@@OptimizationOptions @@Optional @@RandomDataset @@Reducer @@ -86,10 +87,8 @@ from tensorflow.python.data.experimental.ops.interleave_ops import parallel_inte from tensorflow.python.data.experimental.ops.interleave_ops import sample_from_datasets from tensorflow.python.data.experimental.ops.iterator_ops import CheckpointInputPipelineHook from tensorflow.python.data.experimental.ops.iterator_ops import make_saveable_from_iterator - -# Optimization constant that can be used to enable auto-tuning. from tensorflow.python.data.experimental.ops.optimization import AUTOTUNE - +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.experimental.ops.parsing_ops import parse_example_dataset from tensorflow.python.data.experimental.ops.prefetching_ops import copy_to_device from tensorflow.python.data.experimental.ops.prefetching_ops import prefetch_to_device diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD b/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD index 121798ad3e..e05f382171 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD @@ -42,6 +42,7 @@ py_test( "//tensorflow/python:errors", "//tensorflow/python:math_ops", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", "@absl_py//absl/testing:parameterized", @@ -68,6 +69,7 @@ py_test( "//tensorflow/python:math_ops", "//tensorflow/python:random_ops", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", "@absl_py//absl/testing:parameterized", @@ -127,6 +129,7 @@ py_test( "//tensorflow/python:client_testlib", "//tensorflow/python:errors", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", ], @@ -148,6 +151,7 @@ py_test( "//tensorflow/python:errors", "//tensorflow/python:math_ops", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", "@absl_py//absl/testing:parameterized", @@ -167,6 +171,7 @@ py_test( "//tensorflow/python:client_testlib", "//tensorflow/python:errors", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", "@absl_py//absl/testing:parameterized", @@ -192,6 +197,7 @@ py_test( "//tensorflow/python:math_ops", "//tensorflow/python:random_ops", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", "@absl_py//absl/testing:parameterized", @@ -227,6 +233,7 @@ py_test( "//tensorflow/python:parsing_ops", "//tensorflow/python:sparse_tensor", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", "//third_party/py/numpy", @@ -272,6 +279,7 @@ py_test( "//tensorflow/python:errors", "//tensorflow/python:math_ops", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", ], @@ -313,6 +321,7 @@ py_test( "//tensorflow/python:client_testlib", "//tensorflow/python:errors", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", ], diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/filter_fusion_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/filter_fusion_test.py index fe2c104e94..7371cf31df 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/filter_fusion_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/filter_fusion_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from absl.testing import parameterized from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op @@ -71,7 +72,8 @@ class FilterFusionTest(test_base.DatasetTestBase, parameterized.TestCase): dataset = dataset.cache() options = dataset_ops.Options() - options.experimental_filter_fusion = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.filter_fusion = True dataset = dataset.with_options(options) expected_output = [] for x in range(5): diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/hoist_random_uniform_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/hoist_random_uniform_test.py index e86b19438e..0aacf8bb07 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/hoist_random_uniform_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/hoist_random_uniform_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from absl.testing import parameterized from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.eager import context @@ -91,7 +92,8 @@ class HoistRandomUniformTest(test_base.DatasetTestBase, parameterized.TestCase): ["Zip[0]", "Map"] if will_optimize else ["Map"])).map(function) options = dataset_ops.Options() - options.experimental_hoist_random_uniform = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.hoist_random_uniform = True dataset = dataset.with_options(options) self._testDataset(dataset) @@ -107,7 +109,8 @@ class HoistRandomUniformTest(test_base.DatasetTestBase, parameterized.TestCase): dataset = dataset_ops.Dataset.range(5).apply( optimization.assert_next(["Zip[0]", "Map"])).map(random_with_capture) options = dataset_ops.Options() - options.experimental_hoist_random_uniform = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.hoist_random_uniform = True dataset = dataset.with_options(options) self._testDataset(dataset) diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_batch_fusion_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_batch_fusion_test.py index 67f3ceeabe..801f664f09 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_batch_fusion_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_batch_fusion_test.py @@ -18,6 +18,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import test_util @@ -32,7 +33,8 @@ class MapAndBatchFusionTest(test_base.DatasetTestBase): optimization.assert_next( ["MapAndBatch"])).map(lambda x: x * x).batch(10) options = dataset_ops.Options() - options.experimental_map_and_batch_fusion = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.map_and_batch_fusion = True dataset = dataset.with_options(options) self.assertDatasetProduces( dataset, expected_output=[[x * x for x in range(10)]]) diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_filter_fusion_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_filter_fusion_test.py index a898c38440..db8f214fbf 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_filter_fusion_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_and_filter_fusion_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from absl.testing import parameterized from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op @@ -83,7 +84,8 @@ class MapAndFilterFusionTest(test_base.DatasetTestBase, parameterized.TestCase): optimization.assert_next( ["Map", "FilterByLastComponent"])).map(function).filter(predicate) options = dataset_ops.Options() - options.experimental_map_and_filter_fusion = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.map_and_filter_fusion = True dataset = dataset.with_options(options) self._testMapAndFilter(dataset, function, predicate) @@ -101,7 +103,8 @@ class MapAndFilterFusionTest(test_base.DatasetTestBase, parameterized.TestCase): optimization.assert_next(["Map", "Filter"])).map(function).filter(predicate) options = dataset_ops.Options() - options.experimental_map_and_filter_fusion = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.map_and_filter_fusion = True dataset = dataset.with_options(options) self._testMapAndFilter(dataset, function, predicate) diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_fusion_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_fusion_test.py index 47a1b0896c..d8d6390374 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_fusion_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_fusion_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from absl.testing import parameterized from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import test_util @@ -74,7 +75,8 @@ class MapFusionTest(test_base.DatasetTestBase, parameterized.TestCase): dataset = dataset.cache() options = dataset_ops.Options() - options.experimental_map_fusion = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.map_fusion = True dataset = dataset.with_options(options) expected_output = [] for x in range(5): diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_parallelization_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_parallelization_test.py index 042b9ce54b..0ff3fff4f8 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_parallelization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_parallelization_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from absl.testing import parameterized from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import dtypes @@ -67,7 +68,8 @@ class MapParallelizationTest(test_base.DatasetTestBase, parameterized.TestCase): dataset = dataset_ops.Dataset.range(5).apply( optimization.assert_next(next_nodes)).map(function) options = dataset_ops.Options() - options.experimental_map_parallelization = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.map_parallelization = True dataset = dataset.with_options(options) if should_optimize: self.assertDatasetProduces( diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py index 4f05f02669..d979aaa5a0 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.core.example import example_pb2 from tensorflow.core.example import feature_pb2 from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op @@ -353,7 +354,8 @@ class MapVectorizationTest(test_base.DatasetTestBase, parameterized.TestCase): optimized = _make_dataset(["Batch", map_node_name] if expect_optimized else [map_node_name, "Batch"]) options = dataset_ops.Options() - options.experimental_map_vectorization = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.map_vectorization = True optimized = optimized.with_options(options) return unoptimized, optimized diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/noop_elimination_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/noop_elimination_test.py index d957e8007c..ce86bfa4e0 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/noop_elimination_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/noop_elimination_test.py @@ -18,6 +18,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op @@ -42,7 +43,8 @@ class NoopEliminationTest(test_base.DatasetTestBase): dataset = dataset.repeat(some_tensor).skip(5).take(-1).skip(0).repeat( 1).prefetch(0).prefetch(1).cache() options = dataset_ops.Options() - options.experimental_noop_elimination = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.noop_elimination = True dataset = dataset.with_options(options) self.assertDatasetProduces(dataset, expected_output=range(5)) diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/shuffle_and_repeat_fusion_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/shuffle_and_repeat_fusion_test.py index f1d00a59c4..5f746ec63a 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/shuffle_and_repeat_fusion_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/shuffle_and_repeat_fusion_test.py @@ -18,6 +18,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors @@ -32,7 +33,8 @@ class ShuffleAndRepeatFusionTest(test_base.DatasetTestBase): dataset = dataset_ops.Dataset.range(10).apply( optimization.assert_next(["ShuffleAndRepeat"])).shuffle(10).repeat(2) options = dataset_ops.Options() - options.experimental_shuffle_and_repeat_fusion = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.shuffle_and_repeat_fusion = True dataset = dataset.with_options(options) get_next = self.getNext(dataset) diff --git a/tensorflow/python/data/experimental/ops/BUILD b/tensorflow/python/data/experimental/ops/BUILD index f85e774887..50f5127833 100644 --- a/tensorflow/python/data/experimental/ops/BUILD +++ b/tensorflow/python/data/experimental/ops/BUILD @@ -235,6 +235,16 @@ py_library( ], ) +py_library( + name = "optimization_options", + srcs = ["optimization_options.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:util", + "//tensorflow/python/data/util:options", + ], +) + py_library( name = "parsing_ops", srcs = ["parsing_ops.py"], diff --git a/tensorflow/python/data/experimental/ops/optimization_options.py b/tensorflow/python/data/experimental/ops/optimization_options.py new file mode 100644 index 0000000000..dc9d319374 --- /dev/null +++ b/tensorflow/python/data/experimental/ops/optimization_options.py @@ -0,0 +1,83 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Experimental API for controlling optimizations in `tf.data` pipelines.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +from tensorflow.python.data.util import options +from tensorflow.python.util.tf_export import tf_export + + +@tf_export("data.experimental.OptimizationOptions") +class OptimizationOptions(options.OptionsBase): + """Represents options for dataset optimizations. + + You can apply `OptimizationOptions` to a `dataset` object, as follows: + + ```python + options = tf.data.Options() + options.optimization = tf.data.experimental.OptimizationOptions() + options.optimization.map_and_batch_fusion = True + dataset = dataset.with_options(options) + ``` + """ + + filter_fusion = options.create_option( + name="filter_fusion", + ty=bool, + docstring="Whether to fuse filter transformations.") + + hoist_random_uniform = options.create_option( + name="hoist_random_uniform", + ty=bool, + docstring= + "Whether to hoist `tf.random_uniform()` ops out of map transformations.") + + map_and_batch_fusion = options.create_option( + name="map_and_batch_fusion", + ty=bool, + docstring="Whether to fuse map and batch transformations.") + + map_and_filter_fusion = options.create_option( + name="map_and_filter_fusion", + ty=bool, + docstring="Whether to fuse map and filter transformations.") + + map_fusion = options.create_option( + name="map_and_filter_fusion", + ty=bool, + docstring="Whether to fuse map transformations.") + + map_parallelization = options.create_option( + name="map_parallelization", + ty=bool, + docstring="Whether to parallelize stateless map transformations.") + + map_vectorization = options.create_option( + name="map_vectorization", + ty=bool, + docstring="Whether to vectorize map transformations.") + + noop_elimination = options.create_option( + name="noop_elimination", + ty=bool, + docstring="Whether to eliminate no-op transformations.") + + shuffle_and_repeat_fusion = options.create_option( + name="shuffle_and_repeat_fusion", + ty=bool, + docstring="Whether to fuse shuffle and repeat transformations.") diff --git a/tensorflow/python/data/experimental/ops/stats_options.py b/tensorflow/python/data/experimental/ops/stats_options.py index cd7fdcb723..6df608c608 100644 --- a/tensorflow/python/data/experimental/ops/stats_options.py +++ b/tensorflow/python/data/experimental/ops/stats_options.py @@ -34,7 +34,7 @@ class StatsOptions(options.OptionsBase): ```python aggretator = tf.data.experimental.StatsAggregator() - options = dataset_ops.Options() + options = tf.data.Options() options.experimental_stats = tf.data.experimental.StatsOptions() options.experimental_stats.aggregator = aggregator dataset = dataset.with_options(options) diff --git a/tensorflow/python/data/experimental/ops/threading_options.py b/tensorflow/python/data/experimental/ops/threading_options.py index 98df371c25..dbf662186f 100644 --- a/tensorflow/python/data/experimental/ops/threading_options.py +++ b/tensorflow/python/data/experimental/ops/threading_options.py @@ -29,7 +29,7 @@ class ThreadingOptions(options.OptionsBase): To apply `ThreadingOptions` to a `dataset` object, use the following pattern: ```python - options = dataset_ops.Options() + options = tf.data.Options() options.experimental_threading = tf.data.experimental.ThreadingOptions() options.experimental_threading.private_threadpool_size = 10 dataset = dataset.with_options(options) diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index 0867471d74..9f7ce99cbc 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -408,6 +408,7 @@ cuda_py_test( "//tensorflow/python/data/ops:multi_device_iterator_ops", "//tensorflow/python/data/ops:iterator_ops", "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", diff --git a/tensorflow/python/data/kernel_tests/dataset_test.py b/tensorflow/python/data/kernel_tests/dataset_test.py index 7dbab60f9c..2952c08be0 100644 --- a/tensorflow/python/data/kernel_tests/dataset_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_test.py @@ -227,12 +227,12 @@ class DatasetTest(test_base.DatasetTestBase, parameterized.TestCase): options1 = dataset_ops.Options() options1.experimental_autotune = True options2 = dataset_ops.Options() - options2.experimental_filter_fusion = False + options2.experimental_deterministic = False ds = dataset_ops.Dataset.range(0).with_options(options1).with_options( options2) self.assertTrue(ds.options().experimental_autotune) # Explicitly check that flag is False since assertFalse allows None - self.assertIs(ds.options().experimental_filter_fusion, False) + self.assertIs(ds.options().experimental_deterministic, False) def testOptionsTwiceDifferentError(self): options1 = dataset_ops.Options() @@ -247,12 +247,12 @@ class DatasetTest(test_base.DatasetTestBase, parameterized.TestCase): options1 = dataset_ops.Options() options1.experimental_autotune = True options2 = dataset_ops.Options() - options2.experimental_filter_fusion = True + options2.experimental_deterministic = True ds = dataset_ops.Dataset.zip( (dataset_ops.Dataset.range(0).with_options(options1), dataset_ops.Dataset.range(0).with_options(options2))) self.assertTrue(ds.options().experimental_autotune) - self.assertTrue(ds.options().experimental_filter_fusion) + self.assertTrue(ds.options().experimental_deterministic) # TODO(b/119882922): use-after-free bug in eager mode. # pylint: disable=g-long-lambda diff --git a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py index 886c9acc03..622ebb55de 100644 --- a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py +++ b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.core.protobuf import config_pb2 from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.experimental.ops.optimization_options import OptimizationOptions from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import multi_device_iterator_ops @@ -265,7 +266,8 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): dataset = dataset.cache() options = dataset_ops.Options() - options.experimental_noop_elimination = True + options.experimental_optimization = OptimizationOptions() + options.experimental_optimization.noop_elimination = True dataset = dataset.with_options(options) multi_device_iterator = multi_device_iterator_ops.MultiDeviceIterator( diff --git a/tensorflow/python/data/ops/BUILD b/tensorflow/python/data/ops/BUILD index 27c9175ccb..0c5acda180 100644 --- a/tensorflow/python/data/ops/BUILD +++ b/tensorflow/python/data/ops/BUILD @@ -27,6 +27,7 @@ py_library( "//tensorflow/python:tensor_util", "//tensorflow/python:util", "//tensorflow/python/data/experimental/ops:filter_for_shard_ops", + "//tensorflow/python/data/experimental/ops:optimization_options", "//tensorflow/python/data/experimental/ops:stats_options", "//tensorflow/python/data/experimental/ops:threading_options", "//tensorflow/python/data/util:nest", diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 51123aaf44..c57ddab15f 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -27,6 +27,7 @@ import six from tensorflow.python.compat import compat from tensorflow.python.data.experimental.ops import filter_for_shard_ops +from tensorflow.python.data.experimental.ops import optimization_options from tensorflow.python.data.experimental.ops import stats_options from tensorflow.python.data.experimental.ops import threading_options from tensorflow.python.data.ops import iterator_ops @@ -1587,56 +1588,15 @@ class Options(options_lib.OptionsBase): "Whether to dynamically adjust the values of tunable parameters (e.g. " "degrees of parallelism).") - experimental_filter_fusion = options_lib.create_option( - name="experimental_filter_fusion", - ty=bool, - docstring="Whether to fuse filter transformations.") - - experimental_hoist_random_uniform = options_lib.create_option( - name="experimental_hoist_random_uniform", - ty=bool, - docstring= - "Whether to hoist `tf.random_uniform()` ops out of map transformations.") - - experimental_map_and_batch_fusion = options_lib.create_option( - name="experimental_map_and_batch_fusion", - ty=bool, - docstring="Whether to fuse map and batch transformations.") - - experimental_map_and_filter_fusion = options_lib.create_option( - name="experimental_map_and_filter_fusion", - ty=bool, - docstring="Whether to fuse map and filter transformations.") - - experimental_map_fusion = options_lib.create_option( - name="experimental_map_and_filter_fusion", - ty=bool, - docstring="Whether to fuse map transformations.") - - experimental_map_parallelization = options_lib.create_option( - name="experimental_map_parallelization", - ty=bool, - docstring="Whether to parallelize stateless map transformations.") - - experimental_map_vectorization = options_lib.create_option( - name="experimental_map_vectorization", - ty=bool, - docstring="Whether to vectorize map transformations.") - - experimental_noop_elimination = options_lib.create_option( - name="experimental_noop_elimination", - ty=bool, - docstring="Whether to eliminate no-op transformations.") - experimental_numa_aware = options_lib.create_option( name="experimental_numa_aware", ty=bool, docstring="Whether to use NUMA-aware operations.") - experimental_shuffle_and_repeat_fusion = options_lib.create_option( - name="experimental_shuffle_and_repeat_fusion", - ty=bool, - docstring="Whether to fuse shuffle and repeat transformations.") + experimental_optimization = options_lib.create_option( + name="experimental_optimization", + ty=optimization_options.OptimizationOptions, + docstring="Associates the given optimization options with the dataset.") experimental_stats = options_lib.create_option( name="experimental_stats", @@ -1650,29 +1610,30 @@ class Options(options_lib.OptionsBase): def _static_optimizations(self): """Produces the list of enabled static optimizations.""" - experimental_optimizations = [ - "filter_fusion", - "hoist_random_uniform", - "map_and_batch_fusion", - "map_and_filter_fusion", - "map_fusion", - "map_parallelization", - "map_vectorization", - "noop_elimination", - "shuffle_and_repeat_fusion", - ] - result = [] - for exp_opt in experimental_optimizations: - if getattr(self, "experimental_" + exp_opt): - result.append(exp_opt) - if getattr(self, "experimental_numa_aware"): + result = [] + exp_optimization_options = self.experimental_optimization + if exp_optimization_options: + optimizations = [ + "filter_fusion", + "hoist_random_uniform", + "map_and_batch_fusion", + "map_and_filter_fusion", + "map_fusion", + "map_parallelization", + "map_vectorization", + "noop_elimination", + "shuffle_and_repeat_fusion", + ] + for optimization in optimizations: + if getattr(exp_optimization_options, optimization): + result.append(optimization) + if self.experimental_numa_aware: result.append("make_numa_aware") - if getattr(self, "experimental_deterministic") is False: + if self.experimental_deterministic is False: result.append("make_sloppy") - experimental_stats_options = getattr(self, "experimental_stats") - if experimental_stats_options and getattr(experimental_stats_options, - "latency_all_edges"): + exp_stats_options = self.experimental_stats + if exp_stats_options and exp_stats_options.latency_all_edges: result.append("latency_all_edges") return result diff --git a/tensorflow/tools/api/golden/v1/tensorflow.data.-options.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.data.-options.pbtxt index 024b4514ba..72fc2c3a9e 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.data.-options.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.data.-options.pbtxt @@ -11,44 +11,12 @@ tf_class { name: "experimental_deterministic" mtype: "" } - member { - name: "experimental_filter_fusion" - mtype: "" - } - member { - name: "experimental_hoist_random_uniform" - mtype: "" - } - member { - name: "experimental_map_and_batch_fusion" - mtype: "" - } - member { - name: "experimental_map_and_filter_fusion" - mtype: "" - } - member { - name: "experimental_map_fusion" - mtype: "" - } - member { - name: "experimental_map_parallelization" - mtype: "" - } - member { - name: "experimental_map_vectorization" - mtype: "" - } - member { - name: "experimental_noop_elimination" - mtype: "" - } member { name: "experimental_numa_aware" mtype: "" } member { - name: "experimental_shuffle_and_repeat_fusion" + name: "experimental_optimization" mtype: "" } member { diff --git a/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.-optimization-options.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.-optimization-options.pbtxt new file mode 100644 index 0000000000..9ca75828e5 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.-optimization-options.pbtxt @@ -0,0 +1,46 @@ +path: "tensorflow.data.experimental.OptimizationOptions" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "filter_fusion" + mtype: "" + } + member { + name: "hoist_random_uniform" + mtype: "" + } + member { + name: "map_and_batch_fusion" + mtype: "" + } + member { + name: "map_and_filter_fusion" + mtype: "" + } + member { + name: "map_fusion" + mtype: "" + } + member { + name: "map_parallelization" + mtype: "" + } + member { + name: "map_vectorization" + mtype: "" + } + member { + name: "noop_elimination" + mtype: "" + } + member { + name: "shuffle_and_repeat_fusion" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt index a3cb799fc3..ad10b82283 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt @@ -12,6 +12,10 @@ tf_module { name: "CsvDataset" mtype: "" } + member { + name: "OptimizationOptions" + mtype: "" + } member { name: "Optional" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.-options.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.-options.pbtxt index 024b4514ba..72fc2c3a9e 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.-options.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.-options.pbtxt @@ -11,44 +11,12 @@ tf_class { name: "experimental_deterministic" mtype: "" } - member { - name: "experimental_filter_fusion" - mtype: "" - } - member { - name: "experimental_hoist_random_uniform" - mtype: "" - } - member { - name: "experimental_map_and_batch_fusion" - mtype: "" - } - member { - name: "experimental_map_and_filter_fusion" - mtype: "" - } - member { - name: "experimental_map_fusion" - mtype: "" - } - member { - name: "experimental_map_parallelization" - mtype: "" - } - member { - name: "experimental_map_vectorization" - mtype: "" - } - member { - name: "experimental_noop_elimination" - mtype: "" - } member { name: "experimental_numa_aware" mtype: "" } member { - name: "experimental_shuffle_and_repeat_fusion" + name: "experimental_optimization" mtype: "" } member { diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-optimization-options.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-optimization-options.pbtxt new file mode 100644 index 0000000000..9ca75828e5 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-optimization-options.pbtxt @@ -0,0 +1,46 @@ +path: "tensorflow.data.experimental.OptimizationOptions" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "filter_fusion" + mtype: "" + } + member { + name: "hoist_random_uniform" + mtype: "" + } + member { + name: "map_and_batch_fusion" + mtype: "" + } + member { + name: "map_and_filter_fusion" + mtype: "" + } + member { + name: "map_fusion" + mtype: "" + } + member { + name: "map_parallelization" + mtype: "" + } + member { + name: "map_vectorization" + mtype: "" + } + member { + name: "noop_elimination" + mtype: "" + } + member { + name: "shuffle_and_repeat_fusion" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt index a3cb799fc3..ad10b82283 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt @@ -12,6 +12,10 @@ tf_module { name: "CsvDataset" mtype: "" } + member { + name: "OptimizationOptions" + mtype: "" + } member { name: "Optional" mtype: "" -- GitLab From 1223dd41a235c2f3a7debd1a08f0332fe6b2aed2 Mon Sep 17 00:00:00 2001 From: Martin Wicke Date: Thu, 29 Nov 2018 15:03:50 -0800 Subject: [PATCH 585/672] Visibility changes. PiperOrigin-RevId: 223418219 --- tensorflow/contrib/framework/BUILD | 5 +++++ tensorflow/contrib/layers/BUILD | 5 +++++ tensorflow/contrib/learn/BUILD | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/tensorflow/contrib/framework/BUILD b/tensorflow/contrib/framework/BUILD index 53efae1e10..dad50a3a73 100644 --- a/tensorflow/contrib/framework/BUILD +++ b/tensorflow/contrib/framework/BUILD @@ -47,6 +47,11 @@ tf_custom_op_py_library( ":variable_ops_op_lib", ], srcs_version = "PY2AND3", + visibility = [ + "//learning/brain:__subpackages__", + "//tensorflow:__subpackages__", + "//video/youtube/personalization:__subpackages__", + ], deps = [ ":gen_variable_ops", "//tensorflow/contrib/util:util_py", diff --git a/tensorflow/contrib/layers/BUILD b/tensorflow/contrib/layers/BUILD index 795591ea62..9ca6f8df5d 100644 --- a/tensorflow/contrib/layers/BUILD +++ b/tensorflow/contrib/layers/BUILD @@ -78,6 +78,11 @@ tf_custom_op_py_library( ":sparse_feature_cross_op_op_lib", ], srcs_version = "PY2AND3", + visibility = [ + "//learning/brain:__subpackages__", + "//tensorflow:__subpackages__", + "//video/youtube/personalization:__subpackages__", + ], deps = [ ":sparse_feature_cross_op", "//tensorflow/contrib/framework:framework_py", diff --git a/tensorflow/contrib/learn/BUILD b/tensorflow/contrib/learn/BUILD index 61185f65a9..238504f6d6 100644 --- a/tensorflow/contrib/learn/BUILD +++ b/tensorflow/contrib/learn/BUILD @@ -24,6 +24,11 @@ py_library( exclude = ["python/learn/**/*_test.py"], ), srcs_version = "PY2AND3", + visibility = [ + "//learning/brain:__subpackages__", + "//tensorflow:__subpackages__", + "//video/youtube/personalization:__subpackages__", + ], # This library should not depend on sklearn, even though some of the code # refers to it. (The code handles the presence of sklearn conditionally.) deps = [ -- GitLab From ee5f4ebbf4b93283372ba708925318a2a8ce83a5 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 15:23:05 -0800 Subject: [PATCH 586/672] Allow delegates to allocate memory while copying them from their buffers. PiperOrigin-RevId: 223421612 --- tensorflow/lite/c/c_api_internal.c | 11 +++++++++ tensorflow/lite/c/c_api_internal.h | 11 ++++++--- tensorflow/lite/core/subgraph.h | 5 ++-- tensorflow/lite/delegates/flex/delegate.cc | 23 +++++++++---------- tensorflow/lite/delegates/flex/kernel_test.cc | 4 ++-- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/tensorflow/lite/c/c_api_internal.c b/tensorflow/lite/c/c_api_internal.c index 7f67b1c272..598d74be84 100644 --- a/tensorflow/lite/c/c_api_internal.c +++ b/tensorflow/lite/c/c_api_internal.c @@ -139,3 +139,14 @@ const char* TfLiteTypeGetName(TfLiteType type) { return "Unknown type"; } +TfLiteDelegate TfLiteDelegateCreate() { + TfLiteDelegate d = { + .data_ = NULL, + .Prepare = NULL, + .CopyFromBufferHandle = NULL, + .CopyToBufferHandle = NULL, + .FreeBufferHandle = NULL, + .flags = kTfLiteDelegateFlagsNone, + }; + return d; +} diff --git a/tensorflow/lite/c/c_api_internal.h b/tensorflow/lite/c/c_api_internal.h index d7bf06442b..6280bf825d 100644 --- a/tensorflow/lite/c/c_api_internal.h +++ b/tensorflow/lite/c/c_api_internal.h @@ -488,12 +488,13 @@ typedef struct _TfLiteDelegate { // delegated subgraphs of the original graph. TfLiteStatus (*Prepare)(TfLiteContext* context, TfLiteDelegate* delegate); - // Copy the data from delegate buffer handle to raw memory. - // This can be null if the delegate doesn't use its own buffer. + // Copy the data from delegate buffer handle into raw memory of the given + // 'tensor'. This cannot be null. The delegate is allowed to allocate the raw + // bytes as long as it follows the rules for kTfLiteDynamic tensors. TfLiteStatus (*CopyFromBufferHandle)(TfLiteContext* context, TfLiteDelegate* delegate, TfLiteBufferHandle buffer_handle, - void* data, size_t size); + TfLiteTensor* tensor); // Copy the data from raw memory to delegate buffer handle. // This can be null if the delegate doesn't use its own buffer. @@ -513,6 +514,10 @@ typedef struct _TfLiteDelegate { int64_t flags; } TfLiteDelegate; +// Build a 'null' delegate, with all the fields properly set to their default +// values. +TfLiteDelegate TfLiteDelegateCreate(); + // WARNING: This is an experimental interface that is subject to change. // // Currently, TfLiteDelegateParams has to be allocated in a way that it's diff --git a/tensorflow/lite/core/subgraph.h b/tensorflow/lite/core/subgraph.h index e85d6df974..6b44a4731c 100644 --- a/tensorflow/lite/core/subgraph.h +++ b/tensorflow/lite/core/subgraph.h @@ -216,10 +216,9 @@ class Subgraph { if (t->data_is_stale) { TF_LITE_ENSURE(context_, t->delegate != nullptr); TF_LITE_ENSURE(context_, t->buffer_handle != kTfLiteNullBufferHandle); - // This can be null if the delegate doesn't use its own buffer. TF_LITE_ENSURE(context_, t->delegate->CopyFromBufferHandle != nullptr); - t->delegate->CopyFromBufferHandle(context_, t->delegate, t->buffer_handle, - t->data.raw, t->bytes); + TF_LITE_ENSURE(context_, t->delegate->CopyFromBufferHandle( + context_, t->delegate, t->buffer_handle, t)); t->data_is_stale = false; } return kTfLiteOk; diff --git a/tensorflow/lite/delegates/flex/delegate.cc b/tensorflow/lite/delegates/flex/delegate.cc index 4fc2d82b49..12dcaa11d3 100644 --- a/tensorflow/lite/delegates/flex/delegate.cc +++ b/tensorflow/lite/delegates/flex/delegate.cc @@ -57,8 +57,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteDelegate* delegate) { TfLiteStatus CopyFromBufferHandle(TfLiteContext* context, TfLiteDelegate* delegate, - TfLiteBufferHandle buffer_handle, void* data, - size_t size) { + TfLiteBufferHandle buffer_handle, + TfLiteTensor* output) { BufferMap* buffer_map = reinterpret_cast(delegate->data_)->GetBufferMap(context); @@ -70,13 +70,13 @@ TfLiteStatus CopyFromBufferHandle(TfLiteContext* context, tensorflow::Tensor t = buffer_map->GetTensor(buffer_handle); tensorflow::StringPiece t_data = t.tensor_data(); - if (size != t_data.size()) { + if (output->bytes != t_data.size()) { context->ReportError( context, "Not enough space to store TensorFlow's aligned buffer."); return kTfLiteError; } - memcpy(data, t_data.data(), t_data.size()); + memcpy(output->data.raw, t_data.data(), t_data.size()); return kTfLiteOk; } @@ -104,14 +104,13 @@ std::unique_ptr FlexDelegate::Create() { } FlexDelegate::FlexDelegate(std::unique_ptr delegate_data) - : TfLiteDelegate{ - /*data_=*/delegate_data.get(), - /*nullptr,*/ &flex::delegate::Prepare, - /*CopyFromBufferHandle=*/&flex::delegate::CopyFromBufferHandle, - /*CopyToBufferHandle=*/nullptr, - /*FreeBufferHandle=*/nullptr, - /*flags=*/kTfLiteDelegateFlagsAllowDynamicTensors}, - delegate_data_(std::move(delegate_data)) {} + : TfLiteDelegate(TfLiteDelegateCreate()), + delegate_data_(std::move(delegate_data)) { + data_ = delegate_data_.get(); + Prepare = &flex::delegate::Prepare; + CopyFromBufferHandle = &flex::delegate::CopyFromBufferHandle; + flags = kTfLiteDelegateFlagsAllowDynamicTensors; +} FlexDelegate::~FlexDelegate() {} diff --git a/tensorflow/lite/delegates/flex/kernel_test.cc b/tensorflow/lite/delegates/flex/kernel_test.cc index f55759594d..efb7300b0b 100644 --- a/tensorflow/lite/delegates/flex/kernel_test.cc +++ b/tensorflow/lite/delegates/flex/kernel_test.cc @@ -59,12 +59,12 @@ class KernelTest : public testing::FlexModelTest { delegate_.CopyFromBufferHandle = [](TfLiteContext* context, TfLiteDelegate* delegate, TfLiteBufferHandle buffer_handle, - void* data, size_t size) { + TfLiteTensor* output) { auto* delegate_data = reinterpret_cast(delegate->data_); tensorflow::StringPiece values = delegate_data->GetBufferMap(context) ->GetTensor(buffer_handle) .tensor_data(); - memcpy(data, values.data(), values.size()); + memcpy(output->data.raw, values.data(), values.size()); return kTfLiteOk; }; CHECK(interpreter_->ModifyGraphWithDelegate(&delegate_) == kTfLiteOk); -- GitLab From 3a9b2ae05da54b65759a3656db918706115a50dc Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Thu, 29 Nov 2018 15:26:27 -0800 Subject: [PATCH 587/672] Add V2 APIs for losses: `MeanAbsoluteError`, `MeanAbsolutePercentageError`, `MeanSquaredLogarithmicError` PiperOrigin-RevId: 223422208 --- tensorflow/python/keras/losses.py | 21 ++++++++++-------- ...ow.keras.losses.-mean-absolute-error.pbtxt | 22 +++++++++++++++++++ ...sses.-mean-absolute-percentage-error.pbtxt | 22 +++++++++++++++++++ ...ses.-mean-squared-logarithmic-error.pbtxt} | 4 ++-- .../golden/v1/tensorflow.keras.losses.pbtxt | 12 ++++++++++ .../api/golden/v1/tensorflow.losses.pbtxt | 4 ---- ...ow.keras.losses.-mean-absolute-error.pbtxt | 22 +++++++++++++++++++ ...sses.-mean-absolute-percentage-error.pbtxt | 22 +++++++++++++++++++ ...ses.-mean-squared-logarithmic-error.pbtxt} | 4 ++-- .../golden/v2/tensorflow.keras.losses.pbtxt | 12 ++++++++++ .../api/golden/v2/tensorflow.losses.pbtxt | 4 ---- 11 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-error.pbtxt create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt rename tensorflow/tools/api/golden/v1/{tensorflow.losses.-mean-squared-error.pbtxt => tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt} (89%) create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-error.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt rename tensorflow/tools/api/golden/v2/{tensorflow.losses.-mean-squared-error.pbtxt => tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt} (89%) diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index 6b8d560102..f6953f8499 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -116,7 +116,7 @@ class Loss(object): NotImplementedError('Must be implemented in subclasses.') -@tf_export('losses.MeanSquaredError', 'keras.losses.MeanSquaredError') +@tf_export('keras.losses.MeanSquaredError') class MeanSquaredError(Loss): """Computes the mean of squares of errors between labels and predictions. @@ -126,7 +126,7 @@ class MeanSquaredError(Loss): Usage: ```python - mse = tf.losses.MeanSquaredError() + mse = tf.keras.losses.MeanSquaredError() loss = mse([0., 0., 1., 1.], [1., 1., 1., 0.]) print('Loss: ', loss.numpy()) # Loss: 0.75 ``` @@ -135,7 +135,7 @@ class MeanSquaredError(Loss): ```python model = keras.models.Model(inputs, outputs) - model.compile('sgd', loss=tf.losses.MeanSquaredError()) + model.compile('sgd', loss=tf.keras.losses.MeanSquaredError()) ``` """ @@ -154,6 +154,7 @@ class MeanSquaredError(Loss): return mean_squared_error(y_true, y_pred) +@tf_export('keras.losses.MeanAbsoluteError') class MeanAbsoluteError(Loss): """Computes the mean of absolute difference between labels and predictions. @@ -163,7 +164,7 @@ class MeanAbsoluteError(Loss): Usage: ```python - mae = tf.losses.MeanAbsoluteError() + mae = tf.keras.losses.MeanAbsoluteError() loss = mae([0., 0., 1., 1.], [1., 1., 1., 0.]) print('Loss: ', loss.numpy()) # Loss: 0.75 ``` @@ -172,7 +173,7 @@ class MeanAbsoluteError(Loss): ```python model = keras.models.Model(inputs, outputs) - model.compile('sgd', loss=tf.losses.MeanAbsoluteError()) + model.compile('sgd', loss=tf.keras.losses.MeanAbsoluteError()) ``` """ @@ -191,6 +192,7 @@ class MeanAbsoluteError(Loss): return mean_absolute_error(y_true, y_pred) +@tf_export('keras.losses.MeanAbsolutePercentageError') class MeanAbsolutePercentageError(Loss): """Computes the mean absolute percentage error between `y_true` and `y_pred`. @@ -200,7 +202,7 @@ class MeanAbsolutePercentageError(Loss): Usage: ```python - mape = tf.losses.MeanAbsolutePercentageError() + mape = tf.keras.losses.MeanAbsolutePercentageError() loss = mape([0., 0., 1., 1.], [1., 1., 1., 0.]) print('Loss: ', loss.numpy()) # Loss: 5e+08 ``` @@ -209,7 +211,7 @@ class MeanAbsolutePercentageError(Loss): ```python model = keras.models.Model(inputs, outputs) - model.compile('sgd', loss=tf.losses.MeanAbsolutePercentageError()) + model.compile('sgd', loss=tf.keras.losses.MeanAbsolutePercentageError()) ``` """ @@ -228,6 +230,7 @@ class MeanAbsolutePercentageError(Loss): return mean_absolute_percentage_error(y_true, y_pred) +@tf_export('keras.losses.MeanSquaredLogarithmicError') class MeanSquaredLogarithmicError(Loss): """Computes the mean squared logarithmic error between `y_true` and `y_pred`. @@ -237,7 +240,7 @@ class MeanSquaredLogarithmicError(Loss): Usage: ```python - msle = tf.losses.MeanSquaredLogarithmicError() + msle = tf.keras.losses.MeanSquaredLogarithmicError() loss = msle([0., 0., 1., 1.], [1., 1., 1., 0.]) print('Loss: ', loss.numpy()) # Loss: 0.36034 ``` @@ -246,7 +249,7 @@ class MeanSquaredLogarithmicError(Loss): ```python model = keras.models.Model(inputs, outputs) - model.compile('sgd', loss=tf.losses.MeanSquaredLogarithmicError()) + model.compile('sgd', loss=tf.keras.losses.MeanSquaredLogarithmicError()) ``` """ diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-error.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-error.pbtxt new file mode 100644 index 0000000000..712bb2ecd3 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.keras.losses.MeanAbsoluteError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt new file mode 100644 index 0000000000..7fe362da89 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.keras.losses.MeanAbsolutePercentageError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt similarity index 89% rename from tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt rename to tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt index a626d9c7e6..200006db35 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt @@ -1,6 +1,6 @@ -path: "tensorflow.losses.MeanSquaredError" +path: "tensorflow.keras.losses.MeanSquaredLogarithmicError" tf_class { - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" member_method { diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt index a0af6a29f0..c6638bd5e0 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt @@ -1,9 +1,21 @@ path: "tensorflow.keras.losses" tf_module { + member { + name: "MeanAbsoluteError" + mtype: "" + } + member { + name: "MeanAbsolutePercentageError" + mtype: "" + } member { name: "MeanSquaredError" mtype: "" } + member { + name: "MeanSquaredLogarithmicError" + mtype: "" + } member_method { name: "KLD" argspec: "args=[\'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt index a198db1b35..c1d190ae11 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt @@ -1,9 +1,5 @@ path: "tensorflow.losses" tf_module { - member { - name: "MeanSquaredError" - mtype: "" - } member { name: "Reduction" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-error.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-error.pbtxt new file mode 100644 index 0000000000..712bb2ecd3 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.keras.losses.MeanAbsoluteError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt new file mode 100644 index 0000000000..7fe362da89 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-absolute-percentage-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.keras.losses.MeanAbsolutePercentageError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt similarity index 89% rename from tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt rename to tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt index a626d9c7e6..200006db35 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-logarithmic-error.pbtxt @@ -1,6 +1,6 @@ -path: "tensorflow.losses.MeanSquaredError" +path: "tensorflow.keras.losses.MeanSquaredLogarithmicError" tf_class { - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" member_method { diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt index cb156e2248..5204a29a82 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt @@ -1,9 +1,21 @@ path: "tensorflow.keras.losses" tf_module { + member { + name: "MeanAbsoluteError" + mtype: "" + } + member { + name: "MeanAbsolutePercentageError" + mtype: "" + } member { name: "MeanSquaredError" mtype: "" } + member { + name: "MeanSquaredLogarithmicError" + mtype: "" + } member { name: "Reduction" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt index 87f5ef3491..233b1a0131 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt @@ -1,9 +1,5 @@ path: "tensorflow.losses" tf_module { - member { - name: "MeanSquaredError" - mtype: "" - } member { name: "Reduction" mtype: "" -- GitLab From bbad7c0a070b25b37a5522217982e53e8c60c95c Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Thu, 29 Nov 2018 15:28:37 -0800 Subject: [PATCH 588/672] Fix keras_multi_worker test failure. PiperOrigin-RevId: 223422542 --- tensorflow/python/keras/engine/distributed_training_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index cd8e0342cd..c587287ff9 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -328,7 +328,7 @@ def init_restore_or_wait_for_variables(): """Initialize or restore variables or wait for variables to be initialized.""" session = K._get_session() # pylint: disable=protected-access worker_context = dc_context.get_current_worker_context() - if not worker_context or worker_context.should_init: + if not worker_context or worker_context.experimental_should_init: # TODO(yuefengz): if checkpoints exit, restore from checkpoint. K._initialize_variables(session) # pylint: disable=protected-access else: -- GitLab From 24f578cd66bfc3ec35017fc77e136e43c4b74742 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Thu, 29 Nov 2018 15:30:12 -0800 Subject: [PATCH 589/672] Add @run_deprecated_v1 annotation to tests failing in v2 PiperOrigin-RevId: 223422907 --- tensorflow/examples/adding_an_op/fact_test.py | 2 + .../examples/adding_an_op/zero_out_1_test.py | 2 + .../examples/adding_an_op/zero_out_2_test.py | 5 + .../examples/adding_an_op/zero_out_3_test.py | 5 + .../autograph/integration_tests/keras_test.py | 2 + .../examples/speech_commands/freeze_test.py | 4 + .../speech_commands/input_data_test.py | 9 + .../examples/speech_commands/models_test.py | 6 + .../speech_commands/wav_to_features_test.py | 2 + .../autograph/converters/asserts_test.py | 2 + .../converters/builtin_functions_test.py | 4 + .../autograph/converters/control_flow_test.py | 13 + .../converters/function_scopes_test.py | 5 + .../converters/logical_expressions_test.py | 4 + .../converters/side_effect_guards_test.py | 3 + .../python/autograph/core/errors_test.py | 4 + .../autograph/core/function_wrapping_test.py | 2 + tensorflow/python/autograph/impl/api_test.py | 10 + .../autograph/operators/control_flow_test.py | 6 + .../operators/data_structures_test.py | 4 + .../autograph/operators/exceptions_test.py | 3 + .../autograph/operators/logical_test.py | 3 + .../autograph/operators/py_builtins_test.py | 4 + .../python/autograph/utils/misc_test.py | 3 + .../autograph/utils/tensor_list_test.py | 3 + .../python/autograph/utils/type_check_test.py | 1 + .../python/client/session_partial_run_test.py | 24 ++ tensorflow/python/client/timeline_test.py | 1 + .../kernel_tests/copy_to_device_test.py | 10 + .../experimental/kernel_tests/counter_test.py | 2 + .../dense_to_sparse_batch_test.py | 5 + .../directed_interleave_dataset_test.py | 4 + .../kernel_tests/enumerate_dataset_test.py | 2 + .../function_buffering_resource_test.py | 4 + .../kernel_tests/get_single_element_test.py | 2 + .../kernel_tests/group_by_reducer_test.py | 6 + .../kernel_tests/group_by_window_test.py | 11 + .../kernel_tests/ignore_errors_test.py | 4 + .../kernel_tests/indexed_dataset_ops_test.py | 3 + .../make_batched_features_dataset_test.py | 2 + .../kernel_tests/make_csv_dataset_test.py | 9 + .../kernel_tests/map_and_batch_test.py | 13 + .../kernel_tests/matching_files_test.py | 7 + .../kernel_tests/override_threadpool_test.py | 3 + .../parse_example_dataset_test.py | 4 + .../kernel_tests/prefetch_to_device_test.py | 5 + .../kernel_tests/rejection_resample_test.py | 4 + .../kernel_tests/restructured_dataset_test.py | 2 + .../experimental/kernel_tests/scan_test.py | 3 + .../checkpoint_input_pipeline_hook_test.py | 4 + .../kernel_tests/shuffle_and_repeat_test.py | 7 + .../experimental/kernel_tests/sleep_test.py | 2 + .../kernel_tests/stats_dataset_ops_test.py | 17 ++ .../experimental/kernel_tests/unbatch_test.py | 10 + .../experimental/kernel_tests/unique_test.py | 3 + .../python/data/kernel_tests/flat_map_test.py | 1 + .../data/kernel_tests/from_generator_test.py | 17 ++ .../from_sparse_tensor_slices_test.py | 1 + .../data/kernel_tests/from_tensors_test.py | 1 + .../python/data/kernel_tests/iterator_test.py | 17 ++ .../data/kernel_tests/list_files_test.py | 1 + .../python/data/kernel_tests/optional_test.py | 3 + .../data/kernel_tests/padded_batch_test.py | 3 + .../python/data/kernel_tests/reduce_test.py | 1 + .../python/data/kernel_tests/shuffle_test.py | 1 + tensorflow/python/data/util/convert_test.py | 2 + tensorflow/python/data/util/sparse_test.py | 3 + tensorflow/python/data/util/structure_test.py | 2 + .../python/debug/cli/analyzer_cli_test.py | 33 +++ .../python/debug/cli/cli_shared_test.py | 11 + .../debug/cli/profile_analyzer_cli_test.py | 5 + tensorflow/python/debug/lib/common_test.py | 3 + .../python/debug/lib/debug_gradients_test.py | 14 ++ .../python/debug/lib/debug_utils_test.py | 10 + .../debug/lib/session_debug_file_test.py | 2 + .../python/debug/lib/source_utils_test.py | 1 + .../python/distribute/all_reduce_test.py | 5 + .../python/distribute/device_util_test.py | 3 + .../python/distribute/input_ops_test.py | 12 + .../python/eager/function_gradients_test.py | 1 + tensorflow/python/eager/function_test.py | 1 + .../python/eager/graph_only_ops_test.py | 2 + .../feature_column/feature_column_test.py | 130 ++++++++++ .../feature_column/feature_column_v2_test.py | 141 +++++++++++ .../python/framework/file_system_test.py | 2 + .../framework/function_def_to_graph_test.py | 3 + tensorflow/python/framework/function_test.py | 26 ++ .../python/framework/graph_util_test.py | 2 + .../python/framework/meta_graph_test.py | 17 ++ tensorflow/python/framework/ops_test.py | 57 +++++ .../python/framework/smart_cond_test.py | 5 + .../python/framework/sparse_tensor_test.py | 2 + tensorflow/python/framework/subscribe_test.py | 10 + .../python/framework/tensor_spec_test.py | 4 + .../python/framework/tensor_util_test.py | 12 + tensorflow/python/framework/test_util_test.py | 5 + .../python/grappler/cost_analyzer_test.py | 4 + tensorflow/python/grappler/item_test.py | 2 + .../python/grappler/layout_optimizer_test.py | 3 + .../python/grappler/memory_optimizer_test.py | 3 + .../python/grappler/model_analyzer_test.py | 3 + .../python/grappler/tf_optimizer_test.py | 4 + tensorflow/python/keras/activations_test.py | 4 + tensorflow/python/keras/backend_test.py | 8 + tensorflow/python/keras/callbacks_test.py | 10 + tensorflow/python/keras/engine/saving_test.py | 8 + .../python/keras/engine/sequential_test.py | 2 + .../python/keras/engine/topology_test.py | 10 + .../keras/engine/training_dataset_test.py | 1 + .../python/keras/engine/training_test.py | 10 + tensorflow/python/keras/initializers_test.py | 11 + tensorflow/python/keras/integration_test.py | 8 + tensorflow/python/keras/layers/local_test.py | 4 + tensorflow/python/keras/layers/lstm_test.py | 4 + tensorflow/python/keras/layers/merge_test.py | 1 + .../python/keras/layers/normalization_test.py | 1 + .../python/keras/layers/simplernn_test.py | 3 + .../python/keras/layers/unified_rnn_test.py | 2 + .../python/keras/layers/wrappers_test.py | 4 + .../python/keras/model_subclassing_test.py | 4 + tensorflow/python/keras/models_test.py | 10 + .../keras/optimizer_v2/adadelta_test.py | 1 + .../python/keras/optimizer_v2/adagrad_test.py | 7 + .../python/keras/optimizer_v2/adam_test.py | 6 + .../python/keras/optimizer_v2/adamax_test.py | 5 + .../python/keras/optimizer_v2/ftrl_test.py | 14 ++ .../optimizer_v2/gradient_descent_test.py | 9 + .../python/keras/optimizer_v2/nadam_test.py | 5 + .../python/keras/optimizer_v2/rmsprop_test.py | 5 + tensorflow/python/keras/optimizers_test.py | 9 + tensorflow/python/keras/regularizers_test.py | 2 + .../python/kernel_tests/accumulate_n_test.py | 4 + .../python/kernel_tests/ackermann_test.py | 2 + .../python/kernel_tests/aggregate_ops_test.py | 3 + .../python/kernel_tests/argmax_op_test.py | 3 + .../python/kernel_tests/array_ops_test.py | 52 ++++ .../python/kernel_tests/as_string_op_test.py | 7 + .../python/kernel_tests/atrous_conv2d_test.py | 6 + .../python/kernel_tests/barrier_ops_test.py | 18 ++ .../python/kernel_tests/basic_gpu_test.py | 3 + .../kernel_tests/batch_gather_op_test.py | 4 + .../kernel_tests/batch_scatter_ops_test.py | 4 + .../kernel_tests/batchtospace_op_test.py | 21 ++ .../python/kernel_tests/bcast_ops_test.py | 6 + .../python/kernel_tests/betainc_op_test.py | 8 + .../python/kernel_tests/bias_op_test.py | 12 + .../python/kernel_tests/bincount_op_test.py | 7 + .../python/kernel_tests/bitcast_op_test.py | 2 + .../boosted_trees/prediction_ops_test.py | 15 ++ .../boosted_trees/quantile_ops_test.py | 4 + .../boosted_trees/resource_ops_test.py | 3 + .../boosted_trees/stats_ops_test.py | 1 + .../boosted_trees/training_ops_test.py | 10 + .../kernel_tests/broadcast_to_ops_test.py | 11 + .../python/kernel_tests/bucketize_op_test.py | 2 + .../candidate_sampler_ops_test.py | 3 + .../python/kernel_tests/cast_op_test.py | 9 + .../python/kernel_tests/check_ops_test.py | 45 ++++ .../kernel_tests/checkpoint_ops_test.py | 10 + .../python/kernel_tests/cholesky_op_test.py | 9 + .../python/kernel_tests/clip_ops_test.py | 10 + .../python/kernel_tests/concat_op_test.py | 26 ++ .../python/kernel_tests/cond_v2_test.py | 8 + .../conditional_accumulator_test.py | 24 ++ .../kernel_tests/confusion_matrix_test.py | 23 ++ .../python/kernel_tests/constant_op_test.py | 40 ++++ .../kernel_tests/control_flow_ops_py_test.py | 55 +++++ .../conv2d_backprop_filter_grad_test.py | 2 + .../kernel_tests/conv2d_transpose_test.py | 2 + .../conv3d_backprop_filter_v2_grad_test.py | 2 + .../kernel_tests/conv3d_transpose_test.py | 3 + .../python/kernel_tests/conv_ops_3d_test.py | 17 ++ .../python/kernel_tests/cross_grad_test.py | 2 + .../kernel_tests/ctc_decoder_ops_test.py | 3 + .../python/kernel_tests/ctc_loss_op_test.py | 23 ++ .../kernel_tests/cwise_ops_binary_test.py | 73 ++++++ .../python/kernel_tests/cwise_ops_test.py | 15 ++ .../kernel_tests/cwise_ops_unary_test.py | 8 + .../kernel_tests/decode_compressed_op_test.py | 3 + .../kernel_tests/decode_image_op_test.py | 4 + .../python/kernel_tests/decode_raw_op_test.py | 7 + .../python/kernel_tests/denormal_test.py | 3 + .../dense_update_ops_no_tsan_test.py | 5 + .../kernel_tests/dense_update_ops_test.py | 5 + .../kernel_tests/depthtospace_op_test.py | 17 ++ .../python/kernel_tests/diag_op_test.py | 26 ++ .../distributions/bernoulli_test.py | 5 + .../distributions/bijector_test.py | 2 + .../distributions/categorical_test.py | 17 ++ .../dirichlet_multinomial_test.py | 13 + .../distributions/identity_bijector_test.py | 2 + .../distributions/kullback_leibler_test.py | 2 + .../kernel_tests/distributions/normal_test.py | 1 + .../distributions/special_math_test.py | 9 + .../kernel_tests/distributions/util_test.py | 48 ++++ .../python/kernel_tests/duplicate_op_test.py | 2 + .../kernel_tests/dynamic_partition_op_test.py | 8 + .../kernel_tests/dynamic_stitch_op_test.py | 8 + .../python/kernel_tests/embedding_ops_test.py | 44 ++++ .../extract_image_patches_grad_test.py | 3 + .../fractional_avg_pool_op_test.py | 5 + .../fractional_max_pool_op_test.py | 5 + .../kernel_tests/functional_ops_test.py | 33 +++ .../python/kernel_tests/gather_nd_op_test.py | 11 + .../python/kernel_tests/gather_op_test.py | 8 + .../kernel_tests/gradient_correctness_test.py | 11 + .../kernel_tests/identity_n_op_py_test.py | 4 + .../kernel_tests/identity_op_py_test.py | 5 + .../python/kernel_tests/init_ops_test.py | 59 +++++ .../python/kernel_tests/inplace_ops_test.py | 7 + tensorflow/python/kernel_tests/io_ops_test.py | 3 + .../linalg/linear_operator_addition_test.py | 13 + .../linalg/linear_operator_circulant_test.py | 20 ++ .../linear_operator_composition_test.py | 4 + .../linalg/linear_operator_diag_test.py | 4 + .../linear_operator_full_matrix_test.py | 2 + .../linalg/linear_operator_identity_test.py | 15 ++ .../linalg/linear_operator_kronecker_test.py | 2 + .../linalg/linear_operator_test.py | 9 + .../linalg/linear_operator_util_test.py | 25 ++ .../linalg/linear_operator_zeros_test.py | 7 + .../python/kernel_tests/linalg_grad_test.py | 2 + .../python/kernel_tests/linalg_ops_test.py | 5 + .../python/kernel_tests/list_ops_test.py | 15 ++ .../python/kernel_tests/logging_ops_test.py | 4 + .../python/kernel_tests/lookup_ops_test.py | 64 +++++ tensorflow/python/kernel_tests/losses_test.py | 62 +++++ tensorflow/python/kernel_tests/lrn_op_test.py | 4 + .../python/kernel_tests/manip_ops_test.py | 12 + .../python/kernel_tests/map_stage_op_test.py | 13 + .../python/kernel_tests/matmul_op_test.py | 4 + .../matrix_exponential_op_test.py | 4 + .../kernel_tests/matrix_solve_ls_op_test.py | 4 + .../kernel_tests/matrix_solve_op_test.py | 6 + .../matrix_triangular_solve_op_test.py | 7 + .../python/kernel_tests/metrics_test.py | 226 ++++++++++++++++++ .../kernel_tests/morphological_ops_test.py | 3 + .../neon_depthwise_conv_op_test.py | 3 + .../kernel_tests/nth_element_op_test.py | 8 + .../python/kernel_tests/numerics_test.py | 5 + tensorflow/python/kernel_tests/pad_op_test.py | 12 + .../parameterized_truncated_normal_op_test.py | 11 + .../parse_single_example_op_test.py | 7 + .../python/kernel_tests/parsing_ops_test.py | 18 ++ .../partitioned_variables_test.py | 13 + tensorflow/python/kernel_tests/pool_test.py | 4 + .../kernel_tests/pooling_ops_3d_test.py | 19 ++ .../python/kernel_tests/pooling_ops_test.py | 12 + .../python/kernel_tests/py_func_test.py | 2 + tensorflow/python/kernel_tests/qr_op_test.py | 2 + .../random/multinomial_op_big_test.py | 2 + .../random/multinomial_op_test.py | 3 + .../kernel_tests/random/random_crop_test.py | 3 + .../kernel_tests/random/random_gamma_test.py | 6 + .../kernel_tests/random/random_grad_test.py | 11 + .../kernel_tests/random/random_ops_test.py | 22 ++ .../random/random_poisson_test.py | 6 + .../random/stateless_random_ops_test.py | 6 + .../python/kernel_tests/reader_ops_test.py | 25 ++ .../python/kernel_tests/record_input_test.py | 4 + .../kernel_tests/reduce_join_op_test.py | 6 + .../python/kernel_tests/reduction_ops_test.py | 57 +++++ .../kernel_tests/regex_full_match_op_test.py | 7 + .../kernel_tests/regex_replace_op_test.py | 9 + .../python/kernel_tests/relu_op_test.py | 21 ++ .../python/kernel_tests/reshape_op_test.py | 4 + .../resource_variable_ops_test.py | 19 ++ .../kernel_tests/reverse_sequence_op_test.py | 3 + tensorflow/python/kernel_tests/rnn_test.py | 10 + .../kernel_tests/save_restore_ops_test.py | 3 + .../python/kernel_tests/scan_ops_test.py | 24 ++ .../kernel_tests/scatter_nd_ops_test.py | 29 +++ .../python/kernel_tests/scatter_ops_test.py | 28 +++ .../segment_reduction_ops_test.py | 32 +++ tensorflow/python/kernel_tests/sets_test.py | 16 ++ .../python/kernel_tests/shape_ops_test.py | 21 ++ .../kernel_tests/signal/dct_ops_test.py | 2 + .../kernel_tests/signal/fft_ops_test.py | 16 ++ .../kernel_tests/signal/mel_ops_test.py | 4 + .../kernel_tests/signal/mfcc_ops_test.py | 4 + .../signal/reconstruction_ops_test.py | 5 + .../kernel_tests/signal/shape_ops_test.py | 12 + .../kernel_tests/signal/window_ops_test.py | 3 + .../python/kernel_tests/slice_op_test.py | 8 + .../python/kernel_tests/softmax_op_test.py | 3 + .../python/kernel_tests/softplus_op_test.py | 5 + .../python/kernel_tests/softsign_op_test.py | 3 + .../kernel_tests/spacetobatch_op_test.py | 36 +++ .../kernel_tests/spacetodepth_op_test.py | 11 + .../python/kernel_tests/sparse_add_op_test.py | 3 + .../kernel_tests/sparse_concat_op_test.py | 5 + .../sparse_conditional_accumulator_test.py | 24 ++ .../kernel_tests/sparse_cross_op_test.py | 18 ++ .../kernel_tests/sparse_matmul_op_test.py | 7 + .../python/kernel_tests/sparse_ops_test.py | 32 +++ .../kernel_tests/sparse_reorder_op_test.py | 4 + .../kernel_tests/sparse_reshape_op_test.py | 18 ++ .../sparse_serialization_ops_test.py | 25 ++ .../kernel_tests/sparse_slice_op_test.py | 8 + .../kernel_tests/sparse_split_op_test.py | 8 + .../sparse_tensor_dense_matmul_grad_test.py | 2 + .../sparse_tensor_dense_matmul_op_test.py | 4 + .../sparse_tensors_map_ops_test.py | 6 + .../sparse_to_dense_op_py_test.py | 18 ++ .../kernel_tests/sparse_xent_op_test.py | 10 +- .../python/kernel_tests/sparsemask_op_test.py | 2 + .../python/kernel_tests/split_op_test.py | 7 + .../python/kernel_tests/stack_op_test.py | 17 ++ .../python/kernel_tests/stack_ops_test.py | 15 ++ .../python/kernel_tests/stage_op_test.py | 8 + .../kernel_tests/string_join_op_test.py | 2 + .../kernel_tests/string_length_op_test.py | 3 + .../kernel_tests/string_split_op_test.py | 5 + .../string_to_hash_bucket_op_test.py | 5 + .../kernel_tests/string_to_number_op_test.py | 5 + .../python/kernel_tests/substr_op_test.py | 9 + .../kernel_tests/summary_v1_image_op_test.py | 3 + .../kernel_tests/summary_v1_ops_test.py | 2 + .../python/kernel_tests/template_test.py | 5 + .../kernel_tests/tensor_array_ops_test.py | 42 ++++ .../python/kernel_tests/topk_op_test.py | 4 + .../python/kernel_tests/trace_op_test.py | 2 + .../kernel_tests/unicode_decode_op_test.py | 4 + .../kernel_tests/unicode_script_op_test.py | 3 + .../kernel_tests/unicode_transcode_op_test.py | 7 + .../python/kernel_tests/unstack_op_test.py | 6 + .../python/kernel_tests/variable_ops_test.py | 22 ++ .../kernel_tests/variable_scope_test.py | 14 ++ .../python/kernel_tests/variables_test.py | 27 +++ .../kernel_tests/weights_broadcast_test.py | 31 +++ .../python/kernel_tests/where_op_test.py | 17 ++ .../python/kernel_tests/while_v2_test.py | 15 ++ .../python/kernel_tests/xent_op_test.py | 7 + .../python/kernel_tests/zero_division_test.py | 1 + tensorflow/python/layers/base_test.py | 4 + .../python/layers/convolutional_test.py | 56 +++++ tensorflow/python/layers/core_test.py | 19 ++ .../python/layers/normalization_test.py | 37 +++ tensorflow/python/layers/pooling_test.py | 4 + tensorflow/python/ops/bitwise_ops_test.py | 6 + tensorflow/python/ops/clip_ops_test.py | 2 + tensorflow/python/ops/collective_ops_test.py | 5 + .../python/ops/gradient_checker_test.py | 14 ++ tensorflow/python/ops/histogram_ops_test.py | 4 + tensorflow/python/ops/image_grad_test.py | 12 + tensorflow/python/ops/image_ops_test.py | 92 +++++++ tensorflow/python/ops/losses/util_test.py | 2 + tensorflow/python/ops/math_grad_test.py | 26 ++ tensorflow/python/ops/math_ops_test.py | 24 ++ tensorflow/python/ops/nn_batchnorm_test.py | 14 ++ tensorflow/python/ops/nn_grad_test.py | 2 + tensorflow/python/ops/nn_test.py | 20 ++ tensorflow/python/ops/nn_xent_test.py | 6 + ...vert_to_tensor_or_ragged_tensor_op_test.py | 2 + .../ops/ragged/ragged_batch_gather_op_test.py | 3 + .../ops/ragged/ragged_boolean_mask_op_test.py | 2 + .../ops/ragged/ragged_concat_op_test.py | 5 + .../python/ops/ragged/ragged_const_op_test.py | 2 + .../ops/ragged/ragged_elementwise_ops_test.py | 1 + .../ops/ragged/ragged_expand_dims_op_test.py | 1 + .../ops/ragged/ragged_from_sparse_op_test.py | 5 + .../ops/ragged/ragged_from_tensor_op_test.py | 5 + .../ops/ragged/ragged_gather_nd_op_test.py | 3 + .../ops/ragged/ragged_gather_op_test.py | 10 + .../ops/ragged/ragged_map_fn_op_test.py | 5 + .../ragged/ragged_map_inner_values_op_test.py | 13 + .../ops/ragged/ragged_operators_test.py | 3 + .../python/ops/ragged/ragged_range_op_test.py | 9 + .../ops/ragged/ragged_reduce_op_test.py | 4 + .../ops/ragged/ragged_row_lengths_op_test.py | 1 + ...agged_row_splits_to_segment_ids_op_test.py | 3 + ...agged_segment_ids_to_row_splits_op_test.py | 4 + .../ops/ragged/ragged_segment_op_test.py | 5 + .../python/ops/ragged/ragged_stack_op_test.py | 2 + .../python/ops/ragged/ragged_tensor_test.py | 33 +++ .../python/ops/ragged/ragged_tile_op_test.py | 2 + .../ops/ragged/ragged_to_sparse_op_test.py | 7 + .../ops/ragged/ragged_to_tensor_op_test.py | 3 + .../python/ops/ragged/ragged_where_op_test.py | 1 + tensorflow/python/ops/sort_ops_test.py | 10 + .../python/ops/special_math_ops_test.py | 7 + .../profiler/internal/run_metadata_test.py | 3 + .../python/profiler/pprof_profiler_test.py | 2 + .../python/profiler/profile_context_test.py | 4 + tensorflow/python/profiler/profiler_test.py | 3 + tensorflow/python/saved_model/loader_test.py | 7 + tensorflow/python/saved_model/save_test.py | 1 + .../python/saved_model/saved_model_test.py | 31 +++ .../saved_model/signature_def_utils_test.py | 9 + .../python/saved_model/simple_save_test.py | 2 + tensorflow/python/summary/summary_test.py | 13 + .../python/summary/writer/writer_test.py | 15 ++ tensorflow/python/tools/freeze_graph_test.py | 2 + .../tools/optimize_for_inference_test.py | 5 + tensorflow/python/training/adadelta_test.py | 1 + tensorflow/python/training/adagrad_da_test.py | 7 + tensorflow/python/training/adagrad_test.py | 9 + tensorflow/python/training/adam_test.py | 6 + .../python/training/basic_loops_test.py | 4 + .../training/basic_session_run_hooks_test.py | 9 + .../training/checkpoint_management_test.py | 5 + .../python/training/device_setter_test.py | 11 + tensorflow/python/training/ftrl_test.py | 14 ++ .../python/training/gradient_descent_test.py | 10 + tensorflow/python/training/input_test.py | 108 +++++++++ .../training/learning_rate_decay_test.py | 2 + .../training/learning_rate_decay_v2_test.py | 1 + tensorflow/python/training/momentum_test.py | 6 + .../python/training/monitored_session_test.py | 27 +++ .../python/training/moving_averages_test.py | 23 ++ tensorflow/python/training/optimizer_test.py | 4 + .../python/training/proximal_adagrad_test.py | 9 + .../proximal_gradient_descent_test.py | 8 + .../python/training/quantize_training_test.py | 2 + .../python/training/queue_runner_test.py | 16 ++ tensorflow/python/training/rmsprop_test.py | 6 + tensorflow/python/training/saver_test.py | 35 +++ .../server_lib_multiple_containers_test.py | 2 + ...lib_same_variables_clear_container_test.py | 2 + .../server_lib_same_variables_clear_test.py | 2 + ...server_lib_same_variables_no_clear_test.py | 2 + .../training/server_lib_sparse_job_test.py | 2 + .../python/training/session_manager_test.py | 15 ++ .../python/training/slot_creator_test.py | 8 + tensorflow/python/training/supervisor_test.py | 12 + .../python/training/training_ops_test.py | 8 + .../python/training/training_util_test.py | 3 + tensorflow/python/util/deprecation_test.py | 16 ++ tensorflow/python/util/nest_test.py | 1 + tensorflow/python/util/tf_should_use_test.py | 7 + .../tools/api/tests/api_compatibility_test.py | 3 + 431 files changed, 4673 insertions(+), 1 deletion(-) diff --git a/tensorflow/examples/adding_an_op/fact_test.py b/tensorflow/examples/adding_an_op/fact_test.py index 11163e7ba5..46beaebe0c 100644 --- a/tensorflow/examples/adding_an_op/fact_test.py +++ b/tensorflow/examples/adding_an_op/fact_test.py @@ -19,10 +19,12 @@ from __future__ import division from __future__ import print_function import tensorflow as tf +from tensorflow.python.framework import test_util class FactTest(tf.test.TestCase): + @test_util.run_deprecated_v1 def test(self): with self.cached_session(): print(tf.user_ops.my_fact().eval()) diff --git a/tensorflow/examples/adding_an_op/zero_out_1_test.py b/tensorflow/examples/adding_an_op/zero_out_1_test.py index 342d3a020c..459ac2dc27 100644 --- a/tensorflow/examples/adding_an_op/zero_out_1_test.py +++ b/tensorflow/examples/adding_an_op/zero_out_1_test.py @@ -23,10 +23,12 @@ import os.path import tensorflow as tf from tensorflow.examples.adding_an_op import zero_out_op_1 +from tensorflow.python.framework import test_util class ZeroOut1Test(tf.test.TestCase): + @test_util.run_deprecated_v1 def test(self): with self.cached_session(): result = zero_out_op_1.zero_out([5, 4, 3, 2, 1]) diff --git a/tensorflow/examples/adding_an_op/zero_out_2_test.py b/tensorflow/examples/adding_an_op/zero_out_2_test.py index 4504597817..650fd9546b 100644 --- a/tensorflow/examples/adding_an_op/zero_out_2_test.py +++ b/tensorflow/examples/adding_an_op/zero_out_2_test.py @@ -24,20 +24,24 @@ import tensorflow as tf from tensorflow.examples.adding_an_op import zero_out_grad_2 # pylint: disable=unused-import from tensorflow.examples.adding_an_op import zero_out_op_2 +from tensorflow.python.framework import test_util class ZeroOut2Test(tf.test.TestCase): + @test_util.run_deprecated_v1 def test(self): with self.cached_session(): result = zero_out_op_2.zero_out([5, 4, 3, 2, 1]) self.assertAllEqual(result.eval(), [5, 0, 0, 0, 0]) + @test_util.run_deprecated_v1 def test_2d(self): with self.cached_session(): result = zero_out_op_2.zero_out([[6, 5, 4], [3, 2, 1]]) self.assertAllEqual(result.eval(), [[6, 0, 0], [0, 0, 0]]) + @test_util.run_deprecated_v1 def test_grad(self): with self.cached_session(): shape = (5,) @@ -46,6 +50,7 @@ class ZeroOut2Test(tf.test.TestCase): err = tf.test.compute_gradient_error(x, shape, y, shape) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def test_grad_2d(self): with self.cached_session(): shape = (2, 3) diff --git a/tensorflow/examples/adding_an_op/zero_out_3_test.py b/tensorflow/examples/adding_an_op/zero_out_3_test.py index 2327e7cd8f..8cbe2b6793 100644 --- a/tensorflow/examples/adding_an_op/zero_out_3_test.py +++ b/tensorflow/examples/adding_an_op/zero_out_3_test.py @@ -21,26 +21,31 @@ from __future__ import print_function import tensorflow as tf from tensorflow.examples.adding_an_op import zero_out_op_3 +from tensorflow.python.framework import test_util class ZeroOut3Test(tf.test.TestCase): + @test_util.run_deprecated_v1 def test(self): with self.cached_session(): result = zero_out_op_3.zero_out([5, 4, 3, 2, 1]) self.assertAllEqual(result.eval(), [5, 0, 0, 0, 0]) + @test_util.run_deprecated_v1 def testAttr(self): with self.cached_session(): result = zero_out_op_3.zero_out([5, 4, 3, 2, 1], preserve_index=3) self.assertAllEqual(result.eval(), [0, 0, 0, 2, 0]) + @test_util.run_deprecated_v1 def testNegative(self): with self.cached_session(): result = zero_out_op_3.zero_out([5, 4, 3, 2, 1], preserve_index=-1) with self.assertRaisesOpError("Need preserve_index >= 0, got -1"): self.evaluate(result) + @test_util.run_deprecated_v1 def testLarge(self): with self.cached_session(): result = zero_out_op_3.zero_out([5, 4, 3, 2, 1], preserve_index=17) diff --git a/tensorflow/examples/autograph/integration_tests/keras_test.py b/tensorflow/examples/autograph/integration_tests/keras_test.py index fc0b073696..3fe33df920 100644 --- a/tensorflow/examples/autograph/integration_tests/keras_test.py +++ b/tensorflow/examples/autograph/integration_tests/keras_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import tensorflow as tf from tensorflow.python import autograph +from tensorflow.python.framework import test_util class MinimalKeras(tf.keras.Model): @@ -84,6 +85,7 @@ class KerasTest(tf.test.TestCase): model = ModelWithStaticConditional(True) self.assertEqual(model.call(), 25) + @test_util.run_deprecated_v1 def test_recursive_true(self): with self.assertRaisesRegexp(NotImplementedError, 'Object conversion is not yet supported.'): diff --git a/tensorflow/examples/speech_commands/freeze_test.py b/tensorflow/examples/speech_commands/freeze_test.py index 0c7ca9bc01..9ed9050035 100644 --- a/tensorflow/examples/speech_commands/freeze_test.py +++ b/tensorflow/examples/speech_commands/freeze_test.py @@ -19,11 +19,13 @@ from __future__ import division from __future__ import print_function from tensorflow.examples.speech_commands import freeze +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class FreezeTest(test.TestCase): + @test_util.run_deprecated_v1 def testCreateInferenceGraphWithMfcc(self): with self.cached_session() as sess: freeze.create_inference_graph( @@ -43,6 +45,7 @@ class FreezeTest(test.TestCase): ops = [node.op for node in sess.graph_def.node] self.assertEqual(1, ops.count('Mfcc')) + @test_util.run_deprecated_v1 def testCreateInferenceGraphWithoutMfcc(self): with self.cached_session() as sess: freeze.create_inference_graph( @@ -62,6 +65,7 @@ class FreezeTest(test.TestCase): ops = [node.op for node in sess.graph_def.node] self.assertEqual(0, ops.count('Mfcc')) + @test_util.run_deprecated_v1 def testFeatureBinCount(self): with self.cached_session() as sess: freeze.create_inference_graph( diff --git a/tensorflow/examples/speech_commands/input_data_test.py b/tensorflow/examples/speech_commands/input_data_test.py index 33b58b9d09..9269bb6c0b 100644 --- a/tensorflow/examples/speech_commands/input_data_test.py +++ b/tensorflow/examples/speech_commands/input_data_test.py @@ -26,6 +26,7 @@ import tensorflow as tf from tensorflow.contrib.framework.python.ops import audio_ops as contrib_audio from tensorflow.examples.speech_commands import input_data from tensorflow.examples.speech_commands import models +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -96,6 +97,7 @@ class InputDataTest(test.TestCase): input_data.which_set("foo_nohash_0.wav", 10, 10), input_data.which_set("foo_nohash_1.wav", 10, 10)) + @test_util.run_deprecated_v1 def testPrepareDataIndex(self): tmp_dir = self.get_temp_dir() self._saveWavFolders(tmp_dir, ["a", "b", "c"], 100) @@ -125,6 +127,7 @@ class InputDataTest(test.TestCase): 10, self._model_settings(), tmp_dir) self.assertTrue("Expected to find" in str(e.exception)) + @test_util.run_deprecated_v1 def testPrepareBackgroundData(self): tmp_dir = self.get_temp_dir() background_dir = os.path.join(tmp_dir, "_background_noise_") @@ -156,6 +159,7 @@ class InputDataTest(test.TestCase): self.assertIsNotNone(loaded_data) self.assertEqual(16000, len(loaded_data)) + @test_util.run_deprecated_v1 def testPrepareProcessingGraph(self): tmp_dir = self.get_temp_dir() wav_dir = os.path.join(tmp_dir, "wavs") @@ -186,15 +190,19 @@ class InputDataTest(test.TestCase): self.assertIsNotNone(audio_processor.background_volume_placeholder_) self.assertIsNotNone(audio_processor.output_) + @test_util.run_deprecated_v1 def testGetDataAverage(self): self._runGetDataTest("average", 10) + @test_util.run_deprecated_v1 def testGetDataAverageLongWindow(self): self._runGetDataTest("average", 30) + @test_util.run_deprecated_v1 def testGetDataMfcc(self): self._runGetDataTest("mfcc", 30) + @test_util.run_deprecated_v1 def testGetUnprocessedData(self): tmp_dir = self.get_temp_dir() wav_dir = os.path.join(tmp_dir, "wavs") @@ -216,6 +224,7 @@ class InputDataTest(test.TestCase): self.assertEqual(10, len(result_data)) self.assertEqual(10, len(result_labels)) + @test_util.run_deprecated_v1 def testGetFeaturesForWav(self): tmp_dir = self.get_temp_dir() wav_dir = os.path.join(tmp_dir, "wavs") diff --git a/tensorflow/examples/speech_commands/models_test.py b/tensorflow/examples/speech_commands/models_test.py index 04478c0962..cb9304eab8 100644 --- a/tensorflow/examples/speech_commands/models_test.py +++ b/tensorflow/examples/speech_commands/models_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import tensorflow as tf from tensorflow.examples.speech_commands import models +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -47,6 +48,7 @@ class ModelsTest(test.TestCase): feature_bin_count=40, preprocess="mfcc")) + @test_util.run_deprecated_v1 def testCreateModelConvTraining(self): model_settings = self._modelSettings() with self.cached_session() as sess: @@ -58,6 +60,7 @@ class ModelsTest(test.TestCase): self.assertIsNotNone(sess.graph.get_tensor_by_name(logits.name)) self.assertIsNotNone(sess.graph.get_tensor_by_name(dropout_prob.name)) + @test_util.run_deprecated_v1 def testCreateModelConvInference(self): model_settings = self._modelSettings() with self.cached_session() as sess: @@ -67,6 +70,7 @@ class ModelsTest(test.TestCase): self.assertIsNotNone(logits) self.assertIsNotNone(sess.graph.get_tensor_by_name(logits.name)) + @test_util.run_deprecated_v1 def testCreateModelLowLatencyConvTraining(self): model_settings = self._modelSettings() with self.cached_session() as sess: @@ -78,6 +82,7 @@ class ModelsTest(test.TestCase): self.assertIsNotNone(sess.graph.get_tensor_by_name(logits.name)) self.assertIsNotNone(sess.graph.get_tensor_by_name(dropout_prob.name)) + @test_util.run_deprecated_v1 def testCreateModelFullyConnectedTraining(self): model_settings = self._modelSettings() with self.cached_session() as sess: @@ -98,6 +103,7 @@ class ModelsTest(test.TestCase): "bad_architecture", True) self.assertTrue("not recognized" in str(e.exception)) + @test_util.run_deprecated_v1 def testCreateModelTinyConvTraining(self): model_settings = self._modelSettings() with self.cached_session() as sess: diff --git a/tensorflow/examples/speech_commands/wav_to_features_test.py b/tensorflow/examples/speech_commands/wav_to_features_test.py index cb8ea912fa..6234490b26 100644 --- a/tensorflow/examples/speech_commands/wav_to_features_test.py +++ b/tensorflow/examples/speech_commands/wav_to_features_test.py @@ -24,6 +24,7 @@ import tensorflow as tf from tensorflow.contrib.framework.python.ops import audio_ops as contrib_audio from tensorflow.examples.speech_commands import wav_to_features +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -49,6 +50,7 @@ class WavToFeaturesTest(test.TestCase): file_path = os.path.join(dir_name, "some_audio_%d.wav" % i) self._saveTestWavFile(file_path, wav_data) + @test_util.run_deprecated_v1 def testWavToFeatures(self): tmp_dir = self.get_temp_dir() wav_dir = os.path.join(tmp_dir, "wavs") diff --git a/tensorflow/python/autograph/converters/asserts_test.py b/tensorflow/python/autograph/converters/asserts_test.py index 803b6a06da..9ae448892a 100644 --- a/tensorflow/python/autograph/converters/asserts_test.py +++ b/tensorflow/python/autograph/converters/asserts_test.py @@ -23,12 +23,14 @@ from tensorflow.python.autograph.converters import side_effect_guards from tensorflow.python.autograph.core import converter_testing from tensorflow.python.framework import constant_op from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_control_flow_ops from tensorflow.python.platform import test class AssertsTest(converter_testing.TestCase): + @test_util.run_deprecated_v1 def test_basic(self): def test_fn(a): diff --git a/tensorflow/python/autograph/converters/builtin_functions_test.py b/tensorflow/python/autograph/converters/builtin_functions_test.py index 30cfb13233..2683be16ec 100644 --- a/tensorflow/python/autograph/converters/builtin_functions_test.py +++ b/tensorflow/python/autograph/converters/builtin_functions_test.py @@ -24,12 +24,14 @@ from tensorflow.python.autograph.converters import builtin_functions from tensorflow.python.autograph.core import converter_testing from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test class BuiltinFunctionsTest(converter_testing.TestCase): + @test_util.run_deprecated_v1 def test_len(self): def test_fn(a): @@ -41,6 +43,7 @@ class BuiltinFunctionsTest(converter_testing.TestCase): ops = result.test_fn(p) self.assertEqual(sess.run(ops, {p: [0, 0, 0]}), 3) + @test_util.run_deprecated_v1 def test_print(self): if six.PY2: @@ -54,6 +57,7 @@ class BuiltinFunctionsTest(converter_testing.TestCase): with self.assertPrints('a\n'): sess.run(result.test_fn('a')) + @test_util.run_deprecated_v1 def test_print_multiple_values(self): if six.PY2: diff --git a/tensorflow/python/autograph/converters/control_flow_test.py b/tensorflow/python/autograph/converters/control_flow_test.py index 03fdfc804e..034fcbe386 100644 --- a/tensorflow/python/autograph/converters/control_flow_test.py +++ b/tensorflow/python/autograph/converters/control_flow_test.py @@ -23,6 +23,7 @@ from tensorflow.python.autograph.core import converter_testing from tensorflow.python.autograph.pyct import transformer from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -36,6 +37,7 @@ class ControlFlowTest(converter_testing.TestCase): with self.cached_session() as sess: self.assertEqual(sess.run(result.test_fn(*inputs)), expected) + @test_util.run_deprecated_v1 def test_while_basic(self): def test_fn(n): @@ -48,6 +50,7 @@ class ControlFlowTest(converter_testing.TestCase): self.assertTransformedResult(test_fn, constant_op.constant(5), (10, 5, 5)) + @test_util.run_deprecated_v1 def test_while_nested(self): def test_fn(n): @@ -66,6 +69,7 @@ class ControlFlowTest(converter_testing.TestCase): self.assertTransformedResult(test_fn, constant_op.constant(5), (25, 5, 0, 5)) + @test_util.run_deprecated_v1 def test_while_single_output(self): def test_fn(n): @@ -86,6 +90,7 @@ class ControlFlowTest(converter_testing.TestCase): with self.assertRaises(NameError): control_flow.transform(node, ctx) + @test_util.run_deprecated_v1 def test_if_basic(self): def test_fn(n): @@ -100,6 +105,7 @@ class ControlFlowTest(converter_testing.TestCase): self.assertTransformedResult(test_fn, constant_op.constant(1), (-1, 0)) self.assertTransformedResult(test_fn, constant_op.constant(-1), (0, -2)) + @test_util.run_deprecated_v1 def test_if_complex_outputs(self): class TestClass(object): @@ -124,6 +130,7 @@ class ControlFlowTest(converter_testing.TestCase): res_obj = result.test_fn(constant_op.constant(-1), TestClass(0, 0)) self.assertEqual(sess.run((res_obj.a, res_obj.b)), (0, -2)) + @test_util.run_deprecated_v1 def test_if_single_output(self): def test_fn(n): @@ -133,6 +140,7 @@ class ControlFlowTest(converter_testing.TestCase): self.assertTransformedResult(test_fn, constant_op.constant(1), -1) + @test_util.run_deprecated_v1 def test_if_semi(self): def test_fn(n): @@ -143,6 +151,7 @@ class ControlFlowTest(converter_testing.TestCase): self.assertTransformedResult(test_fn, constant_op.constant(2), 3) self.assertTransformedResult(test_fn, constant_op.constant(-3), -3) + @test_util.run_deprecated_v1 def test_if_local_var(self): def test_fn(n): @@ -154,6 +163,7 @@ class ControlFlowTest(converter_testing.TestCase): self.assertTransformedResult(test_fn, constant_op.constant(1), 5) self.assertTransformedResult(test_fn, constant_op.constant(-1), -1) + @test_util.run_deprecated_v1 def test_if_no_outputs(self): def test_fn(n): @@ -177,6 +187,7 @@ class ControlFlowTest(converter_testing.TestCase): with self.assertRaises(transformer.AutographParseError): control_flow.transform(node, ctx) + @test_util.run_deprecated_v1 def test_simple_for(self): def test_fn(l): @@ -191,6 +202,7 @@ class ControlFlowTest(converter_testing.TestCase): empty_vector = constant_op.constant([], shape=(0,), dtype=dtypes.int32) self.assertTransformedResult(test_fn, empty_vector, (0, 0)) + @test_util.run_deprecated_v1 def test_for_single_output(self): def test_fn(l): @@ -235,6 +247,7 @@ class ControlFlowTest(converter_testing.TestCase): with self.assertRaises(NameError): control_flow.transform(node, ctx) + @test_util.run_deprecated_v1 def test_for_tuple_unpacking(self): def test_fn(x_list): z = tf.constant(0) # pylint:disable=undefined-variable diff --git a/tensorflow/python/autograph/converters/function_scopes_test.py b/tensorflow/python/autograph/converters/function_scopes_test.py index e5ce03a109..5a1248c801 100644 --- a/tensorflow/python/autograph/converters/function_scopes_test.py +++ b/tensorflow/python/autograph/converters/function_scopes_test.py @@ -22,11 +22,13 @@ from tensorflow.python.autograph.converters import function_scopes from tensorflow.python.autograph.core import converter_testing from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class FunctionBodyTransformerTest(converter_testing.TestCase): + @test_util.run_deprecated_v1 def test_basic(self): def test_fn(l): @@ -40,6 +42,7 @@ class FunctionBodyTransformerTest(converter_testing.TestCase): self.assertIn('test_fn/', result_op.op.name) self.assertEqual('Docstring.', result.test_fn.__doc__) + @test_util.run_deprecated_v1 def test_multiline_docstring(self): tf = None @@ -58,6 +61,7 @@ class FunctionBodyTransformerTest(converter_testing.TestCase): self.assertIn('First sentence.', result.test_fn.__doc__) self.assertIn('Second sentence.', result.test_fn.__doc__) + @test_util.run_deprecated_v1 def test_nested_functions(self): def test_fn(l): @@ -74,6 +78,7 @@ class FunctionBodyTransformerTest(converter_testing.TestCase): self.assertNotIn('inner_fn', first.op.name) self.assertIn('test_fn/inner_fn/', second.op.name) + @test_util.run_deprecated_v1 def test_method(self): class TestClass(object): diff --git a/tensorflow/python/autograph/converters/logical_expressions_test.py b/tensorflow/python/autograph/converters/logical_expressions_test.py index 99db04a775..687412750e 100644 --- a/tensorflow/python/autograph/converters/logical_expressions_test.py +++ b/tensorflow/python/autograph/converters/logical_expressions_test.py @@ -21,11 +21,13 @@ from __future__ import print_function from tensorflow.python.autograph.converters import logical_expressions from tensorflow.python.autograph.core import converter_testing from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class LogicalExpressionTest(converter_testing.TestCase): + @test_util.run_deprecated_v1 def test_equals(self): def test_fn(a, b): @@ -36,6 +38,7 @@ class LogicalExpressionTest(converter_testing.TestCase): self.assertTrue(sess.run(result.test_fn(constant_op.constant(1), 1))) self.assertFalse(sess.run(result.test_fn(constant_op.constant(1), 2))) + @test_util.run_deprecated_v1 def test_bool_ops(self): def test_fn(a, b, c): @@ -48,6 +51,7 @@ class LogicalExpressionTest(converter_testing.TestCase): self.assertFalse( sess.run(result.test_fn(constant_op.constant(True), False, True))) + @test_util.run_deprecated_v1 def test_comparison(self): def test_fn(a, b, c, d): diff --git a/tensorflow/python/autograph/converters/side_effect_guards_test.py b/tensorflow/python/autograph/converters/side_effect_guards_test.py index f6d0f73b5b..645267e560 100644 --- a/tensorflow/python/autograph/converters/side_effect_guards_test.py +++ b/tensorflow/python/autograph/converters/side_effect_guards_test.py @@ -23,6 +23,7 @@ from tensorflow.python.autograph.core import converter_testing from tensorflow.python.framework import constant_op from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import variable_scope @@ -34,6 +35,7 @@ tf = None # Will be replaced by a mock. class SideEffectGuardsTest(converter_testing.TestCase): + @test_util.run_deprecated_v1 def test_side_effect_on_return_only_variable(self): def test_fn(a): @@ -75,6 +77,7 @@ class SideEffectGuardsTest(converter_testing.TestCase): # Right now it's 3 or 4 based on whether the read is synchronized. self.assertEqual(3, self.evaluate(v)) + @test_util.run_deprecated_v1 def test_side_effect_on_tensor(self): def test_fn(a): diff --git a/tensorflow/python/autograph/core/errors_test.py b/tensorflow/python/autograph/core/errors_test.py index 00c8a726ed..845a28a522 100644 --- a/tensorflow/python/autograph/core/errors_test.py +++ b/tensorflow/python/autograph/core/errors_test.py @@ -22,6 +22,7 @@ from tensorflow.python.autograph.core import errors from tensorflow.python.autograph.pyct import origin_info from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors as tf_errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test from tensorflow.python.util import tf_inspect @@ -47,6 +48,7 @@ class RuntimeErrorsTest(test.TestCase): 'test_comment') return loc, origin + @test_util.run_deprecated_v1 def test_improved_errors_basic(self): loc, origin = self.fake_origin(zero_div, 2) zero_div_caller.ag_source_map = {loc: origin} @@ -62,6 +64,7 @@ class RuntimeErrorsTest(test.TestCase): self.assertNotEqual('zero_div', function_name) self.assertIn(origin.as_frame(), set(cm.exception.custom_traceback)) + @test_util.run_deprecated_v1 def test_improved_errors_no_matching_lineno(self): loc, origin = self.fake_origin(zero_div, -1) zero_div_caller.ag_source_map = {loc: origin} @@ -79,6 +82,7 @@ class RuntimeErrorsTest(test.TestCase): self.assertNotEqual('test_function_name', function_name) self.assertIn('zero_div', all_function_names) + @test_util.run_deprecated_v1 def test_improved_errors_failures(self): loc, _ = self.fake_origin(zero_div, 2) zero_div_caller.ag_source_map = {loc: 'bogus object'} diff --git a/tensorflow/python/autograph/core/function_wrapping_test.py b/tensorflow/python/autograph/core/function_wrapping_test.py index 5e217055c7..7e21b979db 100644 --- a/tensorflow/python/autograph/core/function_wrapping_test.py +++ b/tensorflow/python/autograph/core/function_wrapping_test.py @@ -20,11 +20,13 @@ from __future__ import print_function from tensorflow.python.autograph.core import function_wrapping from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class FunctionWrappingTest(test.TestCase): + @test_util.run_deprecated_v1 def test_function_scope_name(self): with function_wrapping.function_scope('test_name'): t = constant_op.constant(1) diff --git a/tensorflow/python/autograph/impl/api_test.py b/tensorflow/python/autograph/impl/api_test.py index a0fa501fb8..66edda5119 100644 --- a/tensorflow/python/autograph/impl/api_test.py +++ b/tensorflow/python/autograph/impl/api_test.py @@ -29,6 +29,7 @@ from tensorflow.python.autograph.impl import api from tensorflow.python.autograph.pyct import parser from tensorflow.python.autograph.utils import py_func from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.keras.engine import sequential from tensorflow.python.keras.layers import core from tensorflow.python.ops import variables @@ -44,6 +45,7 @@ class TestResource(str): class ApiTest(test.TestCase): + @test_util.run_deprecated_v1 def test_decorator_recurses(self): class TestClass(object): @@ -66,6 +68,7 @@ class ApiTest(test.TestCase): constant_op.constant(-2)) self.assertListEqual([0, 1], self.evaluate(x).tolist()) + @test_util.run_deprecated_v1 def test_decorator_does_not_recurse(self): class TestClass(object): @@ -86,6 +89,7 @@ class ApiTest(test.TestCase): constant_op.constant(-2)) self.assertListEqual([0, 1], self.evaluate(x).tolist()) + @test_util.run_deprecated_v1 def test_decorator_calls_unconverted_graph(self): class TestClass(object): @@ -107,6 +111,7 @@ class ApiTest(test.TestCase): constant_op.constant(-2)) self.assertListEqual([0, 1], self.evaluate(x).tolist()) + @test_util.run_deprecated_v1 def test_decorator_calls_unconverted_py_func(self): class TestClass(object): @@ -133,6 +138,7 @@ class ApiTest(test.TestCase): constant_op.constant(-2)) self.assertListEqual([0, 1], self.evaluate(x).tolist()) + @test_util.run_deprecated_v1 def test_decorator_calls_decorated(self): class TestClass(object): @@ -172,6 +178,7 @@ class ApiTest(test.TestCase): list(tf_inspect.getfullargspec(tc.called_member)), list(tf_inspect.getfullargspec(tc.called_member_converted))) + @test_util.run_deprecated_v1 def test_convert_call_site_decorator(self): class TestClass(object): @@ -326,6 +333,7 @@ class ApiTest(test.TestCase): constant_op.constant(0)) self.assertTrue(self.evaluate(x)) + @test_util.run_deprecated_v1 def test_converted_call_no_user_code(self): def f(x): @@ -400,6 +408,7 @@ class ApiTest(test.TestCase): self.evaluate(variables.global_variables_initializer()) self.assertAllEqual(True, self.evaluate(x)) + @test_util.run_deprecated_v1 def test_to_graph_basic(self): def test_fn(x, s): @@ -413,6 +422,7 @@ class ApiTest(test.TestCase): x = compiled_fn(constant_op.constant([4, 8]), 4) self.assertListEqual([1, 2], self.evaluate(x).tolist()) + @test_util.run_deprecated_v1 def test_to_graph_with_defaults(self): foo = 4 diff --git a/tensorflow/python/autograph/operators/control_flow_test.py b/tensorflow/python/autograph/operators/control_flow_test.py index 05b5660941..0a7d4b6402 100644 --- a/tensorflow/python/autograph/operators/control_flow_test.py +++ b/tensorflow/python/autograph/operators/control_flow_test.py @@ -22,12 +22,14 @@ from tensorflow.python.autograph.operators import control_flow from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.platform import test class ForLoopTest(test.TestCase): + @test_util.run_deprecated_v1 def test_tensor(self): s = control_flow.for_stmt( constant_op.constant([1, 2, 3, 4]), @@ -45,6 +47,7 @@ class ForLoopTest(test.TestCase): init_state=(0,)) self.assertEqual(10, s) + @test_util.run_deprecated_v1 def test_dataset(self): to_int32 = lambda i: math_ops.cast(i, dtypes.int32) s = control_flow.for_stmt( @@ -58,6 +61,7 @@ class ForLoopTest(test.TestCase): class WhileLoopTest(test.TestCase): + @test_util.run_deprecated_v1 def test_tensor(self): n = constant_op.constant(5) results = control_flow.while_stmt( @@ -87,6 +91,7 @@ class IfStmtTest(test.TestCase): return control_flow.if_stmt( cond=cond, body=lambda: (1, 2), orelse=lambda: (-1, -2)) + @test_util.run_deprecated_v1 def test_tensor(self): with self.cached_session() as sess: t = self.single_return_if_stmt(constant_op.constant(True)) @@ -98,6 +103,7 @@ class IfStmtTest(test.TestCase): self.assertEqual(1, self.single_return_if_stmt(True)) self.assertEqual(-1, self.single_return_if_stmt(False)) + @test_util.run_deprecated_v1 def test_tensor_multiple_returns(self): with self.cached_session() as sess: t = self.multi_return_if_stmt(constant_op.constant(True)) diff --git a/tensorflow/python/autograph/operators/data_structures_test.py b/tensorflow/python/autograph/operators/data_structures_test.py index 0433e3f130..9397b9acb8 100644 --- a/tensorflow/python/autograph/operators/data_structures_test.py +++ b/tensorflow/python/autograph/operators/data_structures_test.py @@ -22,6 +22,7 @@ from tensorflow.python.autograph.operators import data_structures from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import list_ops from tensorflow.python.ops import tensor_array_ops from tensorflow.python.platform import test @@ -59,6 +60,7 @@ class ListTest(test.TestCase): with self.cached_session() as sess: self.assertAllEqual(self.evaluate(t), [3, 4, 5]) + @test_util.run_deprecated_v1 def test_tf_tensor_list_new_illegal_input(self): with self.assertRaises(ValueError): data_structures.tf_tensor_list_new([3, 4.0]) @@ -104,6 +106,7 @@ class ListTest(test.TestCase): with self.cached_session() as sess: self.assertAllEqual(self.evaluate(t), [[1, 2, 3]]) + @test_util.run_deprecated_v1 def test_append_tensorarray(self): l = tensor_array_ops.TensorArray(dtypes.int32, size=0, dynamic_size=True) l1 = data_structures.list_append(l, 1) @@ -154,6 +157,7 @@ class ListTest(test.TestCase): t = data_structures.list_stack(l, opts) self.assertAllEqual(self.evaluate(t), self.evaluate(initial_list)) + @test_util.run_deprecated_v1 def test_stack_tensor_list_empty(self): l = list_ops.empty_tensor_list( element_shape=None, element_dtype=dtypes.variant) diff --git a/tensorflow/python/autograph/operators/exceptions_test.py b/tensorflow/python/autograph/operators/exceptions_test.py index 24d3f1bd35..21ba76bb95 100644 --- a/tensorflow/python/autograph/operators/exceptions_test.py +++ b/tensorflow/python/autograph/operators/exceptions_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.autograph.operators import exceptions from tensorflow.python.framework import constant_op from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -32,6 +33,7 @@ class ExceptionsTest(test.TestCase): constant_op.constant(True), lambda: constant_op.constant('ignored')) self.evaluate(t) + @test_util.run_deprecated_v1 def test_assert_tf_triggered(self): with self.cached_session() as sess: t = exceptions.assert_stmt( @@ -42,6 +44,7 @@ class ExceptionsTest(test.TestCase): 'test message'): self.evaluate(t) + @test_util.run_deprecated_v1 def test_assert_tf_multiple_printed_values(self): two_tensors = [ constant_op.constant('test message'), diff --git a/tensorflow/python/autograph/operators/logical_test.py b/tensorflow/python/autograph/operators/logical_test.py index ebf6458f01..e22f39932d 100644 --- a/tensorflow/python/autograph/operators/logical_test.py +++ b/tensorflow/python/autograph/operators/logical_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.autograph.operators import logical from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -42,6 +43,7 @@ class LogicalOperatorsTest(test.TestCase): self.assertFalse(logical.and_(lambda: False, lambda: True)) self.assertFalse(logical.and_(lambda: False, self.assertNotCalled)) + @test_util.run_deprecated_v1 def test_and_tf(self): with self.cached_session() as sess: t = logical.and_(self._tf_true, self._tf_true) @@ -60,6 +62,7 @@ class LogicalOperatorsTest(test.TestCase): self.assertTrue(logical.or_(lambda: False, lambda: True)) self.assertTrue(logical.or_(lambda: True, self.assertNotCalled)) + @test_util.run_deprecated_v1 def test_or_tf(self): with self.cached_session() as sess: t = logical.or_(self._tf_false, self._tf_true) diff --git a/tensorflow/python/autograph/operators/py_builtins_test.py b/tensorflow/python/autograph/operators/py_builtins_test.py index 4d9eec77c3..c856e39d14 100644 --- a/tensorflow/python/autograph/operators/py_builtins_test.py +++ b/tensorflow/python/autograph/operators/py_builtins_test.py @@ -27,6 +27,7 @@ from tensorflow.python.autograph.operators import py_builtins from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import tensor_array_ops from tensorflow.python.platform import test @@ -81,6 +82,7 @@ class PyBuiltinsTest(test.TestCase): with self.assertRaises(ValueError): py_builtins.len_(constant_op.constant(1)) + @test_util.run_deprecated_v1 def test_len_dynamic_shape(self): with self.cached_session() as sess: p = array_ops.placeholder(dtype=dtypes.int32, shape=None) @@ -91,6 +93,7 @@ class PyBuiltinsTest(test.TestCase): t = py_builtins.len_(p) sess.run(t, {p: 1}) + @test_util.run_deprecated_v1 def test_print_tensors(self): try: out_capturer = six.StringIO() @@ -101,6 +104,7 @@ class PyBuiltinsTest(test.TestCase): finally: sys.stdout = sys.__stdout__ + @test_util.run_deprecated_v1 def test_print_complex(self): try: out_capturer = six.StringIO() diff --git a/tensorflow/python/autograph/utils/misc_test.py b/tensorflow/python/autograph/utils/misc_test.py index c813e0f5c9..c78df48d62 100644 --- a/tensorflow/python/autograph/utils/misc_test.py +++ b/tensorflow/python/autograph/utils/misc_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.autograph.utils.misc import alias_tensors +from tensorflow.python.framework import test_util from tensorflow.python.framework.constant_op import constant from tensorflow.python.ops.variables import Variable from tensorflow.python.platform import test @@ -26,6 +27,7 @@ from tensorflow.python.platform import test class MiscTest(test.TestCase): + @test_util.run_deprecated_v1 def test_alias_single_tensor(self): a = constant(1) @@ -34,6 +36,7 @@ class MiscTest(test.TestCase): with self.cached_session() as sess: self.assertEqual(1, self.evaluate(new_a)) + @test_util.run_deprecated_v1 def test_alias_tensors(self): a = constant(1) v = Variable(2) diff --git a/tensorflow/python/autograph/utils/tensor_list_test.py b/tensorflow/python/autograph/utils/tensor_list_test.py index c655f773b0..0bd3007249 100644 --- a/tensorflow/python/autograph/utils/tensor_list_test.py +++ b/tensorflow/python/autograph/utils/tensor_list_test.py @@ -23,6 +23,7 @@ from tensorflow.python.client.session import Session from tensorflow.python.eager import context from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.framework.constant_op import constant from tensorflow.python.ops import list_ops from tensorflow.python.ops import tensor_array_ops @@ -34,6 +35,7 @@ class TensorListTest(test.TestCase): def _shape(self, shape_tuple): return constant(shape_tuple, dtypes.int32) + @test_util.run_deprecated_v1 def test_dynamic_list_append(self): l = [] l = tl.dynamic_list_append(l, 1) @@ -80,6 +82,7 @@ class TensorListTest(test.TestCase): l[0] = ops.convert_to_tensor(b) self.assertEqual(l[0].numpy(), b.numpy()) + @test_util.run_deprecated_v1 def test_list_append_tf(self): a = constant(3.0) l = tl.TensorList(a.shape, a.dtype) diff --git a/tensorflow/python/autograph/utils/type_check_test.py b/tensorflow/python/autograph/utils/type_check_test.py index b3d1304e16..2521dc9f92 100644 --- a/tensorflow/python/autograph/utils/type_check_test.py +++ b/tensorflow/python/autograph/utils/type_check_test.py @@ -28,6 +28,7 @@ from tensorflow.python.platform import test class TypeCheckTest(test.TestCase): + @test_util.run_deprecated_v1 def test_checks(self): self.assertTrue(type_check.is_tensor(constant_op.constant([1, 2, 3]))) self.assertTrue( diff --git a/tensorflow/python/client/session_partial_run_test.py b/tensorflow/python/client/session_partial_run_test.py index a9bd5ab7e0..a97930635a 100644 --- a/tensorflow/python/client/session_partial_run_test.py +++ b/tensorflow/python/client/session_partial_run_test.py @@ -188,6 +188,7 @@ class PartialRunTest(test_util.TensorFlowTestCase): r = sess.partial_run(h, [b], {}) self.assertEqual([6.0], r) + @test_util.run_deprecated_v1 def testInvalidPartialRunSetup(self): sess = session.Session() x = array_ops.placeholder(dtypes.float32, shape=[]) @@ -196,6 +197,7 @@ class PartialRunTest(test_util.TensorFlowTestCase): 'specify at least one target to fetch or execute.'): sess.partial_run_setup(fetches=[], feeds=[x]) + @test_util.run_deprecated_v1 def testPartialRunSetupNoFeedsPassed(self): sess = session.Session() r1 = constant_op.constant([6.0]) @@ -204,80 +206,102 @@ class PartialRunTest(test_util.TensorFlowTestCase): result1 = sess.partial_run(h, r1) self.assertEqual([6.0], result1) + @test_util.run_deprecated_v1 def testPartialRunDirect(self): self.RunTestPartialRun(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunIncompleteDirect(self): self.RunTestPartialRunIncomplete(session.Session()) + @test_util.run_deprecated_v1 def testConcurrentPartialRunDirect(self): self.RunTestConcurrentPartialRun(session.Session()) + @test_util.run_deprecated_v1 def testManyPartialRunDirect(self): self.RunTestManyPartialRun(session.Session()) + @test_util.run_deprecated_v1 def testRunAndPartialRunDirect(self): self.RunTestRunAndPartialRun(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunMissingPlaceholderFeedExceptionDirect(self): self.RunTestPartialRunMissingPlaceholderFeedException(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunUnspecifiedFeedDirect(self): self.RunTestPartialRunUnspecifiedFeed(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunUnspecifiedFetchDirect(self): self.RunTestPartialRunUnspecifiedFetch(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunAlreadyFedDirect(self): self.RunTestPartialRunAlreadyFed(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunAlreadyFetchedDirect(self): self.RunTestPartialRunAlreadyFetched(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunEmptyFetchesDirect(self): self.RunTestPartialRunEmptyFetches(session.Session()) + @test_util.run_deprecated_v1 def testPartialRunDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRun(session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunIncompleteDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunIncomplete(session.Session(server.target)) + @test_util.run_deprecated_v1 def testConcurrentPartialRunDist(self): server = server_lib.Server.create_local_server() self.RunTestConcurrentPartialRun(session.Session(server.target)) + @test_util.run_deprecated_v1 def testManyPartialRunDist(self): server = server_lib.Server.create_local_server() self.RunTestManyPartialRun(session.Session(server.target)) + @test_util.run_deprecated_v1 def testRunAndPartialRunDist(self): server = server_lib.Server.create_local_server() self.RunTestRunAndPartialRun(session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunMissingPlaceholderFeedExceptionDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunMissingPlaceholderFeedException( session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunUnspecifiedFeedDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunUnspecifiedFeed(session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunUnspecifiedFetchDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunUnspecifiedFetch(session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunAlreadyFedDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunAlreadyFed(session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunAlreadyFetchedDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunAlreadyFetched(session.Session(server.target)) + @test_util.run_deprecated_v1 def testPartialRunEmptyFetchesDist(self): server = server_lib.Server.create_local_server() self.RunTestPartialRunEmptyFetches(session.Session(server.target)) diff --git a/tensorflow/python/client/timeline_test.py b/tensorflow/python/client/timeline_test.py index f9bd50957a..61c0da01b8 100644 --- a/tensorflow/python/client/timeline_test.py +++ b/tensorflow/python/client/timeline_test.py @@ -57,6 +57,7 @@ class TimelineTest(test.TestCase): ctf = tl.generate_chrome_trace_format() self._validateTrace(ctf) + @test_util.run_deprecated_v1 def testTimelineCpu(self): run_options = config_pb2.RunOptions( trace_level=config_pb2.RunOptions.FULL_TRACE) diff --git a/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py index 7edaab81f4..b0516573f5 100644 --- a/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py @@ -35,6 +35,7 @@ from tensorflow.python.util import compat as util_compat class CopyToDeviceTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testCopyToDevice(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( @@ -61,6 +62,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyToDeviceInt32(self): host_dataset = dataset_ops.Dataset.from_tensors([0, 1, 2, 3]) device_dataset = host_dataset.apply( @@ -86,6 +88,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyToSameDevice(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( @@ -112,6 +115,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyToDeviceWithPrefetch(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( @@ -138,6 +142,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyDictToDevice(self): host_dataset = dataset_ops.Dataset.range(10).map(lambda x: {"a": x}) device_dataset = host_dataset.apply( @@ -164,6 +169,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyDictToDeviceWithPrefetch(self): host_dataset = dataset_ops.Dataset.range(10).map(lambda x: {"a": x}) device_dataset = host_dataset.apply( @@ -190,6 +196,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopySparseTensorsToDevice(self): def make_tensor(i): @@ -224,6 +231,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopySparseTensorsToDeviceWithPrefetch(self): def make_tensor(i): @@ -426,6 +434,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyToDeviceWithReInit(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( @@ -456,6 +465,7 @@ class CopyToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testCopyToDeviceWithReInitAndPrefetch(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( diff --git a/tensorflow/python/data/experimental/kernel_tests/counter_test.py b/tensorflow/python/data/experimental/kernel_tests/counter_test.py index d1dd07a879..b370e0029e 100644 --- a/tensorflow/python/data/experimental/kernel_tests/counter_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/counter_test.py @@ -20,11 +20,13 @@ from __future__ import print_function from tensorflow.python.data.experimental.ops import counter from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class CounterTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testCounter(self): """Test dataset construction using `count`.""" iterator = (counter.Counter(start=3, step=4) diff --git a/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py b/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py index d9bbfb9c99..4b84446be8 100644 --- a/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py @@ -24,12 +24,14 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test class DenseToSparseBatchTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testDenseToSparseBatchDataset(self): components = np.random.randint(12, size=(100,)).astype(np.int32) iterator = ( @@ -58,6 +60,7 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next) + @test_util.run_deprecated_v1 def testDenseToSparseBatchDatasetWithUnknownShape(self): components = np.random.randint(5, size=(40,)).astype(np.int32) iterator = ( @@ -91,12 +94,14 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next) + @test_util.run_deprecated_v1 def testDenseToSparseBatchDatasetWithInvalidShape(self): input_tensor = array_ops.constant([[1]]) with self.assertRaisesRegexp(ValueError, "Dimension -2 must be >= 0"): dataset_ops.Dataset.from_tensors(input_tensor).apply( batching.dense_to_sparse_batch(4, [-2])).make_initializable_iterator() + @test_util.run_deprecated_v1 def testDenseToSparseBatchDatasetShapeErrors(self): input_tensor = array_ops.placeholder(dtypes.int32) iterator = ( diff --git a/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py index 768a8d774b..269c27dde2 100644 --- a/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py @@ -24,11 +24,13 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testBasic(self): selector_dataset = dataset_ops.Dataset.range(10).repeat(100) input_datasets = [ @@ -77,6 +79,7 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): return freqs + @test_util.run_deprecated_v1 def testSampleFromDatasets(self): random_seed.set_random_seed(1619) num_samples = 5000 @@ -96,6 +99,7 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): freqs = self._testSampleFromDatasetsHelper(probs_ds, classes, num_samples) self.assertLess(self._chi2(probs, freqs / num_samples), 1e-2) + @test_util.run_deprecated_v1 def testSelectFromDatasets(self): words = [b"foo", b"bar", b"baz"] datasets = [dataset_ops.Dataset.from_tensors(w).repeat() for w in words] diff --git a/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py index f32d1d0a6f..3c2e1bb7f3 100644 --- a/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py @@ -24,11 +24,13 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class EnumerateDatasetTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testEnumerateDataset(self): components = (["a", "b"], [1, 2], [37.0, 38]) start = constant_op.constant(20, dtype=dtypes.int64) diff --git a/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py b/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py index 860442571e..a78fb4d229 100644 --- a/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py @@ -107,11 +107,13 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): self.assertEqual(elem, [5.0]) self.evaluate(destroy_op) + @test_util.run_deprecated_v1 def testSameDeviceCPU(self): self._prefetch_fn_helper_one_shot("same_device_cpu", "/job:localhost/replica:0/task:0/cpu:0", "/job:localhost/replica:0/task:0/cpu:0") + @test_util.run_deprecated_v1 def testDifferentDeviceCPU(self): self._prefetch_fn_helper_one_shot("diff_device_cpu", "/job:localhost/replica:0/task:0/cpu:0", @@ -125,6 +127,7 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): "/job:localhost/replica:0/task:0/cpu:0", "/job:localhost/replica:0/task:0/gpu:0") + @test_util.run_deprecated_v1 def testReinitialization(self): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) @@ -165,6 +168,7 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): self.assertEqual(elem, [5.0]) self.evaluate(destroy_op) + @test_util.run_deprecated_v1 def testReinitializationOutOfRange(self): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) diff --git a/tensorflow/python/data/experimental/kernel_tests/get_single_element_test.py b/tensorflow/python/data/experimental/kernel_tests/get_single_element_test.py index 0147988c59..ef576563a1 100644 --- a/tensorflow/python/data/experimental/kernel_tests/get_single_element_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/get_single_element_test.py @@ -25,6 +25,7 @@ from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test @@ -39,6 +40,7 @@ class GetSingleElementTest(test_base.DatasetTestBase, parameterized.TestCase): ("MoreThanOne", 0, 2, errors.InvalidArgumentError, "Dataset had more than one element."), ) + @test_util.run_deprecated_v1 def testGetSingleElement(self, skip, take, error=None, error_msg=None): skip_t = array_ops.placeholder(dtypes.int64, shape=[]) take_t = array_ops.placeholder(dtypes.int64, shape=[]) diff --git a/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py b/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py index f9856500c5..c7366f6641 100644 --- a/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py @@ -27,6 +27,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -44,6 +45,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next) + @test_util.run_deprecated_v1 def testSum(self): reducer = grouping.Reducer( init_func=lambda _: np.int64(0), @@ -55,6 +57,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): self.checkResults( dataset, shapes=tensor_shape.scalar(), values=[(i - 1) * i, i * i]) + @test_util.run_deprecated_v1 def testAverage(self): def reduce_fn(x, y): @@ -72,6 +75,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): self.checkResults( dataset, shapes=tensor_shape.scalar(), values=[i - 1, i]) + @test_util.run_deprecated_v1 def testConcat(self): components = np.array(list("abcdefghijklmnopqrst")).view(np.chararray) reducer = grouping.Reducer( @@ -88,6 +92,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): shapes=tensor_shape.scalar(), values=[b"acegikmoqs" [:i], b"bdfhjlnprt" [:i]]) + @test_util.run_deprecated_v1 def testSparseSum(self): def _sparse(i): return sparse_tensor.SparseTensorValue( @@ -105,6 +110,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): self.checkResults( dataset, shapes=tensor_shape.scalar(), values=[(i - 1) * i, i * i]) + @test_util.run_deprecated_v1 def testChangingStateShape(self): def reduce_fn(x, _): diff --git a/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py b/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py index d5a36e7cb1..1e54091c7d 100644 --- a/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py @@ -27,6 +27,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import string_ops @@ -49,6 +50,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): 32, (tensor_shape.TensorShape([]), tensor_shape.TensorShape( [None]), tensor_shape.TensorShape([3]))))) + @test_util.run_deprecated_v1 def testSingleBucket(self): def _map_fn(v): @@ -84,6 +86,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertAllEqual(expected_unk_int64, bucketed_values[1]) self.assertAllEqual(expected_vec3_str, bucketed_values[2]) + @test_util.run_deprecated_v1 def testEvenOddBuckets(self): def _map_fn(v): @@ -141,6 +144,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertAllEqual(expected_unk_int64, bucketed_values_odd[1]) self.assertAllEqual(expected_vec3_str, bucketed_values_odd[2]) + @test_util.run_deprecated_v1 def testEvenOddBucketsFilterOutAllOdd(self): def _map_fn(v): @@ -188,6 +192,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertAllEqual( np.arange(64, 128, 2, dtype=np.int64), bucketed_values_even1["x"]) + @test_util.run_deprecated_v1 def testDynamicWindowSize(self): components = np.arange(100).astype(np.int64) @@ -221,6 +226,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertEqual(batches, 15) + @test_util.run_deprecated_v1 def testSimple(self): components = np.random.randint(100, size=(200,)).astype(np.int64) iterator = ( @@ -248,6 +254,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertGreaterEqual(num_full_batches, 24) self.assertTrue(all(c == 4 for c in counts[:num_full_batches])) + @test_util.run_deprecated_v1 def testImmediateOutput(self): components = np.array( [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 0, 0, 2, 2, 0, 0], dtype=np.int64) @@ -270,6 +277,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertAllEqual([2, 2, 2, 2], self.evaluate(get_next)) self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) + @test_util.run_deprecated_v1 def testSmallGroups(self): components = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], dtype=np.int64) iterator = ( @@ -288,6 +296,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): self.assertAllEqual([0, 0, 0], self.evaluate(get_next)) self.assertAllEqual([1], self.evaluate(get_next)) + @test_util.run_deprecated_v1 def testEmpty(self): iterator = ( dataset_ops.Dataset.range(4).apply( @@ -303,6 +312,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): "Window size must be greater than zero, but got 0."): print(self.evaluate(get_next)) + @test_util.run_deprecated_v1 def testReduceFuncError(self): components = np.random.randint(100, size=(200,)).astype(np.int64) @@ -327,6 +337,7 @@ class GroupByWindowTest(test_base.DatasetTestBase): with self.assertRaises(errors.InvalidArgumentError): self.evaluate(get_next) + @test_util.run_deprecated_v1 def testConsumeWindowDatasetMoreThanOnce(self): components = np.random.randint(50, size=(200,)).astype(np.int64) diff --git a/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py b/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py index 522b196060..bd323592e4 100644 --- a/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py @@ -25,6 +25,7 @@ from tensorflow.python.data.experimental.ops import error_ops from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import io_ops from tensorflow.python.platform import test @@ -35,6 +36,7 @@ _NUMPY_RANDOM_SEED = 42 class IgnoreErrorsTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testMapIgnoreError(self): components = np.array([1., 2., 3., np.nan, 5.]).astype(np.float32) @@ -53,6 +55,7 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next) + @test_util.run_deprecated_v1 def testParallelMapIgnoreError(self): components = np.array([1., 2., 3., np.nan, 5.]).astype(np.float32) @@ -71,6 +74,7 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next) + @test_util.run_deprecated_v1 def testReadFileIgnoreError(self): def write_string_to_file(value, filename): diff --git a/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py b/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py index 0a436034a8..c3c4ccd077 100644 --- a/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_experimental_dataset_ops as ged_ops from tensorflow.python.platform import test @@ -31,6 +32,7 @@ from tensorflow.python.platform import test class IndexedDatasetOpsTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testLowLevelIndexedDatasetOps(self): identity = ged_ops.experimental_identity_indexed_dataset( ops.convert_to_tensor(16, dtype=dtypes.uint64)) @@ -49,6 +51,7 @@ class IndexedDatasetOpsTest(test_base.DatasetTestBase): self.evaluate(materialize) self.assertEqual([3], sess.run(get_op, feed_dict={index: 3})) + @test_util.run_deprecated_v1 def testIdentityIndexedDataset(self): ds = indexed_dataset_ops.IdentityIndexedDataset(16) materialized = ds.materialize() diff --git a/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py index 109b3696b8..48916471b3 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py @@ -26,6 +26,7 @@ from tensorflow.python.data.util import nest from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import io_ops from tensorflow.python.ops import parsing_ops from tensorflow.python.platform import test @@ -98,6 +99,7 @@ class MakeBatchedFeaturesDatasetTest( with self.assertRaises(errors.OutOfRangeError): self._next_actual_batch(sess) + @test_util.run_deprecated_v1 def testReadWithEquivalentDataset(self): features = { "file": parsing_ops.FixedLenFeature([], dtypes.int64), diff --git a/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py index 1f509384d7..bcbaf1a7c4 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py @@ -30,6 +30,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -127,6 +128,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): self._verify_output(sess, dataset, batch_size, num_epochs, label_name, expected_output, expected_keys) + @test_util.run_deprecated_v1 def testMakeCSVDataset(self): """Tests making a CSV dataset with keys and defaults provided.""" record_defaults = [ @@ -158,6 +160,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): column_defaults=record_defaults, ) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withBatchSizeAndEpochs(self): """Tests making a CSV dataset with keys and defaults provided.""" record_defaults = [ @@ -189,6 +192,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): column_defaults=record_defaults, ) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withCompressionType(self): """Tests `compression_type` argument.""" record_defaults = [ @@ -257,6 +261,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): label_name="not_a_real_label", column_names=column_names) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withNoLabel(self): """Tests making a CSV dataset with no label provided.""" record_defaults = [ @@ -286,6 +291,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): column_defaults=record_defaults, ) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withNoHeader(self): """Tests that datasets can be created from CSV files with no header line. """ @@ -347,6 +353,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): column_defaults=record_defaults, ) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withNoColNames(self): """Tests that datasets can be created when column names are not specified. @@ -451,6 +458,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): header=True, ) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withSelectCols(self): record_defaults = [ constant_op.constant([], dtypes.int32), @@ -557,6 +565,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): label_name=None, select_columns=["invalid_col_name"]) + @test_util.run_deprecated_v1 def testMakeCSVDataset_withShuffle(self): record_defaults = [ constant_op.constant([], dtypes.int32), diff --git a/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py b/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py index 8449c0651d..fc97f63358 100644 --- a/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops @@ -48,6 +49,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("ParallelCallsNUMA", 2, None, True), ("ParallelBatchesNUMA", None, 10, True), ) + @test_util.run_deprecated_v1 def testMapAndBatch(self, num_parallel_calls, num_parallel_batches, numa_aware): """Test a dataset that maps a TF function across its input elements.""" @@ -132,6 +134,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("EvenNUMA", False, True), ("UnevenNUMA", True, True), ) + @test_util.run_deprecated_v1 def testMapAndBatchPartialBatch(self, drop_remainder, numa_aware): dataset = ( dataset_ops.Dataset.range(10).apply( @@ -163,6 +166,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchYieldsPartialBatch(self, numa_aware): dataset = ( dataset_ops.Dataset.range(10).apply( @@ -187,6 +191,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchParallelGetNext(self, numa_aware): dataset = dataset_ops.Dataset.range(50000).apply( batching.map_and_batch(lambda x: x, batch_size=100)) @@ -214,6 +219,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchParallelGetNextDropRemainder(self, numa_aware): dataset = dataset_ops.Dataset.range(49999).apply( batching.map_and_batch( @@ -243,6 +249,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchSparse(self, numa_aware): def _sparse(i): @@ -277,6 +284,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchFails(self, numa_aware): """Test a dataset that maps a TF function across its input elements.""" dataset = dataset_ops.Dataset.from_tensors( @@ -299,6 +307,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchShapeMismatch(self, numa_aware): """Test a dataset that maps a TF function across its input elements.""" @@ -370,6 +379,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("5NUMA", 95, True), ("6NUMA", 99, True), ) + @test_util.run_deprecated_v1 def testMapAndBatchOutOfRangeError(self, threshold, numa_aware): def raising_py_fn(i): @@ -452,6 +462,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Swap", (None, None), lambda x, y: (y, x), None), ("Project", (None, None), lambda x, y: x, None), ) + @test_util.run_deprecated_v1 def testShortCircuit(self, structure, map_fn, num_parallel_calls): dataset = self.structuredDataset(structure).repeat().apply( batching.map_and_batch(map_fn, batch_size=10)) @@ -466,6 +477,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(self.structuredElement(structure, shape=[10]))) self.assertAllEqual(expected, self.evaluate(get_next)) + @test_util.run_deprecated_v1 def testShortCircuitCapturedInput(self): captured_t = array_ops.placeholder(dtypes.int64, shape=[]) dataset = self.structuredDataset(None).repeat().apply( @@ -481,6 +493,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): ("Normal", False), ("NUMA", True), ) + @test_util.run_deprecated_v1 def testMapAndBatchControlFlow(self, numa_aware): def map_fn(x): diff --git a/tensorflow/python/data/experimental/kernel_tests/matching_files_test.py b/tensorflow/python/data/experimental/kernel_tests/matching_files_test.py index 938dd4aff4..787a7a91a4 100644 --- a/tensorflow/python/data/experimental/kernel_tests/matching_files_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/matching_files_test.py @@ -24,6 +24,7 @@ import tempfile from tensorflow.python.data.experimental.ops import matching_files from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -40,6 +41,7 @@ class MatchingFilesTest(test_base.DatasetTestBase): for filename in filenames: open(os.path.join(self.tmp_dir, filename), 'a').close() + @test_util.run_deprecated_v1 def testNonExistingDirectory(self): """Test the MatchingFiles dataset with a non-existing directory.""" @@ -51,6 +53,7 @@ class MatchingFilesTest(test_base.DatasetTestBase): with self.assertRaises(errors.NotFoundError): sess.run(next_element) + @test_util.run_deprecated_v1 def testEmptyDirectory(self): """Test the MatchingFiles dataset with an empty directory.""" @@ -61,6 +64,7 @@ class MatchingFilesTest(test_base.DatasetTestBase): with self.assertRaises(errors.NotFoundError): sess.run(next_element) + @test_util.run_deprecated_v1 def testSimpleDirectory(self): """Test the MatchingFiles dataset with a simple directory.""" @@ -83,6 +87,7 @@ class MatchingFilesTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) + @test_util.run_deprecated_v1 def testFileSuffixes(self): """Test the MatchingFiles dataset using the suffixes of filename.""" @@ -104,6 +109,7 @@ class MatchingFilesTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) + @test_util.run_deprecated_v1 def testFileMiddles(self): """Test the MatchingFiles dataset using the middles of filename.""" @@ -125,6 +131,7 @@ class MatchingFilesTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(next_element) + @test_util.run_deprecated_v1 def testNestedDirectories(self): """Test the MatchingFiles dataset with nested directories.""" diff --git a/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py b/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py index 1dfe854f18..7116e7549f 100644 --- a/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py @@ -29,6 +29,7 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import script_ops from tensorflow.python.platform import test @@ -81,6 +82,7 @@ class OverrideThreadpoolTest(test_base.DatasetTestBase, ("8", 4, 1), ("9", 4, 4), ) + @test_util.run_deprecated_v1 def testNumThreadsDeprecated(self, num_threads, max_intra_op_parallelism): def override_threadpool_fn(dataset): @@ -107,6 +109,7 @@ class OverrideThreadpoolTest(test_base.DatasetTestBase, ("11", 4, 4), ("12", None, None), ) + @test_util.run_deprecated_v1 def testNumThreads(self, num_threads, max_intra_op_parallelism): def override_threadpool_fn(dataset): diff --git a/tensorflow/python/data/experimental/kernel_tests/parse_example_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/parse_example_dataset_test.py index c74f754fef..76e0d4d72a 100644 --- a/tensorflow/python/data/experimental/kernel_tests/parse_example_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/parse_example_dataset_test.py @@ -144,6 +144,7 @@ class ParseExampleDatasetTest(test_base.DatasetTestBase): expected_values=expected_output, create_iterator_twice=True) + @test_util.run_deprecated_v1 def testEmptySerializedWithoutDefaultsShouldFail(self): input_features = { "st_a": @@ -177,6 +178,7 @@ class ParseExampleDatasetTest(test_base.DatasetTestBase): expected_err=(errors_impl.InvalidArgumentError, "Feature: c \\(data type: float\\) is required")) + @test_util.run_deprecated_v1 def testDenseNotMatchingShapeShouldFail(self): original = [ example(features=features({ @@ -669,6 +671,7 @@ class ParseExampleDatasetTest(test_base.DatasetTestBase): for batch_size in (1, 10, 20, 100, 256): self._testSerializedContainingVarLenDenseLargerBatch(batch_size) + @test_util.run_deprecated_v1 def testSkipEagerSerializedShapeMismatch(self): aname = "a" bname = "b" @@ -706,6 +709,7 @@ class ParseExampleDatasetTest(test_base.DatasetTestBase): expected_err=(ValueError, "Cannot reshape a tensor with 0 elements to shape")) + @test_util.run_deprecated_v1 def testSerializedContainingVarLenDense(self): aname = "a" bname = "b" diff --git a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py index 8fc18e1ccd..56befc9e7d 100644 --- a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py @@ -31,6 +31,7 @@ from tensorflow.python.platform import test class PrefetchToDeviceTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testPrefetchToDevice(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( @@ -61,6 +62,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testPrefetchToSameDevice(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( @@ -91,6 +93,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testPrefetchDictToDevice(self): host_dataset = dataset_ops.Dataset.range(10).map(lambda x: {"a": x}) device_dataset = host_dataset.apply( @@ -121,6 +124,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testPrefetchSparseTensorsToDevice(self): def make_tensor(i): return sparse_tensor.SparseTensorValue( @@ -174,6 +178,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testPrefetchToDeviceWithReInit(self): host_dataset = dataset_ops.Dataset.range(10) device_dataset = host_dataset.apply( diff --git a/tensorflow/python/data/experimental/kernel_tests/rejection_resample_test.py b/tensorflow/python/data/experimental/kernel_tests/rejection_resample_test.py index 4c879dbae6..675209d189 100644 --- a/tensorflow/python/data/experimental/kernel_tests/rejection_resample_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/rejection_resample_test.py @@ -28,6 +28,7 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import string_ops @@ -63,6 +64,7 @@ class RejectionResampleTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( ("InitialDistributionKnown", True), ("InitialDistributionUnknown", False)) + @test_util.run_deprecated_v1 def testDistribution(self, initial_known): classes = np.random.randint(5, size=(20000,)) # Uniformly sampled target_dist = [0.9, 0.05, 0.05, 0.0, 0.0] @@ -97,6 +99,7 @@ class RejectionResampleTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( ("OnlyInitial", True), ("NotInitial", False)) + @test_util.run_deprecated_v1 def testEdgeCasesSampleFromInitialDataset(self, only_initial_dist): init_dist = [0.5, 0.5] target_dist = [0.5, 0.5] if only_initial_dist else [0.0, 1.0] @@ -122,6 +125,7 @@ class RejectionResampleTest(test_base.DatasetTestBase, parameterized.TestCase): while True: returned.append(sess.run(get_next)) + @test_util.run_deprecated_v1 def testRandomClasses(self): init_dist = [0.25, 0.25, 0.25, 0.25] target_dist = [0.0, 0.0, 0.0, 1.0] diff --git a/tensorflow/python/data/experimental/kernel_tests/restructured_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/restructured_dataset_test.py index 516e489d04..658e6120cf 100644 --- a/tensorflow/python/data/experimental/kernel_tests/restructured_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/restructured_dataset_test.py @@ -22,12 +22,14 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test class RestructuredDatasetTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testRestructureDataset(self): components = (array_ops.placeholder(dtypes.int32), (array_ops.placeholder(dtypes.int32, shape=[None]), diff --git a/tensorflow/python/data/experimental/kernel_tests/scan_test.py b/tensorflow/python/data/experimental/kernel_tests/scan_test.py index dc8a7bca27..43a765b9e0 100644 --- a/tensorflow/python/data/experimental/kernel_tests/scan_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/scan_test.py @@ -40,6 +40,7 @@ class ScanTest(test_base.DatasetTestBase): return dataset_ops.Dataset.from_tensors(0).repeat().apply( scan_ops.scan(start, scan_fn)) + @test_util.run_deprecated_v1 def testCount(self): def make_scan_fn(step): return lambda state, _: (state + step, state) @@ -83,6 +84,7 @@ class ScanTest(test_base.DatasetTestBase): self.assertEqual(5, self.evaluate(next_element())) self.assertEqual(8, self.evaluate(next_element())) + @test_util.run_deprecated_v1 def testSparseCount(self): def _sparse(i): return sparse_tensor.SparseTensorValue( @@ -114,6 +116,7 @@ class ScanTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testChangingStateShape(self): # Test the fixed-point shape invariant calculations: start with # initial values with known shapes, and use a scan function that diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/checkpoint_input_pipeline_hook_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/checkpoint_input_pipeline_hook_test.py index 94393d6d4b..140ed517ef 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/checkpoint_input_pipeline_hook_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/checkpoint_input_pipeline_hook_test.py @@ -26,6 +26,7 @@ from tensorflow.python.estimator import model_fn from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -68,6 +69,7 @@ class CheckpointInputPipelineHookTest(test_base.DatasetTestBase): def _build_iterator_saver_hook(self, est): return iterator_ops.CheckpointInputPipelineHook(est) + @test_util.run_deprecated_v1 def testReturnDatasetFromInputFn(self): def _input_fn(): @@ -80,6 +82,7 @@ class CheckpointInputPipelineHookTest(test_base.DatasetTestBase): est.train(_input_fn, steps=2, hooks=[self._build_iterator_saver_hook(est)]) self.assertSequenceEqual(self._read_vars(est.model_dir), (4, 3)) + @test_util.run_deprecated_v1 def testBuildIteratorInInputFn(self): def _input_fn(): @@ -94,6 +97,7 @@ class CheckpointInputPipelineHookTest(test_base.DatasetTestBase): est.train(_input_fn, steps=2, hooks=[self._build_iterator_saver_hook(est)]) self.assertSequenceEqual(self._read_vars(est.model_dir), (4, 3)) + @test_util.run_deprecated_v1 def testDoNotRestore(self): def _input_fn(): diff --git a/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py b/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py index 2e8b93feaf..ce63da6bf9 100644 --- a/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py @@ -24,6 +24,7 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -44,6 +45,7 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): self.evaluate(get_next) return outputs + @test_util.run_deprecated_v1 def testCorrectOutput(self): output = self._gen_outputs(lambda: self._build_ds(10), 100) self.assertSequenceEqual( @@ -52,6 +54,7 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): for i in range(5): self.assertSequenceEqual(sorted(output[i * 20:(i + 1) * 20]), range(20)) + @test_util.run_deprecated_v1 def testReshuffling(self): # Check that the output orders of different epochs are indeed different. output = self._gen_outputs(lambda: self._build_ds(10), 100) @@ -60,17 +63,20 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): epoch2 = output[(i + 1) * 20:(i + 2) * 20] self.assertNotEqual(epoch1, epoch2) + @test_util.run_deprecated_v1 def testSameOrderForSameSeeds(self): output1 = self._gen_outputs(lambda: self._build_ds(10), 100) output2 = self._gen_outputs(lambda: self._build_ds(10), 100) self.assertEqual(output1, output2) + @test_util.run_deprecated_v1 def testDifferentOrderForDifferentSeeds(self): output1 = self._gen_outputs(lambda: self._build_ds(10), 100) output2 = self._gen_outputs(lambda: self._build_ds(20), 100) self.assertNotEqual(output1, output2) self.assertEqual(sorted(output1), sorted(output2)) + @test_util.run_deprecated_v1 def testCountNone(self): output1 = self._gen_outputs( lambda: self._build_ds(10, count=None), 100, verify_exhausted=False) @@ -79,6 +85,7 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): self.assertNotEqual(output1, output2) self.assertEqual(sorted(output1), sorted(output2)) + @test_util.run_deprecated_v1 def testCountMinusOne(self): output1 = self._gen_outputs( lambda: self._build_ds(10, count=-1), 100, verify_exhausted=False) diff --git a/tensorflow/python/data/experimental/kernel_tests/sleep_test.py b/tensorflow/python/data/experimental/kernel_tests/sleep_test.py index 1a6d5522ef..8c9e8225d6 100644 --- a/tensorflow/python/data/experimental/kernel_tests/sleep_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/sleep_test.py @@ -23,6 +23,7 @@ from tensorflow.python.data.experimental.ops import sleep from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.platform import test _NUMPY_RANDOM_SEED = 42 @@ -30,6 +31,7 @@ _NUMPY_RANDOM_SEED = 42 class SleepTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testSleep(self): sleep_microseconds = 100 dataset = dataset_ops.Dataset.range(10).apply( diff --git a/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py b/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py index e816006933..b89aa20432 100644 --- a/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py @@ -30,6 +30,7 @@ from tensorflow.python.data.experimental.ops import stats_options from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -59,6 +60,7 @@ def function_apply_options(dataset, aggregator, prefix="", counter_prefix=""): ) class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): + @test_util.run_deprecated_v1 def testBytesProduced(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).map( @@ -85,6 +87,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount(summary_str, "bytes_produced", 100.0) self._assertSummaryHasSum(summary_str, "bytes_produced", expected_sum) + @test_util.run_deprecated_v1 def testLatencyStats(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).apply( @@ -105,6 +108,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount( self.evaluate(summary_t), "record_latency", 100.0) + @test_util.run_deprecated_v1 def testPrefetchBufferUtilization(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).map( @@ -132,6 +136,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount(summary_str, "Prefetch::buffer_utilization", 100) + @test_util.run_deprecated_v1 def testPrefetchBufferScalars(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(10).map( @@ -154,6 +159,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testFilteredElementsStats(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(101).filter( @@ -180,6 +186,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasScalarValue( self.evaluate(summary_t), "Filter::filtered_elements", 34.0) + @test_util.run_deprecated_v1 def testMapBufferUtilization(self, dataset_transformation): def dataset_fn(): @@ -194,6 +201,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): dataset_transformation, function_processing_time=True) + @test_util.run_deprecated_v1 def testMapAutoTuneBufferUtilization(self, dataset_transformation): def dataset_fn(): @@ -211,6 +219,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): dataset_transformation, function_processing_time=True) + @test_util.run_deprecated_v1 def testInterleaveAutoTuneBufferUtilization(self, dataset_transformation): def dataset_fn(): @@ -227,6 +236,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._testParallelCallsStats(dataset_fn, "ParallelInterleaveV2", 10, dataset_transformation) + @test_util.run_deprecated_v1 def testMapAndBatchAutoTuneBufferUtilization(self, dataset_transformation): def dataset_fn(): @@ -248,6 +258,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): check_elements=False, function_processing_time=True) + @test_util.run_deprecated_v1 def testReinitialize(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).apply( @@ -270,6 +281,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount( self.evaluate(summary_t), "record_latency", (j + 1) * 100.0) + @test_util.run_deprecated_v1 def testNoAggregatorRegistered(self, dataset_transformation): dataset = dataset_ops.Dataset.range(100).apply( stats_ops.latency_stats("record_latency")) @@ -283,6 +295,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testMultipleTags(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).apply( @@ -308,6 +321,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount( self.evaluate(summary_t), "record_latency_2", 100.0) + @test_util.run_deprecated_v1 def testRepeatedTags(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).apply( @@ -329,6 +343,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount( self.evaluate(summary_t), "record_latency", 200.0) + @test_util.run_deprecated_v1 def testMultipleIteratorsSameAggregator(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).apply( @@ -350,6 +365,7 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasCount( self.evaluate(summary_t), "record_latency", 200.0) + @test_util.run_deprecated_v1 def testMultipleDatasetWithPrefixes(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() dataset = dataset_ops.Dataset.range(100).apply( @@ -390,6 +406,7 @@ class FeatureStatsDatasetTest( stats_dataset_test_base.StatsDatasetTestBase, reader_dataset_ops_test_base.MakeBatchedFeaturesDatasetTestBase): + @test_util.run_deprecated_v1 def testFeaturesStats(self, dataset_transformation): num_epochs = 5 total_records = num_epochs * self._num_records diff --git a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py index cb94bb4144..9c6830d993 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import string_ops @@ -37,6 +38,7 @@ from tensorflow.python.util import compat class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testUnbatchWithUnknownRankInput(self): placeholder = array_ops.placeholder(dtypes.int32) dataset = dataset_ops.Dataset.from_tensors(placeholder).apply( @@ -51,6 +53,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_elem) + @test_util.run_deprecated_v1 def testUnbatchScalarDataset(self): data = tuple([math_ops.range(10) for _ in range(3)]) data = dataset_ops.Dataset.from_tensor_slices(data) @@ -70,6 +73,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(op) + @test_util.run_deprecated_v1 def testUnbatchDatasetWithStrings(self): data = tuple([math_ops.range(10) for _ in range(3)]) data = dataset_ops.Dataset.from_tensor_slices(data) @@ -90,6 +94,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(op) + @test_util.run_deprecated_v1 def testUnbatchDatasetWithSparseTensor(self): st = sparse_tensor.SparseTensorValue( indices=[[i, i] for i in range(10)], @@ -111,6 +116,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testUnbatchDatasetWithDenseAndSparseTensor(self): st = sparse_tensor.SparseTensorValue( indices=[[i, i] for i in range(10)], @@ -133,6 +139,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testUnbatchSingleElementTupleDataset(self): data = tuple([(math_ops.range(10),) for _ in range(3)]) data = dataset_ops.Dataset.from_tensor_slices(data) @@ -152,6 +159,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(op) + @test_util.run_deprecated_v1 def testUnbatchMultiElementTupleDataset(self): data = tuple([(math_ops.range(10 * i, 10 * i + 10), array_ops.fill([10], "hi")) for i in range(3)]) @@ -173,6 +181,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(op) + @test_util.run_deprecated_v1 def testUnbatchEmpty(self): data = dataset_ops.Dataset.from_tensors( (constant_op.constant([]), constant_op.constant([], shape=[0, 4]), @@ -191,6 +200,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(ValueError): data.apply(batching.unbatch()) + @test_util.run_deprecated_v1 def testUnbatchDynamicShapeMismatch(self): ph1 = array_ops.placeholder(dtypes.int32, shape=[None]) ph2 = array_ops.placeholder(dtypes.int32, shape=None) diff --git a/tensorflow/python/data/experimental/kernel_tests/unique_test.py b/tensorflow/python/data/experimental/kernel_tests/unique_test.py index 91f4bc84e9..ddec968858 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unique_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unique_test.py @@ -22,6 +22,7 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -57,6 +58,7 @@ class UniqueTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testSimpleInt(self): for dtype in [dtypes.int32, dtypes.int64]: self._testSimpleHelper(dtype, [ @@ -69,6 +71,7 @@ class UniqueTest(test_base.DatasetTestBase): ([[1, 1], [1, 1], [2, 2], [3, 3], [1, 1]], [[1, 1], [2, 2], [3, 3]]), ]) + @test_util.run_deprecated_v1 def testSimpleString(self): self._testSimpleHelper(dtypes.string, [ ([], []), diff --git a/tensorflow/python/data/kernel_tests/flat_map_test.py b/tensorflow/python/data/kernel_tests/flat_map_test.py index 5f11c2e3a7..ff52821b10 100644 --- a/tensorflow/python/data/kernel_tests/flat_map_test.py +++ b/tensorflow/python/data/kernel_tests/flat_map_test.py @@ -60,6 +60,7 @@ class FlatMapTest(test_base.DatasetTestBase): self.assertDatasetProduces(dataset, expected_output=expected_output) # Note: no eager mode coverage, session specific test. + @test_util.run_deprecated_v1 def testSkipEagerSharedResourceNestedFlatMapDataset(self): repeats = [[1, 2], [3, 4], [5, 0], [1, 7]] components = np.array(repeats, dtype=np.int64) diff --git a/tensorflow/python/data/kernel_tests/from_generator_test.py b/tensorflow/python/data/kernel_tests/from_generator_test.py index 4d82c2111c..d58e3c2364 100644 --- a/tensorflow/python/data/kernel_tests/from_generator_test.py +++ b/tensorflow/python/data/kernel_tests/from_generator_test.py @@ -27,6 +27,7 @@ from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import script_ops from tensorflow.python.platform import test @@ -69,6 +70,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorUsingFunction(self): def generator(): for i in range(1, 100): @@ -79,18 +81,21 @@ class FromGeneratorTest(test_base.DatasetTestBase): self._testFromGeneratorOneShot(generator, elem_sequence, 1) self._testFromGeneratorOneShot(generator, elem_sequence, 5) + @test_util.run_deprecated_v1 def testFromGeneratorUsingList(self): generator = lambda: [[i] * i for i in range(1, 100)] elem_sequence = list(generator()) self._testFromGenerator(generator, elem_sequence, 1) self._testFromGenerator(generator, elem_sequence, 5) + @test_util.run_deprecated_v1 def testFromGeneratorUsingNdarray(self): generator = lambda: np.arange(100, dtype=np.int64) elem_sequence = list(generator()) self._testFromGenerator(generator, elem_sequence, 1, output_types=np.int64) self._testFromGenerator(generator, elem_sequence, 5, output_types=np.int64) + @test_util.run_deprecated_v1 def testFromGeneratorUsingGeneratorExpression(self): # NOTE(mrry): Generator *expressions* are not repeatable (or in # general reusable), because they eagerly evaluate the `for` @@ -102,6 +107,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): self._testFromGenerator(generator, elem_sequence, 1) self._testFromGenerator(generator, elem_sequence, 5) + @test_util.run_deprecated_v1 def testFromMultipleConcurrentGenerators(self): num_inner_repeats = 5 num_outer_repeats = 100 @@ -199,6 +205,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorImplicitConversion(self): def generator(): yield [1] @@ -223,6 +230,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorString(self): def generator(): yield "foo" @@ -243,6 +251,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorTypeError(self): def generator(): yield np.array([1, 2, 3], dtype=np.int64) @@ -266,6 +275,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorShapeError(self): def generator(): yield np.array([1, 2, 3], dtype=np.int64) @@ -289,6 +299,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorStructureError(self): def generator(): yield 1, 2 @@ -317,6 +328,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorHeterogeneous(self): def generator(): yield 1 @@ -335,6 +347,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorStopShort(self): def generator(): @@ -353,6 +366,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): self.assertAllEqual(0, sess.run(get_next)) self.assertAllEqual(1, sess.run(get_next)) + @test_util.run_deprecated_v1 def testFromGeneratorDestructorCalled(self): # Use an `Event` to signal that the generator has been deleted. event = threading.Event() @@ -387,6 +401,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): # iterator terminates (and the generator iterator is deleted). self.assertTrue(event.is_set()) + @test_util.run_deprecated_v1 def testFromGeneratorWithArgs(self): def flat_map_fn(elem): @@ -414,6 +429,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testFromGeneratorWithTwoArgs(self): def flat_map_fn(elem, message): @@ -446,6 +462,7 @@ class FromGeneratorTest(test_base.DatasetTestBase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testGeneratorDatasetFinalizeFunctionCalled(self): # NOTE(mrry): This test tests the internal `_GeneratorDataset`, # which affords more control over what the finalize function can do than diff --git a/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py b/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py index d23ac0ebe9..80ed26e7fb 100644 --- a/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py +++ b/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py @@ -32,6 +32,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes class FromSparseTensorSlicesTest(test_base.DatasetTestBase): + @test_util.run_deprecated_v1 def testSkipEagerFromSparseTensorSlices(self): """Test a dataset based on slices of a `tf.SparseTensor`.""" st = array_ops.sparse_placeholder(dtypes.float64) diff --git a/tensorflow/python/data/kernel_tests/from_tensors_test.py b/tensorflow/python/data/kernel_tests/from_tensors_test.py index 2857817e14..ce70637572 100644 --- a/tensorflow/python/data/kernel_tests/from_tensors_test.py +++ b/tensorflow/python/data/kernel_tests/from_tensors_test.py @@ -154,6 +154,7 @@ class FromTensorsTest(test_base.DatasetTestBase): self.assertEquals(([], ([], []), []), dataset.output_shapes) # TODO(b/117581999): more specific shapes in eager mode. + @test_util.run_deprecated_v1 def testSkipEagerNestedStructure(self): components = (np.array([1, 2, 3], dtype=np.int64), (np.array([4., 5.]), np.array([6., 7.])), diff --git a/tensorflow/python/data/kernel_tests/iterator_test.py b/tensorflow/python/data/kernel_tests/iterator_test.py index de95a53e57..b836a6aecf 100644 --- a/tensorflow/python/data/kernel_tests/iterator_test.py +++ b/tensorflow/python/data/kernel_tests/iterator_test.py @@ -55,6 +55,7 @@ from tensorflow.python.util import compat class IteratorTest(test.TestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testNoGradients(self): component = constant_op.constant([1.]) side = constant_op.constant(0.) @@ -65,6 +66,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): self.assertIsNone(gradients_impl.gradients(value, side)[0]) self.assertIsNone(gradients_impl.gradients(value, [component, side])[0]) + @test_util.run_deprecated_v1 def testCapturingStateInOneShotRaisesException(self): var = variables.Variable(37.0, name="myvar") dataset = ( @@ -75,6 +77,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): "datasets that capture stateful objects.+myvar"): dataset.make_one_shot_iterator() + @test_util.run_deprecated_v1 def testOneShotIterator(self): components = (np.arange(7), np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], @@ -100,6 +103,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testOneShotIteratorCaptureByValue(self): components = (np.arange(7), np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], @@ -162,6 +166,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testOneShotIteratorNonBlocking(self): dataset = dataset_ops.Dataset.from_tensors([1, 2, 3]).map(lambda x: x * x) iterator = dataset.make_one_shot_iterator() @@ -200,6 +205,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): len([None for r in results if r is None])) self.assertAllEqual([[1, 4, 9]], [r for r in results if r is not None]) + @test_util.run_deprecated_v1 def testOneShotIteratorInitializerFails(self): # Define a dataset whose initialization will always fail. dataset = dataset_ops.Dataset.from_tensors( @@ -280,6 +286,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testNotInitializedError(self): components = (np.array(1), np.array([1, 2, 3]), np.array(37.0)) iterator = ( @@ -292,6 +299,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): "iterator has not been initialized"): sess.run(get_next) + @test_util.run_deprecated_v1 def testReinitializableIterator(self): dataset_3 = dataset_ops.Dataset.from_tensors( constant_op.constant([1, 2, 3])) @@ -331,6 +339,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + @test_util.run_deprecated_v1 def testReinitializableIteratorWithFunctions(self): def g(): @@ -390,6 +399,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): (constant_op.constant([1, 2, 3], dtype=dtypes.int64), constant_op.constant([4., 5., 6., 7.], dtype=dtypes.float64)))) + @test_util.run_deprecated_v1 def testIteratorStringHandle(self): dataset_3 = dataset_ops.Dataset.from_tensor_slices([1, 2, 3]) dataset_4 = dataset_ops.Dataset.from_tensor_slices([10, 20, 30, 40]) @@ -445,6 +455,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): sess.run( next_element, feed_dict={handle_placeholder: iterator_4_handle}) + @test_util.run_deprecated_v1 def testIteratorStringHandleFuture(self): with forward_compat.forward_compatibility_horizon(2018, 8, 4): dataset_3 = dataset_ops.Dataset.from_tensor_slices([1, 2, 3]) @@ -508,6 +519,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): sess.run( next_element, feed_dict={handle_placeholder: iterator_4_handle}) + @test_util.run_deprecated_v1 def testIteratorStringHandleReuseTensorObject(self): dataset = dataset_ops.Dataset.from_tensor_slices([1, 2, 3]) one_shot_iterator = dataset.make_one_shot_iterator() @@ -536,6 +548,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): self.assertEqual("foo_1", handle_with_same_name.op.name) self.assertIsNot(handle_with_name, handle_with_same_name) + @test_util.run_deprecated_v1 def testIteratorStringHandleError(self): dataset_int_scalar = ( dataset_ops.Dataset.from_tensor_slices([1, 2, 3]).repeat()) @@ -576,6 +589,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): feedable_int_vector.get_next(), feed_dict={handle_placeholder: handle_float_vector})) + @test_util.run_deprecated_v1 def testRemoteIteratorUsingRemoteCallOpDirectSession(self): worker_config = config_pb2.ConfigProto() worker_config.device_count["CPU"] = 3 @@ -632,6 +646,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): target_placeholder: "/job:localhost/replica:0/task:0/cpu:1" }) + @test_util.run_deprecated_v1 def testRemoteIteratorUsingRemoteCallOpMultiWorkers(self): s1 = server_lib.Server.create_local_server() s2 = server_lib.Server.create_local_server() @@ -739,6 +754,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): target_placeholder: "/job:localhost/replica:0/task:0/cpu:0" }) + @test_util.run_deprecated_v1 def testIncorrectIteratorRestore(self): def _path(): @@ -797,6 +813,7 @@ class IteratorTest(test.TestCase, parameterized.TestCase): with self.assertRaises(errors.InvalidArgumentError): sess.run(restore_op) + @test_util.run_deprecated_v1 def testRepeatedGetNextWarning(self): iterator = dataset_ops.Dataset.range(10).make_one_shot_iterator() warnings.simplefilter("always") diff --git a/tensorflow/python/data/kernel_tests/list_files_test.py b/tensorflow/python/data/kernel_tests/list_files_test.py index 26c536086b..789f1ab6de 100644 --- a/tensorflow/python/data/kernel_tests/list_files_test.py +++ b/tensorflow/python/data/kernel_tests/list_files_test.py @@ -44,6 +44,7 @@ class ListFilesTest(test_base.DatasetTestBase): open(path.join(self.tmp_dir, filename), 'a').close() # Note: eager mode fails in assertion error same as initializer in graph mode. + @test_util.run_deprecated_v1 def testSkipEagerEmptyDirectory(self): dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*')) self.assertDatasetProduces(dataset, expected_output=[]) diff --git a/tensorflow/python/data/kernel_tests/optional_test.py b/tensorflow/python/data/kernel_tests/optional_test.py index 864013171d..c2c62e9423 100644 --- a/tensorflow/python/data/kernel_tests/optional_test.py +++ b/tensorflow/python/data/kernel_tests/optional_test.py @@ -74,6 +74,7 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertAllEqual(expected.dense_shape, self.evaluate(actual.dense_shape)) + @test_util.run_deprecated_v1 def testFromNone(self): value_structure = structure.TensorStructure(dtypes.float32, []) opt = optional_ops.Optional.none_from_structure(value_structure) @@ -267,6 +268,7 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): optional_ops.OptionalStructure( structure.TensorStructure(dtypes.float32, []))), ) + @test_util.run_deprecated_v1 def testSkipEagerOptionalStructure(self, tf_value_fn, expected_value_structure): tf_value = tf_value_fn() @@ -322,6 +324,7 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): indices=[[0, 1], [1, 0]], values=[37.0, 42.0], dense_shape=[2, 2])}, False), ) + @test_util.run_deprecated_v1 def testSkipEagerIteratorGetNextAsOptional(self, np_value, tf_value_fn, works_on_gpu): if not works_on_gpu and test.is_gpu_available(): diff --git a/tensorflow/python/data/kernel_tests/padded_batch_test.py b/tensorflow/python/data/kernel_tests/padded_batch_test.py index 5f20d7b424..dcfb2f507b 100644 --- a/tensorflow/python/data/kernel_tests/padded_batch_test.py +++ b/tensorflow/python/data/kernel_tests/padded_batch_test.py @@ -93,6 +93,7 @@ class PaddedBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next()) + @test_util.run_deprecated_v1 def testPaddedBatchShortPadding(self): dataset = ( dataset_ops.Dataset.from_tensor_slices( @@ -155,6 +156,7 @@ class PaddedBatchTest(test_base.DatasetTestBase, parameterized.TestCase): next_element = self.getNext(padded_dataset) self.evaluate(next_element()) + @test_util.run_deprecated_v1 def testSkipEagerPaddedBatchDatasetShapeSpecifications(self): int_placeholder = array_ops.placeholder(dtypes.int32) float_placeholder = array_ops.placeholder(dtypes.float32) @@ -226,6 +228,7 @@ class PaddedBatchTest(test_base.DatasetTestBase, parameterized.TestCase): _ = dataset_ops.Dataset.range(10).padded_batch( 5, padded_shapes=shape_as_tensor) + @test_util.run_deprecated_v1 def testSkipEagerPaddedBatchShapeError(self): with self.assertRaisesRegexp( ValueError, diff --git a/tensorflow/python/data/kernel_tests/reduce_test.py b/tensorflow/python/data/kernel_tests/reduce_test.py index d7b653961d..14bbc0bf72 100644 --- a/tensorflow/python/data/kernel_tests/reduce_test.py +++ b/tensorflow/python/data/kernel_tests/reduce_test.py @@ -68,6 +68,7 @@ class ReduceTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual(((i + 1) * i) // 2, s) self.assertEqual(i, c) + @test_util.run_deprecated_v1 def testSkipEagerSquareUsingPlaceholder(self): delta = array_ops.placeholder(dtype=dtypes.int64) diff --git a/tensorflow/python/data/kernel_tests/shuffle_test.py b/tensorflow/python/data/kernel_tests/shuffle_test.py index 49460a1a4e..05d5d814c0 100644 --- a/tensorflow/python/data/kernel_tests/shuffle_test.py +++ b/tensorflow/python/data/kernel_tests/shuffle_test.py @@ -115,6 +115,7 @@ class ShuffleTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next()) + @test_util.run_deprecated_v1 def testSkipEagerSeedZero(self): """Test for same behavior when the seed is a Python or Tensor zero.""" iterator = ( diff --git a/tensorflow/python/data/util/convert_test.py b/tensorflow/python/data/util/convert_test.py index 3058e2b3f6..78ca6e9513 100644 --- a/tensorflow/python/data/util/convert_test.py +++ b/tensorflow/python/data/util/convert_test.py @@ -22,6 +22,7 @@ from tensorflow.python.data.util import convert from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -60,6 +61,7 @@ class ConvertTest(test.TestCase): convert.partial_shape_to_tensor( constant_op.constant([1], dtype=dtypes.int64)))) + @test_util.run_deprecated_v1 def testPartialShapeToTensorUnknownDimension(self): self.assertAllEqual([-1], self.evaluate( diff --git a/tensorflow/python/data/util/sparse_test.py b/tensorflow/python/data/util/sparse_test.py index 4ba314f06a..06acf55ab9 100644 --- a/tensorflow/python/data/util/sparse_test.py +++ b/tensorflow/python/data/util/sparse_test.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -296,6 +297,7 @@ class SparseTest(test.TestCase): self.assertAllEqual(a.eval().values, self.evaluate(b).values) self.assertAllEqual(a.eval().dense_shape, self.evaluate(b).dense_shape) + @test_util.run_deprecated_v1 def testSerializeDeserialize(self): test_cases = ( (), @@ -325,6 +327,7 @@ class SparseTest(test.TestCase): for a, e in zip(nest.flatten(actual), nest.flatten(expected)): self.assertSparseValuesEqual(a, e) + @test_util.run_deprecated_v1 def testSerializeManyDeserialize(self): test_cases = ( (), diff --git a/tensorflow/python/data/util/structure_test.py b/tensorflow/python/data/util/structure_test.py index 65a41a50f1..e9e2f5be0a 100644 --- a/tensorflow/python/data/util/structure_test.py +++ b/tensorflow/python/data/util/structure_test.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -115,6 +116,7 @@ class StructureTest(test.TestCase, parameterized.TestCase): indices=[[0], [1], [2]], values=[4, 5, 6], dense_shape=[3]) }, (constant_op.constant(15.0), constant_op.constant([4, 5, 6]))]), ) + @test_util.run_deprecated_v1 def testIsCompatibleWithStructure( self, original_value_fn, compatible_values_fn, incompatible_values_fn): original_value = original_value_fn() diff --git a/tensorflow/python/debug/cli/analyzer_cli_test.py b/tensorflow/python/debug/cli/analyzer_cli_test.py index 5aa7d1bb4c..322ecf9466 100644 --- a/tensorflow/python/debug/cli/analyzer_cli_test.py +++ b/tensorflow/python/debug/cli/analyzer_cli_test.py @@ -645,6 +645,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): self.assertEqual(len("Size (B)") + 1, dump_size_col_width) self.assertEqual(len("Op type") + 1, op_type_col_width) + @test_util.run_deprecated_v1 def testMeasureTensorListColumnWidthsGivesRightAnswerForData(self): dump = self._debug_dump.dumped_tensor_data[0] self.assertLess(dump.dump_size_bytes, 1000) @@ -660,6 +661,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): # column should be determined by the length of "VariableV2". self.assertEqual(len("VariableV2") + 1, op_type_col_width) + @test_util.run_deprecated_v1 def testListTensors(self): # Use shorthand alias for the command prefix. out = self._registry.dispatch_command("lt", []) @@ -673,6 +675,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): # Check the main menu. check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsInReverseTimeOrderWorks(self): # Use shorthand alias for the command prefix. out = self._registry.dispatch_command("lt", ["-s", "timestamp", "-r"]) @@ -688,6 +691,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): reverse=True) check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsInDumpSizeOrderWorks(self): out = self._registry.dispatch_command("lt", ["-s", "dump_size"]) assert_listed_tensors( @@ -701,6 +705,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): sort_by="dump_size") check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsInReverseDumpSizeOrderWorks(self): out = self._registry.dispatch_command("lt", ["-s", "dump_size", "-r"]) assert_listed_tensors( @@ -720,6 +725,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): self.assertIn("ValueError: Unsupported key to sort tensors by: foobar", out.lines) + @test_util.run_deprecated_v1 def testListTensorsInOpTypeOrderWorks(self): # Use shorthand alias for the command prefix. out = self._registry.dispatch_command("lt", ["-s", "op_type"]) @@ -735,6 +741,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): reverse=False) check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsInReverseOpTypeOrderWorks(self): # Use shorthand alias for the command prefix. out = self._registry.dispatch_command("lt", ["-s", "op_type", "-r"]) @@ -750,6 +757,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): reverse=True) check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsInTensorNameOrderWorks(self): # Use shorthand alias for the command prefix. out = self._registry.dispatch_command("lt", ["-s", "tensor_name"]) @@ -765,6 +773,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): reverse=False) check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsInReverseTensorNameOrderWorks(self): # Use shorthand alias for the command prefix. out = self._registry.dispatch_command("lt", ["-s", "tensor_name", "-r"]) @@ -780,6 +789,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): reverse=True) check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorsFilterByNodeNameRegex(self): out = self._registry.dispatch_command("list_tensors", ["--node_name_filter", ".*read.*"]) @@ -793,6 +803,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): assert_listed_tensors(self, out, [], [], node_name_regex="^read") check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorFilterByOpTypeRegex(self): out = self._registry.dispatch_command("list_tensors", ["--op_type_filter", "Identity"]) @@ -821,6 +832,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): op_type_regex="(Add|MatMul)") check_main_menu(self, out, list_tensors_enabled=False) + @test_util.run_deprecated_v1 def testListTensorWithFilterAndNodeNameExclusionWorks(self): # First, create and register the filter. def is_2x1_vector(datum, tensor): @@ -877,6 +889,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): out = self._registry.dispatch_command("list_tensors", ["--bar"]) check_syntax_error_output(self, out, "list_tensors") + @test_util.run_deprecated_v1 def testNodeInfoByNodeName(self): node_name = "simple_mul_add/matmul" out = self._registry.dispatch_command("node_info", [node_name]) @@ -901,6 +914,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): [(len(out.lines[0]) - len(node_name), len(out.lines[0]), "bold")], out.font_attr_segs[0]) + @test_util.run_deprecated_v1 def testNodeInfoShowAttributes(self): node_name = "simple_mul_add/matmul" out = self._registry.dispatch_command("node_info", ["-a", node_name]) @@ -924,6 +938,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): print_tensor_node_name=node_name, list_outputs_node_name=node_name) + @test_util.run_deprecated_v1 def testNodeInfoShowDumps(self): node_name = "simple_mul_add/matmul" out = self._registry.dispatch_command("node_info", ["-d", node_name]) @@ -948,6 +963,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): len(out.lines[16]) - len(out.lines[16].strip()), len(out.lines[16]), "pt %s:0 -n 0" % node_name) + @test_util.run_deprecated_v1 def testNodeInfoShowStackTraceUnavailableIsIndicated(self): self._debug_dump.set_python_graph(None) @@ -971,6 +987,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): print_tensor_node_name=node_name, list_outputs_node_name=node_name) + @test_util.run_deprecated_v1 def testNodeInfoShowStackTraceAvailableWorks(self): self._debug_dump.set_python_graph(self._sess.graph) @@ -994,6 +1011,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): print_tensor_node_name=node_name, list_outputs_node_name=node_name) + @test_util.run_deprecated_v1 def testNodeInfoByTensorName(self): node_name = "simple_mul_add/u/read" tensor_name = node_name + ":0" @@ -1363,6 +1381,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): break return index + @test_util.run_deprecated_v1 def testPrintSourceForOpNamesWholeFileWorks(self): self._debug_dump.set_python_graph(self._sess.graph) out = self._registry.dispatch_command( @@ -1415,6 +1434,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): self.assertEqual("pt simple_mul_add/add", out.font_attr_segs[index + 1][0][2].content) + @test_util.run_deprecated_v1 def testPrintSourceForTensorNamesWholeFileWorks(self): self._debug_dump.set_python_graph(self._sess.graph) out = self._registry.dispatch_command( @@ -1435,6 +1455,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): self.assertEqual("pt simple_mul_add/u:0", out.font_attr_segs[index + 2][0][2].content) + @test_util.run_deprecated_v1 def testPrintSourceForOpNamesStartingAtSpecifiedLineWorks(self): self._debug_dump.set_python_graph(self._sess.graph) out = self._registry.dispatch_command( @@ -1461,6 +1482,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): self.assertEqual("pt simple_mul_add/u/read", out.font_attr_segs[index + 3][0][2].content) + @test_util.run_deprecated_v1 def testPrintSourceForOpNameSettingMaximumElementCountWorks(self): self._debug_dump.set_python_graph(self._sess.graph) out = self._registry.dispatch_command( @@ -1505,6 +1527,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): self.assertTrue(cli_shared.COLOR_GRAY in attr_seg[2] or attr_seg[2] == cli_shared.COLOR_GRAY) + @test_util.run_deprecated_v1 def testListSourceWithNodeNameFilterWithMatchesWorks(self): self._debug_dump.set_python_graph(self._sess.graph) out = self._registry.dispatch_command("list_source", ["-n", ".*/read"]) @@ -1719,6 +1742,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): # Tear down temporary dump directory. shutil.rmtree(cls._dump_root) + @test_util.run_deprecated_v1 def testNodeInfoWithControlDependencies(self): # Call node_info on a node with control inputs. out = self._registry.dispatch_command("node_info", @@ -1759,6 +1783,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): len(out.lines[z_line]), "ni -a -d -t control_deps/ctrl_dep_z") + @test_util.run_deprecated_v1 def testListInputsNonRecursiveNoControl(self): """List inputs non-recursively, without any control inputs.""" @@ -1801,6 +1826,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): len(out.lines[3]) - len("control_deps/ctrl_dep_y"), len(out.lines[3]), "li -c -r control_deps/ctrl_dep_y") + @test_util.run_deprecated_v1 def testListInputsNonRecursiveNoControlUsingTensorName(self): """List inputs using the name of an output tensor of the node.""" @@ -1829,6 +1855,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): len(out.lines[3]) - len("control_deps/ctrl_dep_y"), len(out.lines[3]), "li -c -r control_deps/ctrl_dep_y") + @test_util.run_deprecated_v1 def testListInputsNonRecursiveWithControls(self): """List inputs non-recursively, with control inputs.""" node_name = "control_deps/ctrl_dep_z" @@ -1859,6 +1886,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): len(out.lines[5]) - len("control_deps/x"), len(out.lines[5]), "li -c -r control_deps/x") + @test_util.run_deprecated_v1 def testListInputsRecursiveWithControls(self): """List inputs recursively, with control inputs.""" node_name = "control_deps/ctrl_dep_z" @@ -1904,6 +1932,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): len(out.lines[18]) - len("control_deps/x"), len(out.lines[18]), "li -c -r control_deps/x") + @test_util.run_deprecated_v1 def testListInputsRecursiveWithControlsWithDepthLimit(self): """List inputs recursively, with control inputs and a depth limit.""" node_name = "control_deps/ctrl_dep_z" @@ -1963,6 +1992,7 @@ class AnalyzerCLIControlDepTest(test_util.TensorFlowTestCase): "ERROR: There is no node named \"control_deps/z/foo\" in the " "partition graphs"], out.lines) + @test_util.run_deprecated_v1 def testListRecipientsRecursiveWithControlsWithDepthLimit(self): """List recipients recursively, with control inputs and a depth limit.""" @@ -2034,6 +2064,7 @@ class AnalyzerCLIWhileLoopTest(test_util.TensorFlowTestCase): # Tear down temporary dump directory. shutil.rmtree(cls._dump_root) + @test_util.run_deprecated_v1 def testMultipleDumpsPrintTensorNoNumber(self): output = self._registry.dispatch_command("pt", ["while/Identity:0"]) @@ -2051,6 +2082,7 @@ class AnalyzerCLIWhileLoopTest(test_util.TensorFlowTestCase): self.assertEqual("For example:", output.lines[-2]) self.assertEqual(" print_tensor while/Identity:0 -n 0", output.lines[-1]) + @test_util.run_deprecated_v1 def testMultipleDumpsPrintTensorWithNumber(self): for i in xrange(5): output = self._registry.dispatch_command( @@ -2064,6 +2096,7 @@ class AnalyzerCLIWhileLoopTest(test_util.TensorFlowTestCase): self.assertTrue(output.lines[4].startswith("array(%d" % i)) self.assertTrue(output.lines[4].endswith(")")) + @test_util.run_deprecated_v1 def testMultipleDumpsPrintTensorInvalidNumber(self): output = self._registry.dispatch_command("pt", ["while/Identity:0", "-n", "10"]) diff --git a/tensorflow/python/debug/cli/cli_shared_test.py b/tensorflow/python/debug/cli/cli_shared_test.py index 07b364db9f..d191a234fd 100644 --- a/tensorflow/python/debug/cli/cli_shared_test.py +++ b/tensorflow/python/debug/cli/cli_shared_test.py @@ -118,6 +118,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): def tearDown(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testSingleFetchNoFeeds(self): run_start_intro = cli_shared.get_run_start_intro(12, self.const_a, None, {}) @@ -181,6 +182,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): run_start_intro = cli_shared.get_run_start_intro(1, self.sparse_d, None, {}) self.assertEqual(str(self.sparse_d), run_start_intro.lines[4].strip()) + @test_util.run_deprecated_v1 def testTwoFetchesListNoFeeds(self): fetches = [self.const_a, self.const_b] run_start_intro = cli_shared.get_run_start_intro(1, fetches, None, {}) @@ -197,6 +199,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): description = cli_shared.get_run_short_description(1, fetches, None) self.assertEqual("run #1: 2 fetches; 0 feeds", description) + @test_util.run_deprecated_v1 def testNestedListAsFetches(self): fetches = [self.const_c, [self.const_a, self.const_b]] run_start_intro = cli_shared.get_run_start_intro(1, fetches, None, {}) @@ -210,6 +213,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): description = cli_shared.get_run_short_description(1, fetches, None) self.assertEqual("run #1: 3 fetches; 0 feeds", description) + @test_util.run_deprecated_v1 def testNestedDictAsFetches(self): fetches = {"c": self.const_c, "ab": {"a": self.const_a, "b": self.const_b}} run_start_intro = cli_shared.get_run_start_intro(1, fetches, None, {}) @@ -227,6 +231,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): description = cli_shared.get_run_short_description(1, fetches, None) self.assertEqual("run #1: 3 fetches; 0 feeds", description) + @test_util.run_deprecated_v1 def testTwoFetchesAsTupleNoFeeds(self): fetches = (self.const_a, self.const_b) run_start_intro = cli_shared.get_run_start_intro(1, fetches, None, {}) @@ -243,6 +248,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): description = cli_shared.get_run_short_description(1, fetches, None) self.assertEqual("run #1: 2 fetches; 0 feeds", description) + @test_util.run_deprecated_v1 def testTwoFetchesAsNamedTupleNoFeeds(self): fetches_namedtuple = namedtuple("fetches", "x y") fetches = fetches_namedtuple(self.const_b, self.const_c) @@ -260,6 +266,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): description = cli_shared.get_run_short_description(1, fetches, None) self.assertEqual("run #1: 2 fetches; 0 feeds", description) + @test_util.run_deprecated_v1 def testWithFeedDict(self): feed_dict = { self.const_a: 10.0, @@ -283,6 +290,7 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): feed_dict) self.assertEqual("run #1: 1 fetch (c:0); 2 feeds", description) + @test_util.run_deprecated_v1 def testTensorFilters(self): feed_dict = {self.const_a: 10.0} tensor_filters = { @@ -313,11 +321,13 @@ class GetRunStartIntroAndDescriptionTest(test_util.TensorFlowTestCase): command_set.add(annot[2].content) self.assertEqual({"run -f filter_a", "run -f filter_b"}, command_set) + @test_util.run_deprecated_v1 def testGetRunShortDescriptionWorksForTensorFeedKey(self): short_description = cli_shared.get_run_short_description( 1, self.const_a, {self.const_a: 42.0}) self.assertEqual("run #1: 1 fetch (a:0); 1 feed (a:0)", short_description) + @test_util.run_deprecated_v1 def testGetRunShortDescriptionWorksForUnicodeFeedKey(self): short_description = cli_shared.get_run_short_description( 1, self.const_a, {u"foo": 42.0}) @@ -332,6 +342,7 @@ class GetErrorIntroTest(test_util.TensorFlowTestCase): def tearDown(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testShapeError(self): tf_error = errors.OpError(None, self.var_a.initializer, "foo description", None) diff --git a/tensorflow/python/debug/cli/profile_analyzer_cli_test.py b/tensorflow/python/debug/cli/profile_analyzer_cli_test.py index 60b6047970..effcd500c7 100644 --- a/tensorflow/python/debug/cli/profile_analyzer_cli_test.py +++ b/tensorflow/python/debug/cli/profile_analyzer_cli_test.py @@ -348,6 +348,7 @@ class ProfileAnalyzerPrintSourceTest(test_util.TensorFlowTestCase): ops.reset_default_graph() super(ProfileAnalyzerPrintSourceTest, self).tearDown() + @test_util.run_deprecated_v1 def testPrintSourceForWhileLoop(self): prof_output = self.prof_analyzer.print_source([__file__]) @@ -361,6 +362,7 @@ class ProfileAnalyzerPrintSourceTest(test_util.TensorFlowTestCase): r"\[(\|)+(\s)*\] .*us .*7\(55\) .*L%d.*(\S)+" % self.loop_lineno, prof_output.lines) + @test_util.run_deprecated_v1 def testPrintSourceOutputContainsClickableLinks(self): prof_output = self.prof_analyzer.print_source([__file__]) any_match, line_index = _at_least_one_line_matches( @@ -377,6 +379,7 @@ class ProfileAnalyzerPrintSourceTest(test_util.TensorFlowTestCase): break self.assertTrue(any_menu_item_match) + @test_util.run_deprecated_v1 def testPrintSourceWithNonDefaultTimeUnit(self): prof_output = self.prof_analyzer.print_source([ __file__, "--time_unit", "ms"]) @@ -391,6 +394,7 @@ class ProfileAnalyzerPrintSourceTest(test_util.TensorFlowTestCase): r"\[(\|)+(\s)*\] .*ms .*7\(55\) .*L%d.*(\S)+" % self.loop_lineno, prof_output.lines) + @test_util.run_deprecated_v1 def testPrintSourceWithNodeNameFilter(self): prof_output = self.prof_analyzer.print_source([ __file__, "--node_name_filter", "x$"]) @@ -423,6 +427,7 @@ class ProfileAnalyzerPrintSourceTest(test_util.TensorFlowTestCase): break self.assertTrue(any_menu_item_match) + @test_util.run_deprecated_v1 def testPrintSourceWithOpTypeFilter(self): prof_output = self.prof_analyzer.print_source([ __file__, "--op_type_filter", "Less"]) diff --git a/tensorflow/python/debug/lib/common_test.py b/tensorflow/python/debug/lib/common_test.py index 5af0dafcf9..f6413f6b7b 100644 --- a/tensorflow/python/debug/lib/common_test.py +++ b/tensorflow/python/debug/lib/common_test.py @@ -27,6 +27,7 @@ from tensorflow.python.platform import googletest class CommonTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testOnFeedOneFetch(self): a = constant_op.constant(10.0, name="a") b = constant_op.constant(20.0, name="b") @@ -35,6 +36,7 @@ class CommonTest(test_util.TensorFlowTestCase): self.assertItemsEqual(["a:0"], loaded[0]) self.assertItemsEqual(["b:0"], loaded[1]) + @test_util.run_deprecated_v1 def testGetRunKeyFlat(self): a = constant_op.constant(10.0, name="a") b = constant_op.constant(20.0, name="b") @@ -43,6 +45,7 @@ class CommonTest(test_util.TensorFlowTestCase): self.assertItemsEqual(["a:0"], loaded[0]) self.assertItemsEqual(["a:0", "b:0"], loaded[1]) + @test_util.run_deprecated_v1 def testGetRunKeyNestedFetches(self): a = constant_op.constant(10.0, name="a") b = constant_op.constant(20.0, name="b") diff --git a/tensorflow/python/debug/lib/debug_gradients_test.py b/tensorflow/python/debug/lib/debug_gradients_test.py index 01867fc69d..1c53147863 100644 --- a/tensorflow/python/debug/lib/debug_gradients_test.py +++ b/tensorflow/python/debug/lib/debug_gradients_test.py @@ -54,6 +54,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): ops.reset_default_graph() debug_gradients.clear_gradient_debuggers() + @test_util.run_deprecated_v1 def testIdentifyGradientGivesCorrectTensorObjectWithoutContextManager(self): grad_debugger = debug_gradients.GradientsDebugger() id_grad_w = grad_debugger.identify_gradient(self.w) @@ -84,6 +85,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertIsInstance(w_grad, ops.Tensor) self.assertAllClose(1.0, self.sess.run(w_grad)) + @test_util.run_deprecated_v1 def testIdentifyGradientGivesCorrectTensorObjectWithTfGradients(self): grad_debugger = debug_gradients.GradientsDebugger() id_grad_w = grad_debugger.identify_gradient(self.w) @@ -115,6 +117,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertIsInstance(w_grad, ops.Tensor) self.assertAllClose(1.0, self.sess.run(w_grad)) + @test_util.run_deprecated_v1 def testCallingIdentifyGradientTwiceWithTheSameGradientsDebuggerErrors(self): grad_debugger = debug_gradients.GradientsDebugger() grad_debugger.identify_gradient(self.w) @@ -122,6 +125,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): "The graph already contains an op named .*"): grad_debugger.identify_gradient(self.w) + @test_util.run_deprecated_v1 def testIdentifyGradientWorksOnMultipleLosses(self): grad_debugger_1 = debug_gradients.GradientsDebugger() grad_debugger_2 = debug_gradients.GradientsDebugger() @@ -150,6 +154,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertAllClose(2.0 * 5.0, self.sess.run(dz1_dy)) self.assertAllClose(0.5 * (5.0**-0.5), self.sess.run(dz2_dy)) + @test_util.run_deprecated_v1 def testIdentifyGradientRaisesLookupErrorForUnknownXTensor(self): grad_debugger_1 = debug_gradients.GradientsDebugger() grad_debugger_2 = debug_gradients.GradientsDebugger() @@ -170,6 +175,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): r"This GradientsDebugger has not received any gradient tensor for "): grad_debugger_2.gradient_tensor(self.w) + @test_util.run_deprecated_v1 def testIdentifyGradientRaisesTypeErrorForNonTensorOrTensorNameInput(self): grad_debugger = debug_gradients.GradientsDebugger() with self.assertRaisesRegexp( @@ -178,6 +184,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): r"has type .*Operation.*"): grad_debugger.gradient_tensor(variables.global_variables_initializer()) + @test_util.run_deprecated_v1 def testIdentifyGradientTensorWorksWithGradientDescentOptimizer(self): grad_debugger = debug_gradients.GradientsDebugger() id_grad_w = grad_debugger.identify_gradient(self.w) @@ -193,6 +200,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertIsInstance(w_grad, ops.Tensor) self.assertAllClose(1.0, self.sess.run(w_grad)) + @test_util.run_deprecated_v1 def testWatchGradientsByXTensorNamesWorks(self): y = math_ops.add(self.w, -1.0, name="y") @@ -219,6 +227,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertIsInstance(w_grad, ops.Tensor) self.assertAllClose(1.0, self.sess.run(w_grad)) + @test_util.run_deprecated_v1 def testWatchGradientsByXTensorNamesWorksWithoutContextManager(self): y = math_ops.add(self.w, -1.0, name="y") @@ -245,6 +254,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertIsInstance(w_grad, ops.Tensor) self.assertAllClose(1.0, self.sess.run(w_grad)) + @test_util.run_deprecated_v1 def testWatchGradientsWorksOnRefTensor(self): y = math_ops.add(self.w, -1.0, name="y") @@ -263,6 +273,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertAllClose(3.0, self.sess.run( grad_debugger.gradient_tensor("u:0"))) + @test_util.run_deprecated_v1 def testWatchGradientsWorksOnMultipleTensors(self): y = math_ops.add(self.w, -1.0, name="y") @@ -283,6 +294,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertAllClose(3.0, self.sess.run( grad_debugger.gradient_tensor("u:0"))) + @test_util.run_deprecated_v1 def testWatchGradientsByXTensorsWorks(self): y = math_ops.add(self.w, -1.0, name="foo/y") z = math_ops.square(y, name="foo/z") @@ -305,6 +317,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertAllClose(10.0, self.sess.run(w_grad)) self.assertAllClose(30.0, self.sess.run(u_grad)) + @test_util.run_deprecated_v1 def testWatchGradientsByTensorCanWorkOnMultipleLosses(self): y = math_ops.add(self.w, -1.0, name="y") z1 = math_ops.square(y, name="z1") @@ -330,6 +343,7 @@ class IdentifyGradientTest(test_util.TensorFlowTestCase): self.assertAllClose(2.0 * 5.0, self.sess.run(dz1_dy)) self.assertAllClose(0.5 * (5.0**-0.5), self.sess.run(dz2_dy)) + @test_util.run_deprecated_v1 def testGradientsValuesFromDumpWorks(self): y = math_ops.add(self.w, -1.0, name="y") z = math_ops.square(y, name="z") diff --git a/tensorflow/python/debug/lib/debug_utils_test.py b/tensorflow/python/debug/lib/debug_utils_test.py index 23ab98444c..cf59b30e3d 100644 --- a/tensorflow/python/debug/lib/debug_utils_test.py +++ b/tensorflow/python/debug/lib/debug_utils_test.py @@ -185,6 +185,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): self.assertEqual(["file:///tmp/tfdbg_1", "file:///tmp/tfdbg_2"], watch_0.debug_urls) + @test_util.run_deprecated_v1 def testWatchGraph_allNodes(self): debug_utils.watch_graph( self._run_options, @@ -216,6 +217,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): self.assertTrue("p1" in node_names) self.assertTrue("s" in node_names) + @test_util.run_deprecated_v1 def testWatchGraph_nodeNameWhitelist(self): debug_utils.watch_graph( self._run_options, @@ -230,6 +232,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): sorted(["a1_init", "a1", "a1/Assign", "a1/read", "p1"]), sorted(node_names)) + @test_util.run_deprecated_v1 def testWatchGraph_opTypeWhitelist(self): debug_utils.watch_graph( self._run_options, @@ -255,6 +258,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): ["DebugIdentity"], ["file:///tmp/tfdbg_1"]) self.assertEqual(["p1"], node_names) + @test_util.run_deprecated_v1 def testWatchGraph_tensorDTypeWhitelist(self): debug_utils.watch_graph( self._run_options, @@ -267,6 +271,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): ["DebugIdentity"], ["file:///tmp/tfdbg_1"]) self.assertItemsEqual(["a1", "a1/Assign", "b", "b/Assign"], node_names) + @test_util.run_deprecated_v1 def testWatchGraph_nodeNameAndTensorDTypeWhitelists(self): debug_utils.watch_graph( self._run_options, @@ -280,6 +285,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): ["DebugIdentity"], ["file:///tmp/tfdbg_1"]) self.assertItemsEqual(["a1", "a1/Assign"], node_names) + @test_util.run_deprecated_v1 def testWatchGraph_nodeNameBlacklist(self): debug_utils.watch_graph_with_blacklists( self._run_options, @@ -294,6 +300,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): sorted(["b_init", "b", "b/Assign", "b/read", "c", "s"]), sorted(node_names)) + @test_util.run_deprecated_v1 def testWatchGraph_opTypeBlacklist(self): debug_utils.watch_graph_with_blacklists( self._run_options, @@ -306,6 +313,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): ["DebugIdentity"], ["file:///tmp/tfdbg_1"]) self.assertEqual(sorted(["p1", "s"]), sorted(node_names)) + @test_util.run_deprecated_v1 def testWatchGraph_nodeNameAndOpTypeBlacklists(self): debug_utils.watch_graph_with_blacklists( self._run_options, @@ -319,6 +327,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): ["DebugIdentity"], ["file:///tmp/tfdbg_1"]) self.assertEqual(["s"], node_names) + @test_util.run_deprecated_v1 def testWatchGraph_tensorDTypeBlacklists(self): debug_utils.watch_graph_with_blacklists( self._run_options, @@ -335,6 +344,7 @@ class DebugUtilsTest(test_util.TensorFlowTestCase): self.assertNotIn("b/Assign", node_names) self.assertIn("s", node_names) + @test_util.run_deprecated_v1 def testWatchGraph_nodeNameAndTensorDTypeBlacklists(self): debug_utils.watch_graph_with_blacklists( self._run_options, diff --git a/tensorflow/python/debug/lib/session_debug_file_test.py b/tensorflow/python/debug/lib/session_debug_file_test.py index 1874160dd6..f5f9ba29ab 100644 --- a/tensorflow/python/debug/lib/session_debug_file_test.py +++ b/tensorflow/python/debug/lib/session_debug_file_test.py @@ -28,6 +28,7 @@ from tensorflow.python.debug.lib import debug_utils from tensorflow.python.debug.lib import session_debug_testlib from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables from tensorflow.python.platform import googletest @@ -44,6 +45,7 @@ class SessionDebugFileTest(session_debug_testlib.SessionDebugTestBase): else: return os.path.join(self._dump_root, "run_%d" % run_number) + @test_util.run_deprecated_v1 def testAllowsDifferentWatchesOnDifferentRuns(self): """Test watching different tensors on different runs of the same graph.""" diff --git a/tensorflow/python/debug/lib/source_utils_test.py b/tensorflow/python/debug/lib/source_utils_test.py index a16d68329a..9083297fdb 100644 --- a/tensorflow/python/debug/lib/source_utils_test.py +++ b/tensorflow/python/debug/lib/source_utils_test.py @@ -65,6 +65,7 @@ class GuessIsTensorFlowLibraryTest(test_util.TensorFlowTestCase): self.assertTrue( source_utils.guess_is_tensorflow_py_library(source_utils.__file__)) + @test_util.run_deprecated_v1 def testFileInPythonKernelsPathReturnsTrue(self): x = constant_op.constant(42.0, name="x") self.assertTrue( diff --git a/tensorflow/python/distribute/all_reduce_test.py b/tensorflow/python/distribute/all_reduce_test.py index 5bf983a1b2..2c6b853124 100644 --- a/tensorflow/python/distribute/all_reduce_test.py +++ b/tensorflow/python/distribute/all_reduce_test.py @@ -37,6 +37,7 @@ from tensorflow.python.platform import tf_logging class AllReduceTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testFlattenTensorsShapesDefined(self): x = array_ops.placeholder(types_pb2.DT_FLOAT, [None]) with self.assertRaisesRegexp(ValueError, @@ -100,6 +101,7 @@ class AllReduceTest(test_util.TensorFlowTestCase): input_tensors.append(array_ops.identity(t8)) return input_tensors, device_names + @test_util.run_deprecated_v1 def testBuildRingGatherPassStructure(self): # 1 worker, 1 device input_tensors, device_names = self._buildInput(1, 1) @@ -170,6 +172,7 @@ class AllReduceTest(test_util.TensorFlowTestCase): "subdiv=%d elapsed=%f" % (num_workers, num_gpus, shape, subdiv, elapsed)) + @test_util.run_deprecated_v1 def testRingAllReduce(self): self._testRingAllReduce(1, 2, [], 1) self._testRingAllReduce(1, 2, [8], 1) @@ -199,6 +202,7 @@ class AllReduceTest(test_util.TensorFlowTestCase): tf_logging.info("ShuffleAllReduce num_workers=%d num_gpus=%d shape=%s " "elapsed=%f" % (num_workers, num_gpus, shape, elapsed)) + @test_util.run_deprecated_v1 def testShuffleAllReduce(self): self._testShuffleAllReduce(1, 2, [], 1) self._testShuffleAllReduce(1, 2, [8], 1) @@ -225,6 +229,7 @@ class AllReduceTest(test_util.TensorFlowTestCase): "shape=%s elapsed=%f" % (num_workers, num_gpus, shape, elapsed)) + @test_util.run_deprecated_v1 def testRecursiveHDAllReduce(self): self._testRecursiveHDAllReduce(1, 2, [8]) self._testRecursiveHDAllReduce(1, 2, [4, 4]) diff --git a/tensorflow/python/distribute/device_util_test.py b/tensorflow/python/distribute/device_util_test.py index baecd43c8e..2f0d7ed3b3 100644 --- a/tensorflow/python/distribute/device_util_test.py +++ b/tensorflow/python/distribute/device_util_test.py @@ -21,11 +21,13 @@ from __future__ import print_function from tensorflow.python.distribute import device_util from tensorflow.python.eager import context from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test class DeviceUtilTest(test.TestCase): + @test_util.run_deprecated_v1 def testCurrentDeviceWithGlobalGraph(self): with ops.device("/cpu:0"): self.assertEqual(device_util.current(), "/device:CPU:0") @@ -49,6 +51,7 @@ class DeviceUtilTest(test.TestCase): self.assertEqual(device_util.current(), "/job:localhost/replica:0/task:0/device:CPU:0") + @test_util.run_deprecated_v1 def testCanonicalizeWithoutDefaultDevice(self): self.assertEqual( device_util.canonicalize("/cpu:0"), diff --git a/tensorflow/python/distribute/input_ops_test.py b/tensorflow/python/distribute/input_ops_test.py index d5f41b7093..dcf946ba47 100644 --- a/tensorflow/python/distribute/input_ops_test.py +++ b/tensorflow/python/distribute/input_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import readers from tensorflow.python.distribute import input_ops from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.lib.io import python_io from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -96,6 +97,7 @@ class AutoShardDatasetTest(test.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testTFRecordDataset(self): dataset = readers.TFRecordDataset(self._createTFRecordFiles()) dataset = input_ops.auto_shard_dataset( @@ -103,6 +105,7 @@ class AutoShardDatasetTest(test.TestCase): self._verifySimpleShardingOutput(dataset, self._record) + @test_util.run_deprecated_v1 def testFlatMap(self): dataset = dataset_ops.Dataset.from_tensor_slices( self._createTFRecordFiles()) @@ -112,6 +115,7 @@ class AutoShardDatasetTest(test.TestCase): self._verifySimpleShardingOutput(dataset, self._record) + @test_util.run_deprecated_v1 def testInterleave(self): dataset = dataset_ops.Dataset.from_tensor_slices( self._createTFRecordFiles()) @@ -124,6 +128,7 @@ class AutoShardDatasetTest(test.TestCase): # contain records in order of files. self._verifySimpleShardingOutput(dataset, self._record) + @test_util.run_deprecated_v1 def testListfiles(self): filenames = self._createTFRecordFiles() file_pattern = filenames[0].rsplit(os.sep, 1)[0] + "/tf_record.*.txt" @@ -144,6 +149,7 @@ class AutoShardDatasetTest(test.TestCase): self.evaluate(next_element) self.assertAllEqual(expected, actual) + @test_util.run_deprecated_v1 def testComplexPipeline(self): # Setup a complex input pipeline. batch_size = 2 @@ -183,6 +189,7 @@ class AutoShardDatasetTest(test.TestCase): self.assertAllEqual(sorted(expected), sorted(actual)) + @test_util.run_deprecated_v1 def testZip(self): dataset1 = readers.TFRecordDataset(self._createTFRecordFiles()) dataset2 = readers.TextLineDataset(self._createTextFiles()) @@ -193,6 +200,7 @@ class AutoShardDatasetTest(test.TestCase): record_fn = lambda r, f: (self._record(r, f), self._text_line(r, f)) self._verifySimpleShardingOutput(dataset, record_fn) + @test_util.run_deprecated_v1 def testConcat(self): dataset1 = readers.TFRecordDataset(self._createTFRecordFiles()) dataset2 = readers.TextLineDataset(self._createTextFiles()) @@ -213,6 +221,7 @@ class AutoShardDatasetTest(test.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(next_element) + @test_util.run_deprecated_v1 def testTextLineReader(self): dataset = readers.TextLineDataset(self._createTextFiles()) dataset = input_ops.auto_shard_dataset( @@ -220,6 +229,7 @@ class AutoShardDatasetTest(test.TestCase): self._verifySimpleShardingOutput(dataset, self._text_line) + @test_util.run_deprecated_v1 def testTextLineReaderWithFlatMap(self): dataset = dataset_ops.Dataset.from_tensor_slices(self._createTextFiles()) dataset = dataset.flat_map(readers.TextLineDataset) @@ -228,6 +238,7 @@ class AutoShardDatasetTest(test.TestCase): self._verifySimpleShardingOutput(dataset, self._text_line) + @test_util.run_deprecated_v1 def testFixedLengthReader(self): dataset = readers.FixedLengthRecordDataset( self._createFixedLengthRecordFiles(), self._record_bytes) @@ -236,6 +247,7 @@ class AutoShardDatasetTest(test.TestCase): self._verifySimpleShardingOutput(dataset, self._fixed_length_record) + @test_util.run_deprecated_v1 def testFixedLengthReaderWithFlatMap(self): dataset = dataset_ops.Dataset.from_tensor_slices( self._createFixedLengthRecordFiles()) diff --git a/tensorflow/python/eager/function_gradients_test.py b/tensorflow/python/eager/function_gradients_test.py index 1ba596573f..9b83f57089 100644 --- a/tensorflow/python/eager/function_gradients_test.py +++ b/tensorflow/python/eager/function_gradients_test.py @@ -187,6 +187,7 @@ class FunctionGradientsTest(test.TestCase, parameterized.TestCase): self.assertAllEqual(2, g(constant_op.constant(2.))) + @test_util.run_deprecated_v1 def testGraphModeEagerGradError(self): with context.graph_mode(): def f(): diff --git a/tensorflow/python/eager/function_test.py b/tensorflow/python/eager/function_test.py index a206b1f791..e47c5083a3 100644 --- a/tensorflow/python/eager/function_test.py +++ b/tensorflow/python/eager/function_test.py @@ -1283,6 +1283,7 @@ class FunctionTest(test.TestCase, parameterized.TestCase): defined.get_concrete_function( tensor_spec.TensorSpec(shape=(3,), dtype=dtypes.float32)) + @test_util.run_deprecated_v1 def testInputSignatureForFunctionWithNonTensorInputsNotAllowed(self): def foo(a, training=True): diff --git a/tensorflow/python/eager/graph_only_ops_test.py b/tensorflow/python/eager/graph_only_ops_test.py index 3aedf5fee1..914b4d9a95 100644 --- a/tensorflow/python/eager/graph_only_ops_test.py +++ b/tensorflow/python/eager/graph_only_ops_test.py @@ -29,12 +29,14 @@ from tensorflow.python.platform import test class GraphOnlyOpsTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testGraphZerosLike(self): x = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32) z_tf = graph_only_ops.graph_zeros_like(x) with self.cached_session(): self.assertAllClose(np.zeros((2, 3)), self.evaluate(z_tf)) + @test_util.run_deprecated_v1 def testGraphPlaceholder(self): x_tf = graph_only_ops.graph_placeholder(dtypes.int32, shape=(1,)) y_tf = math_ops.square(x_tf) diff --git a/tensorflow/python/feature_column/feature_column_test.py b/tensorflow/python/feature_column/feature_column_test.py index 2c70d66810..daa0a3b3a4 100644 --- a/tensorflow/python/feature_column/feature_column_test.py +++ b/tensorflow/python/feature_column/feature_column_test.py @@ -170,6 +170,7 @@ class LazyColumnTest(test.TestCase): TypeError, '"key" must be either a "str" or "_FeatureColumn".'): builder.get(NotAFeatureColumn()) + @test_util.run_deprecated_v1 def test_expand_dim_rank_1_sparse_tensor_empty_batch(self): # empty 1-D sparse tensor: builder = _LazyBuilder(features={'a': sparse_tensor.SparseTensor( @@ -185,6 +186,7 @@ class LazyColumnTest(test.TestCase): class NumericColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): a = fc._numeric_column('aaa') self.assertEqual('aaa', a.key) @@ -263,6 +265,7 @@ class NumericColumnTest(test.TestCase): 'aaa': parsing_ops.FixedLenFeature((2, 3), dtype=dtypes.int32) }, a._parse_example_spec) + @test_util.run_deprecated_v1 def test_parse_example_no_default_value(self): price = fc._numeric_column('price', shape=[2]) data = example_pb2.Example(features=feature_pb2.Features( @@ -278,6 +281,7 @@ class NumericColumnTest(test.TestCase): with self.cached_session(): self.assertAllEqual([[20., 110.]], features['price'].eval()) + @test_util.run_deprecated_v1 def test_parse_example_with_default_value(self): price = fc._numeric_column('price', shape=[2], default_value=11.) data = example_pb2.Example(features=feature_pb2.Features( @@ -304,6 +308,7 @@ class NumericColumnTest(test.TestCase): with self.assertRaisesRegexp(TypeError, 'must be a callable'): fc._numeric_column('price', normalizer_fn='NotACallable') + @test_util.run_deprecated_v1 def test_normalizer_fn_transform_feature(self): def _increment_two(input_tensor): @@ -314,6 +319,7 @@ class NumericColumnTest(test.TestCase): with self.cached_session(): self.assertAllEqual([[3., 4.], [7., 8.]], output[price].eval()) + @test_util.run_deprecated_v1 def test_get_dense_tensor(self): def _increment_two(input_tensor): @@ -333,6 +339,7 @@ class NumericColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'must be a Tensor'): price._transform_feature(builder) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc._numeric_column('aaa', shape=[1, 2], default_value=[[3., 2.]]) a_copy = copy.deepcopy(a) @@ -345,6 +352,7 @@ class NumericColumnTest(test.TestCase): 'aaa', shape=[1, 2], default_value=np.array([[3., 2.]])) self.assertEqual(a.default_value, ((3., 2.),)) + @test_util.run_deprecated_v1 def test_linear_model(self): price = fc._numeric_column('price') with ops.Graph().as_default(): @@ -359,6 +367,7 @@ class NumericColumnTest(test.TestCase): sess.run(price_var.assign([[10.]])) self.assertAllClose([[10.], [50.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): price = fc._numeric_column('price') with ops.Graph().as_default(): @@ -433,6 +442,7 @@ class BucketizedColumnTest(test.TestCase): # Column 'aaa` has shape [2] times three buckets -> num_buckets=6. self.assertEqual(6, b._num_buckets) + @test_util.run_deprecated_v1 def test_parse_example(self): price = fc._numeric_column('price', shape=[2]) bucketized_price = fc._bucketized_column(price, boundaries=[0, 50]) @@ -449,6 +459,7 @@ class BucketizedColumnTest(test.TestCase): with self.cached_session(): self.assertAllEqual([[20., 110.]], features['price'].eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): price = fc._numeric_column('price', shape=[2]) bucketized_price = fc._bucketized_column(price, boundaries=[0, 2, 4, 6]) @@ -531,6 +542,7 @@ class BucketizedColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'must be a Tensor'): bucketized_price._transform_feature(builder) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc._numeric_column('aaa', shape=[2]) a_bucketized = fc._bucketized_column(a, boundaries=[0, 1]) @@ -658,6 +670,7 @@ class BucketizedColumnTest(test.TestCase): class HashedCategoricalColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): a = fc._categorical_column_with_hash_bucket('aaa', 10) self.assertEqual('aaa', a.name) @@ -685,6 +698,7 @@ class HashedCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'dtype must be string or integer'): fc._categorical_column_with_hash_bucket('aaa', 10, dtype=dtypes.float32) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc._categorical_column_with_hash_bucket('aaa', 10) for column in (original, copy.deepcopy(original)): @@ -705,6 +719,7 @@ class HashedCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int32) }, a._parse_example_spec) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_hash_bucket('aaa', 10) data = example_pb2.Example(features=feature_pb2.Features( @@ -726,6 +741,7 @@ class HashedCategoricalColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_strings_should_be_hashed(self): hashed_sparse = fc._categorical_column_with_hash_bucket('wire', 10) wire_tensor = sparse_tensor.SparseTensor( @@ -781,6 +797,7 @@ class HashedCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'dtype must be compatible'): builder.get(hashed_sparse) + @test_util.run_deprecated_v1 def test_ints_should_be_hashed(self): hashed_sparse = fc._categorical_column_with_hash_bucket( 'wire', 10, dtype=dtypes.int64) @@ -795,6 +812,7 @@ class HashedCategoricalColumnTest(test.TestCase): with self.cached_session(): self.assertAllEqual(expected_values, output.values.eval()) + @test_util.run_deprecated_v1 def test_int32_64_is_compatible(self): hashed_sparse = fc._categorical_column_with_hash_bucket( 'wire', 10, dtype=dtypes.int64) @@ -809,6 +827,7 @@ class HashedCategoricalColumnTest(test.TestCase): with self.cached_session(): self.assertAllEqual(expected_values, output.values.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): hashed_sparse = fc._categorical_column_with_hash_bucket('wire', 10) builder = _LazyBuilder({ @@ -837,6 +856,7 @@ class HashedCategoricalColumnTest(test.TestCase): [], ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)) self.assertItemsEqual([], ops.get_collection('my_weights')) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): hashed_sparse = fc._categorical_column_with_hash_bucket('wire', 10) builder = _LazyBuilder({'wire': (('omar', ''), ('stringer', 'marlo'))}) @@ -844,6 +864,7 @@ class HashedCategoricalColumnTest(test.TestCase): self.assertIsNone(id_weight_pair.weight_tensor) self.assertEqual(builder.get(hashed_sparse), id_weight_pair.id_tensor) + @test_util.run_deprecated_v1 def test_linear_model(self): wire_column = fc._categorical_column_with_hash_bucket('wire', 4) self.assertEqual(4, wire_column._num_buckets) @@ -866,6 +887,7 @@ class HashedCategoricalColumnTest(test.TestCase): # 'skywalker' -> 2, 'omar' -> 2: wire_var[2] + wire_var[2] = 3+3 = 6 self.assertAllClose(((4.,), (6.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): wire_column = fc._categorical_column_with_hash_bucket('wire', 4) self.assertEqual(4, wire_column._num_buckets) @@ -975,6 +997,7 @@ class CrossedColumnTest(test.TestCase): crossed = fc._crossed_column([b, 'c'], 15) self.assertEqual(15, crossed._num_buckets) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc._numeric_column('a', dtype=dtypes.int32) b = fc._bucketized_column(a, boundaries=[0, 1]) @@ -985,6 +1008,7 @@ class CrossedColumnTest(test.TestCase): self.assertEqual(15, crossed2_copy.hash_bucket_size) self.assertEqual(5, crossed2_copy.hash_key) + @test_util.run_deprecated_v1 def test_parse_example(self): price = fc._numeric_column('price', shape=[2]) bucketized_price = fc._bucketized_column(price, boundaries=[0, 50]) @@ -1011,6 +1035,7 @@ class CrossedColumnTest(test.TestCase): self.assertAllEqual([b'omar', b'stringer'], wire_sparse.values.eval()) self.assertAllEqual([1, 2], wire_sparse.dense_shape.eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): price = fc._numeric_column('price', shape=[2]) bucketized_price = fc._bucketized_column(price, boundaries=[0, 50]) @@ -1034,6 +1059,7 @@ class CrossedColumnTest(test.TestCase): self.assertIn(val, list(range(hash_bucket_size))) self.assertAllEqual([2, 4], output_val.dense_shape) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): a = fc._numeric_column('a', dtype=dtypes.int32, shape=(2,)) b = fc._bucketized_column(a, boundaries=(0, 1)) @@ -1101,6 +1127,7 @@ class CrossedColumnTest(test.TestCase): self.assertAllEqual(expected_values, id_tensor_eval.values) self.assertAllEqual((2, 4), id_tensor_eval.dense_shape) + @test_util.run_deprecated_v1 def test_linear_model(self): """Tests linear_model. @@ -1182,6 +1209,7 @@ class CrossedColumnTest(test.TestCase): dense_shape=(2, 2)), }, (crossed,)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): """Tests _LinearModel. @@ -1854,6 +1882,7 @@ class LinearModelTest(test.TestCase): features['price2']: [[1.], [5.]], }) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): price = fc._numeric_column('price') price_buckets = fc._bucketized_column( @@ -1889,6 +1918,7 @@ class LinearModelTest(test.TestCase): self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], self.evaluate(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): price = fc._numeric_column('price') price_buckets = fc._bucketized_column( @@ -1936,6 +1966,7 @@ class LinearModelTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): price = fc._numeric_column('price') features = { @@ -2488,6 +2519,7 @@ class _LinearModelTest(test.TestCase): features['price2']: [[1.], [5.]], }) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): price = fc._numeric_column('price') price_buckets = fc._bucketized_column( @@ -2529,6 +2561,7 @@ class _LinearModelTest(test.TestCase): self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], self.evaluate(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): price = fc._numeric_column('price') price_buckets = fc._bucketized_column( @@ -2575,6 +2608,7 @@ class _LinearModelTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): price = fc._numeric_column('price') features = { @@ -2815,6 +2849,7 @@ class FunctionalInputLayerTest(test.TestCase): variables_lib.Variable) self.assertAllEqual(cols_to_vars[some_embedding_column][0].shape, [5, 10]) + @test_util.run_deprecated_v1 def test_fills_cols_to_vars_shared_embedding(self): # Provide 5 DenseColumn's to input_layer: a NumericColumn, a # BucketizedColumn, an EmbeddingColumn, two SharedEmbeddingColumns. The @@ -3012,6 +3047,7 @@ class FunctionalInputLayerTest(test.TestCase): expected_var_names, [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_multiple_layers_with_same_shared_embedding_column(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -3045,6 +3081,7 @@ class FunctionalInputLayerTest(test.TestCase): ['input_layer/aaa_bbb_shared_embedding/embedding_weights:0'], [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_multiple_layers_with_same_shared_embedding_column_diff_graphs(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -3096,6 +3133,7 @@ class FunctionalInputLayerTest(test.TestCase): ['input_layer/aaa_bbb_shared_embedding/embedding_weights:0'], [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): embedding_values = ( (1., 2., 3., 4., 5.), # id 0 @@ -3146,6 +3184,7 @@ class FunctionalInputLayerTest(test.TestCase): [1., 0., 0., 1., 2., 3., 4., 5., 12.]], sess.run(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): embedding_values = ( (1., 2.), # id 0 @@ -3205,6 +3244,7 @@ class FunctionalInputLayerTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): # price has 1 dimension in input_layer price = fc._numeric_column('price') @@ -3335,6 +3375,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'python/feature_column/testdata/wire_vocabulary.txt') self._wire_vocabulary_size = 3 + @test_util.run_deprecated_v1 def test_defaults(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='path_to_file', vocabulary_size=3) @@ -3351,6 +3392,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): fc._categorical_column_with_vocabulary_file( key=('aaa',), vocabulary_file='path_to_file', vocabulary_size=3) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3363,6 +3405,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int32) }, column._parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3387,6 +3430,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): fc._categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='', vocabulary_size=3) + @test_util.run_deprecated_v1 def test_invalid_vocabulary_file(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='file_does_not_exist', vocabulary_size=10) @@ -3411,6 +3455,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): vocabulary_file=self._wire_vocabulary_file_name, vocabulary_size=0) + @test_util.run_deprecated_v1 def test_too_large_vocabulary_size(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3477,6 +3522,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'dtype must be compatible'): column._get_sparse_tensors(_LazyBuilder({'aaa': inputs})) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='path_to_file', vocabulary_size=3) @@ -3499,6 +3545,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3519,6 +3566,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_none_vocabulary_size(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', vocabulary_file=self._wire_vocabulary_file_name) @@ -3537,6 +3585,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3573,6 +3622,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): [], ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)) self.assertItemsEqual([], ops.get_collection('my_weights')) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3592,6 +3642,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_default_value_in_vocabulary(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3613,6 +3664,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_oov_buckets(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3634,6 +3686,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_small_vocabulary_size(self): # 'marlo' is the last entry in our vocabulary file, so be setting # `vocabulary_size` to 1 less than number of entries in file, we take @@ -3657,6 +3710,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3678,6 +3732,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_dense_input(self): default_value = -100 column = fc._categorical_column_with_vocabulary_file( @@ -3700,6 +3755,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=(3, 3)), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_with_oov_buckets(self): column = fc._categorical_column_with_vocabulary_file( key='aaa', @@ -3722,6 +3778,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_linear_model(self): wire_column = fc._categorical_column_with_vocabulary_file( key='wire', @@ -3748,6 +3805,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): wire_column = fc._categorical_column_with_vocabulary_file( key='wire', @@ -3805,6 +3863,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, column._parse_example_spec) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -3816,6 +3875,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int32) }, column._parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(12, 24, 36), dtype=dtypes.int32) @@ -3904,6 +3964,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'dtype must be compatible'): column._get_sparse_tensors(_LazyBuilder({'aaa': inputs})) + @test_util.run_deprecated_v1 def test_parse_example_string(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -3926,6 +3987,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_parse_example_int(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(11, 21, 31)) @@ -3948,6 +4010,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -3966,6 +4029,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -3998,6 +4062,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): [], ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)) self.assertItemsEqual([], ops.get_collection('my_weights')) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -4015,6 +4080,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_default_value_in_vocabulary(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -4035,6 +4101,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_oov_buckets(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -4055,6 +4122,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -4075,6 +4143,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_dense_input(self): default_value = -100 column = fc._categorical_column_with_vocabulary_list( @@ -4098,6 +4167,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=(3, 3)), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_with_oov_buckets(self): column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -4119,6 +4189,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_linear_model(self): wire_column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -4144,6 +4215,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): wire_column = fc._categorical_column_with_vocabulary_list( key='aaa', @@ -4187,6 +4259,7 @@ class IdentityCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'key must be a string.'): fc._categorical_column_with_identity(key=('aaa',), num_buckets=3) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc._categorical_column_with_identity(key='aaa', num_buckets=3) for column in (original, copy.deepcopy(original)): @@ -4223,6 +4296,7 @@ class IdentityCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'Invalid input, not integer'): column._get_sparse_tensors(_LazyBuilder({'aaa': inputs})) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_identity(key='aaa', num_buckets=30) data = example_pb2.Example(features=feature_pb2.Features( @@ -4244,6 +4318,7 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -4261,6 +4336,7 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -4291,6 +4367,7 @@ class IdentityCategoricalColumnTest(test.TestCase): [], ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)) self.assertItemsEqual([], ops.get_collection('my_weights')) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) id_weight_pair = column._get_sparse_tensors( @@ -4307,6 +4384,7 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_inputs_too_small(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -4320,6 +4398,7 @@ class IdentityCategoricalColumnTest(test.TestCase): errors.OpError, 'assert_greater_or_equal_0'): id_weight_pair.id_tensor.eval() + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_inputs_too_big(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -4333,6 +4412,7 @@ class IdentityCategoricalColumnTest(test.TestCase): errors.OpError, 'assert_less_than_num_buckets'): id_weight_pair.id_tensor.eval() + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_default_value(self): column = fc._categorical_column_with_identity( key='aaa', num_buckets=4, default_value=3) @@ -4351,6 +4431,7 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), id_weight_pair.id_tensor.eval()) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_default_value_and_placeholder_inputs(self): column = fc._categorical_column_with_identity( key='aaa', num_buckets=4, default_value=3) @@ -4376,6 +4457,7 @@ class IdentityCategoricalColumnTest(test.TestCase): input_shape: (2, 2), })) + @test_util.run_deprecated_v1 def test_linear_model(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) self.assertEqual(3, column._num_buckets) @@ -4397,6 +4479,7 @@ class IdentityCategoricalColumnTest(test.TestCase): # weight_var[2] + weight_var[1] = 3+2 = 5 self.assertAllClose(((1.,), (5.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): column = fc._categorical_column_with_identity(key='aaa', num_buckets=3) self.assertEqual(3, column._num_buckets) @@ -4548,6 +4631,7 @@ class IndicatorColumnTest(test.TestCase): with self.cached_session(): self.assertAllEqual([[0., 1., 1., 0.]], self.evaluate(output)) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc._categorical_column_with_hash_bucket('a', 4) column = fc._indicator_column(a) @@ -4556,6 +4640,7 @@ class IndicatorColumnTest(test.TestCase): self.assertEqual(column.name, 'a_indicator') self.assertEqual(column._variable_shape, [1, 4]) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -4579,6 +4664,7 @@ class IndicatorColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_transform(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -4594,6 +4680,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllEqual([[0, 0, 1], [1, 0, 0]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_transform_with_weighted_column(self): # Github issue 12557 ids = fc._categorical_column_with_vocabulary_list( @@ -4608,6 +4695,7 @@ class IndicatorColumnTest(test.TestCase): with _initialized_session(): self.assertAllEqual([[6., 4., 3.]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_transform_with_missing_value_in_weighted_column(self): # Github issue 12583 ids = fc._categorical_column_with_vocabulary_list( @@ -4622,6 +4710,7 @@ class IndicatorColumnTest(test.TestCase): with _initialized_session(): self.assertAllEqual([[0., 4., 2.]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_transform_with_missing_value_in_categorical_column(self): # Github issue 12583 ids = fc._categorical_column_with_vocabulary_list( @@ -4634,6 +4723,7 @@ class IndicatorColumnTest(test.TestCase): with _initialized_session(): self.assertAllEqual([[0., 1., 1.]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_linear_model(self): animal = fc._indicator_column( fc._categorical_column_with_identity('animal', num_buckets=4)) @@ -4653,6 +4743,7 @@ class IndicatorColumnTest(test.TestCase): weight_var.assign([[1.], [2.], [3.], [4.]]).eval() self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): animal = fc._indicator_column( fc._categorical_column_with_identity('animal', num_buckets=4)) @@ -4672,6 +4763,7 @@ class IndicatorColumnTest(test.TestCase): weight_var.assign([[1.], [2.], [3.], [4.]]).eval() self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_input_layer(self): animal = fc._indicator_column( fc._categorical_column_with_identity('animal', num_buckets=4)) @@ -4688,6 +4780,7 @@ class IndicatorColumnTest(test.TestCase): class EmbeddingColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): categorical_column = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -4709,6 +4802,7 @@ class EmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column._parse_example_spec) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): categorical_column = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -4737,6 +4831,7 @@ class EmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column._parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): categorical_column = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -4770,6 +4865,7 @@ class EmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column._parse_example_spec) + @test_util.run_deprecated_v1 def test_invalid_initializer(self): categorical_column = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -4777,6 +4873,7 @@ class EmbeddingColumnTest(test.TestCase): fc._embedding_column( categorical_column, dimension=2, initializer='not_fn') + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -4800,6 +4897,7 @@ class EmbeddingColumnTest(test.TestCase): dense_shape=[1, 2]), features['aaa'].eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): a = fc._categorical_column_with_identity(key='aaa', num_buckets=3) a_embedded = fc._embedding_column(a, dimension=2) @@ -4816,6 +4914,7 @@ class EmbeddingColumnTest(test.TestCase): _assert_sparse_tensor_value(self, self.evaluate(output_a), self.evaluate(output_embedded)) + @test_util.run_deprecated_v1 def test_get_dense_tensor(self): # Inputs. vocabulary_size = 3 @@ -4875,6 +4974,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, global_vars[0].eval()) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_3d(self): # Inputs. vocabulary_size = 4 @@ -4936,6 +5036,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, global_vars[0].eval()) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_weight_collections(self): sparse_input = sparse_tensor.SparseTensorValue( # example 0, ids [2] @@ -4965,6 +5066,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertItemsEqual( ('embedding_weights:0',), tuple([v.name for v in my_vars])) + @test_util.run_deprecated_v1 def test_get_dense_tensor_placeholder_inputs(self): # Inputs. vocabulary_size = 3 @@ -5036,6 +5138,7 @@ class EmbeddingColumnTest(test.TestCase): input_shape: sparse_input.dense_shape, })) + @test_util.run_deprecated_v1 def test_get_dense_tensor_restore_from_ckpt(self): # Inputs. vocabulary_size = 3 @@ -5094,6 +5197,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, global_vars[0].eval()) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_linear_model(self): # Inputs. batch_size = 4 @@ -5173,6 +5277,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): # Inputs. batch_size = 4 @@ -5252,6 +5357,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_input_layer(self): # Inputs. vocabulary_size = 3 @@ -5313,6 +5419,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, trainable_vars[0].eval()) self.assertAllEqual(expected_lookups, self.evaluate(input_layer)) + @test_util.run_deprecated_v1 def test_input_layer_not_trainable(self): # Inputs. vocabulary_size = 3 @@ -5376,6 +5483,7 @@ class EmbeddingColumnTest(test.TestCase): class SharedEmbeddingColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -5420,6 +5528,7 @@ class SharedEmbeddingColumnTest(test.TestCase): 'bbb': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column_b._parse_example_spec) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -5471,6 +5580,7 @@ class SharedEmbeddingColumnTest(test.TestCase): 'bbb': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column_b._parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -5509,6 +5619,7 @@ class SharedEmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column_a._parse_example_spec) + @test_util.run_deprecated_v1 def test_invalid_initializer(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -5520,6 +5631,7 @@ class SharedEmbeddingColumnTest(test.TestCase): dimension=2, initializer='not_fn') + @test_util.run_deprecated_v1 def test_incompatible_column_type(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -5535,6 +5647,7 @@ class SharedEmbeddingColumnTest(test.TestCase): [categorical_column_a, categorical_column_b, categorical_column_c], dimension=2) + @test_util.run_deprecated_v1 def test_weighted_categorical_column_ok(self): categorical_column_a = fc._categorical_column_with_identity( key='aaa', num_buckets=3) @@ -5552,6 +5665,7 @@ class SharedEmbeddingColumnTest(test.TestCase): [weighted_categorical_column_a, weighted_categorical_column_b], dimension=2) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5589,6 +5703,7 @@ class SharedEmbeddingColumnTest(test.TestCase): dense_shape=[1, 2]), features['bbb'].eval()) + @test_util.run_deprecated_v1 def test_transform_feature(self): a = fc._categorical_column_with_identity(key='aaa', num_buckets=3) b = fc._categorical_column_with_identity(key='bbb', num_buckets=3) @@ -5615,6 +5730,7 @@ class SharedEmbeddingColumnTest(test.TestCase): _assert_sparse_tensor_value(self, self.evaluate(output_b), self.evaluate(output_b_embedded)) + @test_util.run_deprecated_v1 def test_get_dense_tensor(self): # Inputs. vocabulary_size = 3 @@ -5683,6 +5799,7 @@ class SharedEmbeddingColumnTest(test.TestCase): self.assertAllEqual(expected_lookups_a, self.evaluate(embedding_lookup_a)) self.assertAllEqual(expected_lookups_b, self.evaluate(embedding_lookup_b)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_weight_collections(self): # Inputs. vocabulary_size = 3 @@ -5735,6 +5852,7 @@ class SharedEmbeddingColumnTest(test.TestCase): ('input_layer/aaa_bbb_shared_embedding/embedding_weights:0',), tuple(v.name for v in my_vars)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_placeholder_inputs(self): # Inputs. vocabulary_size = 3 @@ -5791,6 +5909,7 @@ class SharedEmbeddingColumnTest(test.TestCase): with _initialized_session() as sess: sess.run([embedding_lookup_a, embedding_lookup_b], feed_dict=feed_dict) + @test_util.run_deprecated_v1 def test_linear_model(self): # Inputs. batch_size = 2 @@ -5881,6 +6000,7 @@ class SharedEmbeddingColumnTest(test.TestCase): # = [3*1 + 5*2, 3*0 +5*0] = [13, 0] self.assertAllClose([[94. + 13.], [29.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): # Inputs. batch_size = 2 @@ -6048,15 +6168,18 @@ class SharedEmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, shared_embedding_vars[0].eval()) self.assertAllEqual(expected_lookups, self.evaluate(input_layer)) + @test_util.run_deprecated_v1 def test_input_layer(self): self._test_input_layer() + @test_util.run_deprecated_v1 def test_input_layer_no_trainable(self): self._test_input_layer(trainable=False) class WeightedCategoricalColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): column = fc._weighted_categorical_column( categorical_column=fc._categorical_column_with_identity( @@ -6070,6 +6193,7 @@ class WeightedCategoricalColumnTest(test.TestCase): 'values': parsing_ops.VarLenFeature(dtypes.float32) }, column._parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): """Tests deepcopy of categorical_column_with_hash_bucket.""" original = fc._weighted_categorical_column( @@ -6132,6 +6256,7 @@ class WeightedCategoricalColumnTest(test.TestCase): ValueError, 'values is not in features dictionary'): _transform_features({'ids': inputs}, (column,)) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc._categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -6167,6 +6292,7 @@ class WeightedCategoricalColumnTest(test.TestCase): dense_shape=[1, 2]), features['weights'].eval()) + @test_util.run_deprecated_v1 def test_transform_features(self): column = fc._weighted_categorical_column( categorical_column=fc._categorical_column_with_identity( @@ -6198,6 +6324,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array(weights.values, dtype=np.float32), dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) + @test_util.run_deprecated_v1 def test_transform_features_dense_input(self): column = fc._weighted_categorical_column( categorical_column=fc._categorical_column_with_identity( @@ -6225,6 +6352,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array(weights.values, dtype=np.float32), dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) + @test_util.run_deprecated_v1 def test_transform_features_dense_weights(self): column = fc._weighted_categorical_column( categorical_column=fc._categorical_column_with_identity( @@ -6252,6 +6380,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array((.5, 1., .1), dtype=np.float32), dense_shape=(2, 2)), self.evaluate(weight_tensor)) + @test_util.run_deprecated_v1 def test_keras_linear_model(self): column = fc._weighted_categorical_column( categorical_column=fc._categorical_column_with_identity( @@ -6354,6 +6483,7 @@ class WeightedCategoricalColumnTest(test.TestCase): # = 3*1 + 2*.1 = 3+.2 = 3.2 self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_linear_model(self): column = fc._weighted_categorical_column( categorical_column=fc._categorical_column_with_identity( diff --git a/tensorflow/python/feature_column/feature_column_v2_test.py b/tensorflow/python/feature_column/feature_column_v2_test.py index 3147754bee..083cd526e4 100644 --- a/tensorflow/python/feature_column/feature_column_v2_test.py +++ b/tensorflow/python/feature_column/feature_column_v2_test.py @@ -218,6 +218,7 @@ class LazyColumnTest(test.TestCase): TypeError, '"key" must be either a "str" or "FeatureColumn".'): transformation_cache.get(NotAFeatureColumn(), None) + @test_util.run_deprecated_v1 def test_expand_dim_rank_1_sparse_tensor_empty_batch(self): # empty 1-D sparse tensor: transformation_cache = fc.FeatureTransformationCache( @@ -237,6 +238,7 @@ class LazyColumnTest(test.TestCase): class NumericColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): a = fc.numeric_column('aaa') self.assertEqual('aaa', a.key) @@ -315,6 +317,7 @@ class NumericColumnTest(test.TestCase): 'aaa': parsing_ops.FixedLenFeature((2, 3), dtype=dtypes.int32) }, a.parse_example_spec) + @test_util.run_deprecated_v1 def test_parse_example_no_default_value(self): price = fc.numeric_column('price', shape=[2]) data = example_pb2.Example( @@ -331,6 +334,7 @@ class NumericColumnTest(test.TestCase): self.assertAllEqual([[20., 110.]], self.evaluate(features['price'])) + @test_util.run_deprecated_v1 def test_parse_example_with_default_value(self): price = fc.numeric_column('price', shape=[2], default_value=11.) data = example_pb2.Example( @@ -360,6 +364,7 @@ class NumericColumnTest(test.TestCase): with self.assertRaisesRegexp(TypeError, 'must be a callable'): fc.numeric_column('price', normalizer_fn='NotACallable') + @test_util.run_deprecated_v1 def test_normalizer_fn_transform_feature(self): def _increment_two(input_tensor): @@ -372,6 +377,7 @@ class NumericColumnTest(test.TestCase): self.assertAllEqual([[3., 4.], [7., 8.]], self.evaluate(output[price])) + @test_util.run_deprecated_v1 def test_get_dense_tensor(self): def _increment_two(input_tensor): @@ -395,6 +401,7 @@ class NumericColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'must be a Tensor'): price.transform_feature(transformation_cache, None) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc.numeric_column('aaa', shape=[1, 2], default_value=[[3., 2.]]) a_copy = copy.deepcopy(a) @@ -407,6 +414,7 @@ class NumericColumnTest(test.TestCase): 'aaa', shape=[1, 2], default_value=np.array([[3., 2.]])) self.assertEqual(a.default_value, ((3., 2.),)) + @test_util.run_deprecated_v1 def test_linear_model(self): price = fc.numeric_column('price') with ops.Graph().as_default(): @@ -435,6 +443,7 @@ class NumericColumnTest(test.TestCase): sess.run(price_var.assign([[10.]])) self.assertAllClose([[10.], [50.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): def _increment_two(input_tensor): @@ -519,6 +528,7 @@ class BucketizedColumnTest(test.TestCase): # Column 'aaa` has shape [2] times three buckets -> num_buckets=6. self.assertEqual(6, b.num_buckets) + @test_util.run_deprecated_v1 def test_parse_example(self): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 50]) @@ -536,6 +546,7 @@ class BucketizedColumnTest(test.TestCase): self.assertAllEqual([[20., 110.]], self.evaluate(features['price'])) + @test_util.run_deprecated_v1 def test_transform_feature(self): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 2, 4, 6]) @@ -639,6 +650,7 @@ class BucketizedColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'must be a Tensor'): bucketized_price.transform_feature(transformation_cache, None) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc.numeric_column('aaa', shape=[2]) a_bucketized = fc.bucketized_column(a, boundaries=[0, 1]) @@ -789,6 +801,7 @@ class BucketizedColumnTest(test.TestCase): self.assertAllClose([[11.], [21.], [41.], [51.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 2, 4, 6]) @@ -821,6 +834,7 @@ class BucketizedColumnTest(test.TestCase): class HashedCategoricalColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): a = fc.categorical_column_with_hash_bucket('aaa', 10) self.assertEqual('aaa', a.name) @@ -848,6 +862,7 @@ class HashedCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'dtype must be string or integer'): fc.categorical_column_with_hash_bucket('aaa', 10, dtype=dtypes.float32) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc.categorical_column_with_hash_bucket('aaa', 10) for column in (original, copy.deepcopy(original)): @@ -868,6 +883,7 @@ class HashedCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int32) }, a.parse_example_spec) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_hash_bucket('aaa', 10) data = example_pb2.Example( @@ -890,6 +906,7 @@ class HashedCategoricalColumnTest(test.TestCase): values=np.array([b'omar', b'stringer'], dtype=np.object_), dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_strings_should_be_hashed(self): hashed_sparse = fc.categorical_column_with_hash_bucket('wire', 10) wire_tensor = sparse_tensor.SparseTensor( @@ -943,6 +960,7 @@ class HashedCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'dtype must be compatible'): transformation_cache.get(hashed_sparse, None) + @test_util.run_deprecated_v1 def test_ints_should_be_hashed(self): hashed_sparse = fc.categorical_column_with_hash_bucket( 'wire', 10, dtype=dtypes.int64) @@ -957,6 +975,7 @@ class HashedCategoricalColumnTest(test.TestCase): self.assertAllEqual(expected_values, self.evaluate(output.values)) + @test_util.run_deprecated_v1 def test_int32_64_is_compatible(self): hashed_sparse = fc.categorical_column_with_hash_bucket( 'wire', 10, dtype=dtypes.int64) @@ -971,6 +990,7 @@ class HashedCategoricalColumnTest(test.TestCase): self.assertAllEqual(expected_values, self.evaluate(output.values)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): hashed_sparse = fc.categorical_column_with_hash_bucket('wire', 10) transformation_cache = fc.FeatureTransformationCache({ @@ -986,6 +1006,7 @@ class HashedCategoricalColumnTest(test.TestCase): self.assertEqual( transformation_cache.get(hashed_sparse, None), id_weight_pair.id_tensor) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): hashed_sparse = fc.categorical_column_with_hash_bucket('wire', 10) transformation_cache = fc.FeatureTransformationCache({ @@ -997,6 +1018,7 @@ class HashedCategoricalColumnTest(test.TestCase): self.assertEqual( transformation_cache.get(hashed_sparse, None), id_weight_pair.id_tensor) + @test_util.run_deprecated_v1 def test_linear_model(self): wire_column = fc.categorical_column_with_hash_bucket('wire', 4) self.assertEqual(4, wire_column.num_buckets) @@ -1047,6 +1069,7 @@ class HashedCategoricalColumnTest(test.TestCase): # 'skywalker' -> 2, 'omar' -> 2: wire_var[2] + wire_var[2] = 3+3 = 6 self.assertAllClose(((4.,), (6.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): wire_column = fc.categorical_column_with_hash_bucket('wire', 4) self.assertEqual(['wire'], wire_column.parents) @@ -1148,6 +1171,7 @@ class CrossedColumnTest(test.TestCase): crossed = fc.crossed_column([b, 'c'], 15) self.assertEqual(15, crossed.num_buckets) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc.numeric_column('a', dtype=dtypes.int32) b = fc.bucketized_column(a, boundaries=[0, 1]) @@ -1161,6 +1185,7 @@ class CrossedColumnTest(test.TestCase): self.assertEqual(15, crossed2_copy.hash_bucket_size) self.assertEqual(5, crossed2_copy.hash_key) + @test_util.run_deprecated_v1 def test_parse_example(self): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 50]) @@ -1190,6 +1215,7 @@ class CrossedColumnTest(test.TestCase): self.evaluate(wire_sparse.values)) self.assertAllEqual([1, 2], self.evaluate(wire_sparse.dense_shape)) + @test_util.run_deprecated_v1 def test_transform_feature(self): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 50]) @@ -1214,6 +1240,7 @@ class CrossedColumnTest(test.TestCase): self.assertIn(val, list(range(hash_bucket_size))) self.assertAllEqual([2, 4], output_val.dense_shape) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): a = fc.numeric_column('a', dtype=dtypes.int32, shape=(2,)) b = fc.bucketized_column(a, boundaries=(0, 1)) @@ -1285,6 +1312,7 @@ class CrossedColumnTest(test.TestCase): self.assertAllEqual(expected_values, id_tensor_eval.values) self.assertAllEqual((2, 4), id_tensor_eval.dense_shape) + @test_util.run_deprecated_v1 def test_linear_model(self): """Tests linear_model. @@ -1520,6 +1548,7 @@ class CrossedColumnTest(test.TestCase): sess.run(bias.assign((.1,))) self.assertAllClose(((3.1,), (14.1,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): a = fc.numeric_column('a', dtype=dtypes.int32, shape=(2,)) b = fc.bucketized_column(a, boundaries=(0, 1)) @@ -2077,6 +2106,7 @@ class LinearModelTest(test.TestCase): features['price2']: [[1.], [5.]], }) + @test_util.run_deprecated_v1 def test_with_numpy_input_fn(self): price = fc.numeric_column('price') price_buckets = fc.bucketized_column( @@ -2115,6 +2145,7 @@ class LinearModelTest(test.TestCase): coord.request_stop() coord.join(threads) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): price = fc.numeric_column('price') price_buckets = fc.bucketized_column( @@ -2154,6 +2185,7 @@ class LinearModelTest(test.TestCase): self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], self.evaluate(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): price = fc.numeric_column('price') price_buckets = fc.bucketized_column( @@ -2198,6 +2230,7 @@ class LinearModelTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): price = fc.numeric_column('price') features = { @@ -2835,6 +2868,7 @@ class OldLinearModelTest(test.TestCase): features['price2']: [[1.], [5.]], }) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): price = fc.numeric_column('price') price_buckets = fc.bucketized_column( @@ -2875,6 +2909,7 @@ class OldLinearModelTest(test.TestCase): self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], self.evaluate(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): price = fc.numeric_column('price') price_buckets = fc.bucketized_column( @@ -2920,6 +2955,7 @@ class OldLinearModelTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): price = fc.numeric_column('price') features = { @@ -2962,6 +2998,7 @@ class OldLinearModelTest(test.TestCase): sess.run(bias2.assign([5.])) self.assertAllClose([[25.], [105.]], self.evaluate(predictions2)) + @test_util.run_deprecated_v1 def test_linear_model_v1_shared_embedding_all_other_v2(self): price = fc.numeric_column('price') # v2 some_sparse_column = fc.categorical_column_with_hash_bucket( @@ -3001,6 +3038,7 @@ class OldLinearModelTest(test.TestCase): self.assertAllClose([0.], self.evaluate(bias)) + @test_util.run_deprecated_v1 def test_linear_model_v1_shared_embedding_with_v2_cat_all_other_v2(self): price = fc.numeric_column('price') # v2 some_sparse_column = fc.categorical_column_with_hash_bucket( @@ -3040,6 +3078,7 @@ class OldLinearModelTest(test.TestCase): self.assertAllClose([0.], self.evaluate(bias)) + @test_util.run_deprecated_v1 def test_linear_model_v1_v2_mix(self): price = fc.numeric_column('price') # v2 some_sparse_column = fc.categorical_column_with_hash_bucket( @@ -3079,6 +3118,7 @@ class OldLinearModelTest(test.TestCase): self.assertAllClose([0.], self.evaluate(bias)) + @test_util.run_deprecated_v1 def test_linear_model_v2_shared_embedding_all_other_v1(self): price = fc.numeric_column('price') # v1 some_sparse_column = fc.categorical_column_with_hash_bucket( @@ -3468,6 +3508,7 @@ class DenseFeaturesTest(test.TestCase): expected_var_names, [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_multiple_layers_with_same_shared_embedding_column(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -3501,6 +3542,7 @@ class DenseFeaturesTest(test.TestCase): ['aaa_bbb_shared_embedding:0'], [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_multiple_layers_with_same_shared_embedding_column_diff_graphs(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -3552,6 +3594,7 @@ class DenseFeaturesTest(test.TestCase): ['aaa_bbb_shared_embedding:0'], [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_with_numpy_input_fn(self): embedding_values = ( (1., 2., 3., 4., 5.), # id 0 @@ -3596,6 +3639,7 @@ class DenseFeaturesTest(test.TestCase): coord.request_stop() coord.join(threads) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): embedding_values = ( (1., 2., 3., 4., 5.), # id 0 @@ -3652,6 +3696,7 @@ class DenseFeaturesTest(test.TestCase): [1., 0., 0., 1., 2., 3., 4., 5., 12.]], sess.run(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): embedding_values = ( (1., 2.), # id 0 @@ -3710,6 +3755,7 @@ class DenseFeaturesTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): # price has 1 dimension in dense_features price = fc.numeric_column('price') @@ -3967,6 +4013,7 @@ class FunctionalInputLayerTest(test.TestCase): variables_lib.Variable) self.assertAllEqual(cols_to_vars[some_embedding_column][0].shape, [5, 10]) + @test_util.run_deprecated_v1 def test_fills_cols_to_vars_shared_embedding(self): # Provide 5 DenseColumn's to input_layer: a NumericColumn, a # BucketizedColumn, an EmbeddingColumn, two SharedEmbeddingColumns. The @@ -4167,6 +4214,7 @@ class FunctionalInputLayerTest(test.TestCase): expected_var_names, [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) + @test_util.run_deprecated_v1 def test_with_1d_sparse_tensor(self): embedding_values = ( (1., 2., 3., 4., 5.), # id 0 @@ -4223,6 +4271,7 @@ class FunctionalInputLayerTest(test.TestCase): [1., 0., 0., 1., 2., 3., 4., 5., 12.]], sess.run(net)) + @test_util.run_deprecated_v1 def test_with_1d_unknown_shape_sparse_tensor(self): embedding_values = ( (1., 2.), # id 0 @@ -4281,6 +4330,7 @@ class FunctionalInputLayerTest(test.TestCase): features['country']: country_data })) + @test_util.run_deprecated_v1 def test_with_rank_0_feature(self): # price has 1 dimension in input_layer price = fc.numeric_column('price') @@ -4444,6 +4494,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'python/feature_column/testdata/wire_vocabulary.txt') self._wire_vocabulary_size = 3 + @test_util.run_deprecated_v1 def test_defaults(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='path_to_file', vocabulary_size=3) @@ -4460,6 +4511,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): fc.categorical_column_with_vocabulary_file( key=('aaa',), vocabulary_file='path_to_file', vocabulary_size=3) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4472,6 +4524,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int32) }, column.parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4496,6 +4549,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='', vocabulary_size=3) + @test_util.run_deprecated_v1 def test_invalid_vocabulary_file(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='file_does_not_exist', vocabulary_size=10) @@ -4522,6 +4576,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): vocabulary_file=self._wire_vocabulary_file_name, vocabulary_size=0) + @test_util.run_deprecated_v1 def test_too_large_vocabulary_size(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4596,6 +4651,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='path_to_file', vocabulary_size=3) @@ -4619,6 +4675,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): values=np.array([b'omar', b'stringer'], dtype=np.object_), dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4645,6 +4702,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_none_vocabulary_size(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file=self._wire_vocabulary_file_name) @@ -4669,6 +4727,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_transform_feature(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4692,6 +4751,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): values=np.array((2, -1, 0), dtype=np.int64), dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4713,6 +4773,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): values=np.array((2, -1, 0), dtype=np.int64), dense_shape=(2, 2)), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_default_value_in_vocabulary(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4740,6 +4801,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4767,6 +4829,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_small_vocabulary_size(self): # 'marlo' is the last entry in our vocabulary file, so be setting # `vocabulary_size` to 1 less than number of entries in file, we take @@ -4796,6 +4859,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4823,6 +4887,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_dense_input(self): default_value = -100 column = fc.categorical_column_with_vocabulary_file( @@ -4847,6 +4912,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): values=np.array((2, default_value, 0, 4), dtype=np.int64), dense_shape=(3, 3)), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_file( key='aaa', @@ -4875,6 +4941,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_linear_model(self): wire_column = fc.categorical_column_with_vocabulary_file( key='wire', @@ -4933,6 +5000,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): wire_column = fc.categorical_column_with_vocabulary_file( key='wire', @@ -4984,6 +5052,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, column.parse_example_spec) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -4995,6 +5064,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int32) }, column.parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(12, 24, 36), dtype=dtypes.int32) @@ -5089,6 +5159,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) + @test_util.run_deprecated_v1 def test_parse_example_string(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5112,6 +5183,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): values=np.array([b'omar', b'stringer'], dtype=np.object_), dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_parse_example_int(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(11, 21, 31)) @@ -5133,6 +5205,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): indices=[[0, 0], [0, 1]], values=[11, 21], dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5157,6 +5230,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_transform_feature(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5178,6 +5252,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): values=np.array((2, -1, 0), dtype=np.int64), dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5197,6 +5272,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): values=np.array((2, -1, 0), dtype=np.int64), dense_shape=(2, 2)), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_default_value_in_vocabulary(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -5223,6 +5299,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -5249,6 +5326,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -5275,6 +5353,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_dense_input(self): default_value = -100 column = fc.categorical_column_with_vocabulary_list( @@ -5300,6 +5379,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): values=np.array((2, default_value, 0, 4), dtype=np.int64), dense_shape=(3, 3)), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_int32_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -5327,6 +5407,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_linear_model(self): wire_column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -5383,6 +5464,7 @@ class VocabularyListCategoricalColumnTest(test.TestCase): # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): wire_column = fc.categorical_column_with_vocabulary_list( key='aaa', @@ -5420,6 +5502,7 @@ class IdentityCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'key must be a string.'): fc.categorical_column_with_identity(key=('aaa',), num_buckets=3) + @test_util.run_deprecated_v1 def test_deep_copy(self): original = fc.categorical_column_with_identity(key='aaa', num_buckets=3) for column in (original, copy.deepcopy(original)): @@ -5459,6 +5542,7 @@ class IdentityCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=30) data = example_pb2.Example( @@ -5480,6 +5564,7 @@ class IdentityCategoricalColumnTest(test.TestCase): values=np.array([11, 21], dtype=np.int64), dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_get_sparse_tensors(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -5501,6 +5586,7 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_transform_feature(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -5519,6 +5605,7 @@ class IdentityCategoricalColumnTest(test.TestCase): values=np.array((0, 1, 0), dtype=np.int64), dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_dense_input(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) id_weight_pair = column.get_sparse_tensors( @@ -5537,6 +5624,7 @@ class IdentityCategoricalColumnTest(test.TestCase): values=np.array((0, 1, 0), dtype=np.int64), dense_shape=(2, 2)), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_inputs_too_small(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -5553,6 +5641,7 @@ class IdentityCategoricalColumnTest(test.TestCase): with self.assertRaisesRegexp(errors.OpError, 'assert_greater_or_equal_0'): self.evaluate(id_weight_pair.id_tensor) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_inputs_too_big(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( @@ -5570,6 +5659,7 @@ class IdentityCategoricalColumnTest(test.TestCase): 'assert_less_than_num_buckets'): self.evaluate(id_weight_pair.id_tensor) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_default_value(self): column = fc.categorical_column_with_identity( key='aaa', num_buckets=4, default_value=3) @@ -5594,6 +5684,7 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=inputs.dense_shape), self.evaluate(id_weight_pair.id_tensor)) + @test_util.run_deprecated_v1 def test_get_sparse_tensors_with_default_value_and_placeholder_inputs(self): column = fc.categorical_column_with_identity( key='aaa', num_buckets=4, default_value=3) @@ -5624,6 +5715,7 @@ class IdentityCategoricalColumnTest(test.TestCase): input_shape: (2, 2), })) + @test_util.run_deprecated_v1 def test_linear_model(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) self.assertEqual(3, column.num_buckets) @@ -5674,6 +5766,7 @@ class IdentityCategoricalColumnTest(test.TestCase): # weight_var[2] + weight_var[1] = 3+2 = 5 self.assertAllClose(((1.,), (5.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) @@ -5827,6 +5920,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllEqual([[0., 1., 1., 0.]], self.evaluate(output)) + @test_util.run_deprecated_v1 def test_deep_copy(self): a = fc.categorical_column_with_hash_bucket('a', 4) column = fc.indicator_column(a) @@ -5835,6 +5929,7 @@ class IndicatorColumnTest(test.TestCase): self.assertEqual(column.name, 'a_indicator') self.assertEqual(column.variable_shape, [1, 4]) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5859,6 +5954,7 @@ class IndicatorColumnTest(test.TestCase): values=np.array([b'omar', b'stringer'], dtype=np.object_), dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_transform(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -5878,6 +5974,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllEqual([[0, 0, 1], [1, 0, 0]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_transform_with_weighted_column(self): # Github issue 12557 ids = fc.categorical_column_with_vocabulary_list( @@ -5896,6 +5993,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllEqual([[6., 4., 3.]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_transform_with_missing_value_in_weighted_column(self): # Github issue 12583 ids = fc.categorical_column_with_vocabulary_list( @@ -5914,6 +6012,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllEqual([[0., 4., 2.]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_transform_with_missing_value_in_categorical_column(self): # Github issue 12583 ids = fc.categorical_column_with_vocabulary_list( @@ -5930,6 +6029,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllEqual([[0., 1., 1.]], self.evaluate(indicator_tensor)) + @test_util.run_deprecated_v1 def test_linear_model(self): animal = fc.indicator_column( fc.categorical_column_with_identity('animal', num_buckets=4)) @@ -5997,6 +6097,7 @@ class IndicatorColumnTest(test.TestCase): self.evaluate(weight_var.assign([[1.], [2.], [3.], [4.]])) self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_dense_features(self): animal = fc.indicator_column( fc.categorical_column_with_identity('animal', num_buckets=4)) @@ -6013,6 +6114,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) + @test_util.run_deprecated_v1 def test_input_layer(self): animal = fc.indicator_column( fc.categorical_column_with_identity('animal', num_buckets=4)) @@ -6045,6 +6147,7 @@ class IndicatorColumnTest(test.TestCase): self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) + @test_util.run_deprecated_v1 def test_serialization(self): parent = fc.categorical_column_with_identity('animal', num_buckets=4) animal = fc.indicator_column(parent) @@ -6114,6 +6217,7 @@ class _TestStateManager(fc.StateManager): class EmbeddingColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): categorical_column = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -6142,6 +6246,7 @@ class EmbeddingColumnTest(test.TestCase): categorical_column, dimension=embedding_dimension) self.assertFalse(embedding_column._is_v2_column) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): categorical_column = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -6168,6 +6273,7 @@ class EmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column.parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): categorical_column = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -6200,12 +6306,14 @@ class EmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column.parse_example_spec) + @test_util.run_deprecated_v1 def test_invalid_initializer(self): categorical_column = fc.categorical_column_with_identity( key='aaa', num_buckets=3) with self.assertRaisesRegexp(ValueError, 'initializer must be callable'): fc.embedding_column(categorical_column, dimension=2, initializer='not_fn') + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -6230,6 +6338,7 @@ class EmbeddingColumnTest(test.TestCase): values=np.array([b'omar', b'stringer'], dtype=np.object_), dense_shape=[1, 2]), self.evaluate(features['aaa'])) + @test_util.run_deprecated_v1 def test_transform_feature(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=3) a_embedded = fc.embedding_column(a, dimension=2) @@ -6250,6 +6359,7 @@ class EmbeddingColumnTest(test.TestCase): _assert_sparse_tensor_value(self, self.evaluate(output_a), self.evaluate(output_embedded)) + @test_util.run_deprecated_v1 def test_get_dense_tensor(self): # Inputs. vocabulary_size = 3 @@ -6315,6 +6425,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_old_categorical(self): # Inputs. vocabulary_size = 3 @@ -6378,6 +6489,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_3d(self): # Inputs. vocabulary_size = 4 @@ -6445,6 +6557,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_placeholder_inputs(self): # Inputs. vocabulary_size = 3 @@ -6524,6 +6637,7 @@ class EmbeddingColumnTest(test.TestCase): input_shape: sparse_input.dense_shape, })) + @test_util.run_deprecated_v1 def test_get_dense_tensor_restore_from_ckpt(self): # Inputs. vocabulary_size = 3 @@ -6587,6 +6701,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + @test_util.run_deprecated_v1 def test_linear_model(self): # Inputs. batch_size = 4 @@ -6668,6 +6783,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_dense_features(self): # Inputs. vocabulary_size = 3 @@ -6734,6 +6850,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, self.evaluate(trainable_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) + @test_util.run_deprecated_v1 def test_dense_features_not_trainable(self): # Inputs. vocabulary_size = 3 @@ -6799,6 +6916,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) + @test_util.run_deprecated_v1 def test_input_layer(self): # Inputs. vocabulary_size = 3 @@ -7028,6 +7146,7 @@ class EmbeddingColumnTest(test.TestCase): self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), self.evaluate(predictions)) + @test_util.run_deprecated_v1 def test_serialization(self): def _initializer(shape, dtype, partition_info): @@ -7081,6 +7200,7 @@ class EmbeddingColumnTest(test.TestCase): class SharedEmbeddingColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -7105,6 +7225,7 @@ class SharedEmbeddingColumnTest(test.TestCase): 'bbb': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column_b.parse_example_spec) + @test_util.run_deprecated_v1 def test_all_constructor_args(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -7136,6 +7257,7 @@ class SharedEmbeddingColumnTest(test.TestCase): 'bbb': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column_b.parse_example_spec) + @test_util.run_deprecated_v1 def test_deep_copy(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -7167,6 +7289,7 @@ class SharedEmbeddingColumnTest(test.TestCase): 'aaa': parsing_ops.VarLenFeature(dtypes.int64) }, embedding_column_a.parse_example_spec) + @test_util.run_deprecated_v1 def test_invalid_initializer(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -7178,6 +7301,7 @@ class SharedEmbeddingColumnTest(test.TestCase): dimension=2, initializer='not_fn') + @test_util.run_deprecated_v1 def test_incompatible_column_type(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -7192,6 +7316,7 @@ class SharedEmbeddingColumnTest(test.TestCase): [categorical_column_a, categorical_column_b, categorical_column_c], dimension=2) + @test_util.run_deprecated_v1 def test_weighted_categorical_column_ok(self): categorical_column_a = fc.categorical_column_with_identity( key='aaa', num_buckets=3) @@ -7209,6 +7334,7 @@ class SharedEmbeddingColumnTest(test.TestCase): [weighted_categorical_column_a, weighted_categorical_column_b], dimension=2) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -7246,6 +7372,7 @@ class SharedEmbeddingColumnTest(test.TestCase): values=np.array([b'stringer', b'marlo'], dtype=np.object_), dense_shape=[1, 2]), self.evaluate(features['bbb'])) + @test_util.run_deprecated_v1 def test_transform_feature(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=3) b = fc.categorical_column_with_identity(key='bbb', num_buckets=3) @@ -7277,6 +7404,7 @@ class SharedEmbeddingColumnTest(test.TestCase): _assert_sparse_tensor_value(self, self.evaluate(output_b), self.evaluate(output_b_embedded)) + @test_util.run_deprecated_v1 def test_get_dense_tensor(self): # Inputs. vocabulary_size = 3 @@ -7348,6 +7476,7 @@ class SharedEmbeddingColumnTest(test.TestCase): self.assertAllEqual(expected_lookups_a, self.evaluate(embedding_lookup_a)) self.assertAllEqual(expected_lookups_b, self.evaluate(embedding_lookup_b)) + @test_util.run_deprecated_v1 def test_get_dense_tensor_placeholder_inputs(self): # Inputs. vocabulary_size = 3 @@ -7407,6 +7536,7 @@ class SharedEmbeddingColumnTest(test.TestCase): with _initialized_session() as sess: sess.run([embedding_lookup_a, embedding_lookup_b], feed_dict=feed_dict) + @test_util.run_deprecated_v1 def test_linear_model(self): # Inputs. batch_size = 2 @@ -7619,12 +7749,15 @@ class SharedEmbeddingColumnTest(test.TestCase): self.evaluate(shared_embedding_vars[0])) self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) + @test_util.run_deprecated_v1 def test_dense_features(self): self._test_dense_features() + @test_util.run_deprecated_v1 def test_dense_features_no_trainable(self): self._test_dense_features(trainable=False) + @test_util.run_deprecated_v1 def test_serialization(self): def _initializer(shape, dtype, partition_info): @@ -7647,6 +7780,7 @@ class SharedEmbeddingColumnTest(test.TestCase): class WeightedCategoricalColumnTest(test.TestCase): + @test_util.run_deprecated_v1 def test_defaults(self): column = fc.weighted_categorical_column( categorical_column=fc.categorical_column_with_identity( @@ -7667,6 +7801,7 @@ class WeightedCategoricalColumnTest(test.TestCase): weight_feature_key='values') self.assertFalse(column._is_v2_column) + @test_util.run_deprecated_v1 def test_deep_copy(self): """Tests deepcopy of categorical_column_with_hash_bucket.""" original = fc.weighted_categorical_column( @@ -7732,6 +7867,7 @@ class WeightedCategoricalColumnTest(test.TestCase): 'values is not in features dictionary'): fc._transform_features_v2({'ids': inputs}, (column,), None) + @test_util.run_deprecated_v1 def test_parse_example(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) @@ -7766,6 +7902,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array([1., 10.], dtype=np.float32), dense_shape=[1, 2]), self.evaluate(features['weights'])) + @test_util.run_deprecated_v1 def test_transform_features(self): column = fc.weighted_categorical_column( categorical_column=fc.categorical_column_with_identity( @@ -7798,6 +7935,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array(weights.values, dtype=np.float32), dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) + @test_util.run_deprecated_v1 def test_transform_features_dense_input(self): column = fc.weighted_categorical_column( categorical_column=fc.categorical_column_with_identity( @@ -7828,6 +7966,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array(weights.values, dtype=np.float32), dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) + @test_util.run_deprecated_v1 def test_transform_features_dense_weights(self): column = fc.weighted_categorical_column( categorical_column=fc.categorical_column_with_identity( @@ -7856,6 +7995,7 @@ class WeightedCategoricalColumnTest(test.TestCase): values=np.array((.5, 1., .1), dtype=np.float32), dense_shape=(2, 2)), self.evaluate(weight_tensor)) + @test_util.run_deprecated_v1 def test_linear_model(self): column = fc.weighted_categorical_column( categorical_column=fc.categorical_column_with_identity( @@ -8106,6 +8246,7 @@ class WeightedCategoricalColumnTest(test.TestCase): # TODO(ptucker): Add test with embedding of weighted categorical. + @test_util.run_deprecated_v1 def test_serialization(self): categorical_column = fc.categorical_column_with_identity( key='ids', num_buckets=3) diff --git a/tensorflow/python/framework/file_system_test.py b/tensorflow/python/framework/file_system_test.py index 066d34e781..8687bc5a78 100644 --- a/tensorflow/python/framework/file_system_test.py +++ b/tensorflow/python/framework/file_system_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import os from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.framework import load_library from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import io_ops @@ -36,6 +37,7 @@ class FileSystemTest(test.TestCase): "test_file_system.so") load_library.load_file_system_library(file_system_library) + @test_util.run_deprecated_v1 def testBasic(self): with self.cached_session() as sess: reader = io_ops.WholeFileReader("test_reader") diff --git a/tensorflow/python/framework/function_def_to_graph_test.py b/tensorflow/python/framework/function_def_to_graph_test.py index b2ef64f873..ddf1a6e74d 100644 --- a/tensorflow/python/framework/function_def_to_graph_test.py +++ b/tensorflow/python/framework/function_def_to_graph_test.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import function_def_to_graph from tensorflow.python.framework import graph_to_function_def from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.framework import test_ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops @@ -52,6 +53,7 @@ class FunctionDefToGraphTest(test.TestCase): fdef.signature.name = "_whats_in_a_name" return fdef + @test_util.run_deprecated_v1 def testInputsAndOutputs(self): fdef = self._build_function_def() g = function_def_to_graph.function_def_to_graph(fdef) @@ -186,6 +188,7 @@ class FunctionDefToGraphDefTest(test.TestCase): self.assertEqual(g.node[0].attr["shape"].shape.unknown_rank, False) self.assertFalse("shape" in g.node[2].attr) + @test_util.run_deprecated_v1 def testFunctionCallsFromFunction(self): x = constant_op.constant(5.0) y = constant_op.constant(10.0) diff --git a/tensorflow/python/framework/function_test.py b/tensorflow/python/framework/function_test.py index 1a17a48050..d71f06ea52 100644 --- a/tensorflow/python/framework/function_test.py +++ b/tensorflow/python/framework/function_test.py @@ -35,6 +35,7 @@ from tensorflow.python.framework import function from tensorflow.python.framework import graph_to_function_def from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.framework.errors import InvalidArgumentError from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops @@ -104,6 +105,7 @@ class FunctionTest(test.TestCase): with session.Session() as sess: self.assertAllEqual([18.0], self.evaluate(call)) + @test_util.run_deprecated_v1 def testIdentityImplicitDeref(self): @function.Defun(dtypes.float32, func_name="MyIdentity") @@ -322,6 +324,7 @@ class FunctionTest(test.TestCase): self.assertEqual(x.get_shape(), dx.get_shape()) self.assertEqual(y.get_shape(), dy.get_shape()) + @test_util.run_deprecated_v1 def testSymGradAttr(self): @function.Defun(noinline=True) @@ -438,6 +441,7 @@ class FunctionTest(test.TestCase): "assertion failed.*-3"): self.assertAllEqual(Foo(constant_op.constant(-3.0)).eval(), 6.0) + @test_util.run_deprecated_v1 def testAssertWrapper(self): @function.Defun(dtypes.float32) @@ -452,6 +456,7 @@ class FunctionTest(test.TestCase): "assertion"): _ = MyFn(100.0).eval() + @test_util.run_deprecated_v1 def testWhileLoopCallsFunc(self): with self.session(use_gpu=True) as sess: @@ -471,6 +476,7 @@ class FunctionTest(test.TestCase): ans = self.evaluate(loop) self.assertAllClose(ans, 131072.) + @test_util.run_deprecated_v1 def testControlFlowStrictness(self): """Inlined functions must not execute in a untaken control flow branch.""" @@ -517,6 +523,7 @@ class FunctionTest(test.TestCase): "assertion"): sess.run(loop, {pred: True, x: 3}) + @test_util.run_deprecated_v1 def testVar(self): @function.Defun(dtypes.float32) @@ -532,6 +539,7 @@ class FunctionTest(test.TestCase): variables.global_variables_initializer().run() self.assertAllEqual(z.eval(), 101.) + @test_util.run_deprecated_v1 def testResourceVarAsImplicitInput(self): g = ops.Graph() with g.as_default(), ops.device("cpu:0"): @@ -707,6 +715,7 @@ class FunctionTest(test.TestCase): gdef = g.as_graph_def() self.assertEqual(0, len(gdef.library.function)) + @test_util.run_deprecated_v1 def testReduction(self): g = ops.Graph() @@ -735,6 +744,7 @@ class FunctionTest(test.TestCase): self.assertAllClose(vals[0], vals[1]) self.assertAllClose(vals[2], vals[3]) + @test_util.run_deprecated_v1 def testCapture(self): g = ops.Graph() with g.as_default(): @@ -781,6 +791,7 @@ class FunctionTest(test.TestCase): # NOTE: We still do not support capturing control deps. _ = Foo(x) + @test_util.run_deprecated_v1 def testCaptureInWhileLoop(self): g = ops.Graph() with g.as_default(): @@ -796,6 +807,7 @@ class FunctionTest(test.TestCase): with self.session(graph=g) as sess: self.assertEqual(self.evaluate(y), 10) + @test_util.run_deprecated_v1 def testCaptureInCond(self): g = ops.Graph() with g.as_default(): @@ -825,6 +837,7 @@ class FunctionTest(test.TestCase): self.assertEqual("Foo_aCYSbwBkR5A", Foo.instantiate([dtypes.float32] * 3).name) + @test_util.run_deprecated_v1 def testSignatureHash(self): # Foo.Inner and Bar.Inner have identical function body but have # different signatures. They should be treated as two different functions. @@ -877,6 +890,7 @@ class FunctionTest(test.TestCase): y = Bar(array_ops.zeros([1, 2, 3])) self.assertAllEqual(y.get_shape().as_list(), [1, 1, 2, 3]) + @test_util.run_deprecated_v1 def testVariableReuse(self): def LinearWithReuse(input_tensor, reuse=None): @@ -905,6 +919,7 @@ class FunctionTest(test.TestCase): output_op, feed_dict={input_op: np.random.rand(32, 100)}) self.assertEqual(output_val.shape, (32, 100)) + @test_util.run_deprecated_v1 def testFunctionCallInDifferentVariableScopes(self): @function.Defun(dtypes.float32) @@ -968,6 +983,7 @@ class FunctionTest(test.TestCase): self.assertAllClose( np.array([1.0, 0.0]).astype(np.float32), sess.run(dinp, {inp: x})) + @test_util.run_deprecated_v1 def testFunctionMarkedStateful(self): @function.Defun(dtypes.int32, dtypes.float32) @@ -995,6 +1011,7 @@ class FunctionTest(test.TestCase): self.assertEqual(100, self.evaluate(result_2)) self.assertEqual((4.0, 100), sess.run((result_1, result_2))) + @test_util.run_deprecated_v1 def testStatefulFunction(self): @function.Defun() @@ -1037,6 +1054,7 @@ class FunctionTest(test.TestCase): self.assertFalse(all(val3 == val1)) self.assertFalse(all(val4 == val2)) + @test_util.run_deprecated_v1 def testSameFunctionOnTwoDevices(self): @function.Defun(dtypes.float32) @@ -1056,6 +1074,7 @@ class FunctionTest(test.TestCase): self.assertEqual(44.0, self.evaluate(f_1)) self.assertEqual((42.0, 44.0), sess.run((f_0, f_1))) + @test_util.run_deprecated_v1 def testGuaranteedConstsAreCaptured(self): var = variables.Variable(1.0) const = array_ops.guarantee_const(var) @@ -1079,6 +1098,7 @@ class FunctionTest(test.TestCase): self.evaluate(var.initializer) _ = sess.run(CapturesGuaranteedConst(), {also_not_const: 1.0}) + @test_util.run_deprecated_v1 def testSameFunctionDifferentGrads(self): def PartOne(x): @@ -1150,6 +1170,7 @@ class FunctionsFromProtos(test.TestCase): self.assertEqual(func.declared_input_types, new_func.declared_input_types) self.assertEqual(func.captured_inputs, new_func.captured_inputs) + @test_util.run_deprecated_v1 def testBasic(self): @function.Defun(dtypes.float32, dtypes.float32) @@ -1359,6 +1380,7 @@ class FunctionsFromProtos(test.TestCase): class FunctionOverloadTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): @function.Defun() @@ -1411,6 +1433,7 @@ class FunctionOverloadTest(test.TestCase): class FunctionCaptureByValueTest(test.TestCase): + @test_util.run_deprecated_v1 def testCaptureByValue(self): g = ops.Graph() with g.as_default(): @@ -1634,6 +1657,7 @@ class FunctionInlineControlTest(test.TestCase): class ModuleFunctionTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): @function.Defun(*[dtypes.float32] * 3) @@ -1717,10 +1741,12 @@ class VariableHoistingTest(test.TestCase): self.assertAllEqual(db.shape, (64,)) self.assertAllClose(np.sum(db), 0.509, rtol=1e-2) + @test_util.run_deprecated_v1 def testBasic(self): self._testSimpleModel(True) self._testSimpleModel(False) + @test_util.run_deprecated_v1 def testBasicResource(self): self._testSimpleModel(True, use_resource=True) self._testSimpleModel(False, use_resource=True) diff --git a/tensorflow/python/framework/graph_util_test.py b/tensorflow/python/framework/graph_util_test.py index 10a01c71f2..4e7408ad49 100644 --- a/tensorflow/python/framework/graph_util_test.py +++ b/tensorflow/python/framework/graph_util_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import graph_util from tensorflow.python.framework import importer from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_state_ops from tensorflow.python.ops import math_ops # pylint: disable=unused-import from tensorflow.python.ops import math_ops as math_ops_lib @@ -102,6 +103,7 @@ class DeviceFunctionsTest(test.TestCase): self.assertDeviceEqual(var_5.device, "/device:GPU:0") self.assertDeviceEqual(var_6.device, "/device:CPU:0") + @test_util.run_deprecated_v1 def testNestedDeviceFunctions(self): with ops.Graph().as_default(): var_0 = variables.VariableV1(0) diff --git a/tensorflow/python/framework/meta_graph_test.py b/tensorflow/python/framework/meta_graph_test.py index cc93f8b1b8..46ce4616a5 100644 --- a/tensorflow/python/framework/meta_graph_test.py +++ b/tensorflow/python/framework/meta_graph_test.py @@ -63,6 +63,7 @@ def _TestDir(test_name): class SimpleMetaGraphTest(test.TestCase): + @test_util.run_deprecated_v1 def testNoVariables(self): test_dir = _TestDir("no_variables") filename = os.path.join(test_dir, "metafile") @@ -116,6 +117,7 @@ class SimpleMetaGraphTest(test.TestCase): {new_input_tensor: input_feed_value}) self.assertEqual(new_output_value, output_value) + @test_util.run_deprecated_v1 def testStrippedOpListNestedFunctions(self): with self.cached_session(): # Square two levels deep @@ -158,6 +160,7 @@ class SimpleMetaGraphTest(test.TestCase): op_list = meta_graph.stripped_op_list_for_graph(graph) self.assertEqual(["Const"], [op.name for op in op_list.op]) + @test_util.run_deprecated_v1 def testDefaultAttrStripping(self): """Verifies that default attributes are stripped from a graph def.""" @@ -210,6 +213,7 @@ class SimpleMetaGraphTest(test.TestCase): self.assertEqual(node_def.attr["Tout"].type, dtypes.complex128) self.assertTrue(meta_graph_def.meta_info_def.stripped_default_attrs) + @test_util.run_deprecated_v1 def testDefaultAttrStrippingNestedFunctions(self): """Verifies that default attributes are stripped from function node defs.""" with self.cached_session(): @@ -261,6 +265,7 @@ class SimpleMetaGraphTest(test.TestCase): self.assertEqual(node_def.attr["attr_1"].i, 1) self.assertTrue(meta_graph_def.meta_info_def.stripped_default_attrs) + @test_util.run_deprecated_v1 def testVariableObjectsAreSharedAmongCollections(self): with ops.Graph().as_default() as graph1: v = variables.Variable(3.0) @@ -454,6 +459,7 @@ class ScopedMetaGraphTest(test.TestCase): # Verifies that we can export the subgraph under each layer and import # them into new layers in a new graph. + @test_util.run_deprecated_v1 def testScopedExportAndImport(self): test_dir = _TestDir("scoped_export_import") filenames = [ @@ -522,6 +528,7 @@ class ScopedMetaGraphTest(test.TestCase): actual_grad_value = self.evaluate(grad) self.assertEqual(expected_grad_value, actual_grad_value) + @test_util.run_deprecated_v1 def testImportWhileLoopInWhileLoop(self): # Create a simple while loop. with ops.Graph().as_default(): @@ -547,6 +554,7 @@ class ScopedMetaGraphTest(test.TestCase): self.evaluate(variables.global_variables_initializer()) self.evaluate(x) + @test_util.run_deprecated_v1 def testScopedImportUnderNameScope(self): graph = ops.Graph() with graph.as_default(): @@ -562,6 +570,7 @@ class ScopedMetaGraphTest(test.TestCase): self.assertEqual(list(imported_variables.values())[0].name, "foo/bar/myvar:0") + @test_util.run_deprecated_v1 def testScopedImportUnderNameScopeNoVarScope(self): graph = ops.Graph() with graph.as_default(): @@ -590,6 +599,7 @@ class ScopedMetaGraphTest(test.TestCase): self.assertEqual(list(imported_variables.values())[0].name, "s" + suffix + "/v:0") + @test_util.run_deprecated_v1 def testScopedImportWithSelectedCollections(self): meta_graph_filename = os.path.join( _TestDir("selected_collections_import"), "meta_graph.pb") @@ -687,6 +697,7 @@ class ScopedMetaGraphTest(test.TestCase): # Verifies that we can export the subgraph containing a FIFOQueue under # "queue1" and import it into "new_queue1" in a new graph. + @test_util.run_deprecated_v1 def testScopedWithQueue(self): test_dir = _TestDir("scoped_with_queue") orig_meta_graph = self._testScopedExportWithQueue(test_dir, @@ -749,12 +760,15 @@ class ScopedMetaGraphTest(test.TestCase): for n, e in zip(nodes, expected): self.assertEqual([e], graph2.get_operation_by_name(n).get_attr("_class")) + @test_util.run_deprecated_v1 def testExportNestedNames(self): self.doTestExportNestedNames(use_resource=False) + @test_util.run_deprecated_v1 def testExportNestedNamesResource(self): self.doTestExportNestedNames(use_resource=True) + @test_util.run_deprecated_v1 def testPotentialCycle(self): graph1 = ops.Graph() with graph1.as_default(): @@ -783,6 +797,7 @@ class ScopedMetaGraphTest(test.TestCase): 4.0, shape=[2, 2]) }) + @test_util.run_deprecated_v1 def testClearDevices(self): graph1 = ops.Graph() with graph1.as_default(): @@ -842,6 +857,7 @@ class ScopedMetaGraphTest(test.TestCase): class MetaGraphWithVariableScopeTest(test.TestCase): + @test_util.run_deprecated_v1 def testMetricsCollection(self): def _enqueue_vector(sess, queue, values, shape=None): @@ -899,6 +915,7 @@ class MetaGraphWithVariableScopeTest(test.TestCase): class ExportImportAcrossScopesTest(test.TestCase): + @test_util.run_deprecated_v1 def testPartionedVariables(self): def make_graph_with_partitioned_variables(use_resource): diff --git a/tensorflow/python/framework/ops_test.py b/tensorflow/python/framework/ops_test.py index 9c9ef799f7..04a9ed05fd 100644 --- a/tensorflow/python/framework/ops_test.py +++ b/tensorflow/python/framework/ops_test.py @@ -57,11 +57,13 @@ ops._set_call_cpp_shape_fn(common_shapes.call_cpp_shape_fn) class ResourceTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBuildGraph(self): with self.cached_session(): pt = test_ops.stub_resource_handle_op(container="a", shared_name="b") test_ops.resource_create_op(pt).run() + @test_util.run_deprecated_v1 def testInitialize(self): with self.cached_session(): handle = test_ops.stub_resource_handle_op(container="a", shared_name="b") @@ -106,6 +108,7 @@ class TensorAndShapeTest(test_util.TensorFlowTestCase): c = a + b self.assertEqual([2, 3], c.shape) + @test_util.run_deprecated_v1 def testUnknownDim(self): with self.cached_session(): a = array_ops.placeholder(dtype=dtypes.float32, shape=[2, None, 3]) @@ -113,6 +116,7 @@ class TensorAndShapeTest(test_util.TensorFlowTestCase): c = a + b self.assertEqual([2, None, 3], c.shape.as_list()) + @test_util.run_deprecated_v1 def testUnknownShape(self): with self.cached_session(): a = array_ops.placeholder(dtype=dtypes.float32, shape=None) @@ -120,6 +124,7 @@ class TensorAndShapeTest(test_util.TensorFlowTestCase): c = a + b self.assertEqual(tensor_shape.unknown_shape(), c.shape) + @test_util.run_deprecated_v1 def testScalarShape(self): with self.cached_session(): a = array_ops.placeholder(dtype=dtypes.float32, shape=[]) @@ -127,6 +132,7 @@ class TensorAndShapeTest(test_util.TensorFlowTestCase): c = a + b self.assertEqual(tensor_shape.scalar(), c.shape) + @test_util.run_deprecated_v1 def testShapeFunctionError(self): with self.cached_session(): a = array_ops.ones([1, 2, 3]) @@ -140,6 +146,7 @@ class TensorAndShapeTest(test_util.TensorFlowTestCase): class IndexedSlicesTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testToTensor(self): with self.cached_session(): values = constant_op.constant([2, 3, 5, 7], shape=[2, 2]) @@ -149,6 +156,7 @@ class IndexedSlicesTest(test_util.TensorFlowTestCase): tensor = ops.convert_to_tensor(x, name="tensor") self.assertAllEqual(tensor.eval(), [[2, 3], [0, 0], [5, 7]]) + @test_util.run_deprecated_v1 def testNegation(self): with self.cached_session(): values = constant_op.constant([2, 3, 5, 7], shape=[2, 2]) @@ -157,6 +165,7 @@ class IndexedSlicesTest(test_util.TensorFlowTestCase): self.assertAllEqual(x.values.eval(), [[-2, -3], [-5, -7]]) self.assertAllEqual(x.indices.eval(), [0, 2]) + @test_util.run_deprecated_v1 def testScalarMul(self): with self.cached_session(): values = constant_op.constant([2, 3, 5, 7], shape=[2, 2]) @@ -190,6 +199,7 @@ def _apply_op(g, *args, **kwargs): class OperationTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testNoInputs(self): op = test_ops.float_output_string_output(name="myop").a.op self.assertEqual(2, len(op.values())) @@ -212,6 +222,7 @@ class OperationTest(test_util.TensorFlowTestCase): self.assertProtoEquals("op:'FloatOutputStringOutput' name:'myop'", op.node_def) + @test_util.run_deprecated_v1 def testNoOutputs(self): op1 = test_ops.float_output(name="myop1").op float_t, = op1.values() @@ -227,6 +238,7 @@ class OperationTest(test_util.TensorFlowTestCase): self.assertProtoEquals("op:'FloatInput' name:'myop2' input:'myop1'", op2.node_def) + @test_util.run_deprecated_v1 def testInputsAndOutputs(self): op1 = test_ops.float_output(name="myop1").op self.assertEqual(1, len(op1.values())) @@ -308,6 +320,7 @@ class OperationTest(test_util.TensorFlowTestCase): with self.assertRaises(ValueError): ops.Operation(ops._NodeDef("op", "invalid:0"), g) + @test_util.run_deprecated_v1 def testNoShapeFunction(self): op = test_ops.a() self.assertEqual(tensor_shape.unknown_shape(), op.get_shape()) @@ -333,6 +346,7 @@ class OperationTest(test_util.TensorFlowTestCase): converted = ops.convert_to_tensor(1) self.assertTrue(isinstance(converted, ops.EagerTensor)) + @test_util.run_deprecated_v1 def testConvertToTensorNestedTuple(self): with self.cached_session(): values = ((2,), (3,), (5,), (7,)) @@ -384,6 +398,7 @@ class OperationTest(test_util.TensorFlowTestCase): values = [1.23] _ = ops.convert_to_tensor(values, dtype=dtypes.int64) + @test_util.run_deprecated_v1 def testNoConvert(self): # Operation cannot be converted to Tensor. op = control_flow_ops.no_op() @@ -401,6 +416,7 @@ class OperationTest(test_util.TensorFlowTestCase): ops._NodeDef("None", "op1"), ops.Graph(), [], [dtypes.float32]) self.assertEqual("", repr(op)) + @test_util.run_deprecated_v1 def testGetAttr(self): op = test_ops.default_attrs() self.assertEqual(op.get_attr("string_val"), b"abc") @@ -446,6 +462,7 @@ class OperationTest(test_util.TensorFlowTestCase): # TODO(b/65162920): remove this test when users who are directly mutating the # node_def have been updated to proper usage. + @test_util.run_deprecated_v1 def testSetAttr(self): op = test_ops.int_attr().op op._set_attr("foo", attr_value_pb2.AttrValue(i=2)) @@ -466,6 +483,7 @@ class OperationTest(test_util.TensorFlowTestCase): self.assertEqual(z.control_inputs, [x, y]) self.assertEqual(x._control_outputs, [z]) + @test_util.run_deprecated_v1 def testRemoveAllControlInputs(self): a = constant_op.constant(1) with ops.control_dependencies([a]): @@ -490,6 +508,7 @@ class OperationTest(test_util.TensorFlowTestCase): self.assertEqual(f.op.control_inputs, []) self.assertEqual(list(f.op.inputs), [d, e]) + @test_util.run_deprecated_v1 def testControlInputCycle(self): graph = ops.Graph() with graph.as_default(): @@ -582,6 +601,7 @@ class OperationTest(test_util.TensorFlowTestCase): ): x.op._update_input(1, x) # pylint: disable=protected-access + @test_util.run_deprecated_v1 def testOpDef(self): x = constant_op.constant(0) y = constant_op.constant(1) @@ -681,6 +701,7 @@ class CreateOpTest(test_util.TensorFlowTestCase): # the low-level behavior. class CreateOpFromTFOperationTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBasic(self): g = ops.Graph() with g.as_default(): @@ -731,6 +752,7 @@ class CreateOpFromTFOperationTest(test_util.TensorFlowTestCase): self.assertEqual(op3.name, "myop_2") self.assertEqual(op4.name, "myop_1_1") + @test_util.run_deprecated_v1 def testCond(self): g = ops.Graph() with g.as_default(): @@ -760,6 +782,7 @@ class CreateOpFromTFOperationTest(test_util.TensorFlowTestCase): "cond/cond_text") # pylint: enable=protected-access + @test_util.run_deprecated_v1 def testWhileLoop(self): g = ops.Graph() with g.as_default(): @@ -789,6 +812,7 @@ class CreateOpFromTFOperationTest(test_util.TensorFlowTestCase): "myloop/while_context") # pylint: enable=protected-access + @test_util.run_deprecated_v1 def testWhileLoopWithInternalControlDep(self): g = ops.Graph() with g.as_default(): @@ -812,6 +836,7 @@ class CreateOpFromTFOperationTest(test_util.TensorFlowTestCase): # Internal control dep is preserved self.assertEqual(op.control_inputs, [c]) + @test_util.run_deprecated_v1 def testWhileLoopWithExternalControlDep(self): g = ops.Graph() with g.as_default(): @@ -945,6 +970,7 @@ class NameStackTest(test_util.TensorFlowTestCase): self.assertEqual("bar_2", g.unique_name("bar", mark_as_used=False)) self.assertEqual("bar_2", g.unique_name("bar")) + @test_util.run_deprecated_v1 def testNameAndVariableScope(self): with self.cached_session() as sess: with sess.graph.name_scope("l0"): @@ -1671,6 +1697,7 @@ def _CopyOverrideGrad(op, x_grad): # pylint: disable=invalid-name class RegistrationTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testRegisterGradients(self): x = test_ops.float_output() y = test_ops.copy_op(x) @@ -1710,6 +1737,7 @@ class ComparisonTest(test_util.TensorFlowTestCase): class ControlDependenciesTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBasic(self): g = ops.Graph() with g.as_default(): @@ -1953,6 +1981,7 @@ class OpScopeTest(test_util.TensorFlowTestCase): with ops.name_scope(None, "default2") as scope2: self.assertEqual(scope2, "default/default2/") + @test_util.run_deprecated_v1 def testNoScopeName(self): g0 = ops.Graph() values = [ @@ -1966,6 +1995,7 @@ class OpScopeTest(test_util.TensorFlowTestCase): with ops.name_scope(None, None, values): pass + @test_util.run_deprecated_v1 def testEmptyScopeName(self): g0 = ops.Graph() a = g0.create_op("A", [], [dtypes.float32]) @@ -1977,6 +2007,7 @@ class OpScopeTest(test_util.TensorFlowTestCase): self.assertEqual("", scope) self.assertEqual(g0, ops.get_default_graph()) + @test_util.run_deprecated_v1 def testDefaultScopeName(self): g0 = ops.Graph() a = g0.create_op("A", [], [dtypes.float32]) @@ -2001,12 +2032,14 @@ class OpScopeTest(test_util.TensorFlowTestCase): with ops.name_scope(scope_name, values=graph_elements + [a]): pass + @test_util.run_deprecated_v1 def testTensor(self): g0 = ops.Graph() a = g0.create_op("A", [], [dtypes.float32]) b = g0.create_op("B", [], [dtypes.float32]) self._testGraphElements([a, b]) + @test_util.run_deprecated_v1 def testSparseTensor(self): g0 = ops.Graph() a = g0.create_op("A", [], [dtypes.float32]) @@ -2017,6 +2050,7 @@ class OpScopeTest(test_util.TensorFlowTestCase): _apply_op(g0, "Int64Output", [], [dtypes.int64])) self._testGraphElements([a, sparse, b]) + @test_util.run_deprecated_v1 def testVariable(self): g0 = ops.Graph() with g0.as_default(): @@ -2221,6 +2255,7 @@ class InitScopeTest(test_util.TensorFlowTestCase): self.assertEqual(4, int(compiled_outer(inner=compiled_inner))) self.assertEqual(7, int(compiled_outer(inner=compiled_inner))) + @test_util.run_deprecated_v1 def testFallsBackToGlobalGraphWhenAllGraphsAreBuildingFunctions(self): with context.graph_mode(): ops.reset_default_graph() @@ -2357,6 +2392,7 @@ class GraphTest(test_util.TensorFlowTestCase): g.prevent_feeding(a) self.assertFalse(g.is_feedable(a)) + @test_util.run_deprecated_v1 def testPreventFetching(self): g = ops.Graph() a = constant_op.constant(2.0) @@ -2440,10 +2476,12 @@ class AttrScopeTest(test_util.TensorFlowTestCase): b = None return (a, b) + @test_util.run_deprecated_v1 def testNoLabel(self): with self.cached_session(): self.assertAllEqual((None, None), self._get_test_attrs()) + @test_util.run_deprecated_v1 def testLabelMap(self): with self.cached_session() as sess: a1 = self._get_test_attrs() @@ -2478,11 +2516,13 @@ ops.RegisterShape("KernelLabel")(common_shapes.scalar_shape) class KernelLabelTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testNoLabel(self): with self.cached_session(): self.assertAllEqual(b"My label is: default", test_ops.kernel_label().eval()) + @test_util.run_deprecated_v1 def testLabelMap(self): with self.cached_session() as sess: default_1 = test_ops.kernel_label() @@ -2599,6 +2639,7 @@ class StatisticsTest(test_util.TensorFlowTestCase): class DeviceStackTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBasicDeviceAssignmentMetadata(self): def device_func(unused_op): @@ -2630,6 +2671,7 @@ class DeviceStackTest(test_util.TensorFlowTestCase): expected_regex = r"device_func<.*ops_test.py, [0-9]+" self.assertRegexpMatches(func_description, expected_regex) + @test_util.run_deprecated_v1 def testDeviceAssignmentMetadataForGraphDeviceAndTfDeviceFunctions(self): with ops.device("/cpu"): @@ -2649,6 +2691,7 @@ class DeviceStackTest(test_util.TensorFlowTestCase): class ColocationGroupTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBasic(self): a = constant_op.constant([2.0], name="a") with ops.colocate_with(a.op): @@ -2659,6 +2702,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): with self.assertRaises(ValueError): c.op.get_attr("_class") + @test_util.run_deprecated_v1 def testBasicColocationMetadata(self): const_two = constant_op.constant([2.0], name="two") with ops.colocate_with(const_two.op): @@ -2671,6 +2715,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): # colocation statement. self.assertEqual("ops_test.py", os.path.basename(metadata.filename)) + @test_util.run_deprecated_v1 def testColocationDeviceInteraction(self): with ops.device("/cpu:0"): with ops.device("/device:GPU:0"): @@ -2683,6 +2728,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): self.assertEqual([b"loc:@a"], b.op.colocation_groups()) self.assertEqual(a.op.device, b.op.device) + @test_util.run_deprecated_v1 def testColocationCanonicalization(self): with ops.device("/device:GPU:0"): _ = constant_op.constant(2.0) @@ -2698,6 +2744,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): # inherits B's device name, after canonicalizing the names. self.assertEqual(b.op.device, c.op.device) + @test_util.run_deprecated_v1 def testLocationOverrides(self): with ops.device("/cpu:0"): with ops.device("/device:GPU:0"): @@ -2719,6 +2766,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): self.assertEqual("/device:GPU:0", c.op.device) self.assertEqual("/device:CPU:0", d.op.device) + @test_util.run_deprecated_v1 def testNestedColocateWith(self): a = constant_op.constant([2.0], name="a") with ops.colocate_with(a.op): @@ -2728,6 +2776,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): self.assertEqual([b"loc:@a"], b.op.colocation_groups()) self.assertEqual([b"loc:@a"], c.op.colocation_groups()) + @test_util.run_deprecated_v1 def testMultiColocationGroups(self): a = constant_op.constant([2.0], name="a") b = constant_op.constant(3.0, name="b") @@ -2736,6 +2785,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): c = constant_op.constant(4.0) self.assertEqual(set([b"loc:@a", b"loc:@b"]), set(c.op.colocation_groups())) + @test_util.run_deprecated_v1 def testColocationIgnoreStack(self): a = constant_op.constant([2.0], name="a") b = constant_op.constant(3.0, name="b") @@ -2744,6 +2794,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): c = constant_op.constant(4.0) self.assertEqual(set([b"loc:@b"]), set(c.op.colocation_groups())) + @test_util.run_deprecated_v1 def testColocateWithReset(self): a = constant_op.constant([2.0], name="a") with ops.colocate_with(a.op): @@ -2753,6 +2804,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): self.assertEqual([b"loc:@a"], b.op.colocation_groups()) self.assertEqual([b"loc:@c"], c.op.colocation_groups()) + @test_util.run_deprecated_v1 def testColocateWithInitialNoneThenNested(self): a = constant_op.constant([2.0], name="a") with ops.colocate_with(a.op): @@ -2763,12 +2815,14 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): self.assertEqual([b"loc:@b"], b.op.colocation_groups()) self.assertEqual([b"loc:@b"], c.op.colocation_groups()) + @test_util.run_deprecated_v1 def testColocateVariables(self): a = variables.Variable([2.0], name="a") with ops.colocate_with(a.op): b = variables.Variable([3.0], name="b") self.assertEqual([b"loc:@a"], b.op.colocation_groups()) + @test_util.run_deprecated_v1 def testInconsistentDeviceWithinColocate(self): with ops.device("/device:GPU:0"): a = constant_op.constant([2.0], name="a") @@ -2782,6 +2836,7 @@ class ColocationGroupTest(test_util.TensorFlowTestCase): self.assertEqual("/device:CPU:0", b.device) + @test_util.run_deprecated_v1 def testMakeColocationConflictMessage(self): """Test that provides an example of a complicated error message.""" # We could test the message with any ops, but this test will be more @@ -2926,6 +2981,7 @@ class NameScopeTest(test_util.TensorFlowTestCase): class TracebackTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testTracebackWithStartLines(self): with self.cached_session() as sess: a = constant_op.constant(2.0) @@ -2947,6 +3003,7 @@ class TracebackTest(test_util.TensorFlowTestCase): class EnableEagerExecutionTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBadArgumentsToEnableEagerExecution(self): with self.assertRaisesRegexp(TypeError, "config must be a tf.ConfigProto"): ops.enable_eager_execution(context.DEVICE_PLACEMENT_SILENT) diff --git a/tensorflow/python/framework/smart_cond_test.py b/tensorflow/python/framework/smart_cond_test.py index 174ada9fe1..f964c87f02 100644 --- a/tensorflow/python/framework/smart_cond_test.py +++ b/tensorflow/python/framework/smart_cond_test.py @@ -35,6 +35,7 @@ def raise_exception(): class SmartCondTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testTrue(self): with ops.Graph().as_default(): with session.Session(): @@ -44,6 +45,7 @@ class SmartCondTest(test_util.TensorFlowTestCase): lambda: math_ops.multiply(y, 5)) self.assertEqual(z.eval(), 32) + @test_util.run_deprecated_v1 def testFalse(self): with ops.Graph().as_default(): with session.Session(): @@ -99,6 +101,7 @@ class SmartCondTest(test_util.TensorFlowTestCase): class SmartCaseTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testTrue(self): x = array_ops.placeholder(dtype=dtypes.int32, shape=[]) conditions = [(True, lambda: constant_op.constant(1)), @@ -112,6 +115,7 @@ class SmartCaseTest(test_util.TensorFlowTestCase): self.assertEqual(self.evaluate(y), 1) self.assertEqual(self.evaluate(z), 1) + @test_util.run_deprecated_v1 def testFalse(self): conditions = [(False, raise_exception)] y = smart_cond.smart_case(conditions, @@ -124,6 +128,7 @@ class SmartCaseTest(test_util.TensorFlowTestCase): self.assertEqual(self.evaluate(y), 1) self.assertEqual(self.evaluate(z), 1) + @test_util.run_deprecated_v1 def testMix(self): x = array_ops.placeholder(dtype=dtypes.int32, shape=[]) y = constant_op.constant(10) diff --git a/tensorflow/python/framework/sparse_tensor_test.py b/tensorflow/python/framework/sparse_tensor_test.py index 9ee1bd75a5..a999c12ca8 100644 --- a/tensorflow/python/framework/sparse_tensor_test.py +++ b/tensorflow/python/framework/sparse_tensor_test.py @@ -65,6 +65,7 @@ class SparseTensorTest(test_util.TensorFlowTestCase): sparse_tensor.is_sparse( sparse_tensor.SparseTensorValue([[0]], [0], [1]))) + @test_util.run_deprecated_v1 def testConsumers(self): sp = sparse_tensor.SparseTensor([[0, 0], [1, 2]], [1.0, 3.0], [3, 4]) w = ops.convert_to_tensor(np.ones([4, 1], np.float32)) @@ -87,6 +88,7 @@ class ConvertToTensorOrSparseTensorTest(test_util.TensorFlowTestCase): value) self.assertAllEqual(value, self.evaluate(from_value)) + @test_util.run_deprecated_v1 def test_convert_sparse(self): with self.cached_session(): indices = [[0, 1], [1, 0]] diff --git a/tensorflow/python/framework/subscribe_test.py b/tensorflow/python/framework/subscribe_test.py index 5322204ce6..61c6ea6519 100644 --- a/tensorflow/python/framework/subscribe_test.py +++ b/tensorflow/python/framework/subscribe_test.py @@ -43,6 +43,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertTrue( all(subscribe._is_subscribed_identity(x) for x in container)) + @test_util.run_deprecated_v1 def testSideEffect(self): a = constant_op.constant(1) b = constant_op.constant(1) @@ -75,6 +76,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertEqual(d_out, [42]) self.assertEqual(shared, [2, 2, 2]) + @test_util.run_deprecated_v1 def testSupportedTypes(self): """Confirm that supported types are correctly detected and handled.""" @@ -120,6 +122,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): subscribe.subscribe(c.name, lambda t: script_ops.py_func(sub, [t], [t.dtype])) + @test_util.run_deprecated_v1 def testCaching(self): """Confirm caching of control output is recalculated between calls.""" a = constant_op.constant(1) @@ -152,6 +155,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertEqual(d_out, [11]) self.assertEqual(shared, {2: 1, 1: 1}) + @test_util.run_deprecated_v1 def testIsSubscribedIdentity(self): """Confirm subscribed identity ops are correctly detected.""" a = constant_op.constant(1) @@ -165,6 +169,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertFalse(subscribe._is_subscribed_identity(idop)) self.assertTrue(subscribe._is_subscribed_identity(c_sub)) + @test_util.run_deprecated_v1 def testSubscribeExtend(self): """Confirm side effect are correctly added for different input types.""" a = constant_op.constant(1) @@ -210,6 +215,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertIn('graph2', shared) self.assertIn('graph3', shared) + @test_util.run_deprecated_v1 def testSubscribeVariable(self): """Confirm that variables can be subscribed.""" v1 = variables.VariableV1(0.0) @@ -248,6 +254,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): # Make sure the values read from the variable match the expected ones. self.assertEqual([0.0, 3.0], shared) + @test_util.run_deprecated_v1 def testResourceType(self): """Confirm that subscribe correctly handles tensors with 'resource' type.""" tensor_array = tensor_array_ops.TensorArray( @@ -276,6 +283,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.evaluate([reader]) self.assertEqual(0, len(shared)) + @test_util.run_deprecated_v1 def testMultipleOutputs(self): """Handle subscriptions to multiple outputs from the same op.""" sparse_tensor_1 = sparse_tensor.SparseTensor( @@ -309,6 +317,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): # All three ops have been processed. self.assertEqual(3, len(shared)) + @test_util.run_deprecated_v1 def test_subscribe_tensors_on_different_devices(self): """Side effect ops are added with the same device of the subscribed op.""" c1 = constant_op.constant(10) @@ -335,6 +344,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertEqual(add.device, add_sub.device) self.assertEqual(mul.device, mul_sub.device) + @test_util.run_deprecated_v1 def test_subscribe_tensors_within_control_flow_context(self): """Side effect ops are added with the same control flow context.""" c1 = constant_op.constant(10) diff --git a/tensorflow/python/framework/tensor_spec_test.py b/tensorflow/python/framework/tensor_spec_test.py index e3aad7cc23..75c197df09 100644 --- a/tensorflow/python/framework/tensor_spec_test.py +++ b/tensorflow/python/framework/tensor_spec_test.py @@ -45,6 +45,7 @@ class TensorSpecTest(test_util.TensorFlowTestCase): desc = tensor_spec.TensorSpec(shape=None, dtype=dtypes.float32) self.assertEqual(desc.shape, tensor_shape.TensorShape(None)) + @test_util.run_deprecated_v1 def testShapeCompatibility(self): unknown = array_ops.placeholder(dtypes.int64) partial = array_ops.placeholder(dtypes.int64, shape=[None, 1]) @@ -75,6 +76,7 @@ class TensorSpecTest(test_util.TensorFlowTestCase): self.assertFalse(desc_rank3.is_compatible_with(full)) self.assertTrue(desc_rank3.is_compatible_with(rank3)) + @test_util.run_deprecated_v1 def testTypeCompatibility(self): floats = array_ops.placeholder(dtypes.float32, shape=[10, 10]) ints = array_ops.placeholder(dtypes.int32, shape=[10, 10]) @@ -106,6 +108,7 @@ class TensorSpecTest(test_util.TensorFlowTestCase): spec_2 = tensor_spec.TensorSpec.from_spec(spec_1) self.assertEqual(spec_1, spec_2) + @test_util.run_deprecated_v1 def testFromTensor(self): zero = constant_op.constant(0) spec = tensor_spec.TensorSpec.from_tensor(zero) @@ -113,6 +116,7 @@ class TensorSpecTest(test_util.TensorFlowTestCase): self.assertEqual(spec.shape, []) self.assertEqual(spec.name, "Const") + @test_util.run_deprecated_v1 def testFromPlaceholder(self): unknown = array_ops.placeholder(dtypes.int64, name="unknown") partial = array_ops.placeholder(dtypes.float32, diff --git a/tensorflow/python/framework/tensor_util_test.py b/tensorflow/python/framework/tensor_util_test.py index 87d65c8c46..0033754618 100644 --- a/tensorflow/python/framework/tensor_util_test.py +++ b/tensorflow/python/framework/tensor_util_test.py @@ -758,6 +758,7 @@ class TensorUtilTest(test.TestCase): self.assertFalse(tensor_util.ShapeEquals(t, [1, 4])) self.assertFalse(tensor_util.ShapeEquals(t, [4])) + @test_util.run_deprecated_v1 def testMockArray(self): class MockArray(object): @@ -787,6 +788,7 @@ class ConstantValueTest(test.TestCase): tf_val = constant_op.constant(np_val) self.assertAllClose(np_val, tensor_util.constant_value(tf_val)) + @test_util.run_deprecated_v1 def testUnknown(self): tf_val = gen_state_ops.variable( shape=[3, 4, 7], @@ -815,12 +817,14 @@ class ConstantValueTest(test.TestCase): c_val = tensor_util.constant_value(tf_val) self.assertEqual(6, c_val) + @test_util.run_deprecated_v1 def testSizeOfScalar(self): tf_val = array_ops.size(constant_op.constant(0.0)) c_val = tensor_util.constant_value(tf_val) self.assertEqual(1, c_val) self.assertEqual(np.ndarray, type(c_val)) + @test_util.run_deprecated_v1 def testRank(self): tf_val = array_ops.rank(constant_op.constant(0.0, shape=[1, 2, 3])) c_val = tensor_util.constant_value(tf_val) @@ -852,6 +856,7 @@ class ConstantValueTest(test.TestCase): c_val = tensor_util.constant_value(tf_val) self.assertAllClose(np_val.astype(np.float64), c_val) + @test_util.run_deprecated_v1 def testConcat(self): np_val = np.random.rand(3, 4, 7).astype(np.float32) tf_val = array_ops.concat( @@ -871,6 +876,7 @@ class ConstantValueTest(test.TestCase): c_val = tensor_util.constant_value(tf_val) self.assertIs(None, c_val) + @test_util.run_deprecated_v1 def testPack_Axis0(self): inputs = [np.random.rand(4, 7) for _ in range(3)] np_val = np.array(inputs) @@ -883,6 +889,7 @@ class ConstantValueTest(test.TestCase): c_val = tensor_util.constant_value(tf_val) self.assertIs(None, c_val) + @test_util.run_deprecated_v1 def testPack_Axis1(self): inputs = [np.random.rand(4, 7) for _ in range(3)] tf_val = array_ops.stack(inputs, axis=1) @@ -894,6 +901,7 @@ class ConstantValueTest(test.TestCase): c_val = tensor_util.constant_value(tf_val) self.assertIs(None, c_val) + @test_util.run_deprecated_v1 def testPack_Partial_Axis0(self): input_ = np.random.rand(4, 7) tf_val = array_ops.stack([input_, array_ops.placeholder(dtypes.float32)]) @@ -901,6 +909,7 @@ class ConstantValueTest(test.TestCase): self.assertAllClose(input_, c_val[0]) self.assertIsNone(c_val[1]) + @test_util.run_deprecated_v1 def testPack_Partial_Axis1(self): input_ = np.random.rand(4, 7) tf_val = array_ops.stack([input_, array_ops.placeholder(dtypes.float32)], @@ -966,12 +975,14 @@ class ConstantValueAsShapeTest(test.TestCase): c_val = tensor_util.constant_value_as_shape(tf_val) self.assertEqual([None, 1, None], c_val.as_list()) + @test_util.run_deprecated_v1 def testPack(self): tf_val = array_ops.stack( [constant_op.constant(16), 37, array_ops.placeholder(dtypes.int32)]) c_val = tensor_util.constant_value_as_shape(tf_val) self.assertEqual([16, 37, None], c_val.as_list()) + @test_util.run_deprecated_v1 def testConcat(self): tf_val = array_ops.concat( [[16, 37], array_ops.placeholder( @@ -985,6 +996,7 @@ class ConstantValueAsShapeTest(test.TestCase): c_val = tensor_util.constant_value_as_shape(tf_val) self.assertEqual([16, 37, None, 48], c_val.as_list()) + @test_util.run_deprecated_v1 def testSlice(self): tf_val = array_ops.placeholder(dtypes.int32, shape=(4,))[0:2] c_val = tensor_util.constant_value_as_shape(tf_val) diff --git a/tensorflow/python/framework/test_util_test.py b/tensorflow/python/framework/test_util_test.py index 2a37253db6..dfdced5a98 100644 --- a/tensorflow/python/framework/test_util_test.py +++ b/tensorflow/python/framework/test_util_test.py @@ -49,6 +49,7 @@ from tensorflow.python.platform import googletest class TestUtilTest(test_util.TensorFlowTestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def test_assert_ops_in_graph(self): with self.test_session(): constant_op.constant(["hello", "taffy"], name="hello") @@ -60,6 +61,7 @@ class TestUtilTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertRaises(ValueError, test_util.assert_ops_in_graph, {"hello": "Variable"}, ops.get_default_graph()) + @test_util.run_deprecated_v1 def test_session_functions(self): with self.test_session() as sess: sess_ref = weakref.ref(sess) @@ -551,6 +553,7 @@ class TestUtilTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.assertRaises(AssertionError): self.assertAllLessEqual(x, 95.0) + @test_util.run_deprecated_v1 def testAssertAllInRangeWithNonNumericValuesFails(self): s1 = constant_op.constant("Hello, ", name="s1") c = constant_op.constant([1 + 2j, -3 + 5j], name="c") @@ -614,6 +617,7 @@ class TestUtilTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.assertRaises(AssertionError): self.assertAllInSet(x, (42,)) + @test_util.run_deprecated_v1 def testRandomSeed(self): # Call setUp again for WithCApi case (since it makes a new defeault graph # after setup). @@ -706,6 +710,7 @@ class TestUtilTest(test_util.TensorFlowTestCase, parameterized.TestCase): test_util.run_in_graph_and_eager_modes(_test)(self) self.assertEqual(modes, ["graph"]) + @test_util.run_deprecated_v1 def test_run_in_graph_and_eager_modes_setup_in_same_mode(self): modes = [] mode_name = lambda: "eager" if context.executing_eagerly() else "graph" diff --git a/tensorflow/python/grappler/cost_analyzer_test.py b/tensorflow/python/grappler/cost_analyzer_test.py index de80df1879..ee3e289f65 100644 --- a/tensorflow/python/grappler/cost_analyzer_test.py +++ b/tensorflow/python/grappler/cost_analyzer_test.py @@ -38,6 +38,7 @@ from tensorflow.python.training import adam class CostAnalysisTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasicCost(self): """Make sure arguments can be passed correctly.""" a = constant_op.constant(10, name="a") @@ -62,6 +63,7 @@ class CostAnalysisTest(test.TestCase): # Also print the report to make it easier to debug print("{}".format(report)) + @test_util.run_deprecated_v1 def testVerbose(self): """Make sure the full report is generated with verbose=True.""" a = constant_op.constant(10, name="a") @@ -81,6 +83,7 @@ class CostAnalysisTest(test.TestCase): # Also print the report to make it easier to debug print("{}".format(report)) + @test_util.run_deprecated_v1 def testSmallNetworkCost(self): image = array_ops.placeholder(dtypes.float32, shape=[1, 28, 28, 1]) label = array_ops.placeholder(dtypes.float32, shape=[1, 10]) @@ -129,6 +132,7 @@ class CostAnalysisTest(test.TestCase): # self.assertTrue(0 < upper) # self.assertTrue(lower <= upper) + @test_util.run_deprecated_v1 def testBasicMemory(self): """Make sure arguments can be passed correctly.""" with test_util.device(use_gpu=False): diff --git a/tensorflow/python/grappler/item_test.py b/tensorflow/python/grappler/item_test.py index d3d96c646c..78604b259c 100644 --- a/tensorflow/python/grappler/item_test.py +++ b/tensorflow/python/grappler/item_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import errors_impl from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.grappler import item from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_array_ops @@ -107,6 +108,7 @@ class ItemTest(test.TestCase): newest_tf_item = grappler_item.tf_item self.assertEqual(new_tf_item, newest_tf_item) + @test_util.run_deprecated_v1 def testColocationContraints(self): with ops.Graph().as_default() as g: c = constant_op.constant([10]) diff --git a/tensorflow/python/grappler/layout_optimizer_test.py b/tensorflow/python/grappler/layout_optimizer_test.py index 55ccfbb93c..98f2e6d718 100644 --- a/tensorflow/python/grappler/layout_optimizer_test.py +++ b/tensorflow/python/grappler/layout_optimizer_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.grappler import cluster as gcluster from tensorflow.python.grappler import tf_optimizer from tensorflow.python.layers import convolutional as conv_layers @@ -1441,6 +1442,7 @@ class LayoutOptimizerTest(test.TestCase): self._assert_trans_nchw_to_nhwc('Add-0-0', nodes) self.assertAllClose(output_val_ref, output_val, atol=1e-3) + @test_util.run_deprecated_v1 def testGradient(self): meta_graph = _simple_metagraph() config = config_pb2.ConfigProto() @@ -1458,6 +1460,7 @@ class LayoutOptimizerTest(test.TestCase): self.assertEqual(node.attr['data_format'].s, b'NCHW') self.assertEqual(found, 5) + @test_util.run_deprecated_v1 def testDepthwise(self): meta_graph = _simple_metagraph(depthwise=True) config = config_pb2.ConfigProto() diff --git a/tensorflow/python/grappler/memory_optimizer_test.py b/tensorflow/python/grappler/memory_optimizer_test.py index d233629cbb..6eb16fbd39 100644 --- a/tensorflow/python/grappler/memory_optimizer_test.py +++ b/tensorflow/python/grappler/memory_optimizer_test.py @@ -25,6 +25,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.grappler import tf_optimizer from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn @@ -37,6 +38,7 @@ from tensorflow.python.training import training as train class MemoryOptimizerSwapTest(test.TestCase): """Tests the Grappler memory optimizer.""" + @test_util.run_deprecated_v1 def testNoSwapping(self): """Make sure the graph is preserved when there is nothing to swap.""" a = variables.VariableV1(10, name='a') @@ -60,6 +62,7 @@ class MemoryOptimizerSwapTest(test.TestCase): self.assertEqual(len(graph.node), graph_size) self.assertItemsEqual([node.name for node in graph.node], nodes) + @test_util.run_deprecated_v1 def testSimpleSwap(self): """Check that the swap annotations are followed.""" a = variables.VariableV1(10, name='a') diff --git a/tensorflow/python/grappler/model_analyzer_test.py b/tensorflow/python/grappler/model_analyzer_test.py index ec172755f1..d000cfa1ba 100644 --- a/tensorflow/python/grappler/model_analyzer_test.py +++ b/tensorflow/python/grappler/model_analyzer_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.grappler import model_analyzer from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -28,6 +29,7 @@ from tensorflow.python.platform import test class PyWrapOptimizeGraphTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): """Make sure arguments can be passed correctly.""" a = constant_op.constant([10, 11], name="a") @@ -49,6 +51,7 @@ class PyWrapOptimizeGraphTest(test.TestCase): # Also print the report to make it easier to debug print("{}".format(report)) + @test_util.run_deprecated_v1 def testDebugMode(self): """Make sure arguments can be passed correctly.""" a = constant_op.constant([10, 11], name="a") diff --git a/tensorflow/python/grappler/tf_optimizer_test.py b/tensorflow/python/grappler/tf_optimizer_test.py index 0a4d4cbe2d..06ccaa813f 100644 --- a/tensorflow/python/grappler/tf_optimizer_test.py +++ b/tensorflow/python/grappler/tf_optimizer_test.py @@ -23,6 +23,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.grappler import item as gitem from tensorflow.python.grappler import tf_optimizer from tensorflow.python.ops import array_ops @@ -34,6 +35,7 @@ from tensorflow.python.platform import test class PyWrapOptimizeGraphTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): """Make sure arguments can be passed correctly.""" a = constant_op.constant(10, name='a') @@ -55,6 +57,7 @@ class PyWrapOptimizeGraphTest(test.TestCase): self.assertEqual(len(graph.node), 1) self.assertItemsEqual([node.name for node in graph.node], ['d']) + @test_util.run_deprecated_v1 def testKeepNodes(self): g = ops.Graph() with g.as_default(): @@ -83,6 +86,7 @@ class PyWrapOptimizeGraphTest(test.TestCase): self.assertEqual(len(optimized_graph_nodes), len(expected_nodes)) self.assertAllInSet(optimized_graph_nodes, expected_nodes) + @test_util.run_deprecated_v1 def testLoops(self): g = ops.Graph() with g.as_default(): diff --git a/tensorflow/python/keras/activations_test.py b/tensorflow/python/keras/activations_test.py index ad238cb0a9..6b7bfb698b 100644 --- a/tensorflow/python/keras/activations_test.py +++ b/tensorflow/python/keras/activations_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python import keras +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -67,6 +68,7 @@ class KerasActivationsTest(test.TestCase): expected = _ref_softmax(test_values[0, 0]) self.assertAllClose(result[0, 0], expected, rtol=1e-05) + @test_util.run_deprecated_v1 def test_selu(self): x = keras.backend.placeholder(ndim=2) f = keras.backend.function([x], [keras.activations.selu(x)]) @@ -124,6 +126,7 @@ class KerasActivationsTest(test.TestCase): expected = sigmoid(test_values) self.assertAllClose(result, expected, rtol=1e-05) + @test_util.run_deprecated_v1 def test_hard_sigmoid(self): def ref_hard_sigmoid(x): x = (x * 0.2) + 0.5 @@ -147,6 +150,7 @@ class KerasActivationsTest(test.TestCase): # No negative values in test values... self.assertAllClose(result, test_values, rtol=1e-05) + @test_util.run_deprecated_v1 def test_elu(self): with self.cached_session(): x = keras.backend.placeholder(ndim=2) diff --git a/tensorflow/python/keras/backend_test.py b/tensorflow/python/keras/backend_test.py index 48fdd56e9f..fa32b1ecd7 100644 --- a/tensorflow/python/keras/backend_test.py +++ b/tensorflow/python/keras/backend_test.py @@ -1422,6 +1422,7 @@ class TestCTC(test.TestCase): decode_truth[i] == keras.backend.eval(decode_pred_tf[i]))) self.assertAllClose(log_prob_truth, log_prob_pred) + @test_util.run_deprecated_v1 def test_ctc_batch_cost(self): with self.cached_session(): label_lens = np.expand_dims(np.asarray([5, 4]), 1) @@ -1507,6 +1508,7 @@ class TestRandomOps(test.TestCase): class BackendGraphTests(test.TestCase): + @test_util.run_deprecated_v1 def test_is_placeholder(self): x = keras.backend.placeholder(shape=(1,)) self.assertEqual(keras.backend.is_placeholder(x), True) @@ -1546,6 +1548,7 @@ class BackendGraphTests(test.TestCase): output_values = f([None, None]) self.assertEqual(output_values, [5., 6.]) + @test_util.run_deprecated_v1 def test_function_tf_feed_symbols(self): # Test Keras backend functions with TF tensor inputs. with self.cached_session(): @@ -1579,6 +1582,7 @@ class BackendGraphTests(test.TestCase): outs = f([y5, y2, None]) self.assertEqual(outs, [11., 2.]) + @test_util.run_deprecated_v1 def test_function_tf_fetches(self): # Additional operations can be passed to tf.Session().run() via its # `fetches` arguments. In contrast to `updates` argument of @@ -1601,6 +1605,7 @@ class BackendGraphTests(test.TestCase): self.assertEqual(keras.backend.get_session().run(fetches=[x, y]), [11., 5.]) + @test_util.run_deprecated_v1 def test_function_tf_feed_dict(self): # Additional substitutions can be passed to `tf.Session().run()` via its # `feed_dict` arguments. Note that the feed_dict is passed once in the @@ -1633,6 +1638,7 @@ class BackendGraphTests(test.TestCase): self.assertEqual(keras.backend.get_session().run(fetches=[x, y]), [30., 40.]) + @test_util.run_deprecated_v1 def test_function_tf_run_options_with_run_metadata(self): with self.cached_session(): x_placeholder = keras.backend.placeholder(shape=()) @@ -1658,6 +1664,7 @@ class BackendGraphTests(test.TestCase): self.assertEqual(output1, [30.]) self.assertEqual(len(run_metadata.partition_graphs), 0) + @test_util.run_deprecated_v1 def test_function_fetch_callbacks(self): class CallbackStub(object): @@ -1694,6 +1701,7 @@ class BackendGraphTests(test.TestCase): x = keras.backend.placeholder(shape=(3, 4), sparse=True) self.assertEqual(x.get_shape().as_list(), [3, 4]) + @test_util.run_deprecated_v1 def test_batch_normalization(self): # No eager CPU kernel. g_val = np.random.random((3,)) diff --git a/tensorflow/python/keras/callbacks_test.py b/tensorflow/python/keras/callbacks_test.py index 9d9ede22c0..ed05572c68 100644 --- a/tensorflow/python/keras/callbacks_test.py +++ b/tensorflow/python/keras/callbacks_test.py @@ -404,6 +404,7 @@ class KerasCallbacksTest(test.TestCase): float(keras.backend.get_value( model.optimizer.lr)) - 0.01 / 4) < keras.backend.epsilon() + @test_util.run_deprecated_v1 def test_ReduceLROnPlateau(self): with self.cached_session(): np.random.seed(1337) @@ -675,6 +676,7 @@ class KerasCallbacksTest(test.TestCase): self.assertEqual(len(loss), 1) self.assertEqual(loss[0], np.inf) + @test_util.run_deprecated_v1 def test_TensorBoard(self): np.random.seed(1337) @@ -778,6 +780,7 @@ class KerasCallbacksTest(test.TestCase): data_generator(True), len(x_train), epochs=2, callbacks=cbks) assert os.path.exists(temp_dir) + @test_util.run_deprecated_v1 def test_TensorBoard_histogram_freq_must_have_validation_data(self): np.random.seed(1337) tmpdir = self.get_temp_dir() @@ -850,6 +853,7 @@ class KerasCallbacksTest(test.TestCase): # Make sure file writer cache is clear to avoid failures during cleanup. writer_cache.FileWriterCache.clear() + @test_util.run_deprecated_v1 def test_TensorBoard_multi_input_output(self): np.random.seed(1337) tmpdir = self.get_temp_dir() @@ -921,6 +925,7 @@ class KerasCallbacksTest(test.TestCase): callbacks=callbacks_factory(histogram_freq=1)) assert os.path.isdir(filepath) + @test_util.run_deprecated_v1 def test_Tensorboard_histogram_summaries_in_test_function(self): class FileWriterStub(object): @@ -998,6 +1003,7 @@ class KerasCallbacksTest(test.TestCase): self.assertAllEqual(tsb.writer.steps_seen, [0, 0.5, 1, 1.5, 2, 2.5]) + @test_util.run_deprecated_v1 def test_Tensorboard_histogram_summaries_with_generator(self): np.random.seed(1337) tmpdir = self.get_temp_dir() @@ -1129,6 +1135,7 @@ class KerasCallbacksTest(test.TestCase): assert os.path.exists(temp_dir) + @test_util.run_deprecated_v1 def test_Tensorboard_batch_logging(self): class FileWriterStub(object): @@ -1163,6 +1170,7 @@ class KerasCallbacksTest(test.TestCase): self.assertEqual(tb_cbk.writer.summary_values, [0., 1., 2., 3., 4.]) self.assertEqual(tb_cbk.writer.summary_tags, ['batch_acc'] * 5) + @test_util.run_deprecated_v1 def test_Tensorboard_epoch_and_batch_logging(self): class FileWriterStub(object): @@ -1234,6 +1242,7 @@ class KerasCallbacksTest(test.TestCase): self.assertTrue(os.path.exists(temp_dir)) + @test_util.run_deprecated_v1 def test_TensorBoard_update_freq(self): class FileWriterStub(object): @@ -1325,6 +1334,7 @@ class KerasCallbacksTest(test.TestCase): callbacks=cbks, epochs=1) + @test_util.run_deprecated_v1 def test_fit_generator_with_callback(self): class TestCallback(keras.callbacks.Callback): diff --git a/tensorflow/python/keras/engine/saving_test.py b/tensorflow/python/keras/engine/saving_test.py index b92f06449e..6d9d9a2fca 100644 --- a/tensorflow/python/keras/engine/saving_test.py +++ b/tensorflow/python/keras/engine/saving_test.py @@ -289,6 +289,7 @@ class TestWeightSavingAndLoading(test.TestCase, parameterized.TestCase): r'element\(s\)\.'): saving.load_weights_from_hdf5_group_by_name(f_model, model.layers) + @test_util.run_deprecated_v1 def test_sequential_weight_loading_group_name_with_incorrect_shape(self): if h5py is None: return @@ -331,6 +332,7 @@ class TestWeightSavingAndLoading(test.TestCase, parameterized.TestCase): class TestWholeModelSaving(test.TestCase): + @test_util.run_deprecated_v1 def test_sequential_model_saving(self): if h5py is None: self.skipTest('h5py required to run this test') @@ -383,6 +385,7 @@ class TestWholeModelSaving(test.TestCase): out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) + @test_util.run_deprecated_v1 def test_sequential_model_saving_without_input_shape(self): if h5py is None: self.skipTest('h5py required to run this test') @@ -443,6 +446,7 @@ class TestWholeModelSaving(test.TestCase): out2 = new_model.predict(x) self.assertAllClose(out, out2, atol=1e-05) + @test_util.run_deprecated_v1 def test_sequential_model_saving_2(self): if h5py is None: self.skipTest('h5py required to run this test') @@ -479,6 +483,7 @@ class TestWholeModelSaving(test.TestCase): out2 = model.predict(x) self.assertAllClose(out, out2, atol=1e-05) + @test_util.run_deprecated_v1 def test_functional_model_saving(self): if h5py is None: self.skipTest('h5py required to run this test') @@ -630,6 +635,7 @@ class TestWholeModelSaving(test.TestCase): os.close(fd) os.remove(fname) + @test_util.run_deprecated_v1 def test_saving_model_with_long_weights_names(self): if h5py is None: self.skipTest('h5py required to run this test') @@ -675,6 +681,7 @@ class TestWholeModelSaving(test.TestCase): os.close(fd) os.remove(fname) + @test_util.run_deprecated_v1 def test_model_saving_to_pre_created_h5py_file(self): if h5py is None: self.skipTest('h5py required to run this test') @@ -749,6 +756,7 @@ class SubclassedModel(training.Model): class TestWeightSavingAndLoadingTFFormat(test.TestCase): + @test_util.run_deprecated_v1 def test_keras_optimizer_warning(self): graph = ops.Graph() with graph.as_default(), self.session(graph): diff --git a/tensorflow/python/keras/engine/sequential_test.py b/tensorflow/python/keras/engine/sequential_test.py index 2e2927bf47..fbf893c663 100644 --- a/tensorflow/python/keras/engine/sequential_test.py +++ b/tensorflow/python/keras/engine/sequential_test.py @@ -132,6 +132,7 @@ class TestSequential(test.TestCase, parameterized.TestCase): self.assertFalse(model._is_graph_network) @parameterized.parameters((True,), (False,)) + @tf_test_util.run_deprecated_v1 def test_training_and_eval_methods_on_symbolic_tensors(self, deferred): with self.cached_session(): @@ -219,6 +220,7 @@ class TestSequential(test.TestCase, parameterized.TestCase): inner_model.trainable = True self.assertEqual(len(model.trainable_weights), 4) + @tf_test_util.run_deprecated_v1 def test_sequential_update_disabling(self): val_a = np.random.random((10, 4)) val_out = np.random.random((10, 4)) diff --git a/tensorflow/python/keras/engine/topology_test.py b/tensorflow/python/keras/engine/topology_test.py index b4a4babf25..03bfd35589 100644 --- a/tensorflow/python/keras/engine/topology_test.py +++ b/tensorflow/python/keras/engine/topology_test.py @@ -42,6 +42,7 @@ except ImportError: class TopologyConstructionTest(test.TestCase): + @test_util.run_deprecated_v1 def test_get_updates(self): class MyLayer(keras.layers.Layer): @@ -115,6 +116,7 @@ class TopologyConstructionTest(test.TestCase): self.assertEqual(len(layer.get_updates_for(x1)), 2) self.assertEqual(len(layer.get_updates_for(None)), 0) + @test_util.run_deprecated_v1 def test_get_losses(self): class MyLayer(keras.layers.Layer): @@ -268,6 +270,7 @@ class TopologyConstructionTest(test.TestCase): self.assertEqual(test_layer.input_shape, [(None, 32), (None, 32)]) self.assertEqual(test_layer.output_shape, (None, 32)) + @test_util.run_deprecated_v1 def testBasicNetwork(self): # minimum viable network x = input_layer_lib.Input(shape=(32,)) @@ -341,6 +344,7 @@ class TopologyConstructionTest(test.TestCase): self.assertListEqual(model.trainable_weights, []) self.assertListEqual(model.non_trainable_weights, weights) + @test_util.run_deprecated_v1 def test_layer_call_arguments(self): # Test the ability to pass and serialize arguments to `call`. inp = keras.layers.Input(shape=(2,)) @@ -491,6 +495,7 @@ class TopologyConstructionTest(test.TestCase): fn_outputs = fn([input_a_np, input_b_np]) self.assertListEqual([x.shape for x in fn_outputs], [(10, 64), (10, 5)]) + @test_util.run_deprecated_v1 def test_recursion(self): with self.cached_session(): a = keras.layers.Input(shape=(32,), name='input_a') @@ -675,6 +680,7 @@ class TopologyConstructionTest(test.TestCase): with self.assertRaises(Exception): keras.models.Model([j, k], [m, n, 0]) + @test_util.run_deprecated_v1 def test_raw_tf_compatibility(self): # test calling layers/models on TF tensors a = keras.layers.Input(shape=(32,), name='input_a') @@ -719,6 +725,7 @@ class TopologyConstructionTest(test.TestCase): model = keras.models.Model(a, b) self.assertEqual(model.output_mask.get_shape().as_list(), [None, 10]) + @test_util.run_deprecated_v1 def testMaskingSingleInput(self): class MaskedLayer(keras.layers.Layer): @@ -756,6 +763,7 @@ class TopologyConstructionTest(test.TestCase): y_2 = network(x_2) self.assertEqual(y_2.get_shape().as_list(), [None, 32]) + @test_util.run_deprecated_v1 def test_activity_regularization_with_model_composition(self): def reg(x): @@ -825,6 +833,7 @@ class TopologyConstructionTest(test.TestCase): output_val_2 = m2.predict(x_val) self.assertAllClose(output_val, output_val_2, atol=1e-6) + @test_util.run_deprecated_v1 def test_explicit_training_argument(self): with self.cached_session(): a = keras.layers.Input(shape=(2,)) @@ -1145,6 +1154,7 @@ class DefaultShapeInferenceBehaviorTest(test.TestCase): class GraphUtilsTest(test.TestCase): + @test_util.run_deprecated_v1 def testGetReachableFromInputs(self): with self.cached_session(): diff --git a/tensorflow/python/keras/engine/training_dataset_test.py b/tensorflow/python/keras/engine/training_dataset_test.py index e79e5842a1..8020326377 100644 --- a/tensorflow/python/keras/engine/training_dataset_test.py +++ b/tensorflow/python/keras/engine/training_dataset_test.py @@ -274,6 +274,7 @@ class TestTrainingWithDataset(test.TestCase, parameterized.TestCase): model.fit(dataset, epochs=1, steps_per_epoch=2, verbose=1) + @tf_test_util.run_deprecated_v1 def test_dataset_input_shape_validation(self): with self.cached_session(): model = testing_utils.get_small_functional_mlp(1, 4, input_dim=3) diff --git a/tensorflow/python/keras/engine/training_test.py b/tensorflow/python/keras/engine/training_test.py index 97dfe6d900..4674bce244 100644 --- a/tensorflow/python/keras/engine/training_test.py +++ b/tensorflow/python/keras/engine/training_test.py @@ -449,6 +449,7 @@ class TrainingTest(test.TestCase): optimizer=keras.optimizers.Adam(lr=0.0001), metrics=['accuracy']) + @tf_test_util.run_deprecated_v1 def test_that_trainable_disables_updates(self): val_a = np.random.random((10, 4)) val_out = np.random.random((10, 4)) @@ -1146,6 +1147,7 @@ class LossMaskingTest(test.TestCase): class TestDynamicTrainability(test.TestCase): + @tf_test_util.run_deprecated_v1 def test_trainable_warning(self): with self.cached_session(): x = np.random.random((5, 3)) @@ -1159,6 +1161,7 @@ class TestDynamicTrainability(test.TestCase): model.train_on_batch(x, y) self.assertRaises(Warning) + @tf_test_util.run_deprecated_v1 def test_trainable_argument(self): with self.cached_session(): x = np.random.random((5, 3)) @@ -1289,6 +1292,7 @@ class TestDynamicTrainability(test.TestCase): class TestTrainingWithDataTensors(test.TestCase): + @tf_test_util.run_deprecated_v1 def test_training_and_eval_methods_on_symbolic_tensors_single_io(self): with self.cached_session(): x = keras.layers.Input(shape=(3,), name='input') @@ -1329,6 +1333,7 @@ class TestTrainingWithDataTensors(test.TestCase): epochs=1, steps_per_epoch=2, verbose=0, validation_data=(inputs, targets), validation_steps=2) + @tf_test_util.run_deprecated_v1 def test_training_and_eval_methods_on_symbolic_tensors_multi_io(self): with self.cached_session(): a = keras.layers.Input(shape=(3,), name='input_a') @@ -1424,6 +1429,7 @@ class TestTrainingWithDataTensors(test.TestCase): model.predict([input_a_tf, input_b_tf], steps=2) model.test_on_batch([input_a_tf, input_b_tf], [output_d_tf, output_e_tf]) + @tf_test_util.run_deprecated_v1 def test_model_with_input_feed_tensor(self): """We test building a model with a TF variable as input. @@ -1602,6 +1608,7 @@ class TestTrainingWithDataTensors(test.TestCase): # evaluate _ = model.evaluate(input_a_np, [output_a_np]) + @tf_test_util.run_deprecated_v1 def test_model_with_external_loss(self): with self.cached_session(): # None loss, only regularization loss. @@ -1797,6 +1804,7 @@ class TestTrainingWithDataTensors(test.TestCase): model.train_on_batch(input_val, None, sample_weight={'dense_a': np.random.random((10,))}) + @tf_test_util.run_deprecated_v1 def test_model_custom_target_tensors(self): with self.cached_session(): a = keras.Input(shape=(3,), name='input_a') @@ -2018,6 +2026,7 @@ class TestTrainingWithMetrics(test.TestCase): scores = model.train_on_batch(x, y, sample_weight=w) self.assertArrayNear(scores, [0.3328, 0.8], 0.001) + @tf_test_util.run_deprecated_v1 def test_add_metric_with_tensor_on_model_in_graph_mode(self): with self.cached_session(): x = keras.layers.Input(shape=(1,)) @@ -2180,6 +2189,7 @@ class TestTrainingWithMetrics(test.TestCase): self.assertEqual(history.history['metric_1'][-1], 5) self.assertAlmostEqual(history.history['val_metric_1'][-1], 5, 0) + @tf_test_util.run_deprecated_v1 def test_model_metrics_list(self): with self.cached_session(): x = keras.layers.Input(shape=(1,)) diff --git a/tensorflow/python/keras/initializers_test.py b/tensorflow/python/keras/initializers_test.py index 2b758a98f3..4f91bea1e3 100644 --- a/tensorflow/python/keras/initializers_test.py +++ b/tensorflow/python/keras/initializers_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python import keras from tensorflow.python.ops import init_ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -38,6 +39,7 @@ class KerasInitializersTest(test.TestCase): output_2 = keras.backend.get_value(variable) self.assertAllClose(output, output_2, atol=1e-4) + @test_util.run_deprecated_v1 def test_uniform(self): tensor_shape = (9, 6, 7) with self.cached_session(): @@ -47,6 +49,7 @@ class KerasInitializersTest(test.TestCase): tensor_shape, target_mean=0., target_max=1, target_min=-1) + @test_util.run_deprecated_v1 def test_normal(self): tensor_shape = (8, 12, 99) with self.cached_session(): @@ -54,6 +57,7 @@ class KerasInitializersTest(test.TestCase): tensor_shape, target_mean=0., target_std=1) + @test_util.run_deprecated_v1 def test_truncated_normal(self): tensor_shape = (12, 99, 7) with self.cached_session(): @@ -69,6 +73,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.Constant(2), tensor_shape, target_mean=2, target_max=2, target_min=2) + @test_util.run_deprecated_v1 def test_lecun_uniform(self): tensor_shape = (5, 6, 4, 2) with self.cached_session(): @@ -77,6 +82,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.lecun_uniform(seed=123), tensor_shape, target_mean=0., target_std=std) + @test_util.run_deprecated_v1 def test_glorot_uniform(self): tensor_shape = (5, 6, 4, 2) with self.cached_session(): @@ -85,6 +91,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.glorot_uniform(seed=123), tensor_shape, target_mean=0., target_std=std) + @test_util.run_deprecated_v1 def test_he_uniform(self): tensor_shape = (5, 6, 4, 2) with self.cached_session(): @@ -93,6 +100,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.he_uniform(seed=123), tensor_shape, target_mean=0., target_std=std) + @test_util.run_deprecated_v1 def test_lecun_normal(self): tensor_shape = (5, 6, 4, 2) with self.cached_session(): @@ -101,6 +109,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.lecun_normal(seed=123), tensor_shape, target_mean=0., target_std=std) + @test_util.run_deprecated_v1 def test_glorot_normal(self): tensor_shape = (5, 6, 4, 2) with self.cached_session(): @@ -109,6 +118,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.glorot_normal(seed=123), tensor_shape, target_mean=0., target_std=std) + @test_util.run_deprecated_v1 def test_he_normal(self): tensor_shape = (5, 6, 4, 2) with self.cached_session(): @@ -117,6 +127,7 @@ class KerasInitializersTest(test.TestCase): self._runner(keras.initializers.he_normal(seed=123), tensor_shape, target_mean=0., target_std=std) + @test_util.run_deprecated_v1 def test_orthogonal(self): tensor_shape = (20, 20) with self.cached_session(): diff --git a/tensorflow/python/keras/integration_test.py b/tensorflow/python/keras/integration_test.py index 3c0f73b1c3..f1a0932613 100644 --- a/tensorflow/python/keras/integration_test.py +++ b/tensorflow/python/keras/integration_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python import keras from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.keras import testing_utils from tensorflow.python.layers import core as tf_core_layers from tensorflow.python.ops import nn @@ -34,6 +35,7 @@ class KerasIntegrationTest(test.TestCase): def test_version(self): self.assertTrue(keras.__version__.endswith('-tf')) + @test_util.run_deprecated_v1 def test_vector_classification_sequential(self): with self.cached_session(): np.random.seed(1337) @@ -59,6 +61,7 @@ class KerasIntegrationTest(test.TestCase): verbose=2) self.assertGreater(history.history['val_acc'][-1], 0.7) + @test_util.run_deprecated_v1 def test_vector_classification_functional(self): with self.cached_session(): np.random.seed(1337) @@ -83,6 +86,7 @@ class KerasIntegrationTest(test.TestCase): verbose=2) self.assertGreater(history.history['val_acc'][-1], 0.7) + @test_util.run_deprecated_v1 def test_temporal_classification_sequential(self): with self.cached_session(): np.random.seed(1337) @@ -105,6 +109,7 @@ class KerasIntegrationTest(test.TestCase): verbose=2) self.assertGreater(history.history['val_acc'][-1], 0.7) + @test_util.run_deprecated_v1 def test_temporal_classification_sequential_tf_rnn(self): with self.cached_session(): np.random.seed(1337) @@ -163,6 +168,7 @@ class KerasIntegrationTest(test.TestCase): verbose=2) self.assertGreater(history.history['val_acc'][-1], 0.7) + @test_util.run_deprecated_v1 def test_video_classification_functional(self): with self.cached_session(): np.random.seed(1337) @@ -191,6 +197,7 @@ class KerasIntegrationTest(test.TestCase): verbose=2) self.assertGreater(history.history['val_acc'][-1], 0.7) + @test_util.run_deprecated_v1 def test_vector_classification_shared_sequential(self): # Test that Sequential models that feature internal updates # and internal losses can be shared. @@ -225,6 +232,7 @@ class KerasIntegrationTest(test.TestCase): verbose=2) self.assertGreater(history.history['val_acc'][-1], 0.7) + @test_util.run_deprecated_v1 def test_vector_classification_shared_model(self): # Test that functional models that feature internal updates # and internal losses can be shared. diff --git a/tensorflow/python/keras/layers/local_test.py b/tensorflow/python/keras/layers/local_test.py index 1c20d43706..a23c5c38fe 100644 --- a/tensorflow/python/keras/layers/local_test.py +++ b/tensorflow/python/keras/layers/local_test.py @@ -32,6 +32,7 @@ class LocallyConnected1DLayersTest(test.TestCase): # fails inside a graph function in an eager context (fails with error # "Incompatible shapes between op input and calculated input gradient"). + @tf_test_util.run_deprecated_v1 def test_locallyconnected_1d(self): with self.cached_session(): num_samples = 2 @@ -120,6 +121,7 @@ class LocallyConnected2DLayersTest(test.TestCase): # fails inside a graph function in an eager context (fails with error # "Incompatible shapes between op input and calculated input gradient"). + @tf_test_util.run_deprecated_v1 def test_locallyconnected_2d(self): with self.cached_session(): num_samples = 8 @@ -155,6 +157,7 @@ class LocallyConnected2DLayersTest(test.TestCase): kwargs=kwargs, input_shape=(num_samples, num_row, num_col, stack_size)) + @tf_test_util.run_deprecated_v1 def test_locallyconnected_2d_channels_first(self): with self.cached_session(): num_samples = 8 @@ -232,6 +235,7 @@ class LocallyConnected2DLayersTest(test.TestCase): class LocallyConnectedImplementationModeTest(test.TestCase): + @tf_test_util.run_deprecated_v1 def test_locallyconnected_implementation(self): with self.cached_session(): num_samples = 4 diff --git a/tensorflow/python/keras/layers/lstm_test.py b/tensorflow/python/keras/layers/lstm_test.py index 9db697871f..732bbcfa18 100644 --- a/tensorflow/python/keras/layers/lstm_test.py +++ b/tensorflow/python/keras/layers/lstm_test.py @@ -114,6 +114,7 @@ class LSTMLayerTest(test.TestCase): self.assertEqual(layer.cell.recurrent_kernel.constraint, r_constraint) self.assertEqual(layer.cell.bias.constraint, b_constraint) + @tf_test_util.run_deprecated_v1 def test_with_masking_layer_LSTM(self): layer_class = keras.layers.LSTM inputs = np.random.random((2, 3, 4)) @@ -126,6 +127,7 @@ class LSTMLayerTest(test.TestCase): optimizer=RMSPropOptimizer(0.01)) model.fit(inputs, targets, epochs=1, batch_size=2, verbose=1) + @tf_test_util.run_deprecated_v1 def test_masking_with_stacking_LSTM(self): inputs = np.random.random((2, 3, 4)) targets = np.abs(np.random.random((2, 3, 5))) @@ -311,6 +313,7 @@ class LSTMLayerTest(test.TestCase): class LSTMLayerGraphOnlyTest(test.TestCase): + @tf_test_util.run_deprecated_v1 def test_statefulness_LSTM(self): num_samples = 2 timesteps = 3 @@ -374,6 +377,7 @@ class LSTMLayerGraphOnlyTest(test.TestCase): self.assertAllClose(out7, out6, atol=1e-5) + @tf_test_util.run_deprecated_v1 def test_regularizers_LSTM(self): embedding_dim = 4 layer_class = keras.layers.LSTM diff --git a/tensorflow/python/keras/layers/merge_test.py b/tensorflow/python/keras/layers/merge_test.py index 698c5662b6..fcb161ae20 100644 --- a/tensorflow/python/keras/layers/merge_test.py +++ b/tensorflow/python/keras/layers/merge_test.py @@ -207,6 +207,7 @@ class MergeLayersGraphOnlyTest(test.TestCase): mask = layer.output_mask self.assertListEqual(mask.get_shape().as_list(), [None, 4]) + @tf_test_util.run_deprecated_v1 def test_merge_add_dynamic_shape(self): with self.cached_session(): i1 = array_ops.placeholder(shape=(4, None), dtype='float32') diff --git a/tensorflow/python/keras/layers/normalization_test.py b/tensorflow/python/keras/layers/normalization_test.py index 2f7f042b7f..9138c0a08a 100644 --- a/tensorflow/python/keras/layers/normalization_test.py +++ b/tensorflow/python/keras/layers/normalization_test.py @@ -301,6 +301,7 @@ class NormalizationLayersGraphModeOnlyTest(test.TestCase): x2 = model.predict(val_a) self.assertAllClose(x1, x2, atol=1e-7) + @tf_test_util.run_deprecated_v1 def test_batchnorm_trainable(self): """Tests that batchnorm layer is trainable when learning phase is enabled. diff --git a/tensorflow/python/keras/layers/simplernn_test.py b/tensorflow/python/keras/layers/simplernn_test.py index 93456b5e3a..b49b159b71 100644 --- a/tensorflow/python/keras/layers/simplernn_test.py +++ b/tensorflow/python/keras/layers/simplernn_test.py @@ -98,6 +98,7 @@ class SimpleRNNLayerTest(test.TestCase): self.assertEqual(layer.cell.recurrent_kernel.constraint, r_constraint) self.assertEqual(layer.cell.bias.constraint, b_constraint) + @tf_test_util.run_deprecated_v1 def test_with_masking_layer_SimpleRNN(self): layer_class = keras.layers.SimpleRNN inputs = np.random.random((2, 3, 4)) @@ -120,6 +121,7 @@ class SimpleRNNLayerTest(test.TestCase): class SimpleRNNLayerGraphOnlyTest(test.TestCase): + @tf_test_util.run_deprecated_v1 def test_statefulness_SimpleRNN(self): num_samples = 2 timesteps = 3 @@ -183,6 +185,7 @@ class SimpleRNNLayerGraphOnlyTest(test.TestCase): np.testing.assert_allclose(out7, out6, atol=1e-5) + @tf_test_util.run_deprecated_v1 def test_regularizers_SimpleRNN(self): embedding_dim = 4 layer_class = keras.layers.SimpleRNN diff --git a/tensorflow/python/keras/layers/unified_rnn_test.py b/tensorflow/python/keras/layers/unified_rnn_test.py index b08ff3cafc..e26e47000d 100644 --- a/tensorflow/python/keras/layers/unified_rnn_test.py +++ b/tensorflow/python/keras/layers/unified_rnn_test.py @@ -69,6 +69,7 @@ class RNNTest(test.TestCase): def tearDown(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def test_unifiedRNN(self): input_shape = 10 rnn_state_size = 8 @@ -113,6 +114,7 @@ class RNNTest(test.TestCase): self.assertNotEqual(existing_loss, loss_value) existing_loss = loss_value + @test_util.run_deprecated_v1 def test_unifiedRNN_with_cond(self): # This test is to demonstrate the graph rewrite of grappler plugin under # the condition that the function returns different number of internal diff --git a/tensorflow/python/keras/layers/wrappers_test.py b/tensorflow/python/keras/layers/wrappers_test.py index bbafa96aab..427314faf1 100644 --- a/tensorflow/python/keras/layers/wrappers_test.py +++ b/tensorflow/python/keras/layers/wrappers_test.py @@ -201,6 +201,7 @@ class TimeDistributedTest(test.TestCase): assert len(layer.updates) == 2 assert len(layer.trainable_weights) == 2 + @tf_test_util.run_deprecated_v1 def test_TimeDistributed_with_masked_embedding_and_unspecified_shape(self): with self.cached_session(): # test with unspecified shape and Embeddings with mask_zero @@ -233,6 +234,7 @@ class TimeDistributedTest(test.TestCase): self.assertAllEqual(mask_outputs_val[i], ref_mask_val[i]) self.assertIs(mask_outputs[-1], None) # final layer + @tf_test_util.run_deprecated_v1 def test_TimeDistributed_with_masking_layer(self): with self.cached_session(): # test with Masking layer @@ -375,6 +377,7 @@ class BidirectionalTest(test.TestCase): model.compile(loss='mse', optimizer='sgd') model.fit(x, y, epochs=1, batch_size=1) + @tf_test_util.run_deprecated_v1 def test_Bidirectional_merged_value(self): rnn = keras.layers.LSTM samples = 2 @@ -505,6 +508,7 @@ class BidirectionalTest(test.TestCase): layer.trainable = True assert len(layer.trainable_weights) == 6 + @tf_test_util.run_deprecated_v1 def test_Bidirectional_updates(self): with self.cached_session(): x = keras.layers.Input(shape=(3, 2)) diff --git a/tensorflow/python/keras/model_subclassing_test.py b/tensorflow/python/keras/model_subclassing_test.py index ccfff57a3b..ca7dded60d 100644 --- a/tensorflow/python/keras/model_subclassing_test.py +++ b/tensorflow/python/keras/model_subclassing_test.py @@ -917,6 +917,7 @@ class ModelSubclassingTest(test.TestCase): class GraphSpecificModelSubclassingTests(test.TestCase): + @test_util.run_deprecated_v1 def test_single_io_workflow_with_tensors(self): num_classes = 2 num_samples = 10 @@ -934,6 +935,7 @@ class GraphSpecificModelSubclassingTests(test.TestCase): model.fit(x, y, epochs=2, steps_per_epoch=10, verbose=0) _ = model.evaluate(steps=10, verbose=0) + @test_util.run_deprecated_v1 def test_multi_io_workflow_with_tensors(self): num_classes = (2, 3) num_samples = 10 @@ -953,6 +955,7 @@ class GraphSpecificModelSubclassingTests(test.TestCase): model.fit([x1, x2], [y1, y2], epochs=2, steps_per_epoch=10, verbose=0) _ = model.evaluate(steps=10, verbose=0) + @test_util.run_deprecated_v1 def test_updates_and_losses_for_nested_models_in_subclassed_model(self): # Case 1: deferred-build sequential nested in subclass. @@ -1020,6 +1023,7 @@ class GraphSpecificModelSubclassingTests(test.TestCase): self.assertEqual(len(model.get_updates_for(x)), 2) self.assertEqual(len(model.get_losses_for(x)), 1) + @test_util.run_deprecated_v1 def test_multi_io_workflow_with_numpy_arrays_and_custom_placeholders(self): num_classes = (2, 3) num_samples = 1000 diff --git a/tensorflow/python/keras/models_test.py b/tensorflow/python/keras/models_test.py index c68c80f0cc..8af3cc05f5 100644 --- a/tensorflow/python/keras/models_test.py +++ b/tensorflow/python/keras/models_test.py @@ -69,6 +69,7 @@ def sequential_model(add_input_layer, include_input_shape=True): class TestModelCloning(test.TestCase): + @test_util.run_deprecated_v1 def test_clone_sequential_model(self): with self.cached_session(): val_a = np.random.random((10, 4)) @@ -101,7 +102,10 @@ class TestModelCloning(test.TestCase): new_model.compile('rmsprop', 'mse') new_model.train_on_batch(None, val_out) + @test_util.run_deprecated_v1 def test_clone_sequential_model_input_layer(self): + + @test_util.run_deprecated_v1 def test_input_layer(include_inputs): with self.cached_session(): val_a = np.random.random((10, 4)) @@ -138,6 +142,7 @@ class TestModelCloning(test.TestCase): test_input_layer(True) test_input_layer(False) + @test_util.run_deprecated_v1 def test_clone_functional_model(self): with self.cached_session(): val_a = np.random.random((10, 4)) @@ -397,6 +402,7 @@ class TestCloneAndBuildModel(test.TestCase): new_model.train_on_batch(inp, out) new_model.evaluate(inp, out) + @test_util.run_deprecated_v1 def test_clone_and_build_compiled_sequential_model(self): with self.cached_session(): model = keras.models.Sequential() @@ -409,6 +415,7 @@ class TestCloneAndBuildModel(test.TestCase): self._clone_and_build_test_helper(model) + @test_util.run_deprecated_v1 def test_clone_and_build_functional_model(self): with self.cached_session(): input_a = keras.Input(shape=(4,)) @@ -425,6 +432,7 @@ class TestCloneAndBuildModel(test.TestCase): self._clone_and_build_test_helper(model) + @test_util.run_deprecated_v1 def test_clone_and_build_subclassed_model(self): class SubclassedModel(keras.Model): @@ -473,9 +481,11 @@ class TestCloneAndBuildModel(test.TestCase): def test_replace_tf_optimizer_iterations_variable(self): self.assert_optimizer_iterations_increases(adam.AdamOptimizer(0.01)) + @test_util.run_deprecated_v1 def test_replace_keras_optimizer_iterations_variable(self): self.assert_optimizer_iterations_increases('adam') + @test_util.run_deprecated_v1 def test_clone_and_build_sequential_model_without_inputs_defined(self): with self.cached_session(): model = sequential_model(False, False) diff --git a/tensorflow/python/keras/optimizer_v2/adadelta_test.py b/tensorflow/python/keras/optimizer_v2/adadelta_test.py index ef95d27abf..6409f3ead4 100644 --- a/tensorflow/python/keras/optimizer_v2/adadelta_test.py +++ b/tensorflow/python/keras/optimizer_v2/adadelta_test.py @@ -147,6 +147,7 @@ class AdadeltaOptimizerTest(test.TestCase): with context.eager_mode(): self.doTestBasic(use_resource=True, use_callable_params=True) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/adagrad_test.py b/tensorflow/python/keras/optimizer_v2/adagrad_test.py index 5ddeb1ad80..8004907bf5 100644 --- a/tensorflow/python/keras/optimizer_v2/adagrad_test.py +++ b/tensorflow/python/keras/optimizer_v2/adagrad_test.py @@ -160,6 +160,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -179,6 +180,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( [[0, 1], [3, 4]], var0.eval(), atol=0.01) + @test_util.run_deprecated_v1 def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -211,6 +213,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseBasic(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -255,6 +258,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseRepeatedIndices(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -287,6 +291,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllClose(aggregated_update_var.eval(), repeated_index_update_var.eval()) + @test_util.run_deprecated_v1 def testSparseRepeatedIndicesByEmbeddingLookUp(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -311,6 +316,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( var_repeated.eval(), var_aggregated.eval()) + @test_util.run_deprecated_v1 def testSparseStability(self): for dtype in [dtypes.half]: with self.cached_session(): @@ -343,6 +349,7 @@ class AdagradOptimizerTest(test.TestCase): -0.01029443 ]]), var0.eval()) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/adam_test.py b/tensorflow/python/keras/optimizer_v2/adam_test.py index e2bc6a39f9..b1b17f8f08 100644 --- a/tensorflow/python/keras/optimizer_v2/adam_test.py +++ b/tensorflow/python/keras/optimizer_v2/adam_test.py @@ -62,6 +62,7 @@ def get_beta_accumulators(opt, dtype): class AdamOptimizerTest(test.TestCase): + @test_util.run_deprecated_v1 def testSparse(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -106,6 +107,7 @@ class AdamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseDevicePlacement(self): for index_dtype in [dtypes.int32, dtypes.int64]: with self.cached_session(force_gpu=test.is_gpu_available()): @@ -119,6 +121,7 @@ class AdamOptimizerTest(test.TestCase): variables.global_variables_initializer().run() minimize_op.run() + @test_util.run_deprecated_v1 def testSparseRepeatedIndices(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -208,6 +211,7 @@ class AdamOptimizerTest(test.TestCase): with context.eager_mode(): self.doTestBasic(use_callable_params=True) + @test_util.run_deprecated_v1 def testBasicWithLearningRateDecay(self): for i, dtype in enumerate([dtypes.half, dtypes.float32, dtypes.float64]): with self.session(graph=ops.Graph()): @@ -254,6 +258,7 @@ class AdamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -292,6 +297,7 @@ class AdamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/adamax_test.py b/tensorflow/python/keras/optimizer_v2/adamax_test.py index aa215b0faf..7521a6196e 100644 --- a/tensorflow/python/keras/optimizer_v2/adamax_test.py +++ b/tensorflow/python/keras/optimizer_v2/adamax_test.py @@ -124,9 +124,11 @@ class AdamaxOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, var0.eval()) self.assertAllCloseAccordingToType(var1_np, var1.eval()) + @test_util.run_deprecated_v1 def testResourceSparse(self): self.doTestSparse(use_resource=True) + @test_util.run_deprecated_v1 def testSparseDevicePlacement(self): for index_dtype in [dtypes.int32, dtypes.int64]: with self.cached_session(force_gpu=test.is_gpu_available()): @@ -140,6 +142,7 @@ class AdamaxOptimizerTest(test.TestCase): variables.global_variables_initializer().run() minimize_op.run() + @test_util.run_deprecated_v1 def testSparseRepeatedIndices(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -272,6 +275,7 @@ class AdamaxOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1), rtol=1e-2) + @test_util.run_deprecated_v1 def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -308,6 +312,7 @@ class AdamaxOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, var0.eval()) self.assertAllCloseAccordingToType(var1_np, var1.eval()) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/ftrl_test.py b/tensorflow/python/keras/optimizer_v2/ftrl_test.py index ca8c33dfa6..bec400e8cb 100644 --- a/tensorflow/python/keras/optimizer_v2/ftrl_test.py +++ b/tensorflow/python/keras/optimizer_v2/ftrl_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.keras.optimizer_v2 import ftrl from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops @@ -68,12 +69,15 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.28432083, -0.56694895]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithoutRegularization(self): self.doTestFtrlwithoutRegularization(use_resource=False) + @test_util.run_deprecated_v1 def testResourceFtrlWithoutRegularization(self): self.doTestFtrlwithoutRegularization(use_resource=True) + @test_util.run_deprecated_v1 def testFtrlwithoutRegularization2(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session() as sess: @@ -103,6 +107,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.28232238, -0.56096673]), v1_val) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -121,6 +126,7 @@ class FtrlOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testFtrlWithL1(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session() as sess: @@ -150,6 +156,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.93460727, -1.86147261]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL1_L2(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session() as sess: @@ -180,6 +187,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.02406147, -0.04830509]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL1_L2_L2Shrinkage(self): """Test the new FTRL op with support for l2 shrinkage. @@ -217,6 +225,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.14378493, -0.13229476]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL1_L2_L2ShrinkageSparse(self): """Tests the new FTRL op with support for l2 shrinkage on sparse grads.""" for dtype in [dtypes.half, dtypes.float32]: @@ -251,6 +260,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([[-0.22578995], [2.]], v0_val) self.assertAllCloseAccordingToType([[4.], [-0.13229476]], v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL2ShrinkageDoesNotChangeLrSchedule(self): """Verifies that l2 shrinkage in FTRL does not change lr schedule.""" for dtype in [dtypes.half, dtypes.float32]: @@ -335,6 +345,7 @@ class FtrlOptimizerTest(test.TestCase): # with Adagrad. # So, basing on these two properties, we test if our implementation of # FTRL-Proximal performs same updates as Adagrad or GradientDescent. + @test_util.run_deprecated_v1 def testEquivAdagradwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): @@ -355,6 +366,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(val0, val2) self.assertAllCloseAccordingToType(val1, val3) + @test_util.run_deprecated_v1 def testEquivSparseAdagradwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): @@ -378,6 +390,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(val0, val2) self.assertAllCloseAccordingToType(val1, val3) + @test_util.run_deprecated_v1 def testEquivSparseGradientDescentwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): @@ -401,6 +414,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(val0, val2) self.assertAllCloseAccordingToType(val1, val3) + @test_util.run_deprecated_v1 def testEquivGradientDescentwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py b/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py index 348d2728c8..dae2a47735 100644 --- a/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py +++ b/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py @@ -134,6 +134,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.evaluate(var0)) self.assertAllCloseAccordingToType([3.0 - 1.0], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -173,6 +174,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([3.0 - 3.0 * 0.01, 4.0 - 3.0 * 0.01], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testGradWrtRef(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -206,6 +208,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([[3.0], [4.0 - 3.0 * 0.01]], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseBasicWithLearningRateDecay(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -331,6 +334,7 @@ class MomentumOptimizerTest(test.TestCase): 3.98 - ((0.9 * 0.01 + 0.01) * 2.0) ]), self.evaluate(var1)) + @test_util.run_deprecated_v1 def testNesterovMomentum(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -358,6 +362,7 @@ class MomentumOptimizerTest(test.TestCase): self.assertAllClose(var0_np, self.evaluate(var0)) self.assertAllClose(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseNesterovMomentum(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -399,6 +404,7 @@ class MomentumOptimizerTest(test.TestCase): self.assertAllClose(var1_np, self.evaluate(var1)) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: # This test invokes the ResourceSparseApplyMomentum operation, which @@ -452,6 +458,7 @@ class MomentumOptimizerTest(test.TestCase): self.evaluate(sgd_op) self.assertAllCloseAccordingToType([[1, 1], [0, 0]], self.evaluate(var0)) + @test_util.run_deprecated_v1 def testTensorLearningRateAndMomentum(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -510,6 +517,7 @@ class MomentumOptimizerTest(test.TestCase): 3.98 - ((0.9 * 0.01 + 0.01) * 2.0) ]), self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparse(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -585,6 +593,7 @@ class MomentumOptimizerTest(test.TestCase): ]), self.evaluate(var1)[2]) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/nadam_test.py b/tensorflow/python/keras/optimizer_v2/nadam_test.py index b7132bbea7..d991e3117c 100644 --- a/tensorflow/python/keras/optimizer_v2/nadam_test.py +++ b/tensorflow/python/keras/optimizer_v2/nadam_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.keras.optimizer_v2 import nadam from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -111,9 +112,11 @@ class NadamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, var0.eval()) self.assertAllCloseAccordingToType(var1_np, var1.eval()) + @test_util.run_deprecated_v1 def testSparse(self): self.doTestSparse(use_resource=False) + @test_util.run_deprecated_v1 def testResourceSparse(self): self.doTestSparse(use_resource=True) @@ -158,9 +161,11 @@ class NadamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, var0.eval()) self.assertAllCloseAccordingToType(var1_np, var1.eval()) + @test_util.run_deprecated_v1 def testResourceBasic(self): self.doTestBasic(use_resource=True) + @test_util.run_deprecated_v1 def testBasicWithLearningRateDecay(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py index a320cc0c49..a8658a8550 100644 --- a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py +++ b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py @@ -86,6 +86,7 @@ class RMSpropOptimizerTest(test.TestCase): var_t[gindex] = var[gindex] - mom_t[gindex] return var_t, mg_t, rms_t, mom_t + @test_util.run_deprecated_v1 def testDense(self): for (dtype, learning_rate, rho, momentum, epsilon, centered) in _TESTPARAMS: with test_util.use_gpu(): @@ -158,6 +159,7 @@ class RMSpropOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testDenseWithLearningRateDecay(self): var0_np = np.array([1.0, 2.0]) grads0_np = np.array([0.1, 0.2]) @@ -225,6 +227,7 @@ class RMSpropOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -249,6 +252,7 @@ class RMSpropOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariableCentered(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -273,6 +277,7 @@ class RMSpropOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testSparse(self): for (dtype, learning_rate, rho, momentum, epsilon, centered) in _TESTPARAMS: with test_util.use_gpu(): diff --git a/tensorflow/python/keras/optimizers_test.py b/tensorflow/python/keras/optimizers_test.py index 46bb0274c6..d3cacb702c 100644 --- a/tensorflow/python/keras/optimizers_test.py +++ b/tensorflow/python/keras/optimizers_test.py @@ -91,22 +91,26 @@ def _test_optimizer(optimizer, target=0.75): class KerasOptimizersTest(test.TestCase): + @test_util.run_deprecated_v1 def test_sgd(self): with self.cached_session(): _test_optimizer(keras.optimizers.SGD(lr=0.01, momentum=0.9, nesterov=True)) + @test_util.run_deprecated_v1 def test_rmsprop(self): with self.cached_session(): _test_optimizer(keras.optimizers.RMSprop()) _test_optimizer(keras.optimizers.RMSprop(decay=1e-3)) + @test_util.run_deprecated_v1 def test_adagrad(self): with self.cached_session(): _test_optimizer(keras.optimizers.Adagrad()) _test_optimizer(keras.optimizers.Adagrad(decay=1e-3)) + @test_util.run_deprecated_v1 def test_adadelta(self): with self.cached_session(): _test_optimizer(keras.optimizers.Adadelta(), target=0.6) @@ -115,27 +119,32 @@ class KerasOptimizersTest(test.TestCase): # the accuracy. _test_optimizer(keras.optimizers.Adadelta(decay=1e-3), target=0.4) + @test_util.run_deprecated_v1 def test_adam(self): with self.cached_session(): _test_optimizer(keras.optimizers.Adam()) _test_optimizer(keras.optimizers.Adam(decay=1e-3)) _test_optimizer(keras.optimizers.Adam(amsgrad=True)) + @test_util.run_deprecated_v1 def test_adamax(self): with self.cached_session(): _test_optimizer(keras.optimizers.Adamax()) _test_optimizer(keras.optimizers.Adamax(decay=1e-3)) + @test_util.run_deprecated_v1 def test_nadam(self): with self.cached_session(): _test_optimizer(keras.optimizers.Nadam()) + @test_util.run_deprecated_v1 def test_clipnorm(self): with self.cached_session(): _test_optimizer(keras.optimizers.SGD(lr=0.01, momentum=0.9, clipnorm=0.5)) + @test_util.run_deprecated_v1 def test_clipvalue(self): with self.cached_session(): _test_optimizer(keras.optimizers.SGD(lr=0.01, diff --git a/tensorflow/python/keras/regularizers_test.py b/tensorflow/python/keras/regularizers_test.py index bba4ebb287..3d6b259d87 100644 --- a/tensorflow/python/keras/regularizers_test.py +++ b/tensorflow/python/keras/regularizers_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python import keras from tensorflow.python.keras import testing_utils +from tensorflow.python.framework import test_util from tensorflow.python.platform import test @@ -61,6 +62,7 @@ class KerasRegularizersTest(test.TestCase): model.fit(x_train, y_train, batch_size=10, epochs=1, verbose=0) + @test_util.run_deprecated_v1 def test_activity_regularization(self): with self.cached_session(): (x_train, y_train), _ = get_data() diff --git a/tensorflow/python/kernel_tests/accumulate_n_test.py b/tensorflow/python/kernel_tests/accumulate_n_test.py index c7f11f854d..5eece9c941 100644 --- a/tensorflow/python/kernel_tests/accumulate_n_test.py +++ b/tensorflow/python/kernel_tests/accumulate_n_test.py @@ -32,6 +32,7 @@ from tensorflow.python.platform import googletest class AccumulateNV2Test(test_util.TensorFlowTestCase): """Tests of the new, differentiable version of accumulate_n.""" + @test_util.run_deprecated_v1 def testFloat(self): np.random.seed(12345) x = [np.random.random((1, 2, 3, 4, 5)) - 0.5 for _ in range(5)] @@ -41,6 +42,7 @@ class AccumulateNV2Test(test_util.TensorFlowTestCase): self.assertAllClose(x[0] * 5, math_ops.accumulate_n([tf_x[0]] * 5).eval()) + @test_util.run_deprecated_v1 def testInt(self): np.random.seed(54321) x = [np.random.randint(-128, 128, (5, 4, 3, 2, 1)) for _ in range(6)] @@ -50,12 +52,14 @@ class AccumulateNV2Test(test_util.TensorFlowTestCase): self.assertAllEqual(x[0] * 6, math_ops.accumulate_n([tf_x[0]] * 6).eval()) + @test_util.run_deprecated_v1 def testUnknownShape(self): with self.session(use_gpu=True): x0 = array_ops.placeholder(dtype=dtypes_lib.int32, shape=[None]) acc = math_ops.accumulate_n([x0, x0], shape=[None]) self.assertAllEqual([2, 4], acc.eval(feed_dict={x0: [1, 2]})) + @test_util.run_deprecated_v1 def testGrad(self): np.random.seed(42) for num_inputs in range(1, 10): diff --git a/tensorflow/python/kernel_tests/ackermann_test.py b/tensorflow/python/kernel_tests/ackermann_test.py index d267e49752..6c20b19be9 100644 --- a/tensorflow/python/kernel_tests/ackermann_test.py +++ b/tensorflow/python/kernel_tests/ackermann_test.py @@ -20,12 +20,14 @@ from __future__ import print_function import os from tensorflow.python.framework import load_library +from tensorflow.python.framework import test_util from tensorflow.python.platform import resource_loader from tensorflow.python.platform import test class AckermannTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): library_filename = os.path.join(resource_loader.get_data_files_path(), 'ackermann_op.so') diff --git a/tensorflow/python/kernel_tests/aggregate_ops_test.py b/tensorflow/python/kernel_tests/aggregate_ops_test.py index 874d616658..d9787cc3bf 100644 --- a/tensorflow/python/kernel_tests/aggregate_ops_test.py +++ b/tensorflow/python/kernel_tests/aggregate_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.core.framework import tensor_pb2 from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import logging_ops from tensorflow.python.ops import math_ops @@ -67,6 +68,7 @@ class AddNTest(test.TestCase): tol = 5e-3 if dtype == dtypes.float16 else 5e-7 self.assertAllClose(expected, actual, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testUnknownShapes(self): np.random.seed(12345) with self.session(use_gpu=True) as sess: @@ -80,6 +82,7 @@ class AddNTest(test.TestCase): tol = 5e-3 if dtype == dtypes.float16 else 5e-7 self.assertAllClose(expected, actual, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testVariant(self): def create_constant_variant(value): diff --git a/tensorflow/python/kernel_tests/argmax_op_test.py b/tensorflow/python/kernel_tests/argmax_op_test.py index d34a1dc9b2..06ec0948c2 100644 --- a/tensorflow/python/kernel_tests/argmax_op_test.py +++ b/tensorflow/python/kernel_tests/argmax_op_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -110,12 +111,14 @@ class ArgMaxTest(test.TestCase): r"Reduction axis 0 is empty in shape \[0\]"): op([], 0).eval() + @test_util.run_deprecated_v1 def testDefaultAxis(self): with self.cached_session(): for op in math_ops.argmin, math_ops.argmax: ans = op([1]).eval() self.assertAllEqual(ans, 0) + @test_util.run_deprecated_v1 def testOutputEmpty(self): with self.cached_session(): for op in math_ops.argmin, math_ops.argmax: diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py index afc158f697..f4c442b7b1 100644 --- a/tensorflow/python/kernel_tests/array_ops_test.py +++ b/tensorflow/python/kernel_tests/array_ops_test.py @@ -143,36 +143,43 @@ class BooleanMaskTest(test_util.TensorFlowTestCase): self.assertAllClose(masked_arr, masked_tensor.eval()) + @test_util.run_deprecated_v1 def testMaskDim1ArrDim2Axis1(self): ndims_mask = 1 for arr_shape in [(1, 1), (2, 2), (2, 5)]: self.CheckVersusNumpy(ndims_mask, arr_shape, axis=1) + @test_util.run_deprecated_v1 def testMaskDim2ArrDim2Axis1(self): ndims_mask = 2 for arr_shape in [(1, 1), (2, 2), (2, 5)]: self.CheckVersusNumpy(ndims_mask, arr_shape, axis=1) + @test_util.run_deprecated_v1 def testMaskDim1ArrDim1(self): ndims_mask = 1 for arr_shape in [(1,), (2,), (3,), (10,)]: self.CheckVersusNumpy(ndims_mask, arr_shape) + @test_util.run_deprecated_v1 def testMaskDim1ArrDim2(self): ndims_mask = 1 for arr_shape in [(1, 1), (2, 2), (2, 5)]: self.CheckVersusNumpy(ndims_mask, arr_shape) + @test_util.run_deprecated_v1 def testMaskDim2ArrDim2(self): ndims_mask = 2 for arr_shape in [(1, 1), (2, 2), (2, 5)]: self.CheckVersusNumpy(ndims_mask, arr_shape) + @test_util.run_deprecated_v1 def testMaskDim2ArrDim3(self): ndims_mask = 2 for arr_shape in [(1, 1, 1), (1, 2, 2), (2, 2, 1)]: self.CheckVersusNumpy(ndims_mask, arr_shape) + @test_util.run_deprecated_v1 def testEmptyInput2D(self): mask = np.array([True, False]) arr = np.array([[], []]).astype(np.float32) @@ -191,6 +198,7 @@ class BooleanMaskTest(test_util.TensorFlowTestCase): with self.cached_session(): self.assertAllClose(numpy_result, tf_result.eval()) + @test_util.run_deprecated_v1 def testEmptyOutput(self): make_mask = lambda shape: np.zeros(shape, dtype=bool) for ndims_mask in range(1, 4): @@ -199,6 +207,7 @@ class BooleanMaskTest(test_util.TensorFlowTestCase): arr_shape = np.random.randint(1, 5, size=ndims_arr) self.CheckVersusNumpy(ndims_mask, arr_shape, make_mask=make_mask) + @test_util.run_deprecated_v1 def testWorksWithDimensionsEqualToNoneDuringGraphBuild(self): # The rank of the mask tensor must be specified. This is explained # in the docstring as well. @@ -217,6 +226,7 @@ class BooleanMaskTest(test_util.TensorFlowTestCase): }) np.testing.assert_allclose(masked_tensor, arr[mask]) + @test_util.run_deprecated_v1 def testMaskDimensionsSetToNoneRaises(self): # The rank of the mask tensor must be specified. This is explained # in the docstring as well. @@ -283,6 +293,7 @@ class OperatorShapeTest(test_util.TensorFlowTestCase): class ReverseV2Test(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testReverse0DimAuto(self): x_np = 4 for use_gpu in [False, True]: @@ -327,6 +338,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): # This test covers the axis validation in the shape function # (no eval()) + @test_util.run_deprecated_v1 def testInvalidAxis(self): x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32) with self.assertRaisesRegexp(ValueError, @@ -345,6 +357,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): # # Note: this test passes placeholder as constant axis is validated # in shape function (see testInvalidAxis) + @test_util.run_deprecated_v1 def testInvalid(self): x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32) axis = array_ops.placeholder(dtypes.int32) @@ -359,6 +372,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): "axis 0 specified more than once"): array_ops.reverse_v2(x_np, axis).eval(feed_dict={axis: [0, -2]}) + @test_util.run_deprecated_v1 def testReverse1DimAuto(self): for dtype in [ np.uint8, np.int8, np.uint16, np.int16, np.int32, np.int64, np.bool, @@ -367,6 +381,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): ]: self._reverse1DimAuto(dtype) + @test_util.run_deprecated_v1 def testReverse2DimAuto(self): for dtype in [ np.uint8, np.int8, np.uint16, np.int16, np.int32, np.int64, np.bool, @@ -375,6 +390,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): ]: self._reverse2DimAuto(dtype) + @test_util.run_deprecated_v1 def testUnknownDims(self): reverse_v2 = array_ops.reverse_v2 data_t = array_ops.placeholder(dtypes.float32) @@ -392,6 +408,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): reverse_2d_t = reverse_v2(data_2d_t, axis_2d_t) self.assertEqual(2, reverse_2d_t.get_shape().ndims) + @test_util.run_deprecated_v1 def testReverseRowsOf3Channels(self): """Tests optimized code for reversing rows with last dim size = 3.""" with self.session(use_gpu=True): @@ -405,6 +422,7 @@ class ReverseV2Test(test_util.TensorFlowTestCase): np_answer = x_np[:, ::-1, :] self.assertAllEqual(x_tf, np_answer) + @test_util.run_deprecated_v1 def testReverseRowsOf4Channels(self): with self.session(use_gpu=True): for reverse_f in [array_ops.reverse_v2, array_ops.reverse]: @@ -454,6 +472,7 @@ class MeshgridTest(test_util.TensorFlowTestCase): for x_np, x_tf in zip(numpy_out, tf_out): self.assertAllEqual(x_np, x_tf.eval()) + @test_util.run_deprecated_v1 def testCompare(self): for t in (np.float16, np.float32, np.float64, np.int32, np.int64, np.complex64, np.complex128): @@ -526,6 +545,7 @@ STRIDED_SLICE_TYPES = [ class StridedSliceTest(test_util.TensorFlowTestCase): """Test the strided slice operation with variants of slices.""" + @test_util.run_deprecated_v1 def test_basic_slice(self): for tensor_type in STRIDED_SLICE_TYPES: with self.cached_session(use_gpu=True): @@ -581,6 +601,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): v = variables.Variable([1., 2.]) v[0] # pylint: disable=pointless-statement + @test_util.run_deprecated_v1 def testDegenerateSlices(self): with self.session(use_gpu=True): checker = StridedSliceChecker(self, StridedSliceChecker.REF_TENSOR) @@ -591,6 +612,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): # empty interval in every dimension _ = checker[-1:0, 2:2, 2:3:-1] + @test_util.run_deprecated_v1 def testEllipsis(self): with self.session(use_gpu=True): raw = [[[[[1, 2], [3, 4], [5, 6]]], [[[7, 8], [9, 10], [11, 12]]]]] @@ -611,6 +633,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp(ValueError, "Multiple ellipses"): _ = checker[..., :, ...].eval() + @test_util.run_deprecated_v1 def testShrink(self): with self.session(use_gpu=True): raw = [[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]], @@ -621,6 +644,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): _ = checker[:, 0] _ = checker[:, :, 0] + @test_util.run_deprecated_v1 def testBothNewAxisAndShrink(self): with self.session(use_gpu=True): ones = array_ops.placeholder(shape=[2, 2], dtype=dtypes.int16) @@ -629,6 +653,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): feed_dict={ones: [[1, 1], [1, 1]]}), [[1, 1]]) + @test_util.run_deprecated_v1 def testTensorIndexing(self): with self.session(use_gpu=True): raw = [[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]], @@ -654,6 +679,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp(TypeError, expected): _ = checker[constant_op.constant(0.0)] + @test_util.run_deprecated_v1 def testExpand(self): with self.session(use_gpu=True): raw = [[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]], @@ -671,6 +697,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): # Ellipsis in middle of two newaxis _ = checker[np.newaxis, ..., np.newaxis] + @test_util.run_deprecated_v1 def testExpandVariable(self): with self.session(use_gpu=True): x = variables.Variable(7, dtype=dtypes.int32) @@ -679,6 +706,7 @@ class StridedSliceTest(test_util.TensorFlowTestCase): self.assertEqual(y.shape, (1,)) self.assertAllEqual(y, (7,)) + @test_util.run_deprecated_v1 def testOptimizedCases(self): with self.session(use_gpu=True): checker = StridedSliceChecker(self, @@ -708,6 +736,7 @@ class StridedSliceShapeChecker(object): class StridedSliceShapeTest(test_util.TensorFlowTestCase): """Test the shape inference of StridedSliceShapes.""" + @test_util.run_deprecated_v1 def testUnknown(self): with self.session(use_gpu=True): uncertain_tensor = array_ops.placeholder(dtypes.float32) @@ -719,6 +748,7 @@ class StridedSliceShapeTest(test_util.TensorFlowTestCase): self.assertTrue(x is not None and y is not None or x is None and y is None) self.assertEqual(x.as_list(), y.as_list()) + @test_util.run_deprecated_v1 def testTensorShapeUncertain(self): with self.session(use_gpu=True): uncertain_tensor = array_ops.placeholder( @@ -742,6 +772,7 @@ class StridedSliceShapeTest(test_util.TensorFlowTestCase): self.tensorShapeEqual(a[::-1, :, array_ops.newaxis, ::-2], tensor_shape.TensorShape([5, None, 1, 4])) + @test_util.run_deprecated_v1 def testTensorValuedIndexShape(self): with self.session(use_gpu=True): defined_shape_tensor = array_ops.placeholder( @@ -798,6 +829,7 @@ class GradSliceChecker(object): class StridedSliceGradTest(test_util.TensorFlowTestCase): """Test that strided slice's custom gradient produces correct gradients.""" + @test_util.run_deprecated_v1 def testGradient(self): with self.session(use_gpu=True) as sess: var = variables.Variable( @@ -827,6 +859,7 @@ class StridedSliceGradTest(test_util.TensorFlowTestCase): grad = GradSliceChecker(self, sess, var, np.array(8)) _ = grad[tuple()] + @test_util.run_deprecated_v1 def testInt64Indices(self): with self.session(use_gpu=True) as sess: a = math_ops.range(3, dtype=dtypes.float32) @@ -839,6 +872,7 @@ class StridedSliceGradTest(test_util.TensorFlowTestCase): class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): """Test varied index types and host located memory.""" + @test_util.run_deprecated_v1 def testHostVsDevice(self): with self.session(use_gpu=True) as sess: var2 = variables.Variable( @@ -853,6 +887,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): foo = array_ops.strided_slice_grad(varshape, begin, end, strides, var2) sess.run(foo) + @test_util.run_deprecated_v1 def testInt64Shape(self): with self.session(use_gpu=True) as sess: original_dy = array_ops.reshape( @@ -867,6 +902,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): original_dy) sess.run(dx) + @test_util.run_deprecated_v1 def testMixedIndexTypes(self): with self.session(use_gpu=True) as sess: original_dy = array_ops.reshape( @@ -975,6 +1011,7 @@ class StridedSliceAssignChecker(object): class SliceAssignTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testInvalidSlice(self): with self.cached_session() as sess: foo = constant_op.constant([1, 2, 3]) @@ -1012,12 +1049,15 @@ class SliceAssignTest(test_util.TensorFlowTestCase): checker2[...] = 6 # ellipsis checker2[None] = [6] # new axis + @test_util.run_deprecated_v1 def testSliceAssign(self): self.doTestSliceAssign(use_resource=False) + @test_util.run_deprecated_v1 def testSliceAssignResource(self): self.doTestSliceAssign(use_resource=True) + @test_util.run_deprecated_v1 def testUninitialized(self): with self.assertRaisesRegexp( errors.FailedPreconditionError, @@ -1036,6 +1076,7 @@ class SliceAssignTest(test_util.TensorFlowTestCase): with self.assertRaises(TypeError): v[:].assign(too_large_val) + @test_util.run_deprecated_v1 def testTypeErrorResource(self): init_val = constant_op.constant([1, 2], dtype=dtypes.int32) too_small_val = constant_op.constant([3, 4], dtype=dtypes.int8) @@ -1092,6 +1133,7 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp(ValueError, "maxlen must be scalar"): array_ops.sequence_mask([10, 20], [10, 20]) + @test_util.run_deprecated_v1 def testOneDimensionalWithMaxlen(self): with self.cached_session(): res = array_ops.sequence_mask(constant_op.constant([1, 3, 2]), 5) @@ -1101,6 +1143,7 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): [[True, False, False, False, False], [True, True, True, False, False], [True, True, False, False, False]]) + @test_util.run_deprecated_v1 def testOneDimensionalDtypeWithoutMaxlen(self): with self.cached_session(): # test dtype and default maxlen: @@ -1111,6 +1154,7 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): res.eval(), [[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]]) + @test_util.run_deprecated_v1 def testOneDimensionalWithoutMaxlen(self): with self.cached_session(): res = array_ops.sequence_mask( @@ -1139,11 +1183,13 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): [[[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]], [[1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 0.0, 0.0], [1.0, 1.0, 1.0, 0.0]]]) + @test_util.run_deprecated_v1 def testUnknownShape(self): lengths = array_ops.placeholder(dtype=dtypes.int32) res = array_ops.sequence_mask(lengths) self.assertEqual(res.shape, None) + @test_util.run_deprecated_v1 def testDtypes(self): def check_dtypes(lengths_dtype, maxlen_dtype): @@ -1166,6 +1212,7 @@ class SequenceMaskTest(test_util.TensorFlowTestCase): class ConcatSliceResourceTest(test_util.TensorFlowTestCase): @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testConcatSlice(self): r1 = test_ops.stub_resource_handle_op(container="a", shared_name="b") r2 = test_ops.stub_resource_handle_op(container="a", shared_name="c") @@ -1221,6 +1268,7 @@ class PadTest(test_util.TensorFlowTestCase): class InvertPermutationTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testInvertPermutation(self): for dtype in [dtypes.int32, dtypes.int64]: with self.cached_session(use_gpu=True): @@ -1255,12 +1303,14 @@ class UnravelIndexTest(test_util.TensorFlowTestCase): class GuaranteeConstOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testSimple(self): with self.cached_session(): a = array_ops.constant(10) guarantee_a = array_ops.guarantee_const(a) self.assertEqual(10, guarantee_a.eval()) + @test_util.run_deprecated_v1 def testVariables(self): with self.cached_session() as sess: for use_resource in [False, True]: @@ -1272,6 +1322,7 @@ class GuaranteeConstOpTest(test_util.TensorFlowTestCase): self.evaluate(variables.global_variables_initializer()) self.assertEqual(10.0, guarantee_a.eval()) + @test_util.run_deprecated_v1 def testResourceRejection(self): with self.cached_session() as sess: a = variable_scope.get_variable( @@ -1287,6 +1338,7 @@ class GuaranteeConstOpTest(test_util.TensorFlowTestCase): class SnapshotOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testInvertPermutation(self): for dtype in [dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64]: with self.cached_session(use_gpu=True): diff --git a/tensorflow/python/kernel_tests/as_string_op_test.py b/tensorflow/python/kernel_tests/as_string_op_test.py index dd4a90e5f6..287701a73e 100644 --- a/tensorflow/python/kernel_tests/as_string_op_test.py +++ b/tensorflow/python/kernel_tests/as_string_op_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -27,6 +28,7 @@ from tensorflow.python.platform import test class AsStringOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testFloat(self): float_inputs_ = [ 0, 1, -1, 0.5, 0.25, 0.125, float("INF"), float("NAN"), float("-INF") @@ -78,6 +80,7 @@ class AsStringOpTest(test.TestCase): output = string_ops.as_string(input_, fill="ab") output.eval(feed_dict={input_: float_inputs_}) + @test_util.run_deprecated_v1 def testInt(self): # Cannot use values outside -128..127 for test, because we're also # testing int8 @@ -112,6 +115,7 @@ class AsStringOpTest(test.TestCase): output = string_ops.as_string(input_, precision=0) output.eval(feed_dict={input_: int_inputs_}) + @test_util.run_deprecated_v1 def testLargeInt(self): # Cannot use values outside -128..127 for test, because we're also # testing int8 @@ -130,6 +134,7 @@ class AsStringOpTest(test.TestCase): result = output.eval(feed_dict={input_: int_inputs_}) self.assertAllEqual(s(result), ["%d" % x for x in int_inputs_]) + @test_util.run_deprecated_v1 def testHalfInt(self): s = lambda strs: [x.decode("ascii") for x in strs] @@ -140,6 +145,7 @@ class AsStringOpTest(test.TestCase): result = output.eval(feed_dict={input_: int_inputs_}) self.assertAllEqual(s(result), ["%d" % x for x in int_inputs_]) + @test_util.run_deprecated_v1 def testBool(self): bool_inputs_ = [False, True] s = lambda strs: [x.decode("ascii") for x in strs] @@ -152,6 +158,7 @@ class AsStringOpTest(test.TestCase): result = output.eval(feed_dict={input_: bool_inputs_}) self.assertAllEqual(s(result), ["false", "true"]) + @test_util.run_deprecated_v1 def testComplex(self): float_inputs_ = [ 0, 1, -1, 0.5, 0.25, 0.125, complex("INF"), complex("NAN"), diff --git a/tensorflow/python/kernel_tests/atrous_conv2d_test.py b/tensorflow/python/kernel_tests/atrous_conv2d_test.py index fefb797995..a13e325835 100644 --- a/tensorflow/python/kernel_tests/atrous_conv2d_test.py +++ b/tensorflow/python/kernel_tests/atrous_conv2d_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_impl @@ -58,6 +59,7 @@ def _upsample_filters(filters, rate): class AtrousConv2DTest(test.TestCase): + @test_util.run_deprecated_v1 def testAtrousConv2DForward(self): with self.session(use_gpu=True): # Input: [batch, height, width, input_depth] @@ -82,6 +84,7 @@ class AtrousConv2DTest(test.TestCase): self.assertAllClose( y1.eval(), self.evaluate(y2), rtol=1e-3, atol=1e-3) + @test_util.run_deprecated_v1 def testAtrousSequence(self): """Tests optimization of sequence of atrous convolutions. @@ -135,6 +138,7 @@ class AtrousConv2DTest(test.TestCase): self.assertAllClose( y1.eval(), self.evaluate(y2), rtol=1e-2, atol=1e-2) + @test_util.run_deprecated_v1 def testGradient(self): with self.session(use_gpu=True): # Input: [batch, height, width, input_depth] @@ -162,6 +166,7 @@ class AtrousConv2DTest(test.TestCase): class AtrousConv2DTransposeTest(test.TestCase): + @test_util.run_deprecated_v1 def testAtrousConv2DTransposeForward(self): with self.session(use_gpu=True): # Input: [batch, height, width, input_depth] @@ -201,6 +206,7 @@ class AtrousConv2DTransposeTest(test.TestCase): class AtrousDepthwiseConv2DTest(test.TestCase): + @test_util.run_deprecated_v1 def testAtrousDepthwiseConv2DForward(self): strides = [1, 1, 1, 1] with self.session(use_gpu=True): diff --git a/tensorflow/python/kernel_tests/barrier_ops_test.py b/tensorflow/python/kernel_tests/barrier_ops_test.py index 495bbe7b34..60fe6f0eec 100644 --- a/tensorflow/python/kernel_tests/barrier_ops_test.py +++ b/tensorflow/python/kernel_tests/barrier_ops_test.py @@ -25,6 +25,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import data_flow_ops from tensorflow.python.platform import test @@ -66,6 +67,7 @@ class BarrierTest(test.TestCase): attr { key: 'shared_name' value: { s: 'B' } } """, b.barrier_ref.op.node_def) + @test_util.run_deprecated_v1 def testInsertMany(self): with self.cached_session(): b = data_flow_ops.Barrier( @@ -90,6 +92,7 @@ class BarrierTest(test.TestCase): data_flow_ops.Barrier( (dtypes.float32, dtypes.float32), shapes=((1,), (0,)), name="B") + @test_util.run_deprecated_v1 def testInsertManyEmptyTensorUnknown(self): with self.cached_session(): b = data_flow_ops.Barrier((dtypes.float32, dtypes.float32), name="B") @@ -102,6 +105,7 @@ class BarrierTest(test.TestCase): ".*Tensors with no elements are not supported.*"): insert_0_op.run() + @test_util.run_deprecated_v1 def testTakeMany(self): with self.cached_session() as sess: b = data_flow_ops.Barrier( @@ -127,6 +131,7 @@ class BarrierTest(test.TestCase): self.assertEqual(values_0_val[idx], v0) self.assertEqual(values_1_val[idx], v1) + @test_util.run_deprecated_v1 def testTakeManySmallBatch(self): with self.cached_session() as sess: b = data_flow_ops.Barrier( @@ -191,6 +196,7 @@ class BarrierTest(test.TestCase): with self.assertRaisesOpError("is closed"): insert_1_3_op.run() + @test_util.run_deprecated_v1 def testUseBarrierWithShape(self): with self.cached_session() as sess: b = data_flow_ops.Barrier( @@ -220,6 +226,7 @@ class BarrierTest(test.TestCase): self.assertAllEqual(values_0_val[idx], v0) self.assertAllEqual(values_1_val[idx], v1) + @test_util.run_deprecated_v1 def testParallelInsertMany(self): with self.cached_session() as sess: b = data_flow_ops.Barrier(dtypes.float32, shapes=()) @@ -240,6 +247,7 @@ class BarrierTest(test.TestCase): idx = keys_val.tolist().index(k) self.assertEqual(values_val[idx], v) + @test_util.run_deprecated_v1 def testParallelTakeMany(self): with self.cached_session() as sess: b = data_flow_ops.Barrier(dtypes.float32, shapes=()) @@ -274,6 +282,7 @@ class BarrierTest(test.TestCase): self.assertItemsEqual( zip(keys, values), [(k[0], v[0]) for k, v in zip(key_vals, value_vals)]) + @test_util.run_deprecated_v1 def testBlockingTakeMany(self): with self.cached_session() as sess: b = data_flow_ops.Barrier(dtypes.float32, shapes=()) @@ -296,6 +305,7 @@ class BarrierTest(test.TestCase): insert_op.run() t.join() + @test_util.run_deprecated_v1 def testParallelInsertManyTakeMany(self): with self.cached_session() as sess: b = data_flow_ops.Barrier( @@ -375,6 +385,7 @@ class BarrierTest(test.TestCase): 2 + outer_indices_from_keys + inner_indices_from_keys)).T self.assertAllEqual(taken_i["values_1"], expected_values_1) + @test_util.run_deprecated_v1 def testClose(self): with self.cached_session() as sess: b = data_flow_ops.Barrier( @@ -433,6 +444,7 @@ class BarrierTest(test.TestCase): with self.assertRaisesOpError("is closed and has insufficient elements"): sess.run(take_t[0]) + @test_util.run_deprecated_v1 def testCancel(self): with self.cached_session() as sess: b = data_flow_ops.Barrier( @@ -495,6 +507,7 @@ class BarrierTest(test.TestCase): with self.assertRaisesOpError("is closed and has insufficient elements"): self.evaluate(take_t) + @test_util.run_deprecated_v1 def testClosedEmptyBarrierTakeManyAllowSmallBatchRaises(self): self._testClosedEmptyBarrierTakeManyAllowSmallBatchRaises(cancel=False) self._testClosedEmptyBarrierTakeManyAllowSmallBatchRaises(cancel=True) @@ -569,9 +582,11 @@ class BarrierTest(test.TestCase): sorted(taken), [0] * (num_iterations // 2) + [10] * (num_iterations // 2)) + @test_util.run_deprecated_v1 def testParallelInsertManyTakeManyCloseHalfwayThrough(self): self._testParallelInsertManyTakeManyCloseHalfwayThrough(cancel=False) + @test_util.run_deprecated_v1 def testParallelInsertManyTakeManyCancelHalfwayThrough(self): self._testParallelInsertManyTakeManyCloseHalfwayThrough(cancel=True) @@ -669,12 +684,15 @@ class BarrierTest(test.TestCase): else: self.assertEqual(taken, [10] * num_iterations) + @test_util.run_deprecated_v1 def testParallelPartialInsertManyTakeManyCloseHalfwayThrough(self): self._testParallelPartialInsertManyTakeManyCloseHalfwayThrough(cancel=False) + @test_util.run_deprecated_v1 def testParallelPartialInsertManyTakeManyCancelHalfwayThrough(self): self._testParallelPartialInsertManyTakeManyCloseHalfwayThrough(cancel=True) + @test_util.run_deprecated_v1 def testIncompatibleSharedBarrierErrors(self): with self.cached_session(): # Do component types and shapes. diff --git a/tensorflow/python/kernel_tests/basic_gpu_test.py b/tensorflow/python/kernel_tests/basic_gpu_test.py index cd33048121..1a8513d022 100644 --- a/tensorflow/python/kernel_tests/basic_gpu_test.py +++ b/tensorflow/python/kernel_tests/basic_gpu_test.py @@ -159,6 +159,7 @@ class BroadcastSimpleTest(test.TestCase): with self.cached_session(use_gpu=True) as sess: return sess.run(broadcast_gradient_args(xs, ys)) + @test_util.run_deprecated_v1 def testBroadcast(self): r0, r1 = self._GetGradientArgs([2, 3, 5], [1]) self.assertAllEqual(r0, []) @@ -219,6 +220,7 @@ class BroadcastSimpleTest(test.TestCase): self.assertShapeEqual(np_ans, out) # TODO(zhifengc/ke): make gradient checker work on GPU. + @test_util.run_deprecated_v1 def testGradient(self): x = (1 + np.linspace(0, 5, np.prod([1, 3, 2]))).astype(np.float32).reshape( [1, 3, 2]) @@ -255,6 +257,7 @@ class GpuMultiSessionMemoryTest(test_util.TensorFlowTestCase): if len(results) != 1: break + @test_util.run_deprecated_v1 def testConcurrentSessions(self): n_threads = 4 threads = [] diff --git a/tensorflow/python/kernel_tests/batch_gather_op_test.py b/tensorflow/python/kernel_tests/batch_gather_op_test.py index ad4e879131..7e0b3e1b5e 100644 --- a/tensorflow/python/kernel_tests/batch_gather_op_test.py +++ b/tensorflow/python/kernel_tests/batch_gather_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test @@ -87,6 +88,7 @@ class GatherTest(test.TestCase, parameterized.TestCase): self.assertAllEqual(np_val, gather_val) self.assertEqual(np_val.shape, gather_t.get_shape()) + @test_util.run_deprecated_v1 def testString(self): params = np.array([[b"asdf", b"zxcv"], [b"qwer", b"uiop"]]) with self.cached_session(): @@ -94,6 +96,7 @@ class GatherTest(test.TestCase, parameterized.TestCase): self.assertAllEqual([[b"qwer", b"uiop"]], array_ops.batch_gather(params, indices_tf).eval()) + @test_util.run_deprecated_v1 def testUnknownIndices(self): params = constant_op.constant([[0, 1, 2]]) indices = array_ops.placeholder(dtypes.int32, shape=[None, None]) @@ -106,6 +109,7 @@ class GatherTest(test.TestCase, parameterized.TestCase): with self.assertRaisesOpError(r"indices\[0\] = 7 is not in \[0, 2\)"): array_ops.batch_gather(params, [7]).eval() + @test_util.run_deprecated_v1 def testEmptySlices(self): with self.session(use_gpu=True): for dtype in _TEST_TYPES: diff --git a/tensorflow/python/kernel_tests/batch_scatter_ops_test.py b/tensorflow/python/kernel_tests/batch_scatter_ops_test.py index a4b461bc87..eefcdc508f 100644 --- a/tensorflow/python/kernel_tests/batch_scatter_ops_test.py +++ b/tensorflow/python/kernel_tests/batch_scatter_ops_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -73,6 +74,7 @@ class ScatterTest(test.TestCase): tf_scatter(ref, indices, updates).eval() self.assertAllClose(ref.eval(), new) + @test_util.run_deprecated_v1 def testVariableRankUpdate(self): vtypes = [np.float32, np.float64] for vtype in vtypes: @@ -80,6 +82,7 @@ class ScatterTest(test.TestCase): self._VariableRankTest( state_ops.batch_scatter_update, vtype, itype) + @test_util.run_deprecated_v1 def testBooleanScatterUpdate(self): with self.session(use_gpu=False) as session: var = variables.Variable([True, False]) @@ -93,6 +96,7 @@ class ScatterTest(test.TestCase): self.assertAllEqual([False, True], self.evaluate(var)) + @test_util.run_deprecated_v1 def testScatterOutOfRange(self): params = np.array([1, 2, 3, 4, 5, 6]).astype(np.float32) updates = np.array([-3, -4, -5]).astype(np.float32) diff --git a/tensorflow/python/kernel_tests/batchtospace_op_test.py b/tensorflow/python/kernel_tests/batchtospace_op_test.py index 03f3f64353..c422df8806 100644 --- a/tensorflow/python/kernel_tests/batchtospace_op_test.py +++ b/tensorflow/python/kernel_tests/batchtospace_op_test.py @@ -27,6 +27,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import gradient_checker @@ -50,6 +51,7 @@ class CppOpImpl(object): class BatchToSpaceDepthToSpace(test.TestCase, PythonOpImpl): # Verifies that: batch_to_space(x) = transpose(depth_to_space(transpose(x))) + @test_util.run_deprecated_v1 def testDepthToSpaceTranspose(self): x = np.arange(20 * 5 * 8 * 7, dtype=np.float32).reshape([20, 5, 8, 7]) block_size = 2 @@ -70,6 +72,7 @@ class BatchToSpaceDepthToSpaceCpp(BatchToSpaceDepthToSpace, CppOpImpl): class BatchToSpaceErrorHandlingTest(test.TestCase, PythonOpImpl): + @test_util.run_deprecated_v1 def testInputWrongDimMissingBatch(self): # The input is missing the first dimension ("batch") x_np = [[[1], [2]], [[3], [4]]] @@ -78,6 +81,7 @@ class BatchToSpaceErrorHandlingTest(test.TestCase, PythonOpImpl): with self.assertRaises(ValueError): _ = self.batch_to_space(x_np, crops, block_size) + @test_util.run_deprecated_v1 def testBlockSize0(self): # The block size is 0. x_np = [[[[1], [2]], [[3], [4]]]] @@ -87,6 +91,7 @@ class BatchToSpaceErrorHandlingTest(test.TestCase, PythonOpImpl): out_tf = self.batch_to_space(x_np, crops, block_size) out_tf.eval() + @test_util.run_deprecated_v1 def testBlockSizeOne(self): # The block size is 1. The block size needs to be > 1. x_np = [[[[1], [2]], [[3], [4]]]] @@ -96,6 +101,7 @@ class BatchToSpaceErrorHandlingTest(test.TestCase, PythonOpImpl): out_tf = self.batch_to_space(x_np, crops, block_size) out_tf.eval() + @test_util.run_deprecated_v1 def testBlockSizeLarger(self): # The block size is too large for this input. x_np = [[[[1], [2]], [[3], [4]]]] @@ -105,6 +111,7 @@ class BatchToSpaceErrorHandlingTest(test.TestCase, PythonOpImpl): out_tf = self.batch_to_space(x_np, crops, block_size) out_tf.eval() + @test_util.run_deprecated_v1 def testBlockSizeSquaredNotDivisibleBatch(self): # The block size squared does not divide the batch. x_np = [[[[1], [2], [3]], [[3], [4], [7]]]] @@ -113,6 +120,7 @@ class BatchToSpaceErrorHandlingTest(test.TestCase, PythonOpImpl): with self.assertRaises(ValueError): _ = self.batch_to_space(x_np, crops, block_size) + @test_util.run_deprecated_v1 def testUnknownShape(self): t = self.batch_to_space( array_ops.placeholder(dtypes.float32), @@ -160,28 +168,35 @@ class BatchToSpaceNDErrorHandlingTest(test.TestCase): self._testStaticShape(input_shape, block_shape, paddings, error) self._testDynamicShape(input_shape, block_shape, paddings) + @test_util.run_deprecated_v1 def testInputWrongDimMissingBatch(self): self._testShape([2, 2], [2, 2], [[0, 0], [0, 0]], ValueError) self._testShape([2, 2, 3], [2, 2, 3], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testBlockSize0(self): # The block size is 0. self._testShape([1, 2, 2, 1], [0, 1], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testBlockSizeNegative(self): self._testShape([1, 2, 2, 1], [-1, 1], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testNegativePadding(self): self._testShape([1, 2, 2], [1, 1], [[0, -1], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testCropTooLarge(self): # The amount to crop exceeds the padded size. self._testShape([1 * 2 * 2, 2, 3, 1], [2, 2], [[3, 2], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testBlockSizeSquaredNotDivisibleBatch(self): # The batch dimension is not divisible by the product of the block_shape. self._testShape([3, 1, 1, 1], [2, 3], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testUnknownShape(self): # Verify that input shape and paddings shape can be unknown. _ = array_ops.batch_to_space_nd( @@ -263,18 +278,21 @@ class BatchToSpaceGradientTest(test.TestCase, PythonOpImpl): # Don't use very large numbers as dimensions here as the result is tensor # with cartesian product of the dimensions. + @test_util.run_deprecated_v1 def testSmall(self): block_size = 2 crop_beg = 0 crop_end = 0 self._compare(1, 2, 3, 5, block_size, crop_beg, crop_end) + @test_util.run_deprecated_v1 def testSmall2(self): block_size = 2 crop_beg = 0 crop_end = 0 self._compare(2, 4, 3, 2, block_size, crop_beg, crop_end) + @test_util.run_deprecated_v1 def testSmallCrop1x1(self): block_size = 2 crop_beg = 1 @@ -316,14 +334,17 @@ class BatchToSpaceNDGradientTest(test.TestCase): # Don't use very large numbers as dimensions here as the result is tensor # with cartesian product of the dimensions. + @test_util.run_deprecated_v1 def testSmall(self): for dtype in [dtypes.int64, dtypes.int32]: self._compare([1, 2, 3, 5], [2, 2], [[0, 0], [0, 0]], dtype) + @test_util.run_deprecated_v1 def testSmall2(self): for dtype in [dtypes.int64, dtypes.int32]: self._compare([2, 4, 3, 2], [2, 2], [[0, 0], [0, 0]], dtype) + @test_util.run_deprecated_v1 def testSmallCrop1x1(self): for dtype in [dtypes.int64, dtypes.int32]: self._compare([1, 2, 3, 5], [2, 2], [[1, 1], [1, 1]], dtype) diff --git a/tensorflow/python/kernel_tests/bcast_ops_test.py b/tensorflow/python/kernel_tests/bcast_ops_test.py index 3ec820aead..ae00955ac2 100644 --- a/tensorflow/python/kernel_tests/bcast_ops_test.py +++ b/tensorflow/python/kernel_tests/bcast_ops_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops.gen_array_ops import broadcast_args from tensorflow.python.ops.gen_array_ops import broadcast_gradient_args from tensorflow.python.platform import test @@ -35,6 +36,7 @@ class BcastOpsTest(test.TestCase): with self.cached_session() as sess: return sess.run(broadcast_gradient_args(xs, ys)) + @test_util.run_deprecated_v1 def testBasic(self): r = self._GetBroadcastShape([2, 3, 5], [1]) self.assertAllEqual(r, [2, 3, 5]) @@ -66,6 +68,7 @@ class BcastOpsTest(test.TestCase): r = self._GetBroadcastShape([3, 1], [2, 1, 5]) self.assertAllEqual(r, [2, 3, 5]) + @test_util.run_deprecated_v1 def testBasicGradient(self): r0, r1 = self._GetGradientArgs([2, 3, 5], [1]) self.assertAllEqual(r0, []) @@ -107,6 +110,7 @@ class BcastOpsTest(test.TestCase): self.assertAllEqual(r0, [0, 2]) self.assertAllEqual(r1, [1]) + @test_util.run_deprecated_v1 def testZeroDims(self): r = self._GetBroadcastShape([2, 0, 3, 0, 5], [3, 0, 5]) self.assertAllEqual(r, [2, 0, 3, 0, 5]) @@ -120,6 +124,7 @@ class BcastOpsTest(test.TestCase): r = self._GetBroadcastShape([3, 1, 5], [2, 0, 3, 0, 5]) self.assertAllEqual(r, [2, 0, 3, 0, 5]) + @test_util.run_deprecated_v1 def testZeroDimsGradient(self): r0, r1 = self._GetGradientArgs([2, 0, 3, 0, 5], [3, 0, 5]) self.assertAllEqual(r0, []) @@ -137,6 +142,7 @@ class BcastOpsTest(test.TestCase): self.assertAllEqual(r0, [0, 1, 3]) self.assertAllEqual(r1, []) + @test_util.run_deprecated_v1 def testDataTypes(self): for dtype in [dtypes.int32, dtypes.int64]: r = self._GetBroadcastShape( diff --git a/tensorflow/python/kernel_tests/betainc_op_test.py b/tensorflow/python/kernel_tests/betainc_op_test.py index 5d7446042e..9dc34a6062 100644 --- a/tensorflow/python/kernel_tests/betainc_op_test.py +++ b/tensorflow/python/kernel_tests/betainc_op_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -109,36 +110,42 @@ class BetaincTest(test.TestCase): except ImportError as e: tf_logging.warn("Cannot test special functions: %s" % str(e)) + @test_util.run_deprecated_v1 def testBetaIncFloat(self): a_s = np.abs(np.random.randn(10, 10) * 30) # in (0, infty) b_s = np.abs(np.random.randn(10, 10) * 30) # in (0, infty) x_s = np.random.rand(10, 10) # in (0, 1) self._testBetaInc(a_s, b_s, x_s, dtypes.float32) + @test_util.run_deprecated_v1 def testBetaIncDouble(self): a_s = np.abs(np.random.randn(10, 10) * 30) # in (0, infty) b_s = np.abs(np.random.randn(10, 10) * 30) # in (0, infty) x_s = np.random.rand(10, 10) # in (0, 1) self._testBetaInc(a_s, b_s, x_s, dtypes.float64) + @test_util.run_deprecated_v1 def testBetaIncDoubleVeryLargeValues(self): a_s = np.abs(np.random.randn(10, 10) * 1e15) # in (0, infty) b_s = np.abs(np.random.randn(10, 10) * 1e15) # in (0, infty) x_s = np.random.rand(10, 10) # in (0, 1) self._testBetaInc(a_s, b_s, x_s, dtypes.float64) + @test_util.run_deprecated_v1 def testBetaIncDoubleVerySmallValues(self): a_s = np.abs(np.random.randn(10, 10) * 1e-16) # in (0, infty) b_s = np.abs(np.random.randn(10, 10) * 1e-16) # in (0, infty) x_s = np.random.rand(10, 10) # in (0, 1) self._testBetaInc(a_s, b_s, x_s, dtypes.float64) + @test_util.run_deprecated_v1 def testBetaIncFloatVerySmallValues(self): a_s = np.abs(np.random.randn(10, 10) * 1e-8) # in (0, infty) b_s = np.abs(np.random.randn(10, 10) * 1e-8) # in (0, infty) x_s = np.random.rand(10, 10) # in (0, 1) self._testBetaInc(a_s, b_s, x_s, dtypes.float32) + @test_util.run_deprecated_v1 def testBetaIncFpropAndBpropAreNeverNAN(self): with self.cached_session() as sess: space = np.logspace(-8, 5).tolist() @@ -159,6 +166,7 @@ class BetaincTest(test.TestCase): self.assertAllEqual(np.zeros_like(grads_x).astype(np.bool), np.isnan(grads_x)) + @test_util.run_deprecated_v1 def testBetaIncGrads(self): err_tolerance = 1e-3 with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/bias_op_test.py b/tensorflow/python/kernel_tests/bias_op_test.py index 749d6a791e..66f442dbdd 100644 --- a/tensorflow/python/kernel_tests/bias_op_test.py +++ b/tensorflow/python/kernel_tests/bias_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -89,10 +90,12 @@ class BiasAddTest(test.TestCase): self._testBiasNCHW(np_inputs, np_bias, use_gpu=True) + @test_util.run_deprecated_v1 def testInputDims(self): with self.assertRaises(ValueError): nn_ops.bias_add([1, 2], [1]) + @test_util.run_deprecated_v1 def testBiasVec(self): with self.assertRaises(ValueError): nn_ops.bias_add( @@ -101,6 +104,7 @@ class BiasAddTest(test.TestCase): array_ops.reshape( [1, 2], shape=[1, 2])) + @test_util.run_deprecated_v1 def testBiasInputsMatch(self): with self.assertRaises(ValueError): nn_ops.bias_add( @@ -109,23 +113,27 @@ class BiasAddTest(test.TestCase): array_ops.reshape( [1], shape=[1])) + @test_util.run_deprecated_v1 def testIntTypes(self): for t in [np.int8, np.int16, np.int32, np.int64]: self._testAll( np.array([[10, 20, 30], [40, 50, 60]]).astype(t), np.array([1, 2, 3]).astype(t)) + @test_util.run_deprecated_v1 def testFloatTypes(self): for t in [np.float16, np.float32, np.float64]: self._testAll( np.random.rand(4, 3, 3).astype(t), np.random.rand(3).astype(t)) + @test_util.run_deprecated_v1 def test4DFloatTypes(self): for t in [np.float16, np.float32, np.float64]: self._testAll( np.random.rand(4, 3, 2, 3).astype(t), np.random.rand(3).astype(t)) + @test_util.run_deprecated_v1 def test5DFloatTypes(self): for t in [np.float16, np.float32, np.float64]: self._testAll( @@ -187,6 +195,7 @@ class BiasAddTest(test.TestCase): self.assertAllClose(bias_jacob_t, bias_jacob_n, threshold, threshold) self.assertAllClose(grad_jacob_t, grad_jacob_n, threshold, threshold) + @test_util.run_deprecated_v1 def testGradientTensor(self): # TODO(yongtang): BiasAddGrad with NCHW only works 4D. Reenable once # all dimensions are supported. @@ -198,6 +207,7 @@ class BiasAddTest(test.TestCase): bias = np.array([1.3, 2.4], dtype=dtype.as_numpy_dtype) self._testGradient(np_input, bias, dtype, data_format, use_gpu) + @test_util.run_deprecated_v1 def testGradientTensor4D(self): # BiasAddGrad with NCHW support 4D so all are enabled. for (data_format, use_gpu) in [("NHWC", False), ("NHWC", True), @@ -209,11 +219,13 @@ class BiasAddTest(test.TestCase): bias = np.array([1.3, 2.4], dtype=dtype.as_numpy_dtype) self._testGradient(np_input, bias, dtype, data_format, use_gpu) + @test_util.run_deprecated_v1 def testEmpty(self): np.random.seed(7) for shape in (0, 0), (2, 0), (0, 2), (4, 3, 0), (4, 0, 3), (0, 4, 3): self._testAll(np.random.randn(*shape), np.random.randn(shape[-1])) + @test_util.run_deprecated_v1 def testEmptyGradient(self): # TODO(yongtang): BiasAddGrad with NCHW only works 4D. Reenable once # all dimensions are supported. diff --git a/tensorflow/python/kernel_tests/bincount_op_test.py b/tensorflow/python/kernel_tests/bincount_op_test.py index 49eb835847..d064d736cf 100644 --- a/tensorflow/python/kernel_tests/bincount_op_test.py +++ b/tensorflow/python/kernel_tests/bincount_op_test.py @@ -30,6 +30,7 @@ from tensorflow.python.platform import googletest class BincountTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def test_empty(self): with self.session(use_gpu=True): self.assertAllEqual( @@ -43,6 +44,7 @@ class BincountTest(test_util.TensorFlowTestCase): math_ops.bincount([], minlength=3, dtype=np.float64).eval().dtype, np.float64) + @test_util.run_deprecated_v1 def test_values(self): with self.session(use_gpu=True): self.assertAllEqual( @@ -58,12 +60,14 @@ class BincountTest(test_util.TensorFlowTestCase): self.assertAllEqual( math_ops.bincount(np.arange(10000)).eval(), np.ones(10000)) + @test_util.run_deprecated_v1 def test_maxlength(self): with self.session(use_gpu=True): self.assertAllEqual(math_ops.bincount([5], maxlength=3).eval(), [0, 0, 0]) self.assertAllEqual(math_ops.bincount([1], maxlength=3).eval(), [0, 1]) self.assertAllEqual(math_ops.bincount([], maxlength=3).eval(), []) + @test_util.run_deprecated_v1 def test_random_with_weights(self): num_samples = 10000 with self.session(use_gpu=True): @@ -77,6 +81,7 @@ class BincountTest(test_util.TensorFlowTestCase): self.assertAllClose( math_ops.bincount(arr, weights).eval(), np.bincount(arr, weights)) + @test_util.run_deprecated_v1 def test_random_without_weights(self): num_samples = 10000 with self.session(use_gpu=True): @@ -87,6 +92,7 @@ class BincountTest(test_util.TensorFlowTestCase): self.assertAllClose( math_ops.bincount(arr, None).eval(), np.bincount(arr, weights)) + @test_util.run_deprecated_v1 def test_zero_weights(self): with self.session(use_gpu=True): self.assertAllEqual( @@ -99,6 +105,7 @@ class BincountTest(test_util.TensorFlowTestCase): with self.assertRaises(errors.InvalidArgumentError): math_ops.bincount([1, 2, 3, -1, 6, 8]).eval() + @test_util.run_deprecated_v1 def test_shape_function(self): # size must be scalar. with self.assertRaisesRegexp( diff --git a/tensorflow/python/kernel_tests/bitcast_op_test.py b/tensorflow/python/kernel_tests/bitcast_op_test.py index 5ceffcfeda..b4f9a21a89 100644 --- a/tensorflow/python/kernel_tests/bitcast_op_test.py +++ b/tensorflow/python/kernel_tests/bitcast_op_test.py @@ -60,6 +60,7 @@ class BitcastTest(test.TestCase): shape = [3, 4] self._testBitcast(x, dtypes.int64, shape) + @test_util.run_deprecated_v1 def testErrors(self): x = np.zeros([1, 1], np.int8) datatype = dtypes.int32 @@ -72,6 +73,7 @@ class BitcastTest(test.TestCase): shape = [4] self._testBitcast(x, datatype, shape) + @test_util.run_deprecated_v1 def testUnknown(self): x = array_ops.placeholder(dtypes.float32) datatype = dtypes.int8 diff --git a/tensorflow/python/kernel_tests/boosted_trees/prediction_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/prediction_ops_test.py index 7cdc67f83f..6b04e8abf4 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/prediction_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/prediction_ops_test.py @@ -28,6 +28,7 @@ from tensorflow.python.platform import googletest class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): """Tests prediction ops for training.""" + @test_util.run_deprecated_v1 def testCachedPredictionOnEmptyEnsemble(self): """Tests that prediction on a dummy ensemble does not fail.""" with self.cached_session() as session: @@ -61,6 +62,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(cached_node_ids, new_node_ids) self.assertAllClose([[0], [0]], logits_updates) + @test_util.run_deprecated_v1 def testNoCachedPredictionButTreeExists(self): """Tests that predictions are updated once trees are added.""" with self.cached_session() as session: @@ -127,6 +129,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): self.assertAllClose([2, 1], new_node_ids) self.assertAllClose([[0.1 * 8.79], [0.1 * 1.14]], logits_updates) + @test_util.run_deprecated_v1 def testCachedPredictionIsCurrent(self): """Tests that prediction based on previous node in the tree works.""" with self.cached_session() as session: @@ -199,6 +202,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(cached_node_ids, new_node_ids) self.assertAllClose([[0], [0]], logits_updates) + @test_util.run_deprecated_v1 def testCachedPredictionFromTheSameTree(self): """Tests that prediction based on previous node in the tree works.""" with self.cached_session() as session: @@ -313,6 +317,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): # 1.65 and -3.875, and then multiply them by 0.1 (lr) self.assertAllClose([[0.1 * 1.65], [0.1 * -3.875]], logits_updates) + @test_util.run_deprecated_v1 def testCachedPredictionFromPreviousTree(self): """Tests the predictions work when we have cache from previous trees.""" with self.cached_session() as session: @@ -445,6 +450,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): # change= 0.1(1.14+7.0-7.0) self.assertAllClose([[1], [0.114]], logits_updates) + @test_util.run_deprecated_v1 def testCategoricalSplits(self): """Tests the training prediction work for categorical splits.""" with self.cached_session() as session: @@ -517,6 +523,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): self.assertAllClose([3, 4, 2], new_node_ids) self.assertAllClose([[5.], [6.], [7.]], logits_updates) + @test_util.run_deprecated_v1 def testCachedPredictionFromTheSameTreeWithPostPrunedNodes(self): """Tests that prediction based on previous node in the tree works.""" with self.cached_session() as session: @@ -647,6 +654,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): self.assertAllClose([[0.01], [0.01], [0.0553], [0.0783], [0.01], [0.01]], logits_updates + cached_values) + @test_util.run_deprecated_v1 def testCachedPredictionFromThePreviousTreeWithPostPrunedNodes(self): """Tests that prediction based on previous node in the tree works.""" with self.cached_session() as session: @@ -792,6 +800,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): [root + 0.0783], [root + 0.01], [root + 0.01]], logits_updates + cached_values) + @test_util.run_deprecated_v1 def testCachedPredictionTheWholeTreeWasPruned(self): """Tests that prediction based on previous node in the tree works.""" with self.cached_session() as session: @@ -864,6 +873,7 @@ class TrainingPredictionOpsTest(test_util.TensorFlowTestCase): class PredictionOpsTest(test_util.TensorFlowTestCase): """Tests prediction ops for inference.""" + @test_util.run_deprecated_v1 def testPredictionOnEmptyEnsemble(self): """Tests that prediction on a empty ensemble does not fail.""" with self.cached_session() as session: @@ -886,6 +896,7 @@ class PredictionOpsTest(test_util.TensorFlowTestCase): logits = session.run(predict_op) self.assertAllClose(expected_logits, logits) + @test_util.run_deprecated_v1 def testPredictionMultipleTree(self): """Tests the predictions work when we have multiple trees.""" with self.cached_session() as session: @@ -996,6 +1007,7 @@ class PredictionOpsTest(test_util.TensorFlowTestCase): logits = session.run(predict_op) self.assertAllClose(expected_logits, logits) + @test_util.run_deprecated_v1 def testCategoricalSplits(self): """Tests the predictions work for categorical splits.""" with self.cached_session() as session: @@ -1062,6 +1074,7 @@ class PredictionOpsTest(test_util.TensorFlowTestCase): class FeatureContribsOpsTest(test_util.TensorFlowTestCase): """Tests feature contribs ops for model understanding.""" + @test_util.run_deprecated_v1 def testContribsForOnlyABiasNode(self): """Tests case when, after training, only left with a bias node. @@ -1122,6 +1135,7 @@ class FeatureContribsOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(feature_ids, expected_feature_ids) self.assertAllClose(logits_paths, expected_logits_paths) + @test_util.run_deprecated_v1 def testContribsMultipleTreeWhenFirstTreeIsABiasNode(self): """Tests case when, after training, first tree contains only a bias node.""" with self.cached_session() as session: @@ -1219,6 +1233,7 @@ class FeatureContribsOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(feature_ids, expected_feature_ids) self.assertAllClose(logits_paths, expected_logits_paths) + @test_util.run_deprecated_v1 def testContribsMultipleTree(self): """Tests that the contribs work when we have multiple trees.""" with self.cached_session() as session: diff --git a/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py index 1a7b1a7e90..390672febe 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py @@ -82,6 +82,7 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): self.max_elements = 1 << 16 self.num_quantiles = constant_op.constant(3, dtype=dtypes.int64) + @test_util.run_deprecated_v1 def testBasicQuantileBucketsSingleResource(self): with self.cached_session() as sess: quantile_accumulator_handle = self.create_resource("floats", self.eps, @@ -106,6 +107,7 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(self._feature_0_quantiles, quantiles[0].eval()) self.assertAllClose(self._feature_1_quantiles, quantiles[1].eval()) + @test_util.run_deprecated_v1 def testBasicQuantileBucketsMultipleResources(self): with self.cached_session() as sess: quantile_accumulator_handle_0 = self.create_resource("float_0", self.eps, @@ -140,6 +142,7 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(self._feature_0_quantiles, quantiles[0].eval()) self.assertAllClose(self._feature_1_quantiles, quantiles[1].eval()) + @test_util.run_deprecated_v1 def testSaveRestoreAfterFlush(self): save_dir = os.path.join(self.get_temp_dir(), "save_restore") save_path = os.path.join(tempfile.mkdtemp(prefix=save_dir), "hash") @@ -172,6 +175,7 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): self.assertAllClose(self._feature_0_boundaries, buckets[0].eval()) self.assertAllClose(self._feature_1_boundaries, buckets[1].eval()) + @test_util.run_deprecated_v1 def testSaveRestoreBeforeFlush(self): save_dir = os.path.join(self.get_temp_dir(), "save_restore") save_path = os.path.join(tempfile.mkdtemp(prefix=save_dir), "hash") diff --git a/tensorflow/python/kernel_tests/boosted_trees/resource_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/resource_ops_test.py index 493cad80f3..0a34277bbd 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/resource_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/resource_ops_test.py @@ -30,6 +30,7 @@ from tensorflow.python.platform import googletest class ResourceOpsTest(test_util.TensorFlowTestCase): """Tests resource_ops.""" + @test_util.run_deprecated_v1 def testCreate(self): with self.cached_session(): ensemble = boosted_trees_ops.TreeEnsemble('ensemble') @@ -43,6 +44,7 @@ class ResourceOpsTest(test_util.TensorFlowTestCase): self.assertEqual(0, self.evaluate(num_attempted_layers)) self.assertAllEqual([0, 1], self.evaluate(nodes_range)) + @test_util.run_deprecated_v1 def testCreateWithProto(self): with self.cached_session(): ensemble_proto = boosted_trees_pb2.TreeEnsemble() @@ -160,6 +162,7 @@ class ResourceOpsTest(test_util.TensorFlowTestCase): self.assertEqual(6, self.evaluate(num_attempted_layers)) self.assertAllEqual([16, 19], self.evaluate(nodes_range)) + @test_util.run_deprecated_v1 def testSerializeDeserialize(self): with self.cached_session(): # Initialize. diff --git a/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py index e1036b0b75..e2e23486b5 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py @@ -327,6 +327,7 @@ class StatsOpsTest(test_util.TensorFlowTestCase): max_splits=max_splits) self.assertAllEqual([[], []], self.evaluate(node_ids_list)) + @test_util.run_deprecated_v1 def testMakeStatsSummarySimple(self): """Simple test for MakeStatsSummary.""" with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/boosted_trees/training_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/training_ops_test.py index ea022820e4..afc0564fc5 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/training_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/training_ops_test.py @@ -30,6 +30,7 @@ from tensorflow.python.platform import googletest class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): """Tests for growing tree ensemble from split candidates.""" + @test_util.run_deprecated_v1 def testGrowWithEmptyEnsemble(self): """Test growing an empty ensemble.""" with self.cached_session() as session: @@ -139,6 +140,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testBiasCenteringOnEmptyEnsemble(self): """Test growing with bias centering on an empty ensemble.""" with self.cached_session() as session: @@ -182,6 +184,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testGrowExistingEnsembleTreeNotFinalized(self): """Test growing an existing ensemble with the last tree not finalized.""" with self.cached_session() as session: @@ -366,6 +369,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testGrowExistingEnsembleTreeFinalized(self): """Test growing an existing ensemble with the last tree finalized.""" with self.cached_session() as session: @@ -515,6 +519,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testPrePruning(self): """Test growing an existing ensemble with pre-pruning.""" with self.cached_session() as session: @@ -671,6 +676,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testMetadataWhenCantSplitDueToEmptySplits(self): """Test that the metadata is updated even though we can't split.""" with self.cached_session() as session: @@ -782,6 +788,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testMetadataWhenCantSplitDuePrePruning(self): """Test metadata is updated correctly when no split due to prepruning.""" with self.cached_session() as session: @@ -917,6 +924,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 1) self.assertProtoEquals(expected_result, tree_ensemble) + @test_util.run_deprecated_v1 def testPostPruningOfSomeNodes(self): """Test growing an ensemble with post-pruning.""" with self.cached_session() as session: @@ -1251,6 +1259,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): self.assertEqual(new_stamp, 3) self.assertProtoEquals(expected_result, res_ensemble) + @test_util.run_deprecated_v1 def testPostPruningOfAllNodes(self): """Test growing an ensemble with post-pruning, with all nodes are pruned.""" with self.cached_session() as session: @@ -1434,6 +1443,7 @@ class UpdateTreeEnsembleOpTest(test_util.TensorFlowTestCase): } """, res_ensemble) + @test_util.run_deprecated_v1 def testPostPruningChangesNothing(self): """Test growing an ensemble with post-pruning with all gains >0.""" with self.cached_session() as session: diff --git a/tensorflow/python/kernel_tests/broadcast_to_ops_test.py b/tensorflow/python/kernel_tests/broadcast_to_ops_test.py index 233c166405..b9eb2391b4 100644 --- a/tensorflow/python/kernel_tests/broadcast_to_ops_test.py +++ b/tensorflow/python/kernel_tests/broadcast_to_ops_test.py @@ -29,6 +29,7 @@ from tensorflow.python.platform import test as test_lib class BroadcastToTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBroadcastToBasic(self): for dtype in [np.uint8, np.uint16, np.int8, np.int16, np.int32, np.int64]: with self.session(use_gpu=True): @@ -37,6 +38,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): v_np = np.broadcast_to(x, [3, 3]) self.assertAllEqual(v_tf.eval(), v_np) + @test_util.run_deprecated_v1 def testBroadcastToString(self): with self.session(use_gpu=True): x = np.array([b"1", b"2", b"3"]) @@ -44,6 +46,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): v_np = np.broadcast_to(x, [3, 3]) self.assertAllEqual(v_tf.eval(), v_np) + @test_util.run_deprecated_v1 def testBroadcastToBool(self): with self.session(use_gpu=True): x = np.array([True, False, True], dtype=np.bool) @@ -51,6 +54,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): v_np = np.broadcast_to(x, [3, 3]) self.assertAllEqual(v_tf.eval(), v_np) + @test_util.run_deprecated_v1 def testBroadcastToShape(self): for input_dim in range(1, 6): for output_dim in range(input_dim, 6): @@ -62,6 +66,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): v_np = np.broadcast_to(x, output_shape) self.assertAllEqual(v_tf.eval(), v_np) + @test_util.run_deprecated_v1 def testBroadcastToScalar(self): with self.session(use_gpu=True): x = np.array(1, dtype=np.int32) @@ -69,6 +74,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): v_np = np.broadcast_to(x, [3, 3]) self.assertAllEqual(v_tf.eval(), v_np) + @test_util.run_deprecated_v1 def testBroadcastScalarToNonScalar(self): with self.session(use_gpu=True): x = np.array(1.0, dtype=np.float) @@ -76,6 +82,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): v_np = np.broadcast_to(x, [2, 3, 4]) self.assertAllEqual(v_tf.eval(), v_np) + @test_util.run_deprecated_v1 def testBroadcastToShapeTypeAndInference(self): for dtype in [dtypes.int32, dtypes.int64]: with self.cached_session(use_gpu=True): @@ -89,6 +96,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): # check shape inference when shape input is constant self.assertAllEqual(shape, v_np.shape) + @test_util.run_deprecated_v1 def testGradientForScalar(self): x = constant_op.constant(1, dtype=dtypes.float32) v = array_ops.broadcast_to(x, [2, 4, 3]) @@ -98,6 +106,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): out.get_shape()) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientWithSameRank(self): x = constant_op.constant(np.reshape(np.arange(6), (2, 1, 3)), dtype=dtypes.float32) @@ -108,6 +117,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): out, out.get_shape()) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientWithIncreasingRank(self): x = constant_op.constant([[1], [2]], dtype=dtypes.float32) @@ -118,6 +128,7 @@ class BroadcastToTest(test_util.TensorFlowTestCase): out, out.get_shape()) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientWithBroadcastAllDimensions(self): x = constant_op.constant([[1, 2, 3], [4, 5, 6]], dtype=dtypes.float32) v = array_ops.broadcast_to(x, [5, 4, 6]) diff --git a/tensorflow/python/kernel_tests/bucketize_op_test.py b/tensorflow/python/kernel_tests/bucketize_op_test.py index f40ca82527..95df694370 100644 --- a/tensorflow/python/kernel_tests/bucketize_op_test.py +++ b/tensorflow/python/kernel_tests/bucketize_op_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -50,6 +51,7 @@ class BucketizationOpTest(test.TestCase): with self.session(use_gpu=True) as sess: self.assertAllEqual(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def testInvalidBoundariesOrder(self): op = math_ops._bucketize( constant_op.constant([-5, 0]), boundaries=[0, 8, 3, 11]) diff --git a/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py b/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py index 031accee55..fa6eb5c968 100644 --- a/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py +++ b/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import candidate_sampling_ops from tensorflow.python.ops import math_ops @@ -37,6 +38,7 @@ class RangeSamplerOpsTest(test.TestCase): TRUE_LABELS = [[1, 2], [0, 4], [3, 3]] + @test_util.run_deprecated_v1 def testTrueCandidates(self): with self.cached_session() as sess: indices = constant_op.constant([0, 0, 1, 1, 2, 2]) @@ -106,6 +108,7 @@ class RangeSamplerOpsTest(test.TestCase): self.assertTrue(id_ in self.TRUE_LABELS[index]) self.assertLess(weight, -1.0e37) + @test_util.run_deprecated_v1 def testSeed(self): def draw(seed): diff --git a/tensorflow/python/kernel_tests/cast_op_test.py b/tensorflow/python/kernel_tests/cast_op_test.py index 2cfe084d95..b3187e1637 100644 --- a/tensorflow/python/kernel_tests/cast_op_test.py +++ b/tensorflow/python/kernel_tests/cast_op_test.py @@ -25,6 +25,7 @@ import platform from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops @@ -90,10 +91,12 @@ class CastOpTest(test.TestCase): if x.dtype == np.float32 or x.dtype == np.float64: self._testTypes(x, use_gpu=True) + @test_util.run_deprecated_v1 def testBasic(self): self._testAll(np.arange(-10, 10).reshape(2, 10)) self._testAll(np.linspace(-10, 10, 17)) + @test_util.run_deprecated_v1 def testSmallValues(self): f4 = np.finfo(np.float32) f8 = np.finfo(np.float64) @@ -112,6 +115,7 @@ class CastOpTest(test.TestCase): b = math_ops.cast(math_ops.cast(a, dtypes.bfloat16), dtypes.float32) self.assertAllClose(a, self.evaluate(b), rtol=1 / 128.) + @test_util.run_deprecated_v1 def testRandom(self): self._testAll(np.random.normal(0, 10, 210).reshape([2, 3, 5, 7])) self._testAll(np.random.normal(0, 1e6, 210).reshape([2, 3, 5, 7])) @@ -124,6 +128,7 @@ class CastOpTest(test.TestCase): self._cast( x, dst_dtype, use_gpu=use_gpu), dst_dtype(expected)) + @test_util.run_deprecated_v1 def testIntToFloatBoundary(self): i4 = np.iinfo(np.int32) i8 = np.iinfo(np.int64) @@ -138,6 +143,7 @@ class CastOpTest(test.TestCase): self._compare(i8.max, np.float64, i8.max, False) # NOTE: GPU does not support int32/int64 for casting. + @test_util.run_deprecated_v1 def testInfNan(self): i4 = np.iinfo(np.int32) i8 = np.iinfo(np.int64) @@ -181,6 +187,7 @@ class CastOpTest(test.TestCase): def testNotImplemented(self): self._OpError(np.arange(0, 10), dtypes.string, "Cast.*int64.*string.*") + @test_util.run_deprecated_v1 def testCastToTypeOfVariable(self): with self.cached_session() as sess: x = variables.Variable(5, dtype=dtypes.float32) @@ -189,6 +196,7 @@ class CastOpTest(test.TestCase): variables.global_variables_initializer().run() self.assertEqual(1.0, self.evaluate(cast)) + @test_util.run_deprecated_v1 def testGradients(self): t = [dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128] for src_t in t: @@ -203,6 +211,7 @@ class CastOpTest(test.TestCase): class SparseTensorCastTest(test.TestCase): + @test_util.run_deprecated_v1 def testCast(self): indices = constant_op.constant([[0], [1], [2]], dtypes.int64) values = constant_op.constant(np.array([1, 2, 3], np.int64)) diff --git a/tensorflow/python/kernel_tests/check_ops_test.py b/tensorflow/python/kernel_tests/check_ops_test.py index 15124a19a2..95bac85027 100644 --- a/tensorflow/python/kernel_tests/check_ops_test.py +++ b/tensorflow/python/kernel_tests/check_ops_test.py @@ -173,6 +173,7 @@ class AssertEqualTest(test.TestCase): assert x is None @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_greater(self): # Static check static_small = constant_op.constant([1, 2], name="small") @@ -180,6 +181,7 @@ class AssertEqualTest(test.TestCase): with self.assertRaisesRegexp(errors.InvalidArgumentError, "fail"): check_ops.assert_equal(static_big, static_small, message="fail") + @test_util.run_deprecated_v1 def test_raises_when_greater_dynamic(self): with self.cached_session(): small = array_ops.placeholder(dtypes.int32, name="small") @@ -251,6 +253,7 @@ First 2 elements of y: summarize=2) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_less(self): # Static check static_small = constant_op.constant([3, 1], name="small") @@ -258,6 +261,7 @@ First 2 elements of y: with self.assertRaisesRegexp(errors.InvalidArgumentError, "fail"): check_ops.assert_equal(static_big, static_small, message="fail") + @test_util.run_deprecated_v1 def test_raises_when_less_dynamic(self): with self.cached_session(): small = array_ops.placeholder(dtypes.int32, name="small") @@ -317,6 +321,7 @@ class AssertNoneEqualTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_equal(self): small = constant_op.constant([3, 1], name="small") with self.assertRaisesOpError("x != y did not hold"): @@ -506,6 +511,7 @@ class AssertAllCloseTest(test.TestCase): class AssertLessTest(test.TestCase): @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_equal(self): small = constant_op.constant([1, 2], name="small") with self.assertRaisesOpError("failure message.*\n*.* x < y did not hold"): @@ -516,6 +522,7 @@ class AssertLessTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_greater(self): small = constant_op.constant([1, 2], name="small") big = constant_op.constant([3, 4], name="big") @@ -582,6 +589,7 @@ class AssertLessEqualTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_greater(self): small = constant_op.constant([1, 2], name="small") big = constant_op.constant([3, 4], name="big") @@ -637,6 +645,7 @@ class AssertLessEqualTest(test.TestCase): class AssertGreaterTest(test.TestCase): @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_equal(self): small = constant_op.constant([1, 2], name="small") with self.assertRaisesOpError("fail"): @@ -647,6 +656,7 @@ class AssertGreaterTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_less(self): small = constant_op.constant([1, 2], name="small") big = constant_op.constant([3, 4], name="big") @@ -706,6 +716,7 @@ class AssertGreaterEqualTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_less(self): small = constant_op.constant([1, 2], name="small") big = constant_op.constant([3, 4], name="big") @@ -770,6 +781,7 @@ class AssertNegativeTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_positive(self): doug = constant_op.constant([1, 2], name="doug") with self.assertRaisesOpError("fail"): @@ -780,6 +792,7 @@ class AssertNegativeTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_zero(self): claire = constant_op.constant([0], name="claire") with self.assertRaisesOpError("x < 0 did not hold"): @@ -802,6 +815,7 @@ class AssertNegativeTest(test.TestCase): class AssertPositiveTest(test.TestCase): @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_negative(self): freddie = constant_op.constant([-1, -2], name="freddie") with self.assertRaisesOpError("fail"): @@ -819,6 +833,7 @@ class AssertPositiveTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_zero(self): meechum = constant_op.constant([0], name="meechum") with self.assertRaisesOpError("x > 0 did not hold"): @@ -841,26 +856,31 @@ class AssertPositiveTest(test.TestCase): class EnsureShapeTest(test.TestCase): # Static shape inference + @test_util.run_deprecated_v1 def testStaticShape(self): placeholder = array_ops.placeholder(dtypes.int32) ensure_shape_op = check_ops.ensure_shape(placeholder, (3, 3, 3)) self.assertEqual(ensure_shape_op.get_shape(), (3, 3, 3)) + @test_util.run_deprecated_v1 def testStaticShape_MergesShapes(self): placeholder = array_ops.placeholder(dtypes.int32, shape=(None, None, 3)) ensure_shape_op = check_ops.ensure_shape(placeholder, (5, 4, None)) self.assertEqual(ensure_shape_op.get_shape(), (5, 4, 3)) + @test_util.run_deprecated_v1 def testStaticShape_RaisesErrorWhenRankIncompatible(self): placeholder = array_ops.placeholder(dtypes.int32, shape=(None, None, 3)) with self.assertRaises(ValueError): check_ops.ensure_shape(placeholder, (2, 3)) + @test_util.run_deprecated_v1 def testStaticShape_RaisesErrorWhenDimIncompatible(self): placeholder = array_ops.placeholder(dtypes.int32, shape=(None, None, 3)) with self.assertRaises(ValueError): check_ops.ensure_shape(placeholder, (2, 2, 4)) + @test_util.run_deprecated_v1 def testStaticShape_CanSetUnknownShape(self): placeholder = array_ops.placeholder(dtypes.int32) derived = placeholder / 3 @@ -868,6 +888,7 @@ class EnsureShapeTest(test.TestCase): self.assertEqual(ensure_shape_op.get_shape(), None) # Dynamic shape check + @test_util.run_deprecated_v1 def testEnsuresDynamicShape_RaisesError(self): placeholder = array_ops.placeholder(dtypes.int32) derived = math_ops.divide(placeholder, 3, name="MyDivide") @@ -880,6 +901,7 @@ class EnsureShapeTest(test.TestCase): r"expected shape \[3,3,3\]."): sess.run(derived, feed_dict={placeholder: feed_val}) + @test_util.run_deprecated_v1 def testEnsuresDynamicShape_RaisesErrorDimUnknown(self): placeholder = array_ops.placeholder(dtypes.int32) derived = placeholder / 3 @@ -892,6 +914,7 @@ class EnsureShapeTest(test.TestCase): r"expected shape \[\?,\?,3\]."): sess.run(derived, feed_dict={placeholder: feed_val}) + @test_util.run_deprecated_v1 def testEnsuresDynamicShape(self): placeholder = array_ops.placeholder(dtypes.int32) derived = placeholder / 3 @@ -900,6 +923,7 @@ class EnsureShapeTest(test.TestCase): with self.cached_session() as sess: sess.run(derived, feed_dict={placeholder: feed_val}) + @test_util.run_deprecated_v1 def testEnsuresDynamicShape_WithUnknownDims(self): placeholder = array_ops.placeholder(dtypes.int32) derived = placeholder / 3 @@ -908,6 +932,7 @@ class EnsureShapeTest(test.TestCase): with self.cached_session() as sess: sess.run(derived, feed_dict={placeholder: feed_val}) + @test_util.run_deprecated_v1 def testGradient(self): placeholder = array_ops.placeholder(dtypes.float32) derived = check_ops.ensure_shape(placeholder, (None, None)) @@ -1003,6 +1028,7 @@ class AssertRankTest(test.TestCase): tensor, desired_rank, message="fail")]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_zero_tensor_raises_if_rank_too_small_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1021,6 +1047,7 @@ class AssertRankTest(test.TestCase): [check_ops.assert_rank(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_zero_tensor_doesnt_raise_if_rank_just_right_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1038,6 +1065,7 @@ class AssertRankTest(test.TestCase): [check_ops.assert_rank(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_raises_if_rank_too_large_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1055,6 +1083,7 @@ class AssertRankTest(test.TestCase): [check_ops.assert_rank(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_doesnt_raise_if_rank_just_right_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1072,6 +1101,7 @@ class AssertRankTest(test.TestCase): [check_ops.assert_rank(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_raises_if_rank_too_small_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1087,6 +1117,7 @@ class AssertRankTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "Rank must be a scalar"): check_ops.assert_rank(tensor, np.array([], dtype=np.int32)) + @test_util.run_deprecated_v1 def test_raises_if_rank_is_not_scalar_dynamic(self): with self.cached_session(): tensor = constant_op.constant( @@ -1104,6 +1135,7 @@ class AssertRankTest(test.TestCase): "must be of type "): check_ops.assert_rank(tensor, .5) + @test_util.run_deprecated_v1 def test_raises_if_rank_is_not_integer_dynamic(self): with self.cached_session(): tensor = constant_op.constant( @@ -1127,6 +1159,7 @@ class AssertRankInTest(test.TestCase): check_ops.assert_rank_in(tensor_rank0, (1, 2), message="fail")]): self.evaluate(array_ops.identity(tensor_rank0)) + @test_util.run_deprecated_v1 def test_rank_zero_tensor_raises_if_rank_mismatch_dynamic_rank(self): with self.cached_session(): tensor_rank0 = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1143,6 +1176,7 @@ class AssertRankInTest(test.TestCase): check_ops.assert_rank_in(tensor_rank0, desired_ranks)]): self.evaluate(array_ops.identity(tensor_rank0)) + @test_util.run_deprecated_v1 def test_rank_zero_tensor_doesnt_raise_if_rank_matches_dynamic_rank(self): with self.cached_session(): tensor_rank0 = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1159,6 +1193,7 @@ class AssertRankInTest(test.TestCase): check_ops.assert_rank_in(tensor_rank1, desired_ranks)]): self.evaluate(array_ops.identity(tensor_rank1)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_doesnt_raise_if_rank_matches_dynamic_rank(self): with self.cached_session(): tensor_rank1 = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1177,6 +1212,7 @@ class AssertRankInTest(test.TestCase): check_ops.assert_rank_in(tensor_rank1, (0, 2))]): self.evaluate(array_ops.identity(tensor_rank1)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_raises_if_rank_mismatches_dynamic_rank(self): with self.cached_session(): tensor_rank1 = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1196,6 +1232,7 @@ class AssertRankInTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "Rank must be a scalar"): check_ops.assert_rank_in(tensor, desired_ranks) + @test_util.run_deprecated_v1 def test_raises_if_rank_is_not_scalar_dynamic(self): with self.cached_session(): tensor = constant_op.constant( @@ -1218,6 +1255,7 @@ class AssertRankInTest(test.TestCase): "must be of type "): check_ops.assert_rank_in(tensor, (1, .5,)) + @test_util.run_deprecated_v1 def test_raises_if_rank_is_not_integer_dynamic(self): with self.cached_session(): tensor = constant_op.constant( @@ -1241,6 +1279,7 @@ class AssertRankAtLeastTest(test.TestCase): [check_ops.assert_rank_at_least(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_zero_tensor_raises_if_rank_too_small_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1258,6 +1297,7 @@ class AssertRankAtLeastTest(test.TestCase): [check_ops.assert_rank_at_least(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_zero_tensor_doesnt_raise_if_rank_just_right_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1274,6 +1314,7 @@ class AssertRankAtLeastTest(test.TestCase): [check_ops.assert_rank_at_least(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_one_ten_doesnt_raise_if_rank_too_large_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1290,6 +1331,7 @@ class AssertRankAtLeastTest(test.TestCase): [check_ops.assert_rank_at_least(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_doesnt_raise_if_rank_just_right_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1307,6 +1349,7 @@ class AssertRankAtLeastTest(test.TestCase): [check_ops.assert_rank_at_least(tensor, desired_rank)]): self.evaluate(array_ops.identity(tensor)) + @test_util.run_deprecated_v1 def test_rank_one_tensor_raises_if_rank_too_small_dynamic_rank(self): with self.cached_session(): tensor = array_ops.placeholder(dtypes.float32, name="my_tensor") @@ -1320,6 +1363,7 @@ class AssertRankAtLeastTest(test.TestCase): class AssertNonNegativeTest(test.TestCase): @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_negative(self): zoe = constant_op.constant([-1, -2], name="zoe") with self.assertRaisesOpError("x >= 0 did not hold"): @@ -1356,6 +1400,7 @@ class AssertNonPositiveTest(test.TestCase): self.evaluate(out) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_raises_when_positive(self): rachel = constant_op.constant([0, 2], name="rachel") with self.assertRaisesOpError("x <= 0 did not hold"): diff --git a/tensorflow/python/kernel_tests/checkpoint_ops_test.py b/tensorflow/python/kernel_tests/checkpoint_ops_test.py index 213ac292d3..b8c8c9edb5 100644 --- a/tensorflow/python/kernel_tests/checkpoint_ops_test.py +++ b/tensorflow/python/kernel_tests/checkpoint_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_checkpoint_ops from tensorflow.python.ops import partitioned_variables from tensorflow.python.ops import variable_scope @@ -48,6 +49,7 @@ class GenerateVocabRemappingTest(test.TestCase): with open(self.old_vocab_file, 'w') as f: f.write('\n'.join(['knitting', 'eminem', 'MISSING']) + '\n') + @test_util.run_deprecated_v1 def test_generate_remapping_with_no_vocab_changes(self): """Tests where vocab does not change at all.""" remapping, num_present = gen_checkpoint_ops.generate_vocab_remapping( @@ -368,6 +370,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): np.reshape(initializing_values, (new_rows, num_cols)), self.evaluate(remapped_matrix)) + @test_util.run_deprecated_v1 def test_loading_rows_divisible_by_max_rows(self): """Tests loading normal var when rows are evenly divisible by max_rows.""" self._test_loading_variable_with_max_rows( @@ -376,6 +379,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): # 9 is evenly divisible by 3. max_rows_in_memory=3) + @test_util.run_deprecated_v1 def test_loading_rows_not_divisible_by_max_rows(self): """Tests loading normal var when rows aren't divisible by max_rows.""" self._test_loading_variable_with_max_rows( @@ -384,6 +388,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): # 9 is not evenly divisible by 4. max_rows_in_memory=4) + @test_util.run_deprecated_v1 def test_loading_rows_less_than_max_rows(self): """Tests loading normal var as a single slice. @@ -395,6 +400,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): # 10 > 9. max_rows_in_memory=10) + @test_util.run_deprecated_v1 def test_loading_no_max_rows(self): """Tests loading normal var as a single slice with no valid max_rows.""" self._test_loading_variable_with_max_rows( @@ -402,6 +408,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): partitioner=None, max_rows_in_memory=-1) + @test_util.run_deprecated_v1 def test_loading_partitions_equals_max_rows(self): """Tests loading partitioned var sliced on partition boundary.""" self._test_loading_variable_with_max_rows( @@ -411,6 +418,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): # exactly 3 rows. max_rows_in_memory=3) + @test_util.run_deprecated_v1 def test_loading_partitions_greater_than_max_rows(self): """Tests loading partitioned var with more slices than partitions.""" self._test_loading_variable_with_max_rows( @@ -420,6 +428,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): # row at a time. max_rows_in_memory=1) + @test_util.run_deprecated_v1 def test_loading_partitions_less_than_max_rows(self): """Tests loading partitioned var as a single slice. @@ -430,6 +439,7 @@ class LoadAndRemapMatrixWithMaxRowsTest(test.TestCase): partitioner=partitioned_variables.fixed_size_partitioner(3), max_rows_in_memory=10) + @test_util.run_deprecated_v1 def test_loading_partitions_no_max_rows(self): """Tests loading partitioned var as single slice with no valid max_rows.""" self._test_loading_variable_with_max_rows( diff --git a/tensorflow/python/kernel_tests/cholesky_op_test.py b/tensorflow/python/kernel_tests/cholesky_op_test.py index 1a509a43d1..f3947236b1 100644 --- a/tensorflow/python/kernel_tests/cholesky_op_test.py +++ b/tensorflow/python/kernel_tests/cholesky_op_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_linalg_ops @@ -145,6 +146,7 @@ class CholeskyOpTest(test.TestCase): matrices[i] = np.dot(matrices[i].T.conj(), matrices[i]) self._verifyCholesky(matrices) + @test_util.run_deprecated_v1 def testNonSquareMatrix(self): with self.assertRaises(ValueError): linalg_ops.cholesky(np.array([[1., 2., 3.], [3., 4., 5.]])) @@ -175,6 +177,7 @@ class CholeskyOpTest(test.TestCase): self._verifyCholesky(np.empty([0, 2, 2])) self._verifyCholesky(np.empty([2, 0, 0])) + @test_util.run_deprecated_v1 def testConcurrentExecutesWithoutError(self): with self.session(use_gpu=True) as sess: matrix1 = random_ops.random_normal([5, 5], seed=42) @@ -193,18 +196,21 @@ class CholeskyGradTest(test.TestCase): def getShapes(self, shapeList): return ((elem, int(np.floor(1.2 * elem))) for elem in shapeList) + @test_util.run_deprecated_v1 def testSmallMatrices(self): np.random.seed(0) shapes = self.getShapes([1, 2, 10]) self.runFiniteDifferences( shapes, dtypes=(dtypes_lib.float32, dtypes_lib.float64)) + @test_util.run_deprecated_v1 def testSmallMatricesComplex(self): np.random.seed(0) shapes = self.getShapes([1, 2, 10]) self.runFiniteDifferences( shapes, dtypes=(dtypes_lib.complex64, dtypes_lib.complex128)) + @test_util.run_deprecated_v1 def testOneBlockMatrices(self): np.random.seed(0) shapes = self.getShapes([self._backprop_block_size + 1]) @@ -213,12 +219,14 @@ class CholeskyGradTest(test.TestCase): dtypes=(dtypes_lib.float32, dtypes_lib.float64), scalarTest=True) + @test_util.run_deprecated_v1 def testTwoBlockMatrixFloat(self): np.random.seed(0) shapes = self.getShapes([2 * self._backprop_block_size + 1]) self.runFiniteDifferences( shapes, dtypes=(dtypes_lib.float32,), scalarTest=True) + @test_util.run_deprecated_v1 def testTwoBlockMatrixDouble(self): np.random.seed(0) shapes = self.getShapes([2 * self._backprop_block_size + 1]) @@ -231,6 +239,7 @@ class CholeskyGradTest(test.TestCase): self.runFiniteDifferences( shapes, dtypes=(dtypes_lib.complex64,), scalarTest=True) + @test_util.run_deprecated_v1 def testTwoBlockMatrixComplexDouble(self): np.random.seed(0) shapes = self.getShapes([2 * self._backprop_block_size + 1]) diff --git a/tensorflow/python/kernel_tests/clip_ops_test.py b/tensorflow/python/kernel_tests/clip_ops_test.py index 5f1b6b6917..45f1e6152a 100644 --- a/tensorflow/python/kernel_tests/clip_ops_test.py +++ b/tensorflow/python/kernel_tests/clip_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import clip_ops from tensorflow.python.ops import gradient_checker @@ -166,6 +167,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans, tf_ans) self.assertAllClose(np_ans, tf_ans_tensor) + @test_util.run_deprecated_v1 def testClipByNormGradientZeros(self): with self.session(use_gpu=True): x = array_ops.zeros([3]) @@ -242,6 +244,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans, tf_ans) # ClipByGlobalNorm tests + @test_util.run_deprecated_v1 def testClipByGlobalNormClipped(self): # Norm clipping when clip_norm < 5 with self.session(use_gpu=True): @@ -263,6 +266,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans_0, tf_ans_1) self.assertAllClose(np_ans_1, tf_ans_2) + @test_util.run_deprecated_v1 def testClipByGlobalNormClippedTensor(self): # Norm clipping when clip_norm < 5 with self.session(use_gpu=True): @@ -284,6 +288,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans_0, tf_ans_1) self.assertAllClose(np_ans_1, tf_ans_2) + @test_util.run_deprecated_v1 def testClipByGlobalNormSupportsNone(self): # Norm clipping when clip_norm < 5 with self.session(use_gpu=True): @@ -307,6 +312,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans_0, tf_ans_1) self.assertAllClose(np_ans_1, tf_ans_2) + @test_util.run_deprecated_v1 def testClipByGlobalNormWithIndexedSlicesClipped(self): # Norm clipping when clip_norm < 5 with self.session(use_gpu=True): @@ -340,6 +346,7 @@ class ClipTest(test.TestCase): self.assertEqual(dense_shape, slices.dense_shape) self.assertEqual(dense_shape, modified_slices.dense_shape) + @test_util.run_deprecated_v1 def testClipByGlobalNormNotClipped(self): # No norm clipping when clip_norm >= 5 with self.session(use_gpu=True): @@ -359,6 +366,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans_0, tf_ans_1) self.assertAllClose(np_ans_1, tf_ans_2) + @test_util.run_deprecated_v1 def testClipByGlobalNormZero(self): # No norm clipping when norm = 0 with self.session(use_gpu=True): @@ -378,6 +386,7 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans_0, tf_ans_1) self.assertAllClose(np_ans_1, tf_ans_2) + @test_util.run_deprecated_v1 def testClipByGlobalNormInf(self): with self.session(use_gpu=True): x0 = constant_op.constant([-2.0, 0.0, np.inf, 4.0, 0.0, 0.0], @@ -456,6 +465,7 @@ class ClipTest(test.TestCase): clip_by_norm_ans = self.evaluate(without_norm) self.assertAllClose(clip_by_average_norm_ans, clip_by_norm_ans) + @test_util.run_deprecated_v1 def testClipByValueEmptyTensor(self): # Test case for GitHub issue 19337 zero = array_ops.placeholder(dtype=dtypes.float32, shape=None) diff --git a/tensorflow/python/kernel_tests/concat_op_test.py b/tensorflow/python/kernel_tests/concat_op_test.py index 27137f76bd..474760a93f 100644 --- a/tensorflow/python/kernel_tests/concat_op_test.py +++ b/tensorflow/python/kernel_tests/concat_op_test.py @@ -35,6 +35,7 @@ from tensorflow.python.platform import test class ConcatOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testHStack(self): with self.session(use_gpu=True): p1 = array_ops.placeholder(dtypes.float32, shape=[4, 4]) @@ -50,6 +51,7 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result[:4, :], params[p1]) self.assertAllEqual(result[4:, :], params[p2]) + @test_util.run_deprecated_v1 def testVStack(self): with self.session(use_gpu=True): p1 = array_ops.placeholder(dtypes.float32, shape=[4, 4]) @@ -138,6 +140,7 @@ class ConcatOpTest(test.TestCase): else: self.assertAllClose(result[ind], params[p[i]], 0.01) + @test_util.run_deprecated_v1 def testRandom(self): self._testRandom(dtypes.bool) self._testRandom(dtypes.float32) @@ -148,6 +151,7 @@ class ConcatOpTest(test.TestCase): self._testRandom(dtypes.complex64) self._testRandom(dtypes.complex128) + @test_util.run_deprecated_v1 def testInvalidConcatDimTypeAndShape(self): a = variables.Variable(constant_op.constant(1.0, shape=[1])) b = variables.Variable(constant_op.constant(2.0, shape=[1])) @@ -199,10 +203,12 @@ class ConcatOpTest(test.TestCase): result = self.evaluate(concated_grad) self.assertAllEqual(result, grad_inp) + @test_util.run_deprecated_v1 def testGradientsSimple(self): self._testGradientsSimple(dtypes.float32) self._testGradientsSimple(dtypes.complex64) + @test_util.run_deprecated_v1 def testGradientsFirstDim(self): with test_util.use_gpu(): inp = [] @@ -227,6 +233,7 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result, grad_inp) + @test_util.run_deprecated_v1 def testGradientsLastDim(self): # Test both positive and negative concat axis. # -1 and 2 correspond to the same axis for 3-dimensional tensors. @@ -284,10 +291,12 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result, grad_inp) + @test_util.run_deprecated_v1 def testGradientsRandom(self): for _ in range(5): self._RunAndVerifyGradientsRandom() + @test_util.run_deprecated_v1 def testGradientWithUnknownInputDim(self): with self.session(use_gpu=True): x = array_ops.placeholder(dtypes.float32) @@ -309,6 +318,7 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result, grad_inp) + @test_util.run_deprecated_v1 def testShapeError(self): # Rank doesn't match. with self.assertRaises(ValueError): @@ -338,6 +348,7 @@ class ConcatOpTest(test.TestCase): constant_op.constant(20.0, shape=[4, 4, 4]) ], -4) + @test_util.run_deprecated_v1 def testShapeWithUnknownConcatDim(self): p1 = array_ops.placeholder(dtypes.float32) c1 = constant_op.constant(10.0, shape=[4, 4, 4, 4]) @@ -356,6 +367,7 @@ class ConcatOpTest(test.TestCase): with self.assertRaises(ValueError): array_ops.concat([p1, c1, p2, c3], dim) + @test_util.run_deprecated_v1 def testZeroSize(self): # Verify that concat doesn't crash and burn for zero size inputs np.random.seed(7) @@ -377,6 +389,7 @@ class ConcatOpTest(test.TestCase): dxs = self.evaluate(gradients_impl.gradients(c, xs, dc)) self.assertAllEqual(dc, np.concatenate(dxs, axis=axis)) + @test_util.run_deprecated_v1 def testTensorConcatDim0Grad(self): x_shapes = [[20, 7, 3], [10, 7, 3], [14, 7, 3]] output_shape = [44, 7, 3] @@ -391,6 +404,7 @@ class ConcatOpTest(test.TestCase): output_shape) self.assertLess(err, 1e-11) + @test_util.run_deprecated_v1 def testTensorConcatDim1Grad(self): x_shapes = [[20, 7, 3], [20, 3, 3], [20, 1, 3]] output_shape = [20, 11, 3] @@ -405,6 +419,7 @@ class ConcatOpTest(test.TestCase): output_shape) self.assertLess(err, 1e-11) + @test_util.run_deprecated_v1 def testIndexedSlicesConcatDim0Grad(self): x_shapes = [[20, 7, 3], [10, 7, 3], [14, 7, 3]] output_shape = [4, 7, 3] @@ -420,6 +435,7 @@ class ConcatOpTest(test.TestCase): output_shape) self.assertLess(err, 1e-11) + @test_util.run_deprecated_v1 def testIndexedSlicesConcatDim1Grad(self): x_shapes = [[20, 7, 3], [20, 3, 3], [20, 1, 3]] output_shape = [4, 11, 3] @@ -435,6 +451,7 @@ class ConcatOpTest(test.TestCase): output_shape) self.assertLess(err, 1e-11) + @test_util.run_deprecated_v1 def testIndexedSlicesConcatDim2Grad(self): x_shapes = [[20, 7, 3], [20, 7, 1], [20, 7, 2]] output_shape = [4, 7, 6] @@ -450,6 +467,7 @@ class ConcatOpTest(test.TestCase): output_shape) self.assertLess(err, 1e-11) + @test_util.run_deprecated_v1 def testIndexedSlicesConcatDim1Grad_UnknownInputDim(self): x_shapes = [[20, 7, 3], [20, 3, 3], [20, 1, 3]] output_shape = [4, 11, 3] @@ -479,6 +497,7 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual( self.evaluate(concat_list_t), self.evaluate(concat_tuple_t)) + @test_util.run_deprecated_v1 def testConcatNoScalars(self): scalar = constant_op.constant(7) dim = array_ops.placeholder(dtypes.int32) @@ -488,6 +507,7 @@ class ConcatOpTest(test.TestCase): # important as gpu implementation could fail if # shared memory is not large for all the inputs + @test_util.run_deprecated_v1 def testConcatLargeNumberOfTensors(self): with self.session(use_gpu=True): for concat_dim in range(2): @@ -529,6 +549,7 @@ class ConcatOpTest(test.TestCase): output = gen_array_ops.concat_v2([t1, t2], 0) self.assertFalse(self.evaluate(output)) # Checks that output is empty + @test_util.run_deprecated_v1 def testConcatInvalidAxis(self): with self.assertRaises(ValueError): with test_util.use_gpu(): @@ -578,6 +599,7 @@ class ConcatOpTest(test.TestCase): result = concated_grad.eval(feed_dict=feed_dict) self.assertAllEqual(result, grad_inp) + @test_util.run_deprecated_v1 def testGradientsNegativeAxis(self): x1 = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]] x2 = [[7.0, 8.0, 9.0], [10.0, 11.0, 12.0]] @@ -630,6 +652,7 @@ class ConcatOffsetTest(test.TestCase): ans = self.evaluate(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) + @test_util.run_deprecated_v1 def testNotVector(self): cdim = constant_op.constant(1, dtypes.int32) s0 = constant_op.constant([[2, 3, 5]], dtypes.int32) @@ -639,6 +662,7 @@ class ConcatOffsetTest(test.TestCase): r"should be a vector"): self.evaluate(off) + @test_util.run_deprecated_v1 def testConcatDimOutOfRange(self): cdim = constant_op.constant(4, dtypes.int32) s0 = constant_op.constant([2, 3, 5], dtypes.int32) @@ -648,6 +672,7 @@ class ConcatOffsetTest(test.TestCase): r"Concat dim is out of range: 4 vs. 3"): self.evaluate(off) + @test_util.run_deprecated_v1 def testDimMismatch(self): cdim = constant_op.constant(1, dtypes.int32) s0 = constant_op.constant([2, 3, 5], dtypes.int32) @@ -657,6 +682,7 @@ class ConcatOffsetTest(test.TestCase): r"should contain 3 elem"): self.evaluate(off) + @test_util.run_deprecated_v1 def testSizeMismatch(self): cdim = constant_op.constant(1, dtypes.int32) s0 = constant_op.constant([2, 3, 5], dtypes.int32) diff --git a/tensorflow/python/kernel_tests/cond_v2_test.py b/tensorflow/python/kernel_tests/cond_v2_test.py index 4baa8b0212..1f4b37ce2a 100644 --- a/tensorflow/python/kernel_tests/cond_v2_test.py +++ b/tensorflow/python/kernel_tests/cond_v2_test.py @@ -68,6 +68,7 @@ class CondV2Test(test.TestCase): self.assertEqual(expected_val, actual_val) self.assertEqual(expected_grad_val, actual_grad_val) + @test_util.run_deprecated_v1 def testBasic(self): x = constant_op.constant(1.0, name="x") y = constant_op.constant(2.0, name="y") @@ -82,6 +83,7 @@ class CondV2Test(test.TestCase): self._testCond(true_fn, false_fn, [x, y]) self._testCond(true_fn, false_fn, [y]) + @test_util.run_deprecated_v1 def testMultipleOutputs(self): x = constant_op.constant(1.0, name="x") y = constant_op.constant(3.0, name="y") @@ -96,6 +98,7 @@ class CondV2Test(test.TestCase): self._testCond(true_fn, false_fn, [x, y]) self._testCond(true_fn, false_fn, [y]) + @test_util.run_deprecated_v1 def testBasic2(self): x = constant_op.constant(1.0, name="x") y = constant_op.constant(2.0, name="y") @@ -110,6 +113,7 @@ class CondV2Test(test.TestCase): self._testCond(true_fn, false_fn, [x, y]) self._testCond(true_fn, false_fn, [y]) + @test_util.run_deprecated_v1 def testNoInputs(self): with self.cached_session() as sess: pred = array_ops.placeholder(dtypes.bool, name="pred") @@ -540,6 +544,7 @@ class CondV2Test(test.TestCase): pred_inner: False }), [5., 0.]) + @test_util.run_deprecated_v1 def testSecondDerivative(self): with self.cached_session() as sess: pred = array_ops.placeholder(dtypes.bool, name="pred") @@ -636,6 +641,7 @@ class CondV2Test(test.TestCase): self.assertFalse(if_found, "An `If` op was found, but it should be lowered.") + @test_util.run_deprecated_v1 def testLoweringDisabledInXLA(self): with self.session(graph=ops.Graph()) as sess: # Build the cond_v2 in an XLA context @@ -668,6 +674,7 @@ class CondV2Test(test.TestCase): if_found, "An `If` op was not found, but the graph should not be lowered.") + @test_util.run_deprecated_v1 def testLoweringDisabledWithSingleThreadedExecutorContext(self): with self.session(graph=ops.Graph()) as sess: @function.defun @@ -702,6 +709,7 @@ class CondV2Test(test.TestCase): self.assertEqual(self.evaluate(output[1]), 9.) @test_util.enable_control_flow_v2 + @test_util.run_deprecated_v1 def testRaisesOutputStructuresMismatch(self): x = constant_op.constant(1.0, name="x") y = constant_op.constant(3.0, name="y") diff --git a/tensorflow/python/kernel_tests/conditional_accumulator_test.py b/tensorflow/python/kernel_tests/conditional_accumulator_test.py index 7ee1a4bc32..5847e4639b 100644 --- a/tensorflow/python/kernel_tests/conditional_accumulator_test.py +++ b/tensorflow/python/kernel_tests/conditional_accumulator_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import math_ops @@ -79,11 +80,13 @@ class ConditionalAccumulatorTest(test.TestCase): attr { key: 'reduction_type' value {s: 'MEAN'} } """, q.accumulator_ref.op.node_def) + @test_util.run_deprecated_v1 def testAccumulatorSizeEmpty(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator(dtypes_lib.float32, name="Q") self.assertEqual(q.num_accumulated().eval(), 0) + @test_util.run_deprecated_v1 def testAccumulatorSetGlobalStep(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -91,6 +94,7 @@ class ConditionalAccumulatorTest(test.TestCase): set_global_step_op = q.set_global_step(1) set_global_step_op.run() + @test_util.run_deprecated_v1 def testAccumulatorApplyGradFloat32(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -98,6 +102,7 @@ class ConditionalAccumulatorTest(test.TestCase): accum_op = q.apply_grad((10.0,)) accum_op.run() + @test_util.run_deprecated_v1 def testDtypes(self): with self.cached_session() as sess: dtypes = [dtypes_lib.float16, dtypes_lib.float32, dtypes_lib.float64] @@ -115,6 +120,7 @@ class ConditionalAccumulatorTest(test.TestCase): self.assertEqual(sum(elems) / len(elems), result) + @test_util.run_deprecated_v1 def testAccumulatorMultipleAccumulators(self): with self.cached_session(): q_f32_0 = data_flow_ops.ConditionalAccumulator( @@ -134,6 +140,7 @@ class ConditionalAccumulatorTest(test.TestCase): result = accums[i].take_grad(1).eval() self.assertEqual(result, i + 10.0) + @test_util.run_deprecated_v1 def testAccumulatorApplyAndTakeGradWithShape(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -155,6 +162,7 @@ class ConditionalAccumulatorTest(test.TestCase): is_all_equal &= (val[i][j] == elems_ave[i][j]) self.assertTrue(is_all_equal) + @test_util.run_deprecated_v1 def testAccumulatorApplyGradWithWrongShape(self): q = data_flow_ops.ConditionalAccumulator( dtypes_lib.float32, name="Q", shape=(3, 2)) @@ -165,6 +173,7 @@ class ConditionalAccumulatorTest(test.TestCase): with self.assertRaises(ValueError): q.apply_grad([[1.0], [2.0], [3.0]]) + @test_util.run_deprecated_v1 def testAccumulatorDynamicShape(self): with self.cached_session() as sess: q = data_flow_ops.ConditionalAccumulator( @@ -190,6 +199,7 @@ class ConditionalAccumulatorTest(test.TestCase): is_all_equal &= (val[i][j] == elems_ave[i][j]) self.assertTrue(is_all_equal) + @test_util.run_deprecated_v1 def testAccumulatorWrongDynamicShape(self): with self.cached_session() as sess: q = data_flow_ops.ConditionalAccumulator( @@ -208,6 +218,7 @@ class ConditionalAccumulatorTest(test.TestCase): with self.assertRaises(errors_impl.InvalidArgumentError): sess.run(accum_op, feed_dict={x: [[1.0], [2.0], [3.0]]}) + @test_util.run_deprecated_v1 def testAccumulatorSizeAfterApplyGrad(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -219,6 +230,7 @@ class ConditionalAccumulatorTest(test.TestCase): accum_op.run() self.assertEqual(q.num_accumulated().eval(), 2) + @test_util.run_deprecated_v1 def testAccumulatorSizeAfterApplyGradAndTakeGrad(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -247,6 +259,7 @@ class ConditionalAccumulatorTest(test.TestCase): extract_t.op.run() self.assertEqual(q.num_accumulated().eval(), 0) + @test_util.run_deprecated_v1 def testAccumulatorTakeGradMean(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -271,6 +284,7 @@ class ConditionalAccumulatorTest(test.TestCase): val = self.evaluate(takeg_t) self.assertEqual(15.0, val) + @test_util.run_deprecated_v1 def testAccumulatorTakeGradSum(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -298,6 +312,7 @@ class ConditionalAccumulatorTest(test.TestCase): val = self.evaluate(takeg_t) self.assertEqual(30.0, val) + @test_util.run_deprecated_v1 def testAccumulatorTakeGradInvalidReductionType(self): with self.assertRaises(ValueError): data_flow_ops.ConditionalAccumulator( @@ -306,6 +321,7 @@ class ConditionalAccumulatorTest(test.TestCase): shape=tensor_shape.TensorShape([1]), reduction_type="Invalid") + @test_util.run_deprecated_v1 def testAccumulatorInvalidTakeGrad(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -321,6 +337,7 @@ class ConditionalAccumulatorTest(test.TestCase): with self.assertRaises(errors_impl.InvalidArgumentError): self.evaluate(takeg_t) + @test_util.run_deprecated_v1 def testAccumulatorRepeatedTakeGradMean(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -348,6 +365,7 @@ class ConditionalAccumulatorTest(test.TestCase): val = self.evaluate(takeg_t) self.assertEqual(elems_ave + 0.0, val) + @test_util.run_deprecated_v1 def testAccumulatorRepeatedTakeGradSum(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -378,6 +396,7 @@ class ConditionalAccumulatorTest(test.TestCase): val = self.evaluate(takeg_t) self.assertEqual(elems_sum, val) + @test_util.run_deprecated_v1 def testAccumulatorIncrementGlobalStep(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -394,6 +413,7 @@ class ConditionalAccumulatorTest(test.TestCase): set_global_step_op.run() self.evaluate(inc_global_step) + @test_util.run_deprecated_v1 def testAccumulatorSetGlobalStepPreventsAccumulation(self): with self.cached_session(): q = data_flow_ops.ConditionalAccumulator( @@ -415,6 +435,7 @@ class ConditionalAccumulatorTest(test.TestCase): if x >= ls) / sum(1 for x in local_steps if x >= ls), val) + @test_util.run_deprecated_v1 def testParallelApplyGrad(self): with self.cached_session() as sess: q = data_flow_ops.ConditionalAccumulator( @@ -440,6 +461,7 @@ class ConditionalAccumulatorTest(test.TestCase): self.assertEqual(val, sum(elems) / len(elems)) + @test_util.run_deprecated_v1 def testParallelTakeGrad(self): with self.cached_session() as sess: q = data_flow_ops.ConditionalAccumulator( @@ -472,6 +494,7 @@ class ConditionalAccumulatorTest(test.TestCase): self.assertItemsEqual(elems, results) + @test_util.run_deprecated_v1 def testAccumulatorApplyAndBlockingTake(self): with self.cached_session() as sess: q = data_flow_ops.ConditionalAccumulator( @@ -505,6 +528,7 @@ class ConditionalAccumulatorTest(test.TestCase): with self.assertRaisesOpError("was cancelled"): self.evaluate(takeg_op) + @test_util.run_deprecated_v1 def testAccumulatorCancel(self): with self.cached_session() as sess: q = data_flow_ops.ConditionalAccumulator( diff --git a/tensorflow/python/kernel_tests/confusion_matrix_test.py b/tensorflow/python/kernel_tests/confusion_matrix_test.py index b001341c03..ae13c8e32e 100644 --- a/tensorflow/python/kernel_tests/confusion_matrix_test.py +++ b/tensorflow/python/kernel_tests/confusion_matrix_test.py @@ -71,9 +71,11 @@ class ConfusionMatrixTest(test.TestCase): self._testConfMatrix(labels=labels, predictions=predictions, truth=truth) + @test_util.run_deprecated_v1 def testInt32Basic(self): self._testBasic(dtype=np.int32) + @test_util.run_deprecated_v1 def testInt64Basic(self): self._testBasic(dtype=np.int64) @@ -111,9 +113,11 @@ class ConfusionMatrixTest(test.TestCase): self.assertEqual(cm_out.dtype, np_dtype) self.assertAllClose(cm_out, truth, atol=1e-10) + @test_util.run_deprecated_v1 def testOnTensors_int32(self): self._testConfMatrixOnTensors(dtypes.int32, np.int32) + @test_util.run_deprecated_v1 def testOnTensors_int64(self): self._testConfMatrixOnTensors(dtypes.int64, np.int64) @@ -133,9 +137,11 @@ class ConfusionMatrixTest(test.TestCase): self._testConfMatrix(labels=labels, predictions=predictions, truth=truth) + @test_util.run_deprecated_v1 def testInt32DifferentLabels(self, dtype=np.int32): self._testDifferentLabelsInPredictionAndTarget(dtype) + @test_util.run_deprecated_v1 def testInt64DifferentLabels(self, dtype=np.int64): self._testDifferentLabelsInPredictionAndTarget(dtype) @@ -155,12 +161,15 @@ class ConfusionMatrixTest(test.TestCase): self._testConfMatrix(labels=labels, predictions=predictions, truth=truth) + @test_util.run_deprecated_v1 def testInt32MultipleLabels(self, dtype=np.int32): self._testMultipleLabels(dtype) + @test_util.run_deprecated_v1 def testInt64MultipleLabels(self, dtype=np.int64): self._testMultipleLabels(dtype) + @test_util.run_deprecated_v1 def testWeighted(self): labels = np.arange(5, dtype=np.int32) predictions = np.arange(5, dtype=np.int32) @@ -177,6 +186,7 @@ class ConfusionMatrixTest(test.TestCase): self._testConfMatrix( labels=labels, predictions=predictions, weights=weights, truth=truth) + @test_util.run_deprecated_v1 def testLabelsTooLarge(self): labels = np.asarray([1, 1, 0, 3, 5], dtype=np.int32) predictions = np.asarray([2, 1, 0, 2, 2], dtype=np.int32) @@ -191,6 +201,7 @@ class ConfusionMatrixTest(test.TestCase): self._testConfMatrix( labels=labels, predictions=predictions, num_classes=3, truth=None) + @test_util.run_deprecated_v1 def testPredictionsTooLarge(self): labels = np.asarray([1, 1, 0, 2, 2], dtype=np.int32) predictions = np.asarray([2, 1, 0, 3, 5], dtype=np.int32) @@ -205,6 +216,7 @@ class ConfusionMatrixTest(test.TestCase): self._testConfMatrix( labels=labels, predictions=predictions, num_classes=3, truth=None) + @test_util.run_deprecated_v1 def testInvalidRank_predictionsTooBig(self): labels = np.asarray([1, 2, 3]) predictions = np.asarray([[1, 2, 3]]) @@ -212,6 +224,7 @@ class ConfusionMatrixTest(test.TestCase): confusion_matrix.confusion_matrix, predictions, labels) + @test_util.run_deprecated_v1 def testInvalidRank_predictionsTooSmall(self): labels = np.asarray([[1, 2, 3]]) predictions = np.asarray([1, 2, 3]) @@ -219,6 +232,7 @@ class ConfusionMatrixTest(test.TestCase): confusion_matrix.confusion_matrix, predictions, labels) + @test_util.run_deprecated_v1 def testInputDifferentSize(self): labels = np.asarray([1, 2]) predictions = np.asarray([1, 2, 3]) @@ -247,6 +261,7 @@ class ConfusionMatrixTest(test.TestCase): class RemoveSqueezableDimensionsTest(test.TestCase): + @test_util.run_deprecated_v1 def testBothScalarShape(self): label_values = 1.0 prediction_values = 0.0 @@ -272,6 +287,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): self.assertAllEqual( prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testSameShape(self): label_values = np.ones(shape=(2, 3, 1)) prediction_values = np.zeros_like(label_values) @@ -297,6 +313,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): self.assertAllEqual( prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testSameShapeExpectedRankDiff0(self): label_values = np.ones(shape=(2, 3, 1)) prediction_values = np.zeros_like(label_values) @@ -322,6 +339,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): self.assertAllEqual( prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testSqueezableLabels(self): label_values = np.ones(shape=(2, 3, 1)) prediction_values = np.zeros(shape=(2, 3)) @@ -348,6 +366,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): self.assertAllEqual( prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testSqueezableLabelsExpectedRankDiffPlus1(self): label_values = np.ones(shape=(2, 3, 1)) prediction_values = np.zeros(shape=(2, 3, 5)) @@ -374,6 +393,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): self.assertAllEqual( prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testSqueezablePredictions(self): label_values = np.ones(shape=(2, 3)) prediction_values = np.zeros(shape=(2, 3, 1)) @@ -402,6 +422,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): expected_prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testSqueezablePredictionsExpectedRankDiffMinus1(self): label_values = np.ones(shape=(2, 3, 5)) prediction_values = np.zeros(shape=(2, 3, 1)) @@ -430,6 +451,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): expected_prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testUnsqueezableLabels(self): label_values = np.ones(shape=(2, 3, 2)) prediction_values = np.zeros(shape=(2, 3)) @@ -455,6 +477,7 @@ class RemoveSqueezableDimensionsTest(test.TestCase): self.assertAllEqual( prediction_values, dynamic_predictions.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testUnsqueezablePredictions(self): label_values = np.ones(shape=(2, 3)) prediction_values = np.zeros(shape=(2, 3, 2)) diff --git a/tensorflow/python/kernel_tests/constant_op_test.py b/tensorflow/python/kernel_tests/constant_op_test.py index 9c3c96bd31..583082c2aa 100644 --- a/tensorflow/python/kernel_tests/constant_op_test.py +++ b/tensorflow/python/kernel_tests/constant_op_test.py @@ -70,6 +70,7 @@ class ConstantTest(test.TestCase): with self.assertRaises(TypeError): constant_op.constant(dtypes_lib.string, "[,]") + @test_util.run_deprecated_v1 def testBFloat16(self): bfloat16 = dtypes_lib.bfloat16.as_numpy_dtype self._testAll(np.arange(-15, 15).reshape([2, 3, 5]).astype(bfloat16)) @@ -77,36 +78,42 @@ class ConstantTest(test.TestCase): np.random.normal(size=30).reshape([2, 3, 5]).astype(bfloat16)) self._testAll(np.empty((2, 0, 5)).astype(bfloat16)) + @test_util.run_deprecated_v1 def testHalf(self): self._testAll(np.arange(-15, 15).reshape([2, 3, 5]).astype(np.float16)) self._testAll( np.random.normal(size=30).reshape([2, 3, 5]).astype(np.float16)) self._testAll(np.empty((2, 0, 5)).astype(np.float16)) + @test_util.run_deprecated_v1 def testFloat(self): self._testAll(np.arange(-15, 15).reshape([2, 3, 5]).astype(np.float32)) self._testAll( np.random.normal(size=30).reshape([2, 3, 5]).astype(np.float32)) self._testAll(np.empty((2, 0, 5)).astype(np.float32)) + @test_util.run_deprecated_v1 def testDouble(self): self._testAll(np.arange(-15, 15).reshape([2, 3, 5]).astype(np.float64)) self._testAll( np.random.normal(size=30).reshape([2, 3, 5]).astype(np.float64)) self._testAll(np.empty((2, 0, 5)).astype(np.float64)) + @test_util.run_deprecated_v1 def testInt32(self): self._testAll(np.arange(-15, 15).reshape([2, 3, 5]).astype(np.int32)) self._testAll((100 * np.random.normal(size=30)).reshape([2, 3, 5]).astype( np.int32)) self._testAll(np.empty((2, 0, 5)).astype(np.int32)) + @test_util.run_deprecated_v1 def testInt64(self): self._testAll(np.arange(-15, 15).reshape([2, 3, 5]).astype(np.int64)) self._testAll((100 * np.random.normal(size=30)).reshape([2, 3, 5]).astype( np.int64)) self._testAll(np.empty((2, 0, 5)).astype(np.int64)) + @test_util.run_deprecated_v1 def testComplex64(self): self._testAll( np.complex(1, 2) * @@ -116,6 +123,7 @@ class ConstantTest(test.TestCase): np.random.normal(size=30).reshape([2, 3, 5]).astype(np.complex64)) self._testAll(np.empty((2, 0, 5)).astype(np.complex64)) + @test_util.run_deprecated_v1 def testComplex128(self): self._testAll( np.complex(1, 2) * @@ -125,12 +133,14 @@ class ConstantTest(test.TestCase): np.random.normal(size=30).reshape([2, 3, 5]).astype(np.complex128)) self._testAll(np.empty((2, 0, 5)).astype(np.complex128)) + @test_util.run_deprecated_v1 def testString(self): self._testCpu( np.array([compat.as_bytes(str(x)) for x in np.arange(-15, 15)]).reshape( [2, 3, 5])) self._testCpu(np.empty((2, 0, 5)).astype(np.str_)) + @test_util.run_deprecated_v1 def testVariant(self): # TODO(ebrevdo): Re-enable use_gpu=True once non-DMA Variant # copying between CPU and GPU is supported. @@ -161,6 +171,7 @@ class ConstantTest(test.TestCase): message="Variant storing an int, decoded const value:").op logging_const_op.run() + @test_util.run_deprecated_v1 def testStringWithNulls(self): with self.cached_session(): val = ops.convert_to_tensor(b"\0\0\0\0").eval() @@ -265,6 +276,7 @@ class ConstantTest(test.TestCase): "GraphDef cannot be larger than 2GB."): g.as_graph_def() + @test_util.run_deprecated_v1 def testSparseValuesRaiseErrors(self): with self.assertRaisesRegexp(ValueError, "setting an array element with a sequence"): @@ -342,6 +354,7 @@ class AsTensorTest(test.TestCase): ops.convert_to_tensor( tensor_shape.TensorShape([1, 2, 3]), dtype=dtypes_lib.float32) + @test_util.run_deprecated_v1 def testAsTensorForDimensionInput(self): with self.cached_session(): x = ops.convert_to_tensor(tensor_shape.TensorShape([1, 2, 3])[1]) @@ -409,6 +422,7 @@ class ZerosTest(test.TestCase): self.assertShapeEqual(np_ans, d) self.assertShapeEqual(np_ans, z) + @test_util.run_deprecated_v1 def testDtype(self): with self.cached_session(): d = array_ops.fill([2, 3], 12., name="fill") @@ -477,6 +491,7 @@ class ZerosLikeTest(test.TestCase): self.assertFalse(np.any(z_value)) self.assertEqual((2, 3), z_value.shape) + @test_util.run_deprecated_v1 def testZerosLikeCPU(self): for dtype in [ dtypes_lib.half, dtypes_lib.float32, dtypes_lib.float64, @@ -487,6 +502,7 @@ class ZerosLikeTest(test.TestCase): self._compareZeros(dtype, fully_defined_shape=False, use_gpu=False) self._compareZeros(dtype, fully_defined_shape=True, use_gpu=False) + @test_util.run_deprecated_v1 def testZerosLikeGPU(self): for dtype in [ dtypes_lib.half, dtypes_lib.float32, dtypes_lib.float64, @@ -496,11 +512,13 @@ class ZerosLikeTest(test.TestCase): self._compareZeros(dtype, fully_defined_shape=False, use_gpu=True) self._compareZeros(dtype, fully_defined_shape=True, use_gpu=True) + @test_util.run_deprecated_v1 def testZerosLikePartialShape(self): d = array_ops.placeholder(dtypes_lib.float32, shape=[None, 4, None]) z = array_ops.zeros_like(d) self.assertEqual(d.get_shape().as_list(), z.get_shape().as_list()) + @test_util.run_deprecated_v1 def testZerosLikeDtype(self): # Make sure zeros_like works even for dtypes that cannot be cast between with self.cached_session(): @@ -514,6 +532,7 @@ class ZerosLikeTest(test.TestCase): self.assertEqual(y.shape, shape) self.assertAllEqual(y, np.zeros(shape, dtype=out_type)) + @test_util.run_deprecated_v1 def testZerosLikeVariant(self): # TODO(ebrevdo): Re-enable use_gpu=True once non-DMA Variant # copying between CPU and GPU is supported AND we register a @@ -574,6 +593,7 @@ class OnesTest(test.TestCase): self.assertShapeEqual(np_ans, d) self.assertShapeEqual(np_ans, z) + @test_util.run_deprecated_v1 def testAutoPack(self): with self.cached_session(): h = array_ops.placeholder(dtypes_lib.int32, shape=[]) @@ -582,6 +602,7 @@ class OnesTest(test.TestCase): out = z.eval(feed_dict={h: 4, w: 16}) self.assertAllEqual(out, np.array([[1] * 16] * 4)) + @test_util.run_deprecated_v1 def testDtype(self): with self.cached_session(): d = array_ops.fill([2, 3], 12., name="fill") @@ -635,6 +656,7 @@ class OnesLikeTest(test.TestCase): self.assertTrue(np.array_equal(z_value, np.array([[1] * 3] * 2))) self.assertEqual([2, 3], z_var.get_shape()) + @test_util.run_deprecated_v1 def testOnesLikePartialShape(self): d = array_ops.placeholder(dtypes_lib.float32, shape=[None, 4, None]) z = array_ops.ones_like(d) @@ -679,12 +701,14 @@ class FillTest(test.TestCase): np_ans = np.array([[0.15 + 0.3j] * 3] * 2).astype(np.complex128) self._compareAll([2, 3], np_ans[0][0], np_ans) + @test_util.run_deprecated_v1 def testFillString(self): np_ans = np.array([[b"yolo"] * 3] * 2) with self.session(use_gpu=False): tf_ans = array_ops.fill([2, 3], np_ans[0][0], name="fill").eval() self.assertAllEqual(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testFillNegative(self): with self.cached_session(): for shape in (-1,), (2, -1), (-1, 2), (-2), (-3): @@ -698,6 +722,7 @@ class FillTest(test.TestCase): with self.assertRaises(errors_impl.InvalidArgumentError): fill_t.eval({dims: shape}) + @test_util.run_deprecated_v1 def testShapeFunctionEdgeCases(self): # Non-vector dimensions. with self.assertRaises(ValueError): @@ -716,6 +741,7 @@ class FillTest(test.TestCase): dtypes_lib.int32, shape=()), 17], 1.0) self.assertEqual([None, 17], f.get_shape().as_list()) + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session(): in_v = constant_op.constant(5.0) @@ -728,6 +754,7 @@ class FillTest(test.TestCase): class PlaceholderTest(test.TestCase): + @test_util.run_deprecated_v1 def testDtype(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.float32, shape=(10, 10), name="p") @@ -740,6 +767,7 @@ class PlaceholderTest(test.TestCase): "must feed a value for placeholder tensor 'p' with dtype float"): self.evaluate(p_identity) + @test_util.run_deprecated_v1 def testShape(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.float32, shape=(10, 10), name="p") @@ -757,6 +785,7 @@ class PlaceholderTest(test.TestCase): ValueError, lambda e: "Cannot feed value of shape" in str(e)): p_identity.eval(feed_dict={p: feed_array[:5, :5]}) + @test_util.run_deprecated_v1 def testUnknownShape(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.float32, shape=None, name="p") @@ -769,12 +798,14 @@ class PlaceholderTest(test.TestCase): self.assertAllClose( p_identity.eval(feed_dict={p: feed_array}), feed_array) + @test_util.run_deprecated_v1 def testScalarShape(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.float32, shape=[], name="p") p_identity = array_ops.identity(p) self.assertAllClose(p_identity.eval(feed_dict={p: 5}), 5) + @test_util.run_deprecated_v1 def testPartialShape(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.float32, shape=[None, 3], name="p") @@ -787,6 +818,7 @@ class PlaceholderTest(test.TestCase): ValueError, lambda e: "Cannot feed value of shape" in str(e)): p_identity.eval(feed_dict={p: feed_array[:5, :2]}) + @test_util.run_deprecated_v1 def testPartialShapeWhenNotFed(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.float32, shape=[None, 3], name="p") @@ -797,6 +829,7 @@ class PlaceholderTest(test.TestCase): "must feed a value for placeholder tensor 'p' with dtype float"): self.evaluate(p_identity) + @test_util.run_deprecated_v1 def testControlDependency(self): with self.cached_session(): p = array_ops.placeholder(dtypes_lib.int32, shape=[], name="p") @@ -806,10 +839,12 @@ class PlaceholderTest(test.TestCase): val = np.array(2).astype(np.int) self.assertEqual(10, d.eval(feed_dict={p: val})) + @test_util.run_deprecated_v1 def testBadShape(self): with self.assertRaises(ValueError): array_ops.placeholder(dtypes_lib.float32, shape=(-1, 10)) + @test_util.run_deprecated_v1 def testTensorStr(self): a = array_ops.placeholder(dtypes_lib.float32, shape=None, name="a") self.assertEqual(" dtype=float32>", repr(a)) @@ -825,6 +860,7 @@ class PlaceholderTest(test.TestCase): self.assertEqual( "", repr(c)) + @test_util.run_deprecated_v1 def testOldGraph(self): # Load graph generated from earlier version of TF where # placeholder shape was not set. @@ -904,6 +940,7 @@ versions { class PlaceholderWithDefaultTest(test.TestCase): + @test_util.run_deprecated_v1 def testFullShape(self): with self.session(force_gpu=test_util.is_gpu_available()): p = array_ops.placeholder_with_default([[2, 2], [2, 2]], shape=[2, 2]) @@ -915,6 +952,7 @@ class PlaceholderWithDefaultTest(test.TestCase): with self.assertRaises(ValueError): a.eval(feed_dict={p: [[6, 6, 6], [6, 6, 6]]}) + @test_util.run_deprecated_v1 def testPartialShape(self): with self.session(force_gpu=test_util.is_gpu_available()): p = array_ops.placeholder_with_default([1, 2, 3], shape=[None]) @@ -925,6 +963,7 @@ class PlaceholderWithDefaultTest(test.TestCase): with self.assertRaises(ValueError): a.eval(feed_dict={p: [[2, 2], [2, 2]]}) + @test_util.run_deprecated_v1 def testNoShape(self): with self.session(force_gpu=test_util.is_gpu_available()): p = array_ops.placeholder_with_default([17], shape=None) @@ -934,6 +973,7 @@ class PlaceholderWithDefaultTest(test.TestCase): self.assertAllEqual( [[3, 3], [3, 3]], a.eval(feed_dict={p: [[3, 3], [3, 3]]})) + @test_util.run_deprecated_v1 def testGradient(self): with self.session(force_gpu=test_util.is_gpu_available()): x = array_ops.placeholder(dtypes_lib.float32, [5, 7]) diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 685d0438af..f1efc5ce59 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -141,6 +141,7 @@ class ControlFlowTest(test.TestCase): variables.global_variables_initializer().run() self.assertEqual(9, self.evaluate(v2)) + @test_util.run_deprecated_v1 def testRefEnter(self): with self.cached_session(): v = variables.VariableV1(7) @@ -154,6 +155,7 @@ class ControlFlowTest(test.TestCase): variables.global_variables_initializer().run() self.assertEqual(9, self.evaluate(v3)) + @test_util.run_deprecated_v1 def testRefSwitch(self): with self.cached_session(): v = variables.VariableV1(7) @@ -176,6 +178,7 @@ class ControlFlowTest(test.TestCase): result = self.evaluate(exit_op) self.assertAllEqual(np.array([x * 5 for x in [1, 2, 3, 4, 5, 6]]), result) + @test_util.run_deprecated_v1 def testEnterShapePropagation(self): with self.cached_session(): v = variables.Variable([0.0, 0.0], dtype=dtypes.float32) @@ -272,6 +275,7 @@ class ControlFlowTest(test.TestCase): result = self.evaluate(exit_n) self.assertAllEqual(10, result) + @test_util.run_deprecated_v1 def testLoop_1(self): with self.cached_session(): zero = constant_op.constant(0) @@ -333,6 +337,7 @@ class ControlFlowTest(test.TestCase): with self.assertRaisesOpError("has inputs from different frames"): res.eval(feed_dict={data: 1.0}) + @test_util.run_deprecated_v1 def testCondBool(self): values = constant_op.constant(10) fn1 = lambda: math_ops.add(values, 1) @@ -340,6 +345,7 @@ class ControlFlowTest(test.TestCase): with self.assertRaisesRegexp(TypeError, "must not be a Python bool"): _ = control_flow_ops.cond(False, fn1, fn2) + @test_util.run_deprecated_v1 def testCondInt(self): p = array_ops.placeholder(dtypes.bool, shape=[]) v = constant_op.constant(10) @@ -627,6 +633,7 @@ class ControlFlowTest(test.TestCase): test_result = self.evaluate(r) self.assertDictEqual({"a": 210, "b": 210}, test_result) + @test_util.run_deprecated_v1 def testEmbeddedListOutput(self): with self.cached_session() as sess: x = constant_op.constant(10) @@ -678,6 +685,7 @@ class ControlFlowTest(test.TestCase): r = control_flow_ops.cond(pred, fn1, fn2) self.evaluate(r) + @test_util.run_deprecated_v1 def testCondRef(self): with self.cached_session(): @@ -693,6 +701,7 @@ class ControlFlowTest(test.TestCase): self.assertAllEqual([2.0], self.evaluate(r)) @test_util.disable_control_flow_v2("b/79881896 (control deps)") + @test_util.run_deprecated_v1 def testCondWithControl(self): with self.cached_session(): control_holder = array_ops.placeholder(dtypes.float32, shape=()) @@ -773,6 +782,7 @@ class ControlFlowTest(test.TestCase): grad = gradients_impl.gradients(r, [x])[0] self.assertAllEqual(1.0, self.evaluate(grad)) + @test_util.run_deprecated_v1 def testCondGrad_2(self): with self.cached_session(): c = array_ops.placeholder(dtypes.int32, shape=[]) @@ -788,6 +798,7 @@ class ControlFlowTest(test.TestCase): @test_util.disable_control_flow_v2( "b/110550782 (gradient w.r.t external variable)") + @test_util.run_deprecated_v1 def testCondGrad_3(self): with self.cached_session(): c = array_ops.placeholder(dtypes.int32, shape=[]) @@ -805,6 +816,7 @@ class ControlFlowTest(test.TestCase): self.assertAllEqual(980.0, r.eval(feed_dict={c: 1})) self.assertAllEqual(30.0, r.eval(feed_dict={c: 3})) + @test_util.run_deprecated_v1 def testCondGradMultiDevice(self): config = config_pb2.ConfigProto(device_count={"CPU": 2}, allow_soft_placement=True) @@ -849,6 +861,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual(1.0, self.evaluate(result)) @test_util.disable_control_flow_v2("b/113327884") + @test_util.run_deprecated_v1 def testCondGrad_Gather(self): with self.cached_session() as sess: v1 = variables.Variable([1.0, 42.0]) @@ -1030,6 +1043,7 @@ class ControlFlowTest(test.TestCase): self.assertAllEqual(v.eval(), 1.0) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") + @test_util.run_deprecated_v1 def testWhileWithRefs_1(self): with self.cached_session() as sess: x = variables.VariableV1(0)._ref() # pylint: disable=protected-access @@ -1269,6 +1283,7 @@ class ControlFlowTest(test.TestCase): # Have more than 10 parallel iterations and hence exercise k-bound # most of the time. + @test_util.run_deprecated_v1 def testWhile_3(self): with self.cached_session(): @@ -1289,6 +1304,7 @@ class ControlFlowTest(test.TestCase): result = r[3].eval() self.assertAllEqual(10100, result) + @test_util.run_deprecated_v1 def testWhile_4(self): with self.cached_session(): @@ -1402,6 +1418,7 @@ class ControlFlowTest(test.TestCase): r = r[1] * array_ops.ones([8, 8]) self.assertAllEqual(np.ones((8, 8)), self.evaluate(r)) + @test_util.run_deprecated_v1 def testWhileWithNonTensorInput_Scalar(self): with self.cached_session(): n = 0 @@ -1476,6 +1493,7 @@ class ControlFlowTest(test.TestCase): [i.get_shape(), tensor_shape.TensorShape([5])]) @test_util.disable_control_flow_v2("b/116282023 (IndexedSlices)") + @test_util.run_deprecated_v1 def testWhileShapeInferenceIndexedSlices(self): with self.cached_session(): values = constant_op.constant([[2.0, 4.0], [3.0, 5.0]], name="values") @@ -1582,6 +1600,7 @@ class ControlFlowTest(test.TestCase): condition, body, [n, r], parallel_iterations=1) self.assertAllEqual(12, res[1].eval()) + @test_util.run_deprecated_v1 def testWhileWithControl_2(self): with self.cached_session(): r = constant_op.constant(0) @@ -1736,6 +1755,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual([2.0], sess.run(r1, {p: False})) @test_util.disable_control_flow_v2("b/116743589") + @test_util.run_deprecated_v1 def testCondWhile_3(self): self._testCondWhile_3(use_gpu=False) self._testCondWhile_3(use_gpu=True) @@ -1779,6 +1799,7 @@ class ControlFlowTest(test.TestCase): r = control_flow_ops.while_loop(c, b, [n]) self.assertAllEqual(10, self.evaluate(r)) + @test_util.run_deprecated_v1 def testWhileCondGradMultiDevice(self): config = config_pb2.ConfigProto(device_count={"CPU": 2}, allow_soft_placement=True) @@ -1810,6 +1831,7 @@ class ControlFlowTest(test.TestCase): # NOTE: It is ok to have parallel_iterations > 1 @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") + @test_util.run_deprecated_v1 def testWhileUpdateVariable_1(self): with self.cached_session(): select = variables.Variable([3.0, 4.0, 5.0]) @@ -1860,6 +1882,7 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(np.array([10.0, 10.0, 10.0]), result2) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") + @test_util.run_deprecated_v1 def testWhileUpdateVariable_3(self): with self.cached_session(): select = variables.Variable([3.0, 4.0, 5.0]) @@ -1882,6 +1905,7 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(np.array([10.0, 10.0, 10.0]), result) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") + @test_util.run_deprecated_v1 def testWhileUpdateVariable_4(self): with self.cached_session(): var_a = variables.Variable(0, name="a") @@ -1910,6 +1934,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual(10, self.evaluate(var_b)) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") + @test_util.run_deprecated_v1 def testWhileUpdateVariable_5(self): with self.cached_session(): # Create some variables. @@ -2089,6 +2114,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual([None], r.get_shape().as_list()) self.assertAllClose([810.0, 2560.0], r.eval(feed_dict={x: [3.0, 4.0]})) + @test_util.run_deprecated_v1 def testWhileGrad_BaseShape(self): with self.cached_session() as sess: x = array_ops.placeholder(dtypes.float32, [None]) @@ -2137,6 +2163,7 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(81.0, grad_v_val) @test_util.disable_control_flow_v2("b/116630618 (parallel_iters: times out)") + @test_util.run_deprecated_v1 def testWhileGrad_Mul(self): self._testWhileGrad_Mul(use_gpu=False, p_iters=1) self._testWhileGrad_Mul(use_gpu=False, p_iters=10) @@ -2166,9 +2193,11 @@ class ControlFlowTest(test.TestCase): r = gradients_impl.gradients(r, v)[0] self.assertAllClose(512.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testNestedWhileCondWhileGrad(self): self._testNestedWhileCondWhileGrad(use_gpu=False) + @test_util.run_deprecated_v1 def testNestedWhileCondWhileGradGpu(self): self._testNestedWhileCondWhileGrad(use_gpu=True) @@ -2184,6 +2213,7 @@ class ControlFlowTest(test.TestCase): variables.global_variables_initializer().run() self.assertAllClose(216.0, r[0].eval()) + @test_util.run_deprecated_v1 def testWhileGrad_ResourceVariable(self): with self.cached_session(): a = resource_variable_ops.ResourceVariable(3.0) @@ -2213,6 +2243,7 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(9.0, r.eval(feed_dict={x: 1.0})) @test_util.disable_control_flow_v2("b/116340060") + @test_util.run_deprecated_v1 def testGradInWhileWrtInitialLoopVal(self): with self.cached_session(): x = array_ops.placeholder(dtypes.float32, shape=(), name="x") @@ -2330,6 +2361,7 @@ class ControlFlowTest(test.TestCase): r = gradients_impl.gradients([rx], y) self.assertAllClose(120.0, r[0].eval()) + @test_util.run_deprecated_v1 def testWhileGrad_Dependency(self): with self.cached_session(): i = constant_op.constant(0, name="i") @@ -2381,6 +2413,7 @@ class ControlFlowTest(test.TestCase): variables.global_variables_initializer().run() self.assertAllClose(np.ones([2, 3]), sess.run(grad[0])) + @test_util.run_deprecated_v1 def testWhileGrad_Const(self): with self.cached_session() as sess: c0 = constant_op.constant(0.0, name="c0") @@ -2475,6 +2508,7 @@ class ControlFlowTest(test.TestCase): r = gradients_impl.gradients(r, v)[0] self.assertAllClose(8.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testNestedWhileGrad_Simple(self): self._testNestedWhileGrad_Simple(use_gpu=False) self._testNestedWhileGrad_Simple(use_gpu=True) @@ -2502,6 +2536,7 @@ class ControlFlowTest(test.TestCase): r = gradients_impl.gradients(r, v)[0] self.assertAllClose(256.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testNestedWhileGrad_ParallelInner(self): with self.cached_session(): v = constant_op.constant(1.0) @@ -2564,11 +2599,13 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(1024.0, self.evaluate(r)) @test_util.disable_control_flow_v2("b/117519152") + @test_util.run_deprecated_v1 def testWhileCondGrad_Simple(self): self._testWhileCondGrad_Simple(use_gpu=False) self._testWhileCondGrad_Simple(use_gpu=True) @test_util.disable_control_flow_v2("b/117276490") + @test_util.run_deprecated_v1 def testWhileCondGrad_UnknownShape(self): with self.cached_session() as sess: v = array_ops.placeholder(dtypes.float32) @@ -2586,6 +2623,7 @@ class ControlFlowTest(test.TestCase): r = sess.run(r, feed_dict={v: 2.0}) self.assertAllClose(1024.0, r) + @test_util.run_deprecated_v1 def testWhileGrad_Concat(self): with self.cached_session() as sess: x = variable_scope.get_variable("x", initializer=[[1., 2.]]) @@ -2661,6 +2699,7 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(np.array([1024.0, 1024.0]), self.evaluate(r)) @test_util.disable_control_flow_v2("b/116328420 (SparseTensor)") + @test_util.run_deprecated_v1 def testWhileGrad_SparseTensor(self): with self.cached_session(): values = constant_op.constant([2.0, 4.0], name="values") @@ -2703,6 +2742,7 @@ class ControlFlowTest(test.TestCase): c, b, [i0, constant_op.constant(0.0)]) self.assertAllClose(600.0, self.evaluate(output_grad)[1]) + @test_util.run_deprecated_v1 def testWhileAndTensorArray(self): with self.cached_session() as sess: param = constant_op.constant(2.0) @@ -2722,6 +2762,7 @@ class ControlFlowTest(test.TestCase): r = gradients_impl.gradients(r, param)[0] self.assertAllClose(107520.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testWhileGrad_StopGrad(self): with self.cached_session(): x = constant_op.constant(3.0, name="x") @@ -2765,6 +2806,7 @@ class ControlFlowTest(test.TestCase): math_ops.add(array_ops.stop_gradient(rx), ry), y)[0] self.assertEqual(32.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testWhileGrad_StopGradInside(self): with self.cached_session(): x = constant_op.constant(3.0, name="x") @@ -2784,6 +2826,7 @@ class ControlFlowTest(test.TestCase): r = gradients_impl.gradients(rx, x)[0] self.assertAllClose(156.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testWhileGrad_StopGradInsideNoShape(self): with self.cached_session() as sess: x = array_ops.placeholder(dtypes.float32) @@ -2808,6 +2851,7 @@ class ControlFlowTest(test.TestCase): self.assertFalse(any(name in op.name for op in all_ops)) @test_util.disable_control_flow_v2("b/117954949") + @test_util.run_deprecated_v1 def testWhileGradGradFail(self): theta = variables.Variable(initial_value=1.) @@ -2822,6 +2866,7 @@ class ControlFlowTest(test.TestCase): grad_theta_stopped = array_ops.stop_gradient(grad_theta) gradients_impl.gradients(grad_theta_stopped, theta) + @test_util.run_deprecated_v1 def testStopGradOnWhileGrad(self): with self.cached_session(): x = constant_op.constant(2.0, name="x") @@ -2839,6 +2884,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual(388.0, self.evaluate(r)) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") + @test_util.run_deprecated_v1 def testWhileGradientWithNontrainablePath1(self): q = variables.Variable([7., 8.]) @@ -2940,6 +2986,7 @@ class ControlFlowTest(test.TestCase): # False case: c = 0 is not >= 1 self.assertEqual([2], i.eval(feed_dict={c: 0})) + @test_util.run_deprecated_v1 def testExampleCond(self): with self.cached_session(): @@ -3191,6 +3238,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual(op.type, "NoOp") self.assertEqual(op.control_inputs, []) + @test_util.run_deprecated_v1 def testMergeShapes(self): # All inputs unknown. p1 = array_ops.placeholder(dtypes.float32) @@ -3245,6 +3293,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual([None, None], m.get_shape().as_list()) self.assertEqual([], index.get_shape()) + @test_util.run_deprecated_v1 def testRefSelect(self): index = array_ops.placeholder(dtypes.int32) @@ -3278,6 +3327,7 @@ class ControlFlowTest(test.TestCase): s = control_flow_ops.ref_select(index, [v1, v2]) self.assertEqual(None, s.get_shape()) + @test_util.run_deprecated_v1 def testRunLoopTensor(self): with self.cached_session() as sess: tensor_list = [] @@ -3364,6 +3414,7 @@ class ControlFlowTest(test.TestCase): result = control_flow_ops.merge([v_f, v_t]) self.evaluate(result) + @test_util.run_deprecated_v1 def testQIntArgAndRet(self): @function.Defun(dtypes.qint8) @@ -3411,6 +3462,7 @@ class ControlFlowContextCheckTest(test.TestCase): "is in a while loop. See info log for more details."): math_ops.add(1, while_tensor) + @test_util.run_deprecated_v1 def testInvalidContextInCond(self): # Accessing a while loop tensor in cond is illegal. while_tensor = self._getWhileTensor() @@ -3479,6 +3531,7 @@ class ControlFlowContextCheckTest(test.TestCase): control_flow_ops.while_loop(lambda i: i < 5, body, [0]) + @test_util.run_deprecated_v1 def testInvalidNestedContexts(self): # Accessing a tensor from a while context in a different while context, all # inside a cond context, is illegal. @@ -3527,6 +3580,7 @@ class TupleTest(test.TestCase): self.assertAllClose([30.0], self.evaluate(t2)) self.assertAllClose([1.0], self.evaluate(v1)) + @test_util.run_deprecated_v1 def testIndexedSlices(self): for v1_first in [True, False]: with self.cached_session(): @@ -3582,6 +3636,7 @@ class TupleTest(test.TestCase): class AssertTest(test.TestCase): + @test_util.run_deprecated_v1 def testGuardedAssertDoesNotCopyWhenTrue(self): with self.session(use_gpu=True) as sess: with ops.device(test.gpu_device_name()): diff --git a/tensorflow/python/kernel_tests/conv2d_backprop_filter_grad_test.py b/tensorflow/python/kernel_tests/conv2d_backprop_filter_grad_test.py index af6ffc1d19..7b3b560b24 100644 --- a/tensorflow/python/kernel_tests/conv2d_backprop_filter_grad_test.py +++ b/tensorflow/python/kernel_tests/conv2d_backprop_filter_grad_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops @@ -31,6 +32,7 @@ from tensorflow.python.platform import test class Conv2DBackpropFilterGradTest(test.TestCase): + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session(): for padding in ["SAME", "VALID"]: diff --git a/tensorflow/python/kernel_tests/conv2d_transpose_test.py b/tensorflow/python/kernel_tests/conv2d_transpose_test.py index d9aa4ab967..c603c08630 100644 --- a/tensorflow/python/kernel_tests/conv2d_transpose_test.py +++ b/tensorflow/python/kernel_tests/conv2d_transpose_test.py @@ -23,6 +23,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops @@ -154,6 +155,7 @@ class Conv2DTransposeTest(test.TestCase): self.assertAllClose(cache_values, value) + @test_util.run_deprecated_v1 def testGradient(self): x_shape = [2, 6, 4, 3] f_shape = [3, 3, 2, 3] diff --git a/tensorflow/python/kernel_tests/conv3d_backprop_filter_v2_grad_test.py b/tensorflow/python/kernel_tests/conv3d_backprop_filter_v2_grad_test.py index 89b64068ac..7e913febed 100644 --- a/tensorflow/python/kernel_tests/conv3d_backprop_filter_v2_grad_test.py +++ b/tensorflow/python/kernel_tests/conv3d_backprop_filter_v2_grad_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops @@ -31,6 +32,7 @@ from tensorflow.python.platform import test class Conv3DBackpropFilterV2GradTest(test.TestCase): + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session(): for padding in ["SAME", "VALID"]: diff --git a/tensorflow/python/kernel_tests/conv3d_transpose_test.py b/tensorflow/python/kernel_tests/conv3d_transpose_test.py index d4e7ec14da..22ba5b9037 100644 --- a/tensorflow/python/kernel_tests/conv3d_transpose_test.py +++ b/tensorflow/python/kernel_tests/conv3d_transpose_test.py @@ -23,6 +23,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops import tensorflow.python.ops.nn_grad # pylint: disable=unused-import @@ -119,6 +120,7 @@ class Conv3DTransposeTest(test.TestCase): target = 3.0 self.assertAllClose(target, value[n, d, h, w, k]) + @test_util.run_deprecated_v1 def testConv3DTransposeShapeMismatch(self): # Test case for GitHub issue 18460 x_shape = [2, 2, 3, 4, 3] @@ -201,6 +203,7 @@ class Conv3DTransposeTest(test.TestCase): self.assertAllClose(cache_values, value) + @test_util.run_deprecated_v1 def testGradient(self): x_shape = [2, 3, 4, 3, 2] f_shape = [3, 3, 3, 2, 2] diff --git a/tensorflow/python/kernel_tests/conv_ops_3d_test.py b/tensorflow/python/kernel_tests/conv_ops_3d_test.py index 3ec5c29df7..4a689b3fdf 100644 --- a/tensorflow/python/kernel_tests/conv_ops_3d_test.py +++ b/tensorflow/python/kernel_tests/conv_ops_3d_test.py @@ -462,6 +462,7 @@ class Conv3DTest(test.TestCase): self._ConstructAndTestGradientForConfig(data_format=data_format, use_gpu=use_gpu, **kwargs) + @test_util.run_deprecated_v1 def testInputGradientValidPaddingStrideOne(self): self.ConstructAndTestGradient( batch=2, @@ -473,6 +474,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientValidPaddingStrideOne(self): self.ConstructAndTestGradient( batch=4, @@ -484,6 +486,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientValidPaddingStrideTwo(self): self.ConstructAndTestGradient( batch=2, @@ -495,6 +498,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientValidPaddingStrideTwo(self): self.ConstructAndTestGradient( batch=2, @@ -506,6 +510,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientValidPaddingStrideThree(self): self.ConstructAndTestGradient( batch=2, @@ -517,6 +522,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientValidPaddingStrideThree(self): self.ConstructAndTestGradient( batch=2, @@ -528,6 +534,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientSamePaddingStrideOne(self): self.ConstructAndTestGradient( batch=2, @@ -539,6 +546,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientSamePaddingStrideOne(self): self.ConstructAndTestGradient( batch=2, @@ -550,6 +558,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientSamePaddingStrideTwo(self): self.ConstructAndTestGradient( batch=2, @@ -561,6 +570,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientSamePaddingStrideTwo(self): self.ConstructAndTestGradient( batch=4, @@ -572,6 +582,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientSamePaddingStrideThree(self): self.ConstructAndTestGradient( batch=2, @@ -583,6 +594,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientSamePaddingStrideThree(self): self.ConstructAndTestGradient( batch=2, @@ -594,6 +606,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientSamePaddingDifferentStrides(self): self.ConstructAndTestGradient( batch=1, @@ -605,6 +618,7 @@ class Conv3DTest(test.TestCase): padding="SAME", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientKernelSizeMatchesInputSize(self): self.ConstructAndTestGradient( batch=2, @@ -616,6 +630,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=False) + @test_util.run_deprecated_v1 def testInputGradientKernelSizeMatchesInputSize(self): self.ConstructAndTestGradient( batch=2, @@ -640,6 +655,7 @@ class Conv3DTest(test.TestCase): # Test the fast path in gemm_pack_rhs/mkldnn_gemm_pack, when channel # dimension is a multiple of packet size. + @test_util.run_deprecated_v1 def testInputGradientValidPaddingStrideOneFastPath(self): self.ConstructAndTestGradient( batch=2, @@ -651,6 +667,7 @@ class Conv3DTest(test.TestCase): padding="VALID", test_input=True) + @test_util.run_deprecated_v1 def testFilterGradientValidPaddingStrideOneFastPath(self): self.ConstructAndTestGradient( batch=2, diff --git a/tensorflow/python/kernel_tests/cross_grad_test.py b/tensorflow/python/kernel_tests/cross_grad_test.py index 0bd4006d6a..b397133fd7 100644 --- a/tensorflow/python/kernel_tests/cross_grad_test.py +++ b/tensorflow/python/kernel_tests/cross_grad_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops @@ -26,6 +27,7 @@ from tensorflow.python.platform import test class CrossOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testGradientRandomValues(self): with self.cached_session(): us = [2, 3] diff --git a/tensorflow/python/kernel_tests/ctc_decoder_ops_test.py b/tensorflow/python/kernel_tests/ctc_decoder_ops_test.py index d818fbd75c..0d86d13c71 100644 --- a/tensorflow/python/kernel_tests/ctc_decoder_ops_test.py +++ b/tensorflow/python/kernel_tests/ctc_decoder_ops_test.py @@ -25,6 +25,7 @@ from six.moves import zip_longest from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import ctc_ops from tensorflow.python.platform import test @@ -94,6 +95,7 @@ class CTCGreedyDecoderTest(test.TestCase): with self.assertRaisesOpError(expected_err_re): sess.run(decoded_unwrapped + [log_probability]) + @test_util.run_deprecated_v1 def testCTCGreedyDecoder(self): """Test two batch entries - best path decoder.""" max_time_steps = 6 @@ -170,6 +172,7 @@ class CTCGreedyDecoderTest(test.TestCase): self._testCTCDecoder(ctc_ops.ctc_greedy_decoder, inputs, seq_lens, log_prob_truth, decode_truth) + @test_util.run_deprecated_v1 def testCTCDecoderBeamSearch(self): """Test one batch, two beams - hibernating beam search.""" # max_time_steps == 8 diff --git a/tensorflow/python/kernel_tests/ctc_loss_op_test.py b/tensorflow/python/kernel_tests/ctc_loss_op_test.py index 36cae2846c..e6b5835079 100644 --- a/tensorflow/python/kernel_tests/ctc_loss_op_test.py +++ b/tensorflow/python/kernel_tests/ctc_loss_op_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import ctc_ops from tensorflow.python.ops import gradients_impl @@ -105,6 +106,7 @@ class CTCLossTest(test.TestCase): with self.assertRaisesOpError(expected_err_re): self.evaluate([loss, grad]) + @test_util.run_deprecated_v1 def testBasic(self): """Test two batch entries.""" # Input and ground truth from Alex Graves' implementation. @@ -240,6 +242,7 @@ class CTCLossTest(test.TestCase): self._testCTCLoss(inputs, seq_lens, labels, loss_truth, grad_truth) + @test_util.run_deprecated_v1 def test_time_major(self): """Testing time_major param. @@ -269,6 +272,7 @@ class CTCLossTest(test.TestCase): (tf_loss, tf_loss_transposed) = self.evaluate([loss, loss_transposed]) self.assertAllEqual(tf_loss, tf_loss_transposed) + @test_util.run_deprecated_v1 def testInvalidSecondGradient(self): inputs = np.random.randn(2, 2, 3).astype(np.float32) inputs_t = constant_op.constant(inputs) @@ -285,6 +289,7 @@ class CTCLossTest(test.TestCase): "explicitly disabled"): _ = gradients_impl._hessian_vector_product(loss, [inputs_t], v) + @test_util.run_deprecated_v1 def testEmptyBatch(self): inputs = constant_op.constant([], dtype=dtypes.float32, shape=(1, 0, 2)) sequence_lengths = constant_op.constant([], dtype=dtypes.int32) @@ -301,6 +306,7 @@ class CTCLossTest(test.TestCase): class CTCLossTestV2(test.TestCase): + @test_util.run_deprecated_v1 def testCtcLossV2(self): random_seed.set_random_seed(5) @@ -345,6 +351,7 @@ class CTCLossTestV2(test.TestCase): logit_length=logit_length, blank_index=0)) + @test_util.run_deprecated_v1 def testCtcLossDenseIsSameAsCtcLoss(self): with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): random_seed.set_random_seed(5) @@ -398,6 +405,7 @@ class CTCLossTestV2(test.TestCase): rtol=2e-06, atol=2e-06) + @test_util.run_deprecated_v1 def testCtcLossDenseUniqueFastPathIsSameAsCtcLoss(self): random_seed.set_random_seed(5) @@ -451,6 +459,7 @@ class CTCLossTestV2(test.TestCase): rtol=2e-06, atol=2e-06) + @test_util.run_deprecated_v1 def testCtcLossDenseWithBlankIndexIsSameAsCtcLoss(self): random_seed.set_random_seed(5) @@ -507,6 +516,7 @@ class CTCLossTestV2(test.TestCase): rtol=2e-06, atol=2e-06) + @test_util.run_deprecated_v1 def testCtcLossDenseWithNegativeBlankIndexIsSameAsCtcLoss(self): with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): random_seed.set_random_seed(5) @@ -555,6 +565,7 @@ class CTCLossTestV2(test.TestCase): rtol=2e-06, atol=2e-06) + @test_util.run_deprecated_v1 def testCollapseRepeated(self): collapsed, new_seq_lengths = ctc_ops.collapse_repeated( labels=[[1, 3, 3, 3, 0], @@ -568,6 +579,7 @@ class CTCLossTestV2(test.TestCase): [1, 4, 0, 0], [4, 2, 9, 4]]) + @test_util.run_deprecated_v1 def testCollapseRepeatedPreservesDtypes(self): collapsed, new_seq_lengths = ctc_ops.collapse_repeated( labels=constant_op.constant( @@ -585,6 +597,7 @@ class CTCLossTestV2(test.TestCase): [1, 4, 0, 0], [4, 2, 9, 4]]) + @test_util.run_deprecated_v1 def testCollapseRepeatedExtraPadding(self): collapsed, new_seq_lengths = ctc_ops.collapse_repeated( labels=[[1, 3, 3, 3, 0, 0, 0], @@ -598,6 +611,7 @@ class CTCLossTestV2(test.TestCase): [1, 4, 0, 0], [4, 2, 9, 4]]) + @test_util.run_deprecated_v1 def testCollapseRepeatedFrontRepeats(self): collapsed, new_seq_lengths = ctc_ops.collapse_repeated( labels=[[1, 1, 1, 2, 2], @@ -611,6 +625,7 @@ class CTCLossTestV2(test.TestCase): [1, 2], [1, 0]]) + @test_util.run_deprecated_v1 def testCollapseRepeatedAllLabelsTheSame(self): collapsed, new_seq_lengths = ctc_ops.collapse_repeated( labels=[[1, 1, 1, 1, 1], @@ -643,6 +658,7 @@ class CTCLossTestV2(test.TestCase): self.assertAllEqual(padded_dense, new_dense) + @test_util.run_deprecated_v1 def testUnique(self): labels = [ [3, 4, 4, 3], @@ -658,6 +674,7 @@ class CTCLossTestV2(test.TestCase): [0, 0, 0, 1], ], idx) + @test_util.run_deprecated_v1 def testSumStates(self): idx = [ [0, 1, 0, 1], @@ -677,6 +694,7 @@ class CTCLossTestV2(test.TestCase): [1.8, 0.8, 0.0, 0.0]] ], sum_of_states) + @test_util.run_deprecated_v1 def testStateToOlabel(self): labels = [ [3, 4, 3, 4], @@ -715,6 +733,7 @@ class CTCLossTestV2(test.TestCase): [22.0 + 23.0 + 24.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], ]) + @test_util.run_deprecated_v1 def testStateToOlabelUnique(self): labels = [ [3, 4, 3, 4], @@ -753,6 +772,7 @@ class CTCLossTestV2(test.TestCase): [22.0 + 23.0 + 24.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], ]) + @test_util.run_deprecated_v1 def testScan(self): with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): out = ctc_ops._scan( @@ -785,6 +805,7 @@ class CTCLossTestV2(test.TestCase): constant_op.constant([23.0, 24.0])) self.assertAllEqual([[23.0, 25.0], [25.0, 28.0], [29.0, 33.0]], out) + @test_util.run_deprecated_v1 def testScanCapturesVariables(self): with self.cached_session() as sess: x = random_ops.random_uniform([]) @@ -794,6 +815,7 @@ class CTCLossTestV2(test.TestCase): [23.0 + x * 0.0, 23.0 + x * 1.0, 23.0 + x * 3.0], out ])) + @test_util.run_deprecated_v1 def testScanMultipleAccumulators(self): with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): def fn(accum, elem): @@ -806,6 +828,7 @@ class CTCLossTestV2(test.TestCase): self.assertAllEqual([24.0, 26.0, 29.0], a) self.assertAllEqual([[1.0, 2.0], [2.0, 4.0], [6.0, 12.0]], b) + @test_util.run_deprecated_v1 def testScanMultipleElements(self): with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): def fn(accum, elem): diff --git a/tensorflow/python/kernel_tests/cwise_ops_binary_test.py b/tensorflow/python/kernel_tests/cwise_ops_binary_test.py index 272c2b1dac..49dbbb125a 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_binary_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_binary_test.py @@ -196,6 +196,7 @@ class BinaryOpTest(test.TestCase): self._compareGradientY(x, y, np_func, tf_func) self._compareGpu(x, y, np_func, tf_func) + @test_util.run_deprecated_v1 def testFloatBasic(self): x = np.linspace(-5, 20, 15).reshape(1, 3, 5).astype(np.float32) y = np.linspace(20, -5, 15).reshape(1, 3, 5).astype(np.float32) @@ -233,6 +234,7 @@ class BinaryOpTest(test.TestCase): except ImportError as e: tf_logging.warn("Cannot test special functions: %s" % str(e)) + @test_util.run_deprecated_v1 def testFloatDifferentShapes(self): x = np.array([1, 2, 3, 4]).reshape(2, 2).astype(np.float32) y = np.array([1, 2]).reshape(2, 1).astype(np.float32) @@ -262,6 +264,7 @@ class BinaryOpTest(test.TestCase): self.assertAllEqual(np_result, left_result) self.assertAllEqual(np_result, right_result) + @test_util.run_deprecated_v1 def testDoubleBasic(self): x = np.linspace(-5, 20, 15).reshape(1, 3, 5).astype(np.float64) y = np.linspace(20, -5, 15).reshape(1, 3, 5).astype(np.float64) @@ -353,6 +356,7 @@ class BinaryOpTest(test.TestCase): self._compareBoth(x, y, np.floor_divide, _FLOORDIV) self._compareBoth(x, y, np.mod, _MOD) + @test_util.run_deprecated_v1 def testComplex64Basic(self): x = np.complex(1, 1) * np.linspace(-10, 10, 6).reshape(1, 3, 2).astype( np.complex64) @@ -367,6 +371,7 @@ class BinaryOpTest(test.TestCase): self._compareBoth(x, y, np.multiply, _MUL) self._compareBoth(x, y + 0.1, np.true_divide, _TRUEDIV) + @test_util.run_deprecated_v1 def testComplex128Basic(self): x = np.complex(1, 1) * np.linspace(-10, 10, 6).reshape(1, 3, 2).astype( np.complex128) @@ -480,198 +485,263 @@ class BinaryOpTest(test.TestCase): ] self._testBCastByFunc(funcs, xs, ys) + @test_util.run_deprecated_v1 def testBCast_0A(self): self._testBCastA([1, 3, 2], [1]) + @test_util.run_deprecated_v1 def testBCast_0B(self): self._testBCastB([1, 3, 2], [1]) + @test_util.run_deprecated_v1 def testBCast_0C(self): self._testBCastC([1, 3, 2], [1]) + @test_util.run_deprecated_v1 def testBCast_0D(self): self._testBCastD([1, 3, 2], [1]) + @test_util.run_deprecated_v1 def testBCast_1A(self): self._testBCastA([1, 3, 2], [2]) + @test_util.run_deprecated_v1 def testBCast_1B(self): self._testBCastB([1, 3, 2], [2]) + @test_util.run_deprecated_v1 def testBCast_1C(self): self._testBCastC([1, 3, 2], [2]) + @test_util.run_deprecated_v1 def testBCast_1D(self): self._testBCastD([1, 3, 2], [2]) + @test_util.run_deprecated_v1 def testBCast_2A(self): self._testBCastA([1, 3, 2], [3, 2]) + @test_util.run_deprecated_v1 def testBCast_2B(self): self._testBCastB([1, 3, 2], [3, 2]) + @test_util.run_deprecated_v1 def testBCast_2C(self): self._testBCastC([1, 3, 2], [3, 2]) + @test_util.run_deprecated_v1 def testBCast_2D(self): self._testBCastD([1, 3, 2], [3, 2]) + @test_util.run_deprecated_v1 def testBCast_3A(self): self._testBCastA([1, 3, 2], [3, 1]) + @test_util.run_deprecated_v1 def testBCast_3B(self): self._testBCastB([1, 3, 2], [3, 1]) + @test_util.run_deprecated_v1 def testBCast_3C(self): self._testBCastC([1, 3, 2], [3, 1]) + @test_util.run_deprecated_v1 def testBCast_3D(self): self._testBCastD([1, 3, 2], [3, 1]) + @test_util.run_deprecated_v1 def testBCast_4A(self): self._testBCastA([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_4B(self): self._testBCastB([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_4C(self): self._testBCastC([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_4D(self): self._testBCastD([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_5A(self): self._testBCastA([1, 3, 2], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_5B(self): self._testBCastB([1, 3, 2], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_5C(self): self._testBCastC([1, 3, 2], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_5D(self): self._testBCastD([1, 3, 2], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_6A(self): self._testBCastA([1, 3, 2], [2, 1, 1]) + @test_util.run_deprecated_v1 def testBCast_6B(self): self._testBCastB([1, 3, 2], [2, 1, 1]) + @test_util.run_deprecated_v1 def testBCast_6C(self): self._testBCastC([1, 3, 2], [2, 1, 1]) + @test_util.run_deprecated_v1 def testBCast_6D(self): self._testBCastD([1, 3, 2], [2, 1, 1]) + @test_util.run_deprecated_v1 def testBCast_7A(self): self._testBCastA([1, 3, 2], [1, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_7B(self): self._testBCastB([1, 3, 2], [1, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_7C(self): self._testBCastC([1, 3, 2], [1, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_7D(self): self._testBCastD([1, 3, 2], [1, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_8A(self): self._testBCastA([2, 1, 5], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_8B(self): self._testBCastB([2, 1, 5], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_8C(self): self._testBCastC([2, 1, 5], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_8D(self): self._testBCastD([2, 1, 5], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_9A(self): self._testBCastA([2, 0, 5], [2, 0, 1]) + @test_util.run_deprecated_v1 def testBCast_9B(self): self._testBCastB([2, 0, 5], [2, 0, 1]) + @test_util.run_deprecated_v1 def testBCast_9C(self): self._testBCastC([2, 0, 5], [2, 0, 1]) + @test_util.run_deprecated_v1 def testBCast_9D(self): self._testBCastD([2, 0, 5], [2, 0, 1]) + @test_util.run_deprecated_v1 def testBCast_10A(self): self._testBCastA([2, 3, 0], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_10B(self): self._testBCastB([2, 3, 0], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_10C(self): self._testBCastC([2, 3, 0], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_10D(self): self._testBCastD([2, 3, 0], [2, 3, 1]) + @test_util.run_deprecated_v1 def testBCast_11A(self): self._testBCastA([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_11B(self): self._testBCastB([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_11C(self): self._testBCastC([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_11D(self): self._testBCastD([1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_12A(self): self._testBCastA([1, 1, 1, 1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_12B(self): self._testBCastB([1, 1, 1, 1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_12C(self): self._testBCastC([1, 1, 1, 1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_12D(self): self._testBCastD([1, 1, 1, 1, 3, 2], [1, 3, 2]) + @test_util.run_deprecated_v1 def testBCast_13A(self): self._testBCastA([1, 3, 2, 1, 1], [1]) + @test_util.run_deprecated_v1 def testBCast_13B(self): self._testBCastB([1, 3, 2, 1, 1], [1]) + @test_util.run_deprecated_v1 def testBCast_13C(self): self._testBCastC([1, 3, 2, 1, 1], [1]) + @test_util.run_deprecated_v1 def testBCast_13D(self): self._testBCastD([1, 3, 2, 1, 1], [1]) + @test_util.run_deprecated_v1 def testBCast_14A(self): self._testBCastA([2, 3, 1, 1, 5], [1]) + @test_util.run_deprecated_v1 def testBCast_14B(self): self._testBCastB([2, 3, 1, 1, 5], [1]) + @test_util.run_deprecated_v1 def testBCast_14C(self): self._testBCastC([2, 3, 1, 1, 5], [1]) + @test_util.run_deprecated_v1 def testBCast_14D(self): self._testBCastD([2, 3, 1, 1, 5], [1]) + @test_util.run_deprecated_v1 def testBCast_15A(self): self._testBCastA([10, 3, 1, 2], [3, 1, 2]) + @test_util.run_deprecated_v1 def testBCast_15B(self): self._testBCastB([10, 3, 1, 2], [3, 1, 2]) + @test_util.run_deprecated_v1 def testBCast_15C(self): self._testBCastC([10, 3, 1, 2], [3, 1, 2]) + @test_util.run_deprecated_v1 def testBCast_15D(self): self._testBCastD([10, 3, 1, 2], [3, 1, 2]) + @test_util.run_deprecated_v1 def testMismatchedDimensions(self): for func in [ math_ops.add, math_ops.subtract, math_ops.multiply, math_ops.div, _ADD, @@ -683,6 +753,7 @@ class BinaryOpTest(test.TestCase): ops.convert_to_tensor([10.0, 20.0, 30.0]), ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0]])) + @test_util.run_deprecated_v1 def testZeroPowGrad(self): with self.cached_session(): for dtype in (np.float16, np.float32, np.float64, np.complex64, @@ -693,6 +764,7 @@ class BinaryOpTest(test.TestCase): error = gradient_checker.compute_gradient_error(y, [], z, []) self.assertEqual(error, 0) + @test_util.run_deprecated_v1 def testComplexPowGrad(self): with self.cached_session(): for dtype in np.complex64, np.complex128: @@ -861,6 +933,7 @@ class ComparisonOpTest(test.TestCase): self._testBCastByFunc( np.not_equal, math_ops.not_equal, include_complex=True) + @test_util.run_deprecated_v1 def testShapeMismatch(self): dtypes = [np.float16, np.float32, np.float64, np.int32, np.int64] funcs = [ diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index 7e14f95be4..9bb7d8b8b1 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -199,6 +199,7 @@ class ComparisonOpTest(test.TestCase): self._testBCastByFunc( np.not_equal, math_ops.not_equal, include_complex=True) + @test_util.run_deprecated_v1 def testShapeMismatch(self): dtypes = [np.float16, np.float32, np.float64, np.int32, np.int64] funcs = [ @@ -280,6 +281,7 @@ class LogicalOpTest(test.TestCase): self._compareBinary(x, y, np.logical_or, math_ops.logical_or, use_gpu) self._compareBinary(x, y, np.logical_xor, math_ops.logical_xor, use_gpu) + @test_util.run_deprecated_v1 def testShapeMismatch(self): x = np.random.randint(0, 2, 6).astype(np.bool).reshape(1, 3, 2) y = np.random.randint(0, 2, 6).astype(np.bool).reshape(3, 2, 1) @@ -288,6 +290,7 @@ class LogicalOpTest(test.TestCase): ValueError, lambda e: "Dimensions must" in str(e)): f(x, y) + @test_util.run_deprecated_v1 def testUsingAsPythonValueFails(self): # Ensure that we raise an error when the user attempts to treat a # `Tensor` as a Python `bool`. @@ -396,6 +399,7 @@ class SelectOpTest(test.TestCase): if t in [np.float16, np.float32, np.float64]: self._compare(c, xt, yt, use_gpu=True) + @test_util.run_deprecated_v1 def testGradients(self): c = np.random.randint(0, 2, 6).astype(np.bool).reshape(1, 3, 2) x = np.random.rand(1, 3, 2) * 100 @@ -415,6 +419,7 @@ class SelectOpTest(test.TestCase): self._compareGradientX(c, xt, yt) self._compareGradientY(c, xt, yt) + @test_util.run_deprecated_v1 def testShapeMismatch(self): c = np.random.randint(0, 2, 6).astype(np.bool).reshape(1, 3, 2) x = np.random.rand(1, 3, 2) * 100 @@ -428,6 +433,7 @@ class SelectOpTest(test.TestCase): with self.assertRaises(ValueError): array_ops.where(c, xt, yt) + @test_util.run_deprecated_v1 def testEmptyTensor(self): c = np.random.randint(0, 3, 0).astype(np.bool).reshape(1, 3, 0) x = np.random.rand(1, 3, 0) * 100 @@ -439,6 +445,7 @@ class SelectOpTest(test.TestCase): z = array_ops.where(c, xt, yt).eval() self.assertAllEqual(z_expected, z) + @test_util.run_deprecated_v1 def testNan(self): """Verify that nans don't propagate where they shouldn't.""" with self.cached_session(): @@ -525,6 +532,7 @@ class BatchSelectOpTest(test.TestCase): if t in [np.float16, np.float32, np.float64]: self._compare(c, xt, yt, use_gpu=True) + @test_util.run_deprecated_v1 def testGradients(self): c = np.random.randint(0, 2, 16).astype(np.bool) x = np.random.rand(16, 2, 8) * 100 @@ -544,6 +552,7 @@ class BatchSelectOpTest(test.TestCase): self._compareGradientX(c, xt, yt) self._compareGradientY(c, xt, yt) + @test_util.run_deprecated_v1 def testShapeMismatch(self): c = np.random.randint(0, 2, 8).astype(np.bool) x = np.random.rand(16, 3, 2) * 100 @@ -622,6 +631,7 @@ class MinMaxOpTest(test.TestCase): elif x.dtype == np.float64: self.assertAllClose(jacob_t, jacob_n, rtol=1e-5, atol=1e-5) + @test_util.run_deprecated_v1 def testGradients(self): x = np.random.rand(1, 3, 2) * 100. # ensure x != y @@ -898,6 +908,7 @@ class ComplexMakeRealImagTest(test.TestCase): # build failures on GPU (See #10643 for context). # self._compareAngle(cplx, use_gpu=True) + @test_util.run_deprecated_v1 def testRealReal(self): for dtype in (dtypes_lib.int32, dtypes_lib.int64, dtypes_lib.float32, dtypes_lib.float64): @@ -928,6 +939,7 @@ class ComplexMakeRealImagTest(test.TestCase): self._compareConj(cplx, use_gpu=False) self._compareConj(cplx, use_gpu=True) + @test_util.run_deprecated_v1 def testConjReal(self): for dtype in (dtypes_lib.int32, dtypes_lib.int64, dtypes_lib.float16, dtypes_lib.float32, dtypes_lib.float64): @@ -935,6 +947,7 @@ class ComplexMakeRealImagTest(test.TestCase): y = math_ops.conj(x) self.assertEqual(x, y) + @test_util.run_deprecated_v1 def testConjString(self): x = array_ops.placeholder(dtypes_lib.string) with self.assertRaisesRegexp(TypeError, @@ -971,6 +984,7 @@ class ComplexMakeRealImagTest(test.TestCase): x_, list(x.shape), z, [1], x_init_value=x, delta=epsilon) self.assertAllClose(jacob_t, jacob_n, rtol=epsilon, atol=epsilon) + @test_util.run_deprecated_v1 def testGradient(self): # complex64 data = np.arange(1, 2, 0.10).reshape([5, 2]).astype(np.float32) @@ -1006,6 +1020,7 @@ class ComplexMakeRealImagTest(test.TestCase): inp, list(data.shape), loss, [1], x_init_value=data, delta=epsilon) self.assertAllClose(jacob_t, jacob_n, rtol=epsilon, atol=epsilon) + @test_util.run_deprecated_v1 def testMulGradient(self): data = np.arange(1, 2, 0.125).reshape([2, 4]).astype(np.float32) self._compareMulGradient(data) diff --git a/tensorflow/python/kernel_tests/cwise_ops_unary_test.py b/tensorflow/python/kernel_tests/cwise_ops_unary_test.py index 3e8294f34b..709a20f3d0 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_unary_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_unary_test.py @@ -184,6 +184,7 @@ class UnaryOpTest(test.TestCase): return func + @test_util.run_deprecated_v1 def testFloatBasic(self): x = np.arange(-3, 3).reshape(1, 3, 2).astype(np.float32) w = x - x.min() + 1.02 # all greater than 1 @@ -238,12 +239,14 @@ class UnaryOpTest(test.TestCase): self._compareBothSparse(y, np.sign, math_ops.sign) self._compareBothSparse(x, np.vectorize(math.erf), math_ops.erf) + @test_util.run_deprecated_v1 def testFloatTanhEdge(self): x = np.arange(40, 40 + 6).reshape(6).astype(np.float32) self._compareBoth(x, np.tanh, math_ops.tanh) x = np.arange(-40, -40 + 6).reshape(6).astype(np.float32) self._compareBoth(x, np.tanh, math_ops.tanh) + @test_util.run_deprecated_v1 def testFloatEmpty(self): x = np.empty((2, 0, 5), dtype=np.float32) self._compareBoth(x, np.abs, math_ops.abs) @@ -289,6 +292,7 @@ class UnaryOpTest(test.TestCase): self._compareBothSparse(x, np.sign, math_ops.sign) self._compareBothSparse(x, np.sign, math_ops.erf) + @test_util.run_deprecated_v1 def testDoubleBasic(self): x = np.arange(-3, 3).reshape(1, 3, 2).astype(np.float64) w = x - x.min() + 1.02 # all greater than 1 @@ -342,6 +346,7 @@ class UnaryOpTest(test.TestCase): self._compareBothSparse(y, np.sign, math_ops.sign) self._compareBothSparse(x, np.vectorize(math.erf), math_ops.erf) + @test_util.run_deprecated_v1 def testHalfBasic(self): x = np.arange(-3, 3).reshape(1, 3, 2).astype(np.float16) y = (x + .5).astype(np.float16) # no zero @@ -414,6 +419,7 @@ class UnaryOpTest(test.TestCase): self._compareCpu(x, np.square, math_ops.square) self._compareBothSparse(x, np.square, math_ops.square) + @test_util.run_deprecated_v1 def testComplex64Basic(self): x = np.complex(1, 1) * np.arange(-3, 3).reshape(1, 3, 2).astype( np.complex64) @@ -458,6 +464,7 @@ class UnaryOpTest(test.TestCase): self._compareBoth(y, complex_sign, math_ops.sign) self._compareBothSparse(y, complex_sign, math_ops.sign) + @test_util.run_deprecated_v1 def testComplex128Basic(self): x = np.complex(1, 1) * np.arange(-3, 3).reshape(1, 3, 2).astype( np.complex128) @@ -497,6 +504,7 @@ class UnaryOpTest(test.TestCase): self._compareBoth(y, complex_sign, math_ops.sign) self._compareBothSparse(y, complex_sign, math_ops.sign) + @test_util.run_deprecated_v1 def testGradGrad(self): np.random.seed(7) shape = (5,) diff --git a/tensorflow/python/kernel_tests/decode_compressed_op_test.py b/tensorflow/python/kernel_tests/decode_compressed_op_test.py index 1cc1c7da30..fd871c0090 100644 --- a/tensorflow/python/kernel_tests/decode_compressed_op_test.py +++ b/tensorflow/python/kernel_tests/decode_compressed_op_test.py @@ -24,6 +24,7 @@ import zlib from six import BytesIO from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import parsing_ops from tensorflow.python.platform import test @@ -42,6 +43,7 @@ class DecodeCompressedOpTest(test.TestCase): f.write(bytes_in) return out.getvalue() + @test_util.run_deprecated_v1 def testDecompress(self): for compression_type in ["ZLIB", "GZIP", ""]: with self.cached_session(): @@ -55,6 +57,7 @@ class DecodeCompressedOpTest(test.TestCase): self._compress(b"bBbb", compression_type)]}) self.assertAllEqual([b"AaAA", b"bBbb"], result) + @test_util.run_deprecated_v1 def testDecompressWithRaw(self): for compression_type in ["ZLIB", "GZIP", ""]: with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/decode_image_op_test.py b/tensorflow/python/kernel_tests/decode_image_op_test.py index 267afdeb5e..ba5770001a 100644 --- a/tensorflow/python/kernel_tests/decode_image_op_test.py +++ b/tensorflow/python/kernel_tests/decode_image_op_test.py @@ -23,6 +23,7 @@ import os.path import numpy as np from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import image_ops from tensorflow.python.ops import io_ops import tensorflow.python.ops.nn_grad # pylint: disable=unused-import @@ -44,6 +45,7 @@ class DecodeImageOpTest(test.TestCase): self.assertEqual(len(bmp0), 4194) self.assertAllEqual(image0, image1) + @test_util.run_deprecated_v1 def testGif(self): # Read some real GIFs path = os.path.join(prefix_path, "gif", "testdata", "scan.gif") @@ -78,6 +80,7 @@ class DecodeImageOpTest(test.TestCase): with self.assertRaises(errors_impl.InvalidArgumentError): self.evaluate(bad_channels) + @test_util.run_deprecated_v1 def testJpeg(self): # Read a real jpeg and verify shape path = os.path.join(prefix_path, "jpeg", "testdata", "jpeg_merge_test1.jpg") @@ -108,6 +111,7 @@ class DecodeImageOpTest(test.TestCase): self.assertEqual(image0.shape, (26, 51, channels or channels_in)) self.assertAllEqual(image0, image1) + @test_util.run_deprecated_v1 def testInvalidBytes(self): image_bytes = b"ThisIsNotAnImage!" decode = image_ops.decode_image(image_bytes) diff --git a/tensorflow/python/kernel_tests/decode_raw_op_test.py b/tensorflow/python/kernel_tests/decode_raw_op_test.py index dcc984811c..008e59ba3e 100644 --- a/tensorflow/python/kernel_tests/decode_raw_op_test.py +++ b/tensorflow/python/kernel_tests/decode_raw_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import parsing_ops from tensorflow.python.platform import test @@ -28,6 +29,7 @@ from tensorflow.python.platform import test class DecodeRawOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testToUint8(self): with self.cached_session(): in_bytes = array_ops.placeholder(dtypes.string, shape=[2]) @@ -46,6 +48,7 @@ class DecodeRawOpTest(test.TestCase): "element 1 has size 5 != 6"): decode.eval(feed_dict={in_bytes: ["short", "longer"]}) + @test_util.run_deprecated_v1 def testToInt16(self): with self.cached_session(): in_bytes = array_ops.placeholder(dtypes.string, shape=[None]) @@ -61,6 +64,7 @@ class DecodeRawOpTest(test.TestCase): "size of int16"): decode.eval(feed_dict={in_bytes: ["123", "456"]}) + @test_util.run_deprecated_v1 def testEndianness(self): with self.cached_session(): in_bytes = array_ops.placeholder(dtypes.string, shape=[None]) @@ -73,6 +77,7 @@ class DecodeRawOpTest(test.TestCase): result = decode_be.eval(feed_dict={in_bytes: ["\x01\x02\x03\x04"]}) self.assertAllEqual([[0x01020304]], result) + @test_util.run_deprecated_v1 def testToFloat16(self): with self.cached_session(): in_bytes = array_ops.placeholder(dtypes.string, shape=[None]) @@ -84,6 +89,7 @@ class DecodeRawOpTest(test.TestCase): self.assertAllEqual(expected_result, result) + @test_util.run_deprecated_v1 def testEmptyStringInput(self): with self.cached_session(): in_bytes = array_ops.placeholder(dtypes.string, shape=[None]) @@ -93,6 +99,7 @@ class DecodeRawOpTest(test.TestCase): result = decode.eval(feed_dict={in_bytes: [""] * num_inputs}) self.assertEqual((num_inputs, 0), result.shape) + @test_util.run_deprecated_v1 def testToUInt16(self): with self.cached_session(): in_bytes = array_ops.placeholder(dtypes.string, shape=[None]) diff --git a/tensorflow/python/kernel_tests/denormal_test.py b/tensorflow/python/kernel_tests/denormal_test.py index 71a528c4aa..80a3033ecc 100644 --- a/tensorflow/python/kernel_tests/denormal_test.py +++ b/tensorflow/python/kernel_tests/denormal_test.py @@ -22,6 +22,7 @@ import numpy as np import platform from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test @@ -50,10 +51,12 @@ class DenormalTest(test.TestCase): # Make sure the flags don't leak out self.testPythonHasDenormals() + @test_util.run_deprecated_v1 def testFlushDenormalsCPU(self): # On CPUs, the processor flags flush for both single and double precision. self._flushDenormalsTest(use_gpu=False, dtypes=(np.float32, np.float64)) + @test_util.run_deprecated_v1 def testFlushDenormalsGPU(self): # On GPUs, only single precision can flush to zero. self._flushDenormalsTest(use_gpu=True, dtypes=(np.float32,)) diff --git a/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py b/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py index 0676664685..4f74e1e741 100644 --- a/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py +++ b/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import state_ops @@ -32,6 +33,7 @@ class AssignOpTest(test.TestCase): # NOTE(mrry): We exclude thess tests from the TSAN TAP target, because they # contain benign and deliberate data races when multiple threads update # the same parameters without a lock. + @test_util.run_deprecated_v1 def testParallelUpdateWithoutLocking(self): with self.cached_session() as sess: ones_t = array_ops.fill([1024, 1024], 1.0) @@ -59,6 +61,7 @@ class AssignOpTest(test.TestCase): self.assertTrue((vals >= ones).all()) self.assertTrue((vals <= ones * 20).all()) + @test_util.run_deprecated_v1 def testParallelAssignWithoutLocking(self): with self.cached_session() as sess: ones_t = array_ops.fill([1024, 1024], float(1)) @@ -91,6 +94,7 @@ class AssignOpTest(test.TestCase): # contain non-benign but known data races between the variable assignment and # returning the output tensors. This issue will be resolved with the new # resource variables. + @test_util.run_deprecated_v1 def testParallelUpdateWithLocking(self): with self.cached_session() as sess: zeros_t = array_ops.fill([1024, 1024], 0.0) @@ -118,6 +122,7 @@ class AssignOpTest(test.TestCase): ones = np.ones((1024, 1024)).astype(np.float32) self.assertAllEqual(vals, ones * 20) + @test_util.run_deprecated_v1 def testParallelAssignWithLocking(self): with self.cached_session() as sess: zeros_t = array_ops.fill([1024, 1024], 0.0) diff --git a/tensorflow/python/kernel_tests/dense_update_ops_test.py b/tensorflow/python/kernel_tests/dense_update_ops_test.py index a4766fed72..309da88bef 100644 --- a/tensorflow/python/kernel_tests/dense_update_ops_test.py +++ b/tensorflow/python/kernel_tests/dense_update_ops_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables @@ -81,9 +82,11 @@ class AssignOpTest(test.TestCase): self.assertAllEqual(x - y, var_value) self.assertAllEqual(x - y, op_value) + @test_util.run_deprecated_v1 def testBasic(self): self._testTypes(np.arange(0, 20).reshape([4, 5])) + @test_util.run_deprecated_v1 def testAssignNonStrictShapeChecking(self): with self.cached_session(): data = array_ops.fill([1024, 1024], 0) @@ -98,6 +101,7 @@ class AssignOpTest(test.TestCase): a2.op.run() self.assertAllEqual(p.eval(), self.evaluate(data2)) + @test_util.run_deprecated_v1 def testInitRequiredAssignAdd(self): with self.cached_session(): p = variables.VariableV1(array_ops.fill([1024, 1024], 1), dtypes.int32) @@ -105,6 +109,7 @@ class AssignOpTest(test.TestCase): with self.assertRaisesOpError("use uninitialized"): a.op.run() + @test_util.run_deprecated_v1 def testInitRequiredAssignSub(self): with self.cached_session(): p = variables.VariableV1(array_ops.fill([1024, 1024], 1), dtypes.int32) diff --git a/tensorflow/python/kernel_tests/depthtospace_op_test.py b/tensorflow/python/kernel_tests/depthtospace_op_test.py index 19f145865f..96c9b5258e 100644 --- a/tensorflow/python/kernel_tests/depthtospace_op_test.py +++ b/tensorflow/python/kernel_tests/depthtospace_op_test.py @@ -53,12 +53,14 @@ class DepthToSpaceTest(test.TestCase): output_nhwc = test_util.NCHWToNHWC(output_nchw) self.assertAllEqual(output_nhwc.eval(), outputs) + @test_util.run_deprecated_v1 def testBasic(self): x_np = [[[[1, 2, 3, 4]]]] block_size = 2 x_out = [[[[1], [2]], [[3], [4]]]] self._testOne(x_np, block_size, x_out) + @test_util.run_deprecated_v1 def testBasicFloat16(self): x_np = [[[[1, 2, 3, 4]]]] block_size = 2 @@ -67,6 +69,7 @@ class DepthToSpaceTest(test.TestCase): # Tests for larger input dimensions. To make sure elements are # correctly ordered spatially. + @test_util.run_deprecated_v1 def testBlockSize2(self): x_np = [[[[1, 2, 3, 4], [5, 6, 7, 8]], @@ -79,6 +82,7 @@ class DepthToSpaceTest(test.TestCase): [[11], [12], [15], [16]]]] self._testOne(x_np, block_size, x_out) + @test_util.run_deprecated_v1 def testBlockSize2Batch10(self): block_size = 2 def batch_input_elt(i): @@ -115,6 +119,7 @@ class DepthToSpaceTest(test.TestCase): self.evaluate(x_tf) # Tests for different width and height. + @test_util.run_deprecated_v1 def testNonSquare(self): x_np = [[[[1, 10, 2, 20, 3, 30, 4, 40]], [[5, 50, 6, 60, 7, 70, 8, 80]], @@ -130,6 +135,7 @@ class DepthToSpaceTest(test.TestCase): # Tests for larger input dimensions. To make sure elements are # correctly ordered spatially. + @test_util.run_deprecated_v1 def testBlockSize4FlatInput(self): x_np = [[[[1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16]]]] block_size = 4 @@ -141,6 +147,7 @@ class DepthToSpaceTest(test.TestCase): # Tests for larger input depths. # To make sure elements are properly interleaved in depth. + @test_util.run_deprecated_v1 def testDepthInterleaved(self): x_np = [[[[1, 10, 2, 20, 3, 30, 4, 40]]]] block_size = 2 @@ -150,6 +157,7 @@ class DepthToSpaceTest(test.TestCase): # Tests for larger input depths. Here an odd depth. # To make sure elements are properly interleaved in depth. + @test_util.run_deprecated_v1 def testDepthInterleavedDepth3(self): x_np = [[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]]]] block_size = 2 @@ -159,6 +167,7 @@ class DepthToSpaceTest(test.TestCase): # Tests for larger input depths. # To make sure elements are properly interleaved in depth. + @test_util.run_deprecated_v1 def testDepthInterleavedLarger(self): x_np = [[[[1, 10, 2, 20, 3, 30, 4, 40], [5, 50, 6, 60, 7, 70, 8, 80]], @@ -175,6 +184,7 @@ class DepthToSpaceTest(test.TestCase): # Tests for a block larger for the depth. In this case should raise an # exception. + @test_util.run_deprecated_v1 def testBlockSizeTooLarge(self): x_np = [[[[1, 2, 3, 4], [5, 6, 7, 8]], @@ -188,6 +198,7 @@ class DepthToSpaceTest(test.TestCase): self.evaluate(out_tf) # Test when the block size is 0. + @test_util.run_deprecated_v1 def testBlockSize0(self): x_np = [[[[1], [2]], [[3], [4]]]] @@ -197,6 +208,7 @@ class DepthToSpaceTest(test.TestCase): self.evaluate(out_tf) # Test when the block size is 1. The block size should be > 1. + @test_util.run_deprecated_v1 def testBlockSizeOne(self): x_np = [[[[1, 1, 1, 1], [2, 2, 2, 2]], @@ -207,6 +219,7 @@ class DepthToSpaceTest(test.TestCase): out_tf = array_ops.depth_to_space(x_np, block_size) self.evaluate(out_tf) + @test_util.run_deprecated_v1 def testBlockSizeLargerThanInput(self): # The block size is too large for this input. x_np = [[[[1], [2]], @@ -216,6 +229,7 @@ class DepthToSpaceTest(test.TestCase): out_tf = array_ops.space_to_depth(x_np, block_size) self.evaluate(out_tf) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleDepth(self): # The depth is not divisible by the square of the block size. x_np = [[[[1, 1, 1, 1], @@ -226,6 +240,7 @@ class DepthToSpaceTest(test.TestCase): with self.assertRaises(ValueError): _ = array_ops.space_to_depth(x_np, block_size) + @test_util.run_deprecated_v1 def testUnknownShape(self): t = array_ops.depth_to_space( array_ops.placeholder(dtypes.float32), block_size=4) @@ -343,11 +358,13 @@ class DepthToSpaceGradientTest(test.TestCase): # Don't use very large numbers as dimensions here, as the result is tensor # with cartesian product of the dimensions. + @test_util.run_deprecated_v1 def testSmall(self): block_size = 2 self._compare(3, 2, 5, 3, block_size, "NHWC") self._compare(3, 2, 5, 3, block_size, "NCHW") + @test_util.run_deprecated_v1 def testSmall2(self): block_size = 3 self._compare(1, 2, 3, 2, block_size, "NHWC") diff --git a/tensorflow/python/kernel_tests/diag_op_test.py b/tensorflow/python/kernel_tests/diag_op_test.py index f7a9cd8d6e..ed2a9e8e47 100644 --- a/tensorflow/python/kernel_tests/diag_op_test.py +++ b/tensorflow/python/kernel_tests/diag_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -31,6 +32,7 @@ from tensorflow.python.platform import tf_logging class MatrixDiagTest(test.TestCase): + @test_util.run_deprecated_v1 def testVector(self): with self.session(use_gpu=True): v = np.array([1.0, 2.0, 3.0]) @@ -49,6 +51,7 @@ class MatrixDiagTest(test.TestCase): self.assertEqual((2, 3, 3), v_batch_diag.get_shape()) self.assertAllEqual(v_batch_diag.eval(), mat_batch) + @test_util.run_deprecated_v1 def testBatchVector(self): self._testBatchVector(np.float32) self._testBatchVector(np.float64) @@ -56,16 +59,19 @@ class MatrixDiagTest(test.TestCase): self._testBatchVector(np.int64) self._testBatchVector(np.bool) + @test_util.run_deprecated_v1 def testInvalidShape(self): with self.assertRaisesRegexp(ValueError, "must be at least rank 1"): array_ops.matrix_diag(0) + @test_util.run_deprecated_v1 def testInvalidShapeAtEval(self): with self.session(use_gpu=True): v = array_ops.placeholder(dtype=dtypes_lib.float32) with self.assertRaisesOpError("input must be at least 1-dim"): array_ops.matrix_diag(v).eval(feed_dict={v: 0.0}) + @test_util.run_deprecated_v1 def testGrad(self): shapes = ((3,), (7, 4)) with self.session(use_gpu=True): @@ -81,6 +87,7 @@ class MatrixDiagTest(test.TestCase): class MatrixSetDiagTest(test.TestCase): + @test_util.run_deprecated_v1 def testSquare(self): with self.session(use_gpu=True): v = np.array([1.0, 2.0, 3.0]) @@ -91,6 +98,7 @@ class MatrixSetDiagTest(test.TestCase): self.assertEqual((3, 3), output.get_shape()) self.assertAllEqual(mat_set_diag, self.evaluate(output)) + @test_util.run_deprecated_v1 def testRectangular(self): with self.session(use_gpu=True): v = np.array([3.0, 4.0]) @@ -123,6 +131,7 @@ class MatrixSetDiagTest(test.TestCase): self.assertEqual((2, 3, 3), output.get_shape()) self.assertAllEqual(mat_set_diag_batch, self.evaluate(output)) + @test_util.run_deprecated_v1 def testSquareBatch(self): self._testSquareBatch(np.float32) self._testSquareBatch(np.float64) @@ -130,6 +139,7 @@ class MatrixSetDiagTest(test.TestCase): self._testSquareBatch(np.int64) self._testSquareBatch(np.bool) + @test_util.run_deprecated_v1 def testRectangularBatch(self): with self.session(use_gpu=True): v_batch = np.array([[-1.0, -2.0], [-4.0, -5.0]]) @@ -142,12 +152,14 @@ class MatrixSetDiagTest(test.TestCase): self.assertEqual((2, 2, 3), output.get_shape()) self.assertAllEqual(mat_set_diag_batch, self.evaluate(output)) + @test_util.run_deprecated_v1 def testInvalidShape(self): with self.assertRaisesRegexp(ValueError, "must be at least rank 2"): array_ops.matrix_set_diag(0, [0]) with self.assertRaisesRegexp(ValueError, "must be at least rank 1"): array_ops.matrix_set_diag([[0]], 0) + @test_util.run_deprecated_v1 def testInvalidShapeAtEval(self): with self.session(use_gpu=True): v = array_ops.placeholder(dtype=dtypes_lib.float32) @@ -157,6 +169,7 @@ class MatrixSetDiagTest(test.TestCase): r"but received input shape: \[1,1\] and diagonal shape: \[\]"): array_ops.matrix_set_diag([[v]], v).eval(feed_dict={v: 0.0}) + @test_util.run_deprecated_v1 def testGrad(self): shapes = ((3, 4, 4), (3, 3, 4), (3, 4, 3), (7, 4, 8, 8)) with self.session(use_gpu=True): @@ -178,6 +191,7 @@ class MatrixSetDiagTest(test.TestCase): y.get_shape().as_list()) self.assertLess(error_x_diag, 1e-4) + @test_util.run_deprecated_v1 def testGradWithNoShapeInformation(self): with self.session(use_gpu=True) as sess: v = array_ops.placeholder(dtype=dtypes_lib.float32) @@ -200,6 +214,7 @@ class MatrixSetDiagTest(test.TestCase): class MatrixDiagPartTest(test.TestCase): + @test_util.run_deprecated_v1 def testSquare(self): with self.session(use_gpu=True): v = np.array([1.0, 2.0, 3.0]) @@ -208,6 +223,7 @@ class MatrixDiagPartTest(test.TestCase): self.assertEqual((3,), mat_diag.get_shape()) self.assertAllEqual(mat_diag.eval(), v) + @test_util.run_deprecated_v1 def testRectangular(self): with self.session(use_gpu=True): mat = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) @@ -228,6 +244,7 @@ class MatrixDiagPartTest(test.TestCase): self.assertEqual((2, 3), mat_batch_diag.get_shape()) self.assertAllEqual(mat_batch_diag.eval(), v_batch) + @test_util.run_deprecated_v1 def testSquareBatch(self): self._testSquareBatch(np.float32) self._testSquareBatch(np.float64) @@ -235,6 +252,7 @@ class MatrixDiagPartTest(test.TestCase): self._testSquareBatch(np.int64) self._testSquareBatch(np.bool) + @test_util.run_deprecated_v1 def testRectangularBatch(self): with self.session(use_gpu=True): v_batch = np.array([[1.0, 2.0], [4.0, 5.0]]) @@ -245,16 +263,19 @@ class MatrixDiagPartTest(test.TestCase): self.assertEqual((2, 2), mat_batch_diag.get_shape()) self.assertAllEqual(mat_batch_diag.eval(), v_batch) + @test_util.run_deprecated_v1 def testInvalidShape(self): with self.assertRaisesRegexp(ValueError, "must be at least rank 2"): array_ops.matrix_diag_part(0) + @test_util.run_deprecated_v1 def testInvalidShapeAtEval(self): with self.session(use_gpu=True): v = array_ops.placeholder(dtype=dtypes_lib.float32) with self.assertRaisesOpError("input must be at least 2-dim"): array_ops.matrix_diag_part(v).eval(feed_dict={v: 0.0}) + @test_util.run_deprecated_v1 def testGrad(self): shapes = ((3, 3), (2, 3), (3, 2), (5, 3, 3)) with self.session(use_gpu=True): @@ -407,6 +428,7 @@ class DiagTest(test.TestCase): dtype=dtype) self.diagOp(x, dtype, expected_ans) + @test_util.run_deprecated_v1 def testInvalidRank(self): with self.assertRaisesRegexp(ValueError, "must be at least rank 1"): array_ops.diag(0.0) @@ -476,6 +498,7 @@ class DiagPartOpTest(test.TestCase): self.diagPartOp(x, np.complex64, expected_ans) self.diagPartOp(x, np.complex128, expected_ans) + @test_util.run_deprecated_v1 def testOddRank(self): w = np.random.rand(2) x = np.random.rand(2, 2, 2) @@ -484,6 +507,7 @@ class DiagPartOpTest(test.TestCase): with self.assertRaises(ValueError): array_ops.diag_part(0.0) + @test_util.run_deprecated_v1 def testUnevenDimensions(self): w = np.random.rand(2, 5) x = np.random.rand(2, 1, 2, 3) @@ -493,6 +517,7 @@ class DiagPartOpTest(test.TestCase): class DiagGradOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testDiagGrad(self): np.random.seed(0) shapes = ((3,), (3, 3), (3, 3, 3)) @@ -513,6 +538,7 @@ class DiagGradOpTest(test.TestCase): class DiagGradPartOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testDiagPartGrad(self): np.random.seed(0) shapes = ((3, 3), (3, 3, 3, 3)) diff --git a/tensorflow/python/kernel_tests/distributions/bernoulli_test.py b/tensorflow/python/kernel_tests/distributions/bernoulli_test.py index 37b35ba51a..e6d560b4bc 100644 --- a/tensorflow/python/kernel_tests/distributions/bernoulli_test.py +++ b/tensorflow/python/kernel_tests/distributions/bernoulli_test.py @@ -151,6 +151,7 @@ class BernoulliTest(test.TestCase): self.assertAllClose(self.evaluate(dist.prob(x)), expected_pmf) self.assertAllClose(self.evaluate(dist.log_prob(x)), np.log(expected_pmf)) + @test_util.run_deprecated_v1 def testPmfCorrectBroadcastDynamicShape(self): with self.cached_session(): p = array_ops.placeholder(dtype=dtypes.float32) @@ -167,6 +168,7 @@ class BernoulliTest(test.TestCase): }), [[0.2, 0.7, 0.4]]) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testPmfInvalid(self): p = [0.1, 0.2, 0.7] dist = bernoulli.Bernoulli(probs=p, validate_args=True) @@ -193,6 +195,7 @@ class BernoulliTest(test.TestCase): self.evaluate( bernoulli.Bernoulli(probs=p, validate_args=False).log_prob(samps))) + @test_util.run_deprecated_v1 def testBroadcasting(self): with self.cached_session(): p = array_ops.placeholder(dtypes.float32) @@ -207,6 +210,7 @@ class BernoulliTest(test.TestCase): p: [0.5, 0.5, 0.5] })) + @test_util.run_deprecated_v1 def testPmfShapes(self): with self.cached_session(): p = array_ops.placeholder(dtypes.float32, shape=[None, 1]) @@ -276,6 +280,7 @@ class BernoulliTest(test.TestCase): grad_p = tape.gradient(samples, p) self.assertIsNone(grad_p) + @test_util.run_deprecated_v1 def testSampleActsLikeSampleN(self): with self.cached_session() as sess: p = [0.2, 0.6] diff --git a/tensorflow/python/kernel_tests/distributions/bijector_test.py b/tensorflow/python/kernel_tests/distributions/bijector_test.py index e20f59f48a..a0e0a36fec 100644 --- a/tensorflow/python/kernel_tests/distributions/bijector_test.py +++ b/tensorflow/python/kernel_tests/distributions/bijector_test.py @@ -132,6 +132,7 @@ class BijectorTestEventNdims(test.TestCase): with self.assertRaisesRegexp(ValueError, "Expected scalar"): bij.inverse_log_det_jacobian(1., event_ndims=(1, 2)) + @test_util.run_deprecated_v1 def testBijectorDynamicEventNdims(self): bij = BrokenBijector(validate_args=True) event_ndims = array_ops.placeholder(dtype=np.int32, shape=None) @@ -301,6 +302,7 @@ class BijectorReduceEventDimsTest(test.TestCase): 8., self.evaluate(bij.inverse_log_det_jacobian(x, event_ndims=2))) + @test_util.run_deprecated_v1 def testHandlesNonStaticEventNdims(self): x_ = [[[1., 2.], [3., 4.]]] x = array_ops.placeholder_with_default(x_, shape=None) diff --git a/tensorflow/python/kernel_tests/distributions/categorical_test.py b/tensorflow/python/kernel_tests/distributions/categorical_test.py index 9c593d2737..ec1d4ed207 100644 --- a/tensorflow/python/kernel_tests/distributions/categorical_test.py +++ b/tensorflow/python/kernel_tests/distributions/categorical_test.py @@ -25,6 +25,7 @@ from tensorflow.python.eager import backprop from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_util +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops @@ -44,6 +45,7 @@ def make_categorical(batch_shape, num_classes, dtype=dtypes.int32): class CategoricalTest(test.TestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testP(self): p = [0.2, 0.8] dist = categorical.Categorical(probs=p) @@ -51,6 +53,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertAllClose(p, dist.probs.eval()) self.assertAllEqual([2], dist.logits.get_shape()) + @test_util.run_deprecated_v1 def testLogits(self): p = np.array([0.2, 0.8], dtype=np.float32) logits = np.log(p) - 50. @@ -61,6 +64,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertAllClose(dist.probs.eval(), p) self.assertAllClose(dist.logits.eval(), logits) + @test_util.run_deprecated_v1 def testShapes(self): with self.cached_session(): for batch_shape in ([], [1], [2, 3, 4]): @@ -107,6 +111,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertEqual(dist.dtype, dtype) self.assertEqual(dist.dtype, dist.sample(5).dtype) + @test_util.run_deprecated_v1 def testUnknownShape(self): with self.cached_session(): logits = array_ops.placeholder(dtype=dtypes.float32) @@ -121,18 +126,21 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): feed_dict={logits: [[-1000.0, 1000.0], [1000.0, -1000.0]]}) self.assertAllEqual([1, 0], sample_value_batch) + @test_util.run_deprecated_v1 def testPMFWithBatch(self): histograms = [[0.2, 0.8], [0.6, 0.4]] dist = categorical.Categorical(math_ops.log(histograms) - 50.) with self.cached_session(): self.assertAllClose(dist.prob([0, 1]).eval(), [0.2, 0.4]) + @test_util.run_deprecated_v1 def testPMFNoBatch(self): histograms = [0.2, 0.8] dist = categorical.Categorical(math_ops.log(histograms) - 50.) with self.cached_session(): self.assertAllClose(dist.prob(0).eval(), 0.2) + @test_util.run_deprecated_v1 def testCDFWithDynamicEventShapeKnownNdims(self): """Test that dynamically-sized events with unknown shape work.""" batch_size = 2 @@ -184,6 +192,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): actual_cdf = self.evaluate(cdf_op) self.assertAllClose(actual_cdf, expected_cdf) + @test_util.run_deprecated_v1 def testCDFWithBatch(self): histograms = [[0.1, 0.2, 0.3, 0.25, 0.15], [0.0, 0.75, 0.2, 0.05, 0.0]] @@ -195,6 +204,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): with self.cached_session(): self.assertAllClose(cdf_op.eval(), expected_cdf) + @test_util.run_deprecated_v1 def testCDFNoBatch(self): histogram = [0.1, 0.2, 0.3, 0.4] event = 2 @@ -205,6 +215,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): with self.cached_session(): self.assertAlmostEqual(cdf_op.eval(), expected_cdf) + @test_util.run_deprecated_v1 def testCDFBroadcasting(self): # shape: [batch=2, n_bins=3] histograms = [[0.2, 0.1, 0.7], @@ -298,6 +309,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertAllEqual(run_result["cat_log_cdf"].shape, run_result["norm_log_cdf"].shape) + @test_util.run_deprecated_v1 def testLogPMF(self): logits = np.log([[0.2, 0.8], [0.6, 0.4]]) - 50. dist = categorical.Categorical(logits) @@ -305,6 +317,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertAllClose(dist.log_prob([0, 1]).eval(), np.log([0.2, 0.4])) self.assertAllClose(dist.log_prob([0.0, 1.0]).eval(), np.log([0.2, 0.4])) + @test_util.run_deprecated_v1 def testEntropyNoBatch(self): logits = np.log([0.2, 0.8]) - 50. dist = categorical.Categorical(logits) @@ -312,6 +325,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertAllClose(dist.entropy().eval(), -(0.2 * np.log(0.2) + 0.8 * np.log(0.8))) + @test_util.run_deprecated_v1 def testEntropyWithBatch(self): logits = np.log([[0.2, 0.8], [0.6, 0.4]]) - 50. dist = categorical.Categorical(logits) @@ -321,6 +335,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): -(0.6 * np.log(0.6) + 0.4 * np.log(0.4)) ]) + @test_util.run_deprecated_v1 def testEntropyGradient(self): with self.cached_session() as sess: logits = constant_op.constant([[1., 2., 3.], [2., 5., 1.]]) @@ -440,12 +455,14 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): self.assertEqual(3, log_prob.get_shape().ndims) self.assertAllEqual([2, 2, 2], log_prob.get_shape()) + @test_util.run_deprecated_v1 def testMode(self): with self.cached_session(): histograms = [[[0.2, 0.8], [0.6, 0.4]]] dist = categorical.Categorical(math_ops.log(histograms) - 50.) self.assertAllEqual(dist.mode().eval(), [[1, 0]]) + @test_util.run_deprecated_v1 def testCategoricalCategoricalKL(self): def np_softmax(logits): diff --git a/tensorflow/python/kernel_tests/distributions/dirichlet_multinomial_test.py b/tensorflow/python/kernel_tests/distributions/dirichlet_multinomial_test.py index 3662ca1ad1..c530037e1e 100644 --- a/tensorflow/python/kernel_tests/distributions/dirichlet_multinomial_test.py +++ b/tensorflow/python/kernel_tests/distributions/dirichlet_multinomial_test.py @@ -22,6 +22,7 @@ from tensorflow.python.eager import backprop from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops.distributions import dirichlet_multinomial @@ -36,6 +37,7 @@ class DirichletMultinomialTest(test.TestCase): def setUp(self): self._rng = np.random.RandomState(42) + @test_util.run_deprecated_v1 def testSimpleShapes(self): with self.cached_session(): alpha = np.random.rand(3) @@ -45,6 +47,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertEqual(tensor_shape.TensorShape([3]), dist.event_shape) self.assertEqual(tensor_shape.TensorShape([]), dist.batch_shape) + @test_util.run_deprecated_v1 def testComplexShapes(self): with self.cached_session(): alpha = np.random.rand(3, 2, 2) @@ -55,6 +58,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertEqual(tensor_shape.TensorShape([2]), dist.event_shape) self.assertEqual(tensor_shape.TensorShape([3, 2]), dist.batch_shape) + @test_util.run_deprecated_v1 def testNproperty(self): alpha = [[1., 2, 3]] n = [[5.]] @@ -63,6 +67,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertEqual([1, 1], dist.total_count.get_shape()) self.assertAllClose(n, dist.total_count.eval()) + @test_util.run_deprecated_v1 def testAlphaProperty(self): alpha = [[1., 2, 3]] with self.cached_session(): @@ -70,6 +75,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertEqual([1, 3], dist.concentration.get_shape()) self.assertAllClose(alpha, dist.concentration.eval()) + @test_util.run_deprecated_v1 def testPmfNandCountsAgree(self): alpha = [[1., 2, 3]] n = [[5.]] @@ -83,6 +89,7 @@ class DirichletMultinomialTest(test.TestCase): "last-dimension must sum to `self.total_count`"): dist.prob([3., 3, 0]).eval() + @test_util.run_deprecated_v1 def testPmfNonIntegerCounts(self): alpha = [[1., 2, 3]] n = [[5.]] @@ -178,6 +185,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertAllClose([1 / 3., 2 / 5.], self.evaluate(pmf)) self.assertAllEqual([2], pmf.get_shape()) + @test_util.run_deprecated_v1 def testPmfForOneVoteIsTheMeanWithOneRecordInput(self): # The probabilities of one vote falling into class k is the mean for class # k. @@ -194,6 +202,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertAllEqual([3], mean.shape) self.assertAllEqual([], pmf.shape) + @test_util.run_deprecated_v1 def testMeanDoubleTwoVotes(self): # The probabilities of two votes falling into class k for # DirichletMultinomial(2, alpha) is twice as much as the probability of one @@ -215,6 +224,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertAllClose(mean2[class_num], 2 * mean1[class_num]) self.assertAllEqual([3], mean1.shape) + @test_util.run_deprecated_v1 def testCovarianceFromSampling(self): # We will test mean, cov, var, stddev on a DirichletMultinomial constructed # via broadcast between alpha, n. @@ -412,6 +422,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertLess(5 * self.evaluate(pmf_different), self.evaluate(pmf_same)) self.assertEqual((), pmf_same.get_shape()) + @test_util.run_deprecated_v1 def testNonStrictTurnsOffAllChecks(self): # Make totally invalid input. with self.cached_session(): @@ -421,6 +432,7 @@ class DirichletMultinomialTest(test.TestCase): dist = ds.DirichletMultinomial(n, alpha, validate_args=False) dist.prob(counts).eval() # Should not raise. + @test_util.run_deprecated_v1 def testSampleUnbiasedNonScalarBatch(self): with self.cached_session() as sess: dist = ds.DirichletMultinomial( @@ -450,6 +462,7 @@ class DirichletMultinomialTest(test.TestCase): self.assertAllClose( actual_covariance_, sample_covariance_, atol=0., rtol=0.20) + @test_util.run_deprecated_v1 def testSampleUnbiasedScalarBatch(self): with self.cached_session() as sess: dist = ds.DirichletMultinomial( diff --git a/tensorflow/python/kernel_tests/distributions/identity_bijector_test.py b/tensorflow/python/kernel_tests/distributions/identity_bijector_test.py index e35a8e1cdd..62b562387d 100644 --- a/tensorflow/python/kernel_tests/distributions/identity_bijector_test.py +++ b/tensorflow/python/kernel_tests/distributions/identity_bijector_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.ops.distributions import bijector_test_util from tensorflow.python.ops.distributions import identity_bijector from tensorflow.python.platform import test @@ -41,6 +42,7 @@ class IdentityBijectorTest(test.TestCase): self.evaluate( bijector.forward_log_det_jacobian(x, event_ndims=3))) + @test_util.run_deprecated_v1 def testScalarCongruency(self): with self.cached_session(): bijector = identity_bijector.Identity() diff --git a/tensorflow/python/kernel_tests/distributions/kullback_leibler_test.py b/tensorflow/python/kernel_tests/distributions/kullback_leibler_test.py index b8bc2e55cf..1e967de570 100644 --- a/tensorflow/python/kernel_tests/distributions/kullback_leibler_test.py +++ b/tensorflow/python/kernel_tests/distributions/kullback_leibler_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops.distributions import kullback_leibler from tensorflow.python.ops.distributions import normal @@ -45,6 +46,7 @@ class KLTest(test.TestCase): a = MyDist(loc=0.0, scale=1.0) self.assertEqual("OK", kullback_leibler.kl_divergence(a, a, name="OK")) + @test_util.run_deprecated_v1 def testDomainErrorExceptions(self): class MyDistException(normal.Normal): diff --git a/tensorflow/python/kernel_tests/distributions/normal_test.py b/tensorflow/python/kernel_tests/distributions/normal_test.py index 6625a88843..f2a193e69b 100644 --- a/tensorflow/python/kernel_tests/distributions/normal_test.py +++ b/tensorflow/python/kernel_tests/distributions/normal_test.py @@ -511,6 +511,7 @@ class NormalTest(test.TestCase): self.assertAllEqual(self.evaluate(normal.event_shape_tensor()), []) self.assertEqual(normal.event_shape, tensor_shape.TensorShape([])) + @test_util.run_deprecated_v1 def testNormalShapeWithPlaceholders(self): mu = array_ops.placeholder(dtype=dtypes.float32) sigma = array_ops.placeholder(dtype=dtypes.float32) diff --git a/tensorflow/python/kernel_tests/distributions/special_math_test.py b/tensorflow/python/kernel_tests/distributions/special_math_test.py index 0f800b95fa..d97fcfa655 100644 --- a/tensorflow/python/kernel_tests/distributions/special_math_test.py +++ b/tensorflow/python/kernel_tests/distributions/special_math_test.py @@ -104,6 +104,7 @@ class NdtriTest(test.TestCase): x = special_math.ndtri(p) self.assertAllClose(expected_x, self.evaluate(x), atol=0.) + @test_util.run_deprecated_v1 def testNdtriDynamicShape(self): """Verifies that ndtri computation is correct.""" with self.cached_session() as sess: @@ -213,9 +214,11 @@ class NdtrTest(test.TestCase): rtol=error_spec.rtol, atol=error_spec.atol) + @test_util.run_deprecated_v1 def test_float32(self): self._test_grid(np.float32, self._grid32, self._error32) + @test_util.run_deprecated_v1 def test_float64(self): self._test_grid(np.float64, self._grid64, self._error64) @@ -338,10 +341,12 @@ class NdtrGradientTest(test.TestCase): rtol=error_spec.rtol, atol=error_spec.atol) + @test_util.run_deprecated_v1 def test_float32(self): self._test_grad_accuracy(np.float32, self._grid, self._error32) self._test_grad_finite(np.float32) + @test_util.run_deprecated_v1 def test_float64(self): self._test_grad_accuracy(np.float64, self._grid, self._error64) self._test_grad_finite(np.float64) @@ -418,6 +423,7 @@ class LogCDFLaplaceTest(test.TestCase): rtol=error_spec.rtol, atol=error_spec.atol) + @test_util.run_deprecated_v1 def test_float32_lower_and_mid_segment_scipy_float32_ok(self): # Choose values mild enough that we can use scipy in float32, which will # allow for a high accuracy match to scipy (since we both use float32). @@ -427,6 +433,7 @@ class LogCDFLaplaceTest(test.TestCase): GridSpec(min=-10, max=self.CUTOFF_FLOAT32_UPPER - 5, shape=[100]), ErrorSpec(rtol=5e-4, atol=0)) + @test_util.run_deprecated_v1 def test_float32_all_segments_with_scipy_float64_ok(self): # Choose values outside the range where scipy float32 works. # Let scipy use float64. This means we @@ -437,6 +444,7 @@ class LogCDFLaplaceTest(test.TestCase): GridSpec(min=-50, max=self.CUTOFF_FLOAT32_UPPER + 5, shape=[100]), ErrorSpec(rtol=0.05, atol=0)) + @test_util.run_deprecated_v1 def test_float32_extreme_values_result_and_gradient_finite_and_nonzero(self): with self.cached_session() as sess: # On the lower branch, log_cdf_laplace(x) = x, so we know this will be @@ -456,6 +464,7 @@ class LogCDFLaplaceTest(test.TestCase): self.assertFalse(np.any(actual_ == 0)) self.assertFalse(np.any(grad_ == 0)) + @test_util.run_deprecated_v1 def test_float64_extreme_values_result_and_gradient_finite_and_nonzero(self): with self.cached_session() as sess: # On the lower branch, log_cdf_laplace(x) = x, so we know this will be diff --git a/tensorflow/python/kernel_tests/distributions/util_test.py b/tensorflow/python/kernel_tests/distributions/util_test.py index d3fa513f05..030ad601bf 100644 --- a/tensorflow/python/kernel_tests/distributions/util_test.py +++ b/tensorflow/python/kernel_tests/distributions/util_test.py @@ -59,6 +59,7 @@ def _logit(x): class AssertCloseTest(test.TestCase): + @test_util.run_deprecated_v1 def testAssertIntegerForm(self): # This should only be detected as an integer. x = array_ops.placeholder(dtypes.float32) @@ -112,6 +113,7 @@ class MaybeGetStaticTest(test.TestCase): self.assertAllClose( np.array(2.), du.maybe_get_static_value(x, dtype=np.float64)) + @test_util.run_deprecated_v1 def testGetStaticPlaceholder(self): x = array_ops.placeholder(dtype=dtypes.int32, shape=[1]) self.assertEqual(None, du.maybe_get_static_value(x)) @@ -235,6 +237,7 @@ class GetLogitsAndProbsTest(test.TestCase): probs=p4, multidimensional=True, validate_args=False) self.evaluate(prob) + @test_util.run_deprecated_v1 def testProbsMultidimShape(self): with self.cached_session(): with self.assertRaises(ValueError): @@ -249,6 +252,7 @@ class GetLogitsAndProbsTest(test.TestCase): probs=p, multidimensional=True, validate_args=True) prob.eval(feed_dict={p: np.ones([int(2**11+1)])}) + @test_util.run_deprecated_v1 def testLogitsMultidimShape(self): with self.cached_session(): with self.assertRaises(ValueError): @@ -266,6 +270,7 @@ class GetLogitsAndProbsTest(test.TestCase): class EmbedCheckCategoricalEventShapeTest(test.TestCase): + @test_util.run_deprecated_v1 def testTooSmall(self): with self.cached_session(): with self.assertRaises(ValueError): @@ -280,6 +285,7 @@ class EmbedCheckCategoricalEventShapeTest(test.TestCase): param) checked_param.eval(feed_dict={param: np.ones([1])}) + @test_util.run_deprecated_v1 def testTooLarge(self): with self.cached_session(): with self.assertRaises(ValueError): @@ -305,6 +311,7 @@ class EmbedCheckCategoricalEventShapeTest(test.TestCase): class EmbedCheckIntegerCastingClosedTest(test.TestCase): + @test_util.run_deprecated_v1 def testCorrectlyAssertsNonnegative(self): with self.cached_session(): with self.assertRaisesOpError("Elements must be non-negative"): @@ -313,6 +320,7 @@ class EmbedCheckIntegerCastingClosedTest(test.TestCase): x, target_dtype=dtypes.int16) x_checked.eval(feed_dict={x: np.array([1, -1], dtype=np.float16)}) + @test_util.run_deprecated_v1 def testCorrectlyAssersIntegerForm(self): with self.cached_session(): with self.assertRaisesOpError("Elements must be int16-equivalent."): @@ -321,6 +329,7 @@ class EmbedCheckIntegerCastingClosedTest(test.TestCase): x, target_dtype=dtypes.int16) x_checked.eval(feed_dict={x: np.array([1, 1.5], dtype=np.float16)}) + @test_util.run_deprecated_v1 def testCorrectlyAssertsLargestPossibleInteger(self): with self.cached_session(): with self.assertRaisesOpError("Elements cannot exceed 32767."): @@ -329,6 +338,7 @@ class EmbedCheckIntegerCastingClosedTest(test.TestCase): x, target_dtype=dtypes.int16) x_checked.eval(feed_dict={x: np.array([1, 2**15], dtype=np.int32)}) + @test_util.run_deprecated_v1 def testCorrectlyAssertsSmallestPossibleInteger(self): with self.cached_session(): with self.assertRaisesOpError("Elements cannot be smaller than 0."): @@ -369,6 +379,7 @@ class LogCombinationsTest(test.TestCase): class DynamicShapeTest(test.TestCase): + @test_util.run_deprecated_v1 def testSameDynamicShape(self): with self.cached_session(): scalar = constant_op.constant(2.0) @@ -493,6 +504,7 @@ class RotateTransposeTest(test.TestCase): self._np_rotate_transpose(x, shift), self.evaluate(y)) self.assertAllEqual(np.roll(x.shape, shift), y.get_shape().as_list()) + @test_util.run_deprecated_v1 def testRollDynamic(self): with self.cached_session() as sess: x = array_ops.placeholder(dtypes.float32) @@ -511,6 +523,7 @@ class RotateTransposeTest(test.TestCase): class PickVectorTest(test.TestCase): + @test_util.run_deprecated_v1 def testCorrectlyPicksVector(self): with self.cached_session(): x = np.arange(10, 12) @@ -529,36 +542,42 @@ class PickVectorTest(test.TestCase): class PreferStaticRankTest(test.TestCase): + @test_util.run_deprecated_v1 def testNonEmptyConstantTensor(self): x = array_ops.zeros((2, 3, 4)) rank = du.prefer_static_rank(x) self.assertIsInstance(rank, np.ndarray) self.assertEqual(3, rank) + @test_util.run_deprecated_v1 def testEmptyConstantTensor(self): x = constant_op.constant([]) rank = du.prefer_static_rank(x) self.assertIsInstance(rank, np.ndarray) self.assertEqual(1, rank) + @test_util.run_deprecated_v1 def testScalarTensor(self): x = constant_op.constant(1.) rank = du.prefer_static_rank(x) self.assertIsInstance(rank, np.ndarray) self.assertEqual(0, rank) + @test_util.run_deprecated_v1 def testDynamicRankEndsUpBeingNonEmpty(self): x = array_ops.placeholder(np.float64, shape=None) rank = du.prefer_static_rank(x) with self.cached_session(): self.assertAllEqual(2, rank.eval(feed_dict={x: np.zeros((2, 3))})) + @test_util.run_deprecated_v1 def testDynamicRankEndsUpBeingEmpty(self): x = array_ops.placeholder(np.int32, shape=None) rank = du.prefer_static_rank(x) with self.cached_session(): self.assertAllEqual(1, rank.eval(feed_dict={x: []})) + @test_util.run_deprecated_v1 def testDynamicRankEndsUpBeingScalar(self): x = array_ops.placeholder(np.int32, shape=None) rank = du.prefer_static_rank(x) @@ -568,36 +587,42 @@ class PreferStaticRankTest(test.TestCase): class PreferStaticShapeTest(test.TestCase): + @test_util.run_deprecated_v1 def testNonEmptyConstantTensor(self): x = array_ops.zeros((2, 3, 4)) shape = du.prefer_static_shape(x) self.assertIsInstance(shape, np.ndarray) self.assertAllEqual(np.array([2, 3, 4]), shape) + @test_util.run_deprecated_v1 def testEmptyConstantTensor(self): x = constant_op.constant([]) shape = du.prefer_static_shape(x) self.assertIsInstance(shape, np.ndarray) self.assertAllEqual(np.array([0]), shape) + @test_util.run_deprecated_v1 def testScalarTensor(self): x = constant_op.constant(1.) shape = du.prefer_static_shape(x) self.assertIsInstance(shape, np.ndarray) self.assertAllEqual(np.array([]), shape) + @test_util.run_deprecated_v1 def testDynamicShapeEndsUpBeingNonEmpty(self): x = array_ops.placeholder(np.float64, shape=None) shape = du.prefer_static_shape(x) with self.cached_session(): self.assertAllEqual((2, 3), shape.eval(feed_dict={x: np.zeros((2, 3))})) + @test_util.run_deprecated_v1 def testDynamicShapeEndsUpBeingEmpty(self): x = array_ops.placeholder(np.int32, shape=None) shape = du.prefer_static_shape(x) with self.cached_session(): self.assertAllEqual(np.array([0]), shape.eval(feed_dict={x: []})) + @test_util.run_deprecated_v1 def testDynamicShapeEndsUpBeingScalar(self): x = array_ops.placeholder(np.int32, shape=None) shape = du.prefer_static_shape(x) @@ -607,24 +632,28 @@ class PreferStaticShapeTest(test.TestCase): class PreferStaticValueTest(test.TestCase): + @test_util.run_deprecated_v1 def testNonEmptyConstantTensor(self): x = array_ops.zeros((2, 3, 4)) value = du.prefer_static_value(x) self.assertIsInstance(value, np.ndarray) self.assertAllEqual(np.zeros((2, 3, 4)), value) + @test_util.run_deprecated_v1 def testEmptyConstantTensor(self): x = constant_op.constant([]) value = du.prefer_static_value(x) self.assertIsInstance(value, np.ndarray) self.assertAllEqual(np.array([]), value) + @test_util.run_deprecated_v1 def testScalarTensor(self): x = constant_op.constant(1.) value = du.prefer_static_value(x) self.assertIsInstance(value, np.ndarray) self.assertAllEqual(np.array(1.), value) + @test_util.run_deprecated_v1 def testDynamicValueEndsUpBeingNonEmpty(self): x = array_ops.placeholder(np.float64, shape=None) value = du.prefer_static_value(x) @@ -632,12 +661,14 @@ class PreferStaticValueTest(test.TestCase): self.assertAllEqual(np.zeros((2, 3)), value.eval(feed_dict={x: np.zeros((2, 3))})) + @test_util.run_deprecated_v1 def testDynamicValueEndsUpBeingEmpty(self): x = array_ops.placeholder(np.int32, shape=None) value = du.prefer_static_value(x) with self.cached_session(): self.assertAllEqual(np.array([]), value.eval(feed_dict={x: []})) + @test_util.run_deprecated_v1 def testDynamicValueEndsUpBeingScalar(self): x = array_ops.placeholder(np.int32, shape=None) value = du.prefer_static_value(x) @@ -698,43 +729,55 @@ class FillTriangularTest(test.TestCase): self.assertAllClose(expected, actual_, rtol=1e-8, atol=1e-9) self.assertAllClose(x_, grad_actual_, rtol=1e-8, atol=1e-9) + @test_util.run_deprecated_v1 def testCorrectlyMakes1x1TriLower(self): self._run_test(self._rng.randn(3, int(1*2/2))) + @test_util.run_deprecated_v1 def testCorrectlyMakesNoBatchTriLower(self): self._run_test(self._rng.randn(int(4*5/2))) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatchTriLower(self): self._run_test(self._rng.randn(2, 3, int(3*4/2))) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatchTriLowerUnknownShape(self): self._run_test(self._rng.randn(2, 3, int(3*4/2)), use_deferred_shape=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatch7x7TriLowerUnknownShape(self): self._run_test(self._rng.randn(2, 3, int(7*8/2)), use_deferred_shape=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatch7x7TriLower(self): self._run_test(self._rng.randn(2, 3, int(7*8/2))) + @test_util.run_deprecated_v1 def testCorrectlyMakes1x1TriUpper(self): self._run_test(self._rng.randn(3, int(1*2/2)), upper=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesNoBatchTriUpper(self): self._run_test(self._rng.randn(int(4*5/2)), upper=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatchTriUpper(self): self._run_test(self._rng.randn(2, 2, int(3*4/2)), upper=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatchTriUpperUnknownShape(self): self._run_test(self._rng.randn(2, 2, int(3*4/2)), use_deferred_shape=True, upper=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatch7x7TriUpperUnknownShape(self): self._run_test(self._rng.randn(2, 3, int(7*8/2)), use_deferred_shape=True, upper=True) + @test_util.run_deprecated_v1 def testCorrectlyMakesBatch7x7TriUpper(self): self._run_test(self._rng.randn(2, 3, int(7*8/2)), upper=True) @@ -773,6 +816,7 @@ class ReduceWeightedLogSumExp(test.TestCase): m = np.squeeze(m, axis=axis) return m + np.log(sgn * sum_), sgn + @test_util.run_deprecated_v1 def testNoWeights(self): logx_ = np.array([[0., -1, 1000.], [0, 1, -1000.], @@ -903,6 +947,7 @@ class SoftplusTest(test.TestCase): self.assertAllEqual(np.ones_like(tf_softplus_inverse).astype(np.bool), np.isfinite(tf_softplus_inverse)) + @test_util.run_deprecated_v1 def testNumbers(self): for t in [np.float16, np.float32, np.float64]: lower = {np.float16: -15, np.float32: -50, np.float64: -50}.get(t, -100) @@ -933,6 +978,7 @@ class SoftplusTest(test.TestCase): ], use_gpu=True) + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session(): x = constant_op.constant( @@ -949,6 +995,7 @@ class SoftplusTest(test.TestCase): tf_logging.vlog(2, "softplus (float) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testInverseSoftplusGradientNeverNan(self): with self.cached_session(): # Note that this range contains both zero and inf. @@ -958,6 +1005,7 @@ class SoftplusTest(test.TestCase): # Equivalent to `assertAllFalse` (if it existed). self.assertAllEqual(np.zeros_like(grads).astype(np.bool), np.isnan(grads)) + @test_util.run_deprecated_v1 def testInverseSoftplusGradientFinite(self): with self.cached_session(): # This range of x is all finite, and so is 1 / x. So the diff --git a/tensorflow/python/kernel_tests/duplicate_op_test.py b/tensorflow/python/kernel_tests/duplicate_op_test.py index 654267a582..fef3127d4a 100644 --- a/tensorflow/python/kernel_tests/duplicate_op_test.py +++ b/tensorflow/python/kernel_tests/duplicate_op_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import os from tensorflow.python.framework import load_library +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.platform import resource_loader from tensorflow.python.platform import test @@ -27,6 +28,7 @@ from tensorflow.python.platform import test class DuplicateOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): library_filename = os.path.join(resource_loader.get_data_files_path(), 'duplicate_op.so') diff --git a/tensorflow/python/kernel_tests/dynamic_partition_op_test.py b/tensorflow/python/kernel_tests/dynamic_partition_op_test.py index 3622fde3f3..8c44819407 100644 --- a/tensorflow/python/kernel_tests/dynamic_partition_op_test.py +++ b/tensorflow/python/kernel_tests/dynamic_partition_op_test.py @@ -25,6 +25,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import gradients_impl @@ -34,6 +35,7 @@ from tensorflow.python.platform import test class DynamicPartitionTest(test.TestCase): + @test_util.run_deprecated_v1 def testSimpleOneDimensional(self): with self.session(use_gpu=True) as sess: data = constant_op.constant([0, 13, 2, 39, 4, 17], dtype=dtypes.float32) @@ -54,6 +56,7 @@ class DynamicPartitionTest(test.TestCase): self.assertEqual([None], partitions[2].get_shape().as_list()) self.assertEqual([None], partitions[3].get_shape().as_list()) + @test_util.run_deprecated_v1 def testSimpleTwoDimensional(self): with self.session(use_gpu=True) as sess: data = constant_op.constant([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], @@ -151,6 +154,7 @@ class DynamicPartitionTest(test.TestCase): dtype=np.float64).reshape(-1, 4), partition_vals[3]) + @test_util.run_deprecated_v1 def testHigherRank(self): np.random.seed(7) with self.session(use_gpu=True) as sess: @@ -287,6 +291,7 @@ class DynamicPartitionTest(test.TestCase): for i in range(40): self.assertAllEqual([], partition_vals[i]) + @test_util.run_deprecated_v1 def testErrorIndexOutOfRange(self): with self.cached_session() as sess: data = constant_op.constant([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], @@ -297,6 +302,7 @@ class DynamicPartitionTest(test.TestCase): with self.assertRaisesOpError(r"partitions\[2\] = 99 is not in \[0, 4\)"): self.evaluate(partitions) + @test_util.run_deprecated_v1 def testScalarIndexOutOfRange(self): with self.cached_session() as sess: bad = 17 @@ -305,6 +311,7 @@ class DynamicPartitionTest(test.TestCase): with self.assertRaisesOpError(r"partitions = 17 is not in \[0, 7\)"): self.evaluate(partitions) + @test_util.run_deprecated_v1 def testHigherRankIndexOutOfRange(self): with self.cached_session() as sess: shape = (2, 3) @@ -320,6 +327,7 @@ class DynamicPartitionTest(test.TestCase): r"partitions\[%d,%d\] = 17 is not in \[0, 7\)" % (i, j)): sess.run(partitions, feed_dict={indices: bad}) + @test_util.run_deprecated_v1 def testErrorWrongDimsIndices(self): data = constant_op.constant([[0], [1], [2]]) indices = constant_op.constant([[0], [0]]) diff --git a/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py b/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py index 3d063c4e0e..4f338880aa 100644 --- a/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py +++ b/tensorflow/python/kernel_tests/dynamic_stitch_op_test.py @@ -47,6 +47,7 @@ class DynamicStitchTestBase(object): # Dimension 0 is max(flatten(indices))+1. self.assertEqual([2], stitched_t.get_shape().as_list()) + @test_util.run_deprecated_v1 def testShapeInferenceForScalarWithNonConstantIndices(self): with test_util.use_gpu(): indices = [ @@ -134,6 +135,7 @@ class DynamicStitchTestBase(object): # Dimension 0 is max(flatten(indices))+1. self.assertEqual([8, 2], stitched_t.get_shape().as_list()) + @test_util.run_deprecated_v1 def testHigherRank(self): with self.session(use_gpu=True) as sess: indices = [ @@ -160,6 +162,7 @@ class DynamicStitchTestBase(object): for datum, grad in zip(data, sess.run(grads[3:])): self.assertAllEqual(7. * self.evaluate(datum), grad) + @test_util.run_deprecated_v1 def testErrorIndicesMultiDimensional(self): indices = [ constant_op.constant([0, 4, 7]), @@ -172,6 +175,7 @@ class DynamicStitchTestBase(object): with self.assertRaises(ValueError): self.stitch_op(indices, data) + @test_util.run_deprecated_v1 def testErrorDataNumDimsMismatch(self): indices = [ constant_op.constant([0, 4, 7]), @@ -184,6 +188,7 @@ class DynamicStitchTestBase(object): with self.assertRaises(ValueError): self.stitch_op(indices, data) + @test_util.run_deprecated_v1 def testErrorDataDimSizeMismatch(self): indices = [ constant_op.constant([0, 4, 5]), @@ -196,6 +201,7 @@ class DynamicStitchTestBase(object): with self.assertRaises(ValueError): self.stitch_op(indices, data) + @test_util.run_deprecated_v1 def testErrorDataAndIndicesSizeMismatch(self): indices = [ constant_op.constant([0, 4, 7]), @@ -233,6 +239,7 @@ class ParallelDynamicStitchTest(DynamicStitchTestBase, test.TestCase): # Dimension 0 is max(flatten(indices))+1. self.assertEqual([2], stitched_t.get_shape().as_list()) + @test_util.run_deprecated_v1 def testHigherRank(self): with self.session(use_gpu=True) as sess: indices = [ @@ -271,6 +278,7 @@ class ParallelDynamicStitchTest(DynamicStitchTestBase, test.TestCase): # Dimension 0 is max(flatten(indices))+1. self.assertEqual([2], stitched_t.get_shape().as_list()) + @test_util.run_deprecated_v1 def testHigherRankGPU(self): with self.cached_session() as sess: indices = [ diff --git a/tensorflow/python/kernel_tests/embedding_ops_test.py b/tensorflow/python/kernel_tests/embedding_ops_test.py index 39c0575cd5..6019245d0f 100644 --- a/tensorflow/python/kernel_tests/embedding_ops_test.py +++ b/tensorflow/python/kernel_tests/embedding_ops_test.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import embedding_ops @@ -87,16 +88,19 @@ class ScatterAddSubTest(test.TestCase): vals_shape[0], -1)[i, :]) self.assertTrue(all((p_init == result).ravel())) + @test_util.run_deprecated_v1 def testNoRepetitions(self): self._TestCase([2, 2], [1]) self._TestCase([4, 4, 4], [2, 0]) self._TestCase([43, 20, 10, 10], [42, 5, 6, 1, 3, 5, 7, 9]) + @test_util.run_deprecated_v1 def testWithRepetitions(self): self._TestCase([2, 2], [1, 1]) self._TestCase([5, 3, 9, 5], [2, 0, 4, 1, 3, 1, 4, 0, 4, 3]) self._TestCase([32, 4, 4], [31] * 8) + @test_util.run_deprecated_v1 def testRandom(self): # Random shapes of rank 4, random indices for _ in range(5): @@ -104,6 +108,7 @@ class ScatterAddSubTest(test.TestCase): indices = np.random.randint(shape[0], size=2 * shape[0]) self._TestCase(_AsLong(list(shape)), list(indices)) + @test_util.run_deprecated_v1 def testSubRandom(self): # Random shapes of rank 4, random indices for _ in range(5): @@ -111,6 +116,7 @@ class ScatterAddSubTest(test.TestCase): indices = np.random.randint(shape[0], size=2 * shape[0]) self._TestCase(_AsLong(list(shape)), list(indices), state_ops.scatter_sub) + @test_util.run_deprecated_v1 def testWrongShape(self): # Indices and values mismatch. var = variables.Variable( @@ -241,6 +247,7 @@ class EmbeddingLookupTest(test.TestCase): # both the ids are in the first shard, one of the resulting lookup # vector is going to be empty. The subsequent DivOp fails because of that. # TODO(keveman): Disabling the test until the underlying problem is fixed. + @test_util.run_deprecated_v1 def testSimpleSharded(self): with self.cached_session(): num_shards = 2 @@ -257,6 +264,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testMaxNorm(self): with self.cached_session(): embeddings = constant_op.constant([[2.0]]) @@ -267,6 +275,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(embedding.eval(), [[1.0]]) + @test_util.run_deprecated_v1 def testMaxNormNontrivial(self): with self.cached_session(): embeddings = constant_op.constant([[2.0, 4.0], [3.0, 1.0]]) @@ -280,6 +289,7 @@ class EmbeddingLookupTest(test.TestCase): normalized = embeddings / array_ops.stack([norms, norms], axis=1) self.assertAllEqual(embedding.eval(), 2 * self.evaluate(normalized)) + @test_util.run_deprecated_v1 def testSimpleShardedPartitionedVariable(self): with self.cached_session() as sess: num_shards = 2 @@ -302,6 +312,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testSimpleShardedPartitionedResourceVariable(self): with self.cached_session() as sess: num_shards = 2 @@ -325,6 +336,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testShardedModPartitioningInt32Ids(self): with self.cached_session(): num_shards = 5 @@ -347,6 +359,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testShardedModPartitioningInt64Ids(self): with self.cached_session(): num_shards = 5 @@ -369,6 +382,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testShardedDivPartitioningInt32Ids(self): with self.cached_session(): num_shards = 5 @@ -393,6 +407,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testShardedDivPartitioningInt32IdsPartitionedVariable(self): with self.cached_session(): num_shards = 5 @@ -418,6 +433,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testShardedDivPartitioningInt64Ids(self): with self.cached_session(): num_shards = 5 @@ -442,6 +458,7 @@ class EmbeddingLookupTest(test.TestCase): self.assertAllEqual(np_result, tf_result) self.assertShapeEqual(np_result, embedding) + @test_util.run_deprecated_v1 def testShardedDivPartitioningUnknownParamShape(self): with self.cached_session(): num_shards = 5 @@ -468,6 +485,7 @@ class EmbeddingLookupTest(test.TestCase): params, id_vals, num_shards, vocab_size, partition_strategy="div") self.assertAllEqual(np_result, tf_result) + @test_util.run_deprecated_v1 def testGradientsEmbeddingLookup(self): vocab_size = 9 num_ids = 10 @@ -488,6 +506,7 @@ class EmbeddingLookupTest(test.TestCase): x, x_shape, y, y_shape, x_init_value=x_init_value) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientsEmbeddingLookupWithComputedParams(self): vocab_size = 9 num_ids = 5 @@ -526,6 +545,7 @@ class EmbeddingLookupTest(test.TestCase): ids = constant_op.constant([0, 1, 1, 17], dtype=dtypes.int32) embedding_ops.embedding_lookup(p, ids) + @test_util.run_deprecated_v1 def testHigherRank(self): np.random.seed(8) with self.cached_session(): @@ -546,6 +566,7 @@ class EmbeddingLookupTest(test.TestCase): sharded = embedding_ops.embedding_lookup(split_params, ids).eval() self.assertAllEqual(simple, sharded) + @test_util.run_deprecated_v1 def testHigherRankMaxNorm(self): np.random.seed(8) with self.cached_session(): @@ -574,6 +595,7 @@ class EmbeddingLookupTest(test.TestCase): split_params, ids, max_norm=1.0).eval() self.assertAllEqual(simple, sharded) + @test_util.run_deprecated_v1 def testTransform(self): # This tests all combinations of: # - ids rank 0, 1, >1 @@ -648,6 +670,7 @@ class EmbeddingLookupSparseTest(test.TestCase): index += num_val return grouped_vals + @test_util.run_deprecated_v1 def testEmbeddingLookupSparse(self): vocab_size = 13 batch_size = 10 @@ -706,6 +729,7 @@ class EmbeddingLookupSparseTest(test.TestCase): atol = rtol self.assertAllClose(np_embedding_sum, tf_embedding_sum, rtol, atol) + @test_util.run_deprecated_v1 def testGradientsEmbeddingLookupSparse(self): vocab_size = 12 batch_size = 4 @@ -733,6 +757,7 @@ class EmbeddingLookupSparseTest(test.TestCase): x, x_shape, y, y_shape, x_init_value=x_init_value) self.assertLess(err, 1e-5 if dtype == dtypes.float64 else 2e-3) + @test_util.run_deprecated_v1 def testIncompatibleShapes(self): with self.cached_session(): x, _, _ = _EmbeddingParams(1, 10, dtype=dtypes.float32) @@ -820,6 +845,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): return sparse_ids, sparse_weights + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_return_zero_vector(self): with self.cached_session(): embedding_weights = self._random_weights() @@ -833,6 +859,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): [(1.0 * embedding_weights[0][0] + 2.0 * embedding_weights[0][1]) / 3.0, [0] * 4, [0] * 4, embedding_weights[0][2], [0] * 4]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_return_special_vector(self): with self.cached_session(): embedding_weights = self._random_weights() @@ -847,6 +874,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): 3.0, embedding_weights[0][3], embedding_weights[0][3], embedding_weights[0][2], embedding_weights[0][3]]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_no_weights(self): with self.cached_session(): embedding_weights = self._random_weights() @@ -861,6 +889,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): [0] * 4, embedding_weights[0][2], ( embedding_weights[0][0] + embedding_weights[0][1]) / 2.0]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_partitioned(self): with self.cached_session(): embedding_weights = self._random_weights(num_shards=3) @@ -875,6 +904,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): [0] * 4, [0] * 4, embedding_weights[2], (embedding_weights[0] + embedding_weights[1]) / 2.0]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_partitioned_inconsistent_weights(self): with self.cached_session(): embedding_weights = self._random_weights(num_shards=3) @@ -890,6 +920,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): self.assertRaises(ValueError, embedding_ops.safe_embedding_lookup_sparse, embedding_weights, sparse_ids, sparse_weights) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_3d_return_zero_vector(self): with self.cached_session(): embedding_weights = self._random_weights() @@ -903,6 +934,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): [0] * 4, [0] * 4 ], [embedding_weights[0][2], [0] * 4, [0] * 4]]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_3d_return_special_vector(self): with self.cached_session(): embedding_weights = self._random_weights() @@ -919,6 +951,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): embedding_weights[0][3] ]]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_3d_no_weights(self): with self.cached_session(): embedding_weights = self._random_weights() @@ -935,6 +968,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): (embedding_weights[0][0] + embedding_weights[0][1]) / 2.0, [0] * 4 ]]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_3d_partitioned(self): with self.cached_session(): embedding_weights = self._random_weights(num_shards=3) @@ -951,6 +985,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): (embedding_weights[0] + embedding_weights[1]) / 2.0, [0] * 4 ]]) + @test_util.run_deprecated_v1 def test_safe_embedding_lookup_sparse_3d_partitioned_inconsistent_weights( self): with self.cached_session(): @@ -970,6 +1005,7 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): class DynamicStitchOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testCint32Cpu(self): with self.session(use_gpu=False): indices = [ @@ -983,6 +1019,7 @@ class DynamicStitchOpTest(test.TestCase): self.assertAllEqual( data_flow_ops.dynamic_stitch(indices, values).eval(), [12, 23, 1, 2]) + @test_util.run_deprecated_v1 def testCint32Gpu(self): with self.session(use_gpu=True): indices = [ @@ -996,6 +1033,7 @@ class DynamicStitchOpTest(test.TestCase): self.assertAllEqual( data_flow_ops.dynamic_stitch(indices, values).eval(), [12, 23, 1, 2]) + @test_util.run_deprecated_v1 def testInt32Cpu(self): with self.session(use_gpu=False): indices = [ @@ -1009,6 +1047,7 @@ class DynamicStitchOpTest(test.TestCase): self.assertAllEqual( data_flow_ops.dynamic_stitch(indices, values).eval(), [12, 23, 1, 2]) + @test_util.run_deprecated_v1 def testInt32Gpu(self): with self.session(use_gpu=True): indices = [ @@ -1022,6 +1061,7 @@ class DynamicStitchOpTest(test.TestCase): self.assertAllEqual( data_flow_ops.dynamic_stitch(indices, values).eval(), [12, 23, 1, 2]) + @test_util.run_deprecated_v1 def testSumGradArgs(self): with self.session(use_gpu=False): indices = [ @@ -1036,6 +1076,7 @@ class DynamicStitchOpTest(test.TestCase): data_flow_ops.dynamic_stitch(indices, values).eval(), [2, 3, 1, 1]) # We expect that the values are merged in order. + @test_util.run_deprecated_v1 def testStitchOrder(self): with self.cached_session(): indices = [] @@ -1051,6 +1092,7 @@ class DynamicStitchOpTest(test.TestCase): class ParallelDynamicStitchOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testCint32Cpu(self): with self.session(use_gpu=False): indices = [ @@ -1065,6 +1107,7 @@ class ParallelDynamicStitchOpTest(test.TestCase): data_flow_ops.parallel_dynamic_stitch(indices, values).eval(), [12, 23, 1, 2, 34, 3, 45]) + @test_util.run_deprecated_v1 def testInt32Cpu(self): with self.session(use_gpu=False): indices = [ @@ -1079,6 +1122,7 @@ class ParallelDynamicStitchOpTest(test.TestCase): data_flow_ops.parallel_dynamic_stitch(indices, values).eval(), [12, 23, 1, 2, 3, 34, 45, 56]) + @test_util.run_deprecated_v1 def testSimple(self): with self.session(use_gpu=False): indices = [ops.convert_to_tensor([0, 1]), ops.convert_to_tensor([2, 3])] diff --git a/tensorflow/python/kernel_tests/extract_image_patches_grad_test.py b/tensorflow/python/kernel_tests/extract_image_patches_grad_test.py index 7d9d4e5175..7ba2dc6c20 100644 --- a/tensorflow/python/kernel_tests/extract_image_patches_grad_test.py +++ b/tensorflow/python/kernel_tests/extract_image_patches_grad_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import random_seed as random_seed_lib +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -78,6 +79,7 @@ class ExtractImagePatchesGradTest(test.TestCase): }, ] + @test_util.run_deprecated_v1 def testGradient(self): # Set graph seed for determinism. random_seed = 42 @@ -102,6 +104,7 @@ class ExtractImagePatchesGradTest(test.TestCase): print('extract_image_patches gradient err: %.4e' % err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testConstructGradientWithLargeImages(self): batch_size = 4 height = 1024 diff --git a/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py b/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py index 272adecfb8..0d5928aefa 100644 --- a/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py +++ b/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_nn_ops from tensorflow.python.ops import gradient_checker @@ -281,6 +282,7 @@ class FractionalAvgTest(test.TestCase): self._ValidateFractionalAvgPoolResult(rand_mat, [1, 2, 2, 1], pseudo_random, overlapping) + @test_util.run_deprecated_v1 def testDifferentInputTensorShape(self): """Runs the operation in one session with different input tensor shapes.""" with self.cached_session() as sess: @@ -427,6 +429,7 @@ class FractionalAvgPoolGradTest(test.TestCase): self.assertShapeEqual(input_backprop, fap_input_backprop_tensor) self.assertAllClose(input_backprop, fap_input_backprop) + @test_util.run_deprecated_v1 def testAllInputOptionsThroughGradientError(self): input_shape = (1, 7, 13, 1) input_data = self._GenerateRandomInputTensor(input_shape) @@ -455,6 +458,7 @@ class FractionalAvgPoolGradTest(test.TestCase): delta=1e-2) self.assertLess(gradient_error, error_margin) + @test_util.run_deprecated_v1 def testDifferentTensorShapesThroughGradientError(self): pseudo_random = True overlapping = True @@ -486,6 +490,7 @@ class FractionalAvgPoolGradTest(test.TestCase): delta=1e-2) self.assertLess(gradient_error, error_margin) + @test_util.run_deprecated_v1 def testLargePoolingRatioThroughGradientError(self): input_shape = (1, 17, 23, 1) input_data = self._GenerateRandomInputTensor(input_shape) diff --git a/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py b/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py index 9b1e73b318..fa886cc215 100644 --- a/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py +++ b/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_nn_ops from tensorflow.python.ops import gradient_checker @@ -278,6 +279,7 @@ class FractionalMaxPoolTest(test.TestCase): self._ValidateFractionalMaxPoolResult(rand_mat, [1, 2, 2, 1], pseudo_random, overlapping) + @test_util.run_deprecated_v1 def testDifferentInputTensorShape(self): """Runs the operation in one session with different input tensor shapes.""" with self.cached_session() as sess: @@ -430,6 +432,7 @@ class FractionalMaxPoolGradTest(test.TestCase): self.assertShapeEqual(input_backprop, fmp_input_backprop_tensor) self.assertAllClose(input_backprop, fmp_input_backprop) + @test_util.run_deprecated_v1 def testAllInputOptionsThroughGradientError(self): input_shape = (1, 7, 13, 1) input_data = self._GenerateUniqueRandomInputTensor(input_shape) @@ -460,6 +463,7 @@ class FractionalMaxPoolGradTest(test.TestCase): delta=1e-2) self.assertLess(gradient_error, error_margin) + @test_util.run_deprecated_v1 def testDifferentTensorShapesThroughGradientError(self): pseudo_random = True overlapping = True @@ -493,6 +497,7 @@ class FractionalMaxPoolGradTest(test.TestCase): delta=1e-2) self.assertLess(gradient_error, error_margin) + @test_util.run_deprecated_v1 def testLargePoolingRatioThroughGradientError(self): input_shape = (1, 17, 23, 1) input_data = self._GenerateUniqueRandomInputTensor(input_shape) diff --git a/tensorflow/python/kernel_tests/functional_ops_test.py b/tensorflow/python/kernel_tests/functional_ops_test.py index 23b3c7e1cc..c489623fe5 100644 --- a/tensorflow/python/kernel_tests/functional_ops_test.py +++ b/tensorflow/python/kernel_tests/functional_ops_test.py @@ -101,6 +101,7 @@ class FunctionalOpsTest(test.TestCase): (elems, other_elems), initializer) self.assertAllEqual([1.0, 2.0, 3.0], self.evaluate(r)) + @test_util.run_deprecated_v1 def testFoldl_Scoped(self): with self.cached_session() as sess: with variable_scope.variable_scope("root") as varscope: @@ -153,6 +154,7 @@ class FunctionalOpsTest(test.TestCase): initializer) self.assertAllEqual(1, self.evaluate(r)) + @test_util.run_deprecated_v1 def testFoldr_Scoped(self): with self.cached_session() as sess: with variable_scope.variable_scope("root") as varscope: @@ -173,6 +175,7 @@ class FunctionalOpsTest(test.TestCase): self.assertAllEqual(1282, self.evaluate(r)) # pylint: disable=unnecessary-lambda + @test_util.run_deprecated_v1 def testFold_Grad(self): with self.cached_session(): elems = constant_op.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], name="data") @@ -214,6 +217,7 @@ class FunctionalOpsTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "not a scalar"): functional_ops.map_fn(lambda x: x, 1) + @test_util.run_deprecated_v1 def testMap_Scoped(self): with self.cached_session() as sess: @@ -245,6 +249,7 @@ class FunctionalOpsTest(test.TestCase): self.assertEqual(len(variables.trainable_variables()), 1) self.assertAllEqual(doubles, self.evaluate(r)) + @test_util.run_deprecated_v1 def testMap_Grad(self): with self.cached_session(): param = constant_op.constant(2.0) @@ -381,6 +386,7 @@ class FunctionalOpsTest(test.TestCase): ValueError, "two structures don't have the same nested structure"): functional_ops.scan(lambda a, x: (a, -a), elems, initializer) + @test_util.run_deprecated_v1 def testScan_Scoped(self): with self.cached_session() as sess: with variable_scope.variable_scope("root") as varscope: @@ -425,6 +431,7 @@ class FunctionalOpsTest(test.TestCase): # t_1 == 1, b == 4.5, y == 0.5, returns b * y * x = 9 self.assertAllClose([1., 1., 2.25, 9.], self.evaluate(r)) + @test_util.run_deprecated_v1 def testScan_Control(self): with self.cached_session() as sess: s = array_ops.placeholder(dtypes.float32, shape=[None]) @@ -436,6 +443,7 @@ class FunctionalOpsTest(test.TestCase): np.array([1.0, 3.0, 9.0]), sess.run(c, {s: [1, 3, 3], b: True})) + @test_util.run_deprecated_v1 def testScan_Grad(self): with self.cached_session(): elems = constant_op.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], name="data") @@ -448,6 +456,7 @@ class FunctionalOpsTest(test.TestCase): r = gradients_impl.gradients(r, v)[0] self.assertAllEqual(873.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testScanGradientWithPartStopGradient(self): a = variables.Variable(0.0, name="a") b = variables.Variable(0.0, name="b") @@ -477,6 +486,7 @@ class FunctionalOpsTest(test.TestCase): y = functional_ops.map_fn(lambda e: e, x) self.assertAllEqual(y.get_shape(), self.evaluate(y).shape) + @test_util.run_deprecated_v1 def testMapUnknownShape(self): x = array_ops.placeholder(dtypes.float32) y = functional_ops.map_fn(lambda e: e, x) @@ -484,6 +494,7 @@ class FunctionalOpsTest(test.TestCase): @test_util.disable_control_flow_v2("b/119323354") @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testMapEmptyScalar(self): map_return = functional_ops.map_fn(lambda x: 1, constant_op.constant([])) self.assertAllEqual([0], map_return.get_shape().dims) @@ -492,6 +503,7 @@ class FunctionalOpsTest(test.TestCase): # TODO(akshayka): this test fails in eager: the iterable is of length 0 so # so the body of the while loop never executes @test_util.disable_control_flow_v2("b/119323354") + @test_util.run_deprecated_v1 def testMapEmptyTensor(self): with self.cached_session(): map_return = functional_ops.map_fn(lambda x: array_ops.zeros([3, 2]), @@ -512,6 +524,7 @@ class FunctionalOpsTest(test.TestCase): # TODO(akshayka): this test fails in eager: the iterable is of length 0 so # so the body of the while loop never executes + @test_util.run_deprecated_v1 def testScanEmptyTensor(self): with self.cached_session(): x = functional_ops.scan( @@ -519,6 +532,7 @@ class FunctionalOpsTest(test.TestCase): self.assertAllEqual([0, 2, 4], x.get_shape()) self.assertAllEqual(x.get_shape(), self.evaluate(x).shape) + @test_util.run_deprecated_v1 def testScanUnknownShape(self): x = array_ops.placeholder(dtypes.float32) initializer = array_ops.placeholder(dtypes.float32) @@ -529,6 +543,7 @@ class FunctionalOpsTest(test.TestCase): y = functional_ops.scan(fn, x, initializer=initializer) self.assertIs(None, y.get_shape().dims) + @test_util.run_deprecated_v1 def testScanVaryingShape(self): with self.cached_session() as sess: x = array_ops.placeholder(dtype=dtypes.float32, shape=[None, 2]) @@ -545,6 +560,7 @@ class FunctionalOpsTest(test.TestCase): sess.run([result, result_t, result_grad, result_t_grad], feed_dict={x: [[1.0, 2.0]]}) + @test_util.run_deprecated_v1 def testRemoteFunction(self): worker_config = config_pb2.ConfigProto() worker_config.device_count["CPU"] = 2 @@ -571,6 +587,7 @@ class FunctionalOpsTest(test.TestCase): mul = self.evaluate(remote_op) self.assertEqual(mul, [6]) + @test_util.run_deprecated_v1 def testRemoteFunctionDirectSession(self): worker_config = config_pb2.ConfigProto() worker_config.device_count["CPU"] = 2 @@ -595,6 +612,7 @@ class FunctionalOpsTest(test.TestCase): mul = self.evaluate(remote_op) self.assertEqual(mul, [6]) + @test_util.run_deprecated_v1 def testRemoteFunctionSameDeviceDirectSession(self): @function.Defun(dtypes.int32, dtypes.int32) @@ -680,6 +698,7 @@ class FunctionalOpsTest(test.TestCase): ret = self.evaluate(remote_op) self.assertAllEqual(ret, [b"a"]) + @test_util.run_deprecated_v1 def testRemoteFunctionCrossProcess(self): workers, _ = test_util.create_local_cluster(2, 1) @@ -703,6 +722,7 @@ class FunctionalOpsTest(test.TestCase): mul = self.evaluate(remote_op) self.assertEqual(mul, 9) + @test_util.run_deprecated_v1 def testIf(self): @function.Defun(dtypes.float32) @@ -742,6 +762,7 @@ class FunctionalOpsTest(test.TestCase): self.assertAllEqual(Run(sess, 20.), 210.) self.assertAllEqual(Run(sess, 100.), 5050.) + @test_util.run_deprecated_v1 def testWhileLowering(self): def Run(n, fetch_by_name): @@ -776,6 +797,7 @@ class FunctionalOpsTest(test.TestCase): self.assertAllEqual(Run(100., False), 5050.) self.assertAllEqual(Run(100., True), 5050.) + @test_util.run_deprecated_v1 def testWhileError(self): for use_gpu in (True, False): with ops.Graph().as_default() as g: @@ -922,6 +944,7 @@ class FunctionalOpsTest(test.TestCase): self.assertTrue("TestBody_Cond" in names) self.assertTrue("TestBody_Body" in names) + @test_util.run_deprecated_v1 def testForCapturedInputs(self): v = variables.Variable(1.0) @@ -996,12 +1019,15 @@ class FunctionalOpsTest(test.TestCase): tf_for_ans = self._tfMLP(xval, wsval, bsval, rewrite_with_while) self.assertAllClose(np_ans, tf_for_ans) + @test_util.run_deprecated_v1 def testForMLP(self): self._testForMLP(False) + @test_util.run_deprecated_v1 def testForMLPWhile(self): self._testForMLP(True) + @test_util.run_deprecated_v1 def testForError(self): @function.Defun(dtypes.int32, dtypes.float32) @@ -1024,6 +1050,7 @@ class FunctionalOpsTest(test.TestCase): "For loop body returned 2 arguments. Expected: 1"): functional_ops.For(0, 10, 1, [0.0], ReturnsTooManyArgs)[0].eval() + @test_util.run_deprecated_v1 def testGradient(self): @function.Defun(dtypes.float32) @@ -1049,6 +1076,7 @@ class FunctionalOpsTest(test.TestCase): # below test cases. class PartitionedCallTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasicSingleDevice(self): @function.Defun(*[dtypes.float32] * 2) @@ -1064,6 +1092,7 @@ class PartitionedCallTest(test.TestCase): constant_op.constant(2.)], f=Body)) self.assertEqual(output, 6.) + @test_util.run_deprecated_v1 def testBasicMultiDevice(self): config = config_pb2.ConfigProto(device_count={"CPU": 3}) @@ -1107,6 +1136,7 @@ class PartitionedCallTest(test.TestCase): constant_op.constant(2.)], f=Body)) self.assertEqual(output, 6.) + @test_util.run_deprecated_v1 def testBasicNoDeviceAnnotations(self): @function.Defun(*[dtypes.float32] * 2) @@ -1121,6 +1151,7 @@ class PartitionedCallTest(test.TestCase): constant_op.constant(2.)], f=Body)) self.assertEqual(output, 6.) + @test_util.run_deprecated_v1 def testShardsRunOnRequestedDevices(self): config = config_pb2.ConfigProto(device_count={"CPU": 4}) @@ -1150,6 +1181,7 @@ class PartitionedCallTest(test.TestCase): self.assertIn(compat.as_bytes("CPU:1"), outputs[1]) self.assertIn(compat.as_bytes("CPU:2"), outputs[2]) + @test_util.run_deprecated_v1 def testAssignAddResourceVariable(self): v = resource_variable_ops.ResourceVariable(1.0) @@ -1201,6 +1233,7 @@ class PartitionedCallTest(test.TestCase): self.assertAllEqual(expected, result) # Use an invalid executor name to test the plumbing of the executor_type attr. + @test_util.run_deprecated_v1 def testExecutorTypeAttrExecutorNotFound(self): @function.Defun(dtypes.int32) def AddFive(x): diff --git a/tensorflow/python/kernel_tests/gather_nd_op_test.py b/tensorflow/python/kernel_tests/gather_nd_op_test.py index 532d8903ee..320ffc9674 100644 --- a/tensorflow/python/kernel_tests/gather_nd_op_test.py +++ b/tensorflow/python/kernel_tests/gather_nd_op_test.py @@ -27,6 +27,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import variables @@ -54,6 +55,7 @@ class GatherNdTest(test.TestCase): self._testSimpleDtype(np.complex128) self._testSimpleDtype("|S") # byte strings in python2 + 3 + @test_util.run_deprecated_v1 def testEmptyIndicesAndParamsOKButJustEmptyParamsFails(self): with self.session(use_gpu=True): params = np.ones((3, 3), dtype=np.float32) @@ -190,6 +192,7 @@ class GatherNdTest(test.TestCase): def assertIndexedSlices(self, t): self.assertIsInstance(t, ops.IndexedSlices) + @test_util.run_deprecated_v1 def testUnknownIndices(self): params = constant_op.constant([[0, 1, 2]]) indices = array_ops.placeholder(dtypes.int32) @@ -198,6 +201,7 @@ class GatherNdTest(test.TestCase): self.assertEqual(None, shape.ndims) self.assertEqual(None, tensor_shape.dimension_value(shape[0])) + @test_util.run_deprecated_v1 def testBadIndicesCPU(self): with self.session(use_gpu=False): params = [0, 1, 2] @@ -220,6 +224,7 @@ class GatherNdTest(test.TestCase): r"indices\[0,1\] = \[7\] does not index into param shape \[3\]"): self.evaluate(gather_nd) + @test_util.run_deprecated_v1 def testBadIndicesWithSlicesCPU(self): with self.session(use_gpu=False): params = [[0, 1, 2]] @@ -242,6 +247,7 @@ class GatherNdTest(test.TestCase): r"indices\[0,2\] = \[1\] does not index into param shape \[1,3\]"): self.evaluate(gather_nd) + @test_util.run_deprecated_v1 def testGradientsRank2Elements(self): indices = constant_op.constant([[0, 0], [1, 1]], dtype=dtypes.int32) inputs = constant_op.constant([[1, 2], [3, 4]], dtype=dtypes.float64) @@ -253,6 +259,7 @@ class GatherNdTest(test.TestCase): with self.session(use_gpu=True): assert np.array_equal(expected_grads, self.evaluate(grads)) + @test_util.run_deprecated_v1 def testGradientsRank2Slices(self): indices = constant_op.constant([[1], [0]], dtype=dtypes.int32) inputs = constant_op.constant([[1, 2], [3, 4]], dtype=dtypes.float64) @@ -265,6 +272,7 @@ class GatherNdTest(test.TestCase): self.assertIndexedSlices(grads) self.assertAllEqual(expected_grads, ops.convert_to_tensor(grads).eval()) + @test_util.run_deprecated_v1 def testGradientsRank3Elements(self): indices = constant_op.constant( [[[0, 1], [1, 0]], [[0, 0], [1, 1]]], dtype=dtypes.int32) @@ -280,6 +288,7 @@ class GatherNdTest(test.TestCase): with self.session(use_gpu=True): self.assertAllEqual(expected_grads, self.evaluate(grads)) + @test_util.run_deprecated_v1 def testGradientsRank7Elements(self): # Shape [1,1,2,1,1,2,2] indices = constant_op.constant( @@ -309,6 +318,7 @@ class GatherNdTest(test.TestCase): with self.session(use_gpu=True): self.assertAllEqual(expected_grads, self.evaluate(grads)) + @test_util.run_deprecated_v1 def testGradientsInt64Indices(self): indices = constant_op.constant( [[[0, 1], [1, 0]], [[0, 0], [1, 1]]], dtype=dtypes.int64) @@ -324,6 +334,7 @@ class GatherNdTest(test.TestCase): with self.session(use_gpu=True): self.assertAllEqual(expected_grads, self.evaluate(grads)) + @test_util.run_deprecated_v1 def testGradientsRank2SlicesWithEmptySpace(self): indices = constant_op.constant([[2], [0], [5]], dtype=dtypes.int32) inputs = constant_op.constant( diff --git a/tensorflow/python/kernel_tests/gather_op_test.py b/tensorflow/python/kernel_tests/gather_op_test.py index 326e4aacd2..fc86068c3f 100644 --- a/tensorflow/python/kernel_tests/gather_op_test.py +++ b/tensorflow/python/kernel_tests/gather_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.platform import test @@ -87,6 +88,7 @@ class GatherTest(test.TestCase): expected_shape = data.shape[:axis] + (4,) + data.shape[axis + 1:] self.assertEqual(expected_shape, gather_t.get_shape()) + @test_util.run_deprecated_v1 def testHigherRank(self): # We check that scalar and empty indices shapes work as well shape = (2, 1, 3, 2) @@ -148,6 +150,7 @@ class GatherTest(test.TestCase): atol=2e-6, rtol=2e-6) + @test_util.run_deprecated_v1 def testString(self): params = np.array([[b"asdf", b"zxcv"], [b"qwer", b"uiop"]]) with self.cached_session(): @@ -156,6 +159,7 @@ class GatherTest(test.TestCase): self.assertAllEqual([b"asdf", b"qwer"], array_ops.gather(params, 0, axis=1).eval()) + @test_util.run_deprecated_v1 def testUInt32AndUInt64(self): for unsigned_type in (dtypes.uint32, dtypes.uint64): params = self._buildParams( @@ -165,12 +169,14 @@ class GatherTest(test.TestCase): array_ops.gather(params, 1, axis=0).eval()) self.assertAllEqual([1, 7], array_ops.gather(params, 0, axis=1).eval()) + @test_util.run_deprecated_v1 def testUnknownIndices(self): params = constant_op.constant([[0, 1, 2]]) indices = array_ops.placeholder(dtypes.int32) gather_t = array_ops.gather(params, indices) self.assertEqual(None, gather_t.get_shape()) + @test_util.run_deprecated_v1 def testUnknownAxis(self): params = constant_op.constant([[0, 1, 2]]) indices = constant_op.constant([[0, 0], [0, 0]]) @@ -204,6 +210,7 @@ class GatherTest(test.TestCase): with self.assertRaisesOpError(r"indices\[0,0\] = 7 is not in \[0, 3\)"): array_ops.gather(params, [[7]], axis=1).eval() + @test_util.run_deprecated_v1 def testBadAxis(self): with self.session(use_gpu=True): params = [0, 1, 2] @@ -220,6 +227,7 @@ class GatherTest(test.TestCase): array_ops.gather(params_ph, indices, axis=bad_axis).eval( feed_dict={params_ph: params}) + @test_util.run_deprecated_v1 def testEmptySlices(self): with self.session(use_gpu=True): for dtype in _TEST_TYPES: diff --git a/tensorflow/python/kernel_tests/gradient_correctness_test.py b/tensorflow/python/kernel_tests/gradient_correctness_test.py index 12b8a4c8e3..0148de5047 100644 --- a/tensorflow/python/kernel_tests/gradient_correctness_test.py +++ b/tensorflow/python/kernel_tests/gradient_correctness_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -29,6 +30,7 @@ from tensorflow.python.platform import test class GradientCorrectnessTest(test.TestCase): + @test_util.run_deprecated_v1 def testMultipleOutputChainedGradients(self): with self.cached_session() as sess: x = constant_op.constant(1.0, dtype=dtypes.float32) @@ -40,18 +42,21 @@ class GradientCorrectnessTest(test.TestCase): # [dexp(x)/dx + d(log(exp(x)))/dx] @ x=1 == exp(1) + 1 self.assertAllClose(grad_vals[0], exp1_plus_one) + @test_util.run_deprecated_v1 def testIdentityGradient(self): x = constant_op.constant(3.) dx_dx, = gradients_impl.gradients(x, x) with self.cached_session() as sess: self.assertAllClose(1., self.evaluate(dx_dx)) + @test_util.run_deprecated_v1 def testIntegerIdentityGradient(self): x = constant_op.constant(3) dx_dx, = gradients_impl.gradients(x, x) with self.cached_session() as sess: self.assertAllClose(1, self.evaluate(dx_dx)) + @test_util.run_deprecated_v1 def testGradientWithIntegerPath(self): x = constant_op.constant([3.9, 4.1]) k = math_ops.to_float(math_ops.to_int32(x)) @@ -60,6 +65,7 @@ class GradientCorrectnessTest(test.TestCase): with self.cached_session() as sess: self.assertAllClose([3., 4.], self.evaluate(dy_dx)) + @test_util.run_deprecated_v1 def testNoIntegerGradient1(self): x = constant_op.constant([3.9, 4.1]) k = math_ops.to_float(math_ops.to_int32(x)) @@ -67,6 +73,7 @@ class GradientCorrectnessTest(test.TestCase): dy_dx, = gradients_impl.gradients(y, x) self.assertIsNone(dy_dx) + @test_util.run_deprecated_v1 def testNoIntegerGradient2(self): k = constant_op.constant([3, 4]) x = math_ops.to_float(k) @@ -74,18 +81,21 @@ class GradientCorrectnessTest(test.TestCase): dy_dk, = gradients_impl.gradients(y, k) self.assertIsNone(dy_dk) + @test_util.run_deprecated_v1 def testNoIntegerGradient3(self): k = constant_op.constant([3, 4]) m = k * k dm_dk, = gradients_impl.gradients(m, k) self.assertIsNone(dm_dk) + @test_util.run_deprecated_v1 def testNoIntegerGradient4(self): k = constant_op.constant([3, 4]) m = k * k * k dm_dk, = gradients_impl.gradients(m, k) self.assertIsNone(dm_dk) + @test_util.run_deprecated_v1 def testNoIntegerGradient5(self): k = constant_op.constant([3, 4]) m = k * k @@ -93,6 +103,7 @@ class GradientCorrectnessTest(test.TestCase): dn_dk, = gradients_impl.gradients(n, k) self.assertIsNone(dn_dk) + @test_util.run_deprecated_v1 def testNoIntegerGradient6(self): k = constant_op.constant(3) x = math_ops.to_float(k) diff --git a/tensorflow/python/kernel_tests/identity_n_op_py_test.py b/tensorflow/python/kernel_tests/identity_n_op_py_test.py index 518733cd8e..a1110d640f 100644 --- a/tensorflow/python/kernel_tests/identity_n_op_py_test.py +++ b/tensorflow/python/kernel_tests/identity_n_op_py_test.py @@ -21,12 +21,14 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test class IdentityNOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testInt32String_6(self): with self.cached_session() as sess: [value0, value1] = sess.run( @@ -36,6 +38,7 @@ class IdentityNOpTest(test.TestCase): self.assertAllEqual( np.array([b"a", b"b", b"C", b"d", b"E", b"f", b"g"]), value1) + @test_util.run_deprecated_v1 def testInt32_shapes(self): with self.cached_session() as sess: inp0 = constant_op.constant([10, 20, 30, 40, 50, 60], shape=[2, 3]) @@ -50,6 +53,7 @@ class IdentityNOpTest(test.TestCase): np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]), value2) + @test_util.run_deprecated_v1 def testString(self): source = [b"A", b"b", b"C", b"d", b"E", b"f"] with self.cached_session() as sess: diff --git a/tensorflow/python/kernel_tests/identity_op_py_test.py b/tensorflow/python/kernel_tests/identity_op_py_test.py index 88ea10c22a..1a6794e896 100644 --- a/tensorflow/python/kernel_tests/identity_op_py_test.py +++ b/tensorflow/python/kernel_tests/identity_op_py_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import variables @@ -30,17 +31,20 @@ from tensorflow.python.platform import test class IdentityOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testInt32_6(self): with self.cached_session(): value = array_ops.identity([1, 2, 3, 4, 5, 6]).eval() self.assertAllEqual(np.array([1, 2, 3, 4, 5, 6]), value) + @test_util.run_deprecated_v1 def testInt32_2_3(self): with self.cached_session(): inp = constant_op.constant([10, 20, 30, 40, 50, 60], shape=[2, 3]) value = array_ops.identity(inp).eval() self.assertAllEqual(np.array([[10, 20, 30], [40, 50, 60]]), value) + @test_util.run_deprecated_v1 def testString(self): source = [b"A", b"b", b"C", b"d", b"E", b"f"] with self.cached_session(): @@ -58,6 +62,7 @@ class IdentityOpTest(test.TestCase): self.assertEquals(shape, array_ops.identity(np.array(array_2x3)).get_shape()) + @test_util.run_deprecated_v1 def testRefIdentityShape(self): with self.cached_session(): shape = [2, 3] diff --git a/tensorflow/python/kernel_tests/init_ops_test.py b/tensorflow/python/kernel_tests/init_ops_test.py index 87c7bbef3c..09b9944baa 100644 --- a/tensorflow/python/kernel_tests/init_ops_test.py +++ b/tensorflow/python/kernel_tests/init_ops_test.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.layers import convolutional from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops @@ -106,6 +107,7 @@ def _init_sampler(tc, init, num): class ConstantInitializersTest(test.TestCase): + @test_util.run_deprecated_v1 def testZerosInitializer(self): with self.session(use_gpu=True): shape = [2, 3] @@ -114,6 +116,7 @@ class ConstantInitializersTest(test.TestCase): x.initializer.run() self.assertAllEqual(x.eval(), np.zeros(shape)) + @test_util.run_deprecated_v1 def testOnesInitializer(self): with self.session(use_gpu=True): shape = [2, 3] @@ -122,6 +125,7 @@ class ConstantInitializersTest(test.TestCase): x.initializer.run() self.assertAllEqual(x.eval(), np.ones(shape)) + @test_util.run_deprecated_v1 def testConstantZeroInitializer(self): with self.session(use_gpu=True): shape = [2, 3] @@ -130,6 +134,7 @@ class ConstantInitializersTest(test.TestCase): x.initializer.run() self.assertAllEqual(x.eval(), np.zeros(shape)) + @test_util.run_deprecated_v1 def testConstantOneInitializer(self): with self.session(use_gpu=True): shape = [2, 3] @@ -138,6 +143,7 @@ class ConstantInitializersTest(test.TestCase): x.initializer.run() self.assertAllEqual(x.eval(), np.ones(shape)) + @test_util.run_deprecated_v1 def testConstantIntInitializer(self): with self.session(use_gpu=True): shape = [2, 3] @@ -150,6 +156,7 @@ class ConstantInitializersTest(test.TestCase): self.assertEqual(x.dtype.base_dtype, dtypes.int32) self.assertAllEqual(x.eval(), 7 * np.ones(shape, dtype=np.int32)) + @test_util.run_deprecated_v1 def testConstantTupleInitializer(self): with self.session(use_gpu=True): shape = [3] @@ -173,6 +180,7 @@ class ConstantInitializersTest(test.TestCase): for a, e in zip(actual, expected): self.assertEqual(a, e) + @test_util.run_deprecated_v1 def testNDimConstantInitializer(self): value = [0, 1, 2, 3, 4, 5] shape = [2, 3] @@ -199,6 +207,7 @@ class ConstantInitializersTest(test.TestCase): e = expected[i] if i < len(expected) else expected[-1] self.assertEqual(a, e) + @test_util.run_deprecated_v1 def testNDimConstantInitializerLessValues(self): value = [0, 1, 2, 3, 4, 5] shape = [2, 4] @@ -222,6 +231,7 @@ class ConstantInitializersTest(test.TestCase): shape=shape, initializer=init) + @test_util.run_deprecated_v1 def testNDimConstantInitializerMoreValues(self): value = [0, 1, 2, 3, 4, 5, 6, 7] shape = [2, 3] @@ -243,18 +253,21 @@ class ConstantInitializersTest(test.TestCase): class RandomNormalInitializationTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.random_normal_initializer(0.0, 1.0, seed=1, dtype=dtype) init2 = init_ops.random_normal_initializer(0.0, 1.0, seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2)) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.random_normal_initializer(0.0, 1.0, seed=1, dtype=dtype) init2 = init_ops.random_normal_initializer(0.0, 1.0, seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2)) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.random_normal_initializer(0.0, 1.0) self.assertFalse(duplicated_initializer(self, init, 1)) @@ -270,6 +283,7 @@ class RandomNormalInitializationTest(test.TestCase): class TruncatedNormalInitializationTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.truncated_normal_initializer( @@ -278,6 +292,7 @@ class TruncatedNormalInitializationTest(test.TestCase): 0.0, 1.0, seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2)) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.truncated_normal_initializer( @@ -286,6 +301,7 @@ class TruncatedNormalInitializationTest(test.TestCase): 0.0, 1.0, seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2)) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.truncated_normal_initializer(0.0, 1.0) self.assertFalse(duplicated_initializer(self, init, 1)) @@ -301,18 +317,21 @@ class TruncatedNormalInitializationTest(test.TestCase): class RandomUniformInitializationTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64, dtypes.int64]: init1 = init_ops.random_uniform_initializer(0, 7, seed=1, dtype=dtype) init2 = init_ops.random_uniform_initializer(0, 7, seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2)) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64, dtypes.int32, dtypes.int64]: init1 = init_ops.random_uniform_initializer(0, 7, seed=1, dtype=dtype) init2 = init_ops.random_uniform_initializer(0, 7, seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2)) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.random_uniform_initializer(0.0, 1.0) self.assertFalse(duplicated_initializer(self, init, 1)) @@ -320,6 +339,7 @@ class RandomUniformInitializationTest(test.TestCase): class UniformUnitScalingInitializationTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.uniform_unit_scaling_initializer(seed=1, dtype=dtype) @@ -331,6 +351,7 @@ class UniformUnitScalingInitializationTest(test.TestCase): 1.5, seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init3, init4)) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.uniform_unit_scaling_initializer(seed=1, dtype=dtype) @@ -341,6 +362,7 @@ class UniformUnitScalingInitializationTest(test.TestCase): self.assertFalse(identicaltest(self, init1, init3)) self.assertFalse(identicaltest(self, init2, init3)) + @test_util.run_deprecated_v1 def testZeroSize(self): shape = [0, 2] with self.cached_session(): @@ -351,6 +373,7 @@ class UniformUnitScalingInitializationTest(test.TestCase): variables.global_variables_initializer().run() self.assertAllEqual(shape, self.evaluate(x).shape) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.uniform_unit_scaling_initializer() self.assertFalse(duplicated_initializer(self, init, 1)) @@ -364,6 +387,7 @@ class UniformUnitScalingInitializationTest(test.TestCase): class VarianceScalingInitializationTest(test.TestCase): + @test_util.run_deprecated_v1 def testTruncatedNormalDistribution(self): shape = [100, 100] expect_mean = 0. @@ -381,6 +405,7 @@ class VarianceScalingInitializationTest(test.TestCase): self.assertNear(np.mean(x), expect_mean, err=1e-2) self.assertNear(np.var(x), expect_var, err=1e-2) + @test_util.run_deprecated_v1 def testNormalDistribution(self): shape = [100, 100] expect_mean = 0. @@ -397,6 +422,7 @@ class VarianceScalingInitializationTest(test.TestCase): self.assertNear(np.mean(x), expect_mean, err=1e-2) self.assertNear(np.var(x), expect_var, err=1e-2) + @test_util.run_deprecated_v1 def testUntruncatedNormalDistribution(self): shape = [100, 100] expect_mean = 0. @@ -414,6 +440,7 @@ class VarianceScalingInitializationTest(test.TestCase): self.assertNear(np.mean(x), expect_mean, err=1e-2) self.assertNear(np.var(x), expect_var, err=1e-2) + @test_util.run_deprecated_v1 def testUniformDistribution(self): shape = [100, 100] expect_mean = 0. @@ -449,6 +476,7 @@ class RangeTest(test.TestCase): self._Range(100, 500, 100), np.array([100, 200, 300, 400]))) self.assertEqual(math_ops.range(0, 5, 1).dtype, dtypes.int32) + @test_util.run_deprecated_v1 def testLimitOnly(self): with self.session(use_gpu=True): self.assertAllEqual(np.arange(5), math_ops.range(5).eval()) @@ -583,18 +611,21 @@ class DeviceTest(test.TestCase): class OrthogonalInitializerTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.orthogonal_initializer(seed=1, dtype=dtype) init2 = init_ops.orthogonal_initializer(seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2, (10, 10))) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.orthogonal_initializer(seed=1, dtype=dtype) init2 = init_ops.orthogonal_initializer(seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2, (10, 10))) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.orthogonal_initializer() self.assertFalse(duplicated_initializer(self, init, 1, (10, 10))) @@ -608,6 +639,7 @@ class OrthogonalInitializerTest(test.TestCase): with self.session(graph=ops.Graph(), use_gpu=True): self.assertRaises(ValueError, init1, shape=[5]) + @test_util.run_deprecated_v1 def testGain(self): shape = (10, 10) for dtype in [dtypes.float32, dtypes.float64]: @@ -618,6 +650,7 @@ class OrthogonalInitializerTest(test.TestCase): t2 = init2(shape).eval() self.assertAllClose(t1, t2 / 3.14) + @test_util.run_deprecated_v1 def testShapesValues(self): for dtype in [dtypes.float32, dtypes.float64]: for shape in [(10, 10), (10, 9, 8), (100, 5, 5), (50, 40), (40, 50)]: @@ -639,18 +672,21 @@ class OrthogonalInitializerTest(test.TestCase): class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_delta_orthogonal(seed=1, dtype=dtype) init2 = init_ops.convolutional_delta_orthogonal(seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2, (3, 3, 10, 10))) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_delta_orthogonal(seed=1, dtype=dtype) init2 = init_ops.convolutional_delta_orthogonal(seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2, (3, 3, 10, 10))) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.convolutional_delta_orthogonal() self.assertFalse(duplicated_initializer(self, init, 1, (3, 3, 10, 10))) @@ -665,6 +701,7 @@ class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): with self.session(graph=ops.Graph(), use_gpu=True): self.assertRaises(ValueError, init1, shape=[3, 3, 6, 5]) + @test_util.run_deprecated_v1 def testGain(self): shape = (3, 3, 10, 10) for dtype in [dtypes.float32, dtypes.float64]: @@ -676,6 +713,7 @@ class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): t2 = init2(shape).eval() self.assertAllClose(t1, t2 / 3.14) + @test_util.run_deprecated_v1 def testShapesValues(self): gain = 3.14 for dtype in [dtypes.float32]: @@ -711,6 +749,7 @@ class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): # Check isometry of the delta-orthogonal kernel. self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testNonuniformity(self): value = 0 abs_value = 0 @@ -738,18 +777,21 @@ class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): class ConvolutionOrthogonal1dInitializerTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_orthogonal_1d(seed=1, dtype=dtype) init2 = init_ops.convolutional_orthogonal_1d(seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2, (3, 10, 10))) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_orthogonal_1d(seed=1, dtype=dtype) init2 = init_ops.convolutional_orthogonal_1d(seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2, (3, 10, 10))) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.convolutional_orthogonal_1d() self.assertFalse(duplicated_initializer(self, init, 1, (3, 10, 10))) @@ -764,6 +806,7 @@ class ConvolutionOrthogonal1dInitializerTest(test.TestCase): with self.session(graph=ops.Graph(), use_gpu=True): self.assertRaises(ValueError, init1, shape=[3, 6, 5]) + @test_util.run_deprecated_v1 def testGain(self): shape = (3, 10, 10) for dtype in [dtypes.float32, dtypes.float64]: @@ -775,6 +818,7 @@ class ConvolutionOrthogonal1dInitializerTest(test.TestCase): t2 = init2(shape).eval() self.assertAllClose(t1, t2 / 3.14) + @test_util.run_deprecated_v1 def testNonuniformity(self): value = 0 abs_value = 0 @@ -799,6 +843,7 @@ class ConvolutionOrthogonal1dInitializerTest(test.TestCase): # Compute the sum of the absolute values of 'count' determinants self.assertAllClose(abs_value, count, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testShapesValues(self): def circular_pad(input_, width, kernel_size): """Pad input_ for computing (circular) convolution. @@ -852,18 +897,21 @@ class ConvolutionOrthogonal1dInitializerTest(test.TestCase): class ConvolutionOrthogonal2dInitializerTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_orthogonal_2d(seed=1, dtype=dtype) init2 = init_ops.convolutional_orthogonal_2d(seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2, (3, 3, 10, 10))) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_orthogonal_2d(seed=1, dtype=dtype) init2 = init_ops.convolutional_orthogonal_2d(seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2, (3, 3, 10, 10))) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.convolutional_orthogonal_2d() self.assertFalse(duplicated_initializer(self, init, 1, (3, 3, 10, 10))) @@ -878,6 +926,7 @@ class ConvolutionOrthogonal2dInitializerTest(test.TestCase): with self.session(graph=ops.Graph(), use_gpu=True): self.assertRaises(ValueError, init1, shape=[3, 3, 6, 5]) + @test_util.run_deprecated_v1 def testGain(self): shape = (3, 3, 10, 10) for dtype in [dtypes.float32, dtypes.float64]: @@ -889,6 +938,7 @@ class ConvolutionOrthogonal2dInitializerTest(test.TestCase): t2 = init2(shape).eval() self.assertAllClose(t1, t2 / 3.14) + @test_util.run_deprecated_v1 def testShapesValues(self): def circular_pad(input_, width, kernel_size): """Pad input_ for computing (circular) convolution. @@ -947,18 +997,21 @@ class ConvolutionOrthogonal2dInitializerTest(test.TestCase): class ConvolutionOrthogonal3dInitializerTest(test.TestCase): + @test_util.run_deprecated_v1 def testInitializerIdentical(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_orthogonal_3d(seed=1, dtype=dtype) init2 = init_ops.convolutional_orthogonal_3d(seed=1, dtype=dtype) self.assertTrue(identicaltest(self, init1, init2, (3, 3, 3, 10, 10))) + @test_util.run_deprecated_v1 def testInitializerDifferent(self): for dtype in [dtypes.float32, dtypes.float64]: init1 = init_ops.convolutional_orthogonal_3d(seed=1, dtype=dtype) init2 = init_ops.convolutional_orthogonal_3d(seed=2, dtype=dtype) self.assertFalse(identicaltest(self, init1, init2, (3, 3, 3, 10, 10))) + @test_util.run_deprecated_v1 def testDuplicatedInitializer(self): init = init_ops.convolutional_orthogonal_3d() self.assertFalse(duplicated_initializer(self, init, 1, (3, 3, 3, 10, 10))) @@ -973,6 +1026,7 @@ class ConvolutionOrthogonal3dInitializerTest(test.TestCase): with self.session(graph=ops.Graph(), use_gpu=True): self.assertRaises(ValueError, init1, shape=[3, 3, 3, 6, 5]) + @test_util.run_deprecated_v1 def testGain(self): shape = (3, 3, 3, 10, 10) for dtype in [dtypes.float32, dtypes.float64]: @@ -984,6 +1038,7 @@ class ConvolutionOrthogonal3dInitializerTest(test.TestCase): t2 = init2(shape).eval() self.assertAllClose(t1, t2 / 3.14) + @test_util.run_deprecated_v1 def testNonuniformity(self): value = 0 abs_value = 0 @@ -1008,6 +1063,7 @@ class ConvolutionOrthogonal3dInitializerTest(test.TestCase): # Compute the sum of the absolute values of 'count' determinants self.assertAllClose(abs_value, count, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testShapesValues(self): def circular_pad(input_, width, kernel_size): """Padding input_ for computing circular convolution. @@ -1083,12 +1139,14 @@ class IdentityInitializerTest(test.TestCase): self.assertRaises(ValueError, init, shape=[5]) self.assertRaises(ValueError, init, shape=[]) + @test_util.run_deprecated_v1 def testNonSquare(self): init = init_ops.identity_initializer() shape = (10, 5) with self.session(graph=ops.Graph(), use_gpu=True): self.assertAllClose(init(shape).eval(), np.eye(*shape)) + @test_util.run_deprecated_v1 def testGain(self): shape = (10, 10) for dtype in [dtypes.float32, dtypes.float64]: @@ -1099,6 +1157,7 @@ class IdentityInitializerTest(test.TestCase): with self.session(graph=ops.Graph(), use_gpu=True): self.assertAllClose(init_custom(shape).eval(), np.eye(*shape) * 0.9) + @test_util.run_deprecated_v1 def testPartitions(self): shape = (10, 10) init = init_ops.identity_initializer() diff --git a/tensorflow/python/kernel_tests/inplace_ops_test.py b/tensorflow/python/kernel_tests/inplace_ops_test.py index e0c36d3d2e..9eaaac7a24 100644 --- a/tensorflow/python/kernel_tests/inplace_ops_test.py +++ b/tensorflow/python/kernel_tests/inplace_ops_test.py @@ -31,6 +31,7 @@ from tensorflow.python.platform import test as test_lib class InplaceOpsTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBasicUpdate(self): for dtype in [dtypes.float32, dtypes.int32, dtypes.int64]: with self.session(use_gpu=True): @@ -48,6 +49,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): y[5, :] = 7 self.assertAllClose(x.eval(), y) + @test_util.run_deprecated_v1 def testBasicUpdateBool(self): with self.session(use_gpu=True): x = array_ops.ones([7, 3], dtypes.bool) @@ -65,6 +67,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): y[5, :] = False self.assertAllClose(x.eval(), y) + @test_util.run_deprecated_v1 def testBasicAdd(self): for dtype in [dtypes.float32, dtypes.int32, dtypes.int64]: with self.cached_session(use_gpu=True): @@ -84,6 +87,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): y[:, :] += 99 self.assertAllClose(x.eval(), y) + @test_util.run_deprecated_v1 def testBasicSub(self): for dtype in [dtypes.float32, dtypes.int32, dtypes.int64]: with self.cached_session(use_gpu=True): @@ -103,6 +107,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): y[:, :] -= 99 self.assertAllClose(x.eval(), y) + @test_util.run_deprecated_v1 def testRandom(self): with self.session(use_gpu=True): d0, d1, d2 = 100, 3, 5 @@ -123,6 +128,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): y[idx, :] -= val self.assertAllClose(x.eval(), y) + @test_util.run_deprecated_v1 def testRandom1D(self): with self.session(use_gpu=True): d0 = 100 @@ -164,6 +170,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): "i and x shape doesn't match"): _ = inplace_ops.inplace_update([[1.]], [0, 1], [[10]]).eval() + @test_util.run_deprecated_v1 def testEmpty(self): for dtype in [ dtypes.float32, dtypes.float64, dtypes.int32, dtypes.int64, dtypes.bool, diff --git a/tensorflow/python/kernel_tests/io_ops_test.py b/tensorflow/python/kernel_tests/io_ops_test.py index a6b477062e..c5df5231bf 100644 --- a/tensorflow/python/kernel_tests/io_ops_test.py +++ b/tensorflow/python/kernel_tests/io_ops_test.py @@ -23,6 +23,7 @@ import os import shutil import tempfile +from tensorflow.python.framework import test_util from tensorflow.python.ops import io_ops from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -30,6 +31,7 @@ from tensorflow.python.util import compat class IoOpsTest(test.TestCase): + @test_util.run_deprecated_v1 def testReadFile(self): cases = ['', 'Some contents', 'Неки садржаји на српском'] for contents in cases: @@ -78,6 +80,7 @@ class IoOpsTest(test.TestCase): compat.as_bytes(files[i].name) for i in range(len(files)) if i in indices) + @test_util.run_deprecated_v1 def testMatchingFiles(self): cases = [ 'ABcDEF.GH', 'ABzDEF.GH', 'ABasdfjklDEF.GH', 'AB3DEF.GH', 'AB4DEF.GH', diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_addition_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_addition_test.py index 628ed998c5..627349c69b 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_addition_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_addition_test.py @@ -19,6 +19,7 @@ from __future__ import print_function import numpy as np +from tensorflow.python.framework import test_util from tensorflow.python.ops import linalg_ops from tensorflow.python.ops.linalg import linalg as linalg_lib from tensorflow.python.ops.linalg import linear_operator_addition @@ -69,6 +70,7 @@ class LinearOperatorAdditionCorrectnessTest(test.TestCase): with self.assertRaisesRegexp(TypeError, "contain only LinearOperator"): add_operators([1, 2]) + @test_util.run_deprecated_v1 def test_two_diag_operators(self): op_a = linalg.LinearOperatorDiag( [1., 1.], is_positive_definite=True, name="A") @@ -89,6 +91,7 @@ class LinearOperatorAdditionCorrectnessTest(test.TestCase): # Enforce particular name for this simple case self.assertEqual("Add/B__A/", op.name) + @test_util.run_deprecated_v1 def test_three_diag_operators(self): op1 = linalg.LinearOperatorDiag( [1., 1.], is_positive_definite=True, name="op1") @@ -109,6 +112,7 @@ class LinearOperatorAdditionCorrectnessTest(test.TestCase): # Positive definite ==> non-singular self.assertTrue(op.is_non_singular) + @test_util.run_deprecated_v1 def test_diag_tril_diag(self): op1 = linalg.LinearOperatorDiag( [1., 1.], is_non_singular=True, name="diag_a") @@ -134,6 +138,7 @@ class LinearOperatorAdditionCorrectnessTest(test.TestCase): # Since no custom hint was provided, we default to None (unknown). self.assertEqual(None, op.is_non_singular) + @test_util.run_deprecated_v1 def test_matrix_diag_tril_diag_uses_custom_name(self): op0 = linalg.LinearOperatorFullMatrix( [[-1., -1.], [-1., -1.]], name="matrix") @@ -217,6 +222,7 @@ class LinearOperatorOrderOfAdditionTest(test.TestCase): self.assertEqual(1, len(op_sum)) self.assertIsInstance(op_sum[0], linalg.LinearOperatorLowerTriangular) + @test_util.run_deprecated_v1 def test_cannot_add_everything_so_return_more_than_one_operator(self): diag1 = linalg.LinearOperatorDiag([1.]) diag2 = linalg.LinearOperatorDiag([2.]) @@ -261,6 +267,7 @@ class AddAndReturnScaledIdentityTest(test.TestCase): def setUp(self): self._adder = linear_operator_addition._AddAndReturnScaledIdentity() + @test_util.run_deprecated_v1 def test_identity_plus_identity(self): id1 = linalg.LinearOperatorIdentity(num_rows=2) id2 = linalg.LinearOperatorIdentity(num_rows=2, batch_shape=[3]) @@ -279,6 +286,7 @@ class AddAndReturnScaledIdentityTest(test.TestCase): self.assertTrue(operator.is_non_singular) self.assertEqual("my_operator", operator.name) + @test_util.run_deprecated_v1 def test_identity_plus_scaled_identity(self): id1 = linalg.LinearOperatorIdentity(num_rows=2, batch_shape=[3]) id2 = linalg.LinearOperatorScaledIdentity(num_rows=2, multiplier=2.2) @@ -297,6 +305,7 @@ class AddAndReturnScaledIdentityTest(test.TestCase): self.assertTrue(operator.is_non_singular) self.assertEqual("my_operator", operator.name) + @test_util.run_deprecated_v1 def test_scaled_identity_plus_scaled_identity(self): id1 = linalg.LinearOperatorScaledIdentity( num_rows=2, multiplier=[2.2, 2.2, 2.2]) @@ -322,6 +331,7 @@ class AddAndReturnDiagTest(test.TestCase): def setUp(self): self._adder = linear_operator_addition._AddAndReturnDiag() + @test_util.run_deprecated_v1 def test_identity_plus_identity_returns_diag(self): id1 = linalg.LinearOperatorIdentity(num_rows=2) id2 = linalg.LinearOperatorIdentity(num_rows=2, batch_shape=[3]) @@ -340,6 +350,7 @@ class AddAndReturnDiagTest(test.TestCase): self.assertTrue(operator.is_non_singular) self.assertEqual("my_operator", operator.name) + @test_util.run_deprecated_v1 def test_diag_plus_diag(self): diag1 = rng.rand(2, 3, 4) diag2 = rng.rand(4) @@ -366,6 +377,7 @@ class AddAndReturnTriLTest(test.TestCase): def setUp(self): self._adder = linear_operator_addition._AddAndReturnTriL() + @test_util.run_deprecated_v1 def test_diag_plus_tril(self): diag = linalg.LinearOperatorDiag([1., 2.]) tril = linalg.LinearOperatorLowerTriangular([[10., 0.], [30., 0.]]) @@ -389,6 +401,7 @@ class AddAndReturnMatrixTest(test.TestCase): def setUp(self): self._adder = linear_operator_addition._AddAndReturnMatrix() + @test_util.run_deprecated_v1 def test_diag_plus_diag(self): diag1 = linalg.LinearOperatorDiag([1., 2.]) diag2 = linalg.LinearOperatorDiag([-1., 3.]) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py index 09867435a7..6366083ac5 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py @@ -21,6 +21,7 @@ import contextlib import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import spectral_ops_test_util @@ -129,6 +130,7 @@ class LinearOperatorCirculantTestSelfAdjointOperator( return operator, mat + @test_util.run_deprecated_v1 def test_simple_hermitian_spectrum_gives_operator_with_zero_imag_part(self): with self.cached_session(): spectrum = math_ops.cast([1., 1j, -1j], dtypes.complex64) @@ -196,6 +198,7 @@ class LinearOperatorCirculantTestHermitianSpectrum( return operator, mat + @test_util.run_deprecated_v1 def test_simple_hermitian_spectrum_gives_operator_with_zero_imag_part(self): with self.cached_session(): spectrum = math_ops.cast([1., 1j, -1j], dtypes.complex64) @@ -251,6 +254,7 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( return operator, mat + @test_util.run_deprecated_v1 def test_simple_hermitian_spectrum_gives_operator_with_zero_imag_part(self): with self.cached_session(): spectrum = math_ops.cast([1., 1j, -1j], dtypes.complex64) @@ -262,6 +266,7 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( np.testing.assert_allclose( 0, self.evaluate(imag_matrix), rtol=0, atol=eps * 3) + @test_util.run_deprecated_v1 def test_simple_positive_real_spectrum_gives_self_adjoint_pos_def_oper(self): with self.cached_session() as sess: spectrum = math_ops.cast([6., 4, 2], dtypes.complex64) @@ -274,6 +279,7 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( operator.assert_positive_definite().run() # Should not fail operator.assert_self_adjoint().run() # Should not fail + @test_util.run_deprecated_v1 def test_defining_operator_using_real_convolution_kernel(self): with self.cached_session(): convolution_kernel = [1., 2., 1.] @@ -304,6 +310,7 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( np.testing.assert_allclose( 0, self.evaluate(imag_matrix), rtol=0, atol=eps * 3 * 4) + @test_util.run_deprecated_v1 def test_convolution_kernel_same_as_first_row_of_to_dense(self): spectrum = [[3., 2., 1.], [2., 1.5, 1.]] with self.cached_session(): @@ -315,6 +322,7 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( self.assertAllEqual((2, 3, 3), c.get_shape()) self.assertAllClose(h.eval(), self.evaluate(c)[:, :, 0]) + @test_util.run_deprecated_v1 def test_assert_non_singular_fails_for_singular_operator(self): spectrum = math_ops.cast([0, 4, 2j + 2], dtypes.complex64) operator = linalg.LinearOperatorCirculant(spectrum) @@ -322,12 +330,14 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( with self.assertRaisesOpError("Singular operator"): operator.assert_non_singular().run() + @test_util.run_deprecated_v1 def test_assert_non_singular_does_not_fail_for_non_singular_operator(self): spectrum = math_ops.cast([-3j, 4, 2j + 2], dtypes.complex64) operator = linalg.LinearOperatorCirculant(spectrum) with self.cached_session(): operator.assert_non_singular().run() # Should not fail + @test_util.run_deprecated_v1 def test_assert_positive_definite_fails_for_non_positive_definite(self): spectrum = math_ops.cast([6., 4, 2j], dtypes.complex64) operator = linalg.LinearOperatorCirculant(spectrum) @@ -335,6 +345,7 @@ class LinearOperatorCirculantTestNonHermitianSpectrum( with self.assertRaisesOpError("Not positive definite"): operator.assert_positive_definite().run() + @test_util.run_deprecated_v1 def test_assert_positive_definite_does_not_fail_when_pos_def(self): spectrum = math_ops.cast([6., 4, 2j + 2], dtypes.complex64) operator = linalg.LinearOperatorCirculant(spectrum) @@ -529,6 +540,7 @@ class LinearOperatorCirculant2DTestNonHermitianSpectrum( return operator, mat + @test_util.run_deprecated_v1 def test_real_hermitian_spectrum_gives_real_symmetric_operator(self): with self.cached_session() as sess: # This is a real and hermitian spectrum. @@ -546,6 +558,7 @@ class LinearOperatorCirculant2DTestNonHermitianSpectrum( np.testing.assert_allclose(0, imag_matrix, atol=1e-6) self.assertAllClose(matrix, matrix_transpose, atol=0) + @test_util.run_deprecated_v1 def test_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session() as sess: # This is a real and hermitian spectrum. @@ -560,6 +573,7 @@ class LinearOperatorCirculant2DTestNonHermitianSpectrum( matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllClose(matrix, matrix_h, atol=0) + @test_util.run_deprecated_v1 def test_assert_non_singular_fails_for_singular_operator(self): spectrum = math_ops.cast([[0, 4], [2j + 2, 3.]], dtypes.complex64) operator = linalg.LinearOperatorCirculant2D(spectrum) @@ -567,12 +581,14 @@ class LinearOperatorCirculant2DTestNonHermitianSpectrum( with self.assertRaisesOpError("Singular operator"): operator.assert_non_singular().run() + @test_util.run_deprecated_v1 def test_assert_non_singular_does_not_fail_for_non_singular_operator(self): spectrum = math_ops.cast([[-3j, 4], [2j + 2, 3.]], dtypes.complex64) operator = linalg.LinearOperatorCirculant2D(spectrum) with self.cached_session(): operator.assert_non_singular().run() # Should not fail + @test_util.run_deprecated_v1 def test_assert_positive_definite_fails_for_non_positive_definite(self): spectrum = math_ops.cast([[6., 4], [2j, 3.]], dtypes.complex64) operator = linalg.LinearOperatorCirculant2D(spectrum) @@ -580,6 +596,7 @@ class LinearOperatorCirculant2DTestNonHermitianSpectrum( with self.assertRaisesOpError("Not positive definite"): operator.assert_positive_definite().run() + @test_util.run_deprecated_v1 def test_assert_positive_definite_does_not_fail_when_pos_def(self): spectrum = math_ops.cast([[6., 4], [2j + 2, 3.]], dtypes.complex64) operator = linalg.LinearOperatorCirculant2D(spectrum) @@ -618,6 +635,7 @@ class LinearOperatorCirculant3DTest(test.TestCase): with spectral_ops_test_util.fft_kernel_label_map(): yield sess + @test_util.run_deprecated_v1 def test_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session() as sess: # This is a real and hermitian spectrum. @@ -635,6 +653,7 @@ class LinearOperatorCirculant3DTest(test.TestCase): self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) self.assertAllClose(matrix, matrix_h) + @test_util.run_deprecated_v1 def test_defining_operator_using_real_convolution_kernel(self): with self.cached_session(): convolution_kernel = linear_operator_test_util.random_normal( @@ -653,6 +672,7 @@ class LinearOperatorCirculant3DTest(test.TestCase): self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) np.testing.assert_allclose(0, np.imag(matrix), atol=1e-6) + @test_util.run_deprecated_v1 def test_defining_spd_operator_by_taking_real_part(self): with self.cached_session() as sess: # S is real and positive. diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_composition_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_composition_test.py index 3f19dc4bff..214b73aa2f 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_composition_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_composition_test.py @@ -21,6 +21,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops.linalg import linalg as linalg_lib @@ -179,6 +180,7 @@ class NonSquareLinearOperatorCompositionTest( return operator, mat + @test_util.run_deprecated_v1 def test_static_shapes(self): operators = [ linalg.LinearOperatorFullMatrix(rng.rand(2, 3, 4)), @@ -187,6 +189,7 @@ class NonSquareLinearOperatorCompositionTest( operator = linalg.LinearOperatorComposition(operators) self.assertAllEqual((2, 3, 5), operator.shape) + @test_util.run_deprecated_v1 def test_shape_tensors_when_statically_available(self): operators = [ linalg.LinearOperatorFullMatrix(rng.rand(2, 3, 4)), @@ -196,6 +199,7 @@ class NonSquareLinearOperatorCompositionTest( with self.cached_session(): self.assertAllEqual((2, 3, 5), operator.shape_tensor().eval()) + @test_util.run_deprecated_v1 def test_shape_tensors_when_only_dynamically_available(self): mat_1 = rng.rand(1, 2, 3, 4) mat_2 = rng.rand(1, 2, 4, 5) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py index 80889a162f..dcbc0dd7c9 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py @@ -17,6 +17,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.ops import math_ops @@ -80,6 +81,7 @@ class LinearOperatorDiagTest( with self.assertRaisesOpError("non-positive real.*not positive definite"): operator.assert_positive_definite().run() + @test_util.run_deprecated_v1 def test_assert_positive_definite_does_not_raise_if_pd_and_complex(self): with self.cached_session(): x = [1., 2.] @@ -96,6 +98,7 @@ class LinearOperatorDiagTest( with self.assertRaisesOpError("Singular operator"): operator.assert_non_singular().run() + @test_util.run_deprecated_v1 def test_assert_non_singular_does_not_raise_for_complex_nonsingular(self): with self.cached_session(): x = [1., 0.] @@ -113,6 +116,7 @@ class LinearOperatorDiagTest( with self.assertRaisesOpError("imaginary.*not self-adjoint"): operator.assert_self_adjoint().run() + @test_util.run_deprecated_v1 def test_assert_self_adjoint_does_not_raise_for_diag_with_zero_imag(self): with self.cached_session(): x = [1., 0.] diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_full_matrix_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_full_matrix_test.py index 36575ceec3..aff0b1ae14 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_full_matrix_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_full_matrix_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops.linalg import linalg as linalg_lib @@ -69,6 +70,7 @@ class SquareLinearOperatorFullMatrixTest( # Auto-detected. self.assertTrue(operator.is_square) + @test_util.run_deprecated_v1 def test_assert_non_singular_raises_if_cond_too_big_but_finite(self): with self.cached_session(): tril = linear_operator_test_util.random_tril_matrix( diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py index e9fd91c6cf..2da5e712d7 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.ops import math_ops @@ -60,16 +61,19 @@ class LinearOperatorIdentityTest( return operator, mat + @test_util.run_deprecated_v1 def test_assert_positive_definite(self): with self.cached_session(): operator = linalg_lib.LinearOperatorIdentity(num_rows=2) operator.assert_positive_definite().run() # Should not fail + @test_util.run_deprecated_v1 def test_assert_non_singular(self): with self.cached_session(): operator = linalg_lib.LinearOperatorIdentity(num_rows=2) operator.assert_non_singular().run() # Should not fail + @test_util.run_deprecated_v1 def test_assert_self_adjoint(self): with self.cached_session(): operator = linalg_lib.LinearOperatorIdentity(num_rows=2) @@ -109,6 +113,7 @@ class LinearOperatorIdentityTest( with self.assertRaisesRegexp(ValueError, "must be non-negative"): linalg_lib.LinearOperatorIdentity(num_rows=2, batch_shape=[-2]) + @test_util.run_deprecated_v1 def test_non_scalar_num_rows_raises_dynamic(self): with self.cached_session(): num_rows = array_ops.placeholder(dtypes.int32) @@ -117,6 +122,7 @@ class LinearOperatorIdentityTest( with self.assertRaisesOpError("must be a 0-D Tensor"): operator.to_dense().eval(feed_dict={num_rows: [2]}) + @test_util.run_deprecated_v1 def test_negative_num_rows_raises_dynamic(self): with self.cached_session(): num_rows = array_ops.placeholder(dtypes.int32) @@ -125,6 +131,7 @@ class LinearOperatorIdentityTest( with self.assertRaisesOpError("must be non-negative"): operator.to_dense().eval(feed_dict={num_rows: -2}) + @test_util.run_deprecated_v1 def test_non_1d_batch_shape_raises_dynamic(self): with self.cached_session(): batch_shape = array_ops.placeholder(dtypes.int32) @@ -133,6 +140,7 @@ class LinearOperatorIdentityTest( with self.assertRaisesOpError("must be a 1-D"): operator.to_dense().eval(feed_dict={batch_shape: 2}) + @test_util.run_deprecated_v1 def test_negative_batch_shape_raises_dynamic(self): with self.cached_session(): batch_shape = array_ops.placeholder(dtypes.int32) @@ -147,6 +155,7 @@ class LinearOperatorIdentityTest( with self.assertRaisesRegexp(ValueError, "Dimensions.*not compatible"): operator.matmul(x) + @test_util.run_deprecated_v1 def test_wrong_matrix_dimensions_raises_dynamic(self): num_rows = array_ops.placeholder(dtypes.int32) x = array_ops.placeholder(dtypes.float32) @@ -172,6 +181,7 @@ class LinearOperatorIdentityTest( self.assertAllEqual(operator_matmul.get_shape(), expected.get_shape()) self.assertAllClose(*self.evaluate([operator_matmul, expected])) + @test_util.run_deprecated_v1 def test_default_batch_shape_broadcasts_with_everything_dynamic(self): # These cannot be done in the automated (base test class) tests since they # test shapes that tf.batch_matmul cannot handle. @@ -209,6 +219,7 @@ class LinearOperatorIdentityTest( self.assertAllEqual(operator_matmul.get_shape(), expected.get_shape()) self.assertAllClose(*self.evaluate([operator_matmul, expected])) + @test_util.run_deprecated_v1 def test_broadcast_matmul_dynamic_shapes(self): # These cannot be done in the automated (base test class) tests since they # test shapes that tf.batch_matmul cannot handle. @@ -309,6 +320,7 @@ class LinearOperatorScaledIdentityTest( return operator, matrix + @test_util.run_deprecated_v1 def test_assert_positive_definite_does_not_raise_when_positive(self): with self.cached_session(): operator = linalg_lib.LinearOperatorScaledIdentity( @@ -322,6 +334,7 @@ class LinearOperatorScaledIdentityTest( with self.assertRaisesOpError("not positive definite"): operator.assert_positive_definite().run() + @test_util.run_deprecated_v1 def test_assert_non_singular_does_not_raise_when_non_singular(self): with self.cached_session(): operator = linalg_lib.LinearOperatorScaledIdentity( @@ -335,6 +348,7 @@ class LinearOperatorScaledIdentityTest( with self.assertRaisesOpError("was singular"): operator.assert_non_singular().run() + @test_util.run_deprecated_v1 def test_assert_self_adjoint_does_not_raise_when_self_adjoint(self): with self.cached_session(): operator = linalg_lib.LinearOperatorScaledIdentity( @@ -372,6 +386,7 @@ class LinearOperatorScaledIdentityTest( with self.assertRaisesRegexp(ValueError, "Dimensions.*not compatible"): operator.matmul(x) + @test_util.run_deprecated_v1 def test_wrong_matrix_dimensions_raises_dynamic(self): num_rows = array_ops.placeholder(dtypes.int32) x = array_ops.placeholder(dtypes.float32) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_kronecker_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_kronecker_test.py index 2b1ae6e1f5..513b246803 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_kronecker_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_kronecker_test.py @@ -21,6 +21,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops.linalg import linalg as linalg_lib from tensorflow.python.ops.linalg import linear_operator_kronecker as kronecker @@ -53,6 +54,7 @@ def _kronecker_dense(factors): class KroneckerDenseTest(test.TestCase): + @test_util.run_deprecated_v1 def testKroneckerDenseMatrix(self): x = ops.convert_to_tensor([[2., 3.], [1., 2.]], dtype=dtypes.float32) y = ops.convert_to_tensor([[1., 2.], [5., -1.]], dtype=dtypes.float32) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_test.py index 2f67df408c..8f8b15e8ed 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_test.py @@ -22,6 +22,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.ops import math_ops @@ -107,6 +108,7 @@ class LinearOperatorTest(test.TestCase): self.assertAllEqual(4, operator.domain_dimension) self.assertAllEqual(3, operator.range_dimension) + @test_util.run_deprecated_v1 def test_all_shape_methods_defined_by_the_one_method_shape(self): with self.cached_session(): shape = (1, 2, 3, 4) @@ -136,6 +138,7 @@ class LinearOperatorTest(test.TestCase): self.assertAllEqual((2, 3, 4), operator_dense.get_shape()) self.assertAllClose(matrix, self.evaluate(operator_dense)) + @test_util.run_deprecated_v1 def test_generic_to_dense_method_non_square_matrix_tensor(self): matrix = rng.randn(2, 3, 4) matrix_ph = array_ops.placeholder(dtypes.float64) @@ -175,6 +178,7 @@ class LinearOperatorTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "but.*was square"): _ = LinearOperatorShape(shape=(2, 4, 4), is_square=False).is_square + @test_util.run_deprecated_v1 def test_is_square_set_inconsistent_with_other_hints_raises(self): with self.assertRaisesRegexp(ValueError, "is always square"): matrix = array_ops.placeholder(dtypes.float32) @@ -185,6 +189,7 @@ class LinearOperatorTest(test.TestCase): LinearOperatorMatmulSolve( matrix, is_positive_definite=True, is_square=False) + @test_util.run_deprecated_v1 def test_non_square_operators_raise_on_determinant_and_solve(self): operator = LinearOperatorShape((2, 3)) with self.assertRaisesRegexp(NotImplementedError, "not be square"): @@ -199,6 +204,7 @@ class LinearOperatorTest(test.TestCase): LinearOperatorMatmulSolve( matrix, is_positive_definite=True, is_square=False) + @test_util.run_deprecated_v1 def test_is_square_manual_set_works(self): matrix = array_ops.placeholder(dtypes.float32) # Default is None. @@ -208,6 +214,7 @@ class LinearOperatorTest(test.TestCase): operator = LinearOperatorMatmulSolve(matrix, is_square=True) self.assertTrue(operator.is_square) + @test_util.run_deprecated_v1 def test_linear_operator_matmul_hints_closed(self): matrix = array_ops.placeholder(dtypes.float32) operator1 = LinearOperatorMatmulSolve(matrix) @@ -234,6 +241,7 @@ class LinearOperatorTest(test.TestCase): self.assertTrue(operator_matmul.is_self_adjoint) self.assertEqual(None, operator_matmul.is_positive_definite) + @test_util.run_deprecated_v1 def test_linear_operator_matmul_hints_false(self): matrix = array_ops.placeholder(dtypes.float32) operator1 = LinearOperatorMatmulSolve( @@ -266,6 +274,7 @@ class LinearOperatorTest(test.TestCase): self.assertEqual(None, operator_matmul.is_self_adjoint) self.assertEqual(None, operator_matmul.is_positive_definite) + @test_util.run_deprecated_v1 def test_linear_operator_matmul_hint_infer_square(self): matrix1 = array_ops.placeholder(shape=[2, 3], dtype=dtypes.float32) matrix2 = array_ops.placeholder(shape=[3, 2], dtype=dtypes.float32) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py index f12714677e..d1e6c37e35 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py @@ -21,6 +21,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.ops import math_ops @@ -32,12 +33,14 @@ rng = np.random.RandomState(0) class AssertZeroImagPartTest(test.TestCase): + @test_util.run_deprecated_v1 def test_real_tensor_doesnt_raise(self): x = ops.convert_to_tensor([0., 2, 3]) with self.cached_session(): # Should not raise. linear_operator_util.assert_zero_imag_part(x, message="ABC123").run() + @test_util.run_deprecated_v1 def test_complex_tensor_with_imag_zero_doesnt_raise(self): x = ops.convert_to_tensor([1., 0, 3]) y = ops.convert_to_tensor([0., 0, 0]) @@ -57,6 +60,7 @@ class AssertZeroImagPartTest(test.TestCase): class AssertNoEntriesWithModulusZeroTest(test.TestCase): + @test_util.run_deprecated_v1 def test_nonzero_real_tensor_doesnt_raise(self): x = ops.convert_to_tensor([1., 2, 3]) with self.cached_session(): @@ -64,6 +68,7 @@ class AssertNoEntriesWithModulusZeroTest(test.TestCase): linear_operator_util.assert_no_entries_with_modulus_zero( x, message="ABC123").run() + @test_util.run_deprecated_v1 def test_nonzero_complex_tensor_doesnt_raise(self): x = ops.convert_to_tensor([1., 0, 3]) y = ops.convert_to_tensor([1., 2, 0]) @@ -104,6 +109,7 @@ class BroadcastMatrixBatchDimsTest(test.TestCase): with self.cached_session(): self.assertAllClose(arr, self.evaluate(tensor)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast(self): # x.batch_shape = [3, 1, 2] # y.batch_shape = [4, 1] @@ -142,6 +148,7 @@ class BroadcastMatrixBatchDimsTest(test.TestCase): self.assertAllClose(x_bc_expected, x_bc_) self.assertAllClose(y_bc_expected, y_bc_) + @test_util.run_deprecated_v1 def test_dynamic_dims_broadcast_32bit(self): # x.batch_shape = [3, 1, 2] # y.batch_shape = [4, 1] @@ -162,6 +169,7 @@ class BroadcastMatrixBatchDimsTest(test.TestCase): self.assertAllClose(x_bc_expected, x_bc_) self.assertAllClose(y_bc_expected, y_bc_) + @test_util.run_deprecated_v1 def test_dynamic_dims_broadcast_32bit_second_arg_higher_rank(self): # x.batch_shape = [1, 2] # y.batch_shape = [3, 4, 1] @@ -195,6 +203,7 @@ class BroadcastMatrixBatchDimsTest(test.TestCase): class CholeskySolveWithBroadcastTest(test.TestCase): + @test_util.run_deprecated_v1 def test_static_dims_broadcast(self): # batch_shape = [2] chol = rng.rand(3, 3) @@ -207,6 +216,7 @@ class CholeskySolveWithBroadcastTest(test.TestCase): expected = linalg_ops.cholesky_solve(chol_broadcast, rhs) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2, 2] chol = rng.rand(2, 3, 3) @@ -233,6 +243,7 @@ class CholeskySolveWithBroadcastTest(test.TestCase): class MatmulWithBroadcastTest(test.TestCase): + @test_util.run_deprecated_v1 def test_static_dims_broadcast_x_has_extra_dims(self): # batch_shape = [2] # for each batch member, we have a 1x3 matrix times a 3x7 matrix ==> 1x7 @@ -246,6 +257,7 @@ class MatmulWithBroadcastTest(test.TestCase): expected = math_ops.matmul(x, y_broadcast) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_y_has_extra_dims(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -263,6 +275,7 @@ class MatmulWithBroadcastTest(test.TestCase): expected = math_ops.matmul(x_broadcast, y) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_y_has_extra_dims_transpose_a_and_b(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -282,6 +295,7 @@ class MatmulWithBroadcastTest(test.TestCase): x_broadcast, y, transpose_a=True, transpose_b=True) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_y_has_extra_dims_transpose_dynamic(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -308,6 +322,7 @@ class MatmulWithBroadcastTest(test.TestCase): y_ph: y })) + @test_util.run_deprecated_v1 def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2] # for each batch member, we have a 1x3 matrix times a 3x7 matrix ==> 1x7 @@ -333,6 +348,7 @@ class MatmulWithBroadcastTest(test.TestCase): class MatrixSolveWithBroadcastTest(test.TestCase): + @test_util.run_deprecated_v1 def test_static_dims_broadcast_matrix_has_extra_dims(self): # batch_shape = [2] matrix = rng.rand(2, 3, 3) @@ -346,6 +362,7 @@ class MatrixSolveWithBroadcastTest(test.TestCase): expected = linalg_ops.matrix_solve(matrix, rhs_broadcast) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_rhs_has_extra_dims(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -364,6 +381,7 @@ class MatrixSolveWithBroadcastTest(test.TestCase): expected = linalg_ops.matrix_solve(matrix_broadcast, rhs) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_rhs_has_extra_dims_dynamic(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -391,6 +409,7 @@ class MatrixSolveWithBroadcastTest(test.TestCase): rhs_ph: rhs })) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_rhs_has_extra_dims_and_adjoint(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -410,6 +429,7 @@ class MatrixSolveWithBroadcastTest(test.TestCase): expected = linalg_ops.matrix_solve(matrix_broadcast, rhs, adjoint=True) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2, 2] matrix = rng.rand(2, 3, 3) @@ -436,6 +456,7 @@ class MatrixSolveWithBroadcastTest(test.TestCase): class MatrixTriangularSolveWithBroadcastTest(test.TestCase): + @test_util.run_deprecated_v1 def test_static_dims_broadcast_matrix_has_extra_dims(self): # batch_shape = [2] matrix = rng.rand(2, 3, 3) @@ -449,6 +470,7 @@ class MatrixTriangularSolveWithBroadcastTest(test.TestCase): expected = linalg_ops.matrix_triangular_solve(matrix, rhs_broadcast) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_rhs_has_extra_dims(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -468,6 +490,7 @@ class MatrixTriangularSolveWithBroadcastTest(test.TestCase): expected = linalg_ops.matrix_triangular_solve(matrix_broadcast, rhs) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_static_dims_broadcast_rhs_has_extra_dims_and_adjoint(self): # Since the second arg has extra dims, and the domain dim of the first arg # is larger than the number of linear equations, code will "flip" the extra @@ -488,6 +511,7 @@ class MatrixTriangularSolveWithBroadcastTest(test.TestCase): matrix_broadcast, rhs, adjoint=True) self.assertAllClose(expected.eval(), self.evaluate(result)) + @test_util.run_deprecated_v1 def test_dynamic_dims_broadcast_64bit(self): # batch_shape = [2] matrix = rng.rand(2, 3, 3) @@ -522,6 +546,7 @@ class DomainDimensionStubOperator(object): class AssertCompatibleMatrixDimensionsTest(test.TestCase): + @test_util.run_deprecated_v1 def test_compatible_dimensions_do_not_raise(self): with self.cached_session(): x = ops.convert_to_tensor(rng.rand(2, 3, 4)) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_zeros_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_zeros_test.py index e875579a7a..eb0b8ef127 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_zeros_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_zeros_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops.linalg import linalg as linalg_lib from tensorflow.python.ops.linalg import linear_operator_test_util @@ -73,6 +74,7 @@ class LinearOperatorZerosTest( operator = linalg_lib.LinearOperatorZeros(num_rows=2) operator.assert_non_singular() + @test_util.run_deprecated_v1 def test_assert_self_adjoint(self): with self.cached_session(): operator = linalg_lib.LinearOperatorZeros(num_rows=2) @@ -108,6 +110,7 @@ class LinearOperatorZerosTest( with self.assertRaisesRegexp(ValueError, "must be non-negative"): linalg_lib.LinearOperatorZeros(num_rows=2, batch_shape=[-2]) + @test_util.run_deprecated_v1 def test_non_scalar_num_rows_raises_dynamic(self): with self.cached_session(): num_rows = array_ops.placeholder(dtypes.int32) @@ -116,6 +119,7 @@ class LinearOperatorZerosTest( with self.assertRaisesOpError("must be a 0-D Tensor"): operator.to_dense().eval(feed_dict={num_rows: [2]}) + @test_util.run_deprecated_v1 def test_negative_num_rows_raises_dynamic(self): with self.cached_session(): n = array_ops.placeholder(dtypes.int32) @@ -129,6 +133,7 @@ class LinearOperatorZerosTest( with self.assertRaisesOpError("must be non-negative"): operator.to_dense().eval(feed_dict={n: -2}) + @test_util.run_deprecated_v1 def test_non_1d_batch_shape_raises_dynamic(self): with self.cached_session(): batch_shape = array_ops.placeholder(dtypes.int32) @@ -137,6 +142,7 @@ class LinearOperatorZerosTest( with self.assertRaisesOpError("must be a 1-D"): operator.to_dense().eval(feed_dict={batch_shape: 2}) + @test_util.run_deprecated_v1 def test_negative_batch_shape_raises_dynamic(self): with self.cached_session(): batch_shape = array_ops.placeholder(dtypes.int32) @@ -151,6 +157,7 @@ class LinearOperatorZerosTest( with self.assertRaisesRegexp(ValueError, "Dimensions.*not compatible"): operator.matmul(x) + @test_util.run_deprecated_v1 def test_wrong_matrix_dimensions_raises_dynamic(self): num_rows = array_ops.placeholder(dtypes.int32) x = array_ops.placeholder(dtypes.float32) diff --git a/tensorflow/python/kernel_tests/linalg_grad_test.py b/tensorflow/python/kernel_tests/linalg_grad_test.py index 709ecbfc35..28e1d7e168 100644 --- a/tensorflow/python/kernel_tests/linalg_grad_test.py +++ b/tensorflow/python/kernel_tests/linalg_grad_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -39,6 +40,7 @@ def _AddTest(test, op_name, testcase_name, fn): class ShapeTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testBatchGradientUnknownSize(self): with self.cached_session(): batch_size = constant_op.constant(3) diff --git a/tensorflow/python/kernel_tests/linalg_ops_test.py b/tensorflow/python/kernel_tests/linalg_ops_test.py index b5eeee0998..028167a786 100644 --- a/tensorflow/python/kernel_tests/linalg_ops_test.py +++ b/tensorflow/python/kernel_tests/linalg_ops_test.py @@ -25,6 +25,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.ops import math_ops @@ -52,6 +53,7 @@ class CholeskySolveTest(test.TestCase): def setUp(self): self.rng = np.random.RandomState(0) + @test_util.run_deprecated_v1 def test_works_with_five_different_random_pos_def_matrices(self): for n in range(1, 6): for np_type, atol in [(np.float32, 0.05), (np.float64, 1e-5)]: @@ -73,6 +75,7 @@ class LogdetTest(test.TestCase): def setUp(self): self.rng = np.random.RandomState(42) + @test_util.run_deprecated_v1 def test_works_with_five_different_random_pos_def_matrices(self): for n in range(1, 6): for np_dtype, atol in [(np.float32, 0.05), (np.float64, 1e-5), @@ -102,6 +105,7 @@ class SlogdetTest(test.TestCase): def setUp(self): self.rng = np.random.RandomState(42) + @test_util.run_deprecated_v1 def test_works_with_five_different_random_pos_def_matrices(self): for n in range(1, 6): for np_dtype, atol in [(np.float32, 0.05), (np.float64, 1e-5), @@ -232,6 +236,7 @@ class EyeTest(parameterized.TestCase, test.TestCase): dtypes.complex128 ]) ) + @test_util.run_deprecated_v1 def test_eye_with_placeholder( self, num_rows, num_columns, batch_shape, dtype): eye_np = np.eye(num_rows, M=num_columns, dtype=dtype.as_numpy_dtype) diff --git a/tensorflow/python/kernel_tests/list_ops_test.py b/tensorflow/python/kernel_tests/list_ops_test.py index 1d9f4032d1..8df1156438 100644 --- a/tensorflow/python/kernel_tests/list_ops_test.py +++ b/tensorflow/python/kernel_tests/list_ops_test.py @@ -66,6 +66,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): with context.device("gpu:0"): self._testPushPop(max_num_elements) + @test_util.run_deprecated_v1 def testPushInFullListFails(self): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, element_shape=[], max_num_elements=1) @@ -77,6 +78,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 2)) + @test_util.run_deprecated_v1 def testPopFromEmptyTensorListFails(self, max_num_elements): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, @@ -114,6 +116,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 3)) + @test_util.run_deprecated_v1 def testStackWithUnknownElementShape(self, max_num_elements): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, @@ -134,6 +137,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 3)) + @test_util.run_deprecated_v1 def testStackWithPartiallyDefinedElementShape(self, max_num_elements): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, @@ -154,6 +158,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 2)) + @test_util.run_deprecated_v1 def testStackEmptyList(self, max_num_elements): # Should be able to stack empty lists with fully defined element_shape. l = list_ops.empty_tensor_list( @@ -204,6 +209,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 3)) + @test_util.run_deprecated_v1 def testGatherWithUnknownElementShape(self, max_num_elements): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, @@ -227,6 +233,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 3)) + @test_util.run_deprecated_v1 def testGatherWithPartiallyDefinedElementShape(self, max_num_elements): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, @@ -250,6 +257,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.named_parameters(("NoMaxNumElements", None), ("WithMaxNumElements", 3)) + @test_util.run_deprecated_v1 def testGatherEmptyList(self, max_num_elements): # Should be able to gather from empty lists with fully defined # element_shape. @@ -337,6 +345,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertAllEqual(self.evaluate(e), 10.0) self.assertAllEqual(self.evaluate(tape.gradient(e, t)), 2.0) + @test_util.run_deprecated_v1 def testSetOnEmptyListWithMaxNumElementsFails(self): l = list_ops.empty_tensor_list( element_dtype=dtypes.float32, element_shape=[], max_num_elements=3) @@ -572,12 +581,14 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertAllEqual(self.evaluate(grad_c), [0.0, 4.0]) self.assertAllEqual(self.evaluate(grad_c2), 6.0) + @test_util.run_deprecated_v1 def testSetOutOfBounds(self): c = constant_op.constant([1.0, 2.0]) l = list_ops.tensor_list_from_tensor(c, element_shape=[]) with self.assertRaises(errors.InvalidArgumentError): self.evaluate(list_ops.tensor_list_set_item(l, 20, 3.0)) + @test_util.run_deprecated_v1 def testSkipEagerSetItemWithMismatchedShapeFails(self): with self.cached_session() as sess: ph = array_ops.placeholder(dtypes.float32) @@ -612,6 +623,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): [[1.0, 2.0]] * 4) self.assertAllEqual(self.evaluate(updated_v_stacked), expected) + @test_util.run_deprecated_v1 def testConcat(self): c = constant_op.constant([1.0, 2.0], dtype=dtypes.float32) l0 = list_ops.tensor_list_from_tensor(c, element_shape=[]) @@ -670,6 +682,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): list_ops.tensor_list_concat_lists(l_batch_0, l_batch_of_int_tls, element_dtype=dtypes.float32)) + @test_util.run_deprecated_v1 def testPushBackBatch(self): c = constant_op.constant([1.0, 2.0], dtype=dtypes.float32) l0 = list_ops.tensor_list_from_tensor(c, element_shape=[]) @@ -797,6 +810,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertAllEqual(self.evaluate(res_1), [0.]) self.assertAllEqual(self.evaluate(res_2), [0., 0.]) + @test_util.run_deprecated_v1 def testSkipEagerTensorListGetItemGradAggregation(self): l = list_ops.tensor_list_reserve( element_shape=[], num_elements=1, element_dtype=dtypes.float32) @@ -808,6 +822,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.cached_session() as sess: self.assertSequenceEqual(self.evaluate(grad), [2.]) + @test_util.run_deprecated_v1 def testSkipEagerBuildElementShape(self): fn = list_ops._build_element_shape # Unknown shape -> -1. diff --git a/tensorflow/python/kernel_tests/logging_ops_test.py b/tensorflow/python/kernel_tests/logging_ops_test.py index e8fa1cfa28..85035e5f7d 100644 --- a/tensorflow/python/kernel_tests/logging_ops_test.py +++ b/tensorflow/python/kernel_tests/logging_ops_test.py @@ -39,6 +39,7 @@ from tensorflow.python.platform import test class LoggingOpsTest(test.TestCase): + @test_util.run_deprecated_v1 def testAssertDivideByZero(self): with self.cached_session() as sess: epsilon = ops.convert_to_tensor(1e-20) @@ -305,12 +306,14 @@ class PrintV2Test(test.TestCase): tensor, output_stream="unknown") self.evaluate(print_op) + @test_util.run_deprecated_v1 def testPrintOpName(self): with self.cached_session(): tensor = math_ops.range(10) print_op = logging_ops.print_v2(tensor, name="print_name") self.assertEqual(print_op.name, "print_name") + @test_util.run_deprecated_v1 def testNoDuplicateFormatOpGraphModeAfterExplicitFormat(self): with self.cached_session(): tensor = math_ops.range(10) @@ -379,6 +382,7 @@ class PrintGradientTest(test.TestCase): inp_printed = logging_ops.Print(inp, ["hello"]) self.assertEqual(inp.get_shape(), inp_printed.get_shape()) + @test_util.run_deprecated_v1 def testPrintGradient(self): with self.cached_session(): inp = constant_op.constant(2.0, shape=[100, 32], name="in") diff --git a/tensorflow/python/kernel_tests/lookup_ops_test.py b/tensorflow/python/kernel_tests/lookup_ops_test.py index 79961d8dd1..ad81e0be64 100644 --- a/tensorflow/python/kernel_tests/lookup_ops_test.py +++ b/tensorflow/python/kernel_tests/lookup_ops_test.py @@ -37,6 +37,7 @@ from tensorflow.python.training import server_lib class HashTableOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testHashTable(self): with self.cached_session(): default_val = -1 @@ -61,6 +62,7 @@ class HashTableOpTest(test.TestCase): self.evaluate(exported_keys_tensor)) self.assertItemsEqual([0, 1, 2], self.evaluate(exported_values_tensor)) + @test_util.run_deprecated_v1 def testHashTableFindHighRank(self): with self.cached_session(): default_val = -1 @@ -79,6 +81,7 @@ class HashTableOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([[0, 1], [-1, -1]], result) + @test_util.run_deprecated_v1 def testHashTableInitWithPythonArrays(self): with self.cached_session(): default_val = -1 @@ -97,6 +100,7 @@ class HashTableOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([0, 1, -1], result) + @test_util.run_deprecated_v1 def testHashTableInitWithNumPyArrays(self): with self.cached_session(): default_val = -1 @@ -114,6 +118,7 @@ class HashTableOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([0, 1, -1], result) + @test_util.run_deprecated_v1 def testMultipleHashTables(self): with self.cached_session() as sess: default_val = -1 @@ -142,6 +147,7 @@ class HashTableOpTest(test.TestCase): self.assertAllEqual([0, 1, -1], out2) self.assertAllEqual([0, 1, -1], out3) + @test_util.run_deprecated_v1 def testHashTableWithTensorDefault(self): with self.cached_session(): default_val = constant_op.constant(-1, dtypes.int64) @@ -157,6 +163,7 @@ class HashTableOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([0, 1, -1], result) + @test_util.run_deprecated_v1 def testHashTableWithSparseTensorInput(self): with self.cached_session() as sess: default_val = constant_op.constant(-1, dtypes.int64) @@ -180,6 +187,7 @@ class HashTableOpTest(test.TestCase): self.assertAllEqual(sp_indices, out_indices) self.assertAllEqual(sp_shape, out_shape) + @test_util.run_deprecated_v1 def testSignatureMismatch(self): with self.cached_session(): default_val = -1 @@ -210,6 +218,7 @@ class HashTableOpTest(test.TestCase): lookup_ops.KeyValueTensorInitializer(["a"], [1], [dtypes.string], dtypes.int64), default_val) + @test_util.run_deprecated_v1 def testNotInitialized(self): with self.cached_session(): default_val = -1 @@ -223,6 +232,7 @@ class HashTableOpTest(test.TestCase): with self.assertRaisesOpError("Table not initialized"): self.evaluate(output) + @test_util.run_deprecated_v1 def testInitializeTwice(self): with self.cached_session(): default_val = -1 @@ -235,6 +245,7 @@ class HashTableOpTest(test.TestCase): with self.assertRaisesOpError("Table already initialized"): table.initializer.run() + @test_util.run_deprecated_v1 def testInitializationWithInvalidDimensions(self): with self.cached_session(): default_val = -1 @@ -245,6 +256,7 @@ class HashTableOpTest(test.TestCase): lookup_ops.HashTable( lookup_ops.KeyValueTensorInitializer(keys, values), default_val) + @test_util.run_deprecated_v1 def testMultipleSessions(self): # Start a server server = server_lib.Server( @@ -274,6 +286,7 @@ class HashTableOpTest(test.TestCase): table.initializer.run() self.assertAllEqual(3, table.size().eval()) + @test_util.run_deprecated_v1 def testHashTableInt32String(self): with self.cached_session(): default_val = "n/a" @@ -298,6 +311,7 @@ class IndexTableFromFile(test.TestCase): f.write("\n".join(values) + "\n") return vocabulary_file + @test_util.run_deprecated_v1 def test_string_index_table_from_file(self): vocabulary_file = self._createVocabFile("f2i_vocab1.txt") with self.cached_session(): @@ -310,6 +324,7 @@ class IndexTableFromFile(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_string_index_table_from_multicolumn_file(self): vocabulary_file = self._createVocabFile( "f2i_vocab1.txt", values=("brain\t300", "salad\t20", "surgery\t1")) @@ -326,6 +341,7 @@ class IndexTableFromFile(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_string_index_table_from_multicolumn_file_custom_delimiter(self): vocabulary_file = self._createVocabFile( "f2i_vocab1.txt", values=("brain 300", "salad 20", "surgery 1")) @@ -343,6 +359,7 @@ class IndexTableFromFile(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_string_index_table_from_file_tensor_filename(self): vocabulary_file = self._createVocabFile("f2i_vocab1.txt") with self.cached_session(): @@ -358,6 +375,7 @@ class IndexTableFromFile(test.TestCase): self.assertEqual(1, len(ops.get_collection(ops.GraphKeys.ASSET_FILEPATHS))) + @test_util.run_deprecated_v1 def test_string_index_table_from_file_placeholder_filename(self): vocabulary_file = self._createVocabFile("f2i_vocab1.txt") with self.cached_session(): @@ -375,6 +393,7 @@ class IndexTableFromFile(test.TestCase): self.assertEqual(0, len(ops.get_collection(ops.GraphKeys.ASSET_FILEPATHS))) + @test_util.run_deprecated_v1 def test_int32_index_table_from_file(self): vocabulary_file = self._createVocabFile( "f2i_vocab2.txt", values=("42", "1", "-1000")) @@ -391,6 +410,7 @@ class IndexTableFromFile(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_int64_index_table_from_file(self): vocabulary_file = self._createVocabFile( "f2i_vocab3.txt", values=("42", "1", "-1000")) @@ -407,6 +427,7 @@ class IndexTableFromFile(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_index_table_from_file_with_default_value(self): default_value = -42 vocabulary_file = self._createVocabFile("f2i_vocab4.txt") @@ -420,6 +441,7 @@ class IndexTableFromFile(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, default_value), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_index_table_from_file_with_oov_buckets(self): vocabulary_file = self._createVocabFile("f2i_vocab5.txt") with self.cached_session(): @@ -468,6 +490,7 @@ class IndexTableFromFile(test.TestCase): vocabulary_file=vocabulary_file, vocab_size=0) + @test_util.run_deprecated_v1 def test_index_table_from_file_with_vocab_size_too_small(self): vocabulary_file = self._createVocabFile("f2i_vocab6.txt") with self.cached_session(): @@ -481,6 +504,7 @@ class IndexTableFromFile(test.TestCase): self.assertAllEqual((1, -1, -1), self.evaluate(ids)) self.assertEqual(2, table.size().eval()) + @test_util.run_deprecated_v1 def test_index_table_from_file_with_vocab_size_too_large(self): vocabulary_file = self._createVocabFile("f2i_vocab7.txt") with self.cached_session(): @@ -489,6 +513,7 @@ class IndexTableFromFile(test.TestCase): self.assertRaisesRegexp(errors_impl.InvalidArgumentError, "Invalid vocab_size", table.initializer.run) + @test_util.run_deprecated_v1 def test_index_table_from_file_with_vocab_size(self): vocabulary_file = self._createVocabFile("f2i_vocab8.txt") @@ -577,6 +602,7 @@ class KeyValueTensorInitializerTest(test.TestCase): table = lookup_ops.HashTable(init, default_value=-1) table.initializer.run() + @test_util.run_deprecated_v1 def test_int32(self): with ops.Graph().as_default(), self.cached_session(): init = lookup_ops.KeyValueTensorInitializer((42, 1, -1000), (0, 1, 2), @@ -590,6 +616,7 @@ class KeyValueTensorInitializerTest(test.TestCase): class IndexTableFromTensor(test.TestCase): @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def test_index_table_from_tensor_with_tensor_init(self): table = lookup_ops.index_table_from_tensor( vocabulary_list=("brain", "salad", "surgery"), num_oov_buckets=1) @@ -606,6 +633,7 @@ class IndexTableFromTensor(test.TestCase): ids = table.lookup(constant_op.constant(("salad", "surgery", "tarkus"))) self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_int32_index_table_from_tensor_with_tensor_init(self): with self.cached_session(): table = lookup_ops.index_table_from_tensor( @@ -618,6 +646,7 @@ class IndexTableFromTensor(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_int64_index_table_from_tensor_with_tensor_init(self): with self.cached_session(): table = lookup_ops.index_table_from_tensor( @@ -630,6 +659,7 @@ class IndexTableFromTensor(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((1, 2, 3), self.evaluate(ids)) + @test_util.run_deprecated_v1 def test_index_table_from_tensor_with_default_value(self): default_value = -42 with self.cached_session(): @@ -650,6 +680,7 @@ class IndexTableFromTensor(test.TestCase): lookup_ops.index_table_from_tensor( vocabulary_list=None, num_oov_buckets=1) + @test_util.run_deprecated_v1 def test_index_table_from_tensor_empty_vocabulary_list(self): with self.cached_session(): table = lookup_ops.index_table_from_tensor( @@ -686,6 +717,7 @@ class IndexToStringTableFromFileTest(test.TestCase): f.write("\n".join(values) + "\n") return vocabulary_file + @test_util.run_deprecated_v1 def test_index_to_string_table(self): vocabulary_path = self._createVocabFile("i2f_vocab1.txt") # vocabulary_file supports string and tensor @@ -703,6 +735,7 @@ class IndexToStringTableFromFileTest(test.TestCase): self.assertAllEqual((b"brain", b"salad", b"surgery", b"UNK"), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_index_to_string_table_from_multicolumn_file(self): vocabulary_file = self._createVocabFile( "f2i_vocab1.txt", values=("brain\t300", "salad\t20", "surgery\t1")) @@ -718,6 +751,7 @@ class IndexToStringTableFromFileTest(test.TestCase): self.assertAllEqual((b"brain", b"salad", b"surgery", b"UNK"), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_index_to_string_table_from_multicolumn_file_custom_delimiter(self): vocabulary_file = self._createVocabFile( "f2i_vocab1.txt", values=("brain 300", "salad 20", "surgery 1")) @@ -734,6 +768,7 @@ class IndexToStringTableFromFileTest(test.TestCase): self.assertAllEqual((b"brain", b"salad", b"surgery", b"UNK"), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_index_to_string_table_with_default_value(self): default_value = b"NONE" vocabulary_file = self._createVocabFile("f2i_vocab2.txt") @@ -747,6 +782,7 @@ class IndexToStringTableFromFileTest(test.TestCase): self.assertAllEqual((b"salad", b"surgery", default_value), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_index_to_string_table_with_vocab_size_too_small(self): default_value = b"NONE" vocabulary_file = self._createVocabFile("f2i_vocab2.txt") @@ -762,6 +798,7 @@ class IndexToStringTableFromFileTest(test.TestCase): self.assertAllEqual((b"salad", default_value, default_value), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_index_to_string_table_with_vocab_size_too_large(self): vocabulary_file = self._createVocabFile("f2i_vocab6.txt") with self.cached_session(): @@ -775,6 +812,7 @@ class IndexToStringTableFromFileTest(test.TestCase): self.assertRaisesRegexp(errors_impl.InvalidArgumentError, "Invalid vocab_size", init.run) + @test_util.run_deprecated_v1 def test_index_to_string_table_with_vocab_size(self): vocabulary_file = self._createVocabFile("f2i_vocab7.txt") with self.cached_session(): @@ -791,6 +829,7 @@ class IndexToStringTableFromFileTest(test.TestCase): class IndexToStringTableFromTensorTest(test.TestCase): + @test_util.run_deprecated_v1 def test_index_to_string_table_from_tensor(self): with self.cached_session(): vocabulary_list = constant_op.constant(["brain", "salad", "surgery"]) @@ -806,6 +845,7 @@ class IndexToStringTableFromTensorTest(test.TestCase): self.assertAllEqual((b"brain", b"salad", b"surgery", b"UNK"), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_duplicate_entries(self): with self.cached_session(): vocabulary_list = constant_op.constant(["hello", "hello"]) @@ -816,6 +856,7 @@ class IndexToStringTableFromTensorTest(test.TestCase): lookup_ops.tables_initializer().run() self.assertAllEqual((b"hello", b"hello", b"UNK"), self.evaluate(features)) + @test_util.run_deprecated_v1 def test_index_to_string_with_default_value(self): default_value = b"NONE" with self.cached_session(): @@ -855,6 +896,7 @@ class InitializeTableFromFileOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([0, 1, -1], result) + @test_util.run_deprecated_v1 def testInitializeInt64Table(self): vocabulary_file = self._createVocabFile( "one_column_int64.txt", values=("42", "1", "-1000")) @@ -874,6 +916,7 @@ class InitializeTableFromFileOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([0, 1, -1], result) + @test_util.run_deprecated_v1 def testInitializeIndexTable(self): vocabulary_file = self._createVocabFile("one_column_2.txt") @@ -893,6 +936,7 @@ class InitializeTableFromFileOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([b"brain", b"salad", b"surgery", b"UNK"], result) + @test_util.run_deprecated_v1 def testMultiColumn(self): vocabulary_file = os.path.join(self.get_temp_dir(), "three_columns.txt") with open(vocabulary_file, "w") as f: @@ -915,6 +959,7 @@ class InitializeTableFromFileOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([1, 5, 6], result) + @test_util.run_deprecated_v1 def testInvalidDataTypeInMultiColumn(self): vocabulary_file = os.path.join(self.get_temp_dir(), "three_columns.txt") with open(vocabulary_file, "w") as f: @@ -945,6 +990,7 @@ class InitializeTableFromFileOpTest(test.TestCase): key_index, dtypes.string, value_index), default_value) + @test_util.run_deprecated_v1 def testInvalidIndex(self): vocabulary_file = self._createVocabFile("one_column_4.txt") with self.cached_session(): @@ -959,6 +1005,7 @@ class InitializeTableFromFileOpTest(test.TestCase): with self.assertRaisesOpError("Invalid number of columns"): table.initializer.run() + @test_util.run_deprecated_v1 def testInitializeSameTableWithMultipleNodes(self): vocabulary_file = self._createVocabFile("one_column_5.txt") @@ -1010,6 +1057,7 @@ class InitializeTableFromFileOpTest(test.TestCase): dtypes.int64, lookup_ops.TextFileIndex.LINE_NUMBER), default_value) + @test_util.run_deprecated_v1 def testInitializeWithVocabSize(self): with self.cached_session(): default_value = -1 @@ -1056,6 +1104,7 @@ class InitializeTableFromFileOpTest(test.TestCase): table3.initializer.run() self.assertEquals(vocab_size, table3.size().eval()) + @test_util.run_deprecated_v1 def testFeedVocabularyName(self): vocabulary_file = self._createVocabFile("feed_vocabulary.txt") @@ -1082,6 +1131,7 @@ class InitializeTableFromFileOpTest(test.TestCase): result = self.evaluate(output) self.assertAllEqual([0, 1, -1], result) + @test_util.run_deprecated_v1 def testInvalidFilenames(self): vocabulary_file = self._createVocabFile("filename_shape.txt") @@ -1106,6 +1156,7 @@ class InitializeTableFromFileOpTest(test.TestCase): dtypes.int64, lookup_ops.TextFileIndex.LINE_NUMBER), default_value) + @test_util.run_deprecated_v1 def testIdToStringTable(self): vocab_file = self._createVocabFile("feat_to_id_1.txt") with self.cached_session(): @@ -1124,6 +1175,7 @@ class InitializeTableFromFileOpTest(test.TestCase): self.evaluate(out)) self.assertEquals(vocab_size, table.size().eval()) + @test_util.run_deprecated_v1 def testStringToIdTable(self): vocab_file = self._createVocabFile("feat_to_id_2.txt") with self.cached_session(): @@ -1140,6 +1192,7 @@ class InitializeTableFromFileOpTest(test.TestCase): self.assertAllEqual([0, 1, 2, -1], self.evaluate(out)) self.assertEquals(vocab_size, table.size().eval()) + @test_util.run_deprecated_v1 def testInt64ToIdTable(self): vocab_file = self._createVocabFile( "feat_to_id_3.txt", values=("42", "1", "-1000")) @@ -1166,6 +1219,7 @@ class IdTableWithHashBucketsTest(test.TestCase): f.write("\n".join(values) + "\n") return vocabulary_file + @test_util.run_deprecated_v1 def testStringIdTableWithHashBuckets(self): vocab_file = self._createVocabFile("feat_to_id_1.txt") with self.cached_session(): @@ -1186,6 +1240,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertAllEqual([0, 1, 2, 3], self.evaluate(out)) self.assertEquals(vocab_size + oov_buckets, table.size().eval()) + @test_util.run_deprecated_v1 def testInt32IdTableWithHashBuckets(self): vocab_file = self._createVocabFile("feat_to_id_2.txt", ("42", "1", "-1000")) with self.cached_session(): @@ -1208,6 +1263,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertAllEqual([0, 1, 2, 3], self.evaluate(out)) self.assertEquals(vocab_size + oov_buckets, table.size().eval()) + @test_util.run_deprecated_v1 def testInt64IdTableWithHashBuckets(self): vocab_file = self._createVocabFile("feat_to_id_3.txt", ("42", "1", "-1000")) with self.cached_session(): @@ -1228,6 +1284,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertAllEqual([0, 1, 2, 3], self.evaluate(out)) self.assertEquals(vocab_size + oov_buckets, table.size().eval()) + @test_util.run_deprecated_v1 def testStringIdTableWithOnlyHashBucket(self): with self.cached_session(): oov_buckets = 5 @@ -1249,6 +1306,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.evaluate(out)) self.assertEquals(oov_buckets, table.size().eval()) + @test_util.run_deprecated_v1 def testInt32IdTableWithOnlyHashBucket(self): with self.cached_session(): oov_buckets = 5 @@ -1283,6 +1341,7 @@ class IdTableWithHashBucketsTest(test.TestCase): lookup_ops.IdTableWithHashBuckets( None, num_oov_buckets=5, key_dtype=dtypes.bool) + @test_util.run_deprecated_v1 def testIdTableWithHashBucketsWithMultipleInitializers(self): vocab_file = self._createVocabFile("feat_to_id_4.txt") with self.cached_session() as sess: @@ -1323,6 +1382,7 @@ class IdTableWithHashBucketsTest(test.TestCase): "table2_Lookup/hash_bucket": "StringToHashBucketStrong", }, sess.graph) + @test_util.run_deprecated_v1 def testIdTableWithHashBucketsInitializationAcrossSessions(self): vocab_file = self._createVocabFile("feat_to_id_5.txt") shared_name = "across-sessions" @@ -1368,6 +1428,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertAllEqual([3, 1, 3], self.evaluate(out2)) self.assertEquals(vocab_size + oov_buckets, table2.size().eval()) + @test_util.run_deprecated_v1 def testIdTableWithHashBucketsWithMultipleInitializersDifferentDefault(self): vocab_file = self._createVocabFile("feat_to_id_6.txt") with self.cached_session() as sess: @@ -1402,6 +1463,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertEquals(vocab_size + oov_buckets, table1.size().eval()) self.assertEquals(vocab_size + oov_buckets, table2.size().eval()) + @test_util.run_deprecated_v1 def testSparseTensor(self): vocab_file = self._createVocabFile("feat_to_id_7.txt") input_indices = [[0, 0], [0, 1], [2, 0], [2, 2], [3, 0]] @@ -1430,6 +1492,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertAllEqual([0, 1, 0, 2, 3], sp_ids_val) self.assertAllEqual(input_shape, sp_ids_shape) + @test_util.run_deprecated_v1 def testInt32SparseTensor(self): input_indices = [[0, 0], [0, 1], [2, 0], [2, 2], [3, 0]] input_shape = [4, 4] @@ -1458,6 +1521,7 @@ class IdTableWithHashBucketsTest(test.TestCase): self.assertAllEqual([0, 1, 0, 2, 3], sp_ids_val) self.assertAllEqual(input_shape, sp_ids_shape) + @test_util.run_deprecated_v1 def testInt64SparseTensor(self): input_indices = [[0, 0], [0, 1], [2, 0], [2, 2], [3, 0]] input_shape = [4, 4] diff --git a/tensorflow/python/kernel_tests/losses_test.py b/tensorflow/python/kernel_tests/losses_test.py index bda63bcaa9..abff61f81b 100644 --- a/tensorflow/python/kernel_tests/losses_test.py +++ b/tensorflow/python/kernel_tests/losses_test.py @@ -51,22 +51,26 @@ class AbsoluteDifferenceLossTest(test.TestCase): losses.absolute_difference( self._predictions, self._predictions, weights=None) + @test_util.run_deprecated_v1 def testAllCorrectNoLossWeight(self): loss = losses.absolute_difference(self._predictions, self._predictions) with self.cached_session(): self.assertAlmostEqual(0.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLoss(self): loss = losses.absolute_difference(self._labels, self._predictions) with self.cached_session(): self.assertAlmostEqual(5.5, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPythonScalarWeight(self): weights = 2.3 loss = losses.absolute_difference(self._labels, self._predictions, weights) with self.cached_session(): self.assertAlmostEqual(5.5 * weights, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeight(self): weights = 2.3 loss = losses.absolute_difference(self._labels, self._predictions, @@ -123,6 +127,7 @@ class SoftmaxCrossEntropyLossTest(test.TestCase): with self.assertRaises(ValueError): losses.softmax_cross_entropy(labels, logits, weights=None) + @test_util.run_deprecated_v1 def testAllCorrect(self): with self.cached_session(): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], @@ -132,6 +137,7 @@ class SoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals('softmax_cross_entropy_loss/value', loss.op.name) self.assertAlmostEqual(loss.eval(), 0.0, 3) + @test_util.run_deprecated_v1 def testAllWrong(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -142,6 +148,7 @@ class SoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals(loss.op.name, 'softmax_cross_entropy_loss/value') self.assertAlmostEqual(loss.eval(), 10.0, 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPythonScalarWeight(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -151,6 +158,7 @@ class SoftmaxCrossEntropyLossTest(test.TestCase): loss = losses.softmax_cross_entropy(labels, logits, weights) self.assertAlmostEqual(weights * 10.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeight(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -200,6 +208,7 @@ class SoftmaxCrossEntropyLossTest(test.TestCase): with self.assertRaises(ValueError): losses.softmax_cross_entropy(labels, logits, weights=weights).eval() + @test_util.run_deprecated_v1 def testSoftmaxLabelSmoothing(self): with self.cached_session(): # Softmax Cross Entropy Loss is: @@ -232,6 +241,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): with self.assertRaises(ValueError): losses.sparse_softmax_cross_entropy(labels, logits, weights=None) + @test_util.run_deprecated_v1 def testAllCorrectInt32Labels(self): with self.cached_session(): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], @@ -248,6 +258,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): labels = constant_op.constant([[0], [1], [2]], dtype=dtypes.int32) losses.sparse_softmax_cross_entropy(labels, logits) + @test_util.run_deprecated_v1 def testAllCorrectInt64Labels(self): with self.cached_session(): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], @@ -257,6 +268,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals(loss.op.name, 'sparse_softmax_cross_entropy_loss/value') self.assertAlmostEqual(loss.eval(), 0.0, 3) + @test_util.run_deprecated_v1 def testAllCorrectNonColumnLabels(self): with self.cached_session(): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], @@ -266,6 +278,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals(loss.op.name, 'sparse_softmax_cross_entropy_loss/value') self.assertAlmostEqual(loss.eval(), 0.0, 3) + @test_util.run_deprecated_v1 def testAllWrongInt32Labels(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -276,6 +289,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals(loss.op.name, 'sparse_softmax_cross_entropy_loss/value') self.assertAlmostEqual(loss.eval(), 10.0, 3) + @test_util.run_deprecated_v1 def testAllWrongInt64Labels(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -286,6 +300,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals(loss.op.name, 'sparse_softmax_cross_entropy_loss/value') self.assertAlmostEqual(loss.eval(), 10.0, 3) + @test_util.run_deprecated_v1 def testAllWrongNonColumnLabels(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -296,6 +311,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): self.assertEquals(loss.op.name, 'sparse_softmax_cross_entropy_loss/value') self.assertAlmostEqual(loss.eval(), 10.0, 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPythonScalarWeight(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -305,6 +321,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): loss = losses.sparse_softmax_cross_entropy(labels, logits, weights) self.assertAlmostEqual(weights * 10.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeight(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]) @@ -325,6 +342,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): labels, logits, constant_op.constant((weights,))) self.assertAlmostEqual(weights * 10.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPlaceholderForWeights(self): logits = constant_op.constant([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], @@ -337,6 +355,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): feed_dict={weights: ((1.2,), (3.4,), (5.6,))}) self.assertAlmostEqual((1.2 + 3.4 + 5.6) * 10.0 / 3.0, loss_val, 3) + @test_util.run_deprecated_v1 def testUnknownShapePlaceholderForLogitsLabelsButScalarWeights(self): logits = array_ops.placeholder(dtypes.float32) labels = array_ops.placeholder(dtypes.int32) @@ -352,6 +371,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): }) self.assertAlmostEqual((1.0 + 1.0 + 1.0) * 10.0 / 3.0, loss_val, 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPlaceholderForLogitsLabelsAndWeights(self): logits = array_ops.placeholder(dtypes.float32, shape=(None, 3)) labels = array_ops.placeholder(dtypes.int32, shape=(None, 1)) @@ -406,6 +426,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): loss = losses.sparse_softmax_cross_entropy(labels, logits, weights) self.assertAlmostEqual(12.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testMeasurementSpecificWeightsRaisesException(self): with self.cached_session(): logits = constant_op.constant([[100.0, -100.0, -100.0], @@ -444,6 +465,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): losses.sparse_softmax_cross_entropy( labels, logits, weights=weights).eval() + @test_util.run_deprecated_v1 def testInconsistentWeightShapeRaisesException(self): """The weight tensor has incorrect shape.""" with self.cached_session(): @@ -458,6 +480,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): losses.sparse_softmax_cross_entropy( labels, logits, weights=weights).eval() + @test_util.run_deprecated_v1 def testInconsistentLabelShapeRaisesException(self): """The label tensor has incorrect shape.""" with self.cached_session(): @@ -475,6 +498,7 @@ class SparseSoftmaxCrossEntropyLossTest(test.TestCase): class SigmoidCrossEntropyLossTest(test.TestCase): + @test_util.run_deprecated_v1 def testAllCorrectSigmoid(self): with self.cached_session(): logits = constant_op.constant([[100.0, -100.0, -100.0], @@ -486,6 +510,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): self.assertEquals('sigmoid_cross_entropy_loss/value', loss.op.name) self.assertAlmostEqual(0.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testLossWithSingleDimPlaceholderForLogitsAndWeights1(self): logits = array_ops.placeholder(dtypes.float32, shape=(None, 1)) labels = array_ops.placeholder(dtypes.float32, shape=(None, 1)) @@ -502,6 +527,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): }) self.assertAlmostEqual(0.313, loss, 3) + @test_util.run_deprecated_v1 def testLossWithSingleDimPlaceholderForLogitsAndWeights2(self): logits = array_ops.placeholder(dtypes.float32, shape=(None, 2)) labels = array_ops.placeholder(dtypes.float32, shape=(None, 2)) @@ -518,6 +544,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): }) self.assertAlmostEqual(0.313, loss, 3) + @test_util.run_deprecated_v1 def testAllWrongSigmoid(self): with self.cached_session(): logits = constant_op.constant([[100.0, -100.0, -100.0], @@ -529,6 +556,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): self.assertEquals('sigmoid_cross_entropy_loss/value', loss.op.name) self.assertAlmostEqual(loss.eval(), 600.0 / 9.0, 3) + @test_util.run_deprecated_v1 def testAllWrongSigmoidWithMeasurementSpecificWeights(self): with self.cached_session(): logits = constant_op.constant([[100.0, -100.0, -100.0], @@ -541,6 +569,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): self.assertEquals('sigmoid_cross_entropy_loss/value', loss.op.name) self.assertAlmostEqual(1700.0 / 7.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testMultiCorrectSigmoid(self): logits = constant_op.constant([[100.0, -100.0, 100.0], [100.0, 100.0, -100.0], @@ -582,6 +611,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): self.assertAllClose(((0., 0., 0.), (0., 100., 100.), (100., 0., 100.)), self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testSigmoidLabelSmoothingCorrect(self): with self.cached_session(): logits = constant_op.constant([[100.0, -100.0, -100.0]]) @@ -605,6 +635,7 @@ class SigmoidCrossEntropyLossTest(test.TestCase): expected_value = (100.0 + 50.0 * label_smoothing) / 3.0 self.assertAlmostEqual(loss.eval(), expected_value, 3) + @test_util.run_deprecated_v1 def testSigmoidLabelSmoothingEqualsSoftmaxTwoLabel(self): with self.cached_session(): label_smoothing = 0.1 @@ -646,11 +677,13 @@ class LogLossTest(test.TestCase): with self.assertRaises(ValueError): losses.log_loss(self._labels, self._labels, weights=None) + @test_util.run_deprecated_v1 def testAllCorrectNoLossWeight(self): loss = losses.log_loss(self._labels, self._labels) with self.cached_session(): self.assertAlmostEqual(0.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testAllCorrectNoLossWeightWithPlaceholder(self): tf_predictions = array_ops.placeholder( dtypes.float32, shape=self._np_labels.shape) @@ -659,12 +692,14 @@ class LogLossTest(test.TestCase): self.assertAlmostEqual( 0.0, loss.eval(feed_dict={tf_predictions: self._np_labels}), 3) + @test_util.run_deprecated_v1 def testNonZeroLoss(self): loss = losses.log_loss(self._labels, self._predictions) with self.cached_session(): self.assertAlmostEqual(-np.sum(self._expected_losses) / 6.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPythonScalarWeight(self): weights = 2.3 loss = losses.log_loss(self._labels, self._predictions, weights) @@ -672,6 +707,7 @@ class LogLossTest(test.TestCase): self.assertAlmostEqual(weights * -np.sum(self._expected_losses) / 6.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeight(self): weights = 2.3 loss = losses.log_loss(self._labels, self._predictions, @@ -680,6 +716,7 @@ class LogLossTest(test.TestCase): self.assertAlmostEqual(weights * -np.sum(self._expected_losses) / 6.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeightAndPlaceholder(self): tf_predictions = array_ops.placeholder( dtypes.float32, shape=self._np_predictions.shape) @@ -691,6 +728,7 @@ class LogLossTest(test.TestCase): self.assertAlmostEqual(weights * -np.sum(self._expected_losses) / 6.0, loss, 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeightAndPlaceholderWithRankOnly(self): tf_predictions = array_ops.placeholder(dtypes.float32, shape=[None, None]) weights = 2.3 @@ -750,6 +788,7 @@ class LogLossTest(test.TestCase): self.assertAlmostEqual(-np.sum(expected_losses) / 5.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithMeasurementSpecificWeightsWithPlaceholder(self): weights = np.array([3, 6, 5, 0, 4, 2]).reshape((2, 3)) expected_losses = np.multiply(self._expected_losses, weights) @@ -777,6 +816,7 @@ class LogLossTest(test.TestCase): with self.cached_session(): self.assertAlmostEqual(-np.sum(expected_losses), self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithSampleSpecificWeightsMostZeroWithPlaceholder(self): weights = np.array([0, 0, 0, 0, 0, 2]).reshape((2, 3)) expected_losses = np.multiply(self._expected_losses, weights) @@ -805,6 +845,7 @@ class HingeLossTest(test.TestCase): with self.assertRaises(ValueError): _ = losses.hinge_loss(labels, logits).eval() + @test_util.run_deprecated_v1 def testAllOutsideMargin(self): with self.cached_session(): logits = constant_op.constant([1.2, -1.4, -1.0, 2.1]) @@ -812,6 +853,7 @@ class HingeLossTest(test.TestCase): loss = losses.hinge_loss(labels, logits) self.assertAllClose(loss.eval(), 0.0, atol=1e-3) + @test_util.run_deprecated_v1 def testSomeInsideMargin(self): with self.cached_session(): logits = constant_op.constant([[-0.7], [-1.4], [1.4], [0.6]]) @@ -821,6 +863,7 @@ class HingeLossTest(test.TestCase): # the margin so they incur some (small) loss. self.assertAllClose(loss.eval(), 0.175, atol=1e-3) + @test_util.run_deprecated_v1 def testSomeMisclassified(self): with self.cached_session(): logits = constant_op.constant([[[1.2], [0.4], [-1.0], [-1.1]]]) @@ -840,6 +883,7 @@ class HuberLossTest(test.TestCase): with self.assertRaises(ValueError): _ = losses.huber_loss(labels, predictions).eval() + @test_util.run_deprecated_v1 def testAllQuadratic(self): with self.cached_session(): predictions = constant_op.constant([1.5, -1.4, -1.0, 0.0]) @@ -848,6 +892,7 @@ class HuberLossTest(test.TestCase): self.assertAllClose(loss.eval(), 0.5 * (0.25 + 0.16 + 1.0 + 0.25) / 4., atol=1e-5) + @test_util.run_deprecated_v1 def testAllLinear(self): with self.cached_session(): predictions = constant_op.constant([1.5, -1.4, -1.0, 0.0]) @@ -856,6 +901,7 @@ class HuberLossTest(test.TestCase): self.assertAllClose(loss.eval(), (1.5 + 2.4 + 1.0 + 1.5) / 4. - 0.5, atol=1e-5) + @test_util.run_deprecated_v1 def testMixedQuadraticLinear(self): with self.cached_session(): predictions = constant_op.constant([[1.5, -1.4, -1.0, 0.0], @@ -901,6 +947,7 @@ class MeanSquaredErrorTest(test.TestCase): losses.mean_squared_error( self._predictions, self._predictions, weights=None) + @test_util.run_deprecated_v1 def testScalar(self): with self.cached_session(): self.assertEqual( @@ -908,22 +955,26 @@ class MeanSquaredErrorTest(test.TestCase): losses.mean_squared_error(predictions=constant_op.constant(0), labels=constant_op.constant(0)).eval()) + @test_util.run_deprecated_v1 def testAllCorrectNoLossWeight(self): loss = losses.mean_squared_error(self._predictions, self._predictions) with self.cached_session(): self.assertAlmostEqual(0.0, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLoss(self): loss = losses.mean_squared_error(self._labels, self._predictions) with self.cached_session(): self.assertAlmostEqual(49.5, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithPythonScalarWeight(self): weights = 2.3 loss = losses.mean_squared_error(self._labels, self._predictions, weights) with self.cached_session(): self.assertAlmostEqual(49.5 * weights, self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeight(self): weights = 2.3 loss = losses.mean_squared_error(self._labels, self._predictions, @@ -1017,10 +1068,12 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): self.assertAlmostEqual( expected_loss, dynamic_inputs_op.eval(feed_dict=feed_dict), places=3) + @test_util.run_deprecated_v1 def testAllCorrectNoLossWeight(self): self._test_valid_weights( self._labels, self._labels, expected_loss=0.0) + @test_util.run_deprecated_v1 def testNonZeroLoss(self): self._test_valid_weights( self._labels, self._predictions, @@ -1051,6 +1104,7 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): np_grad = self.evaluate(grad) self.assertFalse(np.isnan(np_grad).any()) + @test_util.run_deprecated_v1 def testNonZeroLossWithPythonScalarWeight(self): weight = 2.3 self._test_valid_weights( @@ -1058,6 +1112,7 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): expected_loss=weight * np.sum(self._expected_losses), weights=weight) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarTensorWeight(self): weights = 2.3 loss = losses.mean_pairwise_squared_error( @@ -1068,10 +1123,12 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): self.assertAlmostEqual(weights * np.sum(self._expected_losses), self.evaluate(loss), 3) + @test_util.run_deprecated_v1 def testNonZeroLossWithScalarZeroWeight(self): self._test_valid_weights( self._labels, self._predictions, expected_loss=0.0, weights=0.0) + @test_util.run_deprecated_v1 def test3d(self): labels = np.array([ [[1, 9, 2], [12, 11, 10], [9, 8, 7]], @@ -1083,6 +1140,7 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): ]) self._test_valid_weights(labels, predictions, expected_loss=137.5) + @test_util.run_deprecated_v1 def test3dWeightedScalar(self): labels = np.array([ [[1, 9, 2], [12, 11, 10], [9, 8, 7]], @@ -1121,6 +1179,7 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): weights_placeholder: weights, }) + @test_util.run_deprecated_v1 def testInvalid3dWeighted2x0(self): labels = np.array([ [[1, 9, 2], [12, 11, 10], [9, 8, 7]], @@ -1133,6 +1192,7 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): self._test_invalid_weights( labels, predictions, weights=np.asarray((1.2, 3.4))) + @test_util.run_deprecated_v1 def test3dWeighted2x3x3(self): labels = np.array([ [[1, 9, 2], [12, 11, 10], [9, 8, 7]], @@ -1149,6 +1209,7 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): expected_loss=9 * 137.5, weights=np.ones((2, 3, 3))) + @test_util.run_deprecated_v1 def testLossWithAllZeroBatchSpecificWeights(self): self._test_valid_weights( self._labels, self._predictions, expected_loss=0.0, @@ -1268,6 +1329,7 @@ class CosineDistanceLossTest(test.TestCase): with self.cached_session(): self.assertEqual(3.0 / 4.0, self.evaluate(loss)) + @test_util.run_deprecated_v1 def testMeasurementSpecificWeightsWithPlaceholderWithShape(self): tf_predictions = array_ops.placeholder( dtypes.float32, shape=self._labels.shape) diff --git a/tensorflow/python/kernel_tests/lrn_op_test.py b/tensorflow/python/kernel_tests/lrn_op_test.py index 7ebeb91d90..fbe628c394 100644 --- a/tensorflow/python/kernel_tests/lrn_op_test.py +++ b/tensorflow/python/kernel_tests/lrn_op_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -92,6 +93,7 @@ class LRNOpTest(test.TestCase): self.assertTrue(err < 1e-2) self.assertShapeEqual(expected, lrn_t) + @test_util.run_deprecated_v1 def testCompute(self): for _ in range(2): self._RunAndVerify(dtypes.float32) @@ -99,6 +101,7 @@ class LRNOpTest(test.TestCase): if not test.is_gpu_available(): self._RunAndVerify(dtypes.float16) + @test_util.run_deprecated_v1 def testGradientsZeroInput(self): with self.session(use_gpu=True): shape = [4, 4, 4, 4] @@ -147,6 +150,7 @@ class LRNOpTest(test.TestCase): else: self.assertLess(err, 1.0) + @test_util.run_deprecated_v1 def testGradients(self): for _ in range(2): self._RunAndVerifyGradients(dtypes.float32) diff --git a/tensorflow/python/kernel_tests/manip_ops_test.py b/tensorflow/python/kernel_tests/manip_ops_test.py index f71857a3cb..5700db4b95 100644 --- a/tensorflow/python/kernel_tests/manip_ops_test.py +++ b/tensorflow/python/kernel_tests/manip_ops_test.py @@ -62,6 +62,7 @@ class RollTest(test_util.TensorFlowTestCase): if np_input.dtype == np.float32: self._testGradient(np_input, shift, axis) + @test_util.run_deprecated_v1 def testIntTypes(self): for t in [np.int32, np.int64]: self._testAll(np.random.randint(-100, 100, (5)).astype(t), 3, 0) @@ -73,6 +74,7 @@ class RollTest(test_util.TensorFlowTestCase): np.random.randint(-100, 100, (4, 2, 1, 3)).astype(t), [0, 1, -2], [1, 2, 3]) + @test_util.run_deprecated_v1 def testFloatTypes(self): for t in [np.float32, np.float64]: self._testAll(np.random.rand(5).astype(t), 2, 0) @@ -80,6 +82,7 @@ class RollTest(test_util.TensorFlowTestCase): self._testAll(np.random.rand(3, 4).astype(t), [1, 2], [1, 0]) self._testAll(np.random.rand(1, 3, 4).astype(t), [1, 0, -3], [0, 1, 2]) + @test_util.run_deprecated_v1 def testComplexTypes(self): for t in [np.complex64, np.complex128]: x = np.random.rand(4, 4).astype(t) @@ -90,6 +93,7 @@ class RollTest(test_util.TensorFlowTestCase): x = np.random.rand(3, 2, 1, 1).astype(t) self._testAll(x + 1j * x, [2, 1, 1, 0], [0, 3, 1, 2]) + @test_util.run_deprecated_v1 def testNegativeAxis(self): self._testAll(np.random.randint(-100, 100, (5)).astype(np.int32), 3, -1) self._testAll(np.random.randint(-100, 100, (4, 4)).astype(np.int32), 3, -2) @@ -100,12 +104,14 @@ class RollTest(test_util.TensorFlowTestCase): manip_ops.roll(np.random.randint(-100, 100, (4, 4)).astype(np.int32), 3, -10).eval() + @test_util.run_deprecated_v1 def testInvalidInputShape(self): # The input should be 1-D or higher, checked in shape function. with self.assertRaisesRegexp( ValueError, "Shape must be at least rank 1 but is rank 0"): manip_ops.roll(7, 1, 0) + @test_util.run_deprecated_v1 def testRollInputMustVectorHigherRaises(self): # The input should be 1-D or higher, checked in kernel. tensor = array_ops.placeholder(dtype=dtypes.int32) @@ -116,12 +122,14 @@ class RollTest(test_util.TensorFlowTestCase): "input must be 1-D or higher"): manip_ops.roll(tensor, shift, axis).eval(feed_dict={tensor: 7}) + @test_util.run_deprecated_v1 def testInvalidAxisShape(self): # The axis should be a scalar or 1-D, checked in shape function. with self.assertRaisesRegexp( ValueError, "Shape must be at most rank 1 but is rank 2"): manip_ops.roll([[1, 2], [3, 4]], 1, [[0, 1]]) + @test_util.run_deprecated_v1 def testRollAxisMustBeScalarOrVectorRaises(self): # The axis should be a scalar or 1-D, checked in kernel. tensor = [[1, 2], [3, 4]] @@ -132,12 +140,14 @@ class RollTest(test_util.TensorFlowTestCase): "axis must be a scalar or a 1-D vector"): manip_ops.roll(tensor, shift, axis).eval(feed_dict={axis: [[0, 1]]}) + @test_util.run_deprecated_v1 def testInvalidShiftShape(self): # The shift should be a scalar or 1-D, checked in shape function. with self.assertRaisesRegexp( ValueError, "Shape must be at most rank 1 but is rank 2"): manip_ops.roll([[1, 2], [3, 4]], [[0, 1]], 1) + @test_util.run_deprecated_v1 def testRollShiftMustBeScalarOrVectorRaises(self): # The shift should be a scalar or 1-D, checked in kernel. tensor = [[1, 2], [3, 4]] @@ -148,11 +158,13 @@ class RollTest(test_util.TensorFlowTestCase): "shift must be a scalar or a 1-D vector"): manip_ops.roll(tensor, shift, axis).eval(feed_dict={shift: [[0, 1]]}) + @test_util.run_deprecated_v1 def testInvalidShiftAndAxisNotEqualShape(self): # The shift and axis must be same size, checked in shape function. with self.assertRaisesRegexp(ValueError, "both shapes must be equal"): manip_ops.roll([[1, 2], [3, 4]], [1], [0, 1]) + @test_util.run_deprecated_v1 def testRollShiftAndAxisMustBeSameSizeRaises(self): # The shift and axis must be same size, checked in kernel. tensor = [[1, 2], [3, 4]] diff --git a/tensorflow/python/kernel_tests/map_stage_op_test.py b/tensorflow/python/kernel_tests/map_stage_op_test.py index d503f3d7c9..dd16fad690 100644 --- a/tensorflow/python/kernel_tests/map_stage_op_test.py +++ b/tensorflow/python/kernel_tests/map_stage_op_test.py @@ -19,6 +19,7 @@ from __future__ import print_function from tensorflow.python.framework import errors from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import math_ops @@ -29,6 +30,7 @@ TIMEOUT = 1 class MapStageTest(test.TestCase): + @test_util.run_deprecated_v1 def testSimple(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -50,6 +52,7 @@ class MapStageTest(test.TestCase): _, yval = sess.run([stage, y], feed_dict={x: i, pi: i + 1, gi: i}) self.assertAllClose(4 * (i - 1) * (i - 1) * 128, yval, rtol=1e-4) + @test_util.run_deprecated_v1 def testMultiple(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -72,6 +75,7 @@ class MapStageTest(test.TestCase): self.assertAllClose( 4 * (i - 1) * (i - 1) * (i - 1) * 128, yval, rtol=1e-4) + @test_util.run_deprecated_v1 def testDictionary(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -121,6 +125,7 @@ class MapStageTest(test.TestCase): G.finalize() + @test_util.run_deprecated_v1 def testPeek(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -150,6 +155,7 @@ class MapStageTest(test.TestCase): self.assertTrue(sess.run(size) == 10) + @test_util.run_deprecated_v1 def testSizeAndClear(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -176,6 +182,7 @@ class MapStageTest(test.TestCase): sess.run(clear) self.assertEqual(sess.run(size), 0) + @test_util.run_deprecated_v1 def testCapacity(self): capacity = 3 @@ -239,6 +246,7 @@ class MapStageTest(test.TestCase): self.assertTrue(sess.run(size) == 0) + @test_util.run_deprecated_v1 def testMemoryLimit(self): memory_limit = 512 * 1024 # 512K chunk = 200 * 1024 # 256K @@ -303,6 +311,7 @@ class MapStageTest(test.TestCase): self.assertTrue(sess.run(size) == 0) + @test_util.run_deprecated_v1 def testOrdering(self): import six import random @@ -341,6 +350,7 @@ class MapStageTest(test.TestCase): self.assertTrue(sess.run(size) == 0) + @test_util.run_deprecated_v1 def testPartialDictInsert(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -400,6 +410,7 @@ class MapStageTest(test.TestCase): 'v': 3 }]) + @test_util.run_deprecated_v1 def testPartialIndexInsert(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -443,6 +454,7 @@ class MapStageTest(test.TestCase): # We can now obtain tuple associated with key 1 self.assertTrue(sess.run([key, ret], feed_dict={gi: 1}) == [1, [1, 3, 2]]) + @test_util.run_deprecated_v1 def testPartialDictGetsAndPeeks(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -540,6 +552,7 @@ class MapStageTest(test.TestCase): # Nothing is left self.assertTrue(sess.run([size, isize]) == [0, 0]) + @test_util.run_deprecated_v1 def testPartialIndexGets(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): diff --git a/tensorflow/python/kernel_tests/matmul_op_test.py b/tensorflow/python/kernel_tests/matmul_op_test.py index 6167e01864..983f463f5e 100644 --- a/tensorflow/python/kernel_tests/matmul_op_test.py +++ b/tensorflow/python/kernel_tests/matmul_op_test.py @@ -194,6 +194,7 @@ except AttributeError: class MatMulInfixOperatorTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testMismatchedShape(self): with self.assertRaisesWithPredicateMatch(ValueError, lambda e: "Shape must" in str(e)): @@ -201,6 +202,7 @@ class MatMulInfixOperatorTest(test_lib.TestCase): ops.convert_to_tensor([10.0, 20.0, 30.0]), ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0]])) + @test_util.run_deprecated_v1 def testMismatchedDimensions(self): with self.assertRaisesWithPredicateMatch( ValueError, lambda e: "Dimensions must" in str(e)): @@ -208,12 +210,14 @@ class MatMulInfixOperatorTest(test_lib.TestCase): ops.convert_to_tensor([[10.0, 20.0, 30.0]]), ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0]])) + @test_util.run_deprecated_v1 def testInfixMatmulIsTfMatmul(self): a = ops.convert_to_tensor([[10.0, 20.0, 30.0]]) b = ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0], [80.0, 90.0]]) c = infix_matmul(a, b) self.assertEqual(c.op.type, "MatMul") + @test_util.run_deprecated_v1 def testInfixMatmulDoesDotProduct(self): a = ops.convert_to_tensor([[10.0, 20.0, 30.0]]) b = ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0], [80.0, 90.0]]) diff --git a/tensorflow/python/kernel_tests/matrix_exponential_op_test.py b/tensorflow/python/kernel_tests/matrix_exponential_op_test.py index 83f4216e4d..372b6dc17f 100644 --- a/tensorflow/python/kernel_tests/matrix_exponential_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_exponential_op_test.py @@ -122,12 +122,14 @@ class ExponentialOpTest(test.TestCase): # Complex batch self._verifyExponentialComplex(self._makeBatch(matrix1, matrix2)) + @test_util.run_deprecated_v1 def testNonSquareMatrix(self): # When the exponential of a non-square matrix is attempted we should return # an error with self.assertRaises(ValueError): linalg_impl.matrix_exponential(np.array([[1., 2., 3.], [3., 4., 5.]])) + @test_util.run_deprecated_v1 def testWrongDimensions(self): # The input to the exponential should be at least a 2-dimensional tensor. tensor3 = constant_op.constant([1., 2.]) @@ -138,6 +140,7 @@ class ExponentialOpTest(test.TestCase): self._verifyExponentialReal(np.empty([0, 2, 2])) self._verifyExponentialReal(np.empty([2, 0, 0])) + @test_util.run_deprecated_v1 def testDynamic(self): with self.session(use_gpu=True) as sess: inp = array_ops.placeholder(ops.dtypes.float32) @@ -145,6 +148,7 @@ class ExponentialOpTest(test.TestCase): matrix = np.array([[1., 2.], [3., 4.]]) sess.run(expm, feed_dict={inp: matrix}) + @test_util.run_deprecated_v1 def testConcurrentExecutesWithoutError(self): with self.session(use_gpu=True) as sess: matrix1 = random_ops.random_normal([5, 5], seed=42) diff --git a/tensorflow/python/kernel_tests/matrix_solve_ls_op_test.py b/tensorflow/python/kernel_tests/matrix_solve_ls_op_test.py index 13a7df7f95..a6f5da9d3d 100644 --- a/tensorflow/python/kernel_tests/matrix_solve_ls_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_solve_ls_op_test.py @@ -24,6 +24,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import linalg_ops @@ -133,6 +134,7 @@ class MatrixSolveLsOpTest(test_lib.TestCase): self.assertEqual(np_ans.shape, tf_ans_val.shape) self.assertAllClose(np_ans, tf_ans_val, atol=2 * tol, rtol=2 * tol) + @test_util.run_deprecated_v1 def testWrongDimensions(self): # The matrix and right-hand sides should have the same number of rows. with self.session(use_gpu=True): @@ -141,6 +143,7 @@ class MatrixSolveLsOpTest(test_lib.TestCase): with self.assertRaises(ValueError): linalg_ops.matrix_solve_ls(matrix, rhs) + @test_util.run_deprecated_v1 def testEmpty(self): full = np.array([[1., 2.], [3., 4.], [5., 6.]]) empty0 = np.empty([3, 0]) @@ -156,6 +159,7 @@ class MatrixSolveLsOpTest(test_lib.TestCase): tf_ans = linalg_ops.matrix_solve_ls(empty1, empty1, fast=fast).eval() self.assertEqual(tf_ans.shape, (2, 2)) + @test_util.run_deprecated_v1 def testBatchResultSize(self): # 3x3x3 matrices, 3x3x1 right-hand sides. matrix = np.array([1., 2., 3., 4., 5., 6., 7., 8., 9.] * 3).reshape(3, 3, 3) diff --git a/tensorflow/python/kernel_tests/matrix_solve_op_test.py b/tensorflow/python/kernel_tests/matrix_solve_op_test.py index 80badee896..db7c4802f6 100644 --- a/tensorflow/python/kernel_tests/matrix_solve_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_solve_op_test.py @@ -24,6 +24,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import linalg_ops @@ -75,6 +76,7 @@ class MatrixSolveOpTest(test.TestCase): [m, n])) return matrix + @test_util.run_deprecated_v1 def testSolve(self): for n in 1, 2, 4, 9: matrix = self._generateMatrix(n, n) @@ -82,6 +84,7 @@ class MatrixSolveOpTest(test.TestCase): rhs = self._generateMatrix(n, nrhs) self._verifySolve(matrix, rhs) + @test_util.run_deprecated_v1 def testSolveBatch(self): for n in 2, 5: matrix = self._generateMatrix(n, n) @@ -90,6 +93,7 @@ class MatrixSolveOpTest(test.TestCase): for batch_dims in [[2], [2, 2], [7, 4]]: self._verifySolve(matrix, rhs, batch_dims=batch_dims) + @test_util.run_deprecated_v1 def testNonSquareMatrix(self): # When the solve of a non-square matrix is attempted we should return # an error @@ -98,6 +102,7 @@ class MatrixSolveOpTest(test.TestCase): matrix = constant_op.constant([[1., 2., 3.], [3., 4., 5.]]) linalg_ops.matrix_solve(matrix, matrix) + @test_util.run_deprecated_v1 def testWrongDimensions(self): # The matrix and right-hand sides should have the same number of rows. with self.session(use_gpu=True): @@ -115,6 +120,7 @@ class MatrixSolveOpTest(test.TestCase): [0., -1., 1.]]) linalg_ops.matrix_solve(matrix, matrix).eval() + @test_util.run_deprecated_v1 def testConcurrent(self): with self.session(use_gpu=True) as sess: all_ops = [] diff --git a/tensorflow/python/kernel_tests/matrix_triangular_solve_op_test.py b/tensorflow/python/kernel_tests/matrix_triangular_solve_op_test.py index 317b8f8716..dde83f12f3 100644 --- a/tensorflow/python/kernel_tests/matrix_triangular_solve_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_triangular_solve_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.platform import test @@ -93,6 +94,7 @@ class MatrixTriangularSolveOpTest(test.TestCase): self.assertEqual(np_ans.shape, tf_val.shape) self.assertAllClose(np_ans, tf_val) + @test_util.run_deprecated_v1 def testSolve(self): # 1x1 matrix, single rhs. matrix = np.array([[0.1]]) @@ -106,6 +108,7 @@ class MatrixTriangularSolveOpTest(test.TestCase): rhs1 = np.array([[1., 0., 1.], [0., 1., 1.]]) self._verifySolveAllWaysReal(matrix, rhs1) + @test_util.run_deprecated_v1 def testSolveComplex(self): # 1x1 matrix, single rhs. matrix = np.array([[0.1 + 1j * 0.1]]) @@ -122,6 +125,7 @@ class MatrixTriangularSolveOpTest(test.TestCase): rhs1 += 1j * rhs1 self._verifySolveAllWaysComplex(matrix, rhs1) + @test_util.run_deprecated_v1 def testSolveBatch(self): matrix = np.array([[1., 2.], [3., 4.]]) rhs = np.array([[1., 0., 1.], [0., 1., 1.]]) @@ -130,6 +134,7 @@ class MatrixTriangularSolveOpTest(test.TestCase): # Batch of 3x2x2x2 matrices, 3x2x2x3 right-hand sides. self._verifySolveAllWaysReal(matrix, rhs, batch_dims=[3, 2]) + @test_util.run_deprecated_v1 def testSolveBatchComplex(self): matrix = np.array([[1., 2.], [3., 4.]]).astype(np.complex64) matrix += 1j * matrix @@ -140,6 +145,7 @@ class MatrixTriangularSolveOpTest(test.TestCase): # Batch of 3x2x2x2 matrices, 3x2x2x3 right-hand sides. self._verifySolveAllWaysComplex(matrix, rhs, batch_dims=[3, 2]) + @test_util.run_deprecated_v1 def testNonSquareMatrix(self): # A non-square matrix should cause an error. matrix = np.array([[1., 2., 3.], [3., 4., 5.]]) @@ -149,6 +155,7 @@ class MatrixTriangularSolveOpTest(test.TestCase): with self.assertRaises(ValueError): self._verifySolve(matrix, matrix, batch_dims=[2, 3]) + @test_util.run_deprecated_v1 def testWrongDimensions(self): # The matrix should have the same number of rows as the # right-hand sides. diff --git a/tensorflow/python/kernel_tests/metrics_test.py b/tensorflow/python/kernel_tests/metrics_test.py index eb5f99582c..64dd591455 100644 --- a/tensorflow/python/kernel_tests/metrics_test.py +++ b/tensorflow/python/kernel_tests/metrics_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import math_ops @@ -175,22 +176,26 @@ class MeanTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean(array_ops.ones([4, 3])) _assert_metric_variables(self, ('mean/count:0', 'mean/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.mean( array_ops.ones([4, 3]), metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean( array_ops.ones([4, 3]), updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testBasic(self): with self.cached_session() as sess: values_queue = data_flow_ops.FIFOQueue( @@ -208,6 +213,7 @@ class MeanTest(test.TestCase): self.evaluate(update_op) self.assertAlmostEqual(1.65, self.evaluate(mean), 5) + @test_util.run_deprecated_v1 def testUpdateOpsReturnsCurrentValue(self): with self.cached_session() as sess: values_queue = data_flow_ops.FIFOQueue( @@ -229,6 +235,7 @@ class MeanTest(test.TestCase): self.assertAlmostEqual(1.65, self.evaluate(mean), 5) + @test_util.run_deprecated_v1 def testUnweighted(self): values = _test_values((3, 2, 4, 1)) mean_results = ( @@ -271,37 +278,44 @@ class MeanTest(test.TestCase): self.assertAlmostEqual(expected, update_op.eval(), places=5) self.assertAlmostEqual(expected, mean.eval(), places=5) + @test_util.run_deprecated_v1 def test1x1x1Weighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), weights=np.asarray((5,)).reshape((1, 1, 1))) + @test_util.run_deprecated_v1 def test1x1xNWeighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), weights=np.asarray((5, 7, 11, 3)).reshape((1, 1, 4))) + @test_util.run_deprecated_v1 def test1xNx1Weighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), weights=np.asarray((5, 11)).reshape((1, 2, 1))) + @test_util.run_deprecated_v1 def test1xNxNWeighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), weights=np.asarray((5, 7, 11, 3, 2, 13, 7, 5)).reshape((1, 2, 4))) + @test_util.run_deprecated_v1 def testNx1x1Weighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), weights=np.asarray((5, 7, 11)).reshape((3, 1, 1))) + @test_util.run_deprecated_v1 def testNx1xNWeighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), weights=np.asarray(( 5, 7, 11, 3, 2, 12, 7, 5, 2, 17, 11, 3)).reshape((3, 1, 4))) + @test_util.run_deprecated_v1 def testNxNxNWeighted(self): self._test_3d_weighted( _test_values((3, 2, 4)), @@ -309,6 +323,7 @@ class MeanTest(test.TestCase): 5, 7, 11, 3, 2, 12, 7, 5, 2, 17, 11, 3, 2, 17, 11, 3, 5, 7, 11, 3, 2, 12, 7, 5)).reshape((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidWeights(self): values_placeholder = array_ops.placeholder(dtype=dtypes_lib.float32) values = _test_values((3, 2, 4, 1)) @@ -341,23 +356,27 @@ class MeanTensorTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_tensor(array_ops.ones([4, 3])) _assert_metric_variables(self, ('mean/total_tensor:0', 'mean/count_tensor:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.mean_tensor( array_ops.ones([4, 3]), metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_tensor( array_ops.ones([4, 3]), updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testBasic(self): with self.cached_session() as sess: values_queue = data_flow_ops.FIFOQueue( @@ -375,6 +394,7 @@ class MeanTensorTest(test.TestCase): self.evaluate(update_op) self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(mean)) + @test_util.run_deprecated_v1 def testMultiDimensional(self): with self.cached_session() as sess: values_queue = data_flow_ops.FIFOQueue( @@ -397,6 +417,7 @@ class MeanTensorTest(test.TestCase): self.assertAllClose([[[1, 2], [1, 2]], [[2, 3], [5, 6]]], self.evaluate(mean)) + @test_util.run_deprecated_v1 def testUpdateOpsReturnsCurrentValue(self): with self.cached_session() as sess: values_queue = data_flow_ops.FIFOQueue( @@ -418,6 +439,7 @@ class MeanTensorTest(test.TestCase): self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(mean), 5) + @test_util.run_deprecated_v1 def testBinaryWeighted1d(self): with self.cached_session() as sess: # Create the queue that populates the values. @@ -445,6 +467,7 @@ class MeanTensorTest(test.TestCase): self.evaluate(update_op) self.assertAllClose([[3.25, 0.5]], self.evaluate(mean), 5) + @test_util.run_deprecated_v1 def testWeighted1d(self): with self.cached_session() as sess: # Create the queue that populates the values. @@ -472,6 +495,7 @@ class MeanTensorTest(test.TestCase): self.evaluate(update_op) self.assertAllClose([[0.8, 3.52]], self.evaluate(mean), 5) + @test_util.run_deprecated_v1 def testWeighted2d_1(self): with self.cached_session() as sess: # Create the queue that populates the values. @@ -499,6 +523,7 @@ class MeanTensorTest(test.TestCase): self.evaluate(update_op) self.assertAllClose([[-2.1, 0.5]], self.evaluate(mean), 5) + @test_util.run_deprecated_v1 def testWeighted2d_2(self): with self.cached_session() as sess: # Create the queue that populates the values. @@ -532,6 +557,7 @@ class AccuracyTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.accuracy( predictions=array_ops.ones((10, 1)), @@ -540,6 +566,7 @@ class AccuracyTest(test.TestCase): _assert_metric_variables(self, ('my_accuracy/count:0', 'my_accuracy/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.accuracy( @@ -548,6 +575,7 @@ class AccuracyTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.accuracy( @@ -556,12 +584,14 @@ class AccuracyTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testPredictionsAndLabelsOfDifferentSizeRaisesValueError(self): predictions = array_ops.ones((10, 3)) labels = array_ops.ones((10, 4)) with self.assertRaises(ValueError): metrics.accuracy(labels, predictions) + @test_util.run_deprecated_v1 def testPredictionsAndWeightsOfDifferentSizeRaisesValueError(self): predictions = array_ops.ones((10, 3)) labels = array_ops.ones((10, 3)) @@ -569,6 +599,7 @@ class AccuracyTest(test.TestCase): with self.assertRaises(ValueError): metrics.accuracy(labels, predictions, weights) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=3, dtype=dtypes_lib.int64, seed=1) @@ -588,6 +619,7 @@ class AccuracyTest(test.TestCase): for _ in range(10): self.assertEqual(initial_accuracy, accuracy.eval()) + @test_util.run_deprecated_v1 def testMultipleUpdates(self): with self.cached_session() as sess: # Create the queue that populates the predictions. @@ -616,6 +648,7 @@ class AccuracyTest(test.TestCase): self.assertEqual(0.5, self.evaluate(update_op)) self.assertEqual(0.5, accuracy.eval()) + @test_util.run_deprecated_v1 def testEffectivelyEquivalentSizes(self): predictions = array_ops.ones((40, 1)) labels = array_ops.ones((40,)) @@ -626,6 +659,7 @@ class AccuracyTest(test.TestCase): self.assertEqual(1.0, update_op.eval()) self.assertEqual(1.0, accuracy.eval()) + @test_util.run_deprecated_v1 def testEffectivelyEquivalentSizesWithScalarWeight(self): predictions = array_ops.ones((40, 1)) labels = array_ops.ones((40,)) @@ -636,6 +670,7 @@ class AccuracyTest(test.TestCase): self.assertEqual(1.0, update_op.eval()) self.assertEqual(1.0, accuracy.eval()) + @test_util.run_deprecated_v1 def testEffectivelyEquivalentSizesWithStaticShapedWeight(self): predictions = ops.convert_to_tensor([1, 1, 1]) # shape 3, labels = array_ops.expand_dims(ops.convert_to_tensor([1, 0, 0]), @@ -653,6 +688,7 @@ class AccuracyTest(test.TestCase): self.assertGreater(update_op.eval(), .95) self.assertGreater(accuracy.eval(), .95) + @test_util.run_deprecated_v1 def testEffectivelyEquivalentSizesWithDynamicallyShapedWeight(self): predictions = ops.convert_to_tensor([1, 1, 1]) # shape 3, labels = array_ops.expand_dims(ops.convert_to_tensor([1, 0, 0]), @@ -674,6 +710,7 @@ class AccuracyTest(test.TestCase): self.assertGreater(update_op.eval(feed_dict=feed_dict), .95) self.assertGreater(accuracy.eval(feed_dict=feed_dict), .95) + @test_util.run_deprecated_v1 def testMultipleUpdatesWithWeightedValues(self): with self.cached_session() as sess: # Create the queue that populates the predictions. @@ -718,12 +755,14 @@ class PrecisionTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.precision( predictions=array_ops.ones((10, 1)), labels=array_ops.ones((10, 1))) _assert_metric_variables(self, ('precision/false_positives/count:0', 'precision/true_positives/count:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.precision( @@ -732,6 +771,7 @@ class PrecisionTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.precision( @@ -740,6 +780,7 @@ class PrecisionTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=1, dtype=dtypes_lib.int64, seed=1) @@ -759,6 +800,7 @@ class PrecisionTest(test.TestCase): for _ in range(10): self.assertEqual(initial_precision, precision.eval()) + @test_util.run_deprecated_v1 def testAllCorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -771,6 +813,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual(1, self.evaluate(update_op)) self.assertAlmostEqual(1, precision.eval()) + @test_util.run_deprecated_v1 def testSomeCorrect_multipleInputDtypes(self): for dtype in (dtypes_lib.bool, dtypes_lib.int32, dtypes_lib.float32): predictions = math_ops.cast( @@ -784,6 +827,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual(0.5, update_op.eval()) self.assertAlmostEqual(0.5, precision.eval()) + @test_util.run_deprecated_v1 def testWeighted1d(self): predictions = constant_op.constant([[1, 0, 1, 0], [1, 0, 1, 0]]) labels = constant_op.constant([[0, 1, 1, 0], [1, 0, 0, 1]]) @@ -798,6 +842,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual(expected_precision, update_op.eval()) self.assertAlmostEqual(expected_precision, precision.eval()) + @test_util.run_deprecated_v1 def testWeightedScalar_placeholders(self): predictions = array_ops.placeholder(dtype=dtypes_lib.float32) labels = array_ops.placeholder(dtype=dtypes_lib.float32) @@ -817,6 +862,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual( expected_precision, precision.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testWeighted1d_placeholders(self): predictions = array_ops.placeholder(dtype=dtypes_lib.float32) labels = array_ops.placeholder(dtype=dtypes_lib.float32) @@ -837,6 +883,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual( expected_precision, precision.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testWeighted2d(self): predictions = constant_op.constant([[1, 0, 1, 0], [1, 0, 1, 0]]) labels = constant_op.constant([[0, 1, 1, 0], [1, 0, 0, 1]]) @@ -853,6 +900,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual(expected_precision, update_op.eval()) self.assertAlmostEqual(expected_precision, precision.eval()) + @test_util.run_deprecated_v1 def testWeighted2d_placeholders(self): predictions = array_ops.placeholder(dtype=dtypes_lib.float32) labels = array_ops.placeholder(dtype=dtypes_lib.float32) @@ -875,6 +923,7 @@ class PrecisionTest(test.TestCase): self.assertAlmostEqual( expected_precision, precision.eval(feed_dict=feed_dict)) + @test_util.run_deprecated_v1 def testAllIncorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -887,6 +936,7 @@ class PrecisionTest(test.TestCase): self.evaluate(update_op) self.assertAlmostEqual(0, precision.eval()) + @test_util.run_deprecated_v1 def testZeroTrueAndFalsePositivesGivesZeroPrecision(self): predictions = constant_op.constant([0, 0, 0, 0]) labels = constant_op.constant([0, 0, 0, 0]) @@ -904,6 +954,7 @@ class RecallTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.recall( predictions=array_ops.ones((10, 1)), labels=array_ops.ones((10, 1))) @@ -911,6 +962,7 @@ class RecallTest(test.TestCase): self, ('recall/false_negatives/count:0', 'recall/true_positives/count:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.recall( @@ -919,6 +971,7 @@ class RecallTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.recall( @@ -927,6 +980,7 @@ class RecallTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=1, dtype=dtypes_lib.int64, seed=1) @@ -946,6 +1000,7 @@ class RecallTest(test.TestCase): for _ in range(10): self.assertEqual(initial_recall, recall.eval()) + @test_util.run_deprecated_v1 def testAllCorrect(self): np_inputs = np.random.randint(0, 2, size=(100, 1)) @@ -958,6 +1013,7 @@ class RecallTest(test.TestCase): self.evaluate(update_op) self.assertEqual(1, recall.eval()) + @test_util.run_deprecated_v1 def testSomeCorrect_multipleInputDtypes(self): for dtype in (dtypes_lib.bool, dtypes_lib.int32, dtypes_lib.float32): predictions = math_ops.cast( @@ -971,6 +1027,7 @@ class RecallTest(test.TestCase): self.assertAlmostEqual(0.5, update_op.eval()) self.assertAlmostEqual(0.5, recall.eval()) + @test_util.run_deprecated_v1 def testWeighted1d(self): predictions = constant_op.constant([[1, 0, 1, 0], [0, 1, 0, 1]]) labels = constant_op.constant([[0, 1, 1, 0], [1, 0, 0, 1]]) @@ -985,6 +1042,7 @@ class RecallTest(test.TestCase): self.assertAlmostEqual(expected_precision, update_op.eval()) self.assertAlmostEqual(expected_precision, recall.eval()) + @test_util.run_deprecated_v1 def testWeighted2d(self): predictions = constant_op.constant([[1, 0, 1, 0], [0, 1, 0, 1]]) labels = constant_op.constant([[0, 1, 1, 0], [1, 0, 0, 1]]) @@ -999,6 +1057,7 @@ class RecallTest(test.TestCase): self.assertAlmostEqual(expected_precision, update_op.eval()) self.assertAlmostEqual(expected_precision, recall.eval()) + @test_util.run_deprecated_v1 def testAllIncorrect(self): np_inputs = np.random.randint(0, 2, size=(100, 1)) @@ -1011,6 +1070,7 @@ class RecallTest(test.TestCase): self.evaluate(update_op) self.assertEqual(0, recall.eval()) + @test_util.run_deprecated_v1 def testZeroTruePositivesAndFalseNegativesGivesZeroRecall(self): predictions = array_ops.zeros((1, 4)) labels = array_ops.zeros((1, 4)) @@ -1028,6 +1088,7 @@ class AUCTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.auc(predictions=array_ops.ones((10, 1)), labels=array_ops.ones((10, 1))) @@ -1035,6 +1096,7 @@ class AUCTest(test.TestCase): ('auc/true_positives:0', 'auc/false_negatives:0', 'auc/false_positives:0', 'auc/true_negatives:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.auc(predictions=array_ops.ones((10, 1)), @@ -1042,6 +1104,7 @@ class AUCTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.auc(predictions=array_ops.ones((10, 1)), @@ -1049,6 +1112,7 @@ class AUCTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=1, dtype=dtypes_lib.float32, seed=1) @@ -1068,6 +1132,7 @@ class AUCTest(test.TestCase): for _ in range(10): self.assertAlmostEqual(initial_auc, auc.eval(), 5) + @test_util.run_deprecated_v1 def testAllCorrect(self): self.allCorrectAsExpected('ROC') @@ -1084,6 +1149,7 @@ class AUCTest(test.TestCase): self.assertEqual(1, auc.eval()) + @test_util.run_deprecated_v1 def testSomeCorrect_multipleLabelDtypes(self): with self.cached_session() as sess: for label_dtype in ( @@ -1099,6 +1165,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(0.5, auc.eval()) + @test_util.run_deprecated_v1 def testWeighted1d(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1112,6 +1179,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(0.5, auc.eval(), 5) + @test_util.run_deprecated_v1 def testWeighted2d(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1127,6 +1195,7 @@ class AUCTest(test.TestCase): # Regarding the AUC-PR tests: note that the preferred method when # calculating AUC-PR is summation_method='careful_interpolation'. + @test_util.run_deprecated_v1 def testCorrectAUCPRSpecialCase(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1141,6 +1210,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) + @test_util.run_deprecated_v1 def testCorrectAnotherAUCPRSpecialCase(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1157,6 +1227,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) + @test_util.run_deprecated_v1 def testThirdCorrectAUCPRSpecialCase(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1173,6 +1244,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) + @test_util.run_deprecated_v1 def testIncorrectAUCPRSpecialCase(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1186,6 +1258,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(0.79166, auc.eval(), delta=1e-3) + @test_util.run_deprecated_v1 def testAnotherIncorrectAUCPRSpecialCase(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1201,6 +1274,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(0.610317, auc.eval(), delta=1e-3) + @test_util.run_deprecated_v1 def testThirdIncorrectAUCPRSpecialCase(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1216,6 +1290,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(0.90277, auc.eval(), delta=1e-3) + @test_util.run_deprecated_v1 def testAllIncorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -1229,6 +1304,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(0, auc.eval()) + @test_util.run_deprecated_v1 def testZeroTruePositivesAndFalseNegativesGivesOneAUC(self): with self.cached_session() as sess: predictions = array_ops.zeros([4], dtype=dtypes_lib.float32) @@ -1240,6 +1316,7 @@ class AUCTest(test.TestCase): self.assertAlmostEqual(1, auc.eval(), 6) + @test_util.run_deprecated_v1 def testRecallOneAndPrecisionOneGivesOnePRAUC(self): with self.cached_session() as sess: predictions = array_ops.ones([4], dtype=dtypes_lib.float32) @@ -1278,6 +1355,7 @@ class AUCTest(test.TestCase): tp = np.cumsum(sorted_weights * is_positive) / num_positives return np.sum((sorted_weights * tp)[~is_positive]) / num_negatives + @test_util.run_deprecated_v1 def testWithMultipleUpdates(self): num_samples = 1000 batch_size = 10 @@ -1334,6 +1412,7 @@ class SpecificityAtSensitivityTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.specificity_at_sensitivity( predictions=array_ops.ones((10, 1)), @@ -1345,6 +1424,7 @@ class SpecificityAtSensitivityTest(test.TestCase): 'specificity_at_sensitivity/false_positives:0', 'specificity_at_sensitivity/true_negatives:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.specificity_at_sensitivity( @@ -1354,6 +1434,7 @@ class SpecificityAtSensitivityTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.specificity_at_sensitivity( @@ -1363,6 +1444,7 @@ class SpecificityAtSensitivityTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=1, dtype=dtypes_lib.float32, seed=1) @@ -1383,6 +1465,7 @@ class SpecificityAtSensitivityTest(test.TestCase): for _ in range(10): self.assertAlmostEqual(initial_specificity, specificity.eval(), 5) + @test_util.run_deprecated_v1 def testAllCorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -1396,6 +1479,7 @@ class SpecificityAtSensitivityTest(test.TestCase): self.assertEqual(1, self.evaluate(update_op)) self.assertEqual(1, specificity.eval()) + @test_util.run_deprecated_v1 def testSomeCorrectHighSensitivity(self): predictions_values = [0.1, 0.2, 0.4, 0.3, 0.0, 0.1, 0.45, 0.5, 0.8, 0.9] labels_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] @@ -1411,6 +1495,7 @@ class SpecificityAtSensitivityTest(test.TestCase): self.assertAlmostEqual(1.0, self.evaluate(update_op)) self.assertAlmostEqual(1.0, specificity.eval()) + @test_util.run_deprecated_v1 def testSomeCorrectLowSensitivity(self): predictions_values = [0.1, 0.2, 0.4, 0.3, 0.0, 0.1, 0.2, 0.2, 0.26, 0.26] labels_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] @@ -1427,6 +1512,7 @@ class SpecificityAtSensitivityTest(test.TestCase): self.assertAlmostEqual(0.6, self.evaluate(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) + @test_util.run_deprecated_v1 def testWeighted1d_multipleLabelDtypes(self): for label_dtype in (dtypes_lib.bool, dtypes_lib.int32, dtypes_lib.float32): predictions_values = [0.1, 0.2, 0.4, 0.3, 0.0, 0.1, 0.2, 0.2, 0.26, 0.26] @@ -1446,6 +1532,7 @@ class SpecificityAtSensitivityTest(test.TestCase): self.assertAlmostEqual(0.6, self.evaluate(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) + @test_util.run_deprecated_v1 def testWeighted2d(self): predictions_values = [0.1, 0.2, 0.4, 0.3, 0.0, 0.1, 0.2, 0.2, 0.26, 0.26] labels_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] @@ -1471,6 +1558,7 @@ class SensitivityAtSpecificityTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.sensitivity_at_specificity( predictions=array_ops.ones((10, 1)), @@ -1482,6 +1570,7 @@ class SensitivityAtSpecificityTest(test.TestCase): 'sensitivity_at_specificity/false_positives:0', 'sensitivity_at_specificity/true_negatives:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.sensitivity_at_specificity( @@ -1491,6 +1580,7 @@ class SensitivityAtSpecificityTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.sensitivity_at_specificity( @@ -1500,6 +1590,7 @@ class SensitivityAtSpecificityTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=1, dtype=dtypes_lib.float32, seed=1) @@ -1520,6 +1611,7 @@ class SensitivityAtSpecificityTest(test.TestCase): for _ in range(10): self.assertAlmostEqual(initial_sensitivity, sensitivity.eval(), 5) + @test_util.run_deprecated_v1 def testAllCorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -1533,6 +1625,7 @@ class SensitivityAtSpecificityTest(test.TestCase): self.assertEqual(1, self.evaluate(update_op)) self.assertEqual(1, specificity.eval()) + @test_util.run_deprecated_v1 def testSomeCorrectHighSpecificity(self): predictions_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.1, 0.45, 0.5, 0.8, 0.9] labels_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] @@ -1548,6 +1641,7 @@ class SensitivityAtSpecificityTest(test.TestCase): self.assertAlmostEqual(0.8, self.evaluate(update_op)) self.assertAlmostEqual(0.8, specificity.eval()) + @test_util.run_deprecated_v1 def testSomeCorrectLowSpecificity(self): predictions_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.25, 0.26, 0.26] labels_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] @@ -1563,6 +1657,7 @@ class SensitivityAtSpecificityTest(test.TestCase): self.assertAlmostEqual(0.6, self.evaluate(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) + @test_util.run_deprecated_v1 def testWeighted_multipleLabelDtypes(self): for label_dtype in (dtypes_lib.bool, dtypes_lib.int32, dtypes_lib.float32): predictions_values = [ @@ -1590,6 +1685,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.precision_at_thresholds( predictions=array_ops.ones((10, 1)), @@ -1600,6 +1696,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): 'precision_at_thresholds/false_positives:0', )) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' prec, _ = metrics.precision_at_thresholds( @@ -1614,6 +1711,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [prec, rec]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, precision_op = metrics.precision_at_thresholds( @@ -1629,6 +1727,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertListEqual( ops.get_collection(my_collection_name), [precision_op, recall_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_uniform( (10, 3), maxval=1, dtype=dtypes_lib.float32, seed=1) @@ -1652,6 +1751,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAllClose(initial_rec, rec.eval()) # TODO(nsilberman): fix tests (passing but incorrect). + @test_util.run_deprecated_v1 def testAllCorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -1670,6 +1770,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertEqual(1, prec.eval()) self.assertEqual(1, rec.eval()) + @test_util.run_deprecated_v1 def testSomeCorrect_multipleLabelDtypes(self): with self.cached_session() as sess: for label_dtype in ( @@ -1690,6 +1791,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAlmostEqual(0.5, prec.eval()) self.assertAlmostEqual(0.5, rec.eval()) + @test_util.run_deprecated_v1 def testAllIncorrect(self): inputs = np.random.randint(0, 2, size=(100, 1)) @@ -1708,6 +1810,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAlmostEqual(0, prec.eval()) self.assertAlmostEqual(0, rec.eval()) + @test_util.run_deprecated_v1 def testWeights1d(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1738,6 +1841,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAlmostEqual(1.0, rec_low.eval(), places=5) self.assertAlmostEqual(0.0, rec_high.eval(), places=5) + @test_util.run_deprecated_v1 def testWeights2d(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1768,6 +1872,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAlmostEqual(1.0, rec_low.eval(), places=5) self.assertAlmostEqual(0.0, rec_high.eval(), places=5) + @test_util.run_deprecated_v1 def testExtremeThresholds(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -1792,6 +1897,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAlmostEqual(1.0, rec_low.eval()) self.assertAlmostEqual(0.0, rec_high.eval()) + @test_util.run_deprecated_v1 def testZeroLabelsPredictions(self): with self.cached_session() as sess: predictions = array_ops.zeros([4], dtype=dtypes_lib.float32) @@ -1808,6 +1914,7 @@ class PrecisionRecallThresholdsTest(test.TestCase): self.assertAlmostEqual(0, prec.eval(), 6) self.assertAlmostEqual(0, rec.eval(), 6) + @test_util.run_deprecated_v1 def testWithMultipleUpdates(self): num_samples = 1000 batch_size = 10 @@ -1990,6 +2097,7 @@ class SingleLabelPrecisionAtKTest(test.TestCase): self._test_average_precision_at_k = functools.partial( _test_average_precision_at_k, test_case=self) + @test_util.run_deprecated_v1 def test_at_k1_nan(self): for labels in self._labels: # Classes 0,1,2 have 0 predictions, classes -1 and 4 are out of range. @@ -1999,6 +2107,7 @@ class SingleLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( self._predictions_idx, labels, k=1, expected=NAN, class_id=class_id) + @test_util.run_deprecated_v1 def test_at_k1(self): for labels in self._labels: # Class 3: 1 label, 2 predictions, 1 correct. @@ -2026,6 +2135,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_average_precision_at_k = functools.partial( _test_average_precision_at_k, test_case=self) + @test_util.run_deprecated_v1 def test_average_precision(self): # Example 1. # Matches example here: @@ -2101,6 +2211,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): expected=streaming_average_precision[i], weights=weights) + @test_util.run_deprecated_v1 def test_average_precision_some_labels_out_of_range(self): """Tests that labels outside the [0, n_classes) range are ignored.""" labels_ex1 = (-1, 0, 1, 2, 3, 4, 7) @@ -2120,6 +2231,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_average_precision_at_k( predictions, labels, k, expected=avg_precision_ex1[i]) + @test_util.run_deprecated_v1 def test_three_labels_at_k5_no_predictions(self): predictions = [[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]] @@ -2136,6 +2248,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, labels, k=5, expected=NAN, class_id=class_id) + @test_util.run_deprecated_v1 def test_three_labels_at_k5_no_labels(self): predictions = [[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]] @@ -2152,6 +2265,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, labels, k=5, expected=0.0, class_id=class_id) + @test_util.run_deprecated_v1 def test_three_labels_at_k5(self): predictions = [[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]] @@ -2185,6 +2299,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, labels, k=5, expected=3.0 / 10) + @test_util.run_deprecated_v1 def test_three_labels_at_k5_some_out_of_range(self): """Tests that labels outside the [0, n_classes) range are ignored.""" predictions = [[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], @@ -2221,6 +2336,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, sp_labels, k=5, expected=3.0 / 10) + @test_util.run_deprecated_v1 def test_3d_nan(self): predictions = [[[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]], @@ -2239,6 +2355,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, labels, k=5, expected=NAN, class_id=class_id) + @test_util.run_deprecated_v1 def test_3d_no_labels(self): predictions = [[[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]], @@ -2257,6 +2374,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, labels, k=5, expected=0.0, class_id=class_id) + @test_util.run_deprecated_v1 def test_3d(self): predictions = [[[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]], @@ -2292,6 +2410,7 @@ class MultiLabelPrecisionAtKTest(test.TestCase): self._test_precision_at_top_k( predictions_idx, labels, k=5, expected=7.0 / 20) + @test_util.run_deprecated_v1 def test_3d_ignore_some(self): predictions = [[[0.5, 0.1, 0.6, 0.3, 0.8, 0.0, 0.7, 0.2, 0.4, 0.9], [0.3, 0.0, 0.7, 0.2, 0.4, 0.9, 0.5, 0.8, 0.1, 0.6]], @@ -2433,6 +2552,7 @@ class SingleLabelRecallAtKTest(test.TestCase): self._test_recall_at_top_k = functools.partial( _test_recall_at_top_k, test_case=self) + @test_util.run_deprecated_v1 def test_at_k1_nan(self): # Classes 0,1 have 0 labels, 0 predictions, classes -1 and 4 are out of # range. @@ -2443,6 +2563,7 @@ class SingleLabelRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, labels, k=1, expected=NAN, class_id=class_id) + @test_util.run_deprecated_v1 def test_at_k1_no_predictions(self): for labels in self._labels: # Class 2: 0 predictions. @@ -2451,6 +2572,7 @@ class SingleLabelRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, labels, k=1, expected=0.0, class_id=2) + @test_util.run_deprecated_v1 def test_one_label_at_k1(self): for labels in self._labels: # Class 3: 1 label, 2 predictions, 1 correct. @@ -2464,6 +2586,7 @@ class SingleLabelRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, labels, k=1, expected=1.0 / 2) + @test_util.run_deprecated_v1 def test_one_label_at_k1_weighted_class_id3(self): predictions = self._predictions predictions_idx = self._predictions_idx @@ -2505,6 +2628,7 @@ class SingleLabelRecallAtKTest(test.TestCase): predictions_idx, labels, k=1, expected=2.0 / 2, class_id=3, weights=(2.0, 3.0)) + @test_util.run_deprecated_v1 def test_one_label_at_k1_weighted(self): predictions = self._predictions predictions_idx = self._predictions_idx @@ -2554,6 +2678,7 @@ class MultiLabel2dRecallAtKTest(test.TestCase): self._test_recall_at_top_k = functools.partial( _test_recall_at_top_k, test_case=self) + @test_util.run_deprecated_v1 def test_at_k5_nan(self): for labels in self._labels: # Classes 0,3,4,6,9 have 0 labels, class 10 is out of range. @@ -2563,6 +2688,7 @@ class MultiLabel2dRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, labels, k=5, expected=NAN, class_id=class_id) + @test_util.run_deprecated_v1 def test_at_k5_no_predictions(self): for labels in self._labels: # Class 8: 1 label, no predictions. @@ -2571,6 +2697,7 @@ class MultiLabel2dRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, labels, k=5, expected=0.0 / 1, class_id=8) + @test_util.run_deprecated_v1 def test_at_k5(self): for labels in self._labels: # Class 2: 2 labels, both correct. @@ -2596,6 +2723,7 @@ class MultiLabel2dRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, labels, k=5, expected=3.0 / 6) + @test_util.run_deprecated_v1 def test_at_k5_some_out_of_range(self): """Tests that labels outside the [0, n_classes) count in denominator.""" labels = sparse_tensor.SparseTensorValue( @@ -2648,6 +2776,7 @@ class MultiLabel3dRecallAtKTest(test.TestCase): self._test_recall_at_top_k = functools.partial( _test_recall_at_top_k, test_case=self) + @test_util.run_deprecated_v1 def test_3d_nan(self): # Classes 0,3,4,6,9 have 0 labels, class 10 is out of range. for class_id in (0, 3, 4, 6, 9, 10): @@ -2657,6 +2786,7 @@ class MultiLabel3dRecallAtKTest(test.TestCase): self._predictions_idx, self._labels, k=5, expected=NAN, class_id=class_id) + @test_util.run_deprecated_v1 def test_3d_no_predictions(self): # Classes 1,8 have 0 predictions, >=1 label. for class_id in (1, 8): @@ -2666,6 +2796,7 @@ class MultiLabel3dRecallAtKTest(test.TestCase): self._predictions_idx, self._labels, k=5, expected=0.0, class_id=class_id) + @test_util.run_deprecated_v1 def test_3d(self): # Class 2: 4 labels, all correct. self._test_recall_at_k( @@ -2694,6 +2825,7 @@ class MultiLabel3dRecallAtKTest(test.TestCase): self._test_recall_at_top_k( self._predictions_idx, self._labels, k=5, expected=7.0 / 12) + @test_util.run_deprecated_v1 def test_3d_ignore_all(self): for class_id in xrange(10): self._test_recall_at_k( @@ -2720,6 +2852,7 @@ class MultiLabel3dRecallAtKTest(test.TestCase): self._predictions_idx, self._labels, k=5, expected=NAN, weights=[[0, 0], [0, 0]]) + @test_util.run_deprecated_v1 def test_3d_ignore_some(self): # Class 2: 2 labels, both correct. self._test_recall_at_k( @@ -2775,12 +2908,14 @@ class MeanAbsoluteErrorTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_absolute_error( predictions=array_ops.ones((10, 1)), labels=array_ops.ones((10, 1))) _assert_metric_variables( self, ('mean_absolute_error/count:0', 'mean_absolute_error/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.mean_absolute_error( @@ -2789,6 +2924,7 @@ class MeanAbsoluteErrorTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_absolute_error( @@ -2797,6 +2933,7 @@ class MeanAbsoluteErrorTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_normal((10, 3), seed=1) labels = random_ops.random_normal((10, 3), seed=2) @@ -2814,6 +2951,7 @@ class MeanAbsoluteErrorTest(test.TestCase): for _ in range(10): self.assertEqual(initial_error, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateWithErrorAndWeights(self): predictions = constant_op.constant( [2, 4, 6, 8], shape=(1, 4), dtype=dtypes_lib.float32) @@ -2834,6 +2972,7 @@ class MeanRelativeErrorTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_relative_error( predictions=array_ops.ones((10, 1)), @@ -2842,6 +2981,7 @@ class MeanRelativeErrorTest(test.TestCase): _assert_metric_variables( self, ('mean_relative_error/count:0', 'mean_relative_error/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.mean_relative_error( @@ -2851,6 +2991,7 @@ class MeanRelativeErrorTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_relative_error( @@ -2860,6 +3001,7 @@ class MeanRelativeErrorTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_normal((10, 3), seed=1) labels = random_ops.random_normal((10, 3), seed=2) @@ -2879,6 +3021,7 @@ class MeanRelativeErrorTest(test.TestCase): for _ in range(10): self.assertEqual(initial_error, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateNormalizedByLabels(self): np_predictions = np.asarray([2, 4, 6, 8], dtype=np.float32) np_labels = np.asarray([1, 3, 2, 3], dtype=np.float32) @@ -2897,6 +3040,7 @@ class MeanRelativeErrorTest(test.TestCase): self.assertEqual(expected_error, self.evaluate(update_op)) self.assertEqual(expected_error, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateNormalizedByZeros(self): np_predictions = np.asarray([2, 4, 6, 8], dtype=np.float32) @@ -2919,12 +3063,14 @@ class MeanSquaredErrorTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_squared_error( predictions=array_ops.ones((10, 1)), labels=array_ops.ones((10, 1))) _assert_metric_variables( self, ('mean_squared_error/count:0', 'mean_squared_error/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.mean_squared_error( @@ -2933,6 +3079,7 @@ class MeanSquaredErrorTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_squared_error( @@ -2941,6 +3088,7 @@ class MeanSquaredErrorTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_normal((10, 3), seed=1) labels = random_ops.random_normal((10, 3), seed=2) @@ -2958,6 +3106,7 @@ class MeanSquaredErrorTest(test.TestCase): for _ in range(10): self.assertEqual(initial_error, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateZeroError(self): predictions = array_ops.zeros((1, 3), dtype=dtypes_lib.float32) labels = array_ops.zeros((1, 3), dtype=dtypes_lib.float32) @@ -2969,6 +3118,7 @@ class MeanSquaredErrorTest(test.TestCase): self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateWithError(self): predictions = constant_op.constant( [2, 4, 6], shape=(1, 3), dtype=dtypes_lib.float32) @@ -2982,6 +3132,7 @@ class MeanSquaredErrorTest(test.TestCase): self.assertEqual(6, self.evaluate(update_op)) self.assertEqual(6, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateWithErrorAndWeights(self): predictions = constant_op.constant( [2, 4, 6, 8], shape=(1, 4), dtype=dtypes_lib.float32) @@ -2996,6 +3147,7 @@ class MeanSquaredErrorTest(test.TestCase): self.assertEqual(13, self.evaluate(update_op)) self.assertEqual(13, error.eval()) + @test_util.run_deprecated_v1 def testMultipleBatchesOfSizeOne(self): with self.cached_session() as sess: # Create the queue that populates the predictions. @@ -3020,6 +3172,7 @@ class MeanSquaredErrorTest(test.TestCase): self.assertAlmostEqual(208.0 / 6, error.eval(), 5) + @test_util.run_deprecated_v1 def testMetricsComputedConcurrently(self): with self.cached_session() as sess: # Create the queue that populates one set of predictions. @@ -3063,6 +3216,7 @@ class MeanSquaredErrorTest(test.TestCase): self.assertAlmostEqual(208.0 / 6, mse0, 5) self.assertAlmostEqual(79.0 / 6, mse1, 5) + @test_util.run_deprecated_v1 def testMultipleMetricsOnMultipleBatchesOfSizeOne(self): with self.cached_session() as sess: # Create the queue that populates the predictions. @@ -3095,6 +3249,7 @@ class RootMeanSquaredErrorTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.root_mean_squared_error( predictions=array_ops.ones((10, 1)), labels=array_ops.ones((10, 1))) @@ -3102,6 +3257,7 @@ class RootMeanSquaredErrorTest(test.TestCase): self, ('root_mean_squared_error/count:0', 'root_mean_squared_error/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.root_mean_squared_error( @@ -3110,6 +3266,7 @@ class RootMeanSquaredErrorTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.root_mean_squared_error( @@ -3118,6 +3275,7 @@ class RootMeanSquaredErrorTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_normal((10, 3), seed=1) labels = random_ops.random_normal((10, 3), seed=2) @@ -3135,6 +3293,7 @@ class RootMeanSquaredErrorTest(test.TestCase): for _ in range(10): self.assertEqual(initial_error, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateZeroError(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -3148,6 +3307,7 @@ class RootMeanSquaredErrorTest(test.TestCase): self.assertEqual(0, rmse.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateWithError(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -3161,6 +3321,7 @@ class RootMeanSquaredErrorTest(test.TestCase): self.assertAlmostEqual(math.sqrt(6), update_op.eval(), 5) self.assertAlmostEqual(math.sqrt(6), rmse.eval(), 5) + @test_util.run_deprecated_v1 def testSingleUpdateWithErrorAndWeights(self): with self.cached_session() as sess: predictions = constant_op.constant( @@ -3188,6 +3349,7 @@ class MeanCosineDistanceTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_cosine_distance( predictions=array_ops.ones((10, 3)), @@ -3198,6 +3360,7 @@ class MeanCosineDistanceTest(test.TestCase): 'mean_cosine_distance/total:0', )) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.mean_cosine_distance( @@ -3207,6 +3370,7 @@ class MeanCosineDistanceTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_cosine_distance( @@ -3216,6 +3380,7 @@ class MeanCosineDistanceTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): predictions = random_ops.random_normal((10, 3), seed=1) labels = random_ops.random_normal((10, 3), seed=2) @@ -3233,6 +3398,7 @@ class MeanCosineDistanceTest(test.TestCase): for _ in range(10): self.assertEqual(initial_error, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateZeroError(self): np_labels = np.matrix(('1 0 0;' '0 0 1;' '0 1 0')) @@ -3248,6 +3414,7 @@ class MeanCosineDistanceTest(test.TestCase): self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateWithError1(self): np_labels = np.matrix(('1 0 0;' '0 0 1;' '0 1 0')) np_predictions = np.matrix(('1 0 0;' '0 0 -1;' '1 0 0')) @@ -3264,6 +3431,7 @@ class MeanCosineDistanceTest(test.TestCase): self.assertAlmostEqual(1, self.evaluate(update_op), 5) self.assertAlmostEqual(1, error.eval(), 5) + @test_util.run_deprecated_v1 def testSingleUpdateWithError2(self): np_predictions = np.matrix( ('0.819031913261206 0.567041924552012 0.087465312324590;' @@ -3285,6 +3453,7 @@ class MeanCosineDistanceTest(test.TestCase): self.assertAlmostEqual(1.0, self.evaluate(update_op), 5) self.assertAlmostEqual(1.0, error.eval(), 5) + @test_util.run_deprecated_v1 def testSingleUpdateWithErrorAndWeights1(self): np_predictions = np.matrix(('1 0 0;' '0 0 -1;' '1 0 0')) np_labels = np.matrix(('1 0 0;' '0 0 1;' '0 1 0')) @@ -3304,6 +3473,7 @@ class MeanCosineDistanceTest(test.TestCase): self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, error.eval()) + @test_util.run_deprecated_v1 def testSingleUpdateWithErrorAndWeights2(self): np_predictions = np.matrix(('1 0 0;' '0 0 -1;' '1 0 0')) np_labels = np.matrix(('1 0 0;' '0 0 1;' '0 1 0')) @@ -3329,6 +3499,7 @@ class PcntBelowThreshTest(test.TestCase): def setUp(self): ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.percentage_below(values=array_ops.ones((10,)), threshold=2) _assert_metric_variables(self, ( @@ -3336,6 +3507,7 @@ class PcntBelowThreshTest(test.TestCase): 'percentage_below_threshold/total:0', )) + @test_util.run_deprecated_v1 def testMetricsCollection(self): my_collection_name = '__metrics__' mean, _ = metrics.percentage_below( @@ -3344,6 +3516,7 @@ class PcntBelowThreshTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.percentage_below( @@ -3352,6 +3525,7 @@ class PcntBelowThreshTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testOneUpdate(self): with self.cached_session() as sess: values = constant_op.constant( @@ -3369,6 +3543,7 @@ class PcntBelowThreshTest(test.TestCase): self.assertAlmostEqual(0.75, pcnt1, 5) self.assertAlmostEqual(0.0, pcnt2, 5) + @test_util.run_deprecated_v1 def testSomePresentOneUpdate(self): with self.cached_session() as sess: values = constant_op.constant( @@ -3399,6 +3574,7 @@ class MeanIOUTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_iou( predictions=array_ops.ones([10, 1]), @@ -3406,6 +3582,7 @@ class MeanIOUTest(test.TestCase): num_classes=2) _assert_metric_variables(self, ('mean_iou/total_confusion_matrix:0',)) + @test_util.run_deprecated_v1 def testMetricsCollections(self): my_collection_name = '__metrics__' mean_iou, _ = metrics.mean_iou( @@ -3415,6 +3592,7 @@ class MeanIOUTest(test.TestCase): metrics_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [mean_iou]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_iou( @@ -3424,12 +3602,14 @@ class MeanIOUTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testPredictionsAndLabelsOfDifferentSizeRaisesValueError(self): predictions = array_ops.ones([10, 3]) labels = array_ops.ones([10, 4]) with self.assertRaises(ValueError): metrics.mean_iou(labels, predictions, num_classes=2) + @test_util.run_deprecated_v1 def testLabelsAndWeightsOfDifferentSizeRaisesValueError(self): predictions = array_ops.ones([10]) labels = array_ops.ones([10]) @@ -3437,6 +3617,7 @@ class MeanIOUTest(test.TestCase): with self.assertRaises(ValueError): metrics.mean_iou(labels, predictions, num_classes=2, weights=weights) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): num_classes = 3 predictions = random_ops.random_uniform( @@ -3458,6 +3639,7 @@ class MeanIOUTest(test.TestCase): for _ in range(10): self.assertEqual(initial_mean_iou, mean_iou.eval()) + @test_util.run_deprecated_v1 def testMultipleUpdates(self): num_classes = 3 with self.cached_session() as sess: @@ -3489,6 +3671,7 @@ class MeanIOUTest(test.TestCase): desired_output = np.mean([1.0 / 2.0, 1.0 / 4.0, 0.]) self.assertEqual(desired_output, miou.eval()) + @test_util.run_deprecated_v1 def testMultipleUpdatesWithWeights(self): num_classes = 2 with self.cached_session() as sess: @@ -3534,6 +3717,7 @@ class MeanIOUTest(test.TestCase): desired_output = np.mean([2.0 / 3.0, 1.0 / 2.0]) self.assertAlmostEqual(desired_output, mean_iou.eval()) + @test_util.run_deprecated_v1 def testMultipleUpdatesWithMissingClass(self): # Test the case where there are no predicions and labels for # one class, and thus there is one row and one column with @@ -3570,6 +3754,7 @@ class MeanIOUTest(test.TestCase): desired_output = np.mean([1.0 / 3.0, 2.0 / 4.0]) self.assertAlmostEqual(desired_output, miou.eval()) + @test_util.run_deprecated_v1 def testUpdateOpEvalIsAccumulatedConfusionMatrix(self): predictions = array_ops.concat( [ @@ -3594,6 +3779,7 @@ class MeanIOUTest(test.TestCase): desired_miou = np.mean([3. / 5., 5. / 7.]) self.assertAlmostEqual(desired_miou, miou.eval()) + @test_util.run_deprecated_v1 def testAllCorrect(self): predictions = array_ops.zeros([40]) labels = array_ops.zeros([40]) @@ -3604,6 +3790,7 @@ class MeanIOUTest(test.TestCase): self.assertEqual(40, update_op.eval()[0]) self.assertEqual(1.0, miou.eval()) + @test_util.run_deprecated_v1 def testAllWrong(self): predictions = array_ops.zeros([40]) labels = array_ops.ones([40]) @@ -3614,6 +3801,7 @@ class MeanIOUTest(test.TestCase): self.assertAllEqual([[0, 0], [40, 0]], update_op.eval()) self.assertEqual(0., miou.eval()) + @test_util.run_deprecated_v1 def testResultsWithSomeMissing(self): predictions = array_ops.concat( [ @@ -3646,6 +3834,7 @@ class MeanIOUTest(test.TestCase): desired_miou = np.mean([2. / 4., 4. / 6.]) self.assertAlmostEqual(desired_miou, miou.eval()) + @test_util.run_deprecated_v1 def testMissingClassInLabels(self): labels = constant_op.constant([ [[0, 0, 1, 1, 0, 0], @@ -3666,6 +3855,7 @@ class MeanIOUTest(test.TestCase): 1 / 3 * (7 / (7 + 3 + 7) + 5 / (5 + 4 + 5) + 0 / (0 + 5 + 0)), miou.eval()) + @test_util.run_deprecated_v1 def testMissingClassOverallSmall(self): labels = constant_op.constant([0]) predictions = constant_op.constant([0]) @@ -3676,6 +3866,7 @@ class MeanIOUTest(test.TestCase): self.assertAllEqual([[1, 0], [0, 0]], update_op.eval()) self.assertAlmostEqual(1, miou.eval()) + @test_util.run_deprecated_v1 def testMissingClassOverallLarge(self): labels = constant_op.constant([ [[0, 0, 1, 1, 0, 0], @@ -3702,6 +3893,7 @@ class MeanPerClassAccuracyTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.mean_per_class_accuracy( predictions=array_ops.ones([10, 1]), @@ -3710,6 +3902,7 @@ class MeanPerClassAccuracyTest(test.TestCase): _assert_metric_variables(self, ('mean_accuracy/count:0', 'mean_accuracy/total:0')) + @test_util.run_deprecated_v1 def testMetricsCollections(self): my_collection_name = '__metrics__' mean_accuracy, _ = metrics.mean_per_class_accuracy( @@ -3720,6 +3913,7 @@ class MeanPerClassAccuracyTest(test.TestCase): self.assertListEqual( ops.get_collection(my_collection_name), [mean_accuracy]) + @test_util.run_deprecated_v1 def testUpdatesCollection(self): my_collection_name = '__updates__' _, update_op = metrics.mean_per_class_accuracy( @@ -3729,12 +3923,14 @@ class MeanPerClassAccuracyTest(test.TestCase): updates_collections=[my_collection_name]) self.assertListEqual(ops.get_collection(my_collection_name), [update_op]) + @test_util.run_deprecated_v1 def testPredictionsAndLabelsOfDifferentSizeRaisesValueError(self): predictions = array_ops.ones([10, 3]) labels = array_ops.ones([10, 4]) with self.assertRaises(ValueError): metrics.mean_per_class_accuracy(labels, predictions, num_classes=2) + @test_util.run_deprecated_v1 def testLabelsAndWeightsOfDifferentSizeRaisesValueError(self): predictions = array_ops.ones([10]) labels = array_ops.ones([10]) @@ -3743,6 +3939,7 @@ class MeanPerClassAccuracyTest(test.TestCase): metrics.mean_per_class_accuracy( labels, predictions, num_classes=2, weights=weights) + @test_util.run_deprecated_v1 def testValueTensorIsIdempotent(self): num_classes = 3 predictions = random_ops.random_uniform( @@ -3795,6 +3992,7 @@ class MeanPerClassAccuracyTest(test.TestCase): desired_output = np.mean([1.0, 1.0 / 3.0, 0.0]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) + @test_util.run_deprecated_v1 def testMultipleUpdatesWithWeights(self): num_classes = 2 with self.cached_session() as sess: @@ -3840,6 +4038,7 @@ class MeanPerClassAccuracyTest(test.TestCase): desired_output = np.mean([2.0 / 2.0, 0.5 / 1.5]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) + @test_util.run_deprecated_v1 def testMultipleUpdatesWithMissingClass(self): # Test the case where there are no predicions and labels for # one class, and thus there is one row and one column with @@ -3877,6 +4076,7 @@ class MeanPerClassAccuracyTest(test.TestCase): desired_output = np.mean([1.0 / 2.0, 2.0 / 3.0, 0.]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) + @test_util.run_deprecated_v1 def testAllCorrect(self): predictions = array_ops.zeros([40]) labels = array_ops.zeros([40]) @@ -3888,6 +4088,7 @@ class MeanPerClassAccuracyTest(test.TestCase): self.assertEqual(1.0, update_op.eval()[0]) self.assertEqual(1.0, mean_accuracy.eval()) + @test_util.run_deprecated_v1 def testAllWrong(self): predictions = array_ops.zeros([40]) labels = array_ops.ones([40]) @@ -3899,6 +4100,7 @@ class MeanPerClassAccuracyTest(test.TestCase): self.assertAllEqual([0.0, 0.0], update_op.eval()) self.assertEqual(0., mean_accuracy.eval()) + @test_util.run_deprecated_v1 def testResultsWithSomeMissing(self): predictions = array_ops.concat([ constant_op.constant(0, shape=[5]), constant_op.constant(1, shape=[5]) @@ -3927,12 +4129,14 @@ class FalseNegativesTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.false_negatives( labels=(0, 1, 0, 1), predictions=(0, 0, 1, 1)) _assert_metric_variables(self, ('false_negatives/count:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -3951,6 +4155,7 @@ class FalseNegativesTest(test.TestCase): self.assertAllClose(3., tn_update_op.eval()) self.assertAllClose(3., tn.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -3977,6 +4182,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.false_negatives_at_thresholds( predictions=array_ops.ones((10, 1)), @@ -3984,6 +4190,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) _assert_metric_variables(self, ('false_negatives/false_negatives:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4000,6 +4207,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): self.assertAllEqual((0, 2, 3), fn_update_op.eval()) self.assertAllEqual((0, 2, 3), fn.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4026,12 +4234,14 @@ class FalsePositivesTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.false_positives( labels=(0, 1, 0, 1), predictions=(0, 0, 1, 1)) _assert_metric_variables(self, ('false_positives/count:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -4050,6 +4260,7 @@ class FalsePositivesTest(test.TestCase): self.assertAllClose(7., tn_update_op.eval()) self.assertAllClose(7., tn.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -4076,6 +4287,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.false_positives_at_thresholds( predictions=array_ops.ones((10, 1)), @@ -4083,6 +4295,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) _assert_metric_variables(self, ('false_positives/false_positives:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4099,6 +4312,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): self.assertAllEqual((7, 4, 2), fp_update_op.eval()) self.assertAllEqual((7, 4, 2), fp.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4127,12 +4341,14 @@ class TrueNegativesTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.true_negatives( labels=(0, 1, 0, 1), predictions=(0, 0, 1, 1)) _assert_metric_variables(self, ('true_negatives/count:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -4151,6 +4367,7 @@ class TrueNegativesTest(test.TestCase): self.assertAllClose(3., tn_update_op.eval()) self.assertAllClose(3., tn.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -4177,6 +4394,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.true_negatives_at_thresholds( predictions=array_ops.ones((10, 1)), @@ -4184,6 +4402,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) _assert_metric_variables(self, ('true_negatives/true_negatives:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4200,6 +4419,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): self.assertAllEqual((2, 5, 7), tn_update_op.eval()) self.assertAllEqual((2, 5, 7), tn.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4226,12 +4446,14 @@ class TruePositivesTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.true_positives( labels=(0, 1, 0, 1), predictions=(0, 0, 1, 1)) _assert_metric_variables(self, ('true_positives/count:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -4250,6 +4472,7 @@ class TruePositivesTest(test.TestCase): self.assertAllClose(7., tn_update_op.eval()) self.assertAllClose(7., tn.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): labels = constant_op.constant(((0, 1, 0, 1, 0), (0, 0, 1, 1, 1), @@ -4276,6 +4499,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): np.random.seed(1) ops.reset_default_graph() + @test_util.run_deprecated_v1 def testVars(self): metrics.true_positives_at_thresholds( predictions=array_ops.ones((10, 1)), @@ -4283,6 +4507,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) _assert_metric_variables(self, ('true_positives/true_positives:0',)) + @test_util.run_deprecated_v1 def testUnweighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), @@ -4299,6 +4524,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): self.assertAllEqual((3, 1, 0), tp_update_op.eval()) self.assertAllEqual((3, 1, 0), tp.eval()) + @test_util.run_deprecated_v1 def testWeighted(self): predictions = constant_op.constant(((0.9, 0.2, 0.8, 0.1), (0.2, 0.9, 0.7, 0.6), diff --git a/tensorflow/python/kernel_tests/morphological_ops_test.py b/tensorflow/python/kernel_tests/morphological_ops_test.py index 4ee04209cc..f54aaf30d0 100644 --- a/tensorflow/python/kernel_tests/morphological_ops_test.py +++ b/tensorflow/python/kernel_tests/morphological_ops_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops import tensorflow.python.ops.nn_grad # pylint: disable=unused-import @@ -291,6 +292,7 @@ class DilationTest(test.TestCase): padding="SAME", use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testDilationGrad(self): for use_gpu in True, False: self._testDilationGradValidPadding_1x1x1(use_gpu) @@ -566,6 +568,7 @@ class ErosionTest(test.TestCase): padding="SAME", use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testErosionGrad(self): for use_gpu in True, False: self._testErosionGradValidPadding_1x1x1(use_gpu) diff --git a/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py b/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py index 87f1991aa7..380d2860da 100644 --- a/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py +++ b/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import nn_impl from tensorflow.python.ops import nn_ops @@ -153,6 +154,7 @@ class DepthwiseConv2DTest(test.TestCase): self.assertShapeEqual(native_result, conv_native) self.assertShapeEqual(native_result, conv_interface) + @test_util.run_deprecated_v1 def testDepthwiseConv2D(self): for index, (input_size, filter_size, _, stride, padding) in enumerate(ConfigsToTest()): @@ -216,6 +218,7 @@ class DepthwiseConv2DTest(test.TestCase): self.assertAllClose(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) + @test_util.run_deprecated_v1 def testConv2D2x2Filter(self): # The inputs look like this (it's a 3 x 2 matrix, each of depth 2): # diff --git a/tensorflow/python/kernel_tests/nth_element_op_test.py b/tensorflow/python/kernel_tests/nth_element_op_test.py index 6cd4974671..4be78b2d5c 100644 --- a/tensorflow/python/kernel_tests/nth_element_op_test.py +++ b/tensorflow/python/kernel_tests/nth_element_op_test.py @@ -22,6 +22,7 @@ import numpy as np import tensorflow.python.ops.nn_grad # pylint: disable=unused-import from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import nn_ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl @@ -111,17 +112,20 @@ class NthElementTest(test.TestCase): self._testEnumerateN([10, 10, 10]) self._testEnumerateN([10, 10, 10, 10]) + @test_util.run_deprecated_v1 def testInvalidInput(self): with self.assertRaisesRegexp(ValueError, "at least rank 1 but is rank 0"): nn_ops.nth_element(5, 0) + @test_util.run_deprecated_v1 def testInvalidInputAtEval(self): with self.session(use_gpu=False): v = array_ops.placeholder(dtype=dtypes.float32) with self.assertRaisesOpError("Input must be >= 1-D"): nn_ops.nth_element(v, 0).eval(feed_dict={v: 5.0}) + @test_util.run_deprecated_v1 def testInvalidN(self): with self.assertRaisesRegexp(ValueError, "non-negative but is -1"): @@ -130,6 +134,7 @@ class NthElementTest(test.TestCase): "scalar but has rank 1"): nn_ops.nth_element([5, 6, 3], [1]) + @test_util.run_deprecated_v1 def testInvalidNAtEval(self): inputs = [[0.1, 0.2], [0.3, 0.4]] with self.session(use_gpu=False): @@ -138,12 +143,14 @@ class NthElementTest(test.TestCase): with self.assertRaisesOpError("Need n >= 0, got -7"): values.eval(feed_dict={n: -7}) + @test_util.run_deprecated_v1 def testNTooLarge(self): inputs = [[0.1, 0.2], [0.3, 0.4]] with self.assertRaisesRegexp(ValueError, "must have last dimension > n = 2"): nn_ops.nth_element(inputs, 2) + @test_util.run_deprecated_v1 def testNTooLargeAtEval(self): inputs = [[0.1, 0.2], [0.3, 0.4]] with self.session(use_gpu=False): @@ -152,6 +159,7 @@ class NthElementTest(test.TestCase): with self.assertRaisesOpError(r"Input must have at least n\+1 columns"): values.eval(feed_dict={n: 2}) + @test_util.run_deprecated_v1 def testGradients(self): with self.session(use_gpu=False) as sess: inputs = array_ops.placeholder(dtypes.float32, shape=[3, 5]) diff --git a/tensorflow/python/kernel_tests/numerics_test.py b/tensorflow/python/kernel_tests/numerics_test.py index e3210dcddc..5751f3fe76 100644 --- a/tensorflow/python/kernel_tests/numerics_test.py +++ b/tensorflow/python/kernel_tests/numerics_test.py @@ -66,6 +66,7 @@ class VerifyTensorAllFiniteTest(test.TestCase): class NumericsTest(test.TestCase): + @test_util.run_deprecated_v1 def testInf(self): with self.session(graph=ops.Graph()): t1 = constant_op.constant(1.0) @@ -76,6 +77,7 @@ class NumericsTest(test.TestCase): with self.assertRaisesOpError("Inf"): self.evaluate(a) + @test_util.run_deprecated_v1 def testNaN(self): with self.session(graph=ops.Graph()): t1 = constant_op.constant(0.0) @@ -86,6 +88,7 @@ class NumericsTest(test.TestCase): with self.assertRaisesOpError("NaN"): self.evaluate(a) + @test_util.run_deprecated_v1 def testBoth(self): with self.session(graph=ops.Graph()): t1 = constant_op.constant([1.0, 0.0]) @@ -104,6 +107,7 @@ class NumericsTest(test.TestCase): self.assertAllEqual(np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]), value) self.assertEqual([2, 3], checked.get_shape()) + @test_util.run_deprecated_v1 def testControlFlowCond(self): predicate = array_ops.placeholder(dtypes.bool, shape=[]) _ = control_flow_ops.cond(predicate, @@ -116,6 +120,7 @@ class NumericsTest(test.TestCase): r"or `tf.while_loop\(\)`\."): numerics.add_check_numerics_ops() + @test_util.run_deprecated_v1 def testControlFlowWhile(self): predicate = array_ops.placeholder(dtypes.bool, shape=[]) _ = control_flow_ops.while_loop(lambda _: predicate, diff --git a/tensorflow/python/kernel_tests/pad_op_test.py b/tensorflow/python/kernel_tests/pad_op_test.py index 6fe98d2559..7b1b054ae0 100644 --- a/tensorflow/python/kernel_tests/pad_op_test.py +++ b/tensorflow/python/kernel_tests/pad_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.platform import test @@ -116,6 +117,7 @@ class PadOpTest(test.TestCase): self._testGradient(np_inputs, paddings, mode=mode, constant_values=constant_values) + @test_util.run_deprecated_v1 def testInputDims(self): with self.session(use_gpu=True): with self.assertRaises(ValueError): @@ -124,6 +126,7 @@ class PadOpTest(test.TestCase): array_ops.reshape( [1, 2], shape=[1, 2])) + @test_util.run_deprecated_v1 def testPaddingsDim(self): with self.session(use_gpu=True): with self.assertRaises(ValueError): @@ -132,6 +135,7 @@ class PadOpTest(test.TestCase): array_ops.reshape( [1, 2], shape=[2])) + @test_util.run_deprecated_v1 def testPaddingsDim2(self): with self.session(use_gpu=True): with self.assertRaises(ValueError): @@ -140,6 +144,7 @@ class PadOpTest(test.TestCase): array_ops.reshape( [1, 2], shape=[2, 1])) + @test_util.run_deprecated_v1 def testPaddingsDim3(self): with self.session(use_gpu=True): with self.assertRaises(ValueError): @@ -148,6 +153,7 @@ class PadOpTest(test.TestCase): array_ops.reshape( [1, 2], shape=[1, 2])) + @test_util.run_deprecated_v1 def testPaddingsDim4(self): with self.session(use_gpu=True): with self.assertRaises(ValueError): @@ -156,6 +162,7 @@ class PadOpTest(test.TestCase): array_ops.reshape( [1, 2, 3, 4, 5, 6], shape=[3, 2])) + @test_util.run_deprecated_v1 def testPaddingsNonNegative(self): with self.session(use_gpu=True): with self.assertRaisesRegexp(ValueError, "must be non-negative"): @@ -164,6 +171,7 @@ class PadOpTest(test.TestCase): constant_op.constant( [-1, 0], shape=[1, 2])) + @test_util.run_deprecated_v1 def testPaddingsNonNegative2(self): with self.session(use_gpu=True): with self.assertRaisesRegexp(ValueError, "must be non-negative"): @@ -223,6 +231,7 @@ class PadOpTest(test.TestCase): np.random.randint(-100, 100, (4, 2, 1, 3)).astype(t), [[0, 0], [0, 0], [0, 0], [0, 0]], -123) + @test_util.run_deprecated_v1 def testFloatTypes(self): for t in [np.float32, np.float64]: self._testAll(np.random.rand(2, 5).astype(t), [[1, 0], [2, 0]], 0.0) @@ -261,6 +270,7 @@ class PadOpTest(test.TestCase): [[b"Hello", b"World", b"World"], [b"Hello", b"World", b"World"], [b"Goodnight", b"Moon", b"Moon"]], self.evaluate(symmetric)) + @test_util.run_deprecated_v1 def testShapeFunctionEdgeCases(self): # Unknown paddings shape. inp = constant_op.constant(0.0, shape=[4, 4, 4, 4]) @@ -277,6 +287,7 @@ class PadOpTest(test.TestCase): padded = array_ops.pad(inp, array_ops.placeholder(dtypes.int32)) self.assertAllEqual(None, padded.get_shape().ndims) + @test_util.run_deprecated_v1 def testPartialShapeInformation(self): unknown = array_ops.placeholder(dtypes.int32) @@ -341,6 +352,7 @@ class PadOpTest(test.TestCase): self.assertAllEqual(inp, out) self.assertShapeEqual(inp, tf_val) + @test_util.run_deprecated_v1 def testCollapseAdjacentNonPaddedDimensions(self): # pyformat: disable paddings_values = [[[0, 0], [0, 0], [0, 0], [0, 1]], diff --git a/tensorflow/python/kernel_tests/parameterized_truncated_normal_op_test.py b/tensorflow/python/kernel_tests/parameterized_truncated_normal_op_test.py index c9221f8c20..f87f517053 100644 --- a/tensorflow/python/kernel_tests/parameterized_truncated_normal_op_test.py +++ b/tensorflow/python/kernel_tests/parameterized_truncated_normal_op_test.py @@ -29,6 +29,7 @@ from tensorflow.core.protobuf import config_pb2 from tensorflow.python.client import session from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import random_ops from tensorflow.python.platform import test @@ -166,30 +167,39 @@ class ParameterizedTruncatedNormalTest(test.TestCase): except ImportError as e: tf_logging.warn("Cannot test truncated normal op: %s" % str(e)) + @test_util.run_deprecated_v1 def testDefaults(self): self.validateMoments([10**5], 0.0, 1.0, -2.0, 2.0) + @test_util.run_deprecated_v1 def testShifted(self): self.validateMoments([10**5], -1.0, 1.0, -2.0, 2.0) + @test_util.run_deprecated_v1 def testRightTail(self): self.validateMoments([10**5], 0.0, 1.0, 4.0, np.infty) + @test_util.run_deprecated_v1 def testLeftTail(self): self.validateMoments([10**5], 0.0, 1.0, -np.infty, -4.0) + @test_util.run_deprecated_v1 def testLeftTailTwoSidedBounds(self): self.validateMoments([10**5], 0.0, 1.0, -6.0, -3.0) + @test_util.run_deprecated_v1 def testTwoSidedLeftTailShifted(self): self.validateKolmogorovSmirnov([10**5], 6.0, 1.0, -1.0, 1.0) + @test_util.run_deprecated_v1 def testRightTailShifted(self): self.validateMoments([10**5], -5.0, 1.0, 2.0, np.infty) + @test_util.run_deprecated_v1 def testSmallStddev(self): self.validateKolmogorovSmirnov([10**5], 0.0, 0.1, 0.05, 0.10) + @test_util.run_deprecated_v1 def testSamplingWithSmallStdDevFarFromBound(self): sample_op = random_ops.parameterized_truncated_normal( shape=(int(1e5),), means=0.8, stddevs=0.05, minvals=-1., maxvals=1.) @@ -202,6 +212,7 @@ class ParameterizedTruncatedNormalTest(test.TestCase): no_neg_samples = np.sum(samples < 0.) self.assertEqual(no_neg_samples, 0.) + @test_util.run_deprecated_v1 def testSamplingAtRandnSwitchover(self): # The randn sampler is used as the bounds are moved farther from the mean, # and the probability of accepting a sample increases the farther the diff --git a/tensorflow/python/kernel_tests/parse_single_example_op_test.py b/tensorflow/python/kernel_tests/parse_single_example_op_test.py index 3f50087282..43c8fa4ab5 100644 --- a/tensorflow/python/kernel_tests/parse_single_example_op_test.py +++ b/tensorflow/python/kernel_tests/parse_single_example_op_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import parsing_ops from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging @@ -121,6 +122,7 @@ class ParseExampleTest(test.TestCase): self.assertEqual( tuple(out[k].dense_shape.get_shape().as_list()), (1,)) + @test_util.run_deprecated_v1 def testEmptySerializedWithAllDefaults(self): sparse_name = "st_a" a_name = "a" @@ -229,6 +231,7 @@ class ParseExampleTest(test.TestCase): }, expected_err=(ValueError, "Missing shape for feature a")) + @test_util.run_deprecated_v1 def testSerializedContainingSparse(self): original = [ example(features=features({ @@ -552,6 +555,7 @@ class ParseExampleTest(test.TestCase): } }, expected_output) + @test_util.run_deprecated_v1 def testSerializedContainingSparseAndSparseFeatureAndDenseWithNoDefault(self): original = [ example(features=features({ @@ -618,6 +622,7 @@ class ParseExampleTest(test.TestCase): }, expected_output) + @test_util.run_deprecated_v1 def testSerializedContainingSparseAndSparseFeatureWithReuse(self): original = [ example(features=features({ @@ -658,6 +663,7 @@ class ParseExampleTest(test.TestCase): } }, expected_output) + @test_util.run_deprecated_v1 def testSerializedContainingVarLenDense(self): aname = "a" bname = "b" @@ -869,6 +875,7 @@ class ParseSingleExampleTest(test.TestCase): self.assertEqual( tuple(out[k].dense_shape.get_shape().as_list()), (1,)) + @test_util.run_deprecated_v1 def testSingleExampleWithSparseAndSparseFeatureAndDense(self): original = example(features=features({ "c": float_feature([3, 4]), diff --git a/tensorflow/python/kernel_tests/parsing_ops_test.py b/tensorflow/python/kernel_tests/parsing_ops_test.py index 1f677103dc..af76e09f39 100644 --- a/tensorflow/python/kernel_tests/parsing_ops_test.py +++ b/tensorflow/python/kernel_tests/parsing_ops_test.py @@ -33,6 +33,7 @@ from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import parsing_ops @@ -121,6 +122,7 @@ class ParseExampleTest(test.TestCase): self.assertEqual( tuple(out[k].dense_shape.get_shape().as_list()), (2,)) + @test_util.run_deprecated_v1 def testEmptySerializedWithAllDefaults(self): sparse_name = "st_a" a_name = "a" @@ -243,6 +245,7 @@ class ParseExampleTest(test.TestCase): }, expected_err=(ValueError, "Missing shape for feature a")) + @test_util.run_deprecated_v1 def testSerializedContainingSparse(self): original = [ example(features=features({ @@ -571,6 +574,7 @@ class ParseExampleTest(test.TestCase): } }, expected_output) + @test_util.run_deprecated_v1 def testSerializedContainingSparseAndSparseFeatureAndDenseWithNoDefault(self): expected_st_a = ( # indices, values, shape np.empty((0, 2), dtype=np.int64), # indices @@ -631,6 +635,7 @@ class ParseExampleTest(test.TestCase): }, expected_output) + @test_util.run_deprecated_v1 def testSerializedContainingSparseAndSparseFeatureWithReuse(self): expected_idx = ( # indices, values, shape np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.int64), @@ -740,6 +745,7 @@ class ParseExampleTest(test.TestCase): for batch_size in (1, 10, 20, 100, 256): self._testSerializedContainingVarLenDenseLargerBatch(batch_size) + @test_util.run_deprecated_v1 def testSerializedContainingVarLenDense(self): aname = "a" bname = "b" @@ -962,6 +968,7 @@ class ParseSingleExampleTest(test.TestCase): self.assertEqual( tuple(out[k].dense_shape.get_shape().as_list()), (1,)) + @test_util.run_deprecated_v1 def testSingleExampleWithSparseAndSparseFeatureAndDense(self): original = example( features=features({ @@ -1180,6 +1187,7 @@ class ParseSequenceExampleTest(test.TestCase): expected_err=expected_err, batch=True) + @test_util.run_deprecated_v1 def testSequenceExampleWithSparseAndDenseContext(self): original = sequence_example( context=features({ @@ -1223,6 +1231,7 @@ class ParseSequenceExampleTest(test.TestCase): }, expected_context_values=expected_context_output) + @test_util.run_deprecated_v1 def testSequenceExampleWithMultipleSizeFeatureLists(self): original = sequence_example( feature_lists=feature_lists({ @@ -1286,6 +1295,7 @@ class ParseSequenceExampleTest(test.TestCase): }, expected_feat_list_values=expected_feature_list_output) + @test_util.run_deprecated_v1 def testSequenceExampleWithoutDebugName(self): original = sequence_example( feature_lists=feature_lists({ @@ -1343,6 +1353,7 @@ class ParseSequenceExampleTest(test.TestCase): }, expected_feat_list_values=expected_feature_list_output) + @test_util.run_deprecated_v1 def testSequenceExampleWithSparseAndDenseFeatureLists(self): original = sequence_example( feature_lists=feature_lists({ @@ -1401,6 +1412,7 @@ class ParseSequenceExampleTest(test.TestCase): }, expected_feat_list_values=expected_feature_list_output) + @test_util.run_deprecated_v1 def testSequenceExampleWithEmptyFeatureInFeatureLists(self): original = sequence_example( feature_lists=feature_lists({ @@ -1541,6 +1553,7 @@ class ParseSequenceExampleTest(test.TestCase): " feature_list_dense_missing_assumed_empty or" " feature_list_dense_defaults?")) + @test_util.run_deprecated_v1 def testSequenceExampleBatch(self): first = sequence_example( feature_lists=feature_lists({ @@ -1695,6 +1708,7 @@ class DecodeJSONExampleTest(test.TestCase): })), ]) + @test_util.run_deprecated_v1 def testInvalidSyntax(self): with self.cached_session() as sess: json_tensor = constant_op.constant(["{]"]) @@ -1705,6 +1719,7 @@ class DecodeJSONExampleTest(test.TestCase): class ParseTensorOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testToFloat32(self): with self.cached_session(): expected = np.random.rand(3, 4, 5).astype(np.float32) @@ -1718,6 +1733,7 @@ class ParseTensorOpTest(test.TestCase): self.assertAllEqual(expected, result) + @test_util.run_deprecated_v1 def testToUint8(self): with self.cached_session(): expected = np.random.rand(3, 4, 5).astype(np.uint8) @@ -1731,6 +1747,7 @@ class ParseTensorOpTest(test.TestCase): self.assertAllEqual(expected, result) + @test_util.run_deprecated_v1 def testTypeMismatch(self): with self.cached_session(): expected = np.random.rand(3, 4, 5).astype(np.uint8) @@ -1744,6 +1761,7 @@ class ParseTensorOpTest(test.TestCase): r"\(uint16\)"): tensor.eval(feed_dict={serialized: tensor_proto.SerializeToString()}) + @test_util.run_deprecated_v1 def testInvalidInput(self): with self.cached_session(): serialized = array_ops.placeholder(dtypes.string) diff --git a/tensorflow/python/kernel_tests/partitioned_variables_test.py b/tensorflow/python/kernel_tests/partitioned_variables_test.py index 0c04656196..48655391fa 100644 --- a/tensorflow/python/kernel_tests/partitioned_variables_test.py +++ b/tensorflow/python/kernel_tests/partitioned_variables_test.py @@ -26,6 +26,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops from tensorflow.python.ops import partitioned_variables @@ -322,6 +323,7 @@ class PartitionedVariablesTestCase(test.TestCase): for i in xrange(len(expected_specs)): self.assertEquals(expected_specs[i], slices[i]._save_slice_info.spec) + @test_util.run_deprecated_v1 def testVecConstantInit(self): with self.cached_session(): rnd_par = constant_op.constant([1, 2, 3, 4]) @@ -333,6 +335,7 @@ class PartitionedVariablesTestCase(test.TestCase): self.assertEqual([dtypes.int32] * 4, [v.dtype.base_dtype for v in vs]) self._TestSaveSpec(vs, ["4 0,1", "4 1,1", "4 2,1", "4 3,1"]) + @test_util.run_deprecated_v1 def testConstantInit(self): with self.cached_session(): rnd_par = constant_op.constant([[1, 2, 3, 4], [5, 6, 7, 8]]) @@ -401,12 +404,15 @@ class PartitionedVariablesTestCase(test.TestCase): self.assertEqual(var2_name + "/part_0:0", vs2[0].name) self.assertEqual(var2_name + "/part_1:0", vs2[1].name) + @test_util.run_deprecated_v1 def testName(self): self._testNameHelper(use_resource=False) + @test_util.run_deprecated_v1 def testResourceName(self): self._testNameHelper(use_resource=True) + @test_util.run_deprecated_v1 def testRandomInitValue(self): with self.cached_session(): rnd = variables.Variable(random_ops.random_uniform([200, 40])) @@ -424,6 +430,7 @@ class PartitionedVariablesTestCase(test.TestCase): "200 40 0,200:36,4" ]) + @test_util.run_deprecated_v1 def testRandomInitUnevenPartitions(self): with self.cached_session(): rnd = variables.Variable( @@ -462,6 +469,7 @@ class PartitionedVariablesTestCase(test.TestCase): if i < len(save_specs): self._TestSaveSpec(vs, save_specs[i]) + @test_util.run_deprecated_v1 def testDegenerate(self): with self.cached_session(): rnd = variables.Variable(random_ops.random_uniform([10, 43])) @@ -473,6 +481,7 @@ class PartitionedVariablesTestCase(test.TestCase): self.assertAllClose(rnd, val) self._TestSaveSpec(vs, ["10 43 0,10:0,43"]) + @test_util.run_deprecated_v1 def testSliceSizeOne(self): with self.cached_session(): rnd = variables.Variable(random_ops.random_uniform([10, 43])) @@ -488,6 +497,7 @@ class PartitionedVariablesTestCase(test.TestCase): "10 43 6,1:0,43", "10 43 7,1:0,43", "10 43 8,1:0,43", "10 43 9,1:0,43" ]) + @test_util.run_deprecated_v1 def testIotaInitializer(self): self.assertAllClose([0., 1., 2., 3.], _IotaInitializer([4])) self.assertAllClose([[0., 1.], [0., 10.], [0., 100.], [0., 1000.]], @@ -503,6 +513,7 @@ class PartitionedVariablesTestCase(test.TestCase): self.assertAllClose(slice0 + slice1 + slice2, val) self._TestSaveSpec(vs, ["13 5 0,5:0,5", "13 5 5,4:0,5", "13 5 9,4:0,5"]) + @test_util.run_deprecated_v1 def testRandomInitializer(self): # Sanity check that the slices uses a different seed when using a random # initializer function. @@ -546,6 +557,7 @@ class PartitionedVariablesTestCase(test.TestCase): partitioned_variables.create_partitioned_variables( [10, 43], [1, 50], rnd.initialized_value()) + @test_util.run_deprecated_v1 def testControlDepsNone(self): with self.cached_session() as session: c = constant_op.constant(1.0) @@ -572,6 +584,7 @@ class PartitionedVariablesTestCase(test.TestCase): for op in reading_ops: self.assertEqual([], op.control_inputs) + @test_util.run_deprecated_v1 def testConcat(self): with self.cached_session() as session: var_x = variable_scope.get_variable( diff --git a/tensorflow/python/kernel_tests/pool_test.py b/tensorflow/python/kernel_tests/pool_test.py index 92016a49a2..78e786f01c 100644 --- a/tensorflow/python/kernel_tests/pool_test.py +++ b/tensorflow/python/kernel_tests/pool_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops import tensorflow.python.ops.nn_grad # pylint: disable=unused-import @@ -301,6 +302,7 @@ class PoolingTest(test.TestCase): err_tolerance = 1e-2 self.assertLess(err, err_tolerance) + @test_util.run_deprecated_v1 def testGradient1D(self): with self.session(use_gpu=test.is_gpu_available()): for padding in ["SAME", "VALID"]: @@ -327,6 +329,7 @@ class PoolingTest(test.TestCase): dilation_rate=[1], strides=strides) + @test_util.run_deprecated_v1 def testGradient2D(self): with self.session(use_gpu=test.is_gpu_available()): for padding in ["SAME", "VALID"]: @@ -353,6 +356,7 @@ class PoolingTest(test.TestCase): dilation_rate=[1, 1], strides=strides) + @test_util.run_deprecated_v1 def testGradient3D(self): with self.session(use_gpu=test.is_gpu_available()): for padding in ["SAME", "VALID"]: diff --git a/tensorflow/python/kernel_tests/pooling_ops_3d_test.py b/tensorflow/python/kernel_tests/pooling_ops_3d_test.py index a8e962bc3a..24fb51fc47 100644 --- a/tensorflow/python/kernel_tests/pooling_ops_3d_test.py +++ b/tensorflow/python/kernel_tests/pooling_ops_3d_test.py @@ -294,6 +294,7 @@ class PoolingTest(test.TestCase): use_gpu=use_gpu, **kwargs) + @test_util.run_deprecated_v1 def testMaxPoolGradValidPadding1_1_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -303,6 +304,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="VALID") + @test_util.run_deprecated_v1 def testMaxPoolGradValidPadding2_1_6_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -312,6 +314,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="VALID") + @test_util.run_deprecated_v1 def testMaxPoolGradValidPadding2_1_7_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -321,6 +324,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="VALID") + @test_util.run_deprecated_v1 def testMaxPoolGradValidPadding1_2_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -330,6 +334,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="VALID") + @test_util.run_deprecated_v1 def testMaxPoolGradValidPadding2_2_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -339,6 +344,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="VALID") + @test_util.run_deprecated_v1 def testMaxPoolGradSamePadding1_1_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -348,6 +354,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="SAME") + @test_util.run_deprecated_v1 def testMaxPoolGradSamePadding1_2_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -357,6 +364,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="SAME") + @test_util.run_deprecated_v1 def testMaxPoolGradSamePadding2_1_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -366,6 +374,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="SAME") + @test_util.run_deprecated_v1 def testMaxPoolGradSamePadding2_2_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -375,6 +384,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="SAME") + @test_util.run_deprecated_v1 def testMaxPoolGradSamePadding3_1_3d(self): self._ConstructAndTestGradient( nn_ops.max_pool3d, @@ -384,6 +394,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="SAME") + @test_util.run_deprecated_v1 def testAvgPoolGradValidPadding1_1_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -393,6 +404,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="VALID") + @test_util.run_deprecated_v1 def testAvgPoolGradValidPadding1_2_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -402,6 +414,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="VALID") + @test_util.run_deprecated_v1 def testAvgPoolGradValidPadding2_1_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -411,6 +424,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="VALID") + @test_util.run_deprecated_v1 def testAvgPoolGradValidPadding2_2_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -420,6 +434,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="VALID") + @test_util.run_deprecated_v1 def testAvgPoolGradSamePadding1_1_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -429,6 +444,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="SAME") + @test_util.run_deprecated_v1 def testAvgPoolGradSamePadding1_2_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -438,6 +454,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="SAME") + @test_util.run_deprecated_v1 def testAvgPoolGradSamePadding2_1_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -447,6 +464,7 @@ class PoolingTest(test.TestCase): strides=(1, 1, 1), padding="SAME") + @test_util.run_deprecated_v1 def testAvgPoolGradSamePadding2_2_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, @@ -456,6 +474,7 @@ class PoolingTest(test.TestCase): strides=(2, 2, 2), padding="SAME") + @test_util.run_deprecated_v1 def testAvgPoolGradSamePadding3_1_3d(self): self._ConstructAndTestGradient( nn_ops.avg_pool3d, diff --git a/tensorflow/python/kernel_tests/pooling_ops_test.py b/tensorflow/python/kernel_tests/pooling_ops_test.py index 81222719f2..c33b59bb99 100644 --- a/tensorflow/python/kernel_tests/pooling_ops_test.py +++ b/tensorflow/python/kernel_tests/pooling_ops_test.py @@ -384,6 +384,7 @@ class PoolingTest(test.TestCase): expected=[], use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testAvgPooling(self): for use_gpu in True, False: self._testAvgPoolValidPadding(use_gpu) @@ -577,6 +578,7 @@ class PoolingTest(test.TestCase): expected=[], use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testMaxPooling(self): for use_gpu in True, False: self._testMaxPoolValidPadding(use_gpu) @@ -588,6 +590,7 @@ class PoolingTest(test.TestCase): self._testMaxPoolEmptyInput(use_gpu) # Tests for DepthwiseMaxPooling on CPU only. + @test_util.run_deprecated_v1 def testDepthwiseMaxPool1x1DepthWindow1(self): # input is: # [1.0, ..., 10.0] along depth, @@ -613,6 +616,7 @@ class PoolingTest(test.TestCase): use_gpu=False, v2=v2) + @test_util.run_deprecated_v1 def testDepthwiseMaxPool2x2DepthWindow3(self): # input is: # @@ -639,6 +643,7 @@ class PoolingTest(test.TestCase): use_gpu=False, v2=v2) + @test_util.run_deprecated_v1 def testKernelSmallerThanStrideValid(self): for use_gpu in [True, False]: self._VerifyValues( @@ -670,6 +675,7 @@ class PoolingTest(test.TestCase): expected=[5, 8, 26, 29], use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testKernelSmallerThanStrideSame(self): for use_gpu in [True, False]: for pool_func in [nn_ops.max_pool, nn_ops.avg_pool]: @@ -1167,6 +1173,7 @@ class PoolingTest(test.TestCase): data_format=data_format, use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testMaxPoolGrad(self): for (data_format, use_gpu) in GetTestConfigs(): self._testMaxPoolGradValidPadding1_1(data_format, use_gpu) @@ -1497,6 +1504,7 @@ class PoolingTest(test.TestCase): else: del os.environ["TF_ENABLE_MAXPOOL_NANPROP"] + @test_util.run_deprecated_v1 def testMaxPoolGradDirect(self): self._testMaxPoolGradDirect1_1() self._testMaxPoolGradDirect1_2() @@ -1616,6 +1624,7 @@ class PoolingTest(test.TestCase): data_format=data_format, use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testMaxPoolGradGrad(self): for (data_format, use_gpu) in GetTestConfigs(): self._testMaxPoolGradGradValidPadding1_1(data_format, use_gpu) @@ -1649,6 +1658,7 @@ class PoolingTest(test.TestCase): orig_input, orig_output, grad, [1, window_rows, window_cols, 1], [1, row_stride, col_stride, 1], padding) + @test_util.run_deprecated_v1 def testAvgPoolGrad(self): for (data_format, use_gpu) in GetTestConfigs(): self._testAvgPoolGradValidPadding1_1(data_format, use_gpu) @@ -1778,6 +1788,7 @@ class PoolingTest(test.TestCase): data_format=data_format, use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testShapeFunctionEdgeCases(self): # All shapes unknown. for pool_func in [nn_ops.max_pool, nn_ops.avg_pool]: @@ -1806,6 +1817,7 @@ class PoolingTest(test.TestCase): strides=[1, 1, 1, 1], padding="SAME") + @test_util.run_deprecated_v1 def testOpEdgeCases(self): with self.session(use_gpu=test.is_gpu_available()) as sess: pool_funcs = [nn_ops.max_pool, nn_ops.avg_pool] diff --git a/tensorflow/python/kernel_tests/py_func_test.py b/tensorflow/python/kernel_tests/py_func_test.py index c9cbe44a7f..1f3f02a9f0 100644 --- a/tensorflow/python/kernel_tests/py_func_test.py +++ b/tensorflow/python/kernel_tests/py_func_test.py @@ -514,6 +514,7 @@ class PyFuncTest(test.TestCase): self.assertAllEqual(ret, [[3.0], [3.0], [3.0]]) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testEagerExceptionHandling(self): with test_util.device(use_gpu=True): self._testExceptionHandling( @@ -533,6 +534,7 @@ class PyFuncTest(test.TestCase): self._testExceptionHandling(WeirdError, errors.UnknownError, eager=True) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testEagerReturningVariableRaisesError(self): def return_variable(): return resource_variable_ops.ResourceVariable(0.0) diff --git a/tensorflow/python/kernel_tests/qr_op_test.py b/tensorflow/python/kernel_tests/qr_op_test.py index 305b5aa364..0f2537b371 100644 --- a/tensorflow/python/kernel_tests/qr_op_test.py +++ b/tensorflow/python/kernel_tests/qr_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import linalg_ops @@ -49,6 +50,7 @@ class QrOpTest(test.TestCase): "Shape must be at least rank 2 but is rank 1"): linalg_ops.qr(vector) + @test_util.run_deprecated_v1 def testConcurrentExecutesWithoutError(self): with self.session(use_gpu=True) as sess: all_ops = [] diff --git a/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py b/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py index cab841741e..576720528e 100644 --- a/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py +++ b/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.ops import random_ops from tensorflow.python.platform import test @@ -66,6 +67,7 @@ class MultinomialTest(test.TestCase): counts_by_indices[index] = count self.assertEqual(counts_by_indices[0], 100000000) + @test_util.run_deprecated_v1 def testLargeDynamicRange3(self): random_seed.set_random_seed(10) counts_by_indices = {} diff --git a/tensorflow/python/kernel_tests/random/multinomial_op_test.py b/tensorflow/python/kernel_tests/random/multinomial_op_test.py index 031a1c281c..5d123307a8 100644 --- a/tensorflow/python/kernel_tests/random/multinomial_op_test.py +++ b/tensorflow/python/kernel_tests/random/multinomial_op_test.py @@ -66,6 +66,7 @@ class MultinomialTest(test.TestCase): logits, num_samples, output_dtype=output_dtype)) self.assertAllEqual([[1] * num_samples, [2] * num_samples], samples) + @test_util.run_deprecated_v1 def testOneOpMultipleStepsIndependent(self): with test_util.use_gpu(): sample_op1, _ = self._make_ops(10) @@ -88,6 +89,7 @@ class MultinomialTest(test.TestCase): # 1 in 2^32 chance of this assertion failing. self.assertFalse(np.equal(sample1, sample2).all()) + @test_util.run_deprecated_v1 def testTwoOpsSameSeedDrawSameSequences(self): with test_util.use_gpu(): sample_op1, sample_op2 = self._make_ops(1000, seed=1) @@ -194,6 +196,7 @@ class MultinomialTest(test.TestCase): array_ops.zeros([batch, classes]), samples)) self.assertEqual(x.shape, (batch, samples)) + @test_util.run_deprecated_v1 def testEmptyClasses(self): with test_util.use_gpu(): x = random_ops.multinomial(array_ops.zeros([5, 0]), 7) diff --git a/tensorflow/python/kernel_tests/random/random_crop_test.py b/tensorflow/python/kernel_tests/random/random_crop_test.py index 491d19d6a0..724bee0715 100644 --- a/tensorflow/python/kernel_tests/random/random_crop_test.py +++ b/tensorflow/python/kernel_tests/random/random_crop_test.py @@ -20,12 +20,14 @@ from __future__ import print_function import numpy as np +from tensorflow.python.framework import test_util from tensorflow.python.ops import random_ops from tensorflow.python.platform import test class RandomCropTest(test.TestCase): + @test_util.run_deprecated_v1 def testNoOp(self): # No random cropping is performed since the size is value.shape. for shape in (2, 1, 1), (2, 1, 3), (4, 5, 3): @@ -48,6 +50,7 @@ class RandomCropTest(test.TestCase): self.assertAllEqual(y.shape, target) self.assertTrue(tuple(y.ravel()) in value_set) + @test_util.run_deprecated_v1 def testRandomization(self): # Run 1x1 crop num_samples times in an image and ensure that one finds each # pixel 1/size of the time. diff --git a/tensorflow/python/kernel_tests/random/random_gamma_test.py b/tensorflow/python/kernel_tests/random/random_gamma_test.py index d18e3feb04..a5952a2196 100644 --- a/tensorflow/python/kernel_tests/random/random_gamma_test.py +++ b/tensorflow/python/kernel_tests/random/random_gamma_test.py @@ -26,6 +26,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops @@ -53,9 +54,11 @@ class RandomGammaTest(test.TestCase): return func + @test_util.run_deprecated_v1 def testMomentsFloat32(self): self._testMoments(dtypes.float32) + @test_util.run_deprecated_v1 def testMomentsFloat64(self): self._testMoments(dtypes.float64) @@ -208,6 +211,7 @@ class RandomGammaTest(test.TestCase): sy = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu, seed=345) self.assertAllEqual(sx(), sy()) + @test_util.run_deprecated_v1 def testNoCSE(self): """CSE = constant subexpression eliminator. @@ -222,6 +226,7 @@ class RandomGammaTest(test.TestCase): diff = rnd2 - rnd1 self.assertGreater(np.linalg.norm(diff.eval()), 0.1) + @test_util.run_deprecated_v1 def testShape(self): # Fully known shape. rnd = random_ops.random_gamma([150], 2.0) @@ -253,6 +258,7 @@ class RandomGammaTest(test.TestCase): rnd = random_ops.random_gamma([50], array_ops.placeholder(dtypes.float32)) self.assertIs(None, rnd.get_shape().ndims) + @test_util.run_deprecated_v1 def testPositive(self): n = int(10e3) for dt in [dtypes.float16, dtypes.float32, dtypes.float64]: diff --git a/tensorflow/python/kernel_tests/random/random_grad_test.py b/tensorflow/python/kernel_tests/random/random_grad_test.py index d89056c485..aac6eeac06 100644 --- a/tensorflow/python/kernel_tests/random/random_grad_test.py +++ b/tensorflow/python/kernel_tests/random/random_grad_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops @@ -45,6 +46,7 @@ class AddLeadingUnitDimensionsTest(test.TestCase): ret = random_grad.add_leading_unit_dimensions(1.0, 2) self.assertAllEqual(ret.shape, [1, 1]) + @test_util.run_deprecated_v1 def testUnknownShape(self): x = array_ops.placeholder(dtypes.float32) num_dimensions = array_ops.placeholder(dtypes.int32) @@ -72,6 +74,7 @@ class RandomGammaGradTest(test.TestCase): some statistical properties of the derivative. """ + @test_util.run_deprecated_v1 def testGradientsShape(self): shape = [2, 3] alpha = array_ops.ones([2, 2]) @@ -81,6 +84,7 @@ class RandomGammaGradTest(test.TestCase): self.assertAllEqual(grads_alpha.shape, alpha.shape) self.assertAllEqual(grads_beta.shape, beta.shape) + @test_util.run_deprecated_v1 def testGradientsShapeWithOneSamplePerParameter(self): shape = [] alpha = array_ops.ones([2, 2]) @@ -90,6 +94,7 @@ class RandomGammaGradTest(test.TestCase): self.assertAllEqual(grads_alpha.shape, alpha.shape) self.assertAllEqual(grads_beta.shape, beta.shape) + @test_util.run_deprecated_v1 def testGradientsUnknownShape(self): shape = array_ops.placeholder(dtypes.int32) alpha = array_ops.placeholder(dtypes.float32) @@ -138,9 +143,11 @@ class RandomGammaGradTest(test.TestCase): except ImportError as e: tf_logging.warn("Cannot use special functions in a test: %s" % str(e)) + @test_util.run_deprecated_v1 def testCompareToExplicitDerivativeFloat(self): self._testCompareToExplicitDerivative(dtypes.float32) + @test_util.run_deprecated_v1 def testCompareToExplicitDerivativeDouble(self): self._testCompareToExplicitDerivative(dtypes.float64) @@ -182,12 +189,15 @@ class RandomGammaGradTest(test.TestCase): self.assertAllClose(actual_val, expected_val, rtol=1e-3, atol=1e-3) + @test_util.run_deprecated_v1 def testCompareToImplicitDerivativeFloat(self): self._testCompareToImplicitDerivative(dtypes.float32) + @test_util.run_deprecated_v1 def testCompareToImplicitDerivativeDouble(self): self._testCompareToImplicitDerivative(dtypes.float64) + @test_util.run_deprecated_v1 def testAverageAlphaGradient(self): """Statistical test for the gradient. @@ -207,6 +217,7 @@ class RandomGammaGradTest(test.TestCase): dsample_dalpha_val = self.evaluate(dsample_dalpha) self.assertAllClose(dsample_dalpha_val, [1.0] * 3, atol=1e-1, rtol=1e-1) + @test_util.run_deprecated_v1 def testQuadraticLoss(self): """Statistical test for the gradient. diff --git a/tensorflow/python/kernel_tests/random/random_ops_test.py b/tensorflow/python/kernel_tests/random/random_ops_test.py index 76618316b2..1384c3f446 100644 --- a/tensorflow/python/kernel_tests/random/random_ops_test.py +++ b/tensorflow/python/kernel_tests/random/random_ops_test.py @@ -25,6 +25,7 @@ from tensorflow.python.eager import context from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import variables @@ -92,6 +93,7 @@ class RandomNormalTest(RandomOpTestCommon): # Checks that the CPU and GPU implementation returns the same results, # given the same random seed + @test_util.run_deprecated_v1 def testCPUGPUMatch(self): for dt in dtypes.float16, dtypes.float32, dtypes.float64: results = {} @@ -104,12 +106,14 @@ class RandomNormalTest(RandomOpTestCommon): else: self.assertAllClose(results[False], results[True], rtol=1e-6, atol=1e-6) + @test_util.run_deprecated_v1 def testSeed(self): for dt in dtypes.float16, dtypes.float32, dtypes.float64: sx = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) sy = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) self.assertAllEqual(sx(), sy()) + @test_util.run_deprecated_v1 def testNoCSE(self): for use_gpu in [False, True]: with self.session(use_gpu=use_gpu): @@ -119,12 +123,14 @@ class RandomNormalTest(RandomOpTestCommon): diff = rnd2 - rnd1 self.assertTrue(np.linalg.norm(diff.eval()) > 0.1) + @test_util.run_deprecated_v1 def testSingleSessionNotConstant(self): for use_gpu in [False, True]: for dt in dtypes.float16, dtypes.float32, dtypes.float64: self._testSingleSessionNotConstant( random_ops.random_normal, 100, dt, 0.0, 1.0, use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testSingleSessionOpSeedNotConstant(self): for use_gpu in [False, True]: for dt in dtypes.float16, dtypes.float32, dtypes.float64: @@ -137,6 +143,7 @@ class RandomNormalTest(RandomOpTestCommon): use_gpu=use_gpu, op_seed=1345) + @test_util.run_deprecated_v1 def testSingleSessionGraphSeedNotConstant(self): for use_gpu in [False, True]: for dt in dtypes.float16, dtypes.float32, dtypes.float64: @@ -185,6 +192,7 @@ class TruncatedNormalTest(test.TestCase): # Checks that the CPU and GPU implementation returns the same results, # given the same random seed + @test_util.run_deprecated_v1 def testCPUGPUMatch(self): # Skip the test if there is no GPU. if not test.is_gpu_available(): @@ -203,6 +211,7 @@ class TruncatedNormalTest(test.TestCase): else: self.assertAllClose(results[False], results[True], rtol=1e-6, atol=1e-6) + @test_util.run_deprecated_v1 def testSeed(self): for dt in dtypes.float16, dtypes.float32, dtypes.float64: sx = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) @@ -219,6 +228,7 @@ class TruncatedNormalTest(test.TestCase): print("std(x)", np.std(x), abs(np.std(x) / stddev - 0.85)) self.assertTrue(abs(np.std(x) / stddev - 0.85) < 0.04) + @test_util.run_deprecated_v1 def testLargeShape(self): with self.session(use_gpu=True): v = variables.Variable( @@ -226,6 +236,7 @@ class TruncatedNormalTest(test.TestCase): n = random_ops.truncated_normal(v.shape) self.assertEqual([8589934592, 1], n.shape.as_list()) + @test_util.run_deprecated_v1 def testNoCSE(self): with self.session(use_gpu=True): shape = [2, 3, 4] @@ -287,6 +298,7 @@ class RandomUniformTest(RandomOpTestCommon): print("count = ", count) self.assertTrue(count < count_limit) + @test_util.run_deprecated_v1 def testUniformIntsWithInvalidShape(self): for dtype in dtypes.int32, dtypes.int64: with self.assertRaisesRegexp( @@ -299,6 +311,7 @@ class RandomUniformTest(RandomOpTestCommon): [1000], minval=1, maxval=[2, 3], dtype=dtype) # Check that uniform ints actually follow a uniform distribution. + @test_util.run_deprecated_v1 def testUniformInts(self): minv = -2 maxv = 15 @@ -331,6 +344,7 @@ class RandomUniformTest(RandomOpTestCommon): # Checks that the CPU and GPU implementation returns the same results, # given the same random seed + @test_util.run_deprecated_v1 def testCPUGPUMatch(self): for dt in (dtypes.float16, dtypes.float32, dtypes.float64, dtypes.int32, dtypes.int64): @@ -342,6 +356,7 @@ class RandomUniformTest(RandomOpTestCommon): results[use_gpu] = sampler() self.assertAllEqual(results[False], results[True]) + @test_util.run_deprecated_v1 def testSeed(self): for dt in (dtypes.float16, dtypes.float32, dtypes.float64, dtypes.int32, dtypes.int64): @@ -350,6 +365,7 @@ class RandomUniformTest(RandomOpTestCommon): sy = self._Sampler(1000, 0, 17, dtype=dt, use_gpu=True, seed=seed) self.assertAllEqual(sx(), sy()) + @test_util.run_deprecated_v1 def testNoCSE(self): shape = [2, 3, 4] for dtype in dtypes.float16, dtypes.float32, dtypes.int32: @@ -359,6 +375,7 @@ class RandomUniformTest(RandomOpTestCommon): diff = (rnd2 - rnd1).eval() self.assertTrue(np.linalg.norm(diff) > 0.1) + @test_util.run_deprecated_v1 def testSingleSessionNotConstant(self): for use_gpu in [False, True]: for dt in (dtypes.float16, dtypes.float32, dtypes.float64, dtypes.int32, @@ -366,6 +383,7 @@ class RandomUniformTest(RandomOpTestCommon): self._testSingleSessionNotConstant( random_ops.random_uniform, 100, dt, 0, 17, use_gpu=use_gpu) + @test_util.run_deprecated_v1 def testSingleSessionOpSeedNotConstant(self): for use_gpu in [False, True]: for dt in (dtypes.float16, dtypes.float32, dtypes.float64, dtypes.int32, @@ -379,6 +397,7 @@ class RandomUniformTest(RandomOpTestCommon): use_gpu=use_gpu, op_seed=1345) + @test_util.run_deprecated_v1 def testSingleSessionGraphSeedNotConstant(self): for use_gpu in [False, True]: for dt in (dtypes.float16, dtypes.float32, dtypes.float64, dtypes.int32, @@ -395,6 +414,7 @@ class RandomUniformTest(RandomOpTestCommon): class RandomShapeTest(test.TestCase): + @test_util.run_deprecated_v1 def testTruncatedNormal(self): # Fully known shape. rnd1 = random_ops.truncated_normal([1, 2, 3]) @@ -407,6 +427,7 @@ class RandomShapeTest(test.TestCase): rnd3 = random_ops.truncated_normal(array_ops.placeholder(dtypes.int32)) self.assertIs(None, rnd3.get_shape().ndims) + @test_util.run_deprecated_v1 def testRandomNormal(self): # Fully known shape. rnd1 = random_ops.random_normal([1, 2, 3]) @@ -419,6 +440,7 @@ class RandomShapeTest(test.TestCase): rnd3 = random_ops.random_normal(array_ops.placeholder(dtypes.int32)) self.assertIs(None, rnd3.get_shape().ndims) + @test_util.run_deprecated_v1 def testRandomUniform(self): # Fully known shape. rnd1 = random_ops.random_uniform([1, 2, 3]) diff --git a/tensorflow/python/kernel_tests/random/random_poisson_test.py b/tensorflow/python/kernel_tests/random/random_poisson_test.py index 47c0858db7..0a6b004d68 100644 --- a/tensorflow/python/kernel_tests/random/random_poisson_test.py +++ b/tensorflow/python/kernel_tests/random/random_poisson_test.py @@ -23,6 +23,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.platform import test @@ -104,6 +105,7 @@ class RandomPoissonTest(test.TestCase): # Checks that the CPU and GPU implementation returns the same results, # given the same random seed + @test_util.run_deprecated_v1 def testCPUGPUMatch(self): for dt in _SUPPORTED_DTYPES: results = {} @@ -115,12 +117,14 @@ class RandomPoissonTest(test.TestCase): else: self.assertAllClose(results[False], results[True], rtol=1e-6, atol=1e-6) + @test_util.run_deprecated_v1 def testSeed(self): for dt in dtypes.float16, dtypes.float32, dtypes.float64: sx = self._Sampler(1000, 1.0, dt, use_gpu=True, seed=345) sy = self._Sampler(1000, 1.0, dt, use_gpu=True, seed=345) self.assertAllEqual(sx(), sy()) + @test_util.run_deprecated_v1 def testNoCSE(self): """CSE = constant subexpression eliminator. @@ -142,6 +146,7 @@ class RandomPoissonTest(test.TestCase): self.assertEqual([0], rnd.get_shape().as_list()) self.assertAllClose(np.array([], dtype=np.float32), self.evaluate(rnd)) + @test_util.run_deprecated_v1 def testShape(self): # Fully known shape rnd = random_ops.random_poisson(2.0, [150], seed=12345) @@ -184,6 +189,7 @@ class RandomPoissonTest(test.TestCase): seed=12345) self.assertIs(None, rnd.get_shape().ndims) + @test_util.run_deprecated_v1 def testDTypeCombinationsV2(self): """Tests random_poisson_v2() for all supported dtype combinations.""" with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py b/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py index 071d6c2998..898f38444b 100644 --- a/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py +++ b/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py @@ -129,23 +129,29 @@ class StatelessOpsTest(test.TestCase): yield (functools.partial(stateless.stateless_multinomial, **kwds), functools.partial(random_ops.multinomial, **kwds)) + @test_util.run_deprecated_v1 def testMatchFloat(self): self._test_match(self._float_cases()) + @test_util.run_deprecated_v1 def testMatchInt(self): self._test_match(self._int_cases()) + @test_util.run_deprecated_v1 def testMatchMultinomial(self): self._test_match(self._multinomial_cases()) + @test_util.run_deprecated_v1 def testDeterminismFloat(self): self._test_determinism( self._float_cases(shape_dtypes=(dtypes.int32, dtypes.int64))) + @test_util.run_deprecated_v1 def testDeterminismInt(self): self._test_determinism( self._int_cases(shape_dtypes=(dtypes.int32, dtypes.int64))) + @test_util.run_deprecated_v1 def testDeterminismMultinomial(self): self._test_determinism(self._multinomial_cases()) diff --git a/tensorflow/python/kernel_tests/reader_ops_test.py b/tensorflow/python/kernel_tests/reader_ops_test.py index a4a18c5219..43d15817e9 100644 --- a/tensorflow/python/kernel_tests/reader_ops_test.py +++ b/tensorflow/python/kernel_tests/reader_ops_test.py @@ -28,6 +28,7 @@ import zlib from tensorflow.core.protobuf import config_pb2 from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.lib.io import tf_record from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import io_ops @@ -145,6 +146,7 @@ class IdentityReaderTest(test.TestCase): self.assertAllEqual(expected, k) self.assertAllEqual(expected, v) + @test_util.run_deprecated_v1 def testOneEpoch(self): reader = io_ops.IdentityReader("test_reader") work_completed = reader.num_work_units_completed() @@ -178,6 +180,7 @@ class IdentityReaderTest(test.TestCase): self.assertAllEqual(3, self.evaluate(produced)) self.assertAllEqual(0, self.evaluate(queued_length)) + @test_util.run_deprecated_v1 def testMultipleEpochs(self): reader = io_ops.IdentityReader("test_reader") queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) @@ -198,6 +201,7 @@ class IdentityReaderTest(test.TestCase): "\\(requested 1, current size 0\\)"): self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testSerializeRestore(self): reader = io_ops.IdentityReader("test_reader") produced = reader.num_records_produced() @@ -252,6 +256,7 @@ class IdentityReaderTest(test.TestCase): "Could not parse state for IdentityReader 'test_reader'"): self.evaluate(reader.restore_state(b"BOGUS" + state[5:])) + @test_util.run_deprecated_v1 def testReset(self): reader = io_ops.IdentityReader("test_reader") work_completed = reader.num_work_units_completed() @@ -302,6 +307,7 @@ class WholeFileReaderTest(test.TestCase): self.assertAllEqual(compat.as_bytes(self._filenames[index]), k) self.assertAllEqual(self._content[index], v) + @test_util.run_deprecated_v1 def testOneEpoch(self): reader = io_ops.WholeFileReader("test_reader") queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) @@ -317,6 +323,7 @@ class WholeFileReaderTest(test.TestCase): "\\(requested 1, current size 0\\)"): self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testInfiniteEpochs(self): reader = io_ops.WholeFileReader("test_reader") queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) @@ -376,12 +383,15 @@ class TextLineReaderTest(test.TestCase): "\\(requested 1, current size 0\\)"): k, v = self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testOneEpochLF(self): self._testOneEpoch(self._CreateFiles(crlf=False)) + @test_util.run_deprecated_v1 def testOneEpochCRLF(self): self._testOneEpoch(self._CreateFiles(crlf=True)) + @test_util.run_deprecated_v1 def testSkipHeaderLines(self): files = self._CreateFiles() reader = io_ops.TextLineReader(skip_header_lines=1, name="test_reader") @@ -562,6 +572,7 @@ class FixedLengthRecordReaderTest(TFCompressionTestCase): "\\(requested 1, current size 0\\)"): k, v = self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testOneEpoch(self): for num_records in [0, 7]: # gap_bytes=0: hop_bytes=0 @@ -570,6 +581,7 @@ class FixedLengthRecordReaderTest(TFCompressionTestCase): files = self._CreateFiles(num_records, gap_bytes) self._TestOneEpoch(files, num_records, gap_bytes) + @test_util.run_deprecated_v1 def testGzipOneEpoch(self): for num_records in [0, 7]: # gap_bytes=0: hop_bytes=0 @@ -578,6 +590,7 @@ class FixedLengthRecordReaderTest(TFCompressionTestCase): files = self._CreateGzipFiles(num_records, gap_bytes) self._TestOneEpoch(files, num_records, gap_bytes, encoding="GZIP") + @test_util.run_deprecated_v1 def testZlibOneEpoch(self): for num_records in [0, 7]: # gap_bytes=0: hop_bytes=0 @@ -586,17 +599,20 @@ class FixedLengthRecordReaderTest(TFCompressionTestCase): files = self._CreateZlibFiles(num_records, gap_bytes) self._TestOneEpoch(files, num_records, gap_bytes, encoding="ZLIB") + @test_util.run_deprecated_v1 def testOneEpochWithHopBytes(self): for num_overlapped_records in [0, 2]: files = self._CreateOverlappedRecordFiles(num_overlapped_records) self._TestOneEpochWithHopBytes(files, num_overlapped_records) + @test_util.run_deprecated_v1 def testGzipOneEpochWithHopBytes(self): for num_overlapped_records in [0, 2]: files = self._CreateGzipOverlappedRecordFiles(num_overlapped_records,) self._TestOneEpochWithHopBytes( files, num_overlapped_records, encoding="GZIP") + @test_util.run_deprecated_v1 def testZlibOneEpochWithHopBytes(self): for num_overlapped_records in [0, 2]: files = self._CreateZlibOverlappedRecordFiles(num_overlapped_records) @@ -609,6 +625,7 @@ class TFRecordReaderTest(TFCompressionTestCase): def setUp(self): super(TFRecordReaderTest, self).setUp() + @test_util.run_deprecated_v1 def testOneEpoch(self): files = self._CreateFiles() reader = io_ops.TFRecordReader(name="test_reader") @@ -627,6 +644,7 @@ class TFRecordReaderTest(TFCompressionTestCase): "\\(requested 1, current size 0\\)"): k, v = self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testReadUpTo(self): files = self._CreateFiles() reader = io_ops.TFRecordReader(name="test_reader") @@ -654,6 +672,7 @@ class TFRecordReaderTest(TFCompressionTestCase): self.assertEqual(self._num_files * self._num_records, num_k) self.assertEqual(self._num_files * self._num_records, num_v) + @test_util.run_deprecated_v1 def testReadZlibFiles(self): options = tf_record.TFRecordOptions(TFRecordCompressionType.ZLIB) files = self._CreateFiles(options) @@ -670,6 +689,7 @@ class TFRecordReaderTest(TFCompressionTestCase): self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) self.assertAllEqual(self._Record(i, j), v) + @test_util.run_deprecated_v1 def testReadGzipFiles(self): options = tf_record.TFRecordOptions(TFRecordCompressionType.GZIP) files = self._CreateFiles(options) @@ -689,6 +709,7 @@ class TFRecordReaderTest(TFCompressionTestCase): class AsyncReaderTest(test.TestCase): + @test_util.run_deprecated_v1 def testNoDeadlockFromQueue(self): """Tests that reading does not block main execution threads.""" config = config_pb2.ConfigProto( @@ -737,6 +758,7 @@ class LMDBReaderTest(test.TestCase): self.db_path = os.path.join(self.get_temp_dir(), "data.mdb") shutil.copy(path, self.db_path) + @test_util.run_deprecated_v1 def testReadFromFile(self): reader = io_ops.LMDBReader(name="test_read_from_file") queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) @@ -754,6 +776,7 @@ class LMDBReaderTest(test.TestCase): "\\(requested 1, current size 0\\)"): k, v = self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testReadFromSameFile(self): with self.cached_session() as sess: reader1 = io_ops.LMDBReader(name="test_read_from_same_file1") @@ -773,6 +796,7 @@ class LMDBReaderTest(test.TestCase): coord.request_stop() coord.join(threads) + @test_util.run_deprecated_v1 def testReadFromFolder(self): reader = io_ops.LMDBReader(name="test_read_from_folder") queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) @@ -790,6 +814,7 @@ class LMDBReaderTest(test.TestCase): "\\(requested 1, current size 0\\)"): k, v = self.evaluate([key, value]) + @test_util.run_deprecated_v1 def testReadFromFileRepeatedly(self): with self.cached_session() as sess: reader = io_ops.LMDBReader(name="test_read_from_file_repeated") diff --git a/tensorflow/python/kernel_tests/record_input_test.py b/tensorflow/python/kernel_tests/record_input_test.py index 74020667d9..ad8188b372 100644 --- a/tensorflow/python/kernel_tests/record_input_test.py +++ b/tensorflow/python/kernel_tests/record_input_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import os +from tensorflow.python.framework import test_util from tensorflow.python.framework.errors_impl import NotFoundError from tensorflow.python.lib.io import tf_record from tensorflow.python.ops import data_flow_ops @@ -94,6 +95,7 @@ class RecordInputOpTest(test.TestCase): self.assertEqual(self.evaluate(yield_op), b"0000000000") + @test_util.run_deprecated_v1 def testRecordInputEpochs(self): files = 100 records_per_file = 100 @@ -140,6 +142,7 @@ class RecordInputOpTest(test.TestCase): for _ in range(50): self.evaluate(yield_op) + @test_util.run_deprecated_v1 def testEmptyGlob(self): with self.cached_session() as sess: record_input = data_flow_ops.RecordInput(file_pattern="foo") @@ -148,6 +151,7 @@ class RecordInputOpTest(test.TestCase): with self.assertRaises(NotFoundError): self.evaluate(yield_op) + @test_util.run_deprecated_v1 def testBufferTooSmall(self): files = 10 records_per_file = 10 diff --git a/tensorflow/python/kernel_tests/reduce_join_op_test.py b/tensorflow/python/kernel_tests/reduce_join_op_test.py index c26e62738c..49b6620779 100644 --- a/tensorflow/python/kernel_tests/reduce_join_op_test.py +++ b/tensorflow/python/kernel_tests/reduce_join_op_test.py @@ -25,6 +25,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -230,6 +231,7 @@ class ReduceJoinTest(UnicodeTestCase): axis=1, separator=" ") + @test_util.run_deprecated_v1 def testUnknownShape(self): input_array = [["a"], ["b"]] truth = ["ab"] @@ -241,6 +243,7 @@ class ReduceJoinTest(UnicodeTestCase): self.assertAllEqualUnicode(truth, output_array) self.assertAllEqual(truth_shape, reduced.get_shape()) + @test_util.run_deprecated_v1 def testUnknownIndices(self): input_array = [["this", "is", "a", "test"], ["please", "do", "not", "panic"]] @@ -297,6 +300,7 @@ class ReduceJoinTest(UnicodeTestCase): for permutation in itertools.permutations(xrange(num_dims), i): self._testMultipleReduceJoin(input_array, axis=permutation) + @test_util.run_deprecated_v1 def testInvalidReductionIndices(self): with self.cached_session(): with self.assertRaisesRegexp(ValueError, "Invalid reduction dim"): @@ -325,6 +329,7 @@ class ReduceJoinTest(UnicodeTestCase): output_shape = self.evaluate(output).shape self.assertAllEqual([0], output_shape) + @test_util.run_deprecated_v1 def testInvalidArgsUnknownShape(self): with self.cached_session(): placeholder = array_ops.placeholder(dtypes.string, name="placeholder") @@ -335,6 +340,7 @@ class ReduceJoinTest(UnicodeTestCase): with self.assertRaisesOpError("Duplicate reduction dimension 1"): duplicate_index.eval(feed_dict={placeholder.name: [[""]]}) + @test_util.run_deprecated_v1 def testInvalidArgsUnknownIndices(self): with self.cached_session(): placeholder = array_ops.placeholder(dtypes.int32, name="placeholder") diff --git a/tensorflow/python/kernel_tests/reduction_ops_test.py b/tensorflow/python/kernel_tests/reduction_ops_test.py index 4eb329796e..67a89461f3 100644 --- a/tensorflow/python/kernel_tests/reduction_ops_test.py +++ b/tensorflow/python/kernel_tests/reduction_ops_test.py @@ -27,6 +27,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops @@ -60,6 +61,7 @@ class ReducedShapeTest(test.TestCase): output = math_ops.reduced_shape(shape, axes=axes) self.assertAllEqual(output.eval(), result) + @test_util.run_deprecated_v1 def testSimple(self): with self.cached_session(): self._check([3], [], [3]) @@ -69,6 +71,7 @@ class ReducedShapeTest(test.TestCase): self._check([5, 3], [1], [5, 1]) self._check([5, 3], [0, 1], [1, 1]) + @test_util.run_deprecated_v1 def testZeros(self): """Check that reduced_shape does the right thing with zero dimensions.""" with self.cached_session(): @@ -83,6 +86,7 @@ class ReducedShapeTest(test.TestCase): self._check([3, 0], [1], [3, 1]) self._check([3, 0], [0, 1], [1, 1]) + @test_util.run_deprecated_v1 def testNegAxes(self): with self.cached_session(): self._check([10, 10, 10], [-1], [10, 10, 1]) @@ -94,6 +98,7 @@ class ReducedShapeTest(test.TestCase): class ReductionUnknownShape(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): with self.cached_session(): for dtype, reductions in [(dtypes.float32, @@ -188,6 +193,7 @@ class SumReductionTest(BaseReductionTest): tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) + @test_util.run_deprecated_v1 def testInfinity(self): for dtype in [np.float32, np.float64]: for special_value_x in [-np.inf, np.inf]: @@ -195,11 +201,13 @@ class SumReductionTest(BaseReductionTest): np_arr = np.array([special_value_x, special_value_y]).astype(dtype) self._compareAll(np_arr, None) + @test_util.run_deprecated_v1 def testInt32(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.int32) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testFloat16(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float16) @@ -219,6 +227,7 @@ class SumReductionTest(BaseReductionTest): tf_out_mean = self.evaluate(tf_mean) self.assertAllClose(tf_out_mean, 1.) + @test_util.run_deprecated_v1 def testFloat32(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float32) @@ -256,21 +265,25 @@ class SumReductionTest(BaseReductionTest): self.assertAllClose(sum_y, tf_out_sum_y) self.assertAllClose(sum_xz, tf_out_sum_xz) + @test_util.run_deprecated_v1 def testFloat64(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float64) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testComplex64(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.complex64) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testComplex128(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.complex128) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testInvalidIndex(self): np_arr = np.arange(0, 10).reshape([2, 5]).astype(np.float32) input_tensor = ops.convert_to_tensor(np_arr) @@ -284,6 +297,7 @@ class SumReductionTest(BaseReductionTest): ValueError, lambda e: "Invalid reduction dimension" in str(e)): math_ops.reduce_sum(input_tensor, [0, 2]) + @test_util.run_deprecated_v1 def testPartialShapes(self): np.random.seed(1618) @@ -317,6 +331,7 @@ class SumReductionTest(BaseReductionTest): c_unknown_indices, unknown_indices, keepdims=True) self.assertEqual(2, s_unknown_indices_keep.get_shape().rank) + @test_util.run_deprecated_v1 def testWrongShapeForReductionIndices(self): reduction_axes = [[1], [2]] c_unknown = array_ops.placeholder(dtypes.float32) @@ -326,6 +341,7 @@ class SumReductionTest(BaseReductionTest): # Int64?? + @test_util.run_deprecated_v1 def testGradient(self): for dtype in [ dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128 @@ -333,6 +349,7 @@ class SumReductionTest(BaseReductionTest): x = self._makeIncremental([2, 3, 4, 2], dtype) self._compareGradientAxes(x) + @test_util.run_deprecated_v1 def testHighRank(self): # Do a bunch of random high dimensional reductions np.random.seed(42) @@ -350,11 +367,13 @@ class SumReductionTest(BaseReductionTest): np.arange(1, rank, 2)): self._compareAll(data, axes) + @test_util.run_deprecated_v1 def testExpand(self): # Reduce an empty tensor to a nonempty tensor x = np.zeros((5, 0)) self._compareAll(x, [1]) + @test_util.run_deprecated_v1 def testEmptyGradients(self): with self.session(use_gpu=True): x = array_ops.zeros([0, 3]) @@ -362,6 +381,7 @@ class SumReductionTest(BaseReductionTest): error = gradient_checker.compute_gradient_error(x, [0, 3], y, [0]) self.assertEqual(error, 0) + @test_util.run_deprecated_v1 def testDegenerate(self): with self.session(use_gpu=True): for dtype in (dtypes.float16, dtypes.float32, dtypes.float64, @@ -403,6 +423,7 @@ class MeanReductionTest(BaseReductionTest): tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) + @test_util.run_deprecated_v1 def testInfinity(self): for dtype in [np.float32, np.float64]: for special_value_x in [-np.inf, np.inf]: @@ -410,37 +431,44 @@ class MeanReductionTest(BaseReductionTest): np_arr = np.array([special_value_x, special_value_y]).astype(dtype) self._compareAll(np_arr, None) + @test_util.run_deprecated_v1 def testInt32(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.int32) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testFloat32(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float32) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testFloat64(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float64) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testComplex64(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.complex64) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testComplex128(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.complex128) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testGradient(self): s = [2, 3, 4, 2] for dtype in [dtypes.float32, dtypes.float64]: x = self._makeIncremental(s, dtype) self._compareGradientAxes(x, rtol=1e-3, atol=1e-3) + @test_util.run_deprecated_v1 def testEmptyGradients(self): with self.session(use_gpu=True): x = array_ops.zeros([0, 3]) @@ -448,6 +476,7 @@ class MeanReductionTest(BaseReductionTest): error = gradient_checker.compute_gradient_error(x, [0, 3], y, [0]) self.assertEqual(error, 0) + @test_util.run_deprecated_v1 def testDegenerate(self): with self.session(use_gpu=True): for dtype in (dtypes.float16, dtypes.float32, dtypes.float64): @@ -476,6 +505,7 @@ class ProdReductionTest(BaseReductionTest): tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) + @test_util.run_deprecated_v1 def testInfinity(self): for dtype in [np.float32, np.float64]: for special_value_x in [-np.inf, np.inf]: @@ -483,6 +513,7 @@ class ProdReductionTest(BaseReductionTest): np_arr = np.array([special_value_x, special_value_y]).astype(dtype) self._compareAll(np_arr, None) + @test_util.run_deprecated_v1 def testInt32(self): # Numpy automatically upgrades the type of np.prod from int32 to int64, so # Numpy does not overflow an int32 np.prod while TensorFlow does. To avoid @@ -491,26 +522,31 @@ class ProdReductionTest(BaseReductionTest): np_arr = self._makeIncremental((2,) * rank, dtypes.int32) / 2 self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testFloat32(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float32) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testFloat64(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.float64) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testComplex64(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.complex64) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testComplex128(self): for rank in range(1, _MAX_RANK + 1): np_arr = self._makeIncremental((2,) * rank, dtypes.complex128) self._compareAllAxes(np_arr) + @test_util.run_deprecated_v1 def testGradientWithZeros(self): s = [2, 3, 4, 2] x = self._makeIncremental(s, dtypes.float32) / 20. @@ -533,6 +569,7 @@ class ProdReductionTest(BaseReductionTest): x4[:, :, :, :] = 0 self._compareGradientAxes(x4, rtol=1e-3, atol=1e-3) + @test_util.run_deprecated_v1 def testEmptyGradients(self): with self.session(use_gpu=True): x = array_ops.zeros([0, 3]) @@ -540,6 +577,7 @@ class ProdReductionTest(BaseReductionTest): error = gradient_checker.compute_gradient_error(x, [0, 3], y, [0]) self.assertEqual(error, 0) + @test_util.run_deprecated_v1 def testDegenerate(self): with self.session(use_gpu=True): for dtype in (dtypes.float16, dtypes.float32, dtypes.float64): @@ -579,6 +617,7 @@ class MinReductionTest(test.TestCase): tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) + @test_util.run_deprecated_v1 def testInfinity(self): for dtype in [np.float32, np.float64]: for special_value_x in [-np.inf, np.inf]: @@ -614,6 +653,7 @@ class MinReductionTest(test.TestCase): self._compareAll(np_arr, [0, 2]) self._compareAll(np_arr, [0, 1, 2]) + @test_util.run_deprecated_v1 def testGradient(self): s = [2, 3, 4, 2] x = np.arange(1.0, 49.0).reshape(s).astype(np.float64) @@ -624,6 +664,7 @@ class MinReductionTest(test.TestCase): t, s, su, [2, 2], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient2(self): s = [2, 3, 4, 2] x = np.arange(1.0, 49.0).reshape(s).astype(np.float64) @@ -634,6 +675,7 @@ class MinReductionTest(test.TestCase): t, s, su, [2, 4, 2], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient3(self): s = [2, 3, 4, 2] x = np.arange(1.0, 49.0).reshape(s).astype(np.float64) @@ -644,6 +686,7 @@ class MinReductionTest(test.TestCase): t, s, su, [2, 3, 2], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient4(self): s = [2, 3, 4, 2] x = np.arange(1.0, 49.0).reshape(s).astype(np.float64) @@ -654,6 +697,7 @@ class MinReductionTest(test.TestCase): t, s, su, [1], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testEmptyGradients(self): with self.cached_session(): x = array_ops.zeros([0, 3]) @@ -692,6 +736,7 @@ class MaxReductionTest(test.TestCase): tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) + @test_util.run_deprecated_v1 def testInfinity(self): for dtype in [np.float32, np.float64]: for special_value_x in [-np.inf, np.inf]: @@ -741,6 +786,7 @@ class MaxReductionTest(test.TestCase): self._compareAll(np_arr, [0, 2]) self._compareAll(np_arr, [0, 1, 2]) + @test_util.run_deprecated_v1 def testGradient(self): s = [2, 3, 4, 2] x = np.arange(-49.0, -1.0).reshape(s).astype(np.float64) @@ -751,6 +797,7 @@ class MaxReductionTest(test.TestCase): t, s, su, [2, 2], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient2(self): s = [2, 3, 4, 2] x = np.arange(-49.0, -1.0).reshape(s).astype(np.float64) @@ -761,6 +808,7 @@ class MaxReductionTest(test.TestCase): t, s, su, [2, 4, 2], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient3(self): s = [2, 3, 4, 2] x = np.arange(-49.0, -1.0).reshape(s).astype(np.float64) @@ -771,6 +819,7 @@ class MaxReductionTest(test.TestCase): t, s, su, [2, 3, 2], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient4(self): s = [2, 3, 4, 2] x = np.arange(-49.0, -1.0).reshape(s).astype(np.float64) @@ -781,6 +830,7 @@ class MaxReductionTest(test.TestCase): t, s, su, [1], x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testEmptyGradients(self): with self.cached_session(): x = array_ops.zeros([0, 3]) @@ -913,6 +963,7 @@ class CountNonzeroReductionTest(test.TestCase): self._compare(x, reduction_axes, True, use_gpu=True, feed_dict=feed_dict) self._compare(x, reduction_axes, True, use_gpu=False, feed_dict=feed_dict) + @test_util.run_deprecated_v1 def testBoolReduce1D(self): # Create a 1D array of floats np_arr = np.asarray([False, False, True, False, False, True]) @@ -920,11 +971,13 @@ class CountNonzeroReductionTest(test.TestCase): self._compareAll(np_arr, []) self._compareAll(np_arr, [0]) + @test_util.run_deprecated_v1 def testFloatReduce1D(self): # Create a 1D array of floats np_arr = np.asarray([0.0, 1.0, -1.0, 0.0, 0.0, 3.0]).astype(np.float32) self._compareAll(np_arr, [0]) + @test_util.run_deprecated_v1 def testFloatReduce4D(self): # Create a 4D array of floats and reduce across some # dimensions @@ -944,11 +997,13 @@ class CountNonzeroReductionTest(test.TestCase): self._compareAll(np_arr, [1, 2, 3]) self._compareAll(np_arr, [0, 1, 2, 3]) + @test_util.run_deprecated_v1 def testExpand(self): # Reduce an empty tensor to a nonempty tensor x = np.zeros((5, 0)) self._compareAll(x, [1]) + @test_util.run_deprecated_v1 def testDegenerate(self): for use_gpu in False, True: with self.cached_session(use_gpu=use_gpu): @@ -964,6 +1019,7 @@ class CountNonzeroReductionTest(test.TestCase): v = math_ops.count_nonzero(constant_op.constant(["test"])) self.assertAllClose(self.evaluate(v), 1) + @test_util.run_deprecated_v1 def testStringReduce1D(self): # Create a 1D array of strings x = np.asarray(["", "", "a", "", "", "b"]) @@ -974,6 +1030,7 @@ class CountNonzeroReductionTest(test.TestCase): self._compare(x, [], keepdims=True, zero=np.str("")) self._compare(x, [0], keepdims=True, zero=np.str("")) + @test_util.run_deprecated_v1 def testStringReduce2D(self): # Create a 2D array of strings x = np.asarray([["", "", "a", "", "", "b"], diff --git a/tensorflow/python/kernel_tests/regex_full_match_op_test.py b/tensorflow/python/kernel_tests/regex_full_match_op_test.py index 4edd3e98d9..488ec85ab2 100644 --- a/tensorflow/python/kernel_tests/regex_full_match_op_test.py +++ b/tensorflow/python/kernel_tests/regex_full_match_op_test.py @@ -23,6 +23,7 @@ from absl.testing import parameterized from tensorflow.python.compat import compat from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_string_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -33,6 +34,7 @@ from tensorflow.python.platform import test (gen_string_ops.static_regex_full_match)) class RegexFullMatchOpVariantsTest(test.TestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testRegexFullMatch(self, op): values = ["abaaba", "abcdabcde"] with self.cached_session(): @@ -40,6 +42,7 @@ class RegexFullMatchOpVariantsTest(test.TestCase, parameterized.TestCase): matched = op(input_tensor, "a.*a").eval() self.assertAllEqual([True, False], matched) + @test_util.run_deprecated_v1 def testRegexFullMatchTwoDims(self, op): values = [["abaaba", "abcdabcde"], ["acdcba", "ebcda"]] with self.cached_session(): @@ -47,6 +50,7 @@ class RegexFullMatchOpVariantsTest(test.TestCase, parameterized.TestCase): matched = op(input_tensor, "a.*a").eval() self.assertAllEqual([[True, False], [True, False]], matched) + @test_util.run_deprecated_v1 def testEmptyMatch(self, op): values = ["abc", "1"] with self.cached_session(): @@ -54,6 +58,7 @@ class RegexFullMatchOpVariantsTest(test.TestCase, parameterized.TestCase): matched = op(input_tensor, "").eval() self.assertAllEqual([False, False], matched) + @test_util.run_deprecated_v1 def testInvalidPattern(self, op): values = ["abc", "1"] with self.cached_session(): @@ -66,6 +71,7 @@ class RegexFullMatchOpVariantsTest(test.TestCase, parameterized.TestCase): class RegexFullMatchOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testRegexFullMatchDelegation(self): with compat.forward_compatibility_horizon(2018, 11, 1): with self.cached_session(): @@ -78,6 +84,7 @@ class RegexFullMatchOpTest(test.TestCase): op_tensor = string_ops.regex_full_match(input_tensor, pattern_tensor) self.assertTrue(op_tensor.name.startswith("RegexFullMatch"), op.name) + @test_util.run_deprecated_v1 def testStaticRegexFullMatchDelegation(self): with compat.forward_compatibility_horizon(2018, 11, 20): with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/regex_replace_op_test.py b/tensorflow/python/kernel_tests/regex_replace_op_test.py index ce9a1b5279..6c7dfee7b4 100644 --- a/tensorflow/python/kernel_tests/regex_replace_op_test.py +++ b/tensorflow/python/kernel_tests/regex_replace_op_test.py @@ -22,6 +22,7 @@ from absl.testing import parameterized from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_string_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -32,6 +33,7 @@ from tensorflow.python.platform import test (gen_string_ops.static_regex_replace)) class RegexReplaceOpVariantsTest(test.TestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testForwarding(self, op): with self.cached_session(): # Generate an input that is uniquely consumed by the regex op. @@ -45,6 +47,7 @@ class RegexReplaceOpVariantsTest(test.TestCase, parameterized.TestCase): stripped = op(inp, "\\p{Ll}", ".").eval() self.assertAllEqual([b"A.C.E", b"H.J.L"], stripped) + @test_util.run_deprecated_v1 def testRemovePrefix(self, op): values = ["a:foo", "a:bar", "a:foo", "b:baz", "b:qux", "ca:b"] with self.cached_session(): @@ -53,6 +56,7 @@ class RegexReplaceOpVariantsTest(test.TestCase, parameterized.TestCase): self.assertAllEqual([b"foo", b"bar", b"foo", b"baz", b"qux", b"ca:b"], stripped) + @test_util.run_deprecated_v1 def testRegexReplace(self, op): values = ["aba\naba", "abcdabcde"] with self.cached_session(): @@ -60,6 +64,7 @@ class RegexReplaceOpVariantsTest(test.TestCase, parameterized.TestCase): stripped = op(input_vector, "a.*a", "(\\0)").eval() self.assertAllEqual([b"(aba)\n(aba)", b"(abcda)bcde"], stripped) + @test_util.run_deprecated_v1 def testEmptyMatch(self, op): values = ["abc", "1"] with self.cached_session(): @@ -67,6 +72,7 @@ class RegexReplaceOpVariantsTest(test.TestCase, parameterized.TestCase): stripped = op(input_vector, "", "x").eval() self.assertAllEqual([b"xaxbxcx", b"x1x"], stripped) + @test_util.run_deprecated_v1 def testInvalidPattern(self, op): values = ["abc", "1"] with self.cached_session(): @@ -76,6 +82,7 @@ class RegexReplaceOpVariantsTest(test.TestCase, parameterized.TestCase): with self.assertRaisesOpError("Invalid pattern"): self.evaluate(replace) + @test_util.run_deprecated_v1 def testGlobal(self, op): values = ["ababababab", "abcabcabc", ""] with self.cached_session(): @@ -98,6 +105,7 @@ class RegexReplaceTest(test.TestCase, parameterized.TestCase): (as_string, as_tensor), (as_tensor, as_string), (as_tensor, as_tensor)) + @test_util.run_deprecated_v1 def testRegexReplaceDelegation(self, pattern_fn, rewrite_fn): with self.cached_session(): input_vector = constant_op.constant("foo", dtypes.string) @@ -106,6 +114,7 @@ class RegexReplaceTest(test.TestCase, parameterized.TestCase): op = string_ops.regex_replace(input_vector, pattern, replace) self.assertTrue(op.name.startswith("RegexReplace")) + @test_util.run_deprecated_v1 def testStaticRegexReplaceDelegation(self): with self.cached_session(): input_vector = constant_op.constant("foo", dtypes.string) diff --git a/tensorflow/python/kernel_tests/relu_op_test.py b/tensorflow/python/kernel_tests/relu_op_test.py index 30cef90885..55e68f4884 100644 --- a/tensorflow/python/kernel_tests/relu_op_test.py +++ b/tensorflow/python/kernel_tests/relu_op_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -105,6 +106,7 @@ class ReluTest(test.TestCase): # The gradient test for ReLU is a bit tricky as the derivative is not well # defined at around zero and we want to avoid that in terms of input values. + @test_util.run_deprecated_v1 def testGradientFloat32(self): with self.cached_session(): x = constant_op.constant( @@ -124,6 +126,7 @@ class ReluTest(test.TestCase): # The gradient for fp16 is inaccurate due to the low-precision. # Instead of relying on compute_gradient_error, we compare the fp16 analytical # gradient against their fp32 counterpart. + @test_util.run_deprecated_v1 def testGradientFloat16(self): with self.session(use_gpu=True) as sess: # Randomly construct a 1D shape from [1, 40) @@ -150,6 +153,7 @@ class ReluTest(test.TestCase): dx_f32_v, dx_f16_v = self.evaluate([dx_f32, dx_f16]) self.assertAllClose(dx_f32_v, dx_f16_v, atol=3e-4) + @test_util.run_deprecated_v1 def testGradientFloat64(self): with self.cached_session(): x = constant_op.constant( @@ -167,6 +171,7 @@ class ReluTest(test.TestCase): print("relu (float64) gradient err = ", err) self.assertLess(err, 1e-10) + @test_util.run_deprecated_v1 def testGradGradFloat32(self): with self.cached_session(): x = constant_op.constant( @@ -184,6 +189,7 @@ class ReluTest(test.TestCase): print("relu (float32) gradient of gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradGradFloat64(self): with self.cached_session(): x = constant_op.constant( @@ -252,6 +258,7 @@ class Relu6Test(test.TestCase): # The gradient test for ReLU6 is a bit tricky as the derivative is # not well defined at around zero and six and we want to avoid that # in terms of input values. + @test_util.run_deprecated_v1 def testGradientFloat32(self): with self.cached_session(): x = constant_op.constant( @@ -268,6 +275,7 @@ class Relu6Test(test.TestCase): print("relu6 (float32) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientFloat64(self): with self.cached_session(): x = constant_op.constant( @@ -325,6 +333,7 @@ class LeakyReluTest(test.TestCase): # The gradient test for Leaky ReLU is a bit tricky as the derivative is not # well defined at around zero and we want to avoid that in terms of input # values. + @test_util.run_deprecated_v1 def testGradientFloat32(self): with self.test_session(): x = constant_op.constant( @@ -341,6 +350,7 @@ class LeakyReluTest(test.TestCase): print("leaky_relu (float32) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientFloat64(self): with self.test_session(): x = constant_op.constant( @@ -358,6 +368,7 @@ class LeakyReluTest(test.TestCase): print("leaky_relu (float64) gradient err = ", err) self.assertLess(err, 1e-10) + @test_util.run_deprecated_v1 def testGradGradFloat32(self): with compat.forward_compatibility_horizon(2018, 11, 2): with self.test_session(): @@ -376,6 +387,7 @@ class LeakyReluTest(test.TestCase): print("leaky_relu (float32) gradient of gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradGradFloat64(self): with compat.forward_compatibility_horizon(2018, 11, 2): with self.test_session(): @@ -439,6 +451,7 @@ class EluTest(test.TestCase): for t in [np.float16, np.float32, np.float64]: self._testElu(np.array([[-9, 7, -5, 3, -1], [1, -3, 5, -7, 9]]).astype(t)) + @test_util.run_deprecated_v1 def testGradientFloat32(self): with self.cached_session(): x_val = [[-0.9, -0.7, -0.5, -0.3, -0.1], [0.1, 0.3, 0.5, 0.7, 0.9]] @@ -450,6 +463,7 @@ class EluTest(test.TestCase): print("elu (float32) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientFloat64(self): with self.cached_session(): x_val = [[-0.9, -0.7, -0.5, -0.3, -0.1], [0.1, 0.3, 0.5, 0.7, 0.9]] @@ -461,6 +475,7 @@ class EluTest(test.TestCase): print("elu (float64) gradient err = ", err) self.assertLess(err, 1e-6) + @test_util.run_deprecated_v1 def testGradGrad(self): with self.cached_session(): x = array_ops.placeholder(dtype=dtypes.float32) @@ -472,6 +487,7 @@ class EluTest(test.TestCase): err = np.abs(gg.eval(feed_dict={x: x_val}) - _elu_grad_grad(x_val)) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradGradFloat32(self): with self.cached_session(): x = constant_op.constant( @@ -489,6 +505,7 @@ class EluTest(test.TestCase): print("elu (float32) gradient of gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradGradFloat64(self): with self.cached_session(): x = constant_op.constant( @@ -539,6 +556,7 @@ class SeluTest(test.TestCase): self._testSelu( np.array([[-9, 7, -5, 3, -1], [1, -3, 5, -7, 9]]).astype(t)) + @test_util.run_deprecated_v1 def testGradientFloat32(self): with self.cached_session(): x_val = [[-0.9, -0.7, -0.5, -0.3, -0.1], [0.1, 0.3, 0.5, 0.7, 0.9]] @@ -550,6 +568,7 @@ class SeluTest(test.TestCase): print("selu (float32) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradientFloat64(self): with self.cached_session(): x_val = [[-0.9, -0.7, -0.5, -0.3, -0.1], [0.1, 0.3, 0.5, 0.7, 0.9]] @@ -561,6 +580,7 @@ class SeluTest(test.TestCase): print("selu (float64) gradient err = ", err) self.assertLess(err, 1e-6) + @test_util.run_deprecated_v1 def testGradGradFloat32(self): with self.cached_session(): x = constant_op.constant( @@ -578,6 +598,7 @@ class SeluTest(test.TestCase): print("selu (float32) gradient of gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradGradFloat64(self): with self.cached_session(): x = constant_op.constant( diff --git a/tensorflow/python/kernel_tests/reshape_op_test.py b/tensorflow/python/kernel_tests/reshape_op_test.py index 84539c2b02..db3e88a104 100644 --- a/tensorflow/python/kernel_tests/reshape_op_test.py +++ b/tensorflow/python/kernel_tests/reshape_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.platform import test @@ -91,6 +92,7 @@ class ReshapeTest(test.TestCase): # TODO(vrv): Add tests for failure conditions once python test_util # reports errors. + @test_util.run_deprecated_v1 def testFloatReshapeGradThreeDimensions(self): x = np.arange(1., 25.).reshape([2, 3, 4]).astype(np.float32) s = list(np.shape(x)) @@ -111,6 +113,7 @@ class ReshapeTest(test.TestCase): self._testBothReshape(x, [0, 0, 0]) self._testBothReshape(x, [1, -1, 5]) + @test_util.run_deprecated_v1 def testErrors(self): y = constant_op.constant(0.0, shape=[23, 29, 31]) with self.assertRaisesRegexp(ValueError, "must be evenly divisible by 17"): @@ -121,6 +124,7 @@ class ReshapeTest(test.TestCase): "Cannot reshape a tensor with 4096 elements"): array_ops.reshape(z, [4095]) + @test_util.run_deprecated_v1 def testPartialShapes(self): x = array_ops.placeholder(dtypes.float32) diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index d30ab6a9c2..b57d9d47aa 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -54,6 +54,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): # involving objects with __del__ defined. self.assertEqual(0, len(gc.garbage)) + @test_util.run_deprecated_v1 def testHandleDtypeShapeMatch(self): with self.cached_session(): handle = resource_variable_ops.var_handle_op(dtype=dtypes.int32, shape=[]) @@ -123,6 +124,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): # values. self.assertFalse(np.allclose(variable.numpy(), copied_variable.numpy())) + @test_util.run_deprecated_v1 def testGraphDeepCopy(self): with self.cached_session(): init_value = np.ones((4, 4, 4)) @@ -146,6 +148,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): resource_variable_ops.variable_shape(v.handle)), [2]) + @test_util.run_deprecated_v1 def testDifferentAssignGraph(self): with ops.Graph().as_default(): v = resource_variable_ops.ResourceVariable(1.0) @@ -153,12 +156,14 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): v.assign(2.0) # Note: this fails if we run convert_to_tensor on not the # variable graph. + @test_util.run_deprecated_v1 def testFetchHandle(self): with self.cached_session(): handle = resource_variable_ops.var_handle_op( dtype=dtypes.int32, shape=[1], name="foo") self.assertGreater(len(handle.eval()), 0) + @test_util.run_deprecated_v1 def testCachedValueReadBeforeWrite(self): with self.cached_session() as sess: v = resource_variable_ops.ResourceVariable(0.0, caching_device="cpu:0") @@ -435,6 +440,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) self.assertEqual(self.evaluate(read), [[6]]) + @test_util.run_deprecated_v1 def testScatterUpdateString(self): handle = resource_variable_ops.var_handle_op( dtype=dtypes.string, shape=[1, 1]) @@ -446,6 +452,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.assertEqual(compat.as_bytes(self.evaluate(read)[0][0]), compat.as_bytes("b")) + @test_util.run_deprecated_v1 def testScatterUpdateStringScalar(self): handle = resource_variable_ops.var_handle_op( dtype=dtypes.string, shape=[1, 1]) @@ -500,6 +507,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): initial_value=lambda: 1, constraint=constraint, name="var1") # TODO(alive): how should this work in Eager mode? + @test_util.run_deprecated_v1 def testInitFn(self): with self.cached_session(): v = resource_variable_ops.ResourceVariable( @@ -591,6 +599,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): variable_def=other_v_def) self.assertTrue(other_v_prime._cached_value is not None) + @test_util.run_deprecated_v1 def testVariableDefInitializedInstances(self): with ops.Graph().as_default(), self.cached_session() as sess: v_def = resource_variable_ops.ResourceVariable( @@ -646,6 +655,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): value = self.evaluate(v.sparse_read([0, 3, 1, 2])) self.assertAllEqual(init_value[[0, 3, 1, 2], ...], value) + @test_util.run_deprecated_v1 def testToFromProto(self): with self.cached_session(): v = resource_variable_ops.ResourceVariable(1.0) @@ -694,6 +704,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.assertEqual(0.0, self.evaluate(v.value())) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testDestroyResource(self): v = resource_variable_ops.ResourceVariable(3.0, name="var0") self.evaluate(variables.global_variables_initializer()) @@ -707,6 +718,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.evaluate(resource_variable_ops.destroy_resource_op( handle, ignore_lookup_error=True)) + @test_util.run_deprecated_v1 def testAssignDifferentShapes(self): with self.cached_session() as sess, variable_scope.variable_scope( "foo", use_resource=True): @@ -727,6 +739,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): assign = var.assign(np.zeros(shape=[2, 2])) self.evaluate(assign) + @test_util.run_deprecated_v1 def testDtypeAfterFromProto(self): v = resource_variable_ops.ResourceVariable(2.0) w = resource_variable_ops.ResourceVariable.from_proto(v.to_proto()) @@ -734,6 +747,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.assertEqual(v.dtype, w.dtype) # TODO(alive): get caching to work in eager mode. + @test_util.run_deprecated_v1 def testCachingDevice(self): with ops.device("/job:server/task:1"): v = resource_variable_ops.ResourceVariable( @@ -749,6 +763,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): with self.assertRaises(ValueError): _ = w.value().op.get_attr("_class") + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): v = resource_variable_ops.ResourceVariable(300.0, name="var4") @@ -767,6 +782,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): with self.assertRaisesOpError("Resource .*/var5/.* does not exist"): resource_variable_ops.read_variable_op(x, v.dtype.base_dtype).eval() + @test_util.run_deprecated_v1 def testSharedNameWithNamescope(self): with self.cached_session(): with ops.name_scope("foo"): @@ -795,6 +811,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): "", str(v.sparse_read(array_ops.placeholder(dtypes.int32)).shape)) + @test_util.run_deprecated_v1 def testSetInitialValue(self): with self.cached_session(): # Initialize variable with a value different from the initial value passed @@ -803,6 +820,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): v.initializer.run(feed_dict={v.initial_value: 3.0}) self.assertEqual(3.0, v.value().eval()) + @test_util.run_deprecated_v1 def testControlFlowInitialization(self): """Expects an error if an initializer is in a control-flow scope.""" @@ -939,6 +957,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(self.evaluate(v.assign_add(1)), [1, 2, 3, 4]) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testCopyToGraphUninitialized(self): v = resource_variable_ops.ResourceVariable([0, 1, 2, 3]) copy_to_graph = ops.Graph() diff --git a/tensorflow/python/kernel_tests/reverse_sequence_op_test.py b/tensorflow/python/kernel_tests/reverse_sequence_op_test.py index 91d054ad9a..05307c9834 100644 --- a/tensorflow/python/kernel_tests/reverse_sequence_op_test.py +++ b/tensorflow/python/kernel_tests/reverse_sequence_op_test.py @@ -23,6 +23,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.platform import test @@ -107,6 +108,7 @@ class ReverseSequenceTest(test.TestCase): def testComplex128Basic(self): self._testBasic(np.complex128) + @test_util.run_deprecated_v1 def testFloatReverseSequenceGrad(self): x = np.asarray( [[[1, 2, 3, 4], [5, 6, 7, 8]], [[9, 10, 11, 12], [13, 14, 15, 16]], @@ -133,6 +135,7 @@ class ReverseSequenceTest(test.TestCase): print("ReverseSequence gradient error = %g" % err) self.assertLess(err, 1e-8) + @test_util.run_deprecated_v1 def testShapeFunctionEdgeCases(self): t = array_ops.reverse_sequence( array_ops.placeholder( diff --git a/tensorflow/python/kernel_tests/rnn_test.py b/tensorflow/python/kernel_tests/rnn_test.py index 0090b7332f..3bc457f8fb 100644 --- a/tensorflow/python/kernel_tests/rnn_test.py +++ b/tensorflow/python/kernel_tests/rnn_test.py @@ -262,6 +262,7 @@ class RNNTest(test.TestCase): rnn.dynamic_rnn(cell, inputs, dtype=dtypes.float32, sequence_length=[4]) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testTensorArrayStateIsAccepted(self): cell = TensorArrayStateRNNCell() in_eager_mode = context.executing_eagerly() @@ -285,6 +286,7 @@ class RNNTest(test.TestCase): self.assertAllEqual(4, state[0]) self.assertAllEqual([[[1]], [[2]], [[3]], [[4]]], state[1]) + @test_util.run_deprecated_v1 def testCellGetInitialState(self): cell = rnn_cell_impl.BasicRNNCell(5) with self.assertRaisesRegexp( @@ -345,6 +347,7 @@ class RNNTest(test.TestCase): self._assert_cell_builds(contrib_rnn.IndyLSTMCell, f32, 5, 7, 3) self._assert_cell_builds(contrib_rnn.IndyLSTMCell, f64, 5, 7, 3) + @test_util.run_deprecated_v1 def testRNNWithKerasSimpleRNNCell(self): with self.cached_session() as sess: input_shape = 10 @@ -378,6 +381,7 @@ class RNNTest(test.TestCase): self.assertEqual(len(outputs), batch) self.assertEqual(len(state), batch) + @test_util.run_deprecated_v1 def testRNNWithKerasGRUCell(self): with self.cached_session() as sess: input_shape = 10 @@ -411,6 +415,7 @@ class RNNTest(test.TestCase): self.assertEqual(len(outputs), batch) self.assertEqual(len(state), batch) + @test_util.run_deprecated_v1 def testRNNWithKerasLSTMCell(self): with self.cached_session() as sess: input_shape = 10 @@ -448,6 +453,7 @@ class RNNTest(test.TestCase): self.assertEqual(len(state[0]), batch) self.assertEqual(len(state[1]), batch) + @test_util.run_deprecated_v1 def testRNNWithStackKerasCell(self): with self.cached_session() as sess: input_shape = 10 @@ -491,6 +497,7 @@ class RNNTest(test.TestCase): for s in state: self.assertEqual(len(s), batch) + @test_util.run_deprecated_v1 def testStaticRNNWithKerasSimpleRNNCell(self): with self.cached_session() as sess: input_shape = 10 @@ -529,6 +536,7 @@ class RNNTest(test.TestCase): self.assertEqual(len(outputs[0]), batch) self.assertEqual(len(state), batch) + @test_util.run_deprecated_v1 def testKerasAndTFRNNLayerOutputComparison(self): input_shape = 10 output_shape = 5 @@ -562,6 +570,7 @@ class RNNTest(test.TestCase): self.assertAllClose(tf_out, k_out) self.assertAllClose(tf_state, k_state) + @test_util.run_deprecated_v1 def testSimpleRNNCellAndBasicRNNCellComparison(self): input_shape = 10 output_shape = 5 @@ -601,6 +610,7 @@ class RNNTest(test.TestCase): self.assertAllClose(tf_out, k_out, atol=1e-5) self.assertAllClose(tf_state, k_state, atol=1e-5) + @test_util.run_deprecated_v1 def testBasicLSTMCellInterchangeWithLSTMCell(self): with self.session(graph=ops_lib.Graph()) as sess: basic_cell = rnn_cell_impl.BasicLSTMCell(1) diff --git a/tensorflow/python/kernel_tests/save_restore_ops_test.py b/tensorflow/python/kernel_tests/save_restore_ops_test.py index be117c4350..fecc9a3800 100644 --- a/tensorflow/python/kernel_tests/save_restore_ops_test.py +++ b/tensorflow/python/kernel_tests/save_restore_ops_test.py @@ -55,6 +55,7 @@ class ShardedFileOpsTest(test.TestCase): class ShapeInferenceTest(test.TestCase): + @test_util.run_deprecated_v1 def testRestoreV2WithSliceInput(self): op = io_ops.restore_v2("model", ["var1", "var2"], ["", "3 4 0,1:-"], [dtypes.float32, dtypes.float32]) @@ -62,11 +63,13 @@ class ShapeInferenceTest(test.TestCase): self.assertFalse(op[0].get_shape().is_fully_defined()) self.assertEqual([1, 4], op[1].get_shape()) + @test_util.run_deprecated_v1 def testRestoreV2NumSlicesNotMatch(self): with self.assertRaises(ValueError): io_ops.restore_v2("model", ["var1", "var2", "var3"], ["", "3 4 0,1:-"], [dtypes.float32, dtypes.float32]) + @test_util.run_deprecated_v1 def testRestoreSlice(self): op = gen_io_ops.restore_slice("model", "var", "3 4 0,1:-", dtypes.float32) self.assertEqual([1, 4], op.get_shape()) diff --git a/tensorflow/python/kernel_tests/scan_ops_test.py b/tensorflow/python/kernel_tests/scan_ops_test.py index c48e0e2e67..33e491fee1 100644 --- a/tensorflow/python/kernel_tests/scan_ops_test.py +++ b/tensorflow/python/kernel_tests/scan_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -88,12 +89,14 @@ class CumsumTest(test.TestCase): for reverse in [True, False]: self._compare(x, axis, exclusive, reverse) + @test_util.run_deprecated_v1 def testEmpty(self): for dtype in self.valid_dtypes: x = np.zeros([0]).astype(dtype) for axis in (-1, 0): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def testAxisType(self): for dtype in self.valid_dtypes: x = np.arange(1, 6).reshape([5]).astype(dtype) @@ -102,30 +105,35 @@ class CumsumTest(test.TestCase): axis = constant_op.constant(0, axis_dtype) tf_out = math_ops.cumsum(x, axis).eval() + @test_util.run_deprecated_v1 def test1D(self): for dtype in self.valid_dtypes: x = np.arange(1, 6).reshape([5]).astype(dtype) for axis in (-1, 0): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def test2D(self): for dtype in self.valid_dtypes: x = np.arange(0, 10).reshape([2, 5]).astype(dtype) for axis in (-2, -1, 0, 1): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def test3D(self): for dtype in self.valid_dtypes: x = np.arange(0, 20).reshape([2, 2, 5]).astype(dtype) for axis in (-3, -2, -1, 0, 1, 2): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def test6D(self): for dtype in self.valid_dtypes: x = np.arange(1, 145).reshape([2, 2, 3, 3, 2, 2]).astype(dtype) for axis in range(-6, 6, 3): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def testLarge(self): for dtype in self.valid_dtypes: x = np.ones([1000000], dtype=dtype) / 1024 @@ -157,22 +165,27 @@ class CumsumTest(test.TestCase): t, shape, result, shape, x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient(self): for axis in (-1, 0): self._compareGradient([50], axis, False, False) + @test_util.run_deprecated_v1 def testGradientReverse(self): for axis in (-1, 0): self._compareGradient([50], axis, False, True) + @test_util.run_deprecated_v1 def testGradientExclusive(self): for axis in (-1, 0): self._compareGradient([50], axis, True, False) + @test_util.run_deprecated_v1 def testGradientExclusiveReverse(self): for axis in (-1, 0): self._compareGradient([50], axis, True, True) + @test_util.run_deprecated_v1 def testGradient2D(self): for axis in (-1, 0, 1): for exclusive in [True, False]: @@ -199,12 +212,14 @@ class CumprodTest(test.TestCase): for reverse in [True, False]: self._compare(x, axis, exclusive, reverse) + @test_util.run_deprecated_v1 def testEmpty(self): for dtype in self.valid_dtypes: x = np.zeros([0]).astype(dtype) for axis in (-1, 0): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def testAxisType(self): for dtype in self.valid_dtypes: x = np.arange(1, 6).reshape([5]).astype(dtype) @@ -213,24 +228,28 @@ class CumprodTest(test.TestCase): axis = constant_op.constant(0, axis_dtype) tf_out = math_ops.cumprod(x, axis).eval() + @test_util.run_deprecated_v1 def test1D(self): for dtype in self.valid_dtypes: x = np.arange(1, 6).reshape([5]).astype(dtype) for axis in (-1, 0): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def test2D(self): for dtype in self.valid_dtypes: x = np.arange(1, 11).reshape([2, 5]).astype(dtype) for axis in (-2, -1, 0, 1): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def test3D(self): for dtype in self.valid_dtypes: x = np.arange(1, 21).reshape([2, 2, 5]).astype(dtype) for axis in (-3, -2, -1, 0, 1, 2): self._compareAll(x, axis) + @test_util.run_deprecated_v1 def test6D(self): for dtype in self.valid_dtypes: x = np.arange(1, 145).reshape([2, 2, 3, 3, 2, 2]).astype(dtype) @@ -263,22 +282,27 @@ class CumprodTest(test.TestCase): t, shape, result, shape, x_init_value=x, delta=1) self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8) + @test_util.run_deprecated_v1 def testGradient(self): for axis in (-1, 0): self._compareGradient([8], axis, False, False) + @test_util.run_deprecated_v1 def testGradientReverse(self): for axis in (-1, 0): self._compareGradient([8], axis, False, True) + @test_util.run_deprecated_v1 def testGradientExclusive(self): for axis in (-1, 0): self._compareGradient([8], axis, True, False) + @test_util.run_deprecated_v1 def testGradientExclusiveReverse(self): for axis in (-1, 0): self._compareGradient([8], axis, True, True) + @test_util.run_deprecated_v1 def testGradient2D(self): for axis in (-2, -1, 0, 1): for exclusive in [True, False]: diff --git a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py index c388121982..298db1547a 100644 --- a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py +++ b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py @@ -165,6 +165,7 @@ class StatefulScatterNdTest(test.TestCase): result = self.evaluate(scatter) self.assertAllClose(result, expected) + @test_util.run_deprecated_v1 def testSimpleResource(self): indices = constant_op.constant([[4], [3], [1], [7]], dtype=dtypes.int32) updates = constant_op.constant([9, 10, 11, 12], dtype=dtypes.float32) @@ -207,12 +208,15 @@ class StatefulScatterNdTest(test.TestCase): result = self.evaluate(scatter) self.assertAllClose(result, expected) + @test_util.run_deprecated_v1 def testVariableRankUpdate(self): self._VariableRankTests(_NumpyUpdate, state_ops.scatter_nd_update) + @test_util.run_deprecated_v1 def testVariableRankAdd(self): self._VariableRankTests(_NumpyAdd, state_ops.scatter_nd_add) + @test_util.run_deprecated_v1 def testVariableRankSub(self): self._VariableRankTests(_NumpySub, state_ops.scatter_nd_sub) @@ -230,6 +234,7 @@ class StatefulScatterNdTest(test.TestCase): self._VariableRankTest( np_scatter, tf_scatter, vtype, itype, repeat_indices=True) + @test_util.run_deprecated_v1 def testScatterRepeatIndices(self): """This tests scatter_add using indices that repeat.""" self._ScatterRepeatIndicesTest(_NumpyAdd, state_ops.scatter_nd_add) @@ -251,6 +256,7 @@ class StatefulScatterNdTest(test.TestCase): # session.run([update0, update1]) # self.assertAllEqual([False, True], self.evaluate(var)) + @test_util.run_deprecated_v1 def testScatterOutOfRangeCpu(self): # TODO(simister): Re-enable once binary size increase due to # scatter_nd ops is under control. @@ -287,6 +293,7 @@ class StatefulScatterNdTest(test.TestCase): state_ops.scatter_nd_update(ref, indices, updates).get_shape().as_list(), shape) + @test_util.run_deprecated_v1 def testResVarInvalidOutputShape(self): res = variables.Variable( initial_value=lambda: array_ops.zeros(shape=[], dtype=dtypes.float32), @@ -296,6 +303,7 @@ class StatefulScatterNdTest(test.TestCase): with self.assertRaisesOpError("Output must be at least 1-D"): state_ops.scatter_nd_update(res, [[0]], [0.22]).eval() + @test_util.run_deprecated_v1 def testExtraIndicesDimensions(self): indices = array_ops.zeros([1, 1, 2], dtypes.int32) updates = array_ops.zeros([1, 1], dtypes.int32) @@ -309,6 +317,7 @@ class StatefulScatterNdTest(test.TestCase): ref.initializer.run() self.assertAllEqual(expected_result, self.evaluate(scatter_update)) + @test_util.run_deprecated_v1 def testRank3InvalidShape1(self): indices = array_ops.zeros([3, 2, 2], dtypes.int32) updates = array_ops.zeros([2, 2, 2], dtypes.int32) @@ -318,6 +327,7 @@ class StatefulScatterNdTest(test.TestCase): ValueError, "The outer \\d+ dimensions of indices\\.shape="): state_ops.scatter_nd_update(ref, indices, updates) + @test_util.run_deprecated_v1 def testRank3InvalidShape2(self): indices = array_ops.zeros([2, 2, 1], dtypes.int32) updates = array_ops.zeros([2, 2], dtypes.int32) @@ -327,6 +337,7 @@ class StatefulScatterNdTest(test.TestCase): ValueError, "The inner \\d+ dimensions of input\\.shape="): state_ops.scatter_nd_update(ref, indices, updates) + @test_util.run_deprecated_v1 def testConcurrentUpdates(self): num_updates = 10000 update_values = np.random.rand(num_updates) @@ -455,6 +466,7 @@ class ScatterNdTest(test.TestCase): self.assertAllEqual( self.scatter_nd(indices, updates, shape).get_shape().as_list(), shape) + @test_util.run_deprecated_v1 def testExtraIndicesDimensions(self): indices = array_ops.zeros([1, 1, 2], dtypes.int32) updates = array_ops.zeros([1, 1], dtypes.int32) @@ -465,24 +477,28 @@ class ScatterNdTest(test.TestCase): with self.cached_session(): self.assertAllEqual(expected_result, self.evaluate(scatter)) + @test_util.run_deprecated_v1 def testUndefinedIndicesShape(self): indices = array_ops.placeholder(dtypes.int32, shape=None) updates = array_ops.placeholder(dtypes.int32, shape=[2, 2, 2]) shape = constant_op.constant([2, 2, 2], dtypes.int32) self.scatter_nd(indices, updates, shape) + @test_util.run_deprecated_v1 def testUndefinedUpdatesShape(self): indices = array_ops.placeholder(dtypes.int32, shape=[2, 2, 2]) updates = array_ops.placeholder(dtypes.int32, shape=None) shape = constant_op.constant([2, 2, 2], dtypes.int32) self.scatter_nd(indices, updates, shape) + @test_util.run_deprecated_v1 def testUndefinedOutputShape(self): indices = array_ops.placeholder(dtypes.int32, shape=[2, 2, 2]) updates = array_ops.placeholder(dtypes.int32, shape=[2, 2, 2]) shape = array_ops.placeholder(dtypes.int32, shape=[None]) self.scatter_nd(indices, updates, shape) + @test_util.run_deprecated_v1 def testEmptyOutputShape1(self): indices = array_ops.zeros([2, 2, 2], dtypes.int32) updates = array_ops.zeros([2, 2, 2], dtypes.int32) @@ -492,6 +508,7 @@ class ScatterNdTest(test.TestCase): ValueError, "Indices and updates specified for empty output shape"): self.scatter_nd(indices, updates, shape) + @test_util.run_deprecated_v1 def testEmptyOutputShape2(self): indices = array_ops.placeholder(dtypes.int32, shape=None) updates = array_ops.placeholder(dtypes.int32, shape=None) @@ -505,6 +522,7 @@ class ScatterNdTest(test.TestCase): updates: np.zeros([2, 2, 2], dtype=np.int32) }) + @test_util.run_deprecated_v1 def testEmptyOutputShape3(self): indices = array_ops.zeros([0], dtypes.int32) updates = array_ops.zeros([0], dtypes.int32) @@ -514,6 +532,7 @@ class ScatterNdTest(test.TestCase): with self.cached_session(): self.assertEqual(scatter.eval().size, 0) + @test_util.run_deprecated_v1 def testRank3InvalidShape1(self): indices = array_ops.zeros([3, 2, 2], dtypes.int32) updates = array_ops.zeros([2, 2, 2], dtypes.int32) @@ -522,6 +541,7 @@ class ScatterNdTest(test.TestCase): ValueError, "The outer \\d+ dimensions of indices\\.shape="): self.scatter_nd(indices, updates, shape) + @test_util.run_deprecated_v1 def testRank3InvalidShape2(self): indices = array_ops.zeros([2, 2, 1], dtypes.int32) updates = array_ops.zeros([2, 2], dtypes.int32) @@ -530,6 +550,7 @@ class ScatterNdTest(test.TestCase): ValueError, "The inner \\d+ dimensions of (input|output)\\.shape="): self.scatter_nd(indices, updates, shape) + @test_util.run_deprecated_v1 def testGradientsRank2ElementUpdate(self): for dtype in GRADIENT_TESTS_DTYPES: indices = constant_op.constant([[0, 0], [1, 1]], dtype=dtypes.int32) @@ -549,6 +570,7 @@ class ScatterNdTest(test.TestCase): if self.non_aliasing_add_test: self.assertAllEqual(expected_input_grad, self.evaluate(input_grad)) + @test_util.run_deprecated_v1 def testGradientsRank2SliceUpdate(self): for dtype in GRADIENT_TESTS_DTYPES: indices = constant_op.constant([[1], [0]], dtype=dtypes.int32) @@ -569,6 +591,7 @@ class ScatterNdTest(test.TestCase): if self.non_aliasing_add_test: self.assertAllEqual(expected_input_grad, self.evaluate(input_grad)) + @test_util.run_deprecated_v1 def testGradientsRank3SliceUpdate(self): for dtype in GRADIENT_TESTS_DTYPES: indices = constant_op.constant([[[0, 1], [1, 0]], [[0, 0], [1, 1]]], @@ -592,6 +615,7 @@ class ScatterNdTest(test.TestCase): if self.non_aliasing_add_test: self.assertAllEqual(expected_input_grad, self.evaluate(input_grad)) + @test_util.run_deprecated_v1 def testGradientsRank7SliceUpdate(self): for dtype in GRADIENT_TESTS_DTYPES: indices = constant_op.constant( @@ -619,6 +643,7 @@ class ScatterNdTest(test.TestCase): if self.non_aliasing_add_test: self.assertAllEqual(expected_input_grad, self.evaluate(input_grad)) + @test_util.run_deprecated_v1 def testScatterNdRepatedIndicesAdd(self): indices = array_ops.zeros([100000, 1], dtypes.int32) values = np.random.randn(100000) @@ -627,6 +652,7 @@ class ScatterNdTest(test.TestCase): val = self.scatter_nd(indices, values, shape).eval() self.assertAllClose([np.sum(values)], val) + @test_util.run_deprecated_v1 def testSmokeScatterNdBatch2DSliceDim2(self): with self.cached_session(): indices = array_ops.zeros([3, 5, 2], dtype=dtypes.int32) @@ -634,6 +660,7 @@ class ScatterNdTest(test.TestCase): shape = [4, 6, 7] self.scatter_nd(indices, values, shape).eval() + @test_util.run_deprecated_v1 def testSmokeScatterNdBatch1DSliceDim2(self): with self.cached_session(): indices = array_ops.zeros([0, 2], dtype=dtypes.int32) @@ -641,6 +668,7 @@ class ScatterNdTest(test.TestCase): shape = [4, 6, 7] self.scatter_nd(indices, values, shape).eval() + @test_util.run_deprecated_v1 def testSmokeScatterNdBatch1DSliceDim3ShapeRank7(self): with self.cached_session(): indices = array_ops.zeros([1, 3], dtype=dtypes.int32) @@ -648,6 +676,7 @@ class ScatterNdTest(test.TestCase): shape = [3, 4, 5, 6, 7, 8, 9] self.scatter_nd(indices, values, shape).eval() + @test_util.run_deprecated_v1 def testSmokeScatterNdBatch2DSliceDim3ShapeRank7(self): with self.cached_session(): indices = array_ops.zeros([1, 2, 3], dtype=dtypes.int32) diff --git a/tensorflow/python/kernel_tests/scatter_ops_test.py b/tensorflow/python/kernel_tests/scatter_ops_test.py index a4daad7adc..623c17d373 100644 --- a/tensorflow/python/kernel_tests/scatter_ops_test.py +++ b/tensorflow/python/kernel_tests/scatter_ops_test.py @@ -197,84 +197,111 @@ class ScatterTest(test.TestCase): self._VariableRankTest(tf_scatter, vtype, itype, repeat_indices, updates_are_scalar) + @test_util.run_deprecated_v1 def testVariableRankUpdate(self): self._VariableRankTests(state_ops.scatter_update, False) + @test_util.run_deprecated_v1 def testVariableRankAdd(self): self._VariableRankTests(state_ops.scatter_add, False) + @test_util.run_deprecated_v1 def testVariableRankSub(self): self._VariableRankTests(state_ops.scatter_sub, False) + @test_util.run_deprecated_v1 def testVariableRankMul(self): self._VariableRankTests(state_ops.scatter_mul, False) + @test_util.run_deprecated_v1 def testVariableRankDiv(self): self._VariableRankTests(state_ops.scatter_div, False) + @test_util.run_deprecated_v1 def testVariableRankMin(self): self._VariableRankTests(state_ops.scatter_min, False) + @test_util.run_deprecated_v1 def testVariableRankMax(self): self._VariableRankTests(state_ops.scatter_max, False) + @test_util.run_deprecated_v1 def testRepeatIndicesAdd(self): self._VariableRankTests(state_ops.scatter_add, True) + @test_util.run_deprecated_v1 def testRepeatIndicesSub(self): self._VariableRankTests(state_ops.scatter_sub, True) + @test_util.run_deprecated_v1 def testRepeatIndicesMul(self): self._VariableRankTests(state_ops.scatter_mul, True) + @test_util.run_deprecated_v1 def testRepeatIndicesDiv(self): self._VariableRankTests(state_ops.scatter_div, True) + @test_util.run_deprecated_v1 def testRepeatIndicesMin(self): self._VariableRankTests(state_ops.scatter_min, True) + @test_util.run_deprecated_v1 def testRepeatIndicesMax(self): self._VariableRankTests(state_ops.scatter_max, True) + @test_util.run_deprecated_v1 def testVariableRankUpdateScalar(self): self._VariableRankTests(state_ops.scatter_update, False, True) + @test_util.run_deprecated_v1 def testVariableRankAddScalar(self): self._VariableRankTests(state_ops.scatter_add, False, True) + @test_util.run_deprecated_v1 def testVariableRankSubScalar(self): self._VariableRankTests(state_ops.scatter_sub, False, True) + @test_util.run_deprecated_v1 def testVariableRankMulScalar(self): self._VariableRankTests(state_ops.scatter_mul, False, True) + @test_util.run_deprecated_v1 def testVariableRankDivScalar(self): self._VariableRankTests(state_ops.scatter_div, False, True) + @test_util.run_deprecated_v1 def testVariableRankMinScalar(self): self._VariableRankTests(state_ops.scatter_min, False, True) + @test_util.run_deprecated_v1 def testVariableRankMaxScalar(self): self._VariableRankTests(state_ops.scatter_max, False, True) + @test_util.run_deprecated_v1 def testRepeatIndicesAddScalar(self): self._VariableRankTests(state_ops.scatter_add, True, True) + @test_util.run_deprecated_v1 def testRepeatIndicesSubScalar(self): self._VariableRankTests(state_ops.scatter_sub, True, True) + @test_util.run_deprecated_v1 def testRepeatIndicesMulScalar(self): self._VariableRankTests(state_ops.scatter_mul, True, True) + @test_util.run_deprecated_v1 def testRepeatIndicesDivScalar(self): self._VariableRankTests(state_ops.scatter_div, True, True) + @test_util.run_deprecated_v1 def testRepeatIndicesMinScalar(self): self._VariableRankTests(state_ops.scatter_min, True, True) + @test_util.run_deprecated_v1 def testRepeatIndicesMaxScalar(self): self._VariableRankTests(state_ops.scatter_max, True, True) + @test_util.run_deprecated_v1 def testBooleanScatterUpdate(self): if not test.is_gpu_available(): with self.session(use_gpu=False) as session: @@ -289,6 +316,7 @@ class ScatterTest(test.TestCase): self.assertAllEqual([False, True], self.evaluate(var)) + @test_util.run_deprecated_v1 def testScatterOutOfRangeCpu(self): for op, _ in _TF_OPS_TO_NUMPY.items(): params = np.array([1, 2, 3, 4, 5, 6]).astype(np.float32) diff --git a/tensorflow/python/kernel_tests/segment_reduction_ops_test.py b/tensorflow/python/kernel_tests/segment_reduction_ops_test.py index 5ab889895e..8af1b47e83 100644 --- a/tensorflow/python/kernel_tests/segment_reduction_ops_test.py +++ b/tensorflow/python/kernel_tests/segment_reduction_ops_test.py @@ -26,6 +26,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables @@ -126,6 +127,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): # and may therefore vary dynamically. self.assertAllEqual(np_ans.shape[1:], tf_ans.shape[1:]) + @test_util.run_deprecated_v1 def testSegmentIdsShape(self): shape = [4, 4] tf_x, _ = self._input(shape) @@ -133,6 +135,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): with self.assertRaises(ValueError): math_ops.segment_sum(data=tf_x, segment_ids=indices) + @test_util.run_deprecated_v1 def testSegmentIdsSize(self): shape = [4, 4] for use_gpu in [True, False]: @@ -143,6 +146,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): with self.assertRaisesOpError("segment_ids should be the same size"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentIdsValid(self): # This is a baseline for the following SegmentIdsInvalid* tests. shape = [4, 4] @@ -175,6 +179,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): tf_ans = self.evaluate(s) self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testSegmentIdsInvalid1(self): shape = [4, 4] with self.cached_session(): @@ -186,6 +191,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): "'segment_ids' input is not sorted."): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentIdsInvalid2(self): shape = [4, 4] with self.cached_session(): @@ -195,6 +201,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): with self.assertRaisesOpError("segment ids are not increasing"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentIdsInvalid3(self): shape = [4, 4] with self.cached_session(): @@ -206,6 +213,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): "because 'segment_ids' input is not sorted."): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentIdsInvalid4(self): shape = [4, 4] for use_gpu in [True, False]: @@ -216,6 +224,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): with self.assertRaisesOpError("segment ids must be >= 0"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentIdsInvalid5(self): shape = [4, 4] for use_gpu in [True, False]: @@ -226,6 +235,7 @@ class SegmentReductionOpTest(SegmentReductionHelper): with self.assertRaisesOpError("segment ids must be >= 0"): self.evaluate(s) + @test_util.run_deprecated_v1 def testGradient(self): shape = [4, 4] indices = [0, 1, 2, 2] @@ -324,6 +334,7 @@ class UnsortedSegmentTest(SegmentReductionHelper): self.assertAllClose(np_ans, tf_ans) self.assertShapeEqual(np_ans, s) + @test_util.run_deprecated_v1 def testGradients(self): num_cols = 2 indices_flat = np.array([0, 4, 0, -1, 3, -1, 4, 7, 7, 3]) @@ -346,6 +357,7 @@ class UnsortedSegmentTest(SegmentReductionHelper): delta=1) self.assertAllClose(jacob_t, jacob_n) + @test_util.run_deprecated_v1 def testProdGrad(self): # additional test for the prod gradient to ensure correct handling of zeros values = np.array([0, 0, 1, 0, 2, 2, 3, 3, 3], dtype=np.float32) @@ -370,6 +382,7 @@ class UnsortedSegmentTest(SegmentReductionHelper): self.assertAllClose(jacob_t, jacob_n) self.assertAllClose(jacob_t, grad_gt) + @test_util.run_deprecated_v1 def testGradientMatchesSegmentSum(self): # Strategy: compute the gradient for UnsortedSegmentSum and SegmentSum # and compare the outputs, which should be identical. @@ -403,6 +416,7 @@ class UnsortedSegmentTest(SegmentReductionHelper): self.assertAllClose(unsorted_jacob_t, sorted_jacob_t) self.assertAllClose(unsorted_jacob_n, sorted_jacob_n) + @test_util.run_deprecated_v1 def testBadIndices(self): # Note: GPU kernel does not return the out-of-range error needed for this # test, so this test is marked as cpu-only. @@ -414,6 +428,7 @@ class UnsortedSegmentTest(SegmentReductionHelper): r"segment_ids\[0,0\] = %d is out of range \[0, 2\)" % bad[0][0]): self.evaluate(unsorted) + @test_util.run_deprecated_v1 def testEmptySecondDimension(self): dtypes = [np.float16, np.float32, np.float64, np.int64, np.int32, np.complex64, np.complex128] @@ -590,6 +605,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): s = tf_op(data=tf_x, indices=tf_indices, segment_ids=segment_indices) self.evaluate(s) + @test_util.run_deprecated_v1 def testIndicesInvalid1(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -602,6 +618,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): r"indices\[1\] == -1 out of range \[0, 10\)"): self.evaluate(s) + @test_util.run_deprecated_v1 def testIndicesInvalid2(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -614,6 +631,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): r"indices\[3\] == 10 out of range \[0, 10\)"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentsInvalid2(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -625,6 +643,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError("segment ids are not increasing"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentsInvalid3(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -638,6 +657,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): "'segment_ids' input is not sorted"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentsInvalid4(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -651,6 +671,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): "'segment_ids' input is not sorted"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentsInvalid6(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -662,6 +683,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError("segment ids must be >= 0"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentsInvalid7(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [math_ops.sparse_segment_sum, math_ops.sparse_segment_mean] @@ -692,6 +714,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): num_segments=num_segments) self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentWithNumSegmentsInvalid1(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [ @@ -711,6 +734,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError("segment ids must be < num_segments"): self.evaluate(s) + @test_util.run_deprecated_v1 def testSegmentWithNumSegmentsInvalid2(self): tf_x, _ = self._input([10, 4], dtype=dtypes_lib.float32) ops_list = [ @@ -730,6 +754,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): segment_ids=segment_indices, num_segments=num_segments) + @test_util.run_deprecated_v1 def testGradient(self): shape = [10, 4] @@ -748,6 +773,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): delta=1) self.assertAllClose(jacob_t, jacob_n) + @test_util.run_deprecated_v1 def testGradientWithEmptySegmentsAtEnd(self): shape = [10, 4] @@ -787,6 +813,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): s = tf_op(tf_x, tf_indices, segment_indices, 10) self.evaluate(s) + @test_util.run_deprecated_v1 def testGradientIndicesInvalid1(self): tf_x, _ = self._input([3, 4], dtype=dtypes_lib.float32) ops_list = [ @@ -800,6 +827,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError(r"Index 10 out of range \[0, 10\)"): self.evaluate(s) + @test_util.run_deprecated_v1 def testGradientIndicesInvalid2(self): tf_x, _ = self._input([3, 4], dtype=dtypes_lib.float32) ops_list = [ @@ -813,6 +841,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError(r"Index -1 out of range \[0, 10\)"): self.evaluate(s) + @test_util.run_deprecated_v1 def testGradientSegmentsInvalid1(self): tf_x, _ = self._input( [3, 4], dtype=dtypes_lib.float32) # expecting 3 segments @@ -827,6 +856,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError("Invalid number of segments"): self.evaluate(s) + @test_util.run_deprecated_v1 def testGradientSegmentsInvalid2(self): tf_x, _ = self._input([1, 4], dtype=dtypes_lib.float32) ops_list = [ @@ -840,6 +870,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError(r"Segment id 1 out of range \[0, 1\)"): self.evaluate(s) + @test_util.run_deprecated_v1 def testGradientSegmentsInvalid3(self): tf_x, _ = self._input([2, 4], dtype=dtypes_lib.float32) ops_list = [ @@ -853,6 +884,7 @@ class SparseSegmentReductionOpTest(SparseSegmentReductionHelper): with self.assertRaisesOpError(r"Segment id -1 out of range \[0, 2\)"): self.evaluate(s) + @test_util.run_deprecated_v1 def testGradientSegmentsInvalid4(self): tf_x, _ = self._input([0, 4], dtype=dtypes_lib.float32) ops_list = [ diff --git a/tensorflow/python/kernel_tests/sets_test.py b/tensorflow/python/kernel_tests/sets_test.py index ba3d32b192..b4f2322934 100644 --- a/tensorflow/python/kernel_tests/sets_test.py +++ b/tensorflow/python/kernel_tests/sets_test.py @@ -70,6 +70,7 @@ def _dense_to_sparse(dense, dtype): class SetOpsTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def test_set_size_2d(self): for dtype in _DTYPES: self._test_set_size_2d(dtype) @@ -83,6 +84,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual( [0, 3], self._set_size(_dense_to_sparse([[], [1, 9, 2]], dtype))) + @test_util.run_deprecated_v1 def test_set_size_duplicates_2d(self): for dtype in _DTYPES: self._test_set_size_duplicates_2d(dtype) @@ -96,6 +98,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): 6, 7, 8, 8, 6, 7, 5, 3, 3, 0, 6, 6, 9, 0, 0, 0 ], [999, 1, -1000], [], [-1]], dtype))) + @test_util.run_deprecated_v1 def test_set_size_3d(self): for dtype in _DTYPES: self._test_set_size_3d(dtype) @@ -163,6 +166,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(results[0], results[1]) return results[0] + @test_util.run_deprecated_v1 def test_set_intersection_multirow_2d(self): for dtype in _DTYPES: self._test_set_intersection_multirow_2d(dtype) @@ -199,6 +203,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(expected_counts, self._set_intersection_count(sp_a, sp_b)) + @test_util.run_deprecated_v1 def test_dense_set_intersection_multirow_2d(self): for dtype in _DTYPES: self._test_dense_set_intersection_multirow_2d(dtype) @@ -223,6 +228,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): dtype=dtype) self.assertAllEqual(expected_counts, self._set_intersection_count(a, b)) + @test_util.run_deprecated_v1 def test_set_intersection_duplicates_2d(self): for dtype in _DTYPES: self._test_set_intersection_duplicates_2d(dtype) @@ -270,6 +276,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(expected_counts, self._set_intersection_count(sp_a, sp_b)) + @test_util.run_deprecated_v1 def test_set_intersection_3d(self): for dtype in _DTYPES: self._test_set_intersection_3d(dtype=dtype) @@ -536,6 +543,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): with self.cached_session() as sess: return self.evaluate(op) + @test_util.run_deprecated_v1 def test_set_difference_multirow_2d(self): for dtype in _DTYPES: self._test_set_difference_multirow_2d(dtype) @@ -604,6 +612,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(expected_counts, self._set_difference_count(sp_a, sp_b, False)) + @test_util.run_deprecated_v1 def test_dense_set_difference_multirow_2d(self): for dtype in _DTYPES: self._test_dense_set_difference_multirow_2d(dtype) @@ -647,6 +656,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(expected_counts, self._set_difference_count(a, b, False)) + @test_util.run_deprecated_v1 def test_sparse_set_difference_multirow_2d(self): for dtype in _DTYPES: self._test_sparse_set_difference_multirow_2d(dtype) @@ -688,6 +698,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(expected_counts, self._set_difference_count(sp_a, sp_b, False)) + @test_util.run_deprecated_v1 def test_set_difference_duplicates_2d(self): for dtype in _DTYPES: self._test_set_difference_duplicates_2d(dtype) @@ -755,6 +766,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertAllEqual(expected_counts, self._set_difference_count(a, sp_b, False)) + @test_util.run_deprecated_v1 def test_sparse_set_difference_3d(self): for dtype in _DTYPES: self._test_sparse_set_difference_3d(dtype) @@ -974,6 +986,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): with self.cached_session() as sess: return self.evaluate(op) + @test_util.run_deprecated_v1 def test_set_union_multirow_2d(self): for dtype in _DTYPES: self._test_set_union_multirow_2d(dtype) @@ -1001,6 +1014,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): expected_indices, expected_values, expected_shape, union, dtype=dtype) self.assertAllEqual(expected_counts, self._set_union_count(sp_a, sp_b)) + @test_util.run_deprecated_v1 def test_dense_set_union_multirow_2d(self): for dtype in _DTYPES: self._test_dense_set_union_multirow_2d(dtype) @@ -1021,6 +1035,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): expected_indices, expected_values, expected_shape, union, dtype=dtype) self.assertAllEqual(expected_counts, self._set_union_count(a, b)) + @test_util.run_deprecated_v1 def test_set_union_duplicates_2d(self): for dtype in _DTYPES: self._test_set_union_duplicates_2d(dtype) @@ -1047,6 +1062,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): expected_indices, expected_values, expected_shape, union, dtype=dtype) self.assertAllEqual([2], self._set_union_count(sp_a, sp_b)) + @test_util.run_deprecated_v1 def test_sparse_set_union_3d(self): for dtype in _DTYPES: self._test_sparse_set_union_3d(dtype) diff --git a/tensorflow/python/kernel_tests/shape_ops_test.py b/tensorflow/python/kernel_tests/shape_ops_test.py index a0506fbfc5..c8e7c143ad 100644 --- a/tensorflow/python/kernel_tests/shape_ops_test.py +++ b/tensorflow/python/kernel_tests/shape_ops_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import importer from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl @@ -227,6 +228,7 @@ class ShapeOpsTest(test.TestCase): self._compareExpandDimsAll(choice([2, 3, 5]), -3) self._compareExpandDimsAll(choice([2, 3, 5]), -4) + @test_util.run_deprecated_v1 def testExpandDimsErrors(self): with self.cached_session(): self.assertRaises(ValueError, array_ops.expand_dims, @@ -238,6 +240,7 @@ class ShapeOpsTest(test.TestCase): self.assertRaises(ValueError, array_ops.expand_dims, [False, True, True], 4) + @test_util.run_deprecated_v1 def testExpandDimsGradient(self): with self.cached_session(): inp = constant_op.constant( @@ -248,6 +251,7 @@ class ShapeOpsTest(test.TestCase): [4, 1, 2]) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testExpandDimsScalar(self): with self.cached_session(): inp = constant_op.constant(7) @@ -353,6 +357,7 @@ class ShapeOpsTest(test.TestCase): tf_ans = self.evaluate(tensor) self.assertEqual(np.shape(1), tf_ans.shape) + @test_util.run_deprecated_v1 def testSqueezeOnlyOnes(self): for use_gpu in [False, True]: with self.cached_session(use_gpu=use_gpu): @@ -362,6 +367,7 @@ class ShapeOpsTest(test.TestCase): self._compareSqueezeAll(input_1x1x3, [1]) self.assertRaises(ValueError, array_ops.squeeze, input_1x1x3, [2]) + @test_util.run_deprecated_v1 def testSqueezeErrors(self): for use_gpu in [False, True]: with self.cached_session(use_gpu=use_gpu): @@ -374,6 +380,7 @@ class ShapeOpsTest(test.TestCase): self.assertRaises(ValueError, array_ops.squeeze, np.zeros([1, 2, 1]), [2, 3]) + @test_util.run_deprecated_v1 def testSqueezeGradient(self): with self.cached_session(): inp = np.random.rand(4, 2).astype("f") @@ -384,6 +391,7 @@ class ShapeOpsTest(test.TestCase): [4, 2]) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testSqueezeGradientWithSqueezeDims(self): with self.cached_session(): inp = np.random.rand(4, 2).astype("f") @@ -394,6 +402,7 @@ class ShapeOpsTest(test.TestCase): [4, 2, 1]) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testSqueezeWithUnknownShape(self): with self.cached_session(): a = array_ops.placeholder(dtypes.float32, shape=[2, None]) @@ -451,6 +460,7 @@ class TileTest(test.TestCase): self.assertEqual(result.shape, (10, 0)) self.assertEqual([10, 0], tiled.get_shape()) + @test_util.run_deprecated_v1 def testUnknownInputShape(self): """Importing can call _TileShape without shape of known.""" with self.cached_session(): @@ -502,6 +512,7 @@ class TileTest(test.TestCase): self.assertEqual([4, 4], tiled.get_shape()) self.assertAllEqual(result, np.tile(inp, (1, 4))) + @test_util.run_deprecated_v1 def testInvalidDim(self): with self.cached_session(): inp = np.random.rand(4, 1).astype("f") @@ -545,6 +556,7 @@ class TileTest(test.TestCase): for _ in range(5): self._RunAndVerifyResult(10, use_gpu=True) + @test_util.run_deprecated_v1 def testGradientSimpleReduction(self): with self.cached_session(): inp = np.random.rand(4, 1).astype("f") @@ -560,6 +572,7 @@ class TileTest(test.TestCase): result = self.evaluate(grad) self.assertAllClose(np.sum(grad_inp, axis=1).reshape(4, 1), result, 1e-3) + @test_util.run_deprecated_v1 def testGradientStridedReduction(self): with self.cached_session(): inp = np.random.rand(4, 2).astype("f") @@ -579,6 +592,7 @@ class TileTest(test.TestCase): expected[:, 1] = grad_inp[:, 1] + grad_inp[:, 3] self.assertTrue((np.abs(expected - result) < 1e-3).all()) + @test_util.run_deprecated_v1 def testGradientSimpleReductionOnGPU(self): with self.session(use_gpu=True): inp = np.random.rand(4, 1).astype("f") @@ -593,6 +607,7 @@ class TileTest(test.TestCase): result = self.evaluate(grad) self.assertAllClose(np.sum(grad_inp, axis=1).reshape(4, 1), result, 1e-3) + @test_util.run_deprecated_v1 def testGradientStridedReductionOnGPU(self): with self.session(use_gpu=True): inp = np.random.rand(4, 2).astype("f") @@ -624,15 +639,18 @@ class TileTest(test.TestCase): print("tile(float) error = ", err) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testGradientRandomScalar(self): self._RunAndVerifyGradientResult([], []) + @test_util.run_deprecated_v1 def testGradientRandom(self): self._RunAndVerifyGradientResult([2, 2, 1, 1, 3], [1, 1, 1, 1, 1]) self._RunAndVerifyGradientResult([2, 2, 1, 1, 3], [1, 2, 1, 3, 1]) self._RunAndVerifyGradientResult([2, 3, 1, 1, 3], [3, 1, 1, 2, 2]) self._RunAndVerifyGradientResult([2, 1, 3, 3, 2], [1, 3, 3, 1, 2]) + @test_util.run_deprecated_v1 def testGradientStridedReductionGC(self): with self.cached_session(): inp = np.random.rand(4, 2).astype("f") @@ -642,6 +660,7 @@ class TileTest(test.TestCase): err = gradient_checker.compute_gradient_error(a, [4, 2], tiled, [4, 4]) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testGradientWithSparseGradWithRank1(self): inputs = constant_op.constant([1.0, 2.0, 3.0, 4.0], dtype=dtypes.float32) @@ -653,6 +672,7 @@ class TileTest(test.TestCase): outputs, outputs.get_shape().as_list()) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testGradientWithSparseGradWithRank3(self): inputs = constant_op.constant([1.0, 2.0, 3.0, 4.0], dtype=dtypes.float32) @@ -665,6 +685,7 @@ class TileTest(test.TestCase): outputs, outputs.get_shape().as_list()) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testShapeFunctionEdgeCases(self): # Unknown multiples shape. inp = constant_op.constant(0.0, shape=[4, 4, 4, 4]) diff --git a/tensorflow/python/kernel_tests/signal/dct_ops_test.py b/tensorflow/python/kernel_tests/signal/dct_ops_test.py index af4939332f..a3ac15bab8 100644 --- a/tensorflow/python/kernel_tests/signal/dct_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/dct_ops_test.py @@ -23,6 +23,7 @@ import importlib from absl.testing import parameterized import numpy as np +from tensorflow.python.framework import test_util from tensorflow.python.ops import spectral_ops_test_util from tensorflow.python.ops.signal import dct_ops from tensorflow.python.platform import test @@ -132,6 +133,7 @@ class DCTOpsTest(parameterized.TestCase, test.TestCase): @parameterized.parameters([ [[2]], [[3]], [[10]], [[2, 20]], [[2, 3, 25]]]) + @test_util.run_deprecated_v1 def test_random(self, shape): """Test randomly generated batches of data.""" with spectral_ops_test_util.fft_kernel_label_map(): diff --git a/tensorflow/python/kernel_tests/signal/fft_ops_test.py b/tensorflow/python/kernel_tests/signal/fft_ops_test.py index 3eeecc12a8..5b1053428c 100644 --- a/tensorflow/python/kernel_tests/signal/fft_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/fft_ops_test.py @@ -25,6 +25,7 @@ from tensorflow.core.protobuf import config_pb2 from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_spectral_ops from tensorflow.python.ops import gradient_checker @@ -157,6 +158,7 @@ class FFTOpsTest(BaseFFTOpsTest): else: raise ValueError("invalid rank") + @test_util.run_deprecated_v1 def testEmpty(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type in (np.complex64, np.complex128): @@ -166,6 +168,7 @@ class FFTOpsTest(BaseFFTOpsTest): self.assertEqual(x.shape, self._tfFFT(x, rank).shape) self.assertEqual(x.shape, self._tfIFFT(x, rank).shape) + @test_util.run_deprecated_v1 def testBasic(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type, tol in ((np.complex64, 1e-4), (np.complex128, 1e-8)): @@ -194,6 +197,7 @@ class FFTOpsTest(BaseFFTOpsTest): # np.mod(np.arange(np.power(128, dims)), 64).reshape( # (128,) * dims).astype(np.complex64), rank) + @test_util.run_deprecated_v1 def testBasicPlaceholder(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type, tol in ((np.complex64, 1e-4), (np.complex128, 1e-8)): @@ -204,6 +208,7 @@ class FFTOpsTest(BaseFFTOpsTest): (4,) * dims).astype(np_type), rank, use_placeholder=True, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testRandom(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type, tol in ((np.complex64, 1e-4), (np.complex128, 5e-6)): @@ -218,6 +223,7 @@ class FFTOpsTest(BaseFFTOpsTest): self._compare(gen((4,) * dims).astype(np_type), rank, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testRandom1D(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type in (np.complex64, np.complex128): @@ -240,6 +246,7 @@ class FFTOpsTest(BaseFFTOpsTest): for dim in (127, 255, 511, 1023): self._compare(gen((dim,)).astype(np_type), 1, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testError(self): for rank in VALID_FFT_RANKS: for dims in xrange(0, rank): @@ -251,6 +258,7 @@ class FFTOpsTest(BaseFFTOpsTest): ValueError, "Shape must be .*rank {}.*".format(rank)): self._tfIFFT(x, rank) + @test_util.run_deprecated_v1 def testGrad_Simple(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type, tol in ((np.float32, 1e-4), (np.float64, 1e-10)): @@ -263,6 +271,7 @@ class FFTOpsTest(BaseFFTOpsTest): self._checkGradComplex(self._tfIFFTForRank(rank), re, im, rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testGrad_Random(self): with spectral_ops_test_util.fft_kernel_label_map(): for np_type, tol in ((np.float32, 1e-2), (np.float64, 1e-10)): @@ -330,6 +339,7 @@ class RFFTOpsTest(BaseFFTOpsTest): else: raise ValueError("invalid rank") + @test_util.run_deprecated_v1 def testEmpty(self): with spectral_ops_test_util.fft_kernel_label_map(): for rank in VALID_FFT_RANKS: @@ -339,6 +349,7 @@ class RFFTOpsTest(BaseFFTOpsTest): x = np.zeros((0,) * dims).astype(np.complex64) self.assertEqual(x.shape, self._tfIFFT(x, rank).shape) + @test_util.run_deprecated_v1 def testBasic(self): with spectral_ops_test_util.fft_kernel_label_map(): for rank in VALID_FFT_RANKS: @@ -366,6 +377,7 @@ class RFFTOpsTest(BaseFFTOpsTest): 10).reshape((size,) * (dims - 1) + (inner_dim,)) self._compareBackward(c2r.astype(np.complex64), rank, (size,) * rank) + @test_util.run_deprecated_v1 def testBasicPlaceholder(self): with spectral_ops_test_util.fft_kernel_label_map(): for rank in VALID_FFT_RANKS: @@ -427,6 +439,7 @@ class RFFTOpsTest(BaseFFTOpsTest): fft_length, use_placeholder=True) + @test_util.run_deprecated_v1 def testRandom(self): with spectral_ops_test_util.fft_kernel_label_map(): def gen_real(shape): @@ -451,6 +464,7 @@ class RFFTOpsTest(BaseFFTOpsTest): self._compareBackward( gen_complex(complex_dims), rank, (size,) * rank) + @test_util.run_deprecated_v1 def testError(self): with spectral_ops_test_util.fft_kernel_label_map(): for rank in VALID_FFT_RANKS: @@ -507,6 +521,7 @@ class RFFTOpsTest(BaseFFTOpsTest): with self.cached_session(): irfft_fn(x, fft_length).eval() + @test_util.run_deprecated_v1 def testGrad_Simple(self): with spectral_ops_test_util.fft_kernel_label_map(): for rank in VALID_FFT_RANKS: @@ -521,6 +536,7 @@ class RFFTOpsTest(BaseFFTOpsTest): self._checkGradComplex( self._tfIFFTForRank(rank), re, im, result_is_complex=False) + @test_util.run_deprecated_v1 def testGrad_Random(self): with spectral_ops_test_util.fft_kernel_label_map(): for rank in VALID_FFT_RANKS: diff --git a/tensorflow/python/kernel_tests/signal/mel_ops_test.py b/tensorflow/python/kernel_tests/signal/mel_ops_test.py index 2b3dde30f3..3134503dae 100644 --- a/tensorflow/python/kernel_tests/signal/mel_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/mel_ops_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.kernel_tests.signal import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops.signal import mel_ops @@ -143,12 +144,14 @@ class LinearToMelTest(test.TestCase): mel_matrix = mel_ops.linear_to_mel_weight_matrix(*config) self.assertAllClose(mel_matrix_np, self.evaluate(mel_matrix), atol=3e-6) + @tf_test_util.run_deprecated_v1 def test_dtypes(self): # LinSpace is not supported for tf.float16. for dtype in (dtypes.bfloat16, dtypes.float32, dtypes.float64): self.assertEqual(dtype, mel_ops.linear_to_mel_weight_matrix(dtype=dtype).dtype) + @tf_test_util.run_deprecated_v1 def test_error(self): with self.assertRaises(ValueError): mel_ops.linear_to_mel_weight_matrix(num_mel_bins=0) @@ -177,6 +180,7 @@ class LinearToMelTest(test.TestCase): rewritten_graph = test_util.grappler_optimize(g, [mel_matrix]) self.assertEqual(1, len(rewritten_graph.node)) + @tf_test_util.run_deprecated_v1 def test_num_spectrogram_bins_dynamic(self): with self.session(use_gpu=True): num_spectrogram_bins = array_ops.placeholder(shape=(), diff --git a/tensorflow/python/kernel_tests/signal/mfcc_ops_test.py b/tensorflow/python/kernel_tests/signal/mfcc_ops_test.py index 79d23d77d1..935922657c 100644 --- a/tensorflow/python/kernel_tests/signal/mfcc_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/mfcc_ops_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import spectral_ops_test_util @@ -32,6 +33,7 @@ from tensorflow.python.platform import test # HTK conventions. class MFCCTest(test.TestCase): + @test_util.run_deprecated_v1 def test_error(self): # num_mel_bins must be positive. with self.assertRaises(ValueError): @@ -43,6 +45,7 @@ class MFCCTest(test.TestCase): signal = array_ops.zeros((2, 3, 5), dtype=dtypes.float64) mfcc_ops.mfccs_from_log_mel_spectrograms(signal) + @test_util.run_deprecated_v1 def test_basic(self): """A basic test that the op runs on random input.""" with spectral_ops_test_util.fft_kernel_label_map(): @@ -50,6 +53,7 @@ class MFCCTest(test.TestCase): signal = random_ops.random_normal((2, 3, 5)) mfcc_ops.mfccs_from_log_mel_spectrograms(signal).eval() + @test_util.run_deprecated_v1 def test_unknown_shape(self): """A test that the op runs when shape and rank are unknown.""" with spectral_ops_test_util.fft_kernel_label_map(): diff --git a/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py b/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py index de3351e543..d9b45f67c3 100644 --- a/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops @@ -62,6 +63,7 @@ class ReconstructionOpsTest(test.TestCase): self.assertAllClose(output, expected_output) + @test_util.run_deprecated_v1 def test_simple(self): def make_input(frame_length, num_frames=3): """Generate a tensor of num_frames frames of frame_length.""" @@ -133,6 +135,7 @@ class ReconstructionOpsTest(test.TestCase): self.assertEqual(output.shape, (1, 9)) self.assertEqual(string_output, self.expected_string) + @test_util.run_deprecated_v1 def test_gradient(self): configurations = [ ((1, 128), 1), @@ -154,6 +157,7 @@ class ReconstructionOpsTest(test.TestCase): gradient = sess.run(gradients_impl.gradients([loss], [signal])[0]) self.assertTrue((gradient == 1.0).all()) + @test_util.run_deprecated_v1 def test_gradient_batch(self): with self.session(use_gpu=True) as sess: signal = array_ops.zeros((2, 10, 10)) @@ -176,6 +180,7 @@ class ReconstructionOpsTest(test.TestCase): np.reshape(np.arange(100).astype(np.float32), (10, 10))]) self.assertAllEqual(expected_gradient, gradient) + @test_util.run_deprecated_v1 def test_gradient_numerical(self): with self.session(use_gpu=True): shape = (2, 10, 10) diff --git a/tensorflow/python/kernel_tests/signal/shape_ops_test.py b/tensorflow/python/kernel_tests/signal/shape_ops_test.py index 21a6b23b30..32ac76e80d 100644 --- a/tensorflow/python/kernel_tests/signal/shape_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/shape_ops_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.kernel_tests.signal import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops @@ -32,6 +33,7 @@ from tensorflow.python.platform import test class FrameTest(test.TestCase): + @tf_test_util.run_deprecated_v1 def test_mapping_of_indices_without_padding(self): with self.session(use_gpu=True): tensor = constant_op.constant(np.arange(9152), dtypes.int32) @@ -47,6 +49,7 @@ class FrameTest(test.TestCase): self.assertAllEqual(expected, result) + @tf_test_util.run_deprecated_v1 def test_mapping_of_indices_with_padding(self): with self.session(use_gpu=True): tensor = constant_op.constant(np.arange(10000), dtypes.int32) @@ -64,6 +67,7 @@ class FrameTest(test.TestCase): self.assertAllEqual(expected, result) + @tf_test_util.run_deprecated_v1 def test_invalid_inputs(self): # Rank 0 input signal. with self.assertRaises(ValueError): @@ -84,6 +88,7 @@ class FrameTest(test.TestCase): with self.assertRaises(ValueError): shape_ops.frame([1], 1, 1, pad_end=True, pad_value=[1]) + @tf_test_util.run_deprecated_v1 def test_length_zero(self): signal = constant_op.constant([], dtype=dtypes.float32) frame_length = 2 @@ -98,6 +103,7 @@ class FrameTest(test.TestCase): pad_end=False).eval() self.assertEqual((0, 2), result.shape) + @tf_test_util.run_deprecated_v1 def test_shape_inference(self): signal = array_ops.placeholder(dtypes.int32, shape=[1, 1]) frame_length = 2 @@ -153,6 +159,7 @@ class FrameTest(test.TestCase): result = self.evaluate(op) self.assertEqual(op.shape.as_list(), list(result.shape)) + @tf_test_util.run_deprecated_v1 def test_basic_mono(self): signal = np.arange(6) frame_length = 3 @@ -178,6 +185,7 @@ class FrameTest(test.TestCase): pad_end=False).eval() self.assertAllEqual(expected, result) + @tf_test_util.run_deprecated_v1 def test_basic_stereo(self): signal = np.vstack([np.arange(6), np.arange(6) + 10]) @@ -207,6 +215,7 @@ class FrameTest(test.TestCase): pad_end=False).eval() self.assertAllEqual(expected, result) + @tf_test_util.run_deprecated_v1 def test_complex_shape(self): signal = np.vstack([np.arange(6), np.arange(6) + 10, @@ -274,6 +283,7 @@ class FrameTest(test.TestCase): [[14, 15], [0, 0], [0, 0]]]] self.assertAllEqual(expected, self.evaluate(result)) + @tf_test_util.run_deprecated_v1 def test_window_larger_than_signal(self): signal = constant_op.constant([[1, 2], [11, 12]], dtype=dtypes.float32) frame_length = 4 @@ -307,6 +317,7 @@ class FrameTest(test.TestCase): result = shape_ops.frame(signal, frame_length, frame_step) self.assertEqual(result.dtype, signal.dtype) + @tf_test_util.run_deprecated_v1 def test_dynamic_tensor(self): # Show that frame works even when the dimensions of its input are # not known at graph creation time. @@ -325,6 +336,7 @@ class FrameTest(test.TestCase): [[10, 11], [12, 13]], [[20, 21], [22, 23]]], result) + @tf_test_util.run_deprecated_v1 def test_gradient_numerical(self): with self.session(use_gpu=True): signal_shape = (2, 128) diff --git a/tensorflow/python/kernel_tests/signal/window_ops_test.py b/tensorflow/python/kernel_tests/signal/window_ops_test.py index 2f19134f5a..a72cdb288b 100644 --- a/tensorflow/python/kernel_tests/signal/window_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/window_ops_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.kernel_tests.signal import test_util from tensorflow.python.ops.signal import window_ops from tensorflow.python.platform import test @@ -75,6 +76,7 @@ class WindowOpsTest(test.TestCase): dtype=tf_dtype).eval() self.assertAllClose(expected, actual, tol, tol) + @tf_test_util.run_deprecated_v1 def test_hann_window(self): """Check that hann_window matches scipy.signal.hann behavior.""" # The Hann window is a raised cosine window with parameters alpha=0.5 and @@ -84,6 +86,7 @@ class WindowOpsTest(test.TestCase): functools.partial(_scipy_raised_cosine, a=0.5, b=0.5), window_ops.hann_window) + @tf_test_util.run_deprecated_v1 def test_hamming_window(self): """Check that hamming_window matches scipy.signal.hamming's behavior.""" # The Hamming window is a raised cosine window with parameters alpha=0.54 diff --git a/tensorflow/python/kernel_tests/slice_op_test.py b/tensorflow/python/kernel_tests/slice_op_test.py index ee48c6eb0e..8f7245214a 100644 --- a/tensorflow/python/kernel_tests/slice_op_test.py +++ b/tensorflow/python/kernel_tests/slice_op_test.py @@ -24,6 +24,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops @@ -145,6 +146,7 @@ class SliceTest(test.TestCase): slice_val = self.evaluate(slice_t) self.assertAllEqual(slice_val, inp[lo:hi]) + @test_util.run_deprecated_v1 def testScalarInput(self): input_val = 0 with self.cached_session() as sess: @@ -159,6 +161,7 @@ class SliceTest(test.TestCase): "out of range"): sess.run([slice_t], feed_dict={input_t: input_val}) + @test_util.run_deprecated_v1 def testInvalidIndex(self): input_val = [1, 2] with self.cached_session() as sess: @@ -179,6 +182,7 @@ class SliceTest(test.TestCase): np_ans = x[begin:begin + size, :] self.assertAllEqual(tf_ans, np_ans) + @test_util.run_deprecated_v1 def testSliceMatrixDim0(self): x = np.random.rand(8, 4).astype("f") self._testSliceMatrixDim0(x, 1, 2) @@ -213,6 +217,7 @@ class SliceTest(test.TestCase): self.assertEqual(slice_val.shape, slice_t.get_shape()) self.assertEqual(slice2_val.shape, slice2_t.get_shape()) + @test_util.run_deprecated_v1 def testComplex(self): with self.session(use_gpu=True): inp = np.random.rand(4, 10, 10, 4).astype("f") @@ -316,6 +321,7 @@ class SliceTest(test.TestCase): g1_val, g2_val = self.evaluate([g1, g2]) self.assertAllEqual(g1_val, g2_val) + @test_util.run_deprecated_v1 def testGradientsAll(self): # Slice the middle square out of a 4x4 input self._testGradientSlice([4, 4], [1, 1], [2, 2]) @@ -335,6 +341,7 @@ class SliceTest(test.TestCase): # Use -1 as a slice dimension on a 2D tensor. self._testGradientVariableSize2D() + @test_util.run_deprecated_v1 def testNotIterable(self): # NOTE(mrry): If we register __getitem__ as an overloaded # operator, Python will valiantly attempt to iterate over the @@ -346,6 +353,7 @@ class SliceTest(test.TestCase): for _ in c: pass + @test_util.run_deprecated_v1 def testComputedShape(self): # NOTE(mrry): We cannot currently handle partially-known values, # because `tf.slice()` uses -1 to specify a wildcard size, and diff --git a/tensorflow/python/kernel_tests/softmax_op_test.py b/tensorflow/python/kernel_tests/softmax_op_test.py index 8b1a2e4c4e..707b8a429f 100644 --- a/tensorflow/python/kernel_tests/softmax_op_test.py +++ b/tensorflow/python/kernel_tests/softmax_op_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import nn_ops from tensorflow.python.platform import test @@ -206,6 +207,7 @@ class SoftmaxTest(test.TestCase): [[5., 4., 3., 2.], [1., 2., 3., 4.]]]) self.assertEqual([3, 2, 4], op.get_shape()) + @test_util.run_deprecated_v1 def testEmptyInput(self): with self.cached_session(): x = array_ops.placeholder(dtypes.float32, shape=[0, 3]) @@ -229,6 +231,7 @@ class SoftmaxTest(test.TestCase): with self.assertRaises(errors_impl.InvalidArgumentError): nn_ops.softmax(ones, axis=2).eval() + @test_util.run_deprecated_v1 def testLargeDims(self): # Make sure that we properly handle large inputs. See # https://github.com/tensorflow/tensorflow/issues/4425 for details diff --git a/tensorflow/python/kernel_tests/softplus_op_test.py b/tensorflow/python/kernel_tests/softplus_op_test.py index 48445a7380..5273dd7ffc 100644 --- a/tensorflow/python/kernel_tests/softplus_op_test.py +++ b/tensorflow/python/kernel_tests/softplus_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import nn_ops @@ -70,6 +71,7 @@ class SoftplusTest(test.TestCase): ], use_gpu=True) + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session(): x = constant_op.constant( @@ -86,6 +88,7 @@ class SoftplusTest(test.TestCase): print("softplus (float) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testGradGrad(self): with self.cached_session(): x = constant_op.constant( @@ -103,6 +106,7 @@ class SoftplusTest(test.TestCase): print("softplus (float) gradient of gradient err = ", err) self.assertLess(err, 5e-5) + @test_util.run_deprecated_v1 def testGradGradGrad(self): with self.cached_session(): x = constant_op.constant( @@ -121,6 +125,7 @@ class SoftplusTest(test.TestCase): print("softplus (float) third-order gradient err = ", err) self.assertLess(err, 5e-5) + @test_util.run_deprecated_v1 def testNoInts(self): with self.cached_session(): with self.assertRaisesRegexp( diff --git a/tensorflow/python/kernel_tests/softsign_op_test.py b/tensorflow/python/kernel_tests/softsign_op_test.py index 71aac7e48e..5554240c82 100644 --- a/tensorflow/python/kernel_tests/softsign_op_test.py +++ b/tensorflow/python/kernel_tests/softsign_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import nn_ops import tensorflow.python.ops.nn_grad # pylint: disable=unused-import @@ -49,6 +50,7 @@ class SoftsignTest(test.TestCase): np.array([[-9, 7, -5, 3, -1], [1, -3, 5, -7, 9]]).astype(t), use_gpu=True) + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session(): x = constant_op.constant( @@ -65,6 +67,7 @@ class SoftsignTest(test.TestCase): print("softsign (float) gradient err = ", err) self.assertLess(err, 1e-4) + @test_util.run_deprecated_v1 def testNoInts(self): with self.cached_session(): with self.assertRaisesRegexp( diff --git a/tensorflow/python/kernel_tests/spacetobatch_op_test.py b/tensorflow/python/kernel_tests/spacetobatch_op_test.py index 21134adf2c..8641156604 100644 --- a/tensorflow/python/kernel_tests/spacetobatch_op_test.py +++ b/tensorflow/python/kernel_tests/spacetobatch_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import gradient_checker @@ -115,6 +116,7 @@ class SpaceToBatchTest(test.TestCase, PythonOpImpl): self._testPad(inputs, paddings, block_size, outputs) # [1, 2, 2, 1] <-> [4, 1, 1, 1] + @test_util.run_deprecated_v1 def testSmallInput2x2(self): x_np = [[[[1], [2]], [[3], [4]]]] block_size = 2 @@ -122,6 +124,7 @@ class SpaceToBatchTest(test.TestCase, PythonOpImpl): self._testOne(x_np, block_size, x_out) # [1, 2, 2, 1] <-> [1, 3, 3, 1] (padding) <-> [9, 1, 1, 1] + @test_util.run_deprecated_v1 def testSmallInput2x2Pad1x0(self): x_np = [[[[1], [2]], [[3], [4]]]] paddings = np.array([[1, 0], [1, 0]], dtype=np.int32) @@ -132,6 +135,7 @@ class SpaceToBatchTest(test.TestCase, PythonOpImpl): # Test with depth larger than 1. # [1, 2, 2, 3] <-> [4, 1, 1, 3] + @test_util.run_deprecated_v1 def testDepthInput2x2(self): x_np = [[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]] block_size = 2 @@ -140,6 +144,7 @@ class SpaceToBatchTest(test.TestCase, PythonOpImpl): # Test for larger input dimensions. # [1, 4, 4, 1] <-> [4, 2, 2, 1] + @test_util.run_deprecated_v1 def testLargerInput2x2(self): x_np = [[[[1], [2], [3], [4]], [[5], [6], [7], [8]], [[9], [10], [11], [12]], [[13], [14], [15], [16]]]] @@ -150,6 +155,7 @@ class SpaceToBatchTest(test.TestCase, PythonOpImpl): # Test with batch larger than 1. # [2, 2, 4, 1] <-> [8, 1, 2, 1] + @test_util.run_deprecated_v1 def testBatchInput2x2(self): x_np = [[[[1], [2], [3], [4]], [[5], [6], [7], [8]]], [[[9], [10], [11], [12]], [[13], [14], [15], [16]]]] @@ -162,6 +168,7 @@ class SpaceToBatchTest(test.TestCase, PythonOpImpl): # that elements are correctly laid out spatially and properly interleaved # along the batch dimension. # [2, 4, 4, 1] <-> [8, 2, 2, 1] + @test_util.run_deprecated_v1 def testLargerInputBatch2x2(self): x_np = [[[[1], [2], [3], [4]], [[5], [6], [7], [8]], [[9], [10], [11], [12]], [[13], [14], [15], [16]]], @@ -206,6 +213,7 @@ class SpaceToBatchNDTest(test.TestCase): self._testPad(inputs, block_shape, paddings, space_to_batch_direct(inputs, block_shape, paddings)) + @test_util.run_deprecated_v1 def testZeroBlockDimsZeroRemainingDims(self): self._testPad( inputs=[1, 2], @@ -213,6 +221,7 @@ class SpaceToBatchNDTest(test.TestCase): paddings=[], outputs=[1, 2],) + @test_util.run_deprecated_v1 def testZeroBlockDimsOneRemainingDim(self): self._testPad( inputs=[[1, 2], [3, 4]], @@ -227,6 +236,7 @@ class SpaceToBatchNDTest(test.TestCase): paddings=[[0, 0]], outputs=[[1, 2], [3, 4]]) + @test_util.run_deprecated_v1 def testZeroBlockDimsTwoRemainingDims(self): self._testPad( inputs=[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], @@ -248,6 +258,7 @@ class SpaceToBatchNDTest(test.TestCase): paddings=[[0, 0], [0, 0]], outputs=[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) + @test_util.run_deprecated_v1 def testOneBlockDimZeroRemainingDims(self): self._testPad( inputs=[[1, 2, 3], [4, 5, 6]], @@ -255,6 +266,7 @@ class SpaceToBatchNDTest(test.TestCase): paddings=[1, 0], outputs=[[0, 2], [0, 5], [1, 3], [4, 6]]) + @test_util.run_deprecated_v1 def testOneBlockDimOneRemainingDim(self): self._testPad( inputs=[[[1, 11], [2, 21], [3, 31]], [[4, 41], [5, 51], [6, 61]]], @@ -263,6 +275,7 @@ class SpaceToBatchNDTest(test.TestCase): outputs=[[[0, 0], [2, 21]], [[0, 0], [5, 51]], [[1, 11], [3, 31]], [[4, 41], [6, 61]]]) + @test_util.run_deprecated_v1 def testDirect(self): # Test with zero-size remaining dimension. self._testDirect( @@ -300,6 +313,7 @@ class SpaceToBatchNDTest(test.TestCase): class SpaceToBatchSpaceToDepth(test.TestCase, PythonOpImpl): # Verifies that: space_to_batch(x) = transpose(space_to_depth(transpose(x))) + @test_util.run_deprecated_v1 def testSpaceToDepthTranspose(self): x = np.arange(5 * 10 * 16 * 7, dtype=np.float32).reshape([5, 10, 16, 7]) block_size = 2 @@ -319,6 +333,7 @@ class SpaceToBatchSpaceToDepthCpp(SpaceToBatchSpaceToDepth, CppOpImpl): class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): + @test_util.run_deprecated_v1 def testInputWrongDimMissingBatch(self): # The input is missing the first dimension ("batch") x_np = [[[1], [2]], [[3], [4]]] @@ -327,6 +342,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): with self.assertRaises(ValueError): _ = self.space_to_batch(x_np, paddings, block_size) + @test_util.run_deprecated_v1 def testBlockSize0(self): # The block size is 0. x_np = [[[[1], [2]], [[3], [4]]]] @@ -336,6 +352,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): out_tf = self.space_to_batch(x_np, paddings, block_size) out_tf.eval() + @test_util.run_deprecated_v1 def testBlockSizeOne(self): # The block size is 1. The block size needs to be > 1. x_np = [[[[1], [2]], [[3], [4]]]] @@ -345,6 +362,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): out_tf = self.space_to_batch(x_np, paddings, block_size) out_tf.eval() + @test_util.run_deprecated_v1 def testBlockSizeLarger(self): # The block size is too large for this input. x_np = [[[[1], [2]], [[3], [4]]]] @@ -354,6 +372,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): out_tf = self.space_to_batch(x_np, paddings, block_size) out_tf.eval() + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleWidth(self): # The block size divides width but not height. x_np = [[[[1], [2], [3]], [[3], [4], [7]]]] @@ -362,6 +381,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): with self.assertRaises(ValueError): _ = self.space_to_batch(x_np, paddings, block_size) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleHeight(self): # The block size divides height but not width. x_np = [[[[1], [2]], [[3], [4]], [[5], [6]]]] @@ -370,6 +390,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): with self.assertRaises(ValueError): _ = self.space_to_batch(x_np, paddings, block_size) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleBoth(self): # The block size does not divide neither width or height. x_np = [[[[1], [2]], [[3], [4]]]] @@ -378,6 +399,7 @@ class SpaceToBatchErrorHandlingTest(test.TestCase, PythonOpImpl): with self.assertRaises(ValueError): _ = self.space_to_batch(x_np, paddings, block_size) + @test_util.run_deprecated_v1 def testUnknownShape(self): t = self.space_to_batch( array_ops.placeholder(dtypes.float32), @@ -424,25 +446,31 @@ class SpaceToBatchNDErrorHandlingTest(test.TestCase): self._testStaticShape(input_shape, block_shape, paddings, error) self._testDynamicShape(input_shape, block_shape, paddings) + @test_util.run_deprecated_v1 def testBlockSize0(self): # The block size is 0. self._testShape([1, 2, 2], [0, 2], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testBlockSizeNegative(self): self._testShape([1, 2, 2], [-1, 2], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testNegativePadding(self): # The padding is negative. self._testShape([1, 2, 2], [1, 1], [[0, -1], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisible(self): # The padded size is not divisible by the block size. self._testShape([1, 2, 3, 1], [3, 3], [[0, 0], [0, 0]], ValueError) + @test_util.run_deprecated_v1 def testBlockDimsMismatch(self): # Shape of block_shape does not match shape of paddings. self._testStaticShape([1, 3, 3, 1], [3, 3], [[0, 0]], ValueError) + @test_util.run_deprecated_v1 def testUnknown(self): # Verify that input shape and paddings shape can be unknown. _ = array_ops.space_to_batch_nd( @@ -522,18 +550,21 @@ class SpaceToBatchGradientTest(test.TestCase, PythonOpImpl): # Don't use very large numbers as dimensions here as the result is tensor # with cartesian product of the dimensions. + @test_util.run_deprecated_v1 def testSmall(self): block_size = 2 pad_beg = 0 pad_end = 0 self._compare(1, 2, 3, 5, block_size, pad_beg, pad_end) + @test_util.run_deprecated_v1 def testSmall2(self): block_size = 2 pad_beg = 0 pad_end = 0 self._compare(2, 4, 3, 2, block_size, pad_beg, pad_end) + @test_util.run_deprecated_v1 def testSmallPad1x1(self): block_size = 2 pad_beg = 1 @@ -572,15 +603,19 @@ class SpaceToBatchNDGradientTest(test.TestCase): # Don't use very large numbers as dimensions here as the result is tensor # with cartesian product of the dimensions. + @test_util.run_deprecated_v1 def testSmall(self): self._compare([1, 4, 6, 5], [2, 2], [[0, 0], [0, 0]]) + @test_util.run_deprecated_v1 def testSmall2(self): self._compare([2, 8, 6, 2], [2, 2], [[0, 0], [0, 0]]) + @test_util.run_deprecated_v1 def testSmallPad1(self): self._compare([2, 4, 6, 2], [2, 2], [[1, 1], [1, 1]]) + @test_util.run_deprecated_v1 def testSmallPadThreeBlockDims(self): self._compare([2, 2, 4, 3, 2], [2, 2, 2], [[1, 1], [1, 1], [1, 0]]) @@ -644,6 +679,7 @@ class RequiredSpaceToBatchPaddingsTest(test.TestCase): self.assertAllEqual(paddings_result, paddings_const) self.assertAllEqual(crops_result, crops_const) + @test_util.run_deprecated_v1 def testSimple(self): self._test( input_shape=np.zeros((0,), np.int32), diff --git a/tensorflow/python/kernel_tests/spacetodepth_op_test.py b/tensorflow/python/kernel_tests/spacetodepth_op_test.py index c9aaa68971..e96bc09f36 100644 --- a/tensorflow/python/kernel_tests/spacetodepth_op_test.py +++ b/tensorflow/python/kernel_tests/spacetodepth_op_test.py @@ -159,6 +159,7 @@ class SpaceToDepthTest(test.TestCase): # Error handling: + @test_util.run_deprecated_v1 def testInputWrongDimMissingDepth(self): # The input is missing the last dimension ("depth") x_np = [[[1, 2], [3, 4]]] @@ -167,6 +168,7 @@ class SpaceToDepthTest(test.TestCase): out_tf = array_ops.space_to_depth(x_np, block_size) self.evaluate(out_tf) + @test_util.run_deprecated_v1 def testInputWrongDimMissingBatch(self): # The input is missing the first dimension ("batch") x_np = [[[1], [2]], [[3], [4]]] @@ -174,6 +176,7 @@ class SpaceToDepthTest(test.TestCase): with self.assertRaises(ValueError): _ = array_ops.space_to_depth(x_np, block_size) + @test_util.run_deprecated_v1 def testBlockSize0(self): # The block size is 0. x_np = [[[[1], [2]], [[3], [4]]]] @@ -182,6 +185,7 @@ class SpaceToDepthTest(test.TestCase): out_tf = array_ops.space_to_depth(x_np, block_size) self.evaluate(out_tf) + @test_util.run_deprecated_v1 def testBlockSizeOne(self): # The block size is 1. The block size needs to be > 1. x_np = [[[[1], [2]], [[3], [4]]]] @@ -190,6 +194,7 @@ class SpaceToDepthTest(test.TestCase): out_tf = array_ops.space_to_depth(x_np, block_size) self.evaluate(out_tf) + @test_util.run_deprecated_v1 def testBlockSizeLarger(self): # The block size is too large for this input. x_np = [[[[1], [2]], [[3], [4]]]] @@ -198,6 +203,7 @@ class SpaceToDepthTest(test.TestCase): out_tf = array_ops.space_to_depth(x_np, block_size) self.evaluate(out_tf) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleWidth(self): # The block size divides width but not height. x_np = [[[[1], [2], [3]], [[3], [4], [7]]]] @@ -205,6 +211,7 @@ class SpaceToDepthTest(test.TestCase): with self.assertRaises(ValueError): _ = array_ops.space_to_depth(x_np, block_size) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleHeight(self): # The block size divides height but not width. x_np = [[[[1], [2]], [[3], [4]], [[5], [6]]]] @@ -212,6 +219,7 @@ class SpaceToDepthTest(test.TestCase): with self.assertRaises(ValueError): _ = array_ops.space_to_depth(x_np, block_size) + @test_util.run_deprecated_v1 def testBlockSizeNotDivisibleBoth(self): # The block size does not divide neither width or height. x_np = [[[[1], [2]], [[3], [4]]]] @@ -219,6 +227,7 @@ class SpaceToDepthTest(test.TestCase): with self.assertRaises(ValueError): _ = array_ops.space_to_depth(x_np, block_size) + @test_util.run_deprecated_v1 def testUnknownShape(self): t = array_ops.space_to_depth( array_ops.placeholder(dtypes.float32), block_size=4) @@ -334,11 +343,13 @@ class SpaceToDepthGradientTest(test.TestCase): # Don't use very large numbers as dimensions here as the result is tensor # with cartesian product of the dimensions. + @test_util.run_deprecated_v1 def testSmall(self): block_size = 2 self._compare(1, 2, 3, 5, block_size, "NHWC") self._compare(1, 2, 3, 5, block_size, "NCHW") + @test_util.run_deprecated_v1 def testSmall2(self): block_size = 2 self._compare(2, 4, 3, 2, block_size, "NHWC") diff --git a/tensorflow/python/kernel_tests/sparse_add_op_test.py b/tensorflow/python/kernel_tests/sparse_add_op_test.py index c61f863355..00eff54077 100644 --- a/tensorflow/python/kernel_tests/sparse_add_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_add_op_test.py @@ -140,6 +140,7 @@ class SparseAddTest(test.TestCase): self.assertAllClose(sum_out.values, [2, 6, -.2]) self.assertAllEqual(sum_out.dense_shape, [3, 3]) + @test_util.run_deprecated_v1 def testGradients(self): np.random.seed(1618) # Make it reproducible. with self.session(use_gpu=False): @@ -176,6 +177,7 @@ class SparseAddTest(test.TestCase): self.assertAllEqual(dense_np + rand_vals_np, s) self.assertTrue(s.dtype == dtype) + @test_util.run_deprecated_v1 def testSparseTensorDenseAddGradients(self): np.random.seed(1618) # Make it reproducible. n, m = np.random.randint(30, size=2) @@ -191,6 +193,7 @@ class SparseAddTest(test.TestCase): [(nnz,), (n, m)], s, (n, m)) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testInvalidSparseTensor(self): with test_util.force_cpu(): shape = [2, 2] diff --git a/tensorflow/python/kernel_tests/sparse_concat_op_test.py b/tensorflow/python/kernel_tests/sparse_concat_op_test.py index 368a533e56..04b6b9b8d2 100644 --- a/tensorflow/python/kernel_tests/sparse_concat_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_concat_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test @@ -253,6 +254,7 @@ class SparseConcatTest(test.TestCase): [b"a", b"b", b"e", b"c", b"d", b"f", b"g", b"h"]) self.assertAllEqual(concat_out.dense_shape, [3, 8]) + @test_util.run_deprecated_v1 def testMismatchedRank(self): with self.session(use_gpu=False): sp_a = self._SparseTensor_3x3() @@ -263,6 +265,7 @@ class SparseConcatTest(test.TestCase): with self.assertRaises(ValueError): sparse_ops.sparse_concat(concat_dim, [sp_a, sp_e]) + @test_util.run_deprecated_v1 def testMismatchedRankExpandNonconcatDim(self): with self.session(use_gpu=False): sp_a = self._SparseTensor_3x3() @@ -275,6 +278,7 @@ class SparseConcatTest(test.TestCase): sparse_ops.sparse_concat( concat_dim, [sp_a, sp_e], expand_nonconcat_dim=True) + @test_util.run_deprecated_v1 def testMismatchedShapes(self): with self.session(use_gpu=False) as sess: sp_a = self._SparseTensor_3x3() @@ -321,6 +325,7 @@ class SparseConcatTest(test.TestCase): [1, 1, 2, 1, 1, 1, 2, 3, 4, 2, 1, 0, 2]) self.assertAllEqual(sp_concat_dim1_out.dense_shape, [3, 13]) + @test_util.run_deprecated_v1 def testShapeInferenceUnknownShapes(self): with self.session(use_gpu=False): sp_inputs = [ diff --git a/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py b/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py index 66589fa315..275c86e534 100644 --- a/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py +++ b/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.platform import test @@ -98,12 +99,14 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): attr { key: 'reduction_type' value {s: 'MEAN'} } """, q.accumulator_ref.op.node_def) + @test_util.run_deprecated_v1 def testAccumulatorSizeEmpty(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( dtypes_lib.float32, name="Q") self.assertEqual(q.num_accumulated().eval(), 0) + @test_util.run_deprecated_v1 def testAccumulatorSetGlobalStep(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( @@ -111,6 +114,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): set_global_step_op = q.set_global_step(1) set_global_step_op.run() + @test_util.run_deprecated_v1 def testAccumulatorApplyGradFloat32(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( @@ -122,6 +126,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() self.assertEqual(q.num_accumulated().eval(), 1) + @test_util.run_deprecated_v1 def testDtypes(self): with self.cached_session() as sess: dtypes = [dtypes_lib.float16, dtypes_lib.float32, dtypes_lib.float64] @@ -144,6 +149,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): self._assertEqual_nparray(sum_elems / len(elems), result, sess) + @test_util.run_deprecated_v1 def testAccumulatorMultipleAccumulators(self): with self.cached_session() as sess: q_f32_0 = data_flow_ops.SparseConditionalAccumulator( @@ -174,6 +180,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): result = sess.run(accums[i].take_indexed_slices_grad(1)) self._assertEqual_indexedslices(expected_tensors[i], result) + @test_util.run_deprecated_v1 def testAccumulatorTakeGradMean(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -194,6 +201,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): self.assertAllEqual([[0.5, 0.5], [0, 2], [3, 0]], val.values) self.assertAllEqual([-1, 2], val.dense_shape) + @test_util.run_deprecated_v1 def testAccumulatorTakeGradSum(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -214,11 +222,13 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): self.assertAllEqual([[1, 1], [0, 2], [3, 0]], val.values) self.assertAllEqual([-1, 2], val.dense_shape) + @test_util.run_deprecated_v1 def testAccumulatorTakeGradInvalidReductionType(self): with self.assertRaises(ValueError): data_flow_ops.SparseConditionalAccumulator( dtypes_lib.float32, name="Q", shape=(), reduction_type="Invalid") + @test_util.run_deprecated_v1 def testAccumulatorRepeatedTakeGrad(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -257,6 +267,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): self.assertAllEqual(val.values, [[5, 5], [0, 20], [30, 0]]) self.assertAllEqual(val.dense_shape, [-1, 2]) + @test_util.run_deprecated_v1 def testParallelApplyGradMean(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -288,6 +299,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): np.array([[expected_val, 0], [0, expected_val]]).astype(np.float32), val, sess) + @test_util.run_deprecated_v1 def testParallelApplyGradSum(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -322,6 +334,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): np.array([[expected_val, 0], [0, expected_val]]).astype(np.float32), val, sess) + @test_util.run_deprecated_v1 def testParallelTakeGrad(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -361,6 +374,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): self._assertEqual_nparray( np.array([[0, 0], [elems[i], 0]]), results[i], sess) + @test_util.run_deprecated_v1 def testAccumulatorApplyAndBlockingTake(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -396,6 +410,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): with self.assertRaisesOpError("was cancelled"): self.evaluate(takeg_op) + @test_util.run_deprecated_v1 def testAccumulatorCancel(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -415,6 +430,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): takeg_thread.join() + @test_util.run_deprecated_v1 def testNonVectorIndices(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( @@ -427,6 +443,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): grad_indices=[[0, 1], [1, 0]], grad_values=np.array([1, 2]).astype(np.float32)).run() + @test_util.run_deprecated_v1 def testZeroDimensionValues(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( @@ -437,6 +454,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): q.apply_grad( grad_indices=[0], grad_values=np.array(1).astype(np.float32)).run() + @test_util.run_deprecated_v1 def testWrongNonEmptyInputValues(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( @@ -448,6 +466,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): grad_indices=[0, 1], grad_values=np.array([[0, 1, 1]]).astype(np.float32)).run() + @test_util.run_deprecated_v1 def testDynamicNonVectorIndices(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -467,6 +486,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): x_values: np.array([1, 2]).astype(np.float32) }) + @test_util.run_deprecated_v1 def testDynamicWrongNonEmptyInputValues(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -485,6 +505,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): x_values: np.array([[0, 1, 1]]).astype(np.float32) }) + @test_util.run_deprecated_v1 def testEmptyShapeApply(self): with self.cached_session(): q = data_flow_ops.SparseConditionalAccumulator( @@ -510,6 +531,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): q.apply_grad(grad_indices=[0], grad_values=[1.0], grad_shape=[]).run() q.apply_grad(grad_indices=[0], grad_values=[1.0]).run() + @test_util.run_deprecated_v1 def testValidateShape(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -605,6 +627,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]]).astype(np.float32), local_step=1).run() + @test_util.run_deprecated_v1 def testReturnShape(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( @@ -630,6 +653,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): val = self.evaluate(q.take_indexed_slices_grad(1)) self.assertAllEqual(val.dense_shape, [-1, 2, 2, 3]) + @test_util.run_deprecated_v1 def testApplyGradtInt32IndicesAndShape(self): with self.cached_session() as sess: q = data_flow_ops.SparseConditionalAccumulator( diff --git a/tensorflow/python/kernel_tests/sparse_cross_op_test.py b/tensorflow/python/kernel_tests/sparse_cross_op_test.py index 8451b96c56..566bbb56f0 100644 --- a/tensorflow/python/kernel_tests/sparse_cross_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_cross_op_test.py @@ -24,12 +24,14 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test class SparseCrossOpTest(test.TestCase): + @test_util.run_deprecated_v1 def test_simple(self): """Tests a simple scenario.""" op = sparse_ops.sparse_cross([ @@ -45,6 +47,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_dense(self): """Tests only dense inputs.""" op = sparse_ops.sparse_cross([ @@ -65,6 +68,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_integer_mixed_string_sparse(self): """Tests mixed type.""" op = sparse_ops.sparse_cross([ @@ -79,6 +83,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_integer_mixed_string_dense(self): """Tests mixed dense inputs.""" op = sparse_ops.sparse_cross([ @@ -97,6 +102,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_sparse_cross_dense(self): """Tests sparse and dense inputs.""" op = sparse_ops.sparse_cross([ @@ -114,6 +120,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_integer_sparse_input(self): """Tests mixed type sparse and dense inputs.""" op = sparse_ops.sparse_cross([ @@ -130,6 +137,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_permutation_3x3x3(self): """Tests 3x3x3 permutation.""" op = sparse_ops.sparse_cross([ @@ -172,6 +180,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_permutation_3x1x2(self): """Tests 3x1x2 permutation.""" op = sparse_ops.sparse_cross([ @@ -191,6 +200,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_large_batch(self): """Tests with large batch size to force multithreading.""" batch_size = 5000 @@ -224,6 +234,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_one_column_empty(self): """Tests when one column is empty. @@ -237,6 +248,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_empty(self.evaluate(op)) + @test_util.run_deprecated_v1 def test_some_columns_empty(self): """Tests when more than one columns are empty. @@ -256,6 +268,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_all_columns_empty(self): """Tests when all columns are empty. @@ -269,6 +282,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_empty(self.evaluate(op)) + @test_util.run_deprecated_v1 def test_hashed_zero_bucket_no_hash_key(self): op = sparse_ops.sparse_cross_hashed([ self._sparse_tensor([['batch1-FC1-F1']]), @@ -280,6 +294,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_hashed_zero_bucket(self): op = sparse_ops.sparse_cross_hashed( [ @@ -294,6 +309,7 @@ class SparseCrossOpTest(test.TestCase): self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) # TODO(sibyl-Aix6ihai): Add benchmark to compare Hashed vs Non-hashed. + @test_util.run_deprecated_v1 def test_hashed_no_hash_key(self): op = sparse_ops.sparse_cross_hashed( [ @@ -307,6 +323,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_hashed_output(self): op = sparse_ops.sparse_cross_hashed( [ @@ -321,6 +338,7 @@ class SparseCrossOpTest(test.TestCase): with self.cached_session() as sess: self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) + @test_util.run_deprecated_v1 def test_hashed__has_no_collision(self): """Tests that fingerprint concatenation has no collisions.""" # Although the last 10 bits of 359 and 1024+359 are identical. diff --git a/tensorflow/python/kernel_tests/sparse_matmul_op_test.py b/tensorflow/python/kernel_tests/sparse_matmul_op_test.py index 4de69a26e3..2e17a9c608 100644 --- a/tensorflow/python/kernel_tests/sparse_matmul_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_matmul_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -71,6 +72,7 @@ class SparseMatMulTest(test.TestCase): self.assertShapeEqual(np_ans, tf_ans) self.assertAllCloseAccordingToType(np_ans, out, rtol=1e-4, atol=1e-4) + @test_util.run_deprecated_v1 def testBasic(self): x = np.arange(0., 4.).reshape([4, 1]).astype(np.float32) y = np.arange(-1., 1.).reshape([1, 2]).astype(np.float32) @@ -78,6 +80,7 @@ class SparseMatMulTest(test.TestCase): for y_dtype in (dtypes.float32, dtypes.bfloat16): self._testCpuMatmul(x, y, x_dtype=x_dtype, y_dtype=y_dtype) + @test_util.run_deprecated_v1 def testZeroDim(self): x = np.ones((4, 0)).astype(np.float32) y = np.ones((0, 3)).astype(np.float32) @@ -85,6 +88,7 @@ class SparseMatMulTest(test.TestCase): for y_dtype in (dtypes.float32, dtypes.bfloat16): self._testCpuMatmul(x, y, x_dtype=x_dtype, y_dtype=y_dtype) + @test_util.run_deprecated_v1 def testEmpty(self): x = np.ones((0, 0)).astype(np.float32) y = np.ones((0, 0)).astype(np.float32) @@ -93,6 +97,7 @@ class SparseMatMulTest(test.TestCase): self._testCpuMatmul(x, y, x_dtype=x_dtype, y_dtype=y_dtype) # Tests setting one dimension to be a high value. + @test_util.run_deprecated_v1 def testLarge(self): r1 = np.random.randint(6000, 20000) r2 = np.random.randint(1, 10) @@ -105,6 +110,7 @@ class SparseMatMulTest(test.TestCase): self._testCpuMatmul(x, y, x_dtype=x_dtype, y_dtype=y_dtype) # Tests random sized matrices. + @test_util.run_deprecated_v1 def testRandom(self): for tr_a in [True, False]: for tr_b in [True, False]: @@ -159,6 +165,7 @@ class MatMulGradientTest(test.TestCase): delta=delta)) self.assertLessEqual(err, delta / 2.) + @test_util.run_deprecated_v1 def testGradientInput(self): for tr_a in [True, False]: for tr_b in [True, False]: diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index 605aaf3dd1..75f65e6251 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -71,6 +71,7 @@ class SparseToIndicatorTest(test_util.TensorFlowTestCase): constant_op.constant(val, dtype), constant_op.constant(shape, dtypes.int64)) + @test_util.run_deprecated_v1 def testInt32(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_5x6(dtypes.int32) @@ -83,6 +84,7 @@ class SparseToIndicatorTest(test_util.TensorFlowTestCase): self.assertAllEqual(output, expected_output) + @test_util.run_deprecated_v1 def testInt64(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_5x6(dtypes.int64) @@ -95,6 +97,7 @@ class SparseToIndicatorTest(test_util.TensorFlowTestCase): self.assertAllEqual(output, expected_output) + @test_util.run_deprecated_v1 def testHigherRank(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_2x3x4(dtypes.int64) @@ -296,6 +299,7 @@ class SparseRetainTest(test_util.TensorFlowTestCase): def _SparseTensor_5x6(self): return sparse_tensor.SparseTensor.from_value(self._SparseTensorValue_5x6()) + @test_util.run_deprecated_v1 def testBasic(self): with self.session(use_gpu=False) as sess: for sp_input in (self._SparseTensorValue_5x6(), self._SparseTensor_5x6()): @@ -353,12 +357,14 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): return sparse_tensor.SparseTensorValue(self._IND_2_5_6, self._VAL_2_5_6, self._SHP_2_5_6) + @test_util.run_deprecated_v1 def testStaticShapeInfoPreservedWhenNewShapeIsProvidedAndStatic(self): sp_input = self._SparseTensor_2x5x6() new_shape = np.array([3, 6, 7], dtype=np.int64) sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) self.assertAllEqual([3, 6, 7], sp_output.get_shape()) + @test_util.run_deprecated_v1 def testBasic(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensor_2x5x6() @@ -372,6 +378,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33]) self.assertAllEqual(output.dense_shape, [3, 6, 7]) + @test_util.run_deprecated_v1 def testInputUnavailableInGraphConstructionOk(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorValue_2x5x6() @@ -385,6 +392,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33]) self.assertAllEqual(output.dense_shape, [3, 6, 7]) + @test_util.run_deprecated_v1 def testFeedInputUnavailableInGraphConstructionOk(self): with self.session(use_gpu=False) as sess: sp_input = array_ops.sparse_placeholder(dtype=dtypes.int32) @@ -422,6 +430,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): self.assertAllEqual(output.values.shape, [0]) self.assertAllEqual(output.dense_shape, [0, 0, 0]) + @test_util.run_deprecated_v1 def testInvalidRank(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_2x5x6() @@ -430,6 +439,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): with self.assertRaises(ValueError): sparse_ops.sparse_reset_shape(sp_input, new_shape) + @test_util.run_deprecated_v1 def testInvalidRankNewShapeUnavailableInGraphConstruction(self): with self.session(use_gpu=False) as sess: new_shape = array_ops.placeholder(dtype=dtypes.int64) @@ -439,6 +449,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): with self.assertRaisesOpError("x == y did not hold element-wise"): sess.run(out, feed_dict={new_shape: np.array([3, 7], dtype=np.int64)}) + @test_util.run_deprecated_v1 def testInvalidDimensionSizeStatic(self): sp_input = self._SparseTensor_2x5x6() new_shape = np.array([3, 7, 5], dtype=np.int64) @@ -446,6 +457,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp(ValueError, "should have dimension sizes"): sparse_ops.sparse_reset_shape(sp_input, new_shape) + @test_util.run_deprecated_v1 def testInvalidDimensionSizeDynamic(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensor_2x5x6() @@ -455,6 +467,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): with self.assertRaisesOpError("x <= y did not hold element-wise"): sess.run(out, feed_dict={new_shape: [3, 7, 5]}) + @test_util.run_deprecated_v1 def testInvalidDimensionSizeInputUnavailableInGraphConstruction(self): sp_input = array_ops.sparse_placeholder(dtype=dtypes.int32) with self.session(use_gpu=False) as sess: @@ -496,6 +509,7 @@ class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase): constant_op.constant(val, dtypes.int32), constant_op.constant(shape, dtypes.int64)) + @test_util.run_deprecated_v1 def testFillNumber(self): with self.session(use_gpu=False) as sess: for sp_input in (self._SparseTensorValue_5x6(), self._SparseTensor_5x6()): @@ -513,6 +527,7 @@ class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase): self.assertAllEqual(empty_row_indicator_out, np.array([0, 0, 1, 0, 1]).astype(np.bool)) + @test_util.run_deprecated_v1 def testFillFloat(self): with self.session(use_gpu=False) as sess: values = constant_op.constant( @@ -547,6 +562,7 @@ class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase): self.assertGreater(default_value_grad_err, 0) self.assertLess(default_value_grad_err, 1e-8) + @test_util.run_deprecated_v1 def testFillString(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensor_String5x6() @@ -565,6 +581,7 @@ class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase): self.assertAllEqual(empty_row_indicator_out, np.array([0, 0, 1, 0, 1]).astype(np.bool)) + @test_util.run_deprecated_v1 def testNoEmptyRows(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensor_2x6() @@ -582,6 +599,7 @@ class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase): class SparseAddTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testValuesInVariable(self): indices = constant_op.constant([[1]], dtype=dtypes.int64) values = variables.Variable([1], trainable=False, dtype=dtypes.float32) @@ -657,6 +675,7 @@ class SparseReduceTest(test_util.TensorFlowTestCase): self._compare(sp_t, reduction_axes, ndims, True, False) self._compare(sp_t, reduction_axes, ndims, True, True) + @test_util.run_deprecated_v1 def testSimpleAndRandomInputs(self): if np.__version__ == "1.13.0": self.skipTest("numpy 1.13.0 bug") @@ -696,6 +715,7 @@ class SparseReduceTest(test_util.TensorFlowTestCase): with self.assertRaisesOpError("Invalid reduction dimension 2"): sparse_ops.sparse_reduce_max(sp_t, 2).eval() + @test_util.run_deprecated_v1 def testGradient(self): if np.__version__ == "1.13.0": self.skipTest("numpy 1.13.0 bug") @@ -778,6 +798,7 @@ class SparseMathOpsTest(test_util.TensorFlowTestCase): result_tensor.values).eval() self.assertAllEqual(result_np, res_densified) + @test_util.run_deprecated_v1 def testCwiseDivAndMul(self): np.random.seed(1618) sp_shapes = [(10, 10, 10), (5, 5), (1618,), (3, 3, 7)] @@ -801,6 +822,7 @@ class SparseMathOpsTest(test_util.TensorFlowTestCase): res = sp_t / dense_t # should invoke "__truediv__" self.assertEqual(res.values.eval().dtype, np.float64) + @test_util.run_deprecated_v1 def testCwiseAdd(self): with self.session(use_gpu=False): # Identity(2) + AllOnes(2,2). Should be equal to 2 * Identity(2). @@ -820,6 +842,7 @@ class SparseMathOpsTest(test_util.TensorFlowTestCase): sparse_ops.sparse_dense_cwise_add(sp_t, dense_t), np.identity(2) * 2, sp_t) + @test_util.run_deprecated_v1 def testGradients(self): np.random.seed(1618) sp_shapes = [(10, 10, 10), (5, 5), (1618,), (3, 3, 7)] @@ -853,6 +876,7 @@ class SparseMathOpsTest(test_util.TensorFlowTestCase): class SparseSoftmaxTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testEquivalentToDensified(self): np.random.seed(1618) n, m = np.random.choice(20, size=2) @@ -872,6 +896,7 @@ class SparseSoftmaxTest(test_util.TensorFlowTestCase): self.assertAllClose(dense_result.eval(), sp_result) + @test_util.run_deprecated_v1 def testHigherRanks(self): # For the first shape: # First batch: @@ -901,6 +926,7 @@ class SparseSoftmaxTest(test_util.TensorFlowTestCase): self.assertAllEqual(sp_t.indices.eval(), result.indices) self.assertAllEqual(shape, result.dense_shape) + @test_util.run_deprecated_v1 def testGradient(self): x_shape = [2, 5, 10] with self.cached_session(use_gpu=False): @@ -920,6 +946,7 @@ class SparseMinimumMaximumTest(test_util.TensorFlowTestCase): self.assertAllEqual(a.values, b.values) self.assertAllEqual(a.dense_shape, b.dense_shape) + @test_util.run_deprecated_v1 def testBasic(self): with self.cached_session(use_gpu=False): # 1-D, values at index 0. @@ -939,6 +966,7 @@ class SparseMinimumMaximumTest(test_util.TensorFlowTestCase): self._assertSparseTensorValueEqual(expected.eval(), max_tf) self._assertSparseTensorValueEqual(expected.eval(), min_tf) + @test_util.run_deprecated_v1 def testRandom(self): np.random.seed(1618) shapes = [(13,), (6, 8), (1, 7, 1)] @@ -980,6 +1008,7 @@ class SparseMinimumMaximumTest(test_util.TensorFlowTestCase): class SparseTransposeTest(test.TestCase): + @test_util.run_deprecated_v1 def testTranspose(self): if np.__version__ == "1.13.0": self.skipTest("numpy 1.13.0 bug") @@ -1002,16 +1031,19 @@ class SparseTransposeTest(test.TestCase): class SparsePlaceholderTest(test.TestCase): + @test_util.run_deprecated_v1 def testPlaceholder(self): foo = array_ops.sparse_placeholder(dtypes.float32, shape=(10, 47)) self.assertAllEqual([10, 47], foo.get_shape()) self.assertAllEqual([None, 2], foo.indices.get_shape().as_list()) + @test_util.run_deprecated_v1 def testPartialShapePlaceholder(self): foo = array_ops.sparse_placeholder(dtypes.float32, shape=(None, 47)) self.assertAllEqual([None, None], foo.get_shape().as_list()) self.assertAllEqual([None, 2], foo.indices.get_shape().as_list()) + @test_util.run_deprecated_v1 def testNoShapePlaceholder(self): foo = array_ops.sparse_placeholder(dtypes.float32, shape=None) self.assertAllEqual(None, foo.get_shape()) diff --git a/tensorflow/python/kernel_tests/sparse_reorder_op_test.py b/tensorflow/python/kernel_tests/sparse_reorder_op_test.py index bbf2f39202..93fcc6a18e 100644 --- a/tensorflow/python/kernel_tests/sparse_reorder_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_reorder_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import sparse_ops @@ -65,6 +66,7 @@ class SparseReorderTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) + @test_util.run_deprecated_v1 def testFeedAlreadyInOrder(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -89,6 +91,7 @@ class SparseReorderTest(test.TestCase): self.assertAllEqual(output_val.dense_shape, expected_output_val.dense_shape) + @test_util.run_deprecated_v1 def testFeedOutOfOrder(self): expected_output_val = self._SparseTensorValue_5x6(np.arange(6)) with self.session(use_gpu=False) as sess: @@ -103,6 +106,7 @@ class SparseReorderTest(test.TestCase): self.assertAllEqual(output_val.dense_shape, expected_output_val.dense_shape) + @test_util.run_deprecated_v1 def testGradients(self): with self.session(use_gpu=False): for _ in range(5): # To test various random permutations diff --git a/tensorflow/python/kernel_tests/sparse_reshape_op_test.py b/tensorflow/python/kernel_tests/sparse_reshape_op_test.py index 918af27091..9341228d57 100644 --- a/tensorflow/python/kernel_tests/sparse_reshape_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_reshape_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test @@ -64,12 +65,14 @@ class SparseReshapeTest(test.TestCase): sp_output = sparse_ops.sparse_reshape(sp_input, shape=(2, -1)) self.assertAllEqual((2, 3 * 4), sp_output.get_shape()) + @test_util.run_deprecated_v1 def testRaisesIfMoreThanOneInferredDim(self): sp_input = sparse_tensor.SparseTensor.from_value( self._SparseTensorValue_2x3x4()) with self.assertRaisesRegexp(ValueError, "At most one dimension can"): sparse_ops.sparse_reshape(sp_input, shape=(-1, 2, -1)) + @test_util.run_deprecated_v1 def testRaisesIfInferredShapeNotPossible(self): sp_input = sparse_tensor.SparseTensor.from_value( self._SparseTensorValue_2x3x4()) @@ -86,6 +89,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) + @test_util.run_deprecated_v1 def testFeedSameShape(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -97,6 +101,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) + @test_util.run_deprecated_v1 def testWorksWellWithTfShape(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -109,6 +114,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) + @test_util.run_deprecated_v1 def testFeedSameShapeWithInferredDim(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -120,6 +126,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) + @test_util.run_deprecated_v1 def testFeedNewShapeSameRank(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -133,6 +140,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, [3, 10]) + @test_util.run_deprecated_v1 def testFeedNewShapeSameRankWithInferredDim(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -158,6 +166,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, [2, 3, 5]) + @test_util.run_deprecated_v1 def testFeedUpRank(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -171,6 +180,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, [2, 3, 5]) + @test_util.run_deprecated_v1 def testFeedUpRankWithInferredDim(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -184,6 +194,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, [2, 3, 5]) + @test_util.run_deprecated_v1 def testFeedDownRank(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -197,6 +208,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, [6, 4]) + @test_util.run_deprecated_v1 def testFeedDownRankWithInferredDim(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -210,6 +222,7 @@ class SparseReshapeTest(test.TestCase): self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, [6, 4]) + @test_util.run_deprecated_v1 def testFeedMultipleInferredDims(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -218,12 +231,14 @@ class SparseReshapeTest(test.TestCase): with self.assertRaisesOpError("only one output dimension may be -1"): sess.run(sp_output, {sp_input: input_val}) + @test_util.run_deprecated_v1 def testProvideStaticallyMismatchedSizes(self): input_val = self._SparseTensorValue_5x6() sp_input = sparse_tensor.SparseTensor.from_value(input_val) with self.assertRaisesRegexp(ValueError, "Cannot reshape"): sparse_ops.sparse_reshape(sp_input, [4, 7]) + @test_util.run_deprecated_v1 def testFeedMismatchedSizes(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -233,6 +248,7 @@ class SparseReshapeTest(test.TestCase): "Input to reshape is a tensor with 30 dense values"): sess.run(sp_output, {sp_input: input_val}) + @test_util.run_deprecated_v1 def testFeedMismatchedSizesWithInferredDim(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -241,6 +257,7 @@ class SparseReshapeTest(test.TestCase): with self.assertRaisesOpError("requested shape requires a multiple"): sess.run(sp_output, {sp_input: input_val}) + @test_util.run_deprecated_v1 def testFeedPartialShapes(self): with self.session(use_gpu=False): # Incorporate new rank into shape information if known @@ -266,6 +283,7 @@ class SparseReshapeTest(test.TestCase): self.assertListEqual(sp_output.indices.get_shape().as_list(), [5, None]) self.assertListEqual(sp_output.dense_shape.get_shape().as_list(), [None]) + @test_util.run_deprecated_v1 def testFeedDenseReshapeSemantics(self): with self.session(use_gpu=False) as sess: # Compute a random rank-5 initial shape and new shape, randomly sparsify diff --git a/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py b/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py index 39a9ab9b49..5a48eb825d 100644 --- a/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor as sparse_tensor_lib +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test @@ -110,14 +111,17 @@ class SerializeSparseTest(test.TestCase): self.assertAllEqual(combined_values[6:], sp_input[1]) self.assertAllEqual(combined_shape, [2, 5, 6]) + @test_util.run_deprecated_v1 def testSerializeDeserializeBatch(self): self._testSerializeDeserializeBatchHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testSerializeDeserializeManyBatch(self): self._testSerializeDeserializeBatchHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_many_sparse) + @test_util.run_deprecated_v1 def testVariantSerializeDeserializeBatch(self): self._testSerializeDeserializeBatchHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse, @@ -145,10 +149,12 @@ class SerializeSparseTest(test.TestCase): self.assertAllEqual(combined_values[6:], sp_input1[1]) self.assertAllEqual(combined_shape, [2, 5, 6]) + @test_util.run_deprecated_v1 def testSerializeDeserializeBatchInconsistentShape(self): self._testSerializeDeserializeBatchInconsistentShapeHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testVariantSerializeDeserializeBatchInconsistentShape(self): self._testSerializeDeserializeBatchInconsistentShapeHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse, @@ -188,10 +194,12 @@ class SerializeSparseTest(test.TestCase): self.assertAllEqual(combined_shape, [2, 2, 5, 6]) + @test_util.run_deprecated_v1 def testSerializeDeserializeNestedBatch(self): self._testSerializeDeserializeNestedBatchHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testVariantSerializeDeserializeNestedBatch(self): self._testSerializeDeserializeNestedBatchHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse, @@ -224,14 +232,17 @@ class SerializeSparseTest(test.TestCase): self.assertAllEqual(combined_values[6:], input1_val[1]) self.assertAllEqual(combined_shape, [2, 5, 6]) + @test_util.run_deprecated_v1 def testFeedSerializeDeserializeBatch(self): self._testFeedSerializeDeserializeBatchHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testFeedSerializeDeserializeManyBatch(self): self._testFeedSerializeDeserializeBatchHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_many_sparse) + @test_util.run_deprecated_v1 def testFeedVariantSerializeDeserializeBatch(self): self._testFeedSerializeDeserializeBatchHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse, @@ -256,6 +267,7 @@ class SerializeSparseTest(test.TestCase): }) self.assertEqual(serialized_value.shape, (4, 3)) + @test_util.run_deprecated_v1 def testSerializeManyShape(self): self._testSerializeManyShapeHelper(sparse_ops.serialize_many_sparse) @@ -287,19 +299,23 @@ class SerializeSparseTest(test.TestCase): self.assertAllEqual(deserialized_value.values, values_value) self.assertAllEqual(deserialized_value.dense_shape, shape_value) + @test_util.run_deprecated_v1 def testSerializeManyDeserializeBatch(self): self._testSerializeManyDeserializeBatchHelper( sparse_ops.serialize_many_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testSerializeManyDeserializeManyBatch(self): self._testSerializeManyDeserializeBatchHelper( sparse_ops.serialize_many_sparse, sparse_ops.deserialize_many_sparse) + @test_util.run_deprecated_v1 def testVariantSerializeManyDeserializeBatch(self): self._testSerializeManyDeserializeBatchHelper( sparse_ops.serialize_many_sparse, sparse_ops.deserialize_sparse, dtypes.variant) + @test_util.run_deprecated_v1 def testVariantSerializeDeserializeScalar(self): with self.session(use_gpu=False) as sess: indices_value = np.array([[]], dtype=np.int64) @@ -321,6 +337,7 @@ class SerializeSparseTest(test.TestCase): self.assertAllEqual(deserialized_value.values, values_value) self.assertAllEqual(deserialized_value.dense_shape, shape_value) + @test_util.run_deprecated_v1 def testVariantSerializeDeserializeScalarBatch(self): with self.session(use_gpu=False) as sess: indices_value = np.array([[]], dtype=np.int64) @@ -367,14 +384,17 @@ class SerializeSparseTest(test.TestCase): {sp_input0: input0_val, sp_input1: input1_val}) + @test_util.run_deprecated_v1 def testDeserializeFailsWrongType(self): self._testDeserializeFailsWrongTypeHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testDeserializeManyFailsWrongType(self): self._testDeserializeFailsWrongTypeHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_many_sparse) + @test_util.run_deprecated_v1 def testVariantDeserializeFailsWrongType(self): self._testDeserializeFailsWrongTypeHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse, @@ -402,14 +422,17 @@ class SerializeSparseTest(test.TestCase): {sp_input0: input0_val, sp_input1: input1_val}) + @test_util.run_deprecated_v1 def testDeserializeFailsInconsistentRank(self): self._testDeserializeFailsInconsistentRankHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testDeserializeManyFailsInconsistentRank(self): self._testDeserializeFailsInconsistentRankHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_many_sparse) + @test_util.run_deprecated_v1 def testVariantDeserializeFailsInconsistentRank(self): self._testDeserializeFailsInconsistentRankHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse, @@ -431,10 +454,12 @@ class SerializeSparseTest(test.TestCase): with self.assertRaisesOpError(r"Could not parse serialized proto"): sess.run(sp_deserialized, {sp_input0: input0_val}) + @test_util.run_deprecated_v1 def testDeserializeFailsInvalidProto(self): self._testDeserializeFailsInvalidProtoHelper(sparse_ops.serialize_sparse, sparse_ops.deserialize_sparse) + @test_util.run_deprecated_v1 def testDeserializeManyFailsInvalidProto(self): self._testDeserializeFailsInvalidProtoHelper( sparse_ops.serialize_sparse, sparse_ops.deserialize_many_sparse) diff --git a/tensorflow/python/kernel_tests/sparse_slice_op_test.py b/tensorflow/python/kernel_tests/sparse_slice_op_test.py index 098353741f..7f8c91bde6 100644 --- a/tensorflow/python/kernel_tests/sparse_slice_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_slice_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import sparse_ops import tensorflow.python.ops.sparse_grad # pylint: disable=unused-import @@ -79,6 +80,7 @@ class SparseSliceOpTest(test.TestCase): return sparse_tensor.SparseTensor.from_value( self._SparseTensorValue_3x4x2()) + @test_util.run_deprecated_v1 def testSliceMatrixRows(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_4x6() @@ -96,6 +98,7 @@ class SparseSliceOpTest(test.TestCase): [20, 23, 25, 30, 32, 33, 35]) self.assertAllEqual(sp_tensor1.dense_shape.eval(), [2, 6]) + @test_util.run_deprecated_v1 def testSliceMatrixUnevenCols(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_5x7() @@ -137,6 +140,7 @@ class SparseSliceOpTest(test.TestCase): self.assertAllEqual(sp_tensor3.values.eval(), [16, 46]) self.assertAllEqual(sp_tensor3.dense_shape.eval(), [5, 1]) + @test_util.run_deprecated_v1 def testSliceMatrixUnevenRows(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_5x7() @@ -173,6 +177,7 @@ class SparseSliceOpTest(test.TestCase): self.assertAllEqual(sp_tensor2.dense_shape.eval(), [1, 7]) return + @test_util.run_deprecated_v1 def testSliceAllRows(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_4x6() @@ -195,6 +200,7 @@ class SparseSliceOpTest(test.TestCase): self.assertAllEqual(sp_tensor3.values.eval(), [30, 32, 33, 35]) self.assertAllEqual(sp_tensor3.dense_shape.eval(), [1, 6]) + @test_util.run_deprecated_v1 def testSliceColumns(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_4x6() @@ -215,6 +221,7 @@ class SparseSliceOpTest(test.TestCase): self.assertAllEqual(sparse_tensor2.values.eval(), [4, 5, 14, 25, 35]) self.assertAllEqual(sparse_tensor2.dense_shape.eval(), [4, 2]) + @test_util.run_deprecated_v1 def testSliceAllColumns(self): with self.session(use_gpu=False): sp_input = self._SparseTensor_4x6() @@ -246,6 +253,7 @@ class SparseSliceOpTest(test.TestCase): self.assertAllEqual(sparse_tensor5.values.eval(), [5, 25, 35]) self.assertAllEqual(sparse_tensor5.dense_shape.eval(), [4, 1]) + @test_util.run_deprecated_v1 def testGradients(self): sp_input = self._SparseTensor_4x6(val_dtype=np.float32) start_and_size = [([0, 0], [4, 2]), diff --git a/tensorflow/python/kernel_tests/sparse_split_op_test.py b/tensorflow/python/kernel_tests/sparse_split_op_test.py index 95661ded4b..f4bb7498b0 100644 --- a/tensorflow/python/kernel_tests/sparse_split_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_split_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test @@ -75,6 +76,7 @@ class SparseSplitOpTest(test.TestCase): return sparse_tensor.SparseTensor.from_value(self._SparseTensorValue_3x4x2( )) + @test_util.run_deprecated_v1 def testSplitMatrixRows(self): with self.session(use_gpu=False): sp_tensors = sparse_ops.sparse_split( @@ -92,6 +94,7 @@ class SparseSplitOpTest(test.TestCase): [20, 23, 25, 30, 32, 33, 35]) self.assertAllEqual(sp_tensors[1].dense_shape.eval(), [2, 6]) + @test_util.run_deprecated_v1 def testSplitMatrixUnevenCols(self): with self.session(use_gpu=False): sp_tensors_3 = sparse_ops.sparse_split( @@ -131,6 +134,7 @@ class SparseSplitOpTest(test.TestCase): self.assertAllEqual(sp_tensors_4[3].values.eval(), [16, 46]) self.assertAllEqual(sp_tensors_4[3].dense_shape.eval(), [5, 1]) + @test_util.run_deprecated_v1 def testSplitMatrixUnevenRows(self): with self.session(use_gpu=False): sp_tensors_2 = sparse_ops.sparse_split( @@ -167,6 +171,7 @@ class SparseSplitOpTest(test.TestCase): self.assertAllEqual(sp_tensors_3[2].dense_shape.eval(), [1, 7]) return + @test_util.run_deprecated_v1 def testSplitAllRows(self): with self.session(use_gpu=False): sp_tensors = sparse_ops.sparse_split( @@ -189,6 +194,7 @@ class SparseSplitOpTest(test.TestCase): self.assertAllEqual(sp_tensors[3].values.eval(), [30, 32, 33, 35]) self.assertAllEqual(sp_tensors[3].dense_shape.eval(), [1, 6]) + @test_util.run_deprecated_v1 def testSplitColumns(self): with self.session(use_gpu=False): sparse_tensors = sparse_ops.sparse_split( @@ -207,6 +213,7 @@ class SparseSplitOpTest(test.TestCase): self.assertAllEqual(sparse_tensors[2].values.eval(), [4, 5, 14, 25, 35]) self.assertAllEqual(sparse_tensors[2].dense_shape.eval(), [4, 2]) + @test_util.run_deprecated_v1 def testSplitAllColumns(self): with self.session(use_gpu=False): sparse_tensors = sparse_ops.sparse_split( @@ -234,6 +241,7 @@ class SparseSplitOpTest(test.TestCase): self.assertAllEqual(sparse_tensors[5].values.eval(), [5, 25, 35]) self.assertAllEqual(sparse_tensors[5].dense_shape.eval(), [4, 1]) + @test_util.run_deprecated_v1 def testSliceConcat(self): for sp_input in (self._SparseTensorValue_3x4x2(), self._SparseTensor_3x4x2()): diff --git a/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_grad_test.py b/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_grad_test.py index b8f33d6a81..fa2bab1fca 100644 --- a/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_grad_test.py +++ b/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_grad_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import sparse_ops import tensorflow.python.ops.sparse_grad # pylint: disable=unused-import @@ -89,6 +90,7 @@ class SparseTensorDenseMatMulGradientTest(test.TestCase): self._testGradients(adjoint_a, adjoint_b, name, values_dtype, indices_dtype) + @test_util.run_deprecated_v1 def testGradients(self): np.random.seed(5) # Fix seed to avoid flakiness self._testGradientsType(np.float32, np.int64) diff --git a/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_op_test.py b/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_op_test.py index e605cb1c35..637cfaec99 100644 --- a/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_tensor_dense_matmul_op_test.py @@ -30,6 +30,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops @@ -96,6 +97,7 @@ class SparseTensorDenseMatMulTest(test.TestCase): self._testMatmul(x, y, indices_dtype=indices_dtype) + @test_util.run_deprecated_v1 def testBasic(self): np.random.seed(127) # Repeatable results self._testBasic(np.int32) @@ -106,6 +108,7 @@ class SparseTensorDenseMatMulTest(test.TestCase): self._testBasic(np.int32, indices_dtype=np.int32) self._testBasic(np.float32, indices_dtype=np.int32) + @test_util.run_deprecated_v1 def testShapeInference(self): x = np.random.rand(10, 10) x[np.abs(x) < 0.5] = 0 # Make it sparse @@ -229,6 +232,7 @@ class SparseTensorDenseMatMulTest(test.TestCase): self._testLarge(np.complex128) # Tests random sized matrices. + @test_util.run_deprecated_v1 def testFloatRandom(self): np.random.seed(127) # Repeatable results for _ in range(8): diff --git a/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py b/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py index 538e7c69b5..6039ff1afa 100644 --- a/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor as sparse_tensor_lib +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import sparse_ops from tensorflow.python.ops import variables @@ -76,6 +77,7 @@ class SparseTensorsMapTest(test.TestCase): shape = np.array([3, 4, 5]).astype(np.int64) return sparse_tensor_lib.SparseTensorValue(ind, val, shape) + @test_util.run_deprecated_v1 def testAddTakeMany(self): with self.session(graph=ops.Graph(), use_gpu=False) as sess: sp_input0 = self._SparseTensorValue_5x6(np.arange(6)) @@ -98,6 +100,7 @@ class SparseTensorsMapTest(test.TestCase): self.assertAllEqual(combined_values[6:], sp_input1[1]) self.assertAllEqual(combined_shape, [2, 5, 6]) + @test_util.run_deprecated_v1 def testFeedAddTakeMany(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -125,6 +128,7 @@ class SparseTensorsMapTest(test.TestCase): self.assertAllEqual(combined_values[6:], input1_val[1]) self.assertAllEqual(combined_shape, [2, 5, 6]) + @test_util.run_deprecated_v1 def testAddManyTakeManyRoundTrip(self): with self.session(use_gpu=False) as sess: # N == 4 because shape_value == [4, 5] @@ -147,6 +151,7 @@ class SparseTensorsMapTest(test.TestCase): self.assertAllEqual(roundtrip_value.values, values_value) self.assertAllEqual(roundtrip_value.dense_shape, shape_value) + @test_util.run_deprecated_v1 def testDeserializeFailsInconsistentRank(self): with self.session(use_gpu=False) as sess: sp_input = self._SparseTensorPlaceholder() @@ -168,6 +173,7 @@ class SparseTensorsMapTest(test.TestCase): r"SparseTensor\[1\] was: 3 but rank of SparseTensor\[1\] is: 4"): self.evaluate(sp_roundtrip) + @test_util.run_deprecated_v1 def testTakeManyFailsWrongInputOp(self): with self.session(use_gpu=False) as sess: input_val = self._SparseTensorValue_5x6(np.arange(6)) diff --git a/tensorflow/python/kernel_tests/sparse_to_dense_op_py_test.py b/tensorflow/python/kernel_tests/sparse_to_dense_op_py_test.py index fa6cb13432..c6c45db4f9 100644 --- a/tensorflow/python/kernel_tests/sparse_to_dense_op_py_test.py +++ b/tensorflow/python/kernel_tests/sparse_to_dense_op_py_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test @@ -41,36 +42,42 @@ def _SparseToDense(sparse_indices, class SparseToDenseTest(test.TestCase): + @test_util.run_deprecated_v1 def testInt(self): with self.session(use_gpu=False): tf_ans = _SparseToDense([1, 3], [5], 1, 0).eval() np_ans = np.array([0, 1, 0, 1, 0]).astype(np.int32) self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testFloat(self): with self.session(use_gpu=False): tf_ans = _SparseToDense([1, 3], [5], 1.0, 0.0).eval() np_ans = np.array([0, 1, 0, 1, 0]).astype(np.float32) self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testString(self): with self.session(use_gpu=False): tf_ans = _SparseToDense([1, 3], [5], "a", "b").eval() np_ans = np.array(["b", "a", "b", "a", "b"]).astype(np.string_) self.assertAllEqual(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testSetValue(self): with self.session(use_gpu=False): tf_ans = _SparseToDense([1, 3], [5], [1, 2], -1).eval() np_ans = np.array([-1, 1, -1, 2, -1]).astype(np.int32) self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testSetSingleValue(self): with self.session(use_gpu=False): tf_ans = _SparseToDense([1, 3], [5], 1, -1).eval() np_ans = np.array([-1, 1, -1, 1, -1]).astype(np.int32) self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def test2d(self): # pylint: disable=bad-whitespace with self.session(use_gpu=False): @@ -80,11 +87,13 @@ class SparseToDenseTest(test.TestCase): [ 1, -1, -1, -1]]).astype(np.int32) self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testZeroDefault(self): with self.cached_session(): x = sparse_ops.sparse_to_dense(2, [4], 7).eval() self.assertAllEqual(x, [0, 0, 7, 0]) + @test_util.run_deprecated_v1 def test3d(self): with self.session(use_gpu=False): tf_ans = _SparseToDense([[1, 3, 0], [2, 0, 1]], [3, 4, 2], 1, -1).eval() @@ -93,11 +102,13 @@ class SparseToDenseTest(test.TestCase): np_ans[2, 0, 1] = 1 self.assertAllClose(np_ans, tf_ans) + @test_util.run_deprecated_v1 def testBadShape(self): with self.cached_session(): with self.assertRaisesWithPredicateMatch(ValueError, "must be rank 1"): _SparseToDense([1, 3], [[5], [3]], 1, -1) + @test_util.run_deprecated_v1 def testBadValue(self): with self.cached_session(): dense = _SparseToDense([1, 3], [5], [[5], [3]], -1) @@ -106,6 +117,7 @@ class SparseToDenseTest(test.TestCase): r"should be \[\] or \[2\]"): self.evaluate(dense) + @test_util.run_deprecated_v1 def testBadNumValues(self): with self.cached_session(): dense = _SparseToDense([1, 3], [5], [1, 2, 3], -1) @@ -113,12 +125,14 @@ class SparseToDenseTest(test.TestCase): r"sparse_values has incorrect shape \[3\], should be \[\] or \[2\]"): self.evaluate(dense) + @test_util.run_deprecated_v1 def testBadDefault(self): with self.cached_session(): dense = _SparseToDense([1, 3], [5], [1, 2], [0]) with self.assertRaisesOpError("default_value should be a scalar"): self.evaluate(dense) + @test_util.run_deprecated_v1 def testOutOfBoundsIndicesWithWithoutValidation(self): with self.cached_session(): dense = _SparseToDense( @@ -139,6 +153,7 @@ class SparseToDenseTest(test.TestCase): validate_indices=False) self.evaluate(dense_without_validation) + @test_util.run_deprecated_v1 def testRepeatingIndicesWithWithoutValidation(self): with self.cached_session(): dense = _SparseToDense( @@ -157,6 +172,7 @@ class SparseToDenseTest(test.TestCase): validate_indices=False) self.evaluate(dense_without_validation) + @test_util.run_deprecated_v1 def testUnsortedIndicesWithWithoutValidation(self): with self.cached_session(): dense = _SparseToDense( @@ -175,6 +191,7 @@ class SparseToDenseTest(test.TestCase): validate_indices=False) self.evaluate(dense_without_validation) + @test_util.run_deprecated_v1 def testShapeInferenceKnownShape(self): with self.session(use_gpu=False): indices = array_ops.placeholder(dtypes.int64) @@ -187,6 +204,7 @@ class SparseToDenseTest(test.TestCase): output = sparse_ops.sparse_to_dense(indices, shape, 1, 0) self.assertEqual(output.get_shape().as_list(), [None, None, None]) + @test_util.run_deprecated_v1 def testShapeInferenceUnknownShape(self): with self.session(use_gpu=False): indices = array_ops.placeholder(dtypes.int64) diff --git a/tensorflow/python/kernel_tests/sparse_xent_op_test.py b/tensorflow/python/kernel_tests/sparse_xent_op_test.py index cc8c7c238f..8f0842f7f5 100644 --- a/tensorflow/python/kernel_tests/sparse_xent_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_xent_op_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops as ops_lib +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_nn_ops from tensorflow.python.ops import gradient_checker @@ -80,6 +81,7 @@ class SparseXentTest(test.TestCase): self.assertAllClose([0.0, 0.0, 0.0], tf_loss) self.assertAllClose([[0.0], [0.0], [0.0]], tf_backprop) + @test_util.run_deprecated_v1 def testInvalidLabel(self): features = [[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 2., 3., 4.], [1., 2., 3., 4.]] @@ -152,6 +154,7 @@ class SparseXentTest(test.TestCase): nn_ops.sparse_softmax_cross_entropy_with_logits( labels=constant_op.constant(0), logits=constant_op.constant(1.0)) + @test_util.run_deprecated_v1 def testLabelsPlaceholderScalar(self): with self.session(use_gpu=True): labels = array_ops.placeholder(np.int32) @@ -187,6 +190,7 @@ class SparseXentTest(test.TestCase): def testEmpty(self): self._testXent(np.zeros((0, 3)), np.zeros((0,), dtype=np.int32)) + @test_util.run_deprecated_v1 def testGradient(self): with self.session(use_gpu=True): l = constant_op.constant([3, 0, 1], name="l") @@ -201,6 +205,7 @@ class SparseXentTest(test.TestCase): print("cross entropy gradient err = ", err) self.assertLess(err, 5e-8) + @test_util.run_deprecated_v1 def testSecondGradient(self): images_placeholder = array_ops.placeholder(dtypes.float32, shape=(3, 2)) labels_placeholder = array_ops.placeholder(dtypes.int32, shape=(3)) @@ -230,17 +235,20 @@ class SparseXentTest(test.TestCase): self.assertAllCloseAccordingToType(np_loss, tf_loss) self.assertAllCloseAccordingToType(np_backprop, tf_backprop) + @test_util.run_deprecated_v1 def testHighDim(self): features = [[[1., 1., 1., 1.]], [[1., 2., 3., 4.]]] labels = [[3], [0]] self._testHighDim(features, labels) + @test_util.run_deprecated_v1 def testHighDim2(self): features = [[[1., 1., 1., 1.], [2., 2., 2., 2.]], [[1., 2., 3., 4.], [5., 6., 7., 8.]]] labels = [[3, 2], [0, 3]] self._testHighDim(features, labels) + @test_util.run_deprecated_v1 def testScalarHandling(self): with self.session(use_gpu=False) as sess: with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, @@ -318,7 +326,7 @@ def sparse_vs_dense_xent_benchmark(batch_size, num_entries, use_gpu): # Using sparse_softmax_cross_entropy_with_logits with session.Session(config=config) as sess: if not use_gpu: - with ops_lib.device("/cpu:0"): + with test_util.device("/cpu:0"): ops = _sparse_vs_dense_xent_benchmark_sparse(labels, logits) else: ops = _sparse_vs_dense_xent_benchmark_sparse(labels, logits) diff --git a/tensorflow/python/kernel_tests/sparsemask_op_test.py b/tensorflow/python/kernel_tests/sparsemask_op_test.py index 6f5dd45b61..b1cd0227bc 100644 --- a/tensorflow/python/kernel_tests/sparsemask_op_test.py +++ b/tensorflow/python/kernel_tests/sparsemask_op_test.py @@ -20,12 +20,14 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test class SparseMaskTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): values = np.random.rand(4, 4).astype(np.single) indices = np.array([0, 2, 3, 4], dtype=np.int32) diff --git a/tensorflow/python/kernel_tests/split_op_test.py b/tensorflow/python/kernel_tests/split_op_test.py index af90e03966..517db3450f 100644 --- a/tensorflow/python/kernel_tests/split_op_test.py +++ b/tensorflow/python/kernel_tests/split_op_test.py @@ -42,6 +42,7 @@ class SplitOpTest(test.TestCase): data -= 1j * data return data + @test_util.run_deprecated_v1 def testShapeInference(self): model_input = array_ops.placeholder(dtypes.float32, shape=(1, 10)) @@ -85,6 +86,7 @@ class SplitOpTest(test.TestCase): with self.cached_session(use_gpu=True) as sess: sess.run(result, feed_dict={model_input2: np.ones([4, 2])}) + @test_util.run_deprecated_v1 def testFailWithoutExplicitNum(self): size_splits = array_ops.placeholder(dtype=dtypes.int32, shape=[None]) @@ -209,6 +211,7 @@ class SplitOpTest(test.TestCase): self.assertAllEqual(result[:, 0:1], inp_grads[0]) self.assertAllEqual(result[:, 1:4], inp_grads[1]) + @test_util.run_deprecated_v1 def testOutputShape(self): for axis in [1, -1]: with self.cached_session(use_gpu=True): @@ -322,11 +325,13 @@ class SplitOpTest(test.TestCase): for i in range(4): self.assertAllEqual(result[:, i:i + 1], inp_grads[i]) + @test_util.run_deprecated_v1 def testGradientsAll(self): for dtype in _TEST_DTYPES: self._testGradientsSimple(dtype) self._testGradientsSimpleVariable(dtype) + @test_util.run_deprecated_v1 def testShapeFunctionEdgeCases(self): # split_dim greater than rank of input. with self.assertRaises(ValueError): @@ -356,6 +361,7 @@ class SplitOpTest(test.TestCase): for s in splits: self.assertEqual(None, s.get_shape().ndims) + @test_util.run_deprecated_v1 def testVariableShapeFunction(self): # size_splits too big with self.assertRaises(ValueError): @@ -366,6 +372,7 @@ class SplitOpTest(test.TestCase): assert s0.shape.as_list() == [2] assert s1.shape.as_list() == [1] + @test_util.run_deprecated_v1 def testNonexistentDimTensor(self): x = array_ops.placeholder(dtypes.int32) values = np.zeros([5, 30]) diff --git a/tensorflow/python/kernel_tests/stack_op_test.py b/tensorflow/python/kernel_tests/stack_op_test.py index 0f1fa97c38..ca3357a0ed 100644 --- a/tensorflow/python/kernel_tests/stack_op_test.py +++ b/tensorflow/python/kernel_tests/stack_op_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import variables @@ -41,6 +42,7 @@ def np_split_squeeze(array, axis): class StackOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testSimple(self): np.random.seed(7) with self.session(use_gpu=True): @@ -54,6 +56,7 @@ class StackOpTest(test.TestCase): c = array_ops.stack(xs) self.assertAllEqual(c.eval(), data) + @test_util.run_deprecated_v1 def testSimpleParallelCPU(self): np.random.seed(7) with self.session(use_gpu=False): @@ -63,6 +66,7 @@ class StackOpTest(test.TestCase): c = array_ops.parallel_stack(xs) self.assertAllEqual(c.eval(), data) + @test_util.run_deprecated_v1 def testSimpleParallelGPU(self): np.random.seed(7) with self.session(use_gpu=True): @@ -72,6 +76,7 @@ class StackOpTest(test.TestCase): c = array_ops.parallel_stack(xs) self.assertAllEqual(c.eval(), data) + @test_util.run_deprecated_v1 def testConst(self): np.random.seed(7) with self.session(use_gpu=True): @@ -96,6 +101,7 @@ class StackOpTest(test.TestCase): b = array_ops.reshape(a, array_ops.stack([2, 3])) self.assertAllEqual(b.get_shape(), [2, 3]) + @test_util.run_deprecated_v1 def testConstParallelCPU(self): np.random.seed(7) with self.session(use_gpu=False): @@ -110,6 +116,7 @@ class StackOpTest(test.TestCase): c = array_ops.parallel_stack(data) self.assertAllEqual(c.eval(), data) + @test_util.run_deprecated_v1 def testConstParallelGPU(self): np.random.seed(7) with self.session(use_gpu=True): @@ -124,6 +131,7 @@ class StackOpTest(test.TestCase): c = array_ops.parallel_stack(data) self.assertAllEqual(c.eval(), data) + @test_util.run_deprecated_v1 def testGradientsAxis0(self): np.random.seed(7) for shape in (2,), (3,), (2, 3), (3, 2), (4, 3, 2): @@ -136,6 +144,7 @@ class StackOpTest(test.TestCase): err = gradient_checker.compute_gradient_error(xs, shapes, c, shape) self.assertLess(err, 1e-6) + @test_util.run_deprecated_v1 def testGradientsAxis1(self): np.random.seed(7) for shape in (2, 3), (3, 2), (4, 3, 2): @@ -150,6 +159,7 @@ class StackOpTest(test.TestCase): err = gradient_checker.compute_gradient_error(xs, shapes, c, out_shape) self.assertLess(err, 1e-6) + @test_util.run_deprecated_v1 def testZeroSizeCPU(self): # Verify that stack doesn't crash for zero size inputs with self.session(use_gpu=False): @@ -161,6 +171,7 @@ class StackOpTest(test.TestCase): p = array_ops.parallel_stack(list(x)).eval() self.assertAllEqual(p, x) + @test_util.run_deprecated_v1 def testZeroSizeGPU(self): # Verify that stack doesn't crash for zero size inputs with self.session(use_gpu=True): @@ -172,6 +183,7 @@ class StackOpTest(test.TestCase): p = array_ops.parallel_stack(list(x)).eval() self.assertAllEqual(p, x) + @test_util.run_deprecated_v1 def testAxis0DefaultCPU(self): with self.session(use_gpu=False): t = [constant_op.constant([1, 2, 3]), constant_op.constant([4, 5, 6])] @@ -182,6 +194,7 @@ class StackOpTest(test.TestCase): self.assertAllEqual(stacked, expected) self.assertAllEqual(parallel_stacked, expected) + @test_util.run_deprecated_v1 def testAxis0DefaultGPU(self): with self.session(use_gpu=True): t = [constant_op.constant([1, 2, 3]), constant_op.constant([4, 5, 6])] @@ -225,6 +238,7 @@ class StackOpTest(test.TestCase): class AutomaticStackingTest(test.TestCase): + @test_util.run_deprecated_v1 def testSimple(self): with self.session(use_gpu=True): self.assertAllEqual( @@ -255,6 +269,7 @@ class AutomaticStackingTest(test.TestCase): self.assertAllEqual([[[0., 0.], [1., 1.]], [[2., 2.], [3., 3.]]], self.evaluate(result)) + @test_util.run_deprecated_v1 def testVariable(self): with self.session(use_gpu=True): v = variables.Variable(17) @@ -308,6 +323,7 @@ class AutomaticStackingTest(test.TestCase): t_2 = ops.convert_to_tensor([t_0, t_0, t_1], dtype=dtypes.float64) self.assertEqual(dtypes.float64, t_2.dtype) + @test_util.run_deprecated_v1 def testPlaceholder(self): with self.session(use_gpu=True): # Test using placeholder with a defined shape. @@ -326,6 +342,7 @@ class AutomaticStackingTest(test.TestCase): self.assertAllEqual( [[0, 0, 0], [0, 2, 0], [0, 0, 0]], result_1.eval(feed_dict={ph_1: 2})) + @test_util.run_deprecated_v1 def testShapeErrors(self): # Static shape error. ph_0 = array_ops.placeholder(dtypes.int32, shape=[1]) diff --git a/tensorflow/python/kernel_tests/stack_ops_test.py b/tensorflow/python/kernel_tests/stack_ops_test.py index dffb260b5f..d50f3f4680 100644 --- a/tensorflow/python/kernel_tests/stack_ops_test.py +++ b/tensorflow/python/kernel_tests/stack_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_data_flow_ops from tensorflow.python.ops import math_ops @@ -41,6 +42,7 @@ class StackOpTest(test.TestCase): c1 = gen_data_flow_ops.stack_pop_v2(h, dtypes.float32) self.assertAllClose([[4.0, 5.0]], self.evaluate(c1)) + @test_util.run_deprecated_v1 def testStackPushPop(self): self._testStackPushPop(use_gpu=False) self._testStackPushPop(use_gpu=True) @@ -56,6 +58,7 @@ class StackOpTest(test.TestCase): c1 = gen_data_flow_ops.stack_pop_v2(h, dtypes.float32) self.assertAllClose(a, self.evaluate(c1)) + @test_util.run_deprecated_v1 def testStackPushPopSwap(self): self._testStackPushPopSwap(use_gpu=False) self._testStackPushPopSwap(use_gpu=True) @@ -93,6 +96,7 @@ class StackOpTest(test.TestCase): c1, b1, [r, v], [r.get_shape(), tensor_shape.unknown_shape()]) self.assertAllClose(np.ones(2000) * 10.0, self.evaluate(ry)) + @test_util.run_deprecated_v1 def testStackWhileSwap(self): self._testStackWhileSwap(use_gpu=False) self._testStackWhileSwap(use_gpu=True) @@ -112,6 +116,7 @@ class StackOpTest(test.TestCase): r = c1 + c2 self.assertAllClose(9.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testMultiStack(self): self._testMultiStack(use_gpu=False) self._testMultiStack(use_gpu=True) @@ -135,6 +140,7 @@ class StackOpTest(test.TestCase): self.assertAllClose(out1, 4.0) self.assertAllClose(out2, 5.0) + @test_util.run_deprecated_v1 def testSameNameStacks(self): self._testSameNameStacks(use_gpu=False) self._testSameNameStacks(use_gpu=True) @@ -146,6 +152,7 @@ class StackOpTest(test.TestCase): c1 = gen_data_flow_ops.stack_close_v2(h) self.evaluate(c1) + @test_util.run_deprecated_v1 def testCloseStack(self): self._testCloseStack(use_gpu=False) self._testCloseStack(use_gpu=True) @@ -159,6 +166,7 @@ class StackOpTest(test.TestCase): c1 = gen_data_flow_ops.stack_close_v2(h) self.evaluate(c1) + @test_util.run_deprecated_v1 def testPushCloseStack(self): self._testPushCloseStack(use_gpu=False) self._testPushCloseStack(use_gpu=True) @@ -175,6 +183,7 @@ class StackOpRefTest(test.TestCase): c1 = gen_data_flow_ops.stack_pop(h, dtypes.float32) self.assertAllClose([[4.0, 5.0]], self.evaluate(c1)) + @test_util.run_deprecated_v1 def testStackPushPop(self): self._testStackPushPop(use_gpu=False) self._testStackPushPop(use_gpu=True) @@ -189,6 +198,7 @@ class StackOpRefTest(test.TestCase): c1 = gen_data_flow_ops.stack_pop(h, dtypes.float32) self.assertAllClose(a, self.evaluate(c1)) + @test_util.run_deprecated_v1 def testStackPushPopSwap(self): self._testStackPushPopSwap(use_gpu=False) self._testStackPushPopSwap(use_gpu=True) @@ -238,10 +248,12 @@ class StackOpRefTest(test.TestCase): c1, b1, [r, v], [r.get_shape(), tensor_shape.unknown_shape()]) self.assertAllClose(np.ones(2000) * 10.0, self.evaluate(ry)) + @test_util.run_deprecated_v1 def testStackWhileSwap(self): self._testStackWhileSwap(use_gpu=False) self._testStackWhileSwap(use_gpu=True) + @test_util.run_deprecated_v1 def testMultiStack(self): self._testMultiStack(use_gpu=False) self._testMultiStack(use_gpu=True) @@ -255,6 +267,7 @@ class StackOpRefTest(test.TestCase): _ = c1 + c2 self.assertNotEqual(h1.eval()[1], self.evaluate(h2)[1]) + @test_util.run_deprecated_v1 def testSameNameStacks(self): self._testSameNameStacks(use_gpu=False) self._testSameNameStacks(use_gpu=True) @@ -265,6 +278,7 @@ class StackOpRefTest(test.TestCase): c1 = gen_data_flow_ops.stack_close(h) self.evaluate(c1) + @test_util.run_deprecated_v1 def testCloseStack(self): self._testCloseStack(use_gpu=False) self._testCloseStack(use_gpu=True) @@ -277,6 +291,7 @@ class StackOpRefTest(test.TestCase): c1 = gen_data_flow_ops.stack_close(h) self.evaluate(c1) + @test_util.run_deprecated_v1 def testPushCloseStack(self): self._testPushCloseStack(use_gpu=False) self._testPushCloseStack(use_gpu=True) diff --git a/tensorflow/python/kernel_tests/stage_op_test.py b/tensorflow/python/kernel_tests/stage_op_test.py index b814843b86..83e06ba48b 100644 --- a/tensorflow/python/kernel_tests/stage_op_test.py +++ b/tensorflow/python/kernel_tests/stage_op_test.py @@ -18,6 +18,7 @@ from __future__ import print_function from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import math_ops @@ -28,6 +29,7 @@ TIMEOUT = 1 class StageTest(test.TestCase): + @test_util.run_deprecated_v1 def testSimple(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -47,6 +49,7 @@ class StageTest(test.TestCase): _, yval = sess.run([stage, y], feed_dict={x: i}) self.assertAllClose(4 * (i - 1) * (i - 1) * 128, yval, rtol=1e-4) + @test_util.run_deprecated_v1 def testMultiple(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -67,6 +70,7 @@ class StageTest(test.TestCase): self.assertAllClose( 4 * (i - 1) * (i - 1) * (i - 1) * 128, yval, rtol=1e-4) + @test_util.run_deprecated_v1 def testDictionary(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -110,6 +114,7 @@ class StageTest(test.TestCase): G.finalize() + @test_util.run_deprecated_v1 def testPeek(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -133,6 +138,7 @@ class StageTest(test.TestCase): for i in range(10): self.assertTrue(sess.run(peek, feed_dict={p: i}) == [i]) + @test_util.run_deprecated_v1 def testSizeAndClear(self): with ops.Graph().as_default() as G: with ops.device('/cpu:0'): @@ -158,6 +164,7 @@ class StageTest(test.TestCase): sess.run(clear) self.assertEqual(sess.run(size), 0) + @test_util.run_deprecated_v1 def testCapacity(self): capacity = 3 @@ -219,6 +226,7 @@ class StageTest(test.TestCase): # It should now be empty self.assertTrue(sess.run(size) == 0) + @test_util.run_deprecated_v1 def testMemoryLimit(self): memory_limit = 512 * 1024 # 512K chunk = 200 * 1024 # 256K diff --git a/tensorflow/python/kernel_tests/string_join_op_test.py b/tensorflow/python/kernel_tests/string_join_op_test.py index e4371ab5b9..2548e8695f 100644 --- a/tensorflow/python/kernel_tests/string_join_op_test.py +++ b/tensorflow/python/kernel_tests/string_join_op_test.py @@ -17,12 +17,14 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.ops import string_ops from tensorflow.python.platform import test class StringJoinOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testStringJoin(self): input0 = ["a", "b"] input1 = "a" diff --git a/tensorflow/python/kernel_tests/string_length_op_test.py b/tensorflow/python/kernel_tests/string_length_op_test.py index 06bf28ebce..bfa6ac2454 100644 --- a/tensorflow/python/kernel_tests/string_length_op_test.py +++ b/tensorflow/python/kernel_tests/string_length_op_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -32,6 +33,7 @@ class StringLengthOpTest(test.TestCase): values = self.evaluate(lengths) self.assertAllEqual(values, [[[1, 2], [3, 4], [5, 6]]]) + @test_util.run_deprecated_v1 def testUnit(self): unicode_strings = [u"H\xc3llo", u"\U0001f604"] utf8_strings = [s.encode("utf-8") for s in unicode_strings] @@ -51,6 +53,7 @@ class StringLengthOpTest(test.TestCase): 'not in: "BYTE", "UTF8_CHAR"'): string_ops.string_length(utf8_strings, unit="XYZ") + @test_util.run_deprecated_v1 def testLegacyPositionalName(self): # Code that predates the 'unit' parameter may have used a positional # argument for the 'name' parameter. Check that we don't break such code. diff --git a/tensorflow/python/kernel_tests/string_split_op_test.py b/tensorflow/python/kernel_tests/string_split_op_test.py index 92e13db0f7..0c91deb522 100644 --- a/tensorflow/python/kernel_tests/string_split_op_test.py +++ b/tensorflow/python/kernel_tests/string_split_op_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -39,6 +40,7 @@ class StringSplitOpTest(test.TestCase): self.assertAllEqual(values, [b"pigs", b"on", b"the", b"wing", b"animals"]) self.assertAllEqual(shape, [2, 4]) + @test_util.run_deprecated_v1 def testStringSplitEmptyDelimiter(self): strings = ["hello", "hola", b"\xF0\x9F\x98\x8E"] # Last string is U+1F60E @@ -81,6 +83,7 @@ class StringSplitOpTest(test.TestCase): self.assertAllEqual(values, [b"a", b"b", b"c", b"d", b"e", b"f", b"g"]) self.assertAllEqual(shape, [10, 1]) + @test_util.run_deprecated_v1 def testStringSplitWithDelimiter(self): strings = ["hello|world", "hello world"] @@ -103,6 +106,7 @@ class StringSplitOpTest(test.TestCase): self.assertAllEqual(values, [b"hello", b"world", b"hello", b"world"]) self.assertAllEqual(shape, [2, 2]) + @test_util.run_deprecated_v1 def testStringSplitWithDelimiterTensor(self): strings = ["hello|world", "hello world"] @@ -121,6 +125,7 @@ class StringSplitOpTest(test.TestCase): self.assertAllEqual(values, [b"hello", b"world", b"hello world"]) self.assertAllEqual(shape, [2, 2]) + @test_util.run_deprecated_v1 def testStringSplitWithDelimitersTensor(self): strings = ["hello.cruel,world", "hello cruel world"] diff --git a/tensorflow/python/kernel_tests/string_to_hash_bucket_op_test.py b/tensorflow/python/kernel_tests/string_to_hash_bucket_op_test.py index 2cc87008da..25f573fc14 100644 --- a/tensorflow/python/kernel_tests/string_to_hash_bucket_op_test.py +++ b/tensorflow/python/kernel_tests/string_to_hash_bucket_op_test.py @@ -19,6 +19,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -26,6 +27,7 @@ from tensorflow.python.platform import test class StringToHashBucketOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testStringToOneHashBucketFast(self): with self.cached_session(): input_string = array_ops.placeholder(dtypes.string) @@ -34,6 +36,7 @@ class StringToHashBucketOpTest(test.TestCase): self.assertAllEqual([0, 0, 0], result) + @test_util.run_deprecated_v1 def testStringToHashBucketsFast(self): with self.cached_session(): input_string = array_ops.placeholder(dtypes.string) @@ -46,6 +49,7 @@ class StringToHashBucketOpTest(test.TestCase): # Fingerprint64('d') -> 4470636696479570465 -> mod 10 -> 5 self.assertAllEqual([9, 2, 2, 5], result) + @test_util.run_deprecated_v1 def testStringToOneHashBucketLegacyHash(self): with self.cached_session(): input_string = array_ops.placeholder(dtypes.string) @@ -54,6 +58,7 @@ class StringToHashBucketOpTest(test.TestCase): self.assertAllEqual([0, 0, 0], result) + @test_util.run_deprecated_v1 def testStringToHashBucketsLegacyHash(self): with self.cached_session(): input_string = array_ops.placeholder(dtypes.string) diff --git a/tensorflow/python/kernel_tests/string_to_number_op_test.py b/tensorflow/python/kernel_tests/string_to_number_op_test.py index 99ee25e125..49ccfd1028 100644 --- a/tensorflow/python/kernel_tests/string_to_number_op_test.py +++ b/tensorflow/python/kernel_tests/string_to_number_op_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import parsing_ops from tensorflow.python.platform import test @@ -45,6 +46,7 @@ class StringToNumberOpTest(test.TestCase): with self.assertRaisesOpError(outstr): output.eval(feed_dict={input_string: [instr]}) + @test_util.run_deprecated_v1 def testToFloat(self): self._test(dtypes.float32, [("0", 0), ("3", 3), ("-1", -1), @@ -58,6 +60,7 @@ class StringToNumberOpTest(test.TestCase): ("INF", float("INF"))], [("10foobar", _ERROR_MESSAGE + "10foobar")]) + @test_util.run_deprecated_v1 def testToDouble(self): self._test(dtypes.float64, [("0", 0), ("3", 3), ("-1", -1), @@ -71,6 +74,7 @@ class StringToNumberOpTest(test.TestCase): ("INF", float("INF"))], [("10foobar", _ERROR_MESSAGE + "10foobar")]) + @test_util.run_deprecated_v1 def testToInt32(self): self._test(dtypes.int32, [("0", 0), ("3", 3), ("-1", -1), @@ -84,6 +88,7 @@ class StringToNumberOpTest(test.TestCase): ("2.9", _ERROR_MESSAGE + "2.9"), ("10foobar", _ERROR_MESSAGE + "10foobar")]) + @test_util.run_deprecated_v1 def testToInt64(self): self._test(dtypes.int64, [("0", 0), ("3", 3), ("-1", -1), diff --git a/tensorflow/python/kernel_tests/substr_op_test.py b/tensorflow/python/kernel_tests/substr_op_test.py index bb2d4a7913..9302152e82 100644 --- a/tensorflow/python/kernel_tests/substr_op_test.py +++ b/tensorflow/python/kernel_tests/substr_op_test.py @@ -22,6 +22,7 @@ from absl.testing import parameterized import numpy as np from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -319,6 +320,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): (np.int32, "UTF8_CHAR"), (np.int64, "UTF8_CHAR"), ) + @test_util.run_deprecated_v1 def testBadBroadcast(self, dtype, unit): test_string = [[b"ten", b"eleven", b"twelve"], [b"thirteen", b"fourteen", b"fifteen"], @@ -338,6 +340,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): (np.int32, -6, "UTF8_CHAR"), (np.int64, -6, "UTF8_CHAR"), ) + @test_util.run_deprecated_v1 def testOutOfRangeError_Scalar(self, dtype, pos, unit): # Scalar/Scalar test_string = { @@ -361,6 +364,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): (np.int32, -4, "UTF8_CHAR"), (np.int64, -4, "UTF8_CHAR"), ) + @test_util.run_deprecated_v1 def testOutOfRangeError_VectorScalar(self, dtype, pos, unit): # Vector/Scalar test_string = { @@ -381,6 +385,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): (np.int32, "UTF8_CHAR"), (np.int64, "UTF8_CHAR"), ) + @test_util.run_deprecated_v1 def testOutOfRangeError_MatrixMatrix(self, dtype, unit): # Matrix/Matrix test_string = { @@ -414,6 +419,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): (np.int32, "UTF8_CHAR"), (np.int64, "UTF8_CHAR"), ) + @test_util.run_deprecated_v1 def testOutOfRangeError_Broadcast(self, dtype, unit): # Broadcast test_string = { @@ -444,6 +450,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): (np.int32, "UTF8_CHAR"), (np.int64, "UTF8_CHAR"), ) + @test_util.run_deprecated_v1 def testMismatchPosLenShapes(self, dtype, unit): test_string = { "BYTE": [[b"ten", b"eleven", b"twelve"], @@ -471,6 +478,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): with self.assertRaises(ValueError): string_ops.substr(test_string, position, length) + @test_util.run_deprecated_v1 def testWrongDtype(self): with self.cached_session(): with self.assertRaises(TypeError): @@ -478,6 +486,7 @@ class SubstrOpTest(test.TestCase, parameterized.TestCase): with self.assertRaises(TypeError): string_ops.substr(b"test", 3, 1.0) + @test_util.run_deprecated_v1 def testInvalidUnit(self): with self.cached_session(): with self.assertRaises(ValueError): diff --git a/tensorflow/python/kernel_tests/summary_v1_image_op_test.py b/tensorflow/python/kernel_tests/summary_v1_image_op_test.py index e1b24756f3..56de2e933d 100644 --- a/tensorflow/python/kernel_tests/summary_v1_image_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_image_op_test.py @@ -24,6 +24,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.core.framework import summary_pb2 from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import image_ops import tensorflow.python.ops.nn_grad # pylint: disable=unused-import from tensorflow.python.platform import test @@ -49,6 +50,7 @@ class SummaryV1ImageOpTest(test.TestCase): }""" % ((i,) + shape[1:]) for i in xrange(3)) self.assertProtoEquals(expected, image_summ) + @test_util.run_deprecated_v1 def testImageSummary(self): for depth in (1, 3, 4): for positive in False, True: @@ -84,6 +86,7 @@ class SummaryV1ImageOpTest(test.TestCase): # Check the rest of the proto self._CheckProto(image_summ, shape) + @test_util.run_deprecated_v1 def testImageSummaryUint8(self): np.random.seed(7) for depth in (1, 3, 4): diff --git a/tensorflow/python/kernel_tests/summary_v1_ops_test.py b/tensorflow/python/kernel_tests/summary_v1_ops_test.py index 1206cb7013..e070f5bf6f 100644 --- a/tensorflow/python/kernel_tests/summary_v1_ops_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_ops_test.py @@ -26,6 +26,7 @@ from __future__ import print_function from tensorflow.core.framework import summary_pb2 from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import logging_ops from tensorflow.python.platform import test from tensorflow.python.summary import summary @@ -60,6 +61,7 @@ class SummaryV1OpsTest(test.TestCase): value { tag: "c2" simple_value: 20.0 } """, self._AsSummary(value)) + @test_util.run_deprecated_v1 def testMergeSummary(self): with self.cached_session() as sess: const = constant_op.constant(10.0) diff --git a/tensorflow/python/kernel_tests/template_test.py b/tensorflow/python/kernel_tests/template_test.py index a187fa115c..3b2a56bd1f 100644 --- a/tensorflow/python/kernel_tests/template_test.py +++ b/tensorflow/python/kernel_tests/template_test.py @@ -72,6 +72,7 @@ def variable_scoped_function_with_local_variable(): class TemplateTest(test.TestCase): + @test_util.run_deprecated_v1 def test_end_to_end(self): """This test shows a very simple line model with test_loss. @@ -172,6 +173,7 @@ class TemplateTest(test.TestCase): self.assertEqual("s1/dummy:0", v1.name) self.assertEqual("s1_1/dummy:0", v3.name) + @test_util.run_deprecated_v1 def test_same_unique_name_raise_error(self): tmpl1 = template.make_template( "_", variable_scoped_function, unique_name_="s1") @@ -190,6 +192,7 @@ class TemplateTest(test.TestCase): template.make_template( "_", variable_scoped_function, unique_name_="s1") + @test_util.run_deprecated_v1 def test_unique_name_and_reuse(self): tmpl1 = template.make_template( "_", variable_scoped_function, unique_name_="s1") @@ -260,6 +263,7 @@ class TemplateTest(test.TestCase): self.assertEqual("s1/test/dummy:0", v1.name) self.assertEqual("s1_1/test/dummy:0", v3.name) + @test_util.run_deprecated_v1 def test_enforces_no_extra_trainable_variables(self): tmpl = template.make_template("s", function_with_create, trainable=True) @@ -675,6 +679,7 @@ class TemplateTest(test.TestCase): self.assertEqual(1, len(tb.variables)) # TODO(apassos) handle local variables in Eager + @test_util.run_deprecated_v1 def test_local_variables(self): # Make sure trainable_variables are created. with variable_scope.variable_scope("foo3"): diff --git a/tensorflow/python/kernel_tests/tensor_array_ops_test.py b/tensorflow/python/kernel_tests/tensor_array_ops_test.py index bb8645e2d5..76e90ffea3 100644 --- a/tensorflow/python/kernel_tests/tensor_array_ops_test.py +++ b/tensorflow/python/kernel_tests/tensor_array_ops_test.py @@ -165,6 +165,7 @@ class TensorArrayTest(test.TestCase): [106.0, 107.0], [8.0, 9.0]]), c0) @test_util.disable_control_flow_v2("b/118343594 (TensorArray.concat)") + @test_util.run_deprecated_v1 def testTensorArrayWriteConcat(self): self._testTensorArrayWriteConcat(dtypes.float32) self._testTensorArrayWriteConcat(dtypes.float64) @@ -188,6 +189,7 @@ class TensorArrayTest(test.TestCase): self.evaluate(ta.write(1, [[4.0, 5.0]]).concat())) @test_util.disable_control_flow_v2("b/118890905") + @test_util.run_deprecated_v1 def testTensorArrayReadOrPackNotAllValuesAvailableFillsZeros(self): self._testTensorArrayReadOrPackNotAllValuesAvailableFillsZeros() @@ -204,6 +206,7 @@ class TensorArrayTest(test.TestCase): self.evaluate(ta.write(1, [[4.0, 5.0]]).concat())) @test_util.disable_control_flow_v2("b/118890905") + @test_util.run_deprecated_v1 def testTensorArrayReadOrPackNotAllValuesAvailableInferShapeFillsZeros(self): self._testTensorArrayReadOrPackNotAllValuesAvailableInferShapeFillsZeros() @@ -303,6 +306,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual(convert([[3.0, 301.0]]), d2) @test_util.disable_control_flow_v2("b/118343962 (TensorArray.split)") + @test_util.run_deprecated_v1 def testTensorArraySplitRead(self): self._testTensorArraySplitRead(dtypes.float32) self._testTensorArraySplitRead(dtypes.float64) @@ -313,6 +317,7 @@ class TensorArrayTest(test.TestCase): self._testTensorArraySplitRead(dtypes.string) @test_util.disable_control_flow_v2("v2 does not support TensorArray.grad.") + @test_util.run_deprecated_v1 def testSkipEagerTensorGradArrayWriteRead(self): with self.session(use_gpu=True) as session: ta = tensor_array_ops.TensorArray( @@ -346,6 +351,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual([[2.0]], g_d1) self.assertAllEqual(-2.0, g_d2) + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradGrad(self): if not tensor_array_ops.ENABLE_TENSOR_ARRAY_V2: self.skipTest("Legacy TensorArray does not support double derivatives.") @@ -366,6 +372,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual([2.0], session.run(g2)) @test_util.disable_control_flow_v2("v2 does not support TensorArray.grad.") + @test_util.run_deprecated_v1 def testSkipEagerTensorGradArrayDynamicWriteRead(self): with self.session(use_gpu=True) as session: ta = tensor_array_ops.TensorArray( @@ -408,6 +415,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual(3, g_vs) @test_util.disable_control_flow_v2("v2 does not support TensorArray.grad.") + @test_util.run_deprecated_v1 def testSkipEagerTensorGradAccessTwiceReceiveSameObject(self): with self.session(use_gpu=True) as session: ta = tensor_array_ops.TensorArray( @@ -424,6 +432,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual(t_g_ta_0, t_g_ta_1) self.assertAllEqual([[4.0, 5.0]], d_r1_0) + @test_util.run_deprecated_v1 def testTensorArrayWriteWrongIndexOrDataTypeFails(self): with self.session(use_gpu=True): ta = _make_ta(3, "foo", dtype=dtypes.float32) @@ -457,6 +466,7 @@ class TensorArrayTest(test.TestCase): with self.assertRaisesOpError(error_msg): self.evaluate(ta.write(3, 3.0).flow) + @test_util.run_deprecated_v1 def testTensorArrayReadWrongIndexOrDataTypeFails(self): with self.session(use_gpu=True): ta = _make_ta(3, "foo", dtype=dtypes.float32) @@ -491,6 +501,7 @@ class TensorArrayTest(test.TestCase): self.evaluate(ta.read(3)) @test_util.disable_control_flow_v2("v2 allows multiple writes.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayWriteMultipleFails(self): with self.session(use_gpu=True): ta = tensor_array_ops.TensorArray( @@ -502,6 +513,7 @@ class TensorArrayTest(test.TestCase): self.evaluate(ta.write(2, 3.0).write(2, 3.0).flow) @test_util.disable_control_flow_v2("b/118343594 (TensorArray.concat)") + @test_util.run_deprecated_v1 def testTensorArrayConcatIncompatibleShapesFails(self): with self.session(use_gpu=True): ta = tensor_array_ops.TensorArray( @@ -534,6 +546,7 @@ class TensorArrayTest(test.TestCase): self.evaluate(w3.concat()) @test_util.disable_control_flow_v2("b/118343962 (TensorArray.split)") + @test_util.run_deprecated_v1 def testTensorArraySplitIncompatibleShapesFails(self): with self.session(use_gpu=True): in_eager_mode = context.executing_eagerly() @@ -598,12 +611,14 @@ class TensorArrayTest(test.TestCase): wb1_grad.flow.eval() @test_util.disable_control_flow_v2("v2 does not support TensorArray.grad.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayWriteGradientAddMultipleAdds(self): for dtype in (dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128): self._testTensorArrayWriteGradientAddMultipleAdds(dtype) @test_util.disable_control_flow_v2("Low level legacy TA op test.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradWithShapeKnownElementShape(self): with self.session(use_gpu=True) as sess: ta = tensor_array_ops.TensorArray( @@ -634,6 +649,7 @@ class TensorArrayTest(test.TestCase): sess.run(read_value, feed_dict={value: fed_value})) @test_util.disable_control_flow_v2("Low level legacy TA op test.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradWithShapeUnknownElementShape(self): with self.session(use_gpu=True) as sess: ta = tensor_array_ops.TensorArray( @@ -720,6 +736,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual(c([[3.0, 2.0]]), grad_vals[0]) self.assertAllEqual(c(-2.0), grad_vals[1]) + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradientWriteRead(self): for dtype in (np.float32, np.float64, np.complex64, np.complex128): self._testTensorArrayGradientWriteReadType(dtype) @@ -757,10 +774,12 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual([4.0 + 40.0, 5.0 + 50.0], grad_vals[1]) @test_util.disable_control_flow_v2("b/118343594 (TensorArray.concat)") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradientWritePackConcatAndRead(self): self._testTensorArrayGradientWritePackConcatAndRead() @test_util.disable_control_flow_v2("v2 does not support clear_after_read.") + @test_util.run_deprecated_v1 def testTensorArrayReadTwice(self): with self.session(use_gpu=True): value = constant_op.constant([[1.0, -1.0], [10.0, -10.0]]) @@ -814,10 +833,12 @@ class TensorArrayTest(test.TestCase): self.assertEqual(len(grad_vals), 1) self.assertAllEqual([[2.0 - 1.5, 3.0 + 1.5], [4.0, 5.0]], grad_vals[0]) + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradientUnpackRead(self): self._testTensorArrayGradientUnpackRead() @test_util.disable_control_flow_v2("b/118343962 (TensorArray.split)") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradientSplitConcat(self): with self.session(use_gpu=True) as session: ta = tensor_array_ops.TensorArray( @@ -863,6 +884,7 @@ class TensorArrayTest(test.TestCase): self.assertEqual(len(grad_vals), 1) self.assertAllEqual([[2.0, 3.0], [4.0, 5.0]], grad_vals[0]) + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradientDynamicUnpackRead(self): self._testTensorArrayGradientDynamicUnpackRead() @@ -1043,6 +1065,7 @@ class TensorArrayTest(test.TestCase): grad = gradients_impl.gradients(loop(x), [x])[0] self.assertAllClose(31.0, self.evaluate(grad)) + @test_util.run_deprecated_v1 def testSkipEagerSumOfTwoReadVariablesWithoutRepeatGrad(self): with self.session(use_gpu=True) as session: a = array_ops.identity( @@ -1078,6 +1101,7 @@ class TensorArrayTest(test.TestCase): def _grad_source_for_name(self, name): return tensor_array_grad._GetGradSource(constant_op.constant(0, name=name)) + @test_util.run_deprecated_v1 def testSkipEagerGetGradSource_Invalid(self): with self.assertRaises(ValueError): self._grad_source_for_name("") @@ -1086,6 +1110,7 @@ class TensorArrayTest(test.TestCase): with self.assertRaises(ValueError): self._grad_source_for_name("foo/bar") + @test_util.run_deprecated_v1 def testSkipEagerGetGradSource_NoEnclosingScope(self): self.assertEqual("gradients:0", self._grad_source_for_name("gradients")) self.assertEqual("gradients_0:0", self._grad_source_for_name("gradients_0")) @@ -1097,6 +1122,7 @@ class TensorArrayTest(test.TestCase): self.assertEqual("gradients_0", self._grad_source_for_name("gradients_0/foo/bar")) + @test_util.run_deprecated_v1 def testSkipEagerGetGradSource_EnclosingScope(self): self.assertEqual("foo/gradients:0", self._grad_source_for_name("foo/gradients")) @@ -1111,11 +1137,13 @@ class TensorArrayTest(test.TestCase): self.assertEqual("foo/bar/gradients_0", self._grad_source_for_name("foo/bar/gradients_0/baz")) + @test_util.run_deprecated_v1 def testSkipEagerGetGradSource_NestedUsesInnermost(self): self.assertEqual( "foo/gradients/bar/gradients_0", self._grad_source_for_name("foo/gradients/bar/gradients_0/baz")) + @test_util.run_deprecated_v1 def testSkipEagerWriteShape(self): with self.session(use_gpu=True): ta = tensor_array_ops.TensorArray( @@ -1141,6 +1169,7 @@ class TensorArrayTest(test.TestCase): w0.write(0, c2) @test_util.disable_control_flow_v2("b/118343962 (TensorArray.split)") + @test_util.run_deprecated_v1 def testSkipEagerPartlyUnknownShape(self): with self.session(use_gpu=True): ta = tensor_array_ops.TensorArray( @@ -1212,10 +1241,12 @@ class TensorArrayTest(test.TestCase): w1.write(4, c2) @test_util.disable_control_flow_v2("b/117943489 (dynamic_size)") + @test_util.run_deprecated_v1 def testUnpackShape(self): self._testUnpackShape() @test_util.disable_control_flow_v2("b/118343962 (TensorArray.split)") + @test_util.run_deprecated_v1 def testSplitShape(self): with self.session(use_gpu=True): ta = tensor_array_ops.TensorArray( @@ -1246,6 +1277,7 @@ class TensorArrayTest(test.TestCase): tensor_shape.TensorShape( ta1.handle.op.get_attr("element_shape")).ndims, None) + @test_util.run_deprecated_v1 def testSkipEagerWriteUnknownShape(self): with self.session(use_gpu=True): ta = tensor_array_ops.TensorArray( @@ -1289,10 +1321,12 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual(np.array([1.0, 1.0, 1.0]), self.evaluate(grad)[0]) @test_util.disable_control_flow_v2("b/117943489") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayUnpackDynamic(self): self._testTensorArrayUnpackDynamic() @test_util.disable_control_flow_v2("b/118343594 (TensorArray.concat)") + @test_util.run_deprecated_v1 def testSkipEagerTensorArraySplitDynamic(self): with self.session(use_gpu=True) as sess: ta = tensor_array_ops.TensorArray( @@ -1319,6 +1353,7 @@ class TensorArrayTest(test.TestCase): .ENABLE_TENSOR_ARRAY_V2 else v1_msg): ta.stack().eval() + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayEvalEmpty(self): self._testTensorArrayEvalEmpty() @@ -1339,10 +1374,12 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual([0, 5], self.evaluate(concatenated).shape) @test_util.disable_control_flow_v2("b/117943489") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayEvalEmptyWithDefault(self): self._testTensorArrayEvalEmptyWithDefault() @test_util.disable_control_flow_v2("b/117943489") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayScatterReadAndGradients(self): with self.session(use_gpu=True) as session: ta = tensor_array_ops.TensorArray( @@ -1370,6 +1407,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual([[2.0, 3.0], [4.0, 5.0]], grad_vals[0]) @test_util.disable_control_flow_v2("b/117943286") + @test_util.run_deprecated_v1 def testTensorArrayWriteGatherAndGradients(self): with self.session(use_gpu=True) as session: ta = tensor_array_ops.TensorArray( @@ -1407,6 +1445,7 @@ class TensorArrayTest(test.TestCase): self.assertAllEqual(expected_grad, grad_vals[0]) @test_util.disable_control_flow_v2("colocate_with not supported in v2.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGetsDeviceFromFirstWrite(self): with ops.device("/job:worker/task:0/cpu:0"): # this initial device will be ignored. @@ -1456,6 +1495,7 @@ class TensorArrayTest(test.TestCase): [s for s in dev_stats[d] if "/TensorArray" in s.node_name]) @test_util.disable_control_flow_v2("colocate_with not supported in v2.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGetsDeviceFromFirstWriteInWhileLoop(self): with ops.device("/job:worker/task:0/cpu:0"): ta = tensor_array_ops.TensorArray(dtype=dtypes.float32, size=2) @@ -1486,6 +1526,7 @@ class TensorArrayTest(test.TestCase): [s for s in dev_stats[d] if "TensorArray" == s.node_name]) @test_util.disable_control_flow_v2("colocate_with not supported in v2.") + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayDisabledColocateWithFirstWriteCall(self): with ops.device("/job:worker/task:0/cpu:0"): ta = tensor_array_ops.TensorArray( @@ -1568,6 +1609,7 @@ class TensorArrayTest(test.TestCase): self.assertEqual(size0_v, 2) self.assertEqual(size1_v, 4) + @test_util.run_deprecated_v1 def testSkipEagerTensorArrayGradYsInCorrectScope(self): n_time = 1 n_dim = 1 diff --git a/tensorflow/python/kernel_tests/topk_op_test.py b/tensorflow/python/kernel_tests/topk_op_test.py index a72888c256..5d46176bce 100644 --- a/tensorflow/python/kernel_tests/topk_op_test.py +++ b/tensorflow/python/kernel_tests/topk_op_test.py @@ -27,6 +27,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import nn_ops @@ -181,6 +182,7 @@ class TopKTest(test.TestCase): k = constant_op.constant(3) self._validateTopK(inputs, k, [19, 18, 17], [11, 3, 7]) + @test_util.run_deprecated_v1 def testKNegative(self): inputs = [[0.1, 0.2], [0.3, 0.4]] with self.session(use_gpu=True): @@ -189,12 +191,14 @@ class TopKTest(test.TestCase): with self.assertRaisesOpError("Need k >= 0, got -7"): values.eval(feed_dict={k: -7}) + @test_util.run_deprecated_v1 def testKTooLarge(self): inputs = [[0.1, 0.2], [0.3, 0.4]] with self.assertRaisesRegexp(ValueError, r"must have last dimension >= k = 4"): nn_ops.top_k(inputs, 4) + @test_util.run_deprecated_v1 def testTopKGradients(self): with self.session(use_gpu=True) as sess: inputs = array_ops.placeholder(dtypes.float32, shape=[2, 5]) diff --git a/tensorflow/python/kernel_tests/trace_op_test.py b/tensorflow/python/kernel_tests/trace_op_test.py index f1abaefb66..52640c02c2 100644 --- a/tensorflow/python/kernel_tests/trace_op_test.py +++ b/tensorflow/python/kernel_tests/trace_op_test.py @@ -19,6 +19,7 @@ from __future__ import print_function import numpy as np +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -34,6 +35,7 @@ class TraceTest(test.TestCase): tf_ans = math_ops.trace(x).eval() self.assertAllClose(tf_ans, np_ans) + @test_util.run_deprecated_v1 def testTrace(self): for dtype in [np.int32, np.float32, np.float64]: for shape in [[2, 2], [2, 3], [3, 2], [2, 3, 2], [2, 2, 2, 3]]: diff --git a/tensorflow/python/kernel_tests/unicode_decode_op_test.py b/tensorflow/python/kernel_tests/unicode_decode_op_test.py index c34145bff1..c165021eea 100644 --- a/tensorflow/python/kernel_tests/unicode_decode_op_test.py +++ b/tensorflow/python/kernel_tests/unicode_decode_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import errors_impl as errors +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_string_ops from tensorflow.python.platform import test @@ -79,6 +80,7 @@ class UnicodeDecodeTest(test.TestCase): self.assertAllEqual(self.evaluate(row_splits).tolist(), [0, 4]) self.assertAllEqual(self.evaluate(starts).tolist(), [0, 3, 6, 9]) + @test_util.run_deprecated_v1 def testStrictError(self): text = constant_op.constant([b"\xFEED"]) _, error, _ = gen_string_ops.unicode_decode_with_offsets( @@ -97,6 +99,7 @@ class UnicodeDecodeTest(test.TestCase): with self.test_session(): self.assertAllEqual(self.evaluate(utf8_text).tolist(), [65533]) + @test_util.run_deprecated_v1 def testBadReplacementChar(self): text = constant_op.constant([b"\xFE"]) _, error, _ = gen_string_ops.unicode_decode_with_offsets( @@ -121,6 +124,7 @@ class UnicodeDecodeTest(test.TestCase): codepoint("o") ]) + @test_util.run_deprecated_v1 def testBadErrorPolicy(self): text = constant_op.constant(["hippopotamus"]) diff --git a/tensorflow/python/kernel_tests/unicode_script_op_test.py b/tensorflow/python/kernel_tests/unicode_script_op_test.py index 927e5459ed..83cfeb2021 100644 --- a/tensorflow/python/kernel_tests/unicode_script_op_test.py +++ b/tensorflow/python/kernel_tests/unicode_script_op_test.py @@ -20,12 +20,14 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import string_ops from tensorflow.python.platform import test class UnicodeScriptOpTest(test.TestCase): + @test_util.run_deprecated_v1 def testValidScripts(self): inputs = [ ord("a"), @@ -45,6 +47,7 @@ class UnicodeScriptOpTest(test.TestCase): 0 # USCRIPT_COMMON (ZYYY) ]) + @test_util.run_deprecated_v1 def testInvalidScript(self): inputs = [-100, 0xffffff] with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/unicode_transcode_op_test.py b/tensorflow/python/kernel_tests/unicode_transcode_op_test.py index 037ecd104b..a3b4fd0347 100644 --- a/tensorflow/python/kernel_tests/unicode_transcode_op_test.py +++ b/tensorflow/python/kernel_tests/unicode_transcode_op_test.py @@ -22,6 +22,7 @@ from absl.testing import parameterized from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import string_ops from tensorflow.python.platform import test @@ -133,6 +134,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): values = self.evaluate(outputs) self.assertAllEqual(values, b"\x00 ") + @test_util.run_deprecated_v1 def test_transcode_bad_utf8_with_strict_errors(self): bad_string = b"\x00\xff" with self.cached_session() as sess: @@ -145,6 +147,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): "Invalid formatting on input string"): self.evaluate(outputs) + @test_util.run_deprecated_v1 def test_transcode_bad_utf8_start_with_strict_errors(self): bad_string = b"\xffabcd" with self.cached_session() as sess: @@ -317,12 +320,14 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): (b"\xfe\xff\x00<\xfe\xff\x00>", "UTF-16", b"<\xef\xbb\xbf>"), (b"\xff\xfe<\x00\xff\xfe>\x00", "UTF-16", b"<\xef\xbb\xbf>"), ) + @test_util.run_deprecated_v1 def test_bom_handling(self, string, input_encoding, expected): with self.test_session(): output = string_ops.unicode_transcode( string, input_encoding=input_encoding, output_encoding="UTF-8") self.assertAllEqual(output.eval(), expected) + @test_util.run_deprecated_v1 def test_invalid_encoding_causes_errors(self): strings = [[b"a", b"abc"], [b"ABC", b"DEF"]] @@ -349,6 +354,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): replace_control_characters=False) self.evaluate(outputs) + @test_util.run_deprecated_v1 def test_invalid_error_policy_causes_errors(self): strings = [[b"a", b"abc"], [b"ABC", b"DEF"]] @@ -378,6 +384,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): self.assertAllEqual([b"AbCdE", b"HiJkL"], transcoded) + @test_util.run_deprecated_v1 def test_cjk_encodings(self): strings_ja = [ b"\x5c\x5c", # Yen sign diff --git a/tensorflow/python/kernel_tests/unstack_op_test.py b/tensorflow/python/kernel_tests/unstack_op_test.py index d314e1eaf9..f5ba475e7a 100644 --- a/tensorflow/python/kernel_tests/unstack_op_test.py +++ b/tensorflow/python/kernel_tests/unstack_op_test.py @@ -74,6 +74,7 @@ class UnstackOpTest(test.TestCase): cs = [self.evaluate(c) for c in cs] self.assertAllEqual(cs, data) + @test_util.run_deprecated_v1 def testGradientsAxis0(self): for shape in (2,), (3,), (2, 3), (3, 2), (4, 3, 2): data = np.random.randn(*shape) @@ -86,6 +87,7 @@ class UnstackOpTest(test.TestCase): shapes[i]) self.assertLess(err, 1e-6) + @test_util.run_deprecated_v1 def testGradientsAxis1(self): for shape in (2, 3), (3, 2), (4, 3, 2): data = np.random.randn(*shape) @@ -99,6 +101,7 @@ class UnstackOpTest(test.TestCase): out_shape) self.assertLess(err, 1e-6) + @test_util.run_deprecated_v1 def testInferNum(self): with self.cached_session(): for shape in (2,), (3,), (2, 3), (3, 2), (4, 3, 2): @@ -107,16 +110,19 @@ class UnstackOpTest(test.TestCase): self.assertEqual(type(cs), list) self.assertEqual(len(cs), shape[0]) + @test_util.run_deprecated_v1 def testCannotInferNumFromUnknownShape(self): x = array_ops.placeholder(np.float32) with self.assertRaisesRegexp(ValueError, r'Cannot infer num from shape '): array_ops.unstack(x) + @test_util.run_deprecated_v1 def testUnknownShapeOkWithNum(self): x = array_ops.placeholder(np.float32) array_ops.unstack(x, num=2) + @test_util.run_deprecated_v1 def testCannotInferNumFromNoneShape(self): x = array_ops.placeholder(np.float32, shape=(None,)) with self.assertRaisesRegexp(ValueError, diff --git a/tensorflow/python/kernel_tests/variable_ops_test.py b/tensorflow/python/kernel_tests/variable_ops_test.py index c63d7f89c7..0f3e261992 100644 --- a/tensorflow/python/kernel_tests/variable_ops_test.py +++ b/tensorflow/python/kernel_tests/variable_ops_test.py @@ -60,15 +60,18 @@ class VariableOpTest(test.TestCase): # that Variable and Assign have GPU implementations for matching tf. self.assertAllEqual(x, self._initFetch(x, tftype, use_gpu=True)) + @test_util.run_deprecated_v1 def testBasic(self): self._testTypes(np.arange(0, 20).reshape([4, 5])) + @test_util.run_deprecated_v1 def testset_shape(self): p = state_ops.variable_op([1, 2], dtypes.float32) self.assertEqual([1, 2], p.get_shape()) p = state_ops.variable_op([1, 2], dtypes.float32, set_shape=False) self.assertEqual(tensor_shape.unknown_shape(), p.get_shape()) + @test_util.run_deprecated_v1 def testAssign(self): value = np.array([[42.0, 43.0]]) var = state_ops.variable_op(value.shape, dtypes.float32) @@ -76,6 +79,7 @@ class VariableOpTest(test.TestCase): assigned = state_ops.assign(var, value) self.assertShapeEqual(value, assigned) + @test_util.run_deprecated_v1 def testAssignNoValidateShape(self): value = np.array([[42.0, 43.0]]) var = state_ops.variable_op(value.shape, dtypes.float32) @@ -83,6 +87,7 @@ class VariableOpTest(test.TestCase): assigned = state_ops.assign(var, value, validate_shape=False) self.assertShapeEqual(value, assigned) + @test_util.run_deprecated_v1 def testAssignNoVarShape(self): value = np.array([[42.0, 43.0]]) var = state_ops.variable_op(value.shape, dtypes.float32, set_shape=False) @@ -90,6 +95,7 @@ class VariableOpTest(test.TestCase): assigned = state_ops.assign(var, value) self.assertShapeEqual(value, assigned) + @test_util.run_deprecated_v1 def testAssignNoVarShapeNoValidateShape(self): value = np.array([[42.0, 43.0]]) var = state_ops.variable_op(value.shape, dtypes.float32, set_shape=False) @@ -102,6 +108,7 @@ class VariableOpTest(test.TestCase): self.assertEqual(tensor_shape.unknown_shape(), tensor.get_shape()) return tensor + @test_util.run_deprecated_v1 def testAssignNoValueShape(self): value = self._NewShapelessTensor() shape = [1, 2] @@ -110,6 +117,7 @@ class VariableOpTest(test.TestCase): self.assertEqual(shape, var.get_shape()) self.assertEqual(shape, assigned.get_shape()) + @test_util.run_deprecated_v1 def testAssignNoValueShapeNoValidateShape(self): value = self._NewShapelessTensor() shape = [1, 2] @@ -118,6 +126,7 @@ class VariableOpTest(test.TestCase): assigned = state_ops.assign(var, value, validate_shape=False) self.assertEqual(tensor_shape.unknown_shape(), assigned.get_shape()) + @test_util.run_deprecated_v1 def testAssignNoShape(self): with self.cached_session(): value = self._NewShapelessTensor() @@ -126,6 +135,7 @@ class VariableOpTest(test.TestCase): self.assertEqual(tensor_shape.unknown_shape(), state_ops.assign(var, value).get_shape()) + @test_util.run_deprecated_v1 def testAssignNoShapeNoValidateShape(self): with self.cached_session(): value = self._NewShapelessTensor() @@ -136,6 +146,7 @@ class VariableOpTest(test.TestCase): state_ops.assign( var, value, validate_shape=False).get_shape()) + @test_util.run_deprecated_v1 def testAssignUpdate(self): var = state_ops.variable_op([1, 2], dtypes.float32) added = state_ops.assign_add(var, [[2.0, 3.0]]) @@ -143,6 +154,7 @@ class VariableOpTest(test.TestCase): subbed = state_ops.assign_sub(var, [[12.0, 13.0]]) self.assertEqual([1, 2], subbed.get_shape()) + @test_util.run_deprecated_v1 def testAssignUpdateNoVarShape(self): var = state_ops.variable_op([1, 2], dtypes.float32, set_shape=False) added = state_ops.assign_add(var, [[2.0, 3.0]]) @@ -150,6 +162,7 @@ class VariableOpTest(test.TestCase): subbed = state_ops.assign_sub(var, [[12.0, 13.0]]) self.assertEqual([1, 2], subbed.get_shape()) + @test_util.run_deprecated_v1 def testAssignUpdateNoValueShape(self): var = state_ops.variable_op([1, 2], dtypes.float32) added = state_ops.assign_add(var, self._NewShapelessTensor()) @@ -157,6 +170,7 @@ class VariableOpTest(test.TestCase): subbed = state_ops.assign_sub(var, self._NewShapelessTensor()) self.assertEqual([1, 2], subbed.get_shape()) + @test_util.run_deprecated_v1 def testAssignUpdateNoShape(self): var = state_ops.variable_op([1, 2], dtypes.float32, set_shape=False) added = state_ops.assign_add(var, self._NewShapelessTensor()) @@ -164,6 +178,7 @@ class VariableOpTest(test.TestCase): subbed = state_ops.assign_sub(var, self._NewShapelessTensor()) self.assertEqual(tensor_shape.unknown_shape(), subbed.get_shape()) + @test_util.run_deprecated_v1 def testTemporaryVariable(self): with test_util.use_gpu(): var = gen_state_ops.temporary_variable( @@ -173,6 +188,7 @@ class VariableOpTest(test.TestCase): final = gen_state_ops.destroy_temporary_variable(var, var_name="foo") self.assertAllClose([[10.0, 12.0]], self.evaluate(final)) + @test_util.run_deprecated_v1 def testDestroyNonexistentTemporaryVariable(self): with test_util.use_gpu(): var = gen_state_ops.temporary_variable([1, 2], dtypes.float32) @@ -180,6 +196,7 @@ class VariableOpTest(test.TestCase): with self.assertRaises(errors.NotFoundError): self.evaluate(final) + @test_util.run_deprecated_v1 def testDuplicateTemporaryVariable(self): with test_util.use_gpu(): var1 = gen_state_ops.temporary_variable( @@ -192,6 +209,7 @@ class VariableOpTest(test.TestCase): with self.assertRaises(errors.AlreadyExistsError): self.evaluate(final) + @test_util.run_deprecated_v1 def testDestroyTemporaryVariableTwice(self): with test_util.use_gpu(): var = gen_state_ops.temporary_variable([1, 2], dtypes.float32) @@ -201,6 +219,7 @@ class VariableOpTest(test.TestCase): with self.assertRaises(errors.NotFoundError): self.evaluate(final) + @test_util.run_deprecated_v1 def testTemporaryVariableNoLeak(self): with test_util.use_gpu(): var = gen_state_ops.temporary_variable( @@ -208,6 +227,7 @@ class VariableOpTest(test.TestCase): final = array_ops.identity(var) self.evaluate(final) + @test_util.run_deprecated_v1 def testTwoTemporaryVariablesNoLeaks(self): with test_util.use_gpu(): var1 = gen_state_ops.temporary_variable( @@ -217,6 +237,7 @@ class VariableOpTest(test.TestCase): final = var1 + var2 self.evaluate(final) + @test_util.run_deprecated_v1 def testAssignDependencyAcrossDevices(self): with test_util.use_gpu(): # The variable and an op to increment it are on the GPU. @@ -232,6 +253,7 @@ class VariableOpTest(test.TestCase): result = math_ops.multiply(var, var) self.assertAllClose([4.0], self.evaluate(result)) + @test_util.run_deprecated_v1 def testIsVariableInitialized(self): for use_gpu in [True, False]: with self.test_session(use_gpu=use_gpu): diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index 3720f736ac..44d4bd5e30 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -152,6 +152,7 @@ class VariableScopeTest(test.TestCase): # TypeError: Fetch argument # has invalid type , must be a string or Tensor. # (Can not convert a ResourceVariable into a Tensor or Operation.) + @test_util.run_deprecated_v1 def testStringDefaultInitializer(self): with self.cached_session(): v = variable_scope.get_variable("string", shape=[], dtype=dtypes.string) @@ -310,6 +311,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # InvalidArgumentError: /job:moo/replica:0/task:0/device:CPU:0 unknown device. + @test_util.run_deprecated_v1 def testVarScopeCachingDevice(self): with self.cached_session(): caching_device = "/job:moo" @@ -424,6 +426,7 @@ class VariableScopeTest(test.TestCase): # invalid type , must # be a string or Tensor. (Can not convert a ResourceVariable into a Tensor or # Operation.) + @test_util.run_deprecated_v1 def testControlDeps(self): with self.cached_session() as sess: v0 = variable_scope.get_variable( @@ -450,6 +453,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # AssertionError: True is not false (last assertFalse) + @test_util.run_deprecated_v1 def testEnableResourceVariables(self): old = variable_scope._DEFAULT_USE_RESOURCE try: @@ -464,6 +468,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # TypeError: Fetch argument None has invalid type + @test_util.run_deprecated_v1 def testControlFlow(self): with self.cached_session() as sess: v0 = variable_scope.get_variable( @@ -1148,6 +1153,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testGetCollection(self): with self.cached_session(): _ = variable_scope.get_variable("testGetCollection_a", []) @@ -1204,6 +1210,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testGetTrainableVariablesWithGetVariable(self): with self.cached_session(): _ = variable_scope.get_variable("testGetTrainableVariables_a", []) @@ -1242,6 +1249,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testGetTrainableVariablesWithVariable(self): with self.cached_session(): _ = variable_scope.variable(1.0, name="testGetTrainableVariables_a") @@ -1283,6 +1291,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testGetGlobalVariables(self): with self.cached_session(): _ = variable_scope.get_variable("testGetGlobalVariables_a", []) @@ -1295,6 +1304,7 @@ class VariableScopeTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testGetLocalVariables(self): with self.cached_session(): _ = variable_scope.get_variable( @@ -1370,6 +1380,7 @@ class VariableScopeWithPartitioningTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testResultNameMatchesRequested(self): with variable_scope.variable_scope( "scope0", partitioner=axis0_into2_partitioner): @@ -1444,6 +1455,7 @@ class VariableScopeWithPartitioningTest(test.TestCase): # TODO(mihaimaruseac): Not converted to use wrap_function because of # obtaining different results in the eager case compared to the graph one + @test_util.run_deprecated_v1 def testScalarIgnoresPartitioner(self): with variable_scope.variable_scope( "scope0", partitioner=axis0_into2_partitioner): @@ -1583,6 +1595,7 @@ class VariableScopeWithCustomGetterTest(test.TestCase): # dtype=float32> cannot be interpreted as a Tensor. (Tensor # Tensor("custom_getter/add:0", shape=(1, 2, 3), dtype=float32) is not an # element of this graph.) + @test_util.run_deprecated_v1 def testGetterThatCreatesTwoVariablesAndSumsThem(self): def custom_getter(getter, name, *args, **kwargs): @@ -1610,6 +1623,7 @@ class VariableScopeWithCustomGetterTest(test.TestCase): # dtype=float32> cannot be interpreted as a Tensor. (Tensor # Tensor("sum_getter_2/add:0", shape=(1, 2, 3), dtype=float32) is not an # element of this graph.) + @test_util.run_deprecated_v1 def testNestedCustomGetters(self): def sum_getter(getter, name, *args, **kwargs): diff --git a/tensorflow/python/kernel_tests/variables_test.py b/tensorflow/python/kernel_tests/variables_test.py index 14ec46dcb2..08d885e8a8 100644 --- a/tensorflow/python/kernel_tests/variables_test.py +++ b/tensorflow/python/kernel_tests/variables_test.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_state_ops @@ -42,6 +43,7 @@ from tensorflow.python.util import compat class VariablesTestCase(test.TestCase): + @test_util.run_deprecated_v1 def testInitialization(self): with self.cached_session(): var0 = variables.VariableV1(0.0) @@ -69,6 +71,7 @@ class VariablesTestCase(test.TestCase): self.assertAllClose(0.0, self.evaluate(var0)) self.assertAllClose(1.1, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testInitializationOrder(self): with self.cached_session(): rnd = variables.Variable(random_ops.random_uniform([3, 6]), name="rnd") @@ -107,6 +110,7 @@ class VariablesTestCase(test.TestCase): for _ in variables.Variable([0.0, 1.0]): pass + @test_util.run_deprecated_v1 def testAssignments(self): with self.cached_session(): var = variables.Variable(0.0) @@ -125,6 +129,7 @@ class VariablesTestCase(test.TestCase): self.assertAllClose(4.0, self.evaluate(four)) self.assertAllClose(4.0, self.evaluate(var)) + @test_util.run_deprecated_v1 def testResourceAssignments(self): with self.session(use_gpu=True): var = resource_variable_ops.ResourceVariable(0.0) @@ -181,12 +186,15 @@ class VariablesTestCase(test.TestCase): self.evaluate(count_up_to) self.assertEqual(3, self.evaluate(var)) + @test_util.run_deprecated_v1 def testCountUpToInt32(self): self._countUpToTest(dtypes.int32) + @test_util.run_deprecated_v1 def testCountUpToInt64(self): self._countUpToTest(dtypes.int64) + @test_util.run_deprecated_v1 def testControlDepsNone(self): with self.cached_session(): c = constant_op.constant(1.0) @@ -200,6 +208,7 @@ class VariablesTestCase(test.TestCase): self.assertEqual([], var_x.value().op.control_inputs) self.assertEqual([], var_x._ref().op.control_inputs) # pylint: disable=protected-access + @test_util.run_deprecated_v1 def testControlFlow(self): with self.cached_session() as sess: v0 = variables.Variable(0, name="v0") @@ -236,6 +245,7 @@ class VariablesTestCase(test.TestCase): self.evaluate(v0.initializer) self.evaluate(add) + @test_util.run_deprecated_v1 def testControlFlowInitialization(self): """Expects an error if an initializer is in a control-flow scope.""" def cond(i, _): @@ -249,6 +259,7 @@ class VariablesTestCase(test.TestCase): with self.assertRaisesRegexp(ValueError, "inside a control-flow"): control_flow_ops.while_loop(cond, body, [0, 0]) + @test_util.run_deprecated_v1 def testUseVariableAsTensor(self): with self.cached_session(): var_x = variables.Variable(2.0) @@ -258,6 +269,7 @@ class VariablesTestCase(test.TestCase): self.assertAllClose(3.0, self.evaluate(var_y)) self.assertAllClose(5.0, math_ops.add(var_x, var_y).eval()) + @test_util.run_deprecated_v1 def testZeroSizeVarSameAsConst(self): with self.cached_session(): zero_size_var = variables.Variable(array_ops.zeros([0, 2])) @@ -270,6 +282,7 @@ class VariablesTestCase(test.TestCase): self.assertAllClose(const_mul.eval(), variable_output) self.assertAllClose([[0., 0.], [0., 0.]], variable_output) + @test_util.run_deprecated_v1 def testCachingDevice(self): with self.cached_session(): var = variables.Variable(2.0) @@ -280,6 +293,7 @@ class VariablesTestCase(test.TestCase): self.assertFalse(var_cached.device.startswith("/job:foo")) self.assertTrue(var_cached.value().device.startswith("/job:foo")) + @test_util.run_deprecated_v1 def testCollections(self): with self.cached_session(): var_x = variables.VariableV1(2.0) @@ -295,6 +309,7 @@ class VariablesTestCase(test.TestCase): variables.global_variables()) self.assertEqual([var_x, var_z, var_t], variables.trainable_variables()) + @test_util.run_deprecated_v1 def testCollectionsWithScope(self): with self.cached_session(): with ops.name_scope("scope_1"): @@ -316,6 +331,7 @@ class VariablesTestCase(test.TestCase): getattr(variables.Variable.__add__, attr), getattr(ops.Tensor.__add__, attr)) + @test_util.run_deprecated_v1 def testOperators(self): with self.cached_session(): var_f = variables.Variable([2.0]) @@ -389,12 +405,14 @@ class VariablesTestCase(test.TestCase): self.assertAllClose([[80.0]], self.evaluate(matmul)) self.assertAllClose([[20.0, 30.0], [40.0, 60.0]], self.evaluate(rmatmul)) + @test_util.run_deprecated_v1 def testSession(self): with self.cached_session() as sess: var = variables.Variable([1, 12]) variables.global_variables_initializer().run() self.assertAllClose([1, 12], self.evaluate(var)) + @test_util.run_deprecated_v1 def testColocation(self): with ops.device("/job:ps"): var = variables.VariableV1(0, name="v") @@ -403,6 +421,7 @@ class VariablesTestCase(test.TestCase): self.assertDeviceEqual("/job:ps", assign_op.device) self.assertEqual([b"loc:@v"], assign_op.op.colocation_groups()) + @test_util.run_deprecated_v1 def testInitializerFunction(self): value = [[-42], [133.7]] shape = [2, 1] @@ -440,6 +459,7 @@ class VariablesTestCase(test.TestCase): lambda: constant_op.constant(1.), constraint=constraint) + @test_util.run_deprecated_v1 def testNoRefDataRace(self): with self.cached_session(): a = variables.Variable([1, 2, 3], dtype=dtypes.float32) @@ -450,6 +470,7 @@ class VariablesTestCase(test.TestCase): self.assertAllEqual(b.eval(), [3, 4, 5]) self.assertAllEqual(c.eval(), [5, 6, 7]) + @test_util.run_deprecated_v1 def testInitializerFunctionDevicePlacement(self): with self.cached_session(): initializer = lambda: constant_op.constant(42.0) @@ -468,6 +489,7 @@ class VariablesTestCase(test.TestCase): for i in v2.initializer.inputs: self.assertEqual(expected_group_v2, i.op.colocation_groups()) + @test_util.run_deprecated_v1 def testVariableDefInitializedInstances(self): with ops.Graph().as_default(), self.cached_session() as sess: v_def = variables.Variable( @@ -511,6 +533,7 @@ class VariablesTestCase(test.TestCase): variables.Variable(variable_def=trainable_variable.to_proto()) .trainable) + @test_util.run_deprecated_v1 def testLoad(self): with self.cached_session(): var = variables.Variable(np.zeros((5, 5), np.float32)) @@ -519,6 +542,7 @@ class VariablesTestCase(test.TestCase): self.assertAllClose(np.ones((5, 5), np.float32), self.evaluate(var)) + @test_util.run_deprecated_v1 def testRepr(self): var = variables.VariableV1(np.zeros((5, 5), np.float32), name="noop") self.assertEqual( @@ -552,6 +576,7 @@ class IsInitializedTest(test.TestCase): variables.global_variables_initializer().run() self.assertEqual(0, self.evaluate(uninited).size) + @test_util.run_deprecated_v1 def testVariableList(self): with ops.Graph().as_default(), self.cached_session() as sess: v = variables.VariableV1([1, 2], name="v") @@ -589,6 +614,7 @@ class ObsoleteIsInitializedTest(test.TestCase): with ops.Graph().as_default(): self.assertEqual(None, variables.assert_variables_initialized()) + @test_util.run_deprecated_v1 def testVariables(self): with ops.Graph().as_default(), self.cached_session() as sess: v = variables.VariableV1([1, 2]) @@ -600,6 +626,7 @@ class ObsoleteIsInitializedTest(test.TestCase): variables.global_variables_initializer().run() self.evaluate(inited) + @test_util.run_deprecated_v1 def testVariableList(self): with ops.Graph().as_default(), self.cached_session() as sess: v = variables.VariableV1([1, 2]) diff --git a/tensorflow/python/kernel_tests/weights_broadcast_test.py b/tensorflow/python/kernel_tests/weights_broadcast_test.py index c476004b89..677d8f2f22 100644 --- a/tensorflow/python/kernel_tests/weights_broadcast_test.py +++ b/tensorflow/python/kernel_tests/weights_broadcast_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import dtypes as dtypes_lib from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import weights_broadcast_ops from tensorflow.python.platform import test @@ -51,40 +52,48 @@ class AssertBroadcastableTest(test.TestCase): values_placeholder: values, }) + @test_util.run_deprecated_v1 def testScalar(self): self._test_valid(weights=5, values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def test1x1x1(self): self._test_valid( weights=np.asarray((5,)).reshape((1, 1, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def test1x1xN(self): self._test_valid( weights=np.asarray((5, 7, 11, 3)).reshape((1, 1, 4)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def test1xNx1(self): self._test_valid( weights=np.asarray((5, 11)).reshape((1, 2, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def test1xNxN(self): self._test_valid( weights=np.asarray((5, 7, 11, 3, 2, 13, 7, 5)).reshape((1, 2, 4)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testNx1x1(self): self._test_valid( weights=np.asarray((5, 7, 11)).reshape((3, 1, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testNx1xN(self): self._test_valid( weights=np.asarray(( 5, 7, 11, 3, 2, 12, 7, 5, 2, 17, 11, 3)).reshape((3, 1, 4)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testNxNxN(self): self._test_valid( weights=np.asarray(( @@ -107,29 +116,35 @@ class AssertBroadcastableTest(test.TestCase): values_placeholder: values, }) + @test_util.run_deprecated_v1 def testInvalid1(self): self._test_invalid(weights=np.asarray((5,)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalid1x1(self): self._test_invalid( weights=np.asarray((5,)).reshape((1, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidPrefixMatch(self): self._test_invalid( weights=np.asarray((5, 7, 11, 3, 2, 12)).reshape((3, 2)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidSuffixMatch(self): self._test_invalid( weights=np.asarray((5, 7, 11, 3, 2, 12, 7, 5)).reshape((2, 4)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidOnesExtraDim(self): self._test_invalid( weights=np.asarray((5,)).reshape((1, 1, 1, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidPrefixMatchExtraDim(self): self._test_invalid( weights=np.asarray(( @@ -137,6 +152,7 @@ class AssertBroadcastableTest(test.TestCase): 2, 17, 11, 3, 5, 7, 11, 3, 2, 12, 7, 5)).reshape((3, 2, 4, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidSuffixMatchExtraDim(self): self._test_invalid( weights=np.asarray(( @@ -164,18 +180,21 @@ class BroadcastWeightsTest(test.TestCase): values_placeholder: values, })) + @test_util.run_deprecated_v1 def testScalar(self): self._test_valid( weights=5, values=_test_values((3, 2, 4)), expected=5 * np.ones((3, 2, 4))) + @test_util.run_deprecated_v1 def test1x1x1(self): self._test_valid( weights=np.asarray((5,)).reshape((1, 1, 1)), values=_test_values((3, 2, 4)), expected=5 * np.ones((3, 2, 4))) + @test_util.run_deprecated_v1 def test1x1xN(self): weights = np.asarray((5, 7, 11, 3)).reshape((1, 1, 4)) self._test_valid( @@ -183,6 +202,7 @@ class BroadcastWeightsTest(test.TestCase): values=_test_values((3, 2, 4)), expected=np.tile(weights, reps=(3, 2, 1))) + @test_util.run_deprecated_v1 def test1xNx1(self): weights = np.asarray((5, 11)).reshape((1, 2, 1)) self._test_valid( @@ -190,6 +210,7 @@ class BroadcastWeightsTest(test.TestCase): values=_test_values((3, 2, 4)), expected=np.tile(weights, reps=(3, 1, 4))) + @test_util.run_deprecated_v1 def test1xNxN(self): weights = np.asarray((5, 7, 11, 3, 2, 13, 7, 5)).reshape((1, 2, 4)) self._test_valid( @@ -197,6 +218,7 @@ class BroadcastWeightsTest(test.TestCase): values=_test_values((3, 2, 4)), expected=np.tile(weights, reps=(3, 1, 1))) + @test_util.run_deprecated_v1 def testNx1x1(self): weights = np.asarray((5, 7, 11)).reshape((3, 1, 1)) self._test_valid( @@ -204,6 +226,7 @@ class BroadcastWeightsTest(test.TestCase): values=_test_values((3, 2, 4)), expected=np.tile(weights, reps=(1, 2, 4))) + @test_util.run_deprecated_v1 def testNx1xN(self): weights = np.asarray(( 5, 7, 11, 3, 2, 12, 7, 5, 2, 17, 11, 3)).reshape((3, 1, 4)) @@ -212,6 +235,7 @@ class BroadcastWeightsTest(test.TestCase): values=_test_values((3, 2, 4)), expected=np.tile(weights, reps=(1, 2, 1))) + @test_util.run_deprecated_v1 def testNxNxN(self): weights = np.asarray(( 5, 7, 11, 3, 2, 12, 7, 5, 2, 17, 11, 3, @@ -234,29 +258,35 @@ class BroadcastWeightsTest(test.TestCase): values_placeholder: values, }) + @test_util.run_deprecated_v1 def testInvalid1(self): self._test_invalid(weights=np.asarray((5,)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalid1x1(self): self._test_invalid( weights=np.asarray((5,)).reshape((1, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidPrefixMatch(self): self._test_invalid( weights=np.asarray((5, 7, 11, 3, 2, 12)).reshape((3, 2)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidSuffixMatch(self): self._test_invalid( weights=np.asarray((5, 7, 11, 3, 2, 12, 7, 5)).reshape((2, 4)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidOnesExtraDim(self): self._test_invalid( weights=np.asarray((5,)).reshape((1, 1, 1, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidPrefixMatchExtraDim(self): self._test_invalid( weights=np.asarray(( @@ -264,6 +294,7 @@ class BroadcastWeightsTest(test.TestCase): 2, 17, 11, 3, 5, 7, 11, 3, 2, 12, 7, 5)).reshape((3, 2, 4, 1)), values=_test_values((3, 2, 4))) + @test_util.run_deprecated_v1 def testInvalidSuffixMatchExtraDim(self): self._test_invalid( weights=np.asarray(( diff --git a/tensorflow/python/kernel_tests/where_op_test.py b/tensorflow/python/kernel_tests/where_op_test.py index 9e074b2304..56c1390411 100644 --- a/tensorflow/python/kernel_tests/where_op_test.py +++ b/tensorflow/python/kernel_tests/where_op_test.py @@ -27,6 +27,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import resource_variable_ops @@ -54,6 +55,7 @@ class WhereOpTest(test.TestCase): with self.assertRaises(ValueError): array_ops.where([False, True], None, [1, 2]) + @test_util.run_deprecated_v1 def testBasicVec(self): x = np.asarray([True, False]) truth = np.asarray([[0]], dtype=np.int64) @@ -67,11 +69,13 @@ class WhereOpTest(test.TestCase): truth = np.asarray([[2], [4]], dtype=np.int64) self._testWhere(x, truth) + @test_util.run_deprecated_v1 def testRandomVec(self): x = np.random.rand(1000000) > 0.5 truth = np.vstack([np.where(x)[0].astype(np.int64)]).T self._testWhere(x, truth) + @test_util.run_deprecated_v1 def testBasicMat(self): x = np.asarray([[True, False], [True, False]]) @@ -80,6 +84,7 @@ class WhereOpTest(test.TestCase): self._testWhere(x, truth) + @test_util.run_deprecated_v1 def testBasic3Tensor(self): x = np.asarray([[[True, False], [True, False]], [[False, True], [False, True]], @@ -99,36 +104,47 @@ class WhereOpTest(test.TestCase): truth = np.vstack(truth).T # Convert to [num_true, indices]. self._testWhere(x, truth, expected_err_re) + @test_util.run_deprecated_v1 def testRandomBool(self): self._testRandom(np.bool) + @test_util.run_deprecated_v1 def testRandomInt32(self): self._testRandom(np.int32) + @test_util.run_deprecated_v1 def testRandomInt64(self): self._testRandom(np.int64) + @test_util.run_deprecated_v1 def testRandomFloat(self): self._testRandom(np.float32) + @test_util.run_deprecated_v1 def testRandomDouble(self): self._testRandom(np.float64) + @test_util.run_deprecated_v1 def testRandomComplex64(self): self._testRandom(np.complex64) + @test_util.run_deprecated_v1 def testRandomComplex128(self): self._testRandom(np.complex128) + @test_util.run_deprecated_v1 def testRandomUint8(self): self._testRandom(np.uint8) + @test_util.run_deprecated_v1 def testRandomInt8(self): self._testRandom(np.int8) + @test_util.run_deprecated_v1 def testRandomInt16(self): self._testRandom(np.int16) + @test_util.run_deprecated_v1 def testThreeArgument(self): x = np.array([[-2, 3, -1], [1, -3, -3]]) np_val = np.where(x > 0, x * x, -x) @@ -136,6 +152,7 @@ class WhereOpTest(test.TestCase): tf_val = array_ops.where(constant_op.constant(x) > 0, x * x, -x).eval() self.assertAllEqual(tf_val, np_val) + @test_util.run_deprecated_v1 def testBatchSelect(self): x = np.array([[-2, 3, -1] * 64, [1, -3, -3] * 64] * 8192) # [16384, 192] c_mat = np.array([[False] * 192, [True] * 192] * 8192) # [16384, 192] diff --git a/tensorflow/python/kernel_tests/while_v2_test.py b/tensorflow/python/kernel_tests/while_v2_test.py index e08699922a..09cbeb1a0d 100644 --- a/tensorflow/python/kernel_tests/while_v2_test.py +++ b/tensorflow/python/kernel_tests/while_v2_test.py @@ -43,6 +43,7 @@ from tensorflow.python.platform import test class WhileV2Test(test.TestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testSingleLoopVar(self): x = constant_op.constant(2.) ret = while_loop_v2( @@ -64,6 +65,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertEqual(16., eval_result[0]) self.assertSequenceEqual(sess.run(grad), [32.]) + @test_util.run_deprecated_v1 def testMultipleLoopVarsBasic(self): x = constant_op.constant(5.) y = constant_op.constant(3.) @@ -84,6 +86,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertSequenceEqual(self.evaluate(ret), [45., 3.]) self.assertSequenceEqual(self.evaluate(grad), [9.]) + @test_util.run_deprecated_v1 def testMultipleLoopVars(self): x = constant_op.constant(5.) y = constant_op.constant(3.) @@ -114,6 +117,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertSequenceEqual(self.evaluate(grady_1), [6.]) self.assertSequenceEqual(self.evaluate(grady_2), [61.]) + @test_util.run_deprecated_v1 def testMultipleWhileLoops(self): x = constant_op.constant(2.) ret1 = while_loop_v2( @@ -128,6 +132,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertSequenceEqual(self.evaluate(grad), [32.]) self.assertSequenceEqual(self.evaluate(grad_grad), [48.]) + @test_util.run_deprecated_v1 def testDoubleDerivative(self): x = constant_op.constant(2.) ret = while_loop_v2( @@ -140,6 +145,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertSequenceEqual(self.evaluate(grad), [32.]) self.assertSequenceEqual(self.evaluate(grad_grad), [48.]) + @test_util.run_deprecated_v1 def testPruning(self): x = constant_op.constant(1) @@ -175,6 +181,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): g = GetOptimizedGraph() self.assertEqual(len([n for n in g.node if n.op == "Enter"]), 2) + @test_util.run_deprecated_v1 def testCaptureExternalTensorInCond(self): x = constant_op.constant(2.) y = constant_op.constant(1.) @@ -187,6 +194,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertEqual(self.evaluate(ret), 18.) self.assertSequenceEqual(self.evaluate(grad), [9.]) + @test_util.run_deprecated_v1 def testCaptureExternalTensorInBody(self): x = constant_op.constant(2.) y = constant_op.constant(3.) @@ -197,6 +205,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertEqual(self.evaluate(ret), 18.) self.assertSequenceEqual(self.evaluate(grad), [9.]) + @test_util.run_deprecated_v1 def testLoopWithTensorListPushBack(self): x = constant_op.constant(2.) @@ -219,6 +228,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertEqual(sess.run(ret[0]), 16.) self.assertSequenceEqual(self.evaluate(grad), [32.]) + @test_util.run_deprecated_v1 def testDuplicateAccumulator(self): x = constant_op.constant(2.) @@ -259,6 +269,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ("PartiallyDefinedShape", [None, 2]), ("FullyDefinedShape", [1, 2]), ) + @test_util.run_deprecated_v1 def testAccumulatorElementShape(self, shape): def MatchShape(actual_tensor_shape): @@ -344,6 +355,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): while2_op.get_attr("body").name, r"foo_while_1_body_\d*") @test_util.enable_control_flow_v2 + @test_util.run_deprecated_v1 def testWhileAndTensorArray(self): with self.cached_session() as sess: param = constant_op.constant(2.0) @@ -354,6 +366,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): r = gradients_impl.gradients(r, param)[0] self.assertAllClose(21.0, self.evaluate(r)) + @test_util.run_deprecated_v1 def testNestedWhile(self): # Compute sum of geometric progression: n^0 + n^1 + ... + n^m # We compute the pow using a while loop. @@ -377,6 +390,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertEqual(self.evaluate(result), 364.) self.assertSequenceEqual(self.evaluate(grad), [547.]) + @test_util.run_deprecated_v1 def testIdentityNodeInBody(self): def Body(v): @@ -392,6 +406,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): self.assertEqual(self.evaluate(ret), 16.) self.assertSequenceEqual(self.evaluate(grad), [32.]) + @test_util.run_deprecated_v1 def testNestedWhileAndTensorArray(self): n = constant_op.constant(3.0) diff --git a/tensorflow/python/kernel_tests/xent_op_test.py b/tensorflow/python/kernel_tests/xent_op_test.py index 77669f08cc..f5d03c2370 100644 --- a/tensorflow/python/kernel_tests/xent_op_test.py +++ b/tensorflow/python/kernel_tests/xent_op_test.py @@ -27,6 +27,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_nn_ops from tensorflow.python.ops import gradient_checker @@ -88,6 +89,7 @@ class XentTest(test.TestCase): self._testSingleClass(True) self._testSingleClass(False) + @test_util.run_deprecated_v1 def testRankTooLarge(self): for dtype in np.float16, np.float32: np_features = np.array([[[1., 1., 1., 1.]], [[1., 2., 3., @@ -152,12 +154,14 @@ class XentTest(test.TestCase): self.assertAllCloseAccordingToType(np_loss, tf_loss) self.assertAllCloseAccordingToType(np_backprop, tf_backprop) + @test_util.run_deprecated_v1 def testShapeMismatch(self): with self.cached_session(): with self.assertRaises(ValueError): gen_nn_ops.softmax_cross_entropy_with_logits( [[0., 1.], [2., 3.]], [[0., 1., 0.], [1., 0., 0.]]) + @test_util.run_deprecated_v1 def testNotMatrix(self): with self.cached_session(): with self.assertRaises(ValueError): @@ -179,6 +183,7 @@ class XentTest(test.TestCase): np.array([[1., 1., 1., 1.], [1., 2., 3., 4.]]).astype(np.float64), np.array([[0., 0., 0., 1.], [0., .5, .5, 0.]]).astype(np.float64)) + @test_util.run_deprecated_v1 def testGradient(self): with self.cached_session() as sess: l = constant_op.constant( @@ -206,6 +211,7 @@ class XentTest(test.TestCase): print("cross entropy gradient err = ", err) self.assertLess(err, 5e-8) + @test_util.run_deprecated_v1 def testGradientLabelWithV2(self): with self.cached_session(): l = constant_op.constant( @@ -224,6 +230,7 @@ class XentTest(test.TestCase): self.assertLess(err, 5e-8) + @test_util.run_deprecated_v1 def testSecondGradient(self): with self.cached_session() as sess: l = constant_op.constant( diff --git a/tensorflow/python/kernel_tests/zero_division_test.py b/tensorflow/python/kernel_tests/zero_division_test.py index 7c82f9320a..3dd9ec4ba9 100644 --- a/tensorflow/python/kernel_tests/zero_division_test.py +++ b/tensorflow/python/kernel_tests/zero_division_test.py @@ -27,6 +27,7 @@ from tensorflow.python.platform import test class ZeroDivisionTest(test.TestCase): + @test_util.run_deprecated_v1 def testZeros(self): with test_util.use_gpu(): for dtype in dtypes.uint8, dtypes.int16, dtypes.int32, dtypes.int64: diff --git a/tensorflow/python/layers/base_test.py b/tensorflow/python/layers/base_test.py index 45099677e0..d0ec4f4425 100644 --- a/tensorflow/python/layers/base_test.py +++ b/tensorflow/python/layers/base_test.py @@ -143,6 +143,7 @@ class BaseLayerTest(test.TestCase): synchronization=variable_scope.VariableSynchronization.ON_READ, trainable=True) + @test_util.run_deprecated_v1 def testReusePartitionedVaraiblesAndRegularizers(self): regularizer = lambda x: math_ops.reduce_sum(x) * 1e-3 partitioner = partitioned_variables.fixed_size_partitioner(3) @@ -445,6 +446,7 @@ class BaseLayerTest(test.TestCase): self.assertTrue(isinstance(result, dict)) self.assertEqual(set(['label', 'logits']), set(result.keys())) + @test_util.run_deprecated_v1 def testActivityRegularizer(self): regularizer = math_ops.reduce_sum layer = base_layers.Layer(activity_regularizer=regularizer) @@ -533,6 +535,7 @@ class BaseLayerTest(test.TestCase): self.assertEqual(len(layer.trainable_variables), 1) self.assertEqual(layer.variables[0].graph, outer_graph) + @test_util.run_deprecated_v1 def testGetUpdateFor(self): class MyLayer(base_layers.Layer): @@ -577,6 +580,7 @@ class BaseLayerTest(test.TestCase): self.assertEqual(len(layer.get_updates_for([intermediate_inputs])), 1) self.assertEqual(len(layer.get_updates_for([outputs])), 0) + @test_util.run_deprecated_v1 def testGetLossesFor(self): class MyLayer(base_layers.Layer): diff --git a/tensorflow/python/layers/convolutional_test.py b/tensorflow/python/layers/convolutional_test.py index d3200fa5b5..a3e493edfe 100644 --- a/tensorflow/python/layers/convolutional_test.py +++ b/tensorflow/python/layers/convolutional_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.layers import convolutional as conv_layers from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops @@ -59,6 +60,7 @@ class ConvTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'kernel_size'): conv_layers.conv2d(images, 32, None) + @test_util.run_deprecated_v1 def testCreateConv2D(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -87,6 +89,7 @@ class ConvTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 3, 4, 32]) self.assertListEqual(layer.bias.get_shape().as_list(), [32]) + @test_util.run_deprecated_v1 def testCreateConv2DChannelsFirst(self): height, width = 7, 9 images = random_ops.random_uniform((5, 4, height, width)) @@ -97,6 +100,7 @@ class ConvTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 3, 4, 32]) self.assertListEqual(layer.bias.get_shape().as_list(), [32]) + @test_util.run_deprecated_v1 def testUnknownInputChannels(self): images = array_ops.placeholder(dtypes.float32, (5, 7, 9, None)) layer = conv_layers.Conv2D(32, [3, 3], activation=nn_ops.relu) @@ -140,6 +144,7 @@ class ConvTest(test.TestCase): self.assertListEqual(output.get_shape().as_list(), [5, height / 2, width, 32]) + @test_util.run_deprecated_v1 def testCreateConv1D(self): width = 7 data = random_ops.random_uniform((5, width, 4)) @@ -156,6 +161,7 @@ class ConvTest(test.TestCase): output = conv_layers.conv1d(data, 32, 3, activation=nn_ops.relu) self.assertListEqual(output.get_shape().as_list(), [5, width - 2, 32]) + @test_util.run_deprecated_v1 def testCreateConv1DChannelsFirst(self): width = 7 data = random_ops.random_uniform((5, 4, width)) @@ -165,6 +171,7 @@ class ConvTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 4, 32]) self.assertListEqual(layer.bias.get_shape().as_list(), [32]) + @test_util.run_deprecated_v1 def testUnknownInputChannelsConv1D(self): data = array_ops.placeholder(dtypes.float32, (5, 4, None)) layer = conv_layers.Conv1D(32, 3, activation=nn_ops.relu) @@ -180,6 +187,7 @@ class ConvTest(test.TestCase): 'should be defined. Found `None`.'): _ = layer.apply(data) + @test_util.run_deprecated_v1 def testCreateConv3D(self): depth, height, width = 6, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 4)) @@ -191,6 +199,7 @@ class ConvTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 3, 3, 4, 32]) self.assertListEqual(layer.bias.get_shape().as_list(), [32]) + @test_util.run_deprecated_v1 def testUnknownInputChannelsConv3D(self): volumes = array_ops.placeholder(dtypes.float32, (5, 6, 7, 9, None)) layer = conv_layers.Conv3D(32, [3, 3, 3], activation=nn_ops.relu) @@ -199,6 +208,7 @@ class ConvTest(test.TestCase): 'should be defined. Found `None`.'): _ = layer.apply(volumes) + @test_util.run_deprecated_v1 def testConv2DKernelRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -210,6 +220,7 @@ class ConvTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testConv2DBiasRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -221,6 +232,7 @@ class ConvTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testConv2DNoBias(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -247,6 +259,7 @@ class ConvTest(test.TestCase): output = layer.apply(images) self.assertListEqual(output.get_shape().as_list(), [5, height - 2, 3, 32]) + @test_util.run_deprecated_v1 def testFunctionalConv2DReuse(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 3), seed=1) @@ -255,6 +268,7 @@ class ConvTest(test.TestCase): conv_layers.conv2d(images, 32, [3, 3], name='conv1', reuse=True) self.assertEqual(len(variables.trainable_variables()), 2) + @test_util.run_deprecated_v1 def testFunctionalConv2DReuseFromScope(self): with variable_scope.variable_scope('scope'): height, width = 7, 9 @@ -265,6 +279,7 @@ class ConvTest(test.TestCase): conv_layers.conv2d(images, 32, [3, 3], name='conv1') self.assertEqual(len(variables.trainable_variables()), 2) + @test_util.run_deprecated_v1 def testFunctionalConv2DInitializerFromScope(self): with self.cached_session() as sess: with variable_scope.variable_scope( @@ -283,6 +298,7 @@ class ConvTest(test.TestCase): # Check that the bias still got initialized to zeros. self.assertAllClose(weights[1], np.zeros((32))) + @test_util.run_deprecated_v1 def testFunctionalConv2DNoReuse(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 3), seed=1) @@ -325,6 +341,7 @@ class ConvTest(test.TestCase): self.assertEqual(conv3d.kernel_constraint, k_constraint) self.assertEqual(conv3d.bias_constraint, b_constraint) + @test_util.run_deprecated_v1 def testConv3DChannelsFirst(self): # Test case for GitHub issue 15655 images = array_ops.placeholder( @@ -358,6 +375,7 @@ class SeparableConv1DTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'kernel_size'): conv_layers.separable_conv1d(data, 32, None) + @test_util.run_deprecated_v1 def testCreateSeparableConv1D(self): length = 9 data = random_ops.random_uniform((5, length, 4)) @@ -379,6 +397,7 @@ class SeparableConv1DTest(test.TestCase): self.assertEqual(layer.pointwise_kernel.get_shape().as_list(), [1, 8, 32]) self.assertEqual(layer.bias.get_shape().as_list(), [32]) + @test_util.run_deprecated_v1 def testCreateSeparableConv1DChannelsFirst(self): length = 9 data = random_ops.random_uniform((5, 4, length)) @@ -404,6 +423,7 @@ class SeparableConv1DTest(test.TestCase): output = layer.apply(data) self.assertEqual(output.get_shape().as_list(), [5, length // 2, 32]) + @test_util.run_deprecated_v1 def testCreateSeparableConv1DWithStridesChannelsFirst(self): data_format = 'channels_first' length = 10 @@ -413,6 +433,7 @@ class SeparableConv1DTest(test.TestCase): output = layer.apply(data) self.assertEqual(output.get_shape().as_list(), [5, 32, length // 2]) + @test_util.run_deprecated_v1 def testFunctionalConv1DReuse(self): length = 10 data = random_ops.random_uniform((5, length, 3), seed=1) @@ -421,6 +442,7 @@ class SeparableConv1DTest(test.TestCase): conv_layers.separable_conv1d(data, 32, 3, name='sepconv1', reuse=True) self.assertEqual(len(variables.trainable_variables()), 3) + @test_util.run_deprecated_v1 def testFunctionalConv1DReuseFromScope(self): with variable_scope.variable_scope('scope'): length = 10 @@ -431,6 +453,7 @@ class SeparableConv1DTest(test.TestCase): conv_layers.separable_conv1d(data, 32, 3, name='sepconv1') self.assertEqual(len(variables.trainable_variables()), 3) + @test_util.run_deprecated_v1 def testFunctionalConv1DNoReuse(self): length = 10 data = random_ops.random_uniform((5, length, 3), seed=1) @@ -439,6 +462,7 @@ class SeparableConv1DTest(test.TestCase): conv_layers.separable_conv1d(data, 32, 3) self.assertEqual(len(variables.trainable_variables()), 6) + @test_util.run_deprecated_v1 def testSeparableConv1DDepthwiseRegularizer(self): length = 9 data = random_ops.random_uniform((5, length, 4)) @@ -450,6 +474,7 @@ class SeparableConv1DTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testSeparableConv1DPointwiseRegularizer(self): length = 9 data = random_ops.random_uniform((5, length, 4)) @@ -461,6 +486,7 @@ class SeparableConv1DTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testSeparableConv1DBiasRegularizer(self): length = 9 data = random_ops.random_uniform((5, length, 4)) @@ -472,6 +498,7 @@ class SeparableConv1DTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testSeparableConv1DNoBias(self): length = 9 data = random_ops.random_uniform((5, length, 4)) @@ -522,6 +549,7 @@ class SeparableConv2DTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'kernel_size'): conv_layers.separable_conv2d(images, 32, None) + @test_util.run_deprecated_v1 def testCreateSeparableConv2D(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -562,6 +590,7 @@ class SeparableConv2DTest(test.TestCase): [1, 1, 4, 32]) self.assertListEqual(layer.bias.get_shape().as_list(), [32]) + @test_util.run_deprecated_v1 def testCreateSeparableConv2DChannelsFirst(self): height, width = 7, 9 images = random_ops.random_uniform((5, 4, height, width)) @@ -584,6 +613,7 @@ class SeparableConv2DTest(test.TestCase): output = layer.apply(images) self.assertListEqual(output.get_shape().as_list(), [5, height, width, 64]) + @test_util.run_deprecated_v1 def testCreateSeparableConvWithStrides(self): height, width = 6, 8 # Test strides tuple @@ -607,6 +637,7 @@ class SeparableConv2DTest(test.TestCase): self.assertListEqual(output.get_shape().as_list(), [5, height / 2, width, 32]) + @test_util.run_deprecated_v1 def testCreateSeparableConvWithStridesChannelsFirst(self): data_format = 'channels_first' height, width = 6, 8 @@ -632,6 +663,7 @@ class SeparableConv2DTest(test.TestCase): self.assertListEqual(output.get_shape().as_list(), [5, 32, height / 2, width]) + @test_util.run_deprecated_v1 def testFunctionalConv2DReuse(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 3), seed=1) @@ -641,6 +673,7 @@ class SeparableConv2DTest(test.TestCase): images, 32, [3, 3], name='sepconv1', reuse=True) self.assertEqual(len(variables.trainable_variables()), 3) + @test_util.run_deprecated_v1 def testFunctionalConv2DReuseFromScope(self): with variable_scope.variable_scope('scope'): height, width = 7, 9 @@ -651,6 +684,7 @@ class SeparableConv2DTest(test.TestCase): conv_layers.separable_conv2d(images, 32, [3, 3], name='sepconv1') self.assertEqual(len(variables.trainable_variables()), 3) + @test_util.run_deprecated_v1 def testFunctionalConv2DInitializerFromScope(self): with self.cached_session() as sess: with variable_scope.variable_scope( @@ -671,6 +705,7 @@ class SeparableConv2DTest(test.TestCase): # Check that the bias still got initialized to zeros. self.assertAllClose(weights[2], np.zeros((32))) + @test_util.run_deprecated_v1 def testFunctionalConv2DNoReuse(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 3), seed=1) @@ -679,6 +714,7 @@ class SeparableConv2DTest(test.TestCase): conv_layers.separable_conv2d(images, 32, [3, 3]) self.assertEqual(len(variables.trainable_variables()), 6) + @test_util.run_deprecated_v1 def testSeparableConv2DDepthwiseRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -690,6 +726,7 @@ class SeparableConv2DTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testSeparableConv2DPointwiseRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -701,6 +738,7 @@ class SeparableConv2DTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testSeparableConv2DBiasRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -712,6 +750,7 @@ class SeparableConv2DTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testSeparableConv2DNoBias(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -768,6 +807,7 @@ class Conv2DTransposeTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'kernel_size'): conv_layers.conv2d_transpose(images, 32, None) + @test_util.run_deprecated_v1 def testCreateConv2DTranspose(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -839,6 +879,7 @@ class Conv2DTransposeTest(test.TestCase): self.assertListEqual(output.get_shape().as_list(), [5, height * 2, width, 32]) + @test_util.run_deprecated_v1 def testConv2DTransposeKernelRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -850,6 +891,7 @@ class Conv2DTransposeTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testConv2DTransposeBiasRegularizer(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -861,6 +903,7 @@ class Conv2DTransposeTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testConv2DTransposeNoBias(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 4)) @@ -873,6 +916,7 @@ class Conv2DTransposeTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 3, 32, 4]) self.assertEqual(layer.bias, None) + @test_util.run_deprecated_v1 def testFunctionalConv2DTransposeReuse(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 3), seed=1) @@ -881,6 +925,7 @@ class Conv2DTransposeTest(test.TestCase): conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1', reuse=True) self.assertEqual(len(variables.trainable_variables()), 2) + @test_util.run_deprecated_v1 def testFunctionalConv2DTransposeReuseFromScope(self): with variable_scope.variable_scope('scope'): height, width = 7, 9 @@ -891,6 +936,7 @@ class Conv2DTransposeTest(test.TestCase): conv_layers.conv2d_transpose(images, 32, [3, 3], name='deconv1') self.assertEqual(len(variables.trainable_variables()), 2) + @test_util.run_deprecated_v1 def testFunctionalConv2DTransposeInitializerFromScope(self): with self.cached_session() as sess: with variable_scope.variable_scope( @@ -909,6 +955,7 @@ class Conv2DTransposeTest(test.TestCase): # Check that the bias still got initialized to zeros. self.assertAllClose(weights[1], np.zeros((32))) + @test_util.run_deprecated_v1 def testFunctionalConv2DTransposeNoReuse(self): height, width = 7, 9 images = random_ops.random_uniform((5, height, width, 3), seed=1) @@ -955,6 +1002,7 @@ class Conv3DTransposeTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'kernel_size'): conv_layers.conv3d_transpose(volumes, 4, None) + @test_util.run_deprecated_v1 def testCreateConv3DTranspose(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 32)) @@ -976,6 +1024,7 @@ class Conv3DTransposeTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 3, 3, 4, 32]) self.assertListEqual(layer.bias.get_shape().as_list(), [4]) + @test_util.run_deprecated_v1 def testCreateConv3DTransposeChannelsFirst(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, 32, depth, height, width)) @@ -1019,6 +1068,7 @@ class Conv3DTransposeTest(test.TestCase): self.assertListEqual(output.get_shape().as_list(), [5, depth * 2, height, width, 4]) + @test_util.run_deprecated_v1 def testConv3DTransposeKernelRegularizer(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 32)) @@ -1030,6 +1080,7 @@ class Conv3DTransposeTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testConv3DTransposeBiasRegularizer(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 32)) @@ -1041,6 +1092,7 @@ class Conv3DTransposeTest(test.TestCase): self.evaluate([v.initializer for v in layer.variables]) self.assertListEqual(self.evaluate(layer.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testConv3DTransposeNoBias(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 32)) @@ -1053,6 +1105,7 @@ class Conv3DTransposeTest(test.TestCase): self.assertListEqual(layer.kernel.get_shape().as_list(), [3, 3, 3, 4, 32]) self.assertEqual(layer.bias, None) + @test_util.run_deprecated_v1 def testFunctionalConv3DTransposeReuse(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 32), seed=1) @@ -1062,6 +1115,7 @@ class Conv3DTransposeTest(test.TestCase): volumes, 4, [3, 3, 3], name='deconv1', reuse=True) self.assertEqual(len(variables.trainable_variables()), 2) + @test_util.run_deprecated_v1 def testFunctionalConv3DTransposeReuseFromScope(self): with variable_scope.variable_scope('scope'): depth, height, width = 5, 7, 9 @@ -1072,6 +1126,7 @@ class Conv3DTransposeTest(test.TestCase): conv_layers.conv3d_transpose(volumes, 4, [3, 3, 3], name='deconv1') self.assertEqual(len(variables.trainable_variables()), 2) + @test_util.run_deprecated_v1 def testFunctionalConv3DTransposeInitializerFromScope(self): with self.cached_session() as sess: with variable_scope.variable_scope( @@ -1091,6 +1146,7 @@ class Conv3DTransposeTest(test.TestCase): # Check that the bias still got initialized to zeros. self.assertAllClose(weights[1], np.zeros((4))) + @test_util.run_deprecated_v1 def testFunctionalConv3DTransposeNoReuse(self): depth, height, width = 5, 7, 9 volumes = random_ops.random_uniform((5, depth, height, width, 32), seed=1) diff --git a/tensorflow/python/layers/core_test.py b/tensorflow/python/layers/core_test.py index a61639b2db..cf6f0fbb70 100644 --- a/tensorflow/python/layers/core_test.py +++ b/tensorflow/python/layers/core_test.py @@ -59,6 +59,7 @@ class DenseTest(test.TestCase): dense.apply(random_ops.random_uniform((5, 2))) self.assertEqual(dense.name, 'dense_2') + @test_util.run_deprecated_v1 def testVariableInput(self): with self.cached_session(): v = variable_scope.get_variable( @@ -140,6 +141,7 @@ class DenseTest(test.TestCase): outputs = dense.apply(inputs) self.assertEqual(outputs.get_shape().as_list(), [1, 2, 4, 7]) + @test_util.run_deprecated_v1 def testCallOnPlaceHolder(self): inputs = array_ops.placeholder(dtype=dtypes.float32) dense = core_layers.Dense(4, name='my_dense') @@ -179,6 +181,7 @@ class DenseTest(test.TestCase): if not context.executing_eagerly(): self.assertEqual(outputs.op.name, 'dense2/BiasAdd') + @test_util.run_deprecated_v1 def testActivityRegularizer(self): regularizer = lambda x: math_ops.reduce_sum(x) * 1e-3 dense = core_layers.Dense( @@ -189,6 +192,7 @@ class DenseTest(test.TestCase): self.assertEqual(len(loss_keys), 1) self.assertListEqual(dense.losses, loss_keys) + @test_util.run_deprecated_v1 def testKernelRegularizer(self): regularizer = lambda x: math_ops.reduce_sum(x) * 1e-3 dense = core_layers.Dense( @@ -200,6 +204,7 @@ class DenseTest(test.TestCase): self.evaluate([v.initializer for v in dense.variables]) self.assertAllEqual(self.evaluate(dense.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testKernelRegularizerWithReuse(self): regularizer = lambda x: math_ops.reduce_sum(x) * 1e-3 inputs = random_ops.random_uniform((5, 3), seed=1) @@ -212,6 +217,7 @@ class DenseTest(test.TestCase): self.assertEqual( len(ops.get_collection(ops.GraphKeys.REGULARIZATION_LOSSES)), 1) + @test_util.run_deprecated_v1 def testBiasRegularizer(self): regularizer = lambda x: math_ops.reduce_sum(x) * 1e-3 dense = core_layers.Dense(2, name='my_dense', bias_regularizer=regularizer) @@ -222,6 +228,7 @@ class DenseTest(test.TestCase): self.evaluate([v.initializer for v in dense.variables]) self.assertAllEqual(self.evaluate(dense.losses), self.evaluate(loss_keys)) + @test_util.run_deprecated_v1 def testFunctionalDense(self): with self.cached_session(): inputs = random_ops.random_uniform((5, 3), seed=1) @@ -231,6 +238,7 @@ class DenseTest(test.TestCase): len(ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)), 2) self.assertEqual(outputs.op.name, 'my_dense/Relu') + @test_util.run_deprecated_v1 def testFunctionalDenseTwice(self): inputs = random_ops.random_uniform((5, 3), seed=1) core_layers.dense(inputs, 2) @@ -262,6 +270,7 @@ class DenseTest(test.TestCase): vars2 = variables.trainable_variables() self.assertEqual(vars1, vars2) + @test_util.run_deprecated_v1 def testFunctionalDenseInitializerFromScope(self): with variable_scope.variable_scope( 'scope', @@ -307,6 +316,7 @@ class DenseTest(test.TestCase): core_layers.dense(inputs, 2) self.assertEqual(called[0], 2) + @test_util.run_deprecated_v1 def testFunctionalDenseInScope(self): with self.cached_session(): with variable_scope.variable_scope('test'): @@ -393,6 +403,7 @@ class DropoutTest(test.TestCase): np_output = self.evaluate(dropped) self.assertAllClose(np.ones((5, 3)), np_output) + @test_util.run_deprecated_v1 def testDynamicLearningPhase(self): with self.cached_session() as sess: dp = core_layers.Dropout(0.5, seed=1) @@ -426,6 +437,7 @@ class DropoutTest(test.TestCase): self.assertAlmostEqual(0., np_output.min()) self.assertAllClose(np_output[:, 0, :], np_output[:, 1, :]) + @test_util.run_deprecated_v1 def testFunctionalDropout(self): with self.cached_session(): inputs = array_ops.ones((5, 5)) @@ -437,6 +449,7 @@ class DropoutTest(test.TestCase): np_output = self.evaluate(dropped) self.assertAllClose(np.ones((5, 5)), np_output) + @test_util.run_deprecated_v1 def testDynamicRate(self): with self.cached_session() as sess: rate = array_ops.placeholder(dtype='float32', name='rate') @@ -452,6 +465,7 @@ class DropoutTest(test.TestCase): class FlattenTest(test.TestCase): + @test_util.run_deprecated_v1 def testCreateFlatten(self): with self.cached_session() as sess: x = array_ops.placeholder(shape=(None, 2, 3), dtype='float32') @@ -476,6 +490,7 @@ class FlattenTest(test.TestCase): shape = core_layers.Flatten().compute_output_shape((None, 3, None)) self.assertEqual(shape.as_list(), [None, None]) + @test_util.run_deprecated_v1 def testDataFormat5d(self): np_input_channels_last = np.arange( 120, dtype='float32').reshape([1, 5, 4, 3, 2]) @@ -493,6 +508,7 @@ class FlattenTest(test.TestCase): self.assertAllEqual(np_output_cl, np_output_cf) + @test_util.run_deprecated_v1 def testDataFormat4d(self): np_input_channels_last = np.arange( 24, dtype='float32').reshape([1, 4, 3, 2]) @@ -510,16 +526,19 @@ class FlattenTest(test.TestCase): self.assertAllEqual(np_output_cl, np_output_cf) + @test_util.run_deprecated_v1 def testFunctionalFlatten(self): x = array_ops.placeholder(shape=(None, 2, 3), dtype='float32') y = core_layers.flatten(x, name='flatten') self.assertEqual(y.get_shape().as_list(), [None, 6]) + @test_util.run_deprecated_v1 def testFlattenValueError(self): x = array_ops.placeholder(shape=(None,), dtype='float32') with self.assertRaises(ValueError): core_layers.Flatten()(x) + @test_util.run_deprecated_v1 def testFlattenUnknownAxes(self): with self.cached_session() as sess: x = array_ops.placeholder(shape=(5, None, None), dtype='float32') diff --git a/tensorflow/python/layers/normalization_test.py b/tensorflow/python/layers/normalization_test.py index cc3badbde1..07d8e40b75 100644 --- a/tensorflow/python/layers/normalization_test.py +++ b/tensorflow/python/layers/normalization_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.core.protobuf import saver_pb2 from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.layers import convolutional as conv_layers from tensorflow.python.layers import normalization as normalization_layers from tensorflow.python.ops import array_ops @@ -143,6 +144,7 @@ class BNTest(test.TestCase): return train_vars, loss_val + @test_util.run_deprecated_v1 def testHalfPrecision(self): ref_vars, ref_loss = self._trainEvalSequence( dtype=dtypes.float32, @@ -228,33 +230,43 @@ class BNTest(test.TestCase): ckpt_b_use_gpu, use_gpu_test_a, use_gpu_test_b, freeze_mode) + @test_util.run_deprecated_v1 def testCheckpointFusedCPUAndFusedGPU(self): self._testCheckpointCrossDevice(True, False, True, True) + @test_util.run_deprecated_v1 def testCheckpointFusedCPUAndFusedCPU(self): self._testCheckpointCrossDevice(True, False, True, False) + @test_util.run_deprecated_v1 def testCheckpointFusedGPUAndFusedGPU(self): self._testCheckpointCrossDevice(True, True, True, True) + @test_util.run_deprecated_v1 def testCheckpointNonFusedCPUAndNonFusedGPU(self): self._testCheckpointCrossDevice(False, False, False, True) + @test_util.run_deprecated_v1 def testCheckpointNonFusedCPUAndNonFusedCPU(self): self._testCheckpointCrossDevice(False, False, False, False) + @test_util.run_deprecated_v1 def testCheckpointNonFusedGPUAndNonFusedGPU(self): self._testCheckpointCrossDevice(False, True, False, True) + @test_util.run_deprecated_v1 def testCheckpointNonFusedGPUAndFusedGPU(self): self._testCheckpointCrossDevice(False, True, True, True) + @test_util.run_deprecated_v1 def testCheckpointNonFusedGPUAndFusedCPU(self): self._testCheckpointCrossDevice(False, True, True, False) + @test_util.run_deprecated_v1 def testCheckpointNonFusedCPUAndFusedCPU(self): self._testCheckpointCrossDevice(False, False, True, False) + @test_util.run_deprecated_v1 def testCreateBN(self): # Call layer. bn = normalization_layers.BatchNormalization(axis=1) @@ -281,6 +293,7 @@ class BNTest(test.TestCase): ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES), bn.trainable_variables) + @test_util.run_deprecated_v1 def testCreateFusedBNFloat16(self): # Call layer. bn = normalization_layers.BatchNormalization(axis=1, fused=True) @@ -310,6 +323,7 @@ class BNTest(test.TestCase): ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES), bn.trainable_variables) + @test_util.run_deprecated_v1 def test3DInputAxis1(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -353,6 +367,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def test3DInputAxis2(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -436,6 +451,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def test4DInputAxis2(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -477,6 +493,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def test4DInputAxis3(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -518,6 +535,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def test4DInputAxis3Fused(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -601,6 +619,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def testNegativeAxis(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -643,6 +662,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def testBooleanLearningPhase(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -683,6 +703,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def testFunctionalNoReuse(self): inputs = variables.Variable( np.random.random((5, 4, 3, 6)), dtype=dtypes.float32) @@ -735,6 +756,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def testFunctionalReuse(self): inputs1 = variables.Variable( np.random.random((5, 4, 3, 6)), dtype=dtypes.float32) @@ -799,6 +821,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=2) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def testFunctionalReuseFromScope(self): inputs = variables.Variable( np.random.random((5, 4, 3, 6)), dtype=dtypes.float32) @@ -813,6 +836,7 @@ class BNTest(test.TestCase): inputs, axis=-1, momentum=0.9, epsilon=epsilon, training=training) self.assertEqual(len(variables.global_variables()), 5) + @test_util.run_deprecated_v1 def testNoCenter(self): bn = normalization_layers.BatchNormalization(axis=1, center=False) inputs = random_ops.random_uniform((5, 4, 3), seed=1) @@ -828,6 +852,7 @@ class BNTest(test.TestCase): self.assertEqual(len(bn.trainable_variables), 1) self.assertEqual(len(bn.non_trainable_variables), 2) + @test_util.run_deprecated_v1 def testNoScale(self): bn = normalization_layers.BatchNormalization(axis=1, scale=False) inputs = random_ops.random_uniform((5, 4, 3), seed=1) @@ -843,6 +868,7 @@ class BNTest(test.TestCase): self.assertEqual(len(bn.trainable_variables), 1) self.assertEqual(len(bn.non_trainable_variables), 2) + @test_util.run_deprecated_v1 def testRegularizers(self): reg = lambda x: 0.1 * math_ops.reduce_sum(x) bn = normalization_layers.BatchNormalization(axis=1, beta_regularizer=reg) @@ -868,6 +894,7 @@ class BNTest(test.TestCase): self.assertEqual(bn.gamma_constraint, g_constraint) self.assertEqual(bn.beta_constraint, b_constraint) + @test_util.run_deprecated_v1 def testRenorm(self): shape = (4, 3) xt = array_ops.placeholder(dtypes.float32, shape) @@ -926,6 +953,7 @@ class BNTest(test.TestCase): self.assertAllClose(y_train, yt_val_train, atol=1e-5) self.assertAllClose(y_test, yt_val_test, atol=1e-5) + @test_util.run_deprecated_v1 def testAdjustment(self): shape = (4, 3) xt = array_ops.placeholder(dtypes.float32, shape) @@ -970,6 +998,7 @@ class BNTest(test.TestCase): self.assertAllClose(y_train, yt_val_train, atol=1e-5) self.assertAllClose(y_test, yt_val_test, atol=1e-5) + @test_util.run_deprecated_v1 def testRenormWithAdjustment(self): shape = (4, 3) xt = array_ops.placeholder(dtypes.float32, shape) @@ -1040,6 +1069,7 @@ class BNTest(test.TestCase): normalization_layers.batch_normalization( inp, virtual_batch_size=-1) + @test_util.run_deprecated_v1 def testGhostBNVirtualBatchFull(self): shape = [6, 5, 4, 3] inp = random_ops.random_uniform(shape, seed=1) @@ -1065,6 +1095,7 @@ class BNTest(test.TestCase): inp, virtual_batch_size=3) self.assertListEqual(out.shape.as_list(), shape) + @test_util.run_deprecated_v1 def testGhostBNUnknownBatchSize(self): np_shape = [10, 5, 4] tf_shape = [None, 5, 4] @@ -1080,6 +1111,7 @@ class BNTest(test.TestCase): self.assertListEqual(list(y.shape), np_shape) + @test_util.run_deprecated_v1 def testGhostBN2Dims(self): shape = [6, 2] virtual_batch_size = 3 @@ -1133,6 +1165,7 @@ class BNTest(test.TestCase): self.assertAllClose(y_train, y_val_train, atol=1e-5) self.assertAllClose(y_test, y_val_test, atol=1e-5) + @test_util.run_deprecated_v1 def testGhostBN4DimsAxis3(self): shape = [6, 10, 10, 3] virtual_batch_size = 2 @@ -1186,6 +1219,7 @@ class BNTest(test.TestCase): self.assertAllClose(y_train, y_val_train, atol=1e-2) self.assertAllClose(y_test, y_val_test, atol=1e-2) + @test_util.run_deprecated_v1 def testGhostBN4DimsAxis1(self): shape = [6, 3, 10, 10] virtual_batch_size = 2 @@ -1256,6 +1290,7 @@ class BNTest(test.TestCase): normalization_layers.batch_normalization( inp, axis=[1, 2, 1]) # duplicate + @test_util.run_deprecated_v1 def test3DInputMultiAxis12(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -1297,6 +1332,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def test5DInputMultiAxis123(self): epsilon = 1e-3 bn = normalization_layers.BatchNormalization( @@ -1338,6 +1374,7 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.mean(normed_np_output), 0., places=1) self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) + @test_util.run_deprecated_v1 def testGhostBN5DimsMultiAxis14(self): shape = [6, 3, 10, 10, 4] virtual_batch_size = 3 diff --git a/tensorflow/python/layers/pooling_test.py b/tensorflow/python/layers/pooling_test.py index 7533674e5a..cf1fa1e691 100644 --- a/tensorflow/python/layers/pooling_test.py +++ b/tensorflow/python/layers/pooling_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.layers import pooling as pooling_layers from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops @@ -64,6 +65,7 @@ class PoolingTest(test.TestCase): output = layer.apply(images) self.assertListEqual(output.get_shape().as_list(), [5, 3, 4, 4]) + @test_util.run_deprecated_v1 def testCreateMaxPooling2DChannelsFirst(self): height, width = 7, 9 images = random_ops.random_uniform((5, 2, height, width)) @@ -73,6 +75,7 @@ class PoolingTest(test.TestCase): output = layer.apply(images) self.assertListEqual(output.get_shape().as_list(), [5, 2, 6, 8]) + @test_util.run_deprecated_v1 def testCreateAveragePooling2DChannelsFirst(self): height, width = 5, 6 images = random_ops.random_uniform((3, 4, height, width)) @@ -83,6 +86,7 @@ class PoolingTest(test.TestCase): output = layer.apply(images) self.assertListEqual(output.get_shape().as_list(), [3, 4, 4, 5]) + @test_util.run_deprecated_v1 def testCreateAveragePooling2DChannelsFirstWithNoneBatch(self): height, width = 5, 6 images = array_ops.placeholder(dtype='float32', diff --git a/tensorflow/python/ops/bitwise_ops_test.py b/tensorflow/python/ops/bitwise_ops_test.py index 739278273b..d154b6759b 100644 --- a/tensorflow/python/ops/bitwise_ops_test.py +++ b/tensorflow/python/ops/bitwise_ops_test.py @@ -34,6 +34,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): def __init__(self, method_name="runTest"): super(BitwiseOpTest, self).__init__(method_name) + @test_util.run_deprecated_v1 def testBinaryOps(self): dtype_list = [dtypes.int8, dtypes.int16, dtypes.int32, dtypes.int64, dtypes.uint8, dtypes.uint16, dtypes.uint32, dtypes.uint64] @@ -70,6 +71,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): gen_bitwise_ops.population_count(input_tensor)) self.assertAllEqual(truth, popcnt_result) + @test_util.run_deprecated_v1 def testInvertOp(self): dtype_list = [dtypes.int8, dtypes.int16, dtypes.int32, dtypes.int64, dtypes.uint8, dtypes.uint16, dtypes.uint32, dtypes.uint64] @@ -94,6 +96,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): expected = [dtype.max - x for x in inputs] self.assertAllEqual(inverted, expected) + @test_util.run_deprecated_v1 def testShiftsWithPositiveLHS(self): dtype_list = [np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64] @@ -108,6 +111,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): self.assertAllEqual(left_shift_result, np.left_shift(lhs, rhs)) self.assertAllEqual(right_shift_result, np.right_shift(lhs, rhs)) + @test_util.run_deprecated_v1 def testShiftsWithNegativeLHS(self): dtype_list = [np.int8, np.int16, np.int32, np.int64] @@ -121,6 +125,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): self.assertAllEqual(left_shift_result, np.left_shift(lhs, rhs)) self.assertAllEqual(right_shift_result, np.right_shift(lhs, rhs)) + @test_util.run_deprecated_v1 def testImplementationDefinedShiftsDoNotCrash(self): dtype_list = [np.int8, np.int16, np.int32, np.int64] @@ -136,6 +141,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): bitwise_ops.right_shift(lhs, rhs)]) + @test_util.run_deprecated_v1 def testShapeInference(self): dtype_list = [dtypes.int8, dtypes.int16, dtypes.int32, dtypes.int64, dtypes.uint8, dtypes.uint16] diff --git a/tensorflow/python/ops/clip_ops_test.py b/tensorflow/python/ops/clip_ops_test.py index e9f7941b42..a59a0c22d4 100644 --- a/tensorflow/python/ops/clip_ops_test.py +++ b/tensorflow/python/ops/clip_ops_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import clip_ops from tensorflow.python.ops import numerics from tensorflow.python.platform import test @@ -57,6 +58,7 @@ class ClipOpsTest(test.TestCase): result, expected = self.evaluate([clipped, dense_clipped]) self.assertAllClose(result, expected) + @test_util.run_deprecated_v1 def testClipTensorByNorm(self): # Simple example self._testClipTensorByNorm([[-3.0, 0.0, 0.0], [4.0, 0.0, 0.0]], 4.0, diff --git a/tensorflow/python/ops/collective_ops_test.py b/tensorflow/python/ops/collective_ops_test.py index 9c772a9354..0fd9368d21 100644 --- a/tensorflow/python/ops/collective_ops_test.py +++ b/tensorflow/python/ops/collective_ops_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.core.protobuf import config_pb2 from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import collective_ops from tensorflow.python.platform import test @@ -49,16 +50,19 @@ class CollectiveOpTest(test.TestCase): self.assertAllClose(results[0], expected, rtol=1e-5, atol=1e-5) self.assertAllClose(results[1], expected, rtol=1e-5, atol=1e-5) + @test_util.run_deprecated_v1 def testCollectiveReduce(self): self._testCollectiveReduce([0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1], [0.3, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3], [0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2], True) + @test_util.run_deprecated_v1 def testCollectiveAutoGraphKey(self): self._testCollectiveReduce([0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1], [0.3, 1.3, 2.3, 3.3, 4.3, 5.3, 6.3, 7.3], [0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2], False) + @test_util.run_deprecated_v1 def testCollectiveReduceScalar(self): self._testCollectiveReduce(0.1, 0.3, 0.2, True) @@ -81,6 +85,7 @@ class CollectiveOpTest(test.TestCase): self.assertAllClose(results[0], t0, rtol=1e-5, atol=1e-5) self.assertAllClose(results[1], t0, rtol=1e-5, atol=1e-5) + @test_util.run_deprecated_v1 def testCollectiveBroadcast(self): self._testCollectiveBroadcast([0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1]) diff --git a/tensorflow/python/ops/gradient_checker_test.py b/tensorflow/python/ops/gradient_checker_test.py index 66c7b9a71b..4d2b5efac7 100644 --- a/tensorflow/python/ops/gradient_checker_test.py +++ b/tensorflow/python/ops/gradient_checker_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops @@ -46,6 +47,7 @@ def _nan_grad(unused_op, grad): class GradientCheckerTest(test.TestCase): + @test_util.run_deprecated_v1 def testAddSimple(self): np.random.seed(1) # Fix seed to avoid flakiness with self.session(use_gpu=False): @@ -60,6 +62,7 @@ class GradientCheckerTest(test.TestCase): tf_logging.info("x1 error = %f", error) assert error < 1e-4 + @test_util.run_deprecated_v1 def testAddSimpleGPU(self): np.random.seed(2) # Fix seed to avoid flakiness with self.session(use_gpu=True): @@ -74,6 +77,7 @@ class GradientCheckerTest(test.TestCase): tf_logging.info("x1 error = %f", error) assert error < 1e-4 + @test_util.run_deprecated_v1 def testAddCustomized(self): np.random.seed(3) # Fix seed to avoid flakiness with self.cached_session(): @@ -92,6 +96,7 @@ class GradientCheckerTest(test.TestCase): tf_logging.info("x2 error = %f", error) assert error < 1e-10 + @test_util.run_deprecated_v1 def testGather(self): np.random.seed(4) # Fix seed to avoid flakiness with self.cached_session(): @@ -109,6 +114,7 @@ class GradientCheckerTest(test.TestCase): tf_logging.info("gather error = %f", error) assert error < 1e-4 + @test_util.run_deprecated_v1 def testNestedGather(self): np.random.seed(5) # Fix seed to avoid flakiness with self.cached_session(): @@ -130,6 +136,7 @@ class GradientCheckerTest(test.TestCase): tf_logging.info("nested gather error = %f", error) assert error < 1e-4 + @test_util.run_deprecated_v1 def testComplexMul(self): with self.cached_session(): size = () @@ -144,6 +151,7 @@ class GradientCheckerTest(test.TestCase): self.assertLess( gradient_checker.compute_gradient_error(x, size, y, size), 2e-4) + @test_util.run_deprecated_v1 def testComplexConj(self): with self.cached_session(): size = () @@ -157,6 +165,7 @@ class GradientCheckerTest(test.TestCase): self.assertLess( gradient_checker.compute_gradient_error(x, size, y, size), 2e-5) + @test_util.run_deprecated_v1 def testEmptySucceeds(self): with self.cached_session(): x = array_ops.placeholder(dtypes.float32) @@ -279,18 +288,23 @@ class MiniMNISTTest(test.TestCase): tf_logging.info("Mini MNIST: %s gradient error = %g", tag, err) return err + @test_util.run_deprecated_v1 def testInputGradient(self): self.assertLess(self._BuildAndTestMiniMNIST(0, "input"), 1e-8) + @test_util.run_deprecated_v1 def testHiddenWeightGradient(self): self.assertLess(self._BuildAndTestMiniMNIST(1, "hidden_weight"), 1e-8) + @test_util.run_deprecated_v1 def testHiddenBiasGradient(self): self.assertLess(self._BuildAndTestMiniMNIST(2, "hidden_bias"), 1e-8) + @test_util.run_deprecated_v1 def testSoftmaxWeightGradient(self): self.assertLess(self._BuildAndTestMiniMNIST(3, "softmax_weight"), 1e-8) + @test_util.run_deprecated_v1 def testSoftmaxBiasGradient(self): self.assertLess(self._BuildAndTestMiniMNIST(4, "softmax_bias"), 1e-8) diff --git a/tensorflow/python/ops/histogram_ops_test.py b/tensorflow/python/ops/histogram_ops_test.py index cd1abbfc13..b48ef67196 100644 --- a/tensorflow/python/ops/histogram_ops_test.py +++ b/tensorflow/python/ops/histogram_ops_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.framework import constant_op from tensorflow.python.ops import array_ops from tensorflow.python.ops import histogram_ops @@ -84,6 +85,7 @@ class HistogramFixedWidthTest(test.TestCase): def setUp(self): self.rng = np.random.RandomState(0) + @test_util.run_deprecated_v1 def test_with_invalid_value_range(self): values = [-1.0, 0.0, 1.5, 2.0, 5.0, 15] with self.assertRaisesRegexp( @@ -92,6 +94,7 @@ class HistogramFixedWidthTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "Dimension must be 2 but is 3"): histogram_ops.histogram_fixed_width(values, [1.0, 2.0, 3.0]) + @test_util.run_deprecated_v1 def test_with_invalid_nbins(self): values = [-1.0, 0.0, 1.5, 2.0, 5.0, 15] with self.assertRaisesRegexp( @@ -146,6 +149,7 @@ class HistogramFixedWidthTest(test.TestCase): self.assertEqual(dtypes.int32, hist.dtype) self.assertAllClose(expected_bin_counts, self.evaluate(hist)) + @test_util.run_deprecated_v1 def test_shape_inference(self): value_range = [0.0, 5.0] values = [[-1.0, 0.0, 1.5], [2.0, 5.0, 15]] diff --git a/tensorflow/python/ops/image_grad_test.py b/tensorflow/python/ops/image_grad_test.py index 0ea15b0d23..c481266dd7 100644 --- a/tensorflow/python/ops/image_grad_test.py +++ b/tensorflow/python/ops/image_grad_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import image_ops @@ -47,6 +48,7 @@ class ResizeNearestNeighborOpTest(test.TestCase): resize_out = self.evaluate(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) + @test_util.run_deprecated_v1 def testGradFromResizeToLargerInBothDims(self): in_shape = [1, 2, 3, 1] out_shape = [1, 4, 6, 1] @@ -62,6 +64,7 @@ class ResizeNearestNeighborOpTest(test.TestCase): input_tensor, in_shape, resize_out, out_shape, x_init_value=x) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testGradFromResizeToSmallerInBothDims(self): in_shape = [1, 4, 6, 1] out_shape = [1, 2, 3, 1] @@ -77,6 +80,7 @@ class ResizeNearestNeighborOpTest(test.TestCase): input_tensor, in_shape, resize_out, out_shape, x_init_value=x) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testCompareGpuVsCpu(self): in_shape = [1, 4, 6, 3] out_shape = [1, 8, 16, 3] @@ -116,6 +120,7 @@ class ResizeBilinearOpTest(test.TestCase): resize_out = self.evaluate(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) + @test_util.run_deprecated_v1 def testGradFromResizeToLargerInBothDims(self): in_shape = [1, 2, 3, 1] out_shape = [1, 4, 6, 1] @@ -129,6 +134,7 @@ class ResizeBilinearOpTest(test.TestCase): input_tensor, in_shape, resize_out, out_shape, x_init_value=x) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testGradFromResizeToSmallerInBothDims(self): in_shape = [1, 4, 6, 1] out_shape = [1, 2, 3, 1] @@ -142,6 +148,7 @@ class ResizeBilinearOpTest(test.TestCase): input_tensor, in_shape, resize_out, out_shape, x_init_value=x) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testCompareGpuVsCpu(self): in_shape = [2, 4, 6, 3] out_shape = [2, 8, 16, 3] @@ -160,6 +167,7 @@ class ResizeBilinearOpTest(test.TestCase): self.assertAllClose(grad[False], grad[True], rtol=1e-4, atol=1e-4) + @test_util.run_deprecated_v1 def testTypes(self): in_shape = [1, 4, 6, 1] out_shape = [1, 2, 3, 1] @@ -199,6 +207,7 @@ class ResizeBicubicOpTest(test.TestCase): resize_out = self.evaluate(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) + @test_util.run_deprecated_v1 def testGradFromResizeToLargerInBothDims(self): in_shape = [1, 2, 3, 1] out_shape = [1, 4, 6, 1] @@ -214,6 +223,7 @@ class ResizeBicubicOpTest(test.TestCase): input_tensor, in_shape, resize_out, out_shape, x_init_value=x) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testGradFromResizeToSmallerInBothDims(self): in_shape = [1, 4, 6, 1] out_shape = [1, 2, 3, 1] @@ -229,6 +239,7 @@ class ResizeBicubicOpTest(test.TestCase): input_tensor, in_shape, resize_out, out_shape, x_init_value=x) self.assertLess(err, 1e-3) + @test_util.run_deprecated_v1 def testGradOnUnsupportedType(self): in_shape = [1, 4, 6, 1] out_shape = [1, 2, 3, 1] @@ -306,6 +317,7 @@ class CropAndResizeOpTest(test.TestCase): samples.append(sample) return samples + @test_util.run_deprecated_v1 def testGradRandomBoxes(self): """Test that the gradient is correct for randomly generated boxes. diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 71a574e0a0..e7249333bd 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -211,6 +211,7 @@ class GrayscaleToRGBTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, y_np) + @test_util.run_deprecated_v1 def testShapeInference(self): # Shape inference works and produces expected output where possible rgb_shape = [7, None, 19, 3] @@ -271,6 +272,7 @@ class AdjustGamma(test_util.TensorFlowTestCase): else: raise AssertionError("Exception not raised: %s" % err_msg) + @test_util.run_deprecated_v1 def test_adjust_gamma_less_zero_tensor(self): """White image should be returned for gamma equal to zero""" with self.cached_session(): @@ -308,6 +310,7 @@ class AdjustGamma(test_util.TensorFlowTestCase): self.assertAllClose(y_tf, y_np, 1e-6) + @test_util.run_deprecated_v1 def test_adjust_gamma_less_one(self): """Verifying the output with expected results for gamma correction with gamma equal to half""" @@ -329,6 +332,7 @@ class AdjustGamma(test_util.TensorFlowTestCase): self.assertAllClose(y_tf, y_np, 1e-6) + @test_util.run_deprecated_v1 def test_adjust_gamma_greater_one(self): """Verifying the output with expected results for gamma correction with gamma equal to two""" @@ -938,6 +942,7 @@ class AdjustSaturationTest(test_util.TensorFlowTestCase): y_v[i][2] = b return y_v.reshape(x_np.shape) + @test_util.run_deprecated_v1 def testAdjustRandomSaturation(self): x_shapes = [ [2, 2, 3], @@ -996,6 +1001,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, x_np) + @test_util.run_deprecated_v1 def testLeftRight(self): x_np = np.array([[1, 2, 3], [1, 2, 3]], dtype=np.uint8).reshape([2, 3, 1]) y_np = np.array([[3, 2, 1], [3, 2, 1]], dtype=np.uint8).reshape([2, 3, 1]) @@ -1021,6 +1027,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, y_np) + @test_util.run_deprecated_v1 def testRandomFlipLeftRight(self): x_np = np.array([[1, 2, 3], [1, 2, 3]], dtype=np.uint8).reshape([2, 3, 1]) y_np = np.array([[3, 2, 1], [3, 2, 1]], dtype=np.uint8).reshape([2, 3, 1]) @@ -1049,6 +1056,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): self.assertGreaterEqual(count_flipped, 20) self.assertGreaterEqual(count_unflipped, 20) + @test_util.run_deprecated_v1 def testRandomFlipLeftRightWithBatch(self): batch_size = 16 seed = 42 @@ -1113,6 +1121,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, x_np) + @test_util.run_deprecated_v1 def testUpDown(self): x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint8).reshape([2, 3, 1]) y_np = np.array([[4, 5, 6], [1, 2, 3]], dtype=np.uint8).reshape([2, 3, 1]) @@ -1138,6 +1147,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, y_np) + @test_util.run_deprecated_v1 def testRandomFlipUpDown(self): x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint8).reshape([2, 3, 1]) y_np = np.array([[4, 5, 6], [1, 2, 3]], dtype=np.uint8).reshape([2, 3, 1]) @@ -1166,6 +1176,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): self.assertGreaterEqual(count_flipped, 20) self.assertGreaterEqual(count_unflipped, 20) + @test_util.run_deprecated_v1 def testRandomFlipUpDownWithBatch(self): batch_size = 16 seed = 42 @@ -1230,6 +1241,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, x_np) + @test_util.run_deprecated_v1 def testTranspose(self): x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint8).reshape([2, 3, 1]) y_np = np.array([[1, 4], [2, 5], [3, 6]], dtype=np.uint8).reshape([3, 2, 1]) @@ -1256,6 +1268,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_tf = self.evaluate(y) self.assertAllEqual(y_tf, y_np) + @test_util.run_deprecated_v1 def testPartialShapes(self): p_unknown_rank = array_ops.placeholder(dtypes.uint8) p_unknown_dims_3 = array_ops.placeholder( @@ -1314,6 +1327,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): rotated = image_ops.rot90(rotated) self.assertAllEqual(image, self.evaluate(rotated)) + @test_util.run_deprecated_v1 def testRot90NumpyEquivalence(self): image = np.arange(24, dtype=np.uint8).reshape([2, 4, 3]) with self.test_session(use_gpu=True): @@ -1323,6 +1337,7 @@ class FlipTransposeRotateTest(test_util.TensorFlowTestCase): y_np = np.rot90(image, k=k) self.assertAllEqual(y_np, y_tf.eval({k_placeholder: k})) + @test_util.run_deprecated_v1 def testRot90NumpyEquivalenceWithBatch(self): image = np.arange(48, dtype=np.uint8).reshape([2, 2, 4, 3]) with self.test_session(use_gpu=True): @@ -1411,6 +1426,7 @@ class AdjustContrastTest(test_util.TensorFlowTestCase): y_tf = self._adjustContrastTf(x_np, contrast_factor) self.assertAllClose(y_tf, y_np, rtol=1e-5, atol=1e-5) + @test_util.run_deprecated_v1 def testContrastFactorShape(self): x_shape = [1, 2, 2, 3] x_data = [0, 5, 13, 54, 135, 226, 37, 8, 234, 90, 255, 1] @@ -1474,6 +1490,7 @@ class PerImageWhiteningTest(test_util.TensorFlowTestCase): y /= stddev return y + @test_util.run_deprecated_v1 def testBasic(self): x_shape = [13, 9, 3] x_np = np.arange(0, np.prod(x_shape), dtype=np.int32).reshape(x_shape) @@ -1574,11 +1591,13 @@ class CropToBoundingBoxTest(test_util.TensorFlowTestCase): y = image_ops.crop_to_bounding_box(image, 0, 0, height, width) self.assertEqual(y.get_shape().as_list(), post_shape) + @test_util.run_deprecated_v1 def testNoOp(self): x_shape = [10, 10, 10] x = np.random.uniform(size=x_shape) self._assertReturns(x, x_shape, 0, 0, x, x_shape) + @test_util.run_deprecated_v1 def testCrop(self): x = [1, 2, 3, 4, 5, 6, 7, 8, 9] x_shape = [3, 3, 1] @@ -1603,6 +1622,7 @@ class CropToBoundingBoxTest(test_util.TensorFlowTestCase): y = [1, 2, 4, 5, 7, 8] self._assertReturns(x, x_shape, offset_height, offset_width, y, y_shape) + @test_util.run_deprecated_v1 def testShapeInference(self): self._assertShapeInference([55, 66, 3], 55, 66, [55, 66, 3]) self._assertShapeInference([59, 69, 3], 55, 66, [55, 66, 3]) @@ -1616,6 +1636,7 @@ class CropToBoundingBoxTest(test_util.TensorFlowTestCase): self._assertShapeInference([None, None, None], 55, 66, [55, 66, None]) self._assertShapeInference(None, 55, 66, [55, 66, None]) + @test_util.run_deprecated_v1 def testNon3DInput(self): # Input image is not 3D x = [0] * 15 @@ -1627,6 +1648,7 @@ class CropToBoundingBoxTest(test_util.TensorFlowTestCase): target_width, "'image' must have either 3 or 4 dimensions.") + @test_util.run_deprecated_v1 def testZeroLengthInput(self): # Input image has 0-length dimension(s). # Each line is a test configuration: @@ -1658,6 +1680,7 @@ class CropToBoundingBoxTest(test_util.TensorFlowTestCase): "assertion failed:", use_tensor_inputs_options=[True]) + @test_util.run_deprecated_v1 def testBadParams(self): x_shape = [4, 4, 1] x = np.zeros(x_shape) @@ -1675,6 +1698,7 @@ class CropToBoundingBoxTest(test_util.TensorFlowTestCase): for params, err_msg in test_config: self._assertRaises(x, x_shape, *params, err_msg=err_msg) + @test_util.run_deprecated_v1 def testNameScope(self): image = array_ops.placeholder(dtypes.float32, shape=[55, 66, 3]) y = image_ops.crop_to_bounding_box(image, 0, 0, 55, 66) @@ -1691,6 +1715,7 @@ class CentralCropTest(test_util.TensorFlowTestCase): else: self.assertEqual(y.get_shape().as_list(), post_shape) + @test_util.run_deprecated_v1 def testNoOp(self): x_shapes = [[13, 9, 3], [5, 13, 9, 3]] for x_shape in x_shapes: @@ -1734,6 +1759,7 @@ class CentralCropTest(test_util.TensorFlowTestCase): self.assertAllEqual(y_tf, y_np) self.assertAllEqual(y_tf.shape, y_np.shape) + @test_util.run_deprecated_v1 def testCropping2(self): # Test case for 10315 x_shapes = [[240, 320, 3], [5, 240, 320, 3]] @@ -1750,6 +1776,7 @@ class CentralCropTest(test_util.TensorFlowTestCase): self.assertAllEqual(y_tf, y_np) self.assertAllEqual(y_tf.shape, y_np.shape) + @test_util.run_deprecated_v1 def testShapeInference(self): # Test no-op fraction=1.0, with 3-D tensors. self._assertShapeInference([50, 60, 3], 1.0, [50, 60, 3]) @@ -1810,6 +1837,7 @@ class CentralCropTest(test_util.TensorFlowTestCase): with self.assertRaises(ValueError): _ = image_ops.central_crop(x, 0.5) + @test_util.run_deprecated_v1 def testNameScope(self): x_shape = [13, 9, 3] x_np = np.ones(x_shape, dtype=np.float32) @@ -1902,12 +1930,14 @@ class PadToBoundingBoxTest(test_util.TensorFlowTestCase): with self.test_session(use_gpu=True): self.assertAllClose(y, self.evaluate(y_tf)) + @test_util.run_deprecated_v1 def testNoOp(self): x_shape = [10, 10, 10] x = np.random.uniform(size=x_shape) offset_height, offset_width = [0, 0] self._assertReturns(x, x_shape, offset_height, offset_width, x, x_shape) + @test_util.run_deprecated_v1 def testPadding(self): x = [1, 2, 3, 4, 5, 6, 7, 8, 9] x_shape = [3, 3, 1] @@ -1932,6 +1962,7 @@ class PadToBoundingBoxTest(test_util.TensorFlowTestCase): y_shape = [3, 4, 1] self._assertReturns(x, x_shape, offset_height, offset_width, y, y_shape) + @test_util.run_deprecated_v1 def testShapeInference(self): self._assertShapeInference([55, 66, 3], 55, 66, [55, 66, 3]) self._assertShapeInference([50, 60, 3], 55, 66, [55, 66, 3]) @@ -1945,6 +1976,7 @@ class PadToBoundingBoxTest(test_util.TensorFlowTestCase): self._assertShapeInference([None, None, None], 55, 66, [55, 66, None]) self._assertShapeInference(None, 55, 66, [55, 66, None]) + @test_util.run_deprecated_v1 def testNon3DInput(self): # Input image is not 3D x = [0] * 15 @@ -1956,6 +1988,7 @@ class PadToBoundingBoxTest(test_util.TensorFlowTestCase): target_width, "'image' must have either 3 or 4 dimensions.") + @test_util.run_deprecated_v1 def testZeroLengthInput(self): # Input image has 0-length dimension(s). # Each line is a test configuration: @@ -1988,6 +2021,7 @@ class PadToBoundingBoxTest(test_util.TensorFlowTestCase): "all dims of \\'image.shape\\' must be > 0", use_tensor_inputs_options=[True]) + @test_util.run_deprecated_v1 def testBadParams(self): x_shape = [3, 3, 1] x = np.zeros(x_shape) @@ -2002,6 +2036,7 @@ class PadToBoundingBoxTest(test_util.TensorFlowTestCase): for config_item in test_config: self._assertRaises(x, x_shape, *config_item) + @test_util.run_deprecated_v1 def testNameScope(self): image = array_ops.placeholder(dtypes.float32, shape=[55, 66, 3]) y = image_ops.pad_to_bounding_box(image, 0, 0, 55, 66) @@ -2109,6 +2144,7 @@ class SelectDistortedCropBoxTest(test_util.TensorFlowTestCase): # TODO(wicke, shlens, dga): Restore this test so that it is no longer flaky. # self.assertGreaterEqual(min(fraction_object_covered), min_object_covered) + @test_util.run_deprecated_v1 def testWholeImageBoundingBox(self): height = 40 width = 50 @@ -2123,6 +2159,7 @@ class SelectDistortedCropBoxTest(test_util.TensorFlowTestCase): aspect_ratio_range=(0.75, 1.33), area_range=(0.05, 1.0)) + @test_util.run_deprecated_v1 def testWithBoundingBox(self): height = 40 width = 50 @@ -2153,6 +2190,7 @@ class SelectDistortedCropBoxTest(test_util.TensorFlowTestCase): aspect_ratio_range=(0.75, 1.33), area_range=(0.05, 1.0)) + @test_util.run_deprecated_v1 def testSampleDistortedBoundingBoxShape(self): with self.test_session(use_gpu=True): image_size = constant_op.constant( @@ -2248,6 +2286,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): else: return False + @test_util.run_deprecated_v1 def testNoOp(self): img_shape = [1, 6, 4, 1] single_shape = [6, 4, 1] @@ -2282,6 +2321,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): newshape = self.evaluate(yshape) self.assertAllEqual(single_shape, newshape) + @test_util.run_deprecated_v1 def testTensorArguments(self): img_shape = [1, 6, 4, 1] single_shape = [6, 4, 1] @@ -2343,6 +2383,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): _ = image_ops.resize_images(image, [6, None], image_ops.ResizeMethod.BILINEAR) + @test_util.run_deprecated_v1 def testReturnDtype(self): target_shapes = [[6, 4], [3, 2], [ array_ops.placeholder(dtypes.int32), @@ -2591,6 +2632,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): value[use_gpu] = self.evaluate(out_op) self.assertAllClose(value[True], value[False], rtol=1e-5, atol=1e-5) + @test_util.run_deprecated_v1 def testShapeInference(self): self._assertShapeInference([50, 60, 3], [55, 66], [55, 66, 3]) self._assertShapeInference([55, 66, 3], [55, 66], [55, 66, 3]) @@ -2611,6 +2653,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): self._assertShapeInference([59, 60, None], [55, 66], [55, 66, None]) self._assertShapeInference([None, None, None], [55, 66], [55, 66, None]) + @test_util.run_deprecated_v1 def testNameScope(self): img_shape = [1, 3, 2, 1] with self.test_session(use_gpu=True): @@ -2661,6 +2704,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): preserve_aspect_ratio, use_tensor_inputs) self.assertShapeEqual(y, ops.convert_to_tensor(y_tf)) + @test_util.run_deprecated_v1 def testPreserveAspectRatioMultipleImages(self): x_shape = [10, 100, 100, 10] x = np.random.uniform(size=x_shape) @@ -2668,36 +2712,42 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): self._assertResizeCheckShape(x, x_shape, [250, 250], [10, 250, 250, 10], preserve_aspect_ratio=False) + @test_util.run_deprecated_v1 def testPreserveAspectRatioNoOp(self): x_shape = [10, 10, 10] x = np.random.uniform(size=x_shape) self._assertResizeEqual(x, x_shape, x, x_shape) + @test_util.run_deprecated_v1 def testPreserveAspectRatioSmaller(self): x_shape = [100, 100, 10] x = np.random.uniform(size=x_shape) self._assertResizeCheckShape(x, x_shape, [75, 50], [50, 50, 10]) + @test_util.run_deprecated_v1 def testPreserveAspectRatioSmallerMultipleImages(self): x_shape = [10, 100, 100, 10] x = np.random.uniform(size=x_shape) self._assertResizeCheckShape(x, x_shape, [75, 50], [10, 50, 50, 10]) + @test_util.run_deprecated_v1 def testPreserveAspectRatioLarger(self): x_shape = [100, 100, 10] x = np.random.uniform(size=x_shape) self._assertResizeCheckShape(x, x_shape, [150, 200], [150, 150, 10]) + @test_util.run_deprecated_v1 def testPreserveAspectRatioSameRatio(self): x_shape = [1920, 1080, 3] x = np.random.uniform(size=x_shape) self._assertResizeCheckShape(x, x_shape, [3840, 2160], [3840, 2160, 3]) + @test_util.run_deprecated_v1 def testPreserveAspectRatioSquare(self): x_shape = [299, 299, 3] x = np.random.uniform(size=x_shape) @@ -2767,12 +2817,14 @@ class ResizeImageWithPadTest(test_util.TensorFlowTestCase): y = image_ops.resize_image_with_pad(image, height, width) self.assertEqual(y.get_shape().as_list(), post_shape) + @test_util.run_deprecated_v1 def testNoOp(self): x_shape = [10, 10, 10] x = np.random.uniform(size=x_shape) self._assertReturns(x, x_shape, x, x_shape) + @test_util.run_deprecated_v1 def testPad(self): # Reduce vertical dimension x = [1, 2, 3, 4, 5, 6, 7, 8] @@ -2863,12 +2915,14 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): y = image_ops.resize_image_with_crop_or_pad(image, height, width) self.assertEqual(y.get_shape().as_list(), post_shape) + @test_util.run_deprecated_v1 def testNoOp(self): x_shape = [10, 10, 10] x = np.random.uniform(size=x_shape) self._assertReturns(x, x_shape, x, x_shape) + @test_util.run_deprecated_v1 def testPad(self): # Pad even along col. x = [1, 2, 3, 4, 5, 6, 7, 8] @@ -2906,6 +2960,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): self._assertReturns(x, x_shape, y, y_shape) + @test_util.run_deprecated_v1 def testCrop(self): # Crop even along col. x = [1, 2, 3, 4, 5, 6, 7, 8] @@ -2943,6 +2998,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): self._assertReturns(x, x_shape, y, y_shape) + @test_util.run_deprecated_v1 def testCropAndPad(self): # Pad along row but crop along col. x = [1, 2, 3, 4, 5, 6, 7, 8] @@ -2962,6 +3018,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): self._assertReturns(x, x_shape, y, y_shape) + @test_util.run_deprecated_v1 def testShapeInference(self): self._assertShapeInference([50, 60, 3], 55, 66, [55, 66, 3]) self._assertShapeInference([55, 66, 3], 55, 66, [55, 66, 3]) @@ -2983,6 +3040,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): self._assertShapeInference([None, None, None], 55, 66, [55, 66, None]) self._assertShapeInference(None, 55, 66, [55, 66, None]) + @test_util.run_deprecated_v1 def testNon3DInput(self): # Input image is not 3D x = [0] * 15 @@ -2996,6 +3054,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): self._assertRaises(x, x_shape, target_height, target_width, "'image' must have either 3 or 4 dimensions.") + @test_util.run_deprecated_v1 def testZeroLengthInput(self): # Input image has 0-length dimension(s). target_height, target_width = [1, 1] @@ -3021,6 +3080,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): "all dims of \\'image.shape\\' must be > 0", use_tensor_inputs_options=[True]) + @test_util.run_deprecated_v1 def testBadParams(self): x_shape = [4, 4, 1] x = np.zeros(x_shape) @@ -3035,6 +3095,7 @@ class ResizeImageWithCropOrPadTest(test_util.TensorFlowTestCase): self._assertRaises(x, x_shape, target_height, target_width, "target_width must be > 0") + @test_util.run_deprecated_v1 def testNameScope(self): image = array_ops.placeholder(dtypes.float32, shape=[50, 60, 3]) y = image_ops.resize_image_with_crop_or_pad(image, 55, 66) @@ -3118,6 +3179,7 @@ class JpegTest(test_util.TensorFlowTestCase): image1_crop, image2 = self.evaluate([image1_crop, image2]) self.assertAllEqual(image1_crop, image2) + @test_util.run_deprecated_v1 def testCropAndDecodeJpegWithInvalidCropWindow(self): with self.cached_session() as sess: # Encode it, then decode it, then encode it @@ -3194,6 +3256,7 @@ class JpegTest(test_util.TensorFlowTestCase): # The images should be the same. self.assertAllClose(image1, image2) + @test_util.run_deprecated_v1 def testShape(self): with self.test_session(use_gpu=True) as sess: jpeg = constant_op.constant("nonsense") @@ -3202,6 +3265,7 @@ class JpegTest(test_util.TensorFlowTestCase): self.assertEqual(image.get_shape().as_list(), [None, None, channels or None]) + @test_util.run_deprecated_v1 def testExtractJpegShape(self): # Read a real jpeg and verify shape. path = ("tensorflow/core/lib/jpeg/testdata/" @@ -3212,6 +3276,7 @@ class JpegTest(test_util.TensorFlowTestCase): [image_shape] = sess.run([image_ops.extract_jpeg_shape(jpeg)]) self.assertEqual(image_shape.tolist(), [256, 128, 3]) + @test_util.run_deprecated_v1 def testExtractJpegShapeforCmyk(self): # Read a cmyk jpeg image, and verify its shape. path = ("tensorflow/core/lib/jpeg/testdata/" @@ -3293,6 +3358,7 @@ class PngTest(test_util.TensorFlowTestCase): self.assertEqual(2, image0.shape[-1]) self.assertAllEqual(image0, image1) + @test_util.run_deprecated_v1 def testShape(self): with self.test_session(use_gpu=True): png = constant_op.constant("nonsense") @@ -3337,6 +3403,7 @@ class GifTest(test_util.TensorFlowTestCase): self._testValid("scan.gif") self._testValid("optimized.gif") + @test_util.run_deprecated_v1 def testShape(self): with self.test_session(use_gpu=True) as sess: gif = constant_op.constant("nonsense") @@ -3363,6 +3430,7 @@ class ConvertImageTest(test_util.TensorFlowTestCase): self.assertTrue(y_saturate.dtype == output_dtype) self.assertAllClose(y_saturate.eval(), y_np, atol=1e-5) + @test_util.run_deprecated_v1 def testNoConvert(self): # Make sure converting to the same data type creates only an identity op with self.test_session(use_gpu=True): @@ -3372,6 +3440,7 @@ class ConvertImageTest(test_util.TensorFlowTestCase): self.assertEquals(y.op.type, "Identity") self.assertEquals(y.op.inputs[0], image) + @test_util.run_deprecated_v1 def testConvertBetweenInteger(self): # Make sure converting to between integer types scales appropriately with self.test_session(use_gpu=True): @@ -3380,6 +3449,7 @@ class ConvertImageTest(test_util.TensorFlowTestCase): self._convert([0, 2**32], dtypes.int64, dtypes.int32, [0, 1]) self._convert([0, 1], dtypes.int32, dtypes.int64, [0, 2**32]) + @test_util.run_deprecated_v1 def testConvertBetweenFloat(self): # Make sure converting to between float types does nothing interesting with self.test_session(use_gpu=True): @@ -3388,6 +3458,7 @@ class ConvertImageTest(test_util.TensorFlowTestCase): self._convert([-1.0, 0, 1.0, 200000], dtypes.float64, dtypes.float32, [-1.0, 0, 1.0, 200000]) + @test_util.run_deprecated_v1 def testConvertBetweenIntegerAndFloat(self): # Make sure converting from and to a float type scales appropriately with self.test_session(use_gpu=True): @@ -3396,6 +3467,7 @@ class ConvertImageTest(test_util.TensorFlowTestCase): self._convert([0, 1.1 / 255.0, 1], dtypes.float32, dtypes.uint8, [0, 1, 255]) + @test_util.run_deprecated_v1 def testConvertBetweenInt16AndInt8(self): with self.test_session(use_gpu=True): # uint8, uint16 @@ -3587,6 +3659,7 @@ class TotalVariationTest(test_util.TensorFlowTestCase): class FormatTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testFormats(self): prefix = "tensorflow/core/lib" paths = ("png/testdata/lena_gray.png", "jpeg/testdata/jpeg_merge_test1.jpg", @@ -3619,6 +3692,7 @@ class FormatTest(test_util.TensorFlowTestCase): class NonMaxSuppressionTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testSelectFromThreeClusters(self): boxes_np = [[0, 0, 1, 1], [0, 0.1, 1, 1.1], [0, -0.1, 1, 0.9], [0, 10, 1, 11], [0, 10.1, 1, 11.1], [0, 100, 1, 101]] @@ -3634,6 +3708,7 @@ class NonMaxSuppressionTest(test_util.TensorFlowTestCase): boxes, scores, max_output_size, iou_threshold).eval() self.assertAllClose(selected_indices, [3, 0, 5]) + @test_util.run_deprecated_v1 def testInvalidShape(self): # The boxes should be 2D of shape [num_boxes, 4]. with self.assertRaisesRegexp(ValueError, @@ -3676,6 +3751,7 @@ class NonMaxSuppressionTest(test_util.TensorFlowTestCase): scores = constant_op.constant([0.9]) image_ops.non_max_suppression(boxes, scores, 3, [[0.5]]) + @test_util.run_deprecated_v1 def testDataTypes(self): # Test case for GitHub issue 20199. boxes_np = [[0, 0, 1, 1], [0, 0.1, 1, 1.1], [0, -0.1, 1, 0.9], @@ -3720,6 +3796,7 @@ class NonMaxSuppressionTest(test_util.TensorFlowTestCase): class NonMaxSuppressionPaddedTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testSelectFromThreeClusters(self): boxes_np = [[0, 0, 1, 1], [0, 0.1, 1, 1.1], [0, -0.1, 1, 0.9], [0, 10, 1, 11], [0, 10.1, 1, 11.1], [0, 100, 1, 101]] @@ -3752,6 +3829,7 @@ class NonMaxSuppressionPaddedTest(test_util.TensorFlowTestCase): self.assertAllClose(selected_indices.eval(), [3, 0, 5]) self.assertEqual(num_valid.eval(), 3) + @test_util.run_deprecated_v1 def testSelectFromContinuousOverLap(self): boxes_np = [[0, 0, 1, 1], [0, 0.2, 1, 1.2], [0, 0.4, 1, 1.4], [0, 0.6, 1, 1.6], [0, 0.8, 1, 1.8], [0, 2, 1, 2]] @@ -3779,6 +3857,7 @@ class NonMaxSuppressionPaddedTest(test_util.TensorFlowTestCase): class NonMaxSuppressionWithOverlapsTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testSelectOneFromThree(self): overlaps_np = [ [1.0, 0.7, 0.2], @@ -3804,6 +3883,7 @@ class NonMaxSuppressionWithOverlapsTest(test_util.TensorFlowTestCase): class VerifyCompatibleImageShapesTest(test_util.TensorFlowTestCase): """Tests utility function used by ssim() and psnr().""" + @test_util.run_deprecated_v1 def testWrongDims(self): img = array_ops.placeholder(dtype=dtypes.float32) img_np = np.array((2, 2)) @@ -3813,6 +3893,7 @@ class VerifyCompatibleImageShapesTest(test_util.TensorFlowTestCase): with self.assertRaises(errors.InvalidArgumentError): sess.run(checks, {img: img_np}) + @test_util.run_deprecated_v1 def testShapeMismatch(self): img1 = array_ops.placeholder(dtype=dtypes.float32) img2 = array_ops.placeholder(dtype=dtypes.float32) @@ -3853,6 +3934,7 @@ class PSNRTest(test_util.TensorFlowTestCase): """Returns an image or image batch with given shape.""" return np.random.rand(*shape).astype(np.float32) * max_val + @test_util.run_deprecated_v1 def testPSNRSingleImage(self): image1 = self._RandomImage((8, 8, 1), 1) image2 = self._RandomImage((8, 8, 1), 1) @@ -3866,6 +3948,7 @@ class PSNRTest(test_util.TensorFlowTestCase): tf_psnr = image_ops.psnr(tf_image1, tf_image2, 1.0, "psnr").eval() self.assertAllClose(psnr, tf_psnr, atol=0.001) + @test_util.run_deprecated_v1 def testPSNRMultiImage(self): image1 = self._RandomImage((10, 8, 8, 1), 1) image2 = self._RandomImage((10, 8, 8, 1), 1) @@ -3879,6 +3962,7 @@ class PSNRTest(test_util.TensorFlowTestCase): tf_psnr = image_ops.psnr(tf_image1, tf_image2, 1, "psnr").eval() self.assertAllClose(psnr, tf_psnr, atol=0.001) + @test_util.run_deprecated_v1 def testGoldenPSNR(self): q20, q72, q95 = self._LoadTestImages() @@ -3903,6 +3987,7 @@ class PSNRTest(test_util.TensorFlowTestCase): self.assertAllClose(psnr2, tf_psnr2, atol=0.001) self.assertAllClose(psnr3, tf_psnr3, atol=0.001) + @test_util.run_deprecated_v1 def testInfinity(self): q20, _, _ = self._LoadTestImages() psnr = self._PSNR_NumPy(q20, q20, 1) @@ -3911,6 +3996,7 @@ class PSNRTest(test_util.TensorFlowTestCase): tf_psnr = image_ops.psnr(tf_q20, tf_q20, 1, "psnr").eval() self.assertAllClose(psnr, tf_psnr, atol=0.001) + @test_util.run_deprecated_v1 def testInt(self): img1 = self._RandomImage((10, 8, 8, 1), 255) img2 = self._RandomImage((10, 8, 8, 1), 255) @@ -3952,6 +4038,7 @@ class SSIMTest(test_util.TensorFlowTestCase): """Returns an image or image batch with given shape.""" return np.random.rand(*shape).astype(np.float32) * max_val + @test_util.run_deprecated_v1 def testAgainstMatlab(self): """Tests against values produced by Matlab.""" img = self._LoadTestImages() @@ -3989,6 +4076,7 @@ class SSIMTest(test_util.TensorFlowTestCase): with self.test_session(use_gpu=True): self.assertAllClose(expected, self.evaluate(ssim), atol=1e-4) + @test_util.run_deprecated_v1 def testNegative(self): """Tests against negative SSIM index.""" step = np.expand_dims(np.arange(0, 256, 16, dtype=np.uint8), axis=0) @@ -4003,6 +4091,7 @@ class SSIMTest(test_util.TensorFlowTestCase): with self.test_session(use_gpu=True): self.assertLess(ssim.eval(), 0) + @test_util.run_deprecated_v1 def testInt(self): img1 = self._RandomImage((1, 16, 16, 3), 255) img2 = self._RandomImage((1, 16, 16, 3), 255) @@ -4044,6 +4133,7 @@ class MultiscaleSSIMTest(test_util.TensorFlowTestCase): """Returns an image or image batch with given shape.""" return np.random.rand(*shape).astype(np.float32) * max_val + @test_util.run_deprecated_v1 def testAgainstMatlab(self): """Tests against MS-SSIM computed with Matlab implementation. @@ -4060,6 +4150,7 @@ class MultiscaleSSIMTest(test_util.TensorFlowTestCase): self.assertAllClose(expected, np.squeeze(scores), atol=1e-4) + @test_util.run_deprecated_v1 def testUnweightedIsDifferentiable(self): img = self._LoadTestImages() ph = [array_ops.placeholder(dtype=dtypes.float32) for _ in range(2)] @@ -4121,6 +4212,7 @@ class MultiscaleSSIMTest(test_util.TensorFlowTestCase): self.assertTrue(np.all(msssim >= 0.0)) self.assertTrue(np.all(msssim <= 1.0)) + @test_util.run_deprecated_v1 def testInt(self): img1 = self._RandomImage((1, 180, 240, 3), 255) img2 = self._RandomImage((1, 180, 240, 3), 255) diff --git a/tensorflow/python/ops/losses/util_test.py b/tensorflow/python/ops/losses/util_test.py index df2e60e2e4..22a8eaae26 100644 --- a/tensorflow/python/ops/losses/util_test.py +++ b/tensorflow/python/ops/losses/util_test.py @@ -20,12 +20,14 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops.losses import util from tensorflow.python.platform import test class LossesUtilTest(test.TestCase): + @test_util.run_deprecated_v1 def testGetRegularizationLoss(self): # Empty regularization collection should evaluate to 0.0. with self.cached_session(): diff --git a/tensorflow/python/ops/math_grad_test.py b/tensorflow/python/ops/math_grad_test.py index d1fe834fc7..88aa48271f 100644 --- a/tensorflow/python/ops/math_grad_test.py +++ b/tensorflow/python/ops/math_grad_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients @@ -52,6 +53,7 @@ class SquaredDifferenceOpTest(test.TestCase): self.assertLess(left_err, 1e-10) self.assertLess(right_err, 1e-10) + @test_util.run_deprecated_v1 def testGrad(self): self._testGrad([1, 2, 3, 2], [3, 2]) self._testGrad([2, 4], [3, 2, 4]) @@ -83,6 +85,7 @@ class AbsOpTest(test.TestCase): value, shape, output, output.get_shape().as_list()) self.assertLess(error, max_error) + @test_util.run_deprecated_v1 def testComplexAbs(self): # Bias random test values away from zero to avoid numeric instabilities. self._testGrad( @@ -99,6 +102,7 @@ class AbsOpTest(test.TestCase): class MinOrMaxGradientTest(test.TestCase): + @test_util.run_deprecated_v1 def testMinGradient(self): inputs = constant_op.constant([1.0], dtype=dtypes.float32) outputs = math_ops.reduce_min(array_ops.concat([inputs, inputs], 0)) @@ -106,6 +110,7 @@ class MinOrMaxGradientTest(test.TestCase): error = gradient_checker.compute_gradient_error(inputs, [1], outputs, []) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testMaxGradient(self): inputs = constant_op.constant([1.0], dtype=dtypes.float32) outputs = math_ops.reduce_max(array_ops.concat([inputs, inputs], 0)) @@ -116,6 +121,7 @@ class MinOrMaxGradientTest(test.TestCase): class MaximumOrMinimumGradientTest(test.TestCase): + @test_util.run_deprecated_v1 def testMaximumGradient(self): inputs = constant_op.constant([1.0, 2.0, 3.0, 4.0], dtype=dtypes.float32) outputs = math_ops.maximum(inputs, 3.0) @@ -123,6 +129,7 @@ class MaximumOrMinimumGradientTest(test.TestCase): error = gradient_checker.compute_gradient_error(inputs, [4], outputs, [4]) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testMinimumGradient(self): inputs = constant_op.constant([1.0, 2.0, 3.0, 4.0], dtype=dtypes.float32) outputs = math_ops.minimum(inputs, 2.0) @@ -133,6 +140,7 @@ class MaximumOrMinimumGradientTest(test.TestCase): class ProdGradientTest(test.TestCase): + @test_util.run_deprecated_v1 def testProdGradient(self): inputs = constant_op.constant([[1., 2.], [3., 4.]], dtype=dtypes.float32) @@ -143,6 +151,7 @@ class ProdGradientTest(test.TestCase): outputs, outputs.get_shape().as_list()) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testProdGradientForNegativeAxis(self): inputs = constant_op.constant([[1., 2.], [3., 4.]], dtype=dtypes.float32) @@ -153,6 +162,7 @@ class ProdGradientTest(test.TestCase): outputs, outputs.get_shape().as_list()) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testProdGradientComplex(self): for dtype in dtypes.complex64, dtypes.complex128: inputs = constant_op.constant([[1 + 3j, 2 - 1j], [3j, 4]], @@ -164,6 +174,7 @@ class ProdGradientTest(test.TestCase): outputs, outputs.get_shape().as_list()) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testProdGradientForNegativeAxisComplex(self): for dtype in dtypes.complex64, dtypes.complex128: inputs = constant_op.constant([[1 + 3j, 2 - 1j], [3j, 4]], @@ -178,6 +189,7 @@ class ProdGradientTest(test.TestCase): class SegmentMinOrMaxGradientTest(test.TestCase): + @test_util.run_deprecated_v1 def testSegmentMinGradient(self): data = constant_op.constant([1.0, 2.0, 3.0], dtype=dtypes.float32) segment_ids = constant_op.constant([0, 0, 1], dtype=dtypes.int64) @@ -187,6 +199,7 @@ class SegmentMinOrMaxGradientTest(test.TestCase): [2]) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testSegmentMaxGradient(self): data = constant_op.constant([1.0, 2.0, 3.0], dtype=dtypes.float32) segment_ids = constant_op.constant([0, 0, 1], dtype=dtypes.int64) @@ -196,6 +209,7 @@ class SegmentMinOrMaxGradientTest(test.TestCase): [2]) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testSegmentMinGradientWithTies(self): inputs = constant_op.constant([1.0], dtype=dtypes.float32) data = array_ops.concat([inputs, inputs], 0) @@ -206,6 +220,7 @@ class SegmentMinOrMaxGradientTest(test.TestCase): [1]) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testSegmentMaxGradientWithTies(self): inputs = constant_op.constant([1.0], dtype=dtypes.float32) data = array_ops.concat([inputs, inputs], 0) @@ -219,6 +234,7 @@ class SegmentMinOrMaxGradientTest(test.TestCase): class FloorModGradientTest(test.TestCase): + @test_util.run_deprecated_v1 def testFloorModGradient(self): # Making sure the input is not near the discontinuity point where # x/y == floor(x/y) @@ -233,6 +249,7 @@ class FloorModGradientTest(test.TestCase): class DivNoNanGradientTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasicGradient(self): inputs = constant_op.constant(np.arange(-3, 3), dtype=dtypes.float32) @@ -244,6 +261,7 @@ class DivNoNanGradientTest(test.TestCase): outputs.get_shape().as_list()) self.assertLess(error, 1e-4) + @test_util.run_deprecated_v1 def testGradientWithDenominatorIsZero(self): x = constant_op.constant(np.arange(-3, 3), dtype=dtypes.float32) @@ -263,6 +281,7 @@ class XlogyTest(test.TestCase): xlogy_ygrad = self.evaluate(gradients.gradients(math_ops.xlogy(x, y), y)[0]) return xlogy_xgrad, xlogy_ygrad + @test_util.run_deprecated_v1 def testNonZeroValuesGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0.1, dtype=dtype) @@ -273,6 +292,7 @@ class XlogyTest(test.TestCase): self.assertAllClose(xlogy_expected_xgrad, xlogy_xgrad) self.assertAllClose(xlogy_expected_ygrad, xlogy_ygrad) + @test_util.run_deprecated_v1 def testZeroXGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0., dtype=dtype) @@ -282,6 +302,7 @@ class XlogyTest(test.TestCase): self.assertAllClose(zero, xlogy_xgrad) self.assertAllClose(zero, xlogy_ygrad) + @test_util.run_deprecated_v1 def testZeroYGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0.1, dtype=dtype) @@ -290,6 +311,7 @@ class XlogyTest(test.TestCase): self.assertAllClose(-np.inf, xlogy_xgrad) self.assertAllClose(np.inf, xlogy_ygrad) + @test_util.run_deprecated_v1 def testZeroXYGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0., dtype=dtype) @@ -307,6 +329,7 @@ class XdivyTest(test.TestCase): xdivy_ygrad = self.evaluate(gradients.gradients(math_ops.xdivy(x, y), y)[0]) return xdivy_xgrad, xdivy_ygrad + @test_util.run_deprecated_v1 def testNonZeroValuesGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0.1, dtype=dtype) @@ -317,6 +340,7 @@ class XdivyTest(test.TestCase): self.assertAllClose(xdivy_expected_xgrad, xdivy_xgrad) self.assertAllClose(xdivy_expected_ygrad, xdivy_ygrad) + @test_util.run_deprecated_v1 def testZeroXGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0., dtype=dtype) @@ -326,6 +350,7 @@ class XdivyTest(test.TestCase): self.assertAllClose(zero, xdivy_xgrad) self.assertAllClose(zero, xdivy_ygrad) + @test_util.run_deprecated_v1 def testZeroYGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0.1, dtype=dtype) @@ -334,6 +359,7 @@ class XdivyTest(test.TestCase): self.assertAllClose(np.inf, xdivy_xgrad) self.assertAllClose(-np.inf, xdivy_ygrad) + @test_util.run_deprecated_v1 def testZeroXYGrad(self): for dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: x = constant_op.constant(0., dtype=dtype) diff --git a/tensorflow/python/ops/math_ops_test.py b/tensorflow/python/ops/math_ops_test.py index cd45b6f136..add1621a56 100644 --- a/tensorflow/python/ops/math_ops_test.py +++ b/tensorflow/python/ops/math_ops_test.py @@ -92,6 +92,7 @@ class ReduceTest(test_util.TensorFlowTestCase): class LogSumExpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testReduceLogSumExp(self): for dtype in [np.float16, np.float32, np.double]: x_np = np.random.rand(5, 5).astype(dtype) @@ -120,6 +121,7 @@ class LogSumExpTest(test_util.TensorFlowTestCase): y_tf_np = self.evaluate(y_tf) self.assertAllClose(y_tf_np, y_np) + @test_util.run_deprecated_v1 def testKeepDims(self): for dtype in [np.float16, np.float32, np.double]: x_np = np.random.rand(5, 5).astype(dtype) @@ -129,6 +131,7 @@ class LogSumExpTest(test_util.TensorFlowTestCase): y_np = log(np.sum(exp(x_np), keepdims=True)) self.assertAllClose(y_tf_np, y_np) + @test_util.run_deprecated_v1 def testOverflow(self): x = [1000, 1001, 1002, 1003] for dtype in [np.float16, np.float32, np.double]: @@ -146,6 +149,7 @@ class LogSumExpTest(test_util.TensorFlowTestCase): y_np = log(np.sum(exp(x_np - max_np))) + max_np self.assertAllClose(y_tf_np, y_np) + @test_util.run_deprecated_v1 def testUnderflow(self): x = [-1000, -1001, -1002, -1003] for dtype in [np.float16, np.float32, np.double]: @@ -163,6 +167,7 @@ class LogSumExpTest(test_util.TensorFlowTestCase): y_np = log(np.sum(exp(x_np - max_np))) + max_np self.assertAllClose(y_tf_np, y_np) + @test_util.run_deprecated_v1 def testInfinity(self): with self.session(use_gpu=True): res = math_ops.reduce_logsumexp(-np.inf).eval() @@ -186,6 +191,7 @@ class RoundTest(test_util.TensorFlowTestCase): class ModTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testFloat(self): x = [0.5, 0.7, 0.3] for dtype in [np.float32, np.double]: @@ -256,6 +262,7 @@ class ApproximateEqualTest(test_util.TensorFlowTestCase): z_tf = self.evaluate(math_ops.approximate_equal(x, y, tolerance=0.0001)) self.assertAllEqual(z, z_tf) + @test_util.run_deprecated_v1 def testApproximateEqualShape(self): for dtype in [np.float32, np.double]: x = np.array([1, 2], dtype=dtype) @@ -309,6 +316,7 @@ class ScalarMulTest(test_util.TensorFlowTestCase): class AccumulateNTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testFloat(self): np.random.seed(12345) x = [np.random.random((1, 2, 3, 4, 5)) - 0.5 for _ in range(5)] @@ -317,6 +325,7 @@ class AccumulateNTest(test_util.TensorFlowTestCase): self.assertAllClose(sum(x), math_ops.accumulate_n(tf_x).eval()) self.assertAllClose(x[0] * 5, math_ops.accumulate_n([tf_x[0]] * 5).eval()) + @test_util.run_deprecated_v1 def testInt(self): np.random.seed(54321) x = [np.random.randint(-128, 128, (5, 4, 3, 2, 1)) for _ in range(6)] @@ -328,6 +337,7 @@ class AccumulateNTest(test_util.TensorFlowTestCase): class AddNTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testPartials(self): """Test that previously revealed a bug in buffer forwarding for AddN.""" partials = [] @@ -341,6 +351,7 @@ class AddNTest(test_util.TensorFlowTestCase): with self.session(use_gpu=True): self.assertAllEqual(res.eval(), 100) + @test_util.run_deprecated_v1 def testFloat(self): np.random.seed(12345) for num_inputs in range(1, 10): @@ -351,6 +362,7 @@ class AddNTest(test_util.TensorFlowTestCase): self.assertAllClose(x[0] * num_inputs, math_ops.add_n([tf_x[0]] * num_inputs).eval()) + @test_util.run_deprecated_v1 def testInt(self): np.random.seed(54321) for num_inputs in range(1, 10): @@ -364,6 +376,7 @@ class AddNTest(test_util.TensorFlowTestCase): self.assertAllEqual(x[0] * num_inputs, math_ops.add_n([tf_x[0]] * num_inputs).eval()) + @test_util.run_deprecated_v1 def testGrad(self): np.random.seed(42) for num_inputs in range(1, 10): @@ -392,6 +405,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): divs = np.arange(-3, 0, .25).reshape(1, 12) return nums, divs + @test_util.run_deprecated_v1 def testFloorModInt(self): nums, divs = self.intTestData() with self.cached_session(): @@ -401,6 +415,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): np_result = nums % divs self.assertAllEqual(tf_result, np_result) + @test_util.run_deprecated_v1 def testFloorModFloat(self): nums, divs = self.floatTestData() with self.cached_session(): @@ -412,6 +427,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): # % array_ops.constant(divs)).eval() # self.assertAllEqual(tf2_result, tf_result) + @test_util.run_deprecated_v1 def testTruncateModInt(self): nums, divs = self.intTestData() with self.cached_session(): @@ -419,6 +435,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): np_result = np.fmod(nums, divs) self.assertAllEqual(tf_result, np_result) + @test_util.run_deprecated_v1 def testTruncateModFloat(self): nums, divs = self.floatTestData() with self.cached_session(): @@ -426,6 +443,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): np_result = np.fmod(nums, divs) self.assertAllEqual(tf_result, np_result) + @test_util.run_deprecated_v1 def testDivideInt(self): nums, divs = self.intTestData() with self.cached_session(): @@ -437,12 +455,14 @@ class DivAndModTest(test_util.TensorFlowTestCase): # // array_ops.constant(divs)).eval() # self.assertAllEqual(tf2_result, tf_result) + @test_util.run_deprecated_v1 def testDivideName(self): with self.cached_session(): op = math_ops.divide( array_ops.constant(3), array_ops.constant(4), name="my_cool_divide") self.assertEqual(op.name, "my_cool_divide:0") + @test_util.run_deprecated_v1 def testRealDiv(self): nums, divs = self.floatTestData() with self.cached_session(): @@ -450,12 +470,14 @@ class DivAndModTest(test_util.TensorFlowTestCase): np_result = np.divide(nums, divs) self.assertAllEqual(tf_result, np_result) + @test_util.run_deprecated_v1 def testComplexDiv(self): foo = array_ops.constant([1. + 3.j]) with self.cached_session(): _ = math_ops.divide(foo, 1.).eval() _ = math_ops.div(foo, 2.).eval() + @test_util.run_deprecated_v1 def testFloorDivGrad(self): with self.cached_session(): a = variables.Variable(2.) @@ -471,6 +493,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): [None if x is None else self.evaluate(x) for x in c_grad], [None, None]) + @test_util.run_deprecated_v1 def testConsistent(self): nums, divs = self.intTestData() with self.cached_session(): @@ -497,6 +520,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): class DivNoNanTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testBasic(self): for dtype in [np.float32, np.float64]: nums = np.arange(-10, 10, .25, dtype=dtype).reshape(80, 1) diff --git a/tensorflow/python/ops/nn_batchnorm_test.py b/tensorflow/python/ops/nn_batchnorm_test.py index 31b2790f2b..e978f1d326 100644 --- a/tensorflow/python/ops/nn_batchnorm_test.py +++ b/tensorflow/python/ops/nn_batchnorm_test.py @@ -71,6 +71,7 @@ class BatchNormalizationTest(test.TestCase): gamma if scale_after_normalization else None, epsilon) + @test_util.run_deprecated_v1 def testBatchNorm(self): x_shape = [3, 5, 4, 2] param_shape = [2] @@ -169,16 +170,20 @@ class BatchNormalizationTest(test.TestCase): shift_after_normalization, v, err_tolerance) + @test_util.run_deprecated_v1 def testBatchNormInputGradient(self): self._testBatchNormGradientInAllNeedConfigs(0, "x") + @test_util.run_deprecated_v1 def testBatchNormMeanGradient(self): self._testBatchNormGradientInAllNeedConfigs(1, "mean") + @test_util.run_deprecated_v1 def testBatchNormVarianceGradient(self): self._testBatchNormGradientInAllNeedConfigs( 2, "variance", err_tolerance=1e-03) + @test_util.run_deprecated_v1 def testBatchNormBetaGradient(self): # Since beta does not exist when scale_after_normalization=False, we only # test for scale_after_normalization=True. @@ -187,6 +192,7 @@ class BatchNormalizationTest(test.TestCase): self._testBatchNormGradient(3, "beta", scale_after_normalization, True, v) + @test_util.run_deprecated_v1 def testBatchNormGammaGradient(self): # If scale_after_normalization is False, backprop for gamma in v1 # will be 0. In version 2 of the API, if scale_after_normalization is False, @@ -199,6 +205,7 @@ class BatchNormalizationTest(test.TestCase): self._testBatchNormGradient(4, "gamma", True, shift_after_normalization, 2) + @test_util.run_deprecated_v1 def testBatchNormGradImpl(self): x_shape = [7, 5, 4, 6] param_shape = [6] @@ -245,6 +252,7 @@ class BatchNormalizationTest(test.TestCase): self.assertAllClose( all_grads[i + len(to_check)], all_grads[i], atol=0.000001) + @test_util.run_deprecated_v1 def testBatchNormKeepDims(self): """Test for tf.nn.moments(..., keep_dims=True / False). @@ -391,6 +399,7 @@ class SufficientStatisticsTest(test.TestCase): if shift: self.assertAllClose(np_s, tf_s, atol=0.000001) + @test_util.run_deprecated_v1 def testSuffStats(self): for has_shape in [True, False]: for keep_dims in [True, False]: @@ -511,6 +520,7 @@ class MomentsTest(test.TestCase): self.assertAllCloseAccordingToType(expected_mean, self.evaluate(mean)) self.assertAllCloseAccordingToType(expected_variance, self.evaluate(var)) + @test_util.run_deprecated_v1 def testBasic(self): for keep_dims in [False, True]: for dtype in [dtypes.float32, dtypes.float16]: @@ -519,6 +529,7 @@ class MomentsTest(test.TestCase): self.RunMomentTestWithDynamicShape( shape=[2, 3, 5, 4], axes=[0], keep_dims=keep_dims, dtype=dtype) + @test_util.run_deprecated_v1 def testGlobalNormalization(self): for keep_dims in [False, True]: for dtype in [dtypes.float32, dtypes.float16]: @@ -533,6 +544,7 @@ class MomentsTest(test.TestCase): keep_dims=keep_dims, dtype=dtype) + @test_util.run_deprecated_v1 def testAxes(self): for keep_dims in [False, True]: for dtype in [dtypes.float32, dtypes.float16]: @@ -573,9 +585,11 @@ class MomentsTest(test.TestCase): print("Moments %s gradient err vs input %d = %g" % (from_y, i, err)) self.assertLess(err, 1e-11) + @test_util.run_deprecated_v1 def testMeanGlobalGradient(self): self._testGlobalGradient(from_y="mean") + @test_util.run_deprecated_v1 def testVarGlobalGradient(self): self._testGlobalGradient(from_y="var") diff --git a/tensorflow/python/ops/nn_grad_test.py b/tensorflow/python/ops/nn_grad_test.py index 8065df4b16..95e05a977b 100644 --- a/tensorflow/python/ops/nn_grad_test.py +++ b/tensorflow/python/ops/nn_grad_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import nn_grad # pylint: disable=unused-import @@ -31,6 +32,7 @@ from tensorflow.python.platform import test class Relu6OpTest(test.TestCase): + @test_util.run_deprecated_v1 def testRelu6GradGrad(self): inputs = constant_op.constant( [[-2, -1, 1, 3], [5, 7, 8, 9]], dtype=dtypes.float32) diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index f7c8a7a70a..a7ed834c72 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -49,6 +49,7 @@ class ZeroFractionTest(test_lib.TestCase): nonzeros = np.count_nonzero(x.flatten()) return 1.0 - nonzeros / total_elements + @test_util.run_deprecated_v1 def testZeroFraction(self): x_shape = [5, 17] x_np = np.random.randint(0, 2, size=x_shape).astype(np.float32) @@ -62,21 +63,25 @@ class ZeroFractionTest(test_lib.TestCase): eps = 1e-8 self.assertAllClose(y_tf_np, y_np, eps) + @test_util.run_deprecated_v1 def testZeroFractionEmpty(self): x = np.zeros(0) y = self.evaluate(nn_impl.zero_fraction(x)) self.assertTrue(np.isnan(y)) + @test_util.run_deprecated_v1 def testZeroFraction2_27Zeros(self): sparsity = nn_impl.zero_fraction( array_ops.zeros([int(2**27 * 1.01)], dtype=dtypes.int8)) self.assertAllClose(1.0, self.evaluate(sparsity)) + @test_util.run_deprecated_v1 def testZeroFraction2_27Ones(self): sparsity = nn_impl.zero_fraction( array_ops.ones([int(2**27 * 1.01)], dtype=dtypes.int8)) self.assertAllClose(0.0, self.evaluate(sparsity)) + @test_util.run_deprecated_v1 def testUnknownSize(self): value = array_ops.placeholder(dtype=dtypes.float32) sparsity = nn_impl.zero_fraction(value) @@ -122,6 +127,7 @@ class SoftmaxTest(test_lib.TestCase, parameterized.TestCase): self.assertAllClose(y_pos_axis_tf, z_gt_axis_tf, eps) @parameterized.parameters(((5, 10),), ((2, 3, 4),)) + @test_util.run_deprecated_v1 def testGradient(self, x_shape): x_np = np.random.randn(*x_shape).astype(np.float64) with self.cached_session(): @@ -157,6 +163,7 @@ class LogPoissonLossTest(test_lib.TestCase): self.assertAllClose(y_tf_np, y_np, eps) self.assertAllClose(y_tf_np_stirling, y_np_stirling, eps) + @test_util.run_deprecated_v1 def testGradient(self): x_shape = [5, 10] x_np = np.random.randn(*x_shape).astype(np.float64) @@ -207,6 +214,7 @@ class LogSoftmaxTest(test_lib.TestCase, parameterized.TestCase): self.assertAllClose(y_pos_axis_tf, z_gt_axis_tf, eps) @parameterized.parameters(((5, 10),), ((2, 3, 4),)) + @test_util.run_deprecated_v1 def testGradient(self, x_shape): x_np = np.random.randn(*x_shape).astype(np.float64) with self.cached_session(): @@ -229,6 +237,7 @@ class L2LossTest(test_lib.TestCase): value = self.evaluate(l2loss) self.assertAllClose(7.0, value) + @test_util.run_deprecated_v1 def testGradient(self): x_shape = [20, 7, 3] np.random.seed(1) # Make it reproducible. @@ -276,6 +285,7 @@ class L2NormalizeTest(test_lib.TestCase): y_tf = nn_impl.l2_normalize_v2(x_tf, dim) self.assertAllClose(y_np, self.evaluate(y_tf)) + @test_util.run_deprecated_v1 def testL2NormalizeGradient(self): x_shape = [20, 7, 3] np.random.seed(1) @@ -361,6 +371,7 @@ class DropoutTest(test_lib.TestCase): sorted_value = np.unique(np.sort(value[i, :])) self.assertEqual(sorted_value.size, 1) + @test_util.run_deprecated_v1 def testDropoutPlaceholderKeepProb(self): # Runs dropout with 0-1 tensor 10 times, sum the number of ones and validate # that it is producing approximately the right number of ones over a large @@ -389,6 +400,7 @@ class DropoutTest(test_lib.TestCase): print(rel_error) self.assertTrue(rel_error < 0.15) + @test_util.run_deprecated_v1 def testShapedDropoutUnknownShape(self): x_dim = 40 y_dim = 30 @@ -422,6 +434,7 @@ class DropoutTest(test_lib.TestCase): print(rel_error) self.assertTrue(rel_error < 0.15) + @test_util.run_deprecated_v1 def testInvalidKeepProb(self): x_dim = 40 y_dim = 30 @@ -437,6 +450,7 @@ class DropoutTest(test_lib.TestCase): with self.assertRaises(ValueError): nn_ops.dropout(t, array_ops.placeholder(dtypes.float32, shape=[2])) + @test_util.run_deprecated_v1 def testShapedDropoutShapeError(self): # Runs shaped dropout and verifies an error is thrown on misshapen noise. x_dim = 40 @@ -457,6 +471,7 @@ class DropoutTest(test_lib.TestCase): _ = nn_ops.dropout(t, keep_prob, noise_shape=[x_dim, 1]) _ = nn_ops.dropout(t, keep_prob, noise_shape=[1, 1]) + @test_util.run_deprecated_v1 def testNoDropoutFast(self): x = array_ops.zeros((5,)) for p in 1, constant_op.constant(1.0): @@ -938,6 +953,7 @@ class ReluTest(test_lib.TestCase): z = self.evaluate(nn_ops.relu(constant_op.constant(x))) self.assertAllEqual(y, z) + @test_util.run_deprecated_v1 def testNaNs(self): # Test that relu(nan) = nan for various sizes. for i in range(18): @@ -966,6 +982,7 @@ class LeakyReluTest(test_lib.TestCase): self.assertLessEqual(outputs.max(), 1.0) self.assertAllClose(inputs, outputs) + @test_util.run_deprecated_v1 def testValues(self): for dtype in [np.int32, np.int64, np.float16, np.float32, np.float64]: np_values = np.array([-2, -1, 0, 1, 2], dtype=dtype) @@ -977,6 +994,7 @@ class LeakyReluTest(test_lib.TestCase): self.assertAllClose( outputs, [-0.4, -0.2, 0.0, 1.0, 2.0], rtol=tol, atol=tol) + @test_util.run_deprecated_v1 def testName(self): np_values = np.array([-2, -1, 0, 1, 2], dtype=np.float64) outputs_with_name_set = nn_ops.leaky_relu( @@ -990,6 +1008,7 @@ class LeakyReluTest(test_lib.TestCase): class SwishTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testValues(self): np_values = np.array( [np.linspace(-10.0, 0.0, 100), @@ -1004,6 +1023,7 @@ class SwishTest(test_lib.TestCase): self.assertAllClose(actual_outputs, expected_outputs) + @test_util.run_deprecated_v1 def testGradients(self): shape = [5, 3, 4] sigma = 5 diff --git a/tensorflow/python/ops/nn_xent_test.py b/tensorflow/python/ops/nn_xent_test.py index 7bf18c47fe..3e5c198fc6 100644 --- a/tensorflow/python/ops/nn_xent_test.py +++ b/tensorflow/python/ops/nn_xent_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import nn_impl @@ -53,6 +54,7 @@ class SigmoidCrossEntropyWithLogitsTest(test.TestCase): losses = np.array(self._SigmoidCrossEntropyWithLogits(x, y)).reshape(*sizes) return logits, targets, losses + @test_util.run_deprecated_v1 def testConstructionNamed(self): with self.cached_session(): logits, targets, _ = self._Inputs() @@ -82,6 +84,7 @@ class SigmoidCrossEntropyWithLogitsTest(test.TestCase): tf_loss = self.evaluate(loss) self.assertAllClose(np_loss, tf_loss, atol=0.001) + @test_util.run_deprecated_v1 def testGradient(self): sizes = [4, 2] with self.cached_session(): @@ -92,6 +95,7 @@ class SigmoidCrossEntropyWithLogitsTest(test.TestCase): print("logistic loss gradient err = ", err) self.assertLess(err, 1e-7) + @test_util.run_deprecated_v1 def testGradientAtZero(self): with self.cached_session(): logits = constant_op.constant([0.0, 0.0], dtype=dtypes.float64) @@ -129,6 +133,7 @@ class WeightedCrossEntropyTest(test.TestCase): losses = np.array(self._WeightedCrossEntropy(x, y, q)).reshape(*sizes) return logits, targets, q, losses + @test_util.run_deprecated_v1 def testConstructionNamed(self): with self.cached_session(): logits, targets, pos_weight, _ = self._Inputs() @@ -157,6 +162,7 @@ class WeightedCrossEntropyTest(test.TestCase): tf_loss = self.evaluate(loss) self.assertAllClose(np_loss, tf_loss, atol=0.001) + @test_util.run_deprecated_v1 def testGradient(self): sizes = [4, 2] with self.cached_session(): diff --git a/tensorflow/python/ops/ragged/convert_to_tensor_or_ragged_tensor_op_test.py b/tensorflow/python/ops/ragged/convert_to_tensor_or_ragged_tensor_op_test.py index 243fa34c4b..ef3464f243 100644 --- a/tensorflow/python/ops/ragged/convert_to_tensor_or_ragged_tensor_op_test.py +++ b/tensorflow/python/ops/ragged/convert_to_tensor_or_ragged_tensor_op_test.py @@ -90,6 +90,7 @@ class RaggedConvertToTensorOrRaggedTensorTest(test_util.TensorFlowTestCase, preferred_dtype=dtypes.string, expected_dtype=dtypes.int32), ]) + @test_util.run_deprecated_v1 def testConvertRaggedTensorValue(self, value, dtype=None, @@ -145,6 +146,7 @@ class RaggedConvertToTensorOrRaggedTensorTest(test_util.TensorFlowTestCase, message=('Tensor conversion requested dtype string for ' 'Tensor with dtype int32')), ]) + @test_util.run_deprecated_v1 def testConvertTensorError(self, pylist, message, diff --git a/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py b/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py index 79a2ecd87a..d9d840500c 100644 --- a/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py @@ -135,6 +135,7 @@ class RaggedBatchGatherOpTest(test_util.TensorFlowTestCase, expected=ragged.constant_value( [[[[b'c', b'a'], [b'd', b'd']], [[b'f', b'e']]]], ragged_rank=2)), ]) + @test_util.run_deprecated_v1 def testRaggedBatchGather(self, descr, params, indices, expected): result = ragged.batch_gather(params, indices) self.assertEqual( @@ -144,6 +145,7 @@ class RaggedBatchGatherOpTest(test_util.TensorFlowTestCase, expected = expected.tolist() self.assertEqual(result.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testRaggedBatchGatherUnknownRankError(self): params = [['a', 'b'], ['c', 'd']] indices = array_ops.placeholder(dtypes.int32, shape=None) @@ -186,6 +188,7 @@ class RaggedBatchGatherOpTest(test_util.TensorFlowTestCase, indices=[[[0]]], message='batch shape from indices does not match params shape'), ]) + @test_util.run_deprecated_v1 def testRaggedBatchGatherStaticError(self, params, indices, diff --git a/tensorflow/python/ops/ragged/ragged_boolean_mask_op_test.py b/tensorflow/python/ops/ragged/ragged_boolean_mask_op_test.py index b3279c1e84..d939d9d634 100644 --- a/tensorflow/python/ops/ragged/ragged_boolean_mask_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_boolean_mask_op_test.py @@ -298,6 +298,7 @@ class RaggedBooleanMaskOpTest(test_util.TensorFlowTestCase, keepdims=True, expected=ragged.constant_value([[[1], [4, 6]], [[7, 9], []]])), ]) # pyformat: disable + @test_util.run_deprecated_v1 def testBooleanMask(self, descr, data, mask, keepdims, expected): actual = ragged.boolean_mask(data, mask, keepdims=keepdims) self.assertEqual( @@ -307,6 +308,7 @@ class RaggedBooleanMaskOpTest(test_util.TensorFlowTestCase, expected = expected.tolist() self.assertEqual(actual.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testErrors(self): self.assertRaisesRegexp(ValueError, r'mask\.shape\.ndims must be kown statically', diff --git a/tensorflow/python/ops/ragged/ragged_concat_op_test.py b/tensorflow/python/ops/ragged/ragged_concat_op_test.py index bddc5d8580..3699f90f46 100644 --- a/tensorflow/python/ops/ragged/ragged_concat_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_concat_op_test.py @@ -221,6 +221,7 @@ class RaggedConcatOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): axis=0, expected=[[b'a00', b'a01'], [], [b'a20', b'a21']]), ) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedConcat(self, descr, rt_inputs, @@ -266,6 +267,7 @@ class RaggedConcatOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): error=ValueError, message='Dimension 0 in both shapes must be equal'), ) + @test_util.run_deprecated_v1 def testStaticError(self, rt_inputs, axis, error, message, ragged_ranks=None): rt_inputs = self._rt_inputs_to_tensors(rt_inputs, ragged_ranks) self.assertRaisesRegexp(error, message, ragged.concat, rt_inputs, axis) @@ -278,6 +280,7 @@ class RaggedConcatOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): error=errors.InvalidArgumentError, message='Input tensors have incompatible shapes'), ]) + @test_util.run_deprecated_v1 def testRuntimeError(self, rt_inputs, axis, error, message, ragged_ranks=None): rt_inputs = [ @@ -287,6 +290,7 @@ class RaggedConcatOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.test_session(): self.assertRaisesRegexp(error, message, concatenated.eval) + @test_util.run_deprecated_v1 def testNegativeAxisWithUnknownRankError(self): rt_inputs = [ array_ops.placeholder(dtypes.int64), @@ -296,6 +300,7 @@ class RaggedConcatOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): ValueError, r'axis may only be negative if ndims is statically known.', ragged.concat, rt_inputs, -1) + @test_util.run_deprecated_v1 def testSingleTensorInput(self): """Tests ragged_concat with a single tensor input. diff --git a/tensorflow/python/ops/ragged/ragged_const_op_test.py b/tensorflow/python/ops/ragged/ragged_const_op_test.py index 9c3b2ac88a..2505b23912 100644 --- a/tensorflow/python/ops/ragged/ragged_const_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_const_op_test.py @@ -133,6 +133,7 @@ class RaggedConstOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): dict(pylist=[[b'a', b'b'], [b'c'], [b'd', b'e', b'f']], dtype=dtypes.string), ) + @test_util.run_deprecated_v1 def testRaggedConst(self, pylist, dtype=None, @@ -258,6 +259,7 @@ class RaggedConstOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): exception=ValueError, message='inner values have inconsistent shape'), ) + @test_util.run_deprecated_v1 def testRaggedConstError(self, pylist, dtype=None, diff --git a/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py b/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py index 26e6b8b6d4..305a96df9c 100644 --- a/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py +++ b/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py @@ -394,6 +394,7 @@ class RaggedElementwiseOpsTest(test_util.TensorFlowTestCase, result_flat_values = array_ops.reshape(result, [-1]) self.assertAllEqual(expected_flat_values, result_flat_values) + @test_util.run_deprecated_v1 def testUnknownRankError(self): x = ragged.constant([[1, 2], [3]]) y = ragged.from_row_splits( diff --git a/tensorflow/python/ops/ragged/ragged_expand_dims_op_test.py b/tensorflow/python/ops/ragged/ragged_expand_dims_op_test.py index 0c4fd458c2..3ff66973b6 100644 --- a/tensorflow/python/ops/ragged/ragged_expand_dims_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_expand_dims_op_test.py @@ -105,6 +105,7 @@ class RaggedExpandDimsOpTest(test_util.TensorFlowTestCase, expected=EXAMPLE4D_EXPAND_AXIS[4], expected_shape=[3, None, None, 2, 1]), ]) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedExpandDims(self, rt_input, axis, diff --git a/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py b/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py index 77418ff20d..3c0db9e8fb 100644 --- a/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_from_sparse_op_test.py @@ -29,6 +29,7 @@ from tensorflow.python.platform import googletest class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testDocStringExample(self): st = sparse_tensor.SparseTensor( indices=[[0, 0], [0, 1], [0, 2], [1, 0], [3, 0]], @@ -39,6 +40,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): with self.test_session(): self.assertEqual(rt.eval().tolist(), [[1, 2, 3], [4], [], [5]]) + @test_util.run_deprecated_v1 def testEmpty(self): st = sparse_tensor.SparseTensor( indices=array_ops.zeros([0, 2], dtype=dtypes.int64), @@ -49,6 +51,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): with self.test_session(): self.assertEqual(rt.eval().tolist(), [[], [], [], []]) + @test_util.run_deprecated_v1 def testBadSparseTensorRank(self): st1 = sparse_tensor.SparseTensor(indices=[[0]], values=[0], dense_shape=[3]) st2 = sparse_tensor.SparseTensor( @@ -64,6 +67,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): self.assertRaisesRegexp(ValueError, r'rank\(st_input\) must be 2', ragged.from_sparse, st3) + @test_util.run_deprecated_v1 def testGoodPartialSparseTensorRank(self): st1 = sparse_tensor.SparseTensor( indices=[[0, 0]], @@ -78,6 +82,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): ragged.from_sparse(st1) ragged.from_sparse(st2) + @test_util.run_deprecated_v1 def testNonRaggedSparseTensor(self): # "index_suffix" means the value of the innermost dimension of the index # (i.e., indices[i][-1]). diff --git a/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py b/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py index 7c59cd0b77..1d8a00cc18 100644 --- a/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py @@ -31,6 +31,7 @@ from tensorflow.python.platform import googletest class RaggedFromTensorOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testDocStringExamples(self): # The examples from ragged.from_tensor.__doc__. dt = constant_op.constant([[5, 7, 0], [0, 3, 0], [6, 0, 0]]) @@ -262,6 +263,7 @@ class RaggedFromTensorOpTest(test_util.TensorFlowTestCase, [[[5, 6], [7]], [[0, 8], []]]] }, ) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedFromTensor(self, tensor, expected, @@ -278,6 +280,7 @@ class RaggedFromTensorOpTest(test_util.TensorFlowTestCase, with self.test_session(): self.assertEqual(rt.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testHighDimensions(self): # Use distinct prime numbers for all dimension shapes in this test, so # we can see any errors that are caused by mixing up dimension sizes. @@ -395,6 +398,7 @@ class RaggedFromTensorOpTest(test_util.TensorFlowTestCase, 'expected': [[], []] }, ) + @test_util.run_deprecated_v1 def testEmpty(self, dt_shape, expected, lengths=None, padding=None): dt = array_ops.zeros(dt_shape) rt = ragged.from_tensor(dt, lengths, padding) @@ -447,6 +451,7 @@ class RaggedFromTensorOpTest(test_util.TensorFlowTestCase, 'error': (ValueError, r'ragged_rank must be greater than 0; got -1') }, ) + @test_util.run_deprecated_v1 def testErrors(self, tensor, lengths=None, diff --git a/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py b/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py index c52db9e2a1..62c6819374 100644 --- a/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py @@ -183,6 +183,7 @@ class RaggedGatherNdOpTest(test_util.TensorFlowTestCase, indices=[[0, 0, 1], [0, 0, 0], [0, 1, 0]], expected=[[b'c', b'd'], [b'a', b'b'], [b'e', b'f']]), ]) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedGatherNd(self, descr, params, indices, expected): result = ragged.gather_nd(params, indices) self.assertEqual( @@ -192,6 +193,7 @@ class RaggedGatherNdOpTest(test_util.TensorFlowTestCase, expected = expected.tolist() self.assertEqual(self.evaluate(result).tolist(), expected) + @test_util.run_deprecated_v1 def testRaggedGatherNdUnknownRankError(self): params = ragged.constant([['a', 'b'], ['c', 'd']]) indices1 = array_ops.placeholder(dtypes.int32, shape=None) @@ -219,6 +221,7 @@ class RaggedGatherNdOpTest(test_util.TensorFlowTestCase, indices=ragged.constant([[0]]), message='The innermost dimension of indices may not be ragged'), ]) + @test_util.run_deprecated_v1 def testRaggedGatherNdStaticError(self, params, indices, diff --git a/tensorflow/python/ops/ragged/ragged_gather_op_test.py b/tensorflow/python/ops/ragged/ragged_gather_op_test.py index bb52d05c32..76c90cdfee 100644 --- a/tensorflow/python/ops/ragged/ragged_gather_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_gather_op_test.py @@ -30,6 +30,7 @@ from tensorflow.python.platform import googletest class RaggedTensorOpsTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testDocStringExamples(self): params = constant_op.constant(['a', 'b', 'c', 'd', 'e']) indices = constant_op.constant([3, 1, 2, 1, 0]) @@ -46,6 +47,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): ragged.gather(ragged_params, ragged_indices).eval().tolist(), [[[b'e'], [b'd'], []], [[b'd']], [], [[b'a', b'b', b'c']]]) + @test_util.run_deprecated_v1 def testTensorParamsAndTensorIndices(self): params = ['a', 'b', 'c', 'd', 'e'] indices = [2, 0, 2, 1] @@ -55,6 +57,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): [b'c', b'a', b'c', b'b']) self.assertEqual(type(ragged.gather(params, indices)), ops.Tensor) + @test_util.run_deprecated_v1 def testRaggedParamsAndTensorIndices(self): params = ragged.constant([['a', 'b'], ['c', 'd', 'e'], ['f'], [], ['g']]) indices = [2, 0, 2, 1] @@ -63,6 +66,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): ragged.gather(params, indices).eval().tolist(), [[b'f'], [b'a', b'b'], [b'f'], [b'c', b'd', b'e']]) + @test_util.run_deprecated_v1 def testTensorParamsAndRaggedIndices(self): params = ['a', 'b', 'c', 'd', 'e'] indices = ragged.constant([[2, 1], [1, 2, 0], [3]]) @@ -71,6 +75,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): ragged.gather(params, indices).eval().tolist(), [[b'c', b'b'], [b'b', b'c', b'a'], [b'd']]) + @test_util.run_deprecated_v1 def testRaggedParamsAndRaggedIndices(self): params = ragged.constant([['a', 'b'], ['c', 'd', 'e'], ['f'], [], ['g']]) indices = ragged.constant([[2, 1], [1, 2, 0], [3]]) @@ -82,6 +87,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): [[]]] # [p[3] ]] ) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedParamsAndScalarIndices(self): params = ragged.constant([['a', 'b'], ['c', 'd', 'e'], ['f'], [], ['g']]) indices = 1 @@ -89,6 +95,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): self.assertEqual( ragged.gather(params, indices).eval().tolist(), [b'c', b'd', b'e']) + @test_util.run_deprecated_v1 def test3DRaggedParamsAnd2DTensorIndices(self): params = ragged.constant([[['a', 'b'], []], [['c', 'd'], ['e'], ['f']], [['g']]]) @@ -101,6 +108,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): [[[b'g']], [[b'g']]]] # [p2, p2]] ) # pyformat: disable + @test_util.run_deprecated_v1 def testTensorParamsAnd4DRaggedIndices(self): indices = ragged.constant( [[[[3, 4], [0, 6]], []], [[[2, 1], [1, 0]], [[2, 5]], [[2, 3]]], @@ -115,6 +123,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): [[[b'c', b'b'], [b'b', b'a']], [[b'c', b'f']], [[b'c', b'd']]], [[[b'b', b'a']]]]) # pyformat: disable + @test_util.run_deprecated_v1 def testOutOfBoundsError(self): tensor_params = ['a', 'b', 'c'] tensor_indices = [0, 1, 2] @@ -131,6 +140,7 @@ class RaggedTensorOpsTest(test_util.TensorFlowTestCase): r'indices\[1\] = 3 is not in \[0, 2\)', ragged.gather(ragged_params, ragged_indices).eval) + @test_util.run_deprecated_v1 def testUnknownIndicesRankError(self): params = ragged.constant([], ragged_rank=1) indices = constant_op.constant([0], dtype=dtypes.int64) diff --git a/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py b/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py index dac86310b9..7a8603c949 100644 --- a/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py @@ -140,6 +140,7 @@ class RaggedMapOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): ), ]) + @test_util.run_deprecated_v1 def testRaggedMap( self, fn, @@ -164,6 +165,7 @@ class RaggedMapOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): output_values = self.evaluate(output) self.assertAllEqual(expected_output, output_values.tolist()) + @test_util.run_deprecated_v1 def testRaggedMapOnStructure(self): batman = ragged.constant([[1, 2, 3], [4], [5, 6, 7]]) # [[10, 20, 30], [40], [50, 60, 70]] @@ -184,6 +186,7 @@ class RaggedMapOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertAllEqual(output.eval().tolist(), [66, 44, 198]) # Test mapping over a dict of RTs can produce a dict of RTs. + @test_util.run_deprecated_v1 def testRaggedMapOnStructure_RaggedOutputs(self): batman = ragged.constant([[1, 2, 3], [4], [5, 6, 7]]) # [[10, 20, 30], [40], [50, 60, 70]] @@ -215,6 +218,7 @@ class RaggedMapOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertAllEqual(output['robin'].eval().tolist(), [[11, 21, 31], [41], [51, 61, 71]]) + @test_util.run_deprecated_v1 def testZip(self): x = ragged.constant([[10, 20], [30, 40], [50, 60], [70], [80, 90, 100]], dtypes.int64) @@ -237,6 +241,7 @@ class RaggedMapOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): result, [[[0, 10], [0, 20]], [[1, 30], [1, 40]], [[2, 50], [2, 60]], [[3, 70]], [[4, 80], [4, 90], [4, 100]]]) + @test_util.run_deprecated_v1 def testBatchGather(self): tokens = ragged.constant([['hello', '.', 'there'], ['merhaba'], ['bonjour', '.', 'ca va', '?']]) diff --git a/tensorflow/python/ops/ragged/ragged_map_inner_values_op_test.py b/tensorflow/python/ops/ragged/ragged_map_inner_values_op_test.py index 798d7c3ce8..b5802cb82d 100644 --- a/tensorflow/python/ops/ragged/ragged_map_inner_values_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_map_inner_values_op_test.py @@ -43,6 +43,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, with self.test_session(): self.assertEqual(result.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testDocStringExamples(self): """Test the examples in apply_op_to_ragged_values.__doc__.""" rt = ragged.constant([[1, 2, 3], [], [4, 5], [6]]) @@ -54,6 +55,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, self.assertEqual(v2.eval().tolist(), [[1, 4, 9], [], [16, 25], [36]]) self.assertEqual(v3.eval().tolist(), [[6, 7, 8], [], [9, 10], [11]]) + @test_util.run_deprecated_v1 def testOpWithSingleRaggedTensorArg(self): tensor = ragged.constant([[1, 2, 3], [], [4, 5]]) self.assertRaggedMapInnerValuesReturns( @@ -61,17 +63,20 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, args=(tensor,), expected=[[0, 0, 0], [], [0, 0]]) + @test_util.run_deprecated_v1 def testOpWithTwoRaggedTensorArgs(self): x = ragged.constant([[3, 1, 4], [], [1, 5]]) y = ragged.constant([[1, 2, 3], [], [4, 5]]) self.assertRaggedMapInnerValuesReturns( op=math_ops.multiply, args=(x, y), expected=[[3, 2, 12], [], [4, 25]]) + @test_util.run_deprecated_v1 def testOpWithRaggedTensorAndScalarArgs(self): y = ragged.constant([[1, 2, 3], [], [4, 5]]) self.assertRaggedMapInnerValuesReturns( op=math_ops.multiply, args=(5, y), expected=[[5, 10, 15], [], [20, 25]]) + @test_util.run_deprecated_v1 def testOpWithThreeRaggedTensorArgs(self): condition = ragged.constant( [[True, True, False], [], [True, False]]) # pyformat: disable @@ -82,6 +87,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, args=(condition, x, y), expected=[[b'a', b'b', b'C'], [], [b'd', b'E']]) + @test_util.run_deprecated_v1 def testOpWithRaggedTensorListArg(self): x = ragged.constant([[1, 2, 3], [], [4, 5]]) y = ragged.constant([[10, 20, 30], [], [40, 50]]) @@ -90,6 +96,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, args=([x, y, x],), expected=[[12, 24, 36], [], [48, 60]]) + @test_util.run_deprecated_v1 def testOpWithKeywordArgs(self): x = ragged.constant([[3, 1, 4], [], [1, 5]]) y = ragged.constant([[1, 2, 3], [], [4, 5]]) @@ -98,6 +105,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, kwargs=dict(x=x, y=y), expected=[[3, 2, 12], [], [4, 25]]) + @test_util.run_deprecated_v1 def testOpWithMixedPositionalAndKeywordArgs(self): x = ragged.constant([[3, 1, 4], [], [1, 5]]) y = ragged.constant([[1, 2, 3], [], [4, 5]]) @@ -107,6 +115,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, kwargs=dict(y=y), expected=[[3, 2, 12], [], [4, 25]]) + @test_util.run_deprecated_v1 def testNonElementWiseOp(self): x = ragged.constant( [[[3, 1, 4], [1, 5, 9], [2, 6, 5]], [], [[3, 5, 8], [9, 7, 9]]], @@ -119,6 +128,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, }, expected=[[8, 15, 13], [], [16, 25]]) + @test_util.run_deprecated_v1 def testOpWithRaggedRankGreaterThanOne(self): # ragged_rank=0 x0 = [3, 1, 4, 1, 5, 9, 2, 6, 5] @@ -163,6 +173,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, [[[54, 14], [48, 45]]] # row 3 ]) # pyformat: disable + @test_util.run_deprecated_v1 def testOpWithRaggedRankThree(self): x = ragged.constant([[[3, 1, 4]], [], [[], [1, 5]]]) y = ragged.constant([[[1, 2, 3]], [], [[], [4, 5]]]) @@ -171,6 +182,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, args=(x, y), expected=[[[3, 2, 12]], [], [[], [4, 25]]]) + @test_util.run_deprecated_v1 def testOpWithInnerValuesOnly(self): x = constant_op.constant([[1, 2], [3, 4], [5, 6]]) y = constant_op.constant(2) @@ -191,6 +203,7 @@ class RaggedMapInnerValuesOpTest(test_util.TensorFlowTestCase, r'Inputs must have identical ragged splits.*', ragged.map_inner_values, math_ops.add, x, y) + @test_util.run_deprecated_v1 def testRaggedTensorSplitsMismatchErrorAtRuntime(self): splits1 = array_ops.placeholder_with_default( constant_op.constant([0, 3, 3, 5], dtypes.int64), None) diff --git a/tensorflow/python/ops/ragged/ragged_operators_test.py b/tensorflow/python/ops/ragged/ragged_operators_test.py index a99d788ef7..7fe8159d82 100644 --- a/tensorflow/python/ops/ragged/ragged_operators_test.py +++ b/tensorflow/python/ops/ragged/ragged_operators_test.py @@ -27,6 +27,7 @@ class RaggedElementwiseOpsTest(test_util.TensorFlowTestCase): # @TODO(edloper): Test right-handed versions of operators once we add # broadcasting support for elementwise ops. + @test_util.run_deprecated_v1 def testOrderingOperators(self): x = ragged.constant([[1, 5], [3]]) y = ragged.constant([[4, 5], [1]]) @@ -40,6 +41,7 @@ class RaggedElementwiseOpsTest(test_util.TensorFlowTestCase): if a != b: print('%30s %s' % (b, a)) + @test_util.run_deprecated_v1 def testArithmeticOperators(self): x = ragged.constant([[1.0, -2.0], [8.0]]) y = ragged.constant([[4.0, 4.0], [2.0]]) @@ -75,6 +77,7 @@ class RaggedElementwiseOpsTest(test_util.TensorFlowTestCase): self.assertEqual((2.0 % y).eval().tolist(), [[2.0, 2.0], [0.0]]) self.assertEqual((x % 2.0).eval().tolist(), [[1.0, 0.0], [0.0]]) + @test_util.run_deprecated_v1 def testLogicalOperators(self): a = ragged.constant([[True, True], [False]]) b = ragged.constant([[True, False], [False]]) diff --git a/tensorflow/python/ops/ragged/ragged_range_op_test.py b/tensorflow/python/ops/ragged/ragged_range_op_test.py index 3c6a6fb75c..644423ecb7 100644 --- a/tensorflow/python/ops/ragged/ragged_range_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_range_op_test.py @@ -26,6 +26,7 @@ from tensorflow.python.platform import googletest class RaggedRangeOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testDocStringExamples(self): """Examples from ragged_range.__doc__.""" with self.test_session(): @@ -38,6 +39,7 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): rt3 = ragged.range([0, 5, 8], [3, 3, 12], 2).eval().tolist() self.assertEqual(rt3, [[0, 2], [], [8, 10]]) + @test_util.run_deprecated_v1 def testBasicRanges(self): with self.test_session(): # Specify limits only. @@ -56,6 +58,7 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): [list(range(0, 4, 2)), list(range(3, 4, 3)), list(range(5, 15, 4))]) + @test_util.run_deprecated_v1 def testFloatRanges(self): with self.test_session(): expected = [[0.0, 0.4, 0.8, 1.2, 1.6, 2.0, 2.4, 2.8, 3.2, 3.6], [3.0], @@ -64,6 +67,7 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): [0.4, 1.5, 2.2]).eval().tolist() self.assertEqual(expected, [[round(v, 5) for v in row] for row in actual]) + @test_util.run_deprecated_v1 def testNegativeDeltas(self): with self.test_session(): self.assertEqual( @@ -77,6 +81,7 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): [list(range(0, 0, -1)), list(range(-3, 0, 1)), list(range(5, 0, -2))]) + @test_util.run_deprecated_v1 def testBroadcast(self): with self.test_session(): # Specify starts and limits, broadcast deltas. @@ -89,6 +94,7 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): self.assertEqual( ragged.range(0, 5, 1).eval().tolist(), [list(range(0, 5, 1))]) + @test_util.run_deprecated_v1 def testEmptyRanges(self): rt1 = ragged.range([0, 5, 3], [0, 3, 5]) rt2 = ragged.range([0, 5, 5], [0, 3, 5], -1) @@ -96,6 +102,7 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): self.assertEqual(rt1.eval().tolist(), [[], [], [3, 4]]) self.assertEqual(rt2.eval().tolist(), [[], [5, 4], []]) + @test_util.run_deprecated_v1 def testShapeFnErrors(self): with self.test_session(): self.assertRaisesRegexp(ValueError, r'Shape must be at most rank 1.*', @@ -107,12 +114,14 @@ class RaggedRangeOpTest(test_util.TensorFlowTestCase): self.assertRaisesRegexp(ValueError, r'Dimensions must be equal.*', ragged.range, [0], [1, 2]) + @test_util.run_deprecated_v1 def testKernelErrors(self): with self.test_session(): self.assertRaisesRegexp(errors.InvalidArgumentError, r'Requires delta != 0', ragged.range(0, 0, 0).eval) + @test_util.run_deprecated_v1 def testShape(self): self.assertEqual(ragged.range(0, 0, 0).shape.as_list(), [1, None]) self.assertEqual(ragged.range([1, 2, 3]).shape.as_list(), [3, None]) diff --git a/tensorflow/python/ops/ragged/ragged_reduce_op_test.py b/tensorflow/python/ops/ragged/ragged_reduce_op_test.py index 93176c738d..9f51d59ba3 100644 --- a/tensorflow/python/ops/ragged/ragged_reduce_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_reduce_op_test.py @@ -300,6 +300,7 @@ class RaggedReduceOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): axis=2, expected=[[mean(1, 2), mean(3, 4, 5)], [mean(6, 7), 8], [9]]), ) + @test_util.run_deprecated_v1 def testReduce(self, ragged_reduce_op, rt_input, axis, expected): rt_input = ragged.constant(rt_input) reduced = ragged_reduce_op(rt_input, axis) @@ -311,6 +312,7 @@ class RaggedReduceOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertTrue( ((actual == expected) | (np.isnan(actual) & np.isnan(expected))).all()) + @test_util.run_deprecated_v1 def testMeanNan(self): rt_as_list = [[0, 1, 2, 3], [4], [], [5, 6], [7], [8, 9]] expected = ( @@ -321,6 +323,7 @@ class RaggedReduceOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.test_session(): self.assertEqualWithNan(reduced.eval(), expected) + @test_util.run_deprecated_v1 def testMeanWithTensorInputs(self): tensor = [[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]] expected = [2.0, 20.0] @@ -328,6 +331,7 @@ class RaggedReduceOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.test_session(): self.assertAllEqual(reduced.eval(), expected) + @test_util.run_deprecated_v1 def testErrors(self): rt_input = ragged.constant([[1, 2, 3], [4, 5]]) axis = array_ops.placeholder_with_default(constant_op.constant([0]), None) diff --git a/tensorflow/python/ops/ragged/ragged_row_lengths_op_test.py b/tensorflow/python/ops/ragged/ragged_row_lengths_op_test.py index 4d5a0a5d11..4a705be484 100644 --- a/tensorflow/python/ops/ragged/ragged_row_lengths_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_row_lengths_op_test.py @@ -143,6 +143,7 @@ class RaggedRowLengthsOp(test_util.TensorFlowTestCase, parameterized.TestCase): expected=[[2, 3, 0], [4, 1]], expected_ragged_rank=1), ]) # pyformat: disable + @test_util.run_deprecated_v1 def testRowLengths(self, rt_input, expected, diff --git a/tensorflow/python/ops/ragged/ragged_row_splits_to_segment_ids_op_test.py b/tensorflow/python/ops/ragged/ragged_row_splits_to_segment_ids_op_test.py index f246bf3552..7f5f4e91bd 100644 --- a/tensorflow/python/ops/ragged/ragged_row_splits_to_segment_ids_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_row_splits_to_segment_ids_op_test.py @@ -26,6 +26,7 @@ from tensorflow.python.platform import googletest class RaggedSplitsToSegmentIdsOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testDocStringExample(self): splits = [0, 3, 3, 5, 6, 9] expected = [0, 0, 0, 2, 2, 3, 4, 4, 4] @@ -33,12 +34,14 @@ class RaggedSplitsToSegmentIdsOpTest(test_util.TensorFlowTestCase): with self.test_session(): self.assertEqual(segment_ids.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testEmptySplits(self): # Note: the splits for an empty ragged tensor contains a single zero. segment_ids = ragged.row_splits_to_segment_ids([0]) with self.test_session(): self.assertEqual(segment_ids.eval().tolist(), []) + @test_util.run_deprecated_v1 def testErrors(self): self.assertRaisesRegexp(ValueError, r'Invalid row_splits: \[\]', ragged.row_splits_to_segment_ids, []) diff --git a/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py b/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py index fa7adf66b0..7e52f2d844 100644 --- a/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py @@ -26,6 +26,7 @@ from tensorflow.python.platform import googletest class RaggedSplitsToSegmentIdsOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testDocStringExample(self): segment_ids = [0, 0, 0, 2, 2, 3, 4, 4, 4] expected = [0, 3, 3, 5, 6, 9] @@ -33,6 +34,7 @@ class RaggedSplitsToSegmentIdsOpTest(test_util.TensorFlowTestCase): with self.test_session(): self.assertEqual(splits.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testEmptySegmentIds(self): # Note: the splits for an empty ragged tensor contains a single zero. segment_ids = ragged.segment_ids_to_row_splits([]) @@ -49,6 +51,7 @@ class RaggedSplitsToSegmentIdsOpTest(test_util.TensorFlowTestCase): self.assertRaisesRegexp(ValueError, r'Shape \(1, 1\) must have rank 1', ragged.segment_ids_to_row_splits, [[0]]) + @test_util.run_deprecated_v1 def testNumSegments(self): segment_ids = [0, 0, 0, 2, 2, 3, 4, 4, 4] num_segments = 7 @@ -57,6 +60,7 @@ class RaggedSplitsToSegmentIdsOpTest(test_util.TensorFlowTestCase): with self.test_session(): self.assertEqual(splits.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testUnsortedSegmentIds(self): # Segment ids are not required to be sorted. segment_ids = [0, 4, 3, 2, 4, 4, 2, 0, 0] diff --git a/tensorflow/python/ops/ragged/ragged_segment_op_test.py b/tensorflow/python/ops/ragged/ragged_segment_op_test.py index 40a101b4da..9e4877ae3e 100644 --- a/tensorflow/python/ops/ragged/ragged_segment_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_segment_op_test.py @@ -110,6 +110,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, (ragged.segment_mean, mean, [5, 4, 3, 2, 1, 0]), (ragged.segment_mean, mean, [0, 0, 0, 10, 10, 10]), ) + @test_util.run_deprecated_v1 def testRaggedSegment_Int(self, segment_op, combiner, segment_ids): rt_as_list = [[0, 1, 2, 3], [4], [], [5, 6], [7], [8, 9]] rt = ragged.constant(rt_as_list) @@ -146,6 +147,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, (ragged.segment_sqrt_n, sqrt_n, [5, 4, 3, 2, 1, 0]), (ragged.segment_sqrt_n, sqrt_n, [0, 0, 0, 10, 10, 10]), ) + @test_util.run_deprecated_v1 def testRaggedSegment_Float(self, segment_op, combiner, segment_ids): rt_as_list = [[0., 1., 2., 3.], [4.], [], [5., 6.], [7.], [8., 9.]] rt = ragged.constant(rt_as_list) @@ -157,6 +159,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, self.assertNestedListAmostEqual( self.evaluate(segmented).tolist(), expected, places=5) + @test_util.run_deprecated_v1 def testRaggedRankTwo(self): rt = ragged.constant([ [[111, 112, 113, 114], [121],], # row 0 @@ -179,6 +182,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, []] # pyformat: disable self.assertEqual(self.evaluate(segmented2).tolist(), expected2) + @test_util.run_deprecated_v1 def testRaggedSegmentIds(self): rt = ragged.constant([ [[111, 112, 113, 114], [121],], # row 0 @@ -201,6 +205,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, 'but segment_ids is ragged and data is not.', ragged.segment_sum, dt, segment_ids, 3) + @test_util.run_deprecated_v1 def testShapeMismatchError2(self): rt = ragged.constant([ [[111, 112, 113, 114], [121]], # row 0 diff --git a/tensorflow/python/ops/ragged/ragged_stack_op_test.py b/tensorflow/python/ops/ragged/ragged_stack_op_test.py index d474a749f0..4343471694 100644 --- a/tensorflow/python/ops/ragged/ragged_stack_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_stack_op_test.py @@ -265,6 +265,7 @@ class RaggedStackOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): axis=0, expected=[[[b'a00', b'a01'], [], [b'a20', b'a21']]]), ) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedStack(self, descr, rt_inputs, @@ -313,6 +314,7 @@ class RaggedStackOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): def testError(self, rt_inputs, axis, error, message): self.assertRaisesRegexp(error, message, ragged.stack, rt_inputs, axis) + @test_util.run_deprecated_v1 def testSingleTensorInput(self): """Tests ragged_stack with a single tensor input. diff --git a/tensorflow/python/ops/ragged/ragged_tensor_test.py b/tensorflow/python/ops/ragged/ragged_tensor_test.py index fa681c07bb..608fbd6e5b 100644 --- a/tensorflow/python/ops/ragged/ragged_tensor_test.py +++ b/tensorflow/python/ops/ragged/ragged_tensor_test.py @@ -114,6 +114,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # RaggedTensor class docstring examples #============================================================================= + @test_util.run_deprecated_v1 def testClassDocStringExamples(self): # From section: "Component Tensors" rt = ragged.from_row_splits( @@ -199,6 +200,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # RaggedTensor Constructor (private) #============================================================================= + @test_util.run_deprecated_v1 def testRaggedTensorConstruction(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64) @@ -243,6 +245,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # RaggedTensor Factory Ops #============================================================================= + @test_util.run_deprecated_v1 def testFromValueRowIdsWithDerivedNRows(self): # nrows is known at graph creation time. values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -265,6 +268,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + @test_util.run_deprecated_v1 def testFromValueRowIdsWithDerivedNRowsDynamic(self): # nrows is not known at graph creation time. values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -288,6 +292,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + @test_util.run_deprecated_v1 def testFromValueRowIdsWithExplicitNRows(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64) @@ -309,6 +314,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g'], [], []]) + @test_util.run_deprecated_v1 def testFromValueRowIdsWithExplicitNRowsEqualToDefault(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) value_rowids = constant_op.constant([0, 0, 2, 2, 2, 3, 4], dtypes.int64) @@ -332,6 +338,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + @test_util.run_deprecated_v1 def testFromValueRowIdsWithEmptyValues(self): rt = ragged.from_value_rowids([], []) rt_nrows = ragged.nrows(rt) @@ -343,6 +350,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertEqual(self.evaluate(rt_nrows).tolist(), 0) self.assertEqual(self.evaluate(rt).tolist(), []) + @test_util.run_deprecated_v1 def testFromRowSplits(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64) @@ -368,6 +376,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.assertRaisesRegexp(ValueError, err_msg): ragged.from_row_splits([], []) + @test_util.run_deprecated_v1 def testFromRowStarts(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) row_starts = constant_op.constant([0, 2, 2, 5, 6], dtypes.int64) @@ -388,6 +397,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + @test_util.run_deprecated_v1 def testFromRowLimits(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) row_limits = constant_op.constant([2, 2, 5, 6, 7], dtypes.int64) @@ -408,6 +418,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + @test_util.run_deprecated_v1 def testFromRowLengths(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) row_lengths = constant_op.constant([2, 0, 3, 1, 1], dtypes.int64) @@ -429,6 +440,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + @test_util.run_deprecated_v1 def testFromNestedValueRowIdsWithDerivedNRows(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) nested_value_rowids = [ @@ -453,6 +465,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.evaluate(rt).tolist(), [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) + @test_util.run_deprecated_v1 def testFromNestedValueRowIdsWithExplicitNRows(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) nested_value_rowids = [ @@ -509,6 +522,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): ragged.from_nested_value_rowids([1, 2, 3], [[0, 1, 2], [0, 1, 2]], constant_op.constant([3, 3])) + @test_util.run_deprecated_v1 def testFromNestedRowSplits(self): inner_values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) nested_row_splits = [ @@ -576,6 +590,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): value_rowids=value_rowids, nrows=array_ops.expand_dims(nrows, 0)) + @test_util.run_deprecated_v1 def testGraphMismatch(self): with ops.Graph().as_default(): values = constant_op.constant([1, 2, 3]) @@ -588,6 +603,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # Ragged Value & Row-Partitioning Tensor Accessors #============================================================================= + @test_util.run_deprecated_v1 def testRaggedTensorAccessors_2d(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64) @@ -622,6 +638,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): [self.evaluate(s).tolist() for s in rt.nested_row_splits], [[0, 2, 2, 5, 6, 7]]) + @test_util.run_deprecated_v1 def testRaggedTensorAccessors_3d_with_ragged_rank_1(self): values = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]] row_splits = constant_op.constant([0, 2, 2, 5, 6, 7], dtypes.int64) @@ -657,6 +674,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): [self.evaluate(s).tolist() for s in rt.nested_row_splits], [[0, 2, 2, 5, 6, 7]]) + @test_util.run_deprecated_v1 def testRaggedTensorAccessors_3d_with_ragged_rank_2(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) nested_row_splits = [ @@ -709,6 +727,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # RaggedTensor.shape #============================================================================= + @test_util.run_deprecated_v1 def testShape(self): """Tests for RaggedTensor.shape.""" rt1 = ragged.from_row_splits(b'a b c d e f g'.split(), [0, 2, 5, 6, 6, 7]) @@ -842,6 +861,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): (SLICE_BUILDER[:, -2:], [row[-2:] for row in EXAMPLE_RAGGED_TENSOR_2D]), # TODO(edloper): Add tests for strided slices, once support is added. ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemWithRaggedRank1(self, slice_spec, expected): """Test that rt.__getitem__(slice_spec) == expected.""" # Ragged tensor @@ -883,6 +903,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): (SLICE_BUILDER[..., 0, 0, 0], IndexError, 'Too many indices for RaggedTensor'), ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemErrorsWithRaggedRank1(self, slice_spec, expected, message): """Test that rt.__getitem__(slice_spec) == expected.""" @@ -961,6 +982,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # TODO(edloper): Add tests slicing inner ragged dimensions, one support # is added. ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemWithRaggedRank2(self, slice_spec, expected): """Test that rt.__getitem__(slice_spec) == expected.""" rt = ragged.from_nested_row_splits( @@ -982,6 +1004,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): (SLICE_BUILDER[5], ValueError, '.*out of bounds.*'), (SLICE_BUILDER[0, 5], ValueError, '.*out of bounds.*'), ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemErrorsWithRaggedRank2(self, slice_spec, expected, message): """Test that rt.__getitem__(slice_spec) == expected.""" @@ -996,6 +1019,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): (SLICE_BUILDER[2:], []), (SLICE_BUILDER[:-3], []), ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemWithEmptyTensor(self, slice_spec, expected): """Test that rt.__getitem__(slice_spec) == expected.""" rt = ragged.from_row_splits([], [0]) @@ -1005,6 +1029,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): (SLICE_BUILDER[0], ValueError, '.*out of bounds.*'), (SLICE_BUILDER[-1], ValueError, '.*out of bounds.*'), ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemErrorsWithEmptyTensor(self, slice_spec, expected, message): """Test that rt.__getitem__(slice_spec) == expected.""" @@ -1020,6 +1045,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): (SLICE_BUILDER[0, 1], EXAMPLE_RAGGED_TENSOR_2D[0][1]), (SLICE_BUILDER[-3, 0], EXAMPLE_RAGGED_TENSOR_2D[-3][0]), ) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemWithPlaceholderShapes(self, slice_spec, expected): """Test that rt.__getitem__(slice_spec) == expected.""" # Intentionally use an unknown shape for `splits`, to force the code path @@ -1034,6 +1060,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): @parameterized.parameters( (SLICE_BUILDER[..., 2], ValueError, 'Ellipsis not supported for unknown shape RaggedTensors'),) + @test_util.run_deprecated_v1 def testRaggedTensorGetItemErrorsWithPlaceholderShapes( self, slice_spec, expected, message): """Test that rt.__getitem__(slice_spec) == expected.""" @@ -1042,6 +1069,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt = ragged.from_row_splits(values, [0, 1]) self._TestGetItemException(rt, slice_spec, expected, message) + @test_util.run_deprecated_v1 def testGetItemNewAxis(self): # rt: [[[['a', 'b'], ['c', 'd']], [], [['e', 'f']]], []] splits1 = [0, 3, 3] @@ -1089,6 +1117,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): #============================================================================= # RaggedTensor.__str__ #============================================================================= + @test_util.run_deprecated_v1 def testRaggedTensorStr(self): rt1 = ragged.from_row_splits(b'a b c d e f g'.split(), [0, 2, 5, 6, 6, 7]) expected1 = ('RaggedTensor(values=Tensor("RaggedFromRowSplits/values:0", ' @@ -1126,6 +1155,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # RaggedTensor.with_values() and RaggedTensor.with_inner_values(). #============================================================================= + @test_util.run_deprecated_v1 def testWithValues(self): rt1 = ragged.constant([[1, 2], [3, 4, 5], [6], [], [7]]) rt2 = ragged.constant([[[1, 2], [3, 4, 5]], [[6]], [], [[], [7]]]) @@ -1147,6 +1177,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): #============================================================================= # Session.run #============================================================================= + @test_util.run_deprecated_v1 def testSessionRun(self): rt1 = ragged.constant([[1, 2, 3], [4]]) rt2 = ragged.constant([[[], [1, 2]], [[3]]]) @@ -1156,6 +1187,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertEqual(result['rt1'].tolist(), [[1, 2, 3], [4]]) self.assertEqual(result['rt2'].tolist(), [[[], [1, 2]], [[3]]]) + @test_util.run_deprecated_v1 def testSessionRunFeed(self): rt1 = ragged.from_row_splits( array_ops.placeholder(dtypes.int32), @@ -1176,6 +1208,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertEqual(result['rt1'].tolist(), [[1, 2, 3], [4]]) self.assertEqual(result['rt2'].tolist(), [[[], [1, 2]], [[3]]]) + @test_util.run_deprecated_v1 def testSessionPartialRunFeed(self): # Placeholder inputs. a = ragged.from_row_splits( diff --git a/tensorflow/python/ops/ragged/ragged_tile_op_test.py b/tensorflow/python/ops/ragged/ragged_tile_op_test.py index 672d212114..f335b15dd1 100644 --- a/tensorflow/python/ops/ragged/ragged_tile_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_tile_op_test.py @@ -181,6 +181,7 @@ class RaggedTileOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): [[[5], [6]]]]), ]) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedTile(self, descr, rt_input, @@ -209,6 +210,7 @@ class RaggedTileOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.test_session(): self.assertEqual(tiled.eval().tolist(), expected) + @test_util.run_deprecated_v1 def testRaggedTileWithTensorInput(self): # When the input is a `Tensor`, ragged_tile just delegates to tf.tile. dt = constant_op.constant([[1, 2], [3, 4]]) diff --git a/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py b/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py index cb8e82c00d..69b31ad0e9 100644 --- a/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py @@ -30,6 +30,7 @@ from tensorflow.python.platform import googletest class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): + @test_util.run_deprecated_v1 def testDocStringExample(self): rt = ragged.constant([[1, 2, 3], [4], [], [5, 6]]) st = ragged.to_sparse(rt) @@ -40,6 +41,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): with self.test_session(): self.assertEqual(' '.join(repr(st.eval()).split()), expected) + @test_util.run_deprecated_v1 def test2DRaggedTensorWithOneRaggedDimension(self): rt = ragged.constant([['a', 'b'], ['c', 'd', 'e'], ['f'], [], ['g']]) with self.test_session(): @@ -49,6 +51,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): self.assertAllEqual(st.values, b'a b c d e f g'.split()) self.assertAllEqual(st.dense_shape, [5, 3]) + @test_util.run_deprecated_v1 def test3DRaggedTensorWithOneRaggedDimension(self): rt = ragged.constant([[[1, 2], [3, 4]], [[5, 6], [7, 8], [9, 10]], [[11, 12]], [], [[13, 14]]], @@ -63,6 +66,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]) self.assertAllEqual(st.dense_shape, [5, 3, 2]) + @test_util.run_deprecated_v1 def test4DRaggedTensorWithOneRaggedDimension(self): rt = ragged.constant( [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], [], [[[9, 10], [11, 12]]]], @@ -88,6 +92,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): ]) self.assertAllEqual(st.dense_shape, [3, 2, 2, 2]) + @test_util.run_deprecated_v1 def test4DRaggedTensorWithTwoRaggedDimensions(self): rt = ragged.constant([[[[1, 2], [3, 4]], [[5, 6], [7, 8], [9, 10]]], [[[11, 12]], [], [[13, 14]]], []], @@ -135,6 +140,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): self.assertEqual(st.values.shape.as_list(), [7]) self.assertEqual(st.dense_shape.shape.as_list(), [3]) + @test_util.run_deprecated_v1 def testKernelErrors(self): # An empty vector, defined using a placeholder to ensure that we can't # determine that it's invalid at graph-construction time. @@ -173,6 +179,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): self.assertRaisesRegexp(errors.InvalidArgumentError, empty_splits_error, ragged.to_sparse(bad_rt5).eval) + @test_util.run_deprecated_v1 def testGradient(self): # rt1.shape == rt2.shape == [2, (D2), (D3), 2]. rt1 = ragged.constant([[[[1.0, 2.0], [3.0, 4.0]], [[5.0, 6.0]]]], diff --git a/tensorflow/python/ops/ragged/ragged_to_tensor_op_test.py b/tensorflow/python/ops/ragged/ragged_to_tensor_op_test.py index 688676e46c..77499b9cb3 100644 --- a/tensorflow/python/ops/ragged/ragged_to_tensor_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_to_tensor_op_test.py @@ -30,6 +30,7 @@ from tensorflow.python.platform import googletest class RaggedTensorToTensorOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): + @test_util.run_deprecated_v1 def testDocStringExamples(self): """Example from ragged_to_tensor.__doc__.""" rt = ragged.constant([[9, 8, 7], [], [6, 5], [4]]) @@ -97,6 +98,7 @@ class RaggedTensorToTensorOpTest(test_util.TensorFlowTestCase, 'expected': [[[[1], [2]], [[9], [9]], [[3], [9]]]], }, ) + @test_util.run_deprecated_v1 def testRaggedTensorToTensor(self, rt_input, expected, @@ -132,6 +134,7 @@ class RaggedTensorToTensorOpTest(test_util.TensorFlowTestCase, 'error': (TypeError, "Expected int32, got 'a' of type 'str' instead"), }, ) + @test_util.run_deprecated_v1 def testError(self, rt_input, default, error, ragged_rank=None): rt = ragged.constant(rt_input, ragged_rank=ragged_rank) with self.assertRaisesRegexp(error[0], error[1]): diff --git a/tensorflow/python/ops/ragged/ragged_where_op_test.py b/tensorflow/python/ops/ragged/ragged_where_op_test.py index 03672e4521..de83a54977 100644 --- a/tensorflow/python/ops/ragged/ragged_where_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_where_op_test.py @@ -165,6 +165,7 @@ class RaggedWhereOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): y=ragged.constant_value([[[['a']]], [[['b']]]]), expected=ragged.constant_value([[[[], [b'A']]], [[[b'b']]]])), ]) # pyformat: disable + @test_util.run_deprecated_v1 def testRaggedWhere(self, condition, expected, x=None, y=None): result = ragged.where(condition, x, y) self.assertEqual( diff --git a/tensorflow/python/ops/sort_ops_test.py b/tensorflow/python/ops/sort_ops_test.py index 8a92f49266..17ce604cbf 100644 --- a/tensorflow/python/ops/sort_ops_test.py +++ b/tensorflow/python/ops/sort_ops_test.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import sort_ops @@ -33,9 +34,11 @@ from tensorflow.python.platform import test class SortTest(test.TestCase): + @test_util.run_deprecated_v1 def testRandom_lowDimensionality(self): self._testRandom_lowDimensionality(negative_axis=False) + @test_util.run_deprecated_v1 def testRandom_lowDimensionality_negative(self): self._testRandom_lowDimensionality(negative_axis=True) @@ -53,6 +56,7 @@ class SortTest(test.TestCase): np.sort(arr, axis=sort_axis), sort_ops.sort(constant_op.constant(arr), axis=sort_axis).eval()) + @test_util.run_deprecated_v1 def testRandom_highDimensionality(self): np.random.seed(100) for _ in range(20): @@ -65,6 +69,7 @@ class SortTest(test.TestCase): np.sort(arr, axis=sort_axis), sort_ops.sort(constant_op.constant(arr), axis=sort_axis).eval()) + @test_util.run_deprecated_v1 def testScalar(self): # Create an empty scalar where the static shape is unknown. zeros_length_1 = array_ops.zeros( @@ -77,11 +82,13 @@ class SortTest(test.TestCase): with self.assertRaises(errors.InvalidArgumentError): sort.eval() + @test_util.run_deprecated_v1 def testNegativeOutOfBounds_staticShape(self): arr = constant_op.constant([3, 4, 5]) with self.assertRaises(ValueError): sort_ops.sort(arr, axis=-4) + @test_util.run_deprecated_v1 def testDescending(self): arr = np.random.random((10, 5, 5)) with self.cached_session(): @@ -90,6 +97,7 @@ class SortTest(test.TestCase): sort_ops.sort( constant_op.constant(arr), axis=0, direction='DESCENDING').eval()) + @test_util.run_deprecated_v1 def testSort_staticallyKnownRank_constantTransposition(self): # The transposition array should be a constant if the rank of "values" is # statically known. @@ -107,6 +115,7 @@ class SortTest(test.TestCase): tensor_util.constant_value(transposition), [0, 4, 2, 3, 1]) + @test_util.run_deprecated_v1 def testArgsort_1d(self): arr = np.random.random(42) with self.cached_session(): @@ -114,6 +123,7 @@ class SortTest(test.TestCase): np.sort(arr), array_ops.gather(arr, sort_ops.argsort(arr)).eval()) + @test_util.run_deprecated_v1 def testArgsort(self): arr = np.random.random((5, 6, 7, 8)) for axis in range(4): diff --git a/tensorflow/python/ops/special_math_ops_test.py b/tensorflow/python/ops/special_math_ops_test.py index 7438cdb3f1..94aaebed95 100644 --- a/tensorflow/python/ops/special_math_ops_test.py +++ b/tensorflow/python/ops/special_math_ops_test.py @@ -46,6 +46,7 @@ class LBetaTest(test.TestCase): 0.5, self.evaluate(math_ops.exp(special_math_ops.lbeta(x_one_half)))) self.assertEqual([], special_math_ops.lbeta(x_one).get_shape()) + @test_util.run_deprecated_v1 def test_one_dimensional_arg_dynamic(self): # Should evaluate to 1 and 1/2. x_one = [1, 1.] @@ -57,6 +58,7 @@ class LBetaTest(test.TestCase): self.assertAllClose(0.5, beta_ph.eval(feed_dict={ph: x_one_half})) + @test_util.run_deprecated_v1 def test_four_dimensional_arg_with_partial_shape_dynamic(self): x_ = np.ones((3, 2, 3, 4)) # Gamma(1) = 0! = 1 @@ -81,6 +83,7 @@ class LBetaTest(test.TestCase): self.evaluate(math_ops.exp(special_math_ops.lbeta(x_one_half)))) self.assertEqual((2,), special_math_ops.lbeta(x_one_half).get_shape()) + @test_util.run_deprecated_v1 def test_two_dimensional_arg_dynamic(self): # Should evaluate to 1/2. x_one_half = [[2, 1.], [2, 1.]] @@ -288,6 +291,7 @@ class EinsumTest(test.TestCase): for case in self.long_cases: self.run_test(case) + @test_util.run_deprecated_v1 def test_invalid(self): for axes in self.invalid_cases: inputs = [ @@ -297,6 +301,7 @@ class EinsumTest(test.TestCase): with self.assertRaises(ValueError): _ = special_math_ops.einsum(axes, *inputs) + @test_util.run_deprecated_v1 def test_invalid_keyword_arguments(self): m0 = array_ops.placeholder(dtypes.int32, shape=(1, None)) m1 = array_ops.placeholder(dtypes.int32, shape=(None, 1)) @@ -311,11 +316,13 @@ class EinsumTest(test.TestCase): invalid1='value1', invalid2='value2') + @test_util.run_deprecated_v1 def test_repeated_axis_single_input(self): x = array_ops.placeholder(dtypes.float32, shape=[2, 2]) with self.assertRaises(ValueError): _ = special_math_ops.einsum('ii->', x) + @test_util.run_deprecated_v1 def test_dim_mismatch(self): for axes, input_shapes in self.dim_mismatch_cases: inputs = [ diff --git a/tensorflow/python/profiler/internal/run_metadata_test.py b/tensorflow/python/profiler/internal/run_metadata_test.py index 216cc3dd54..a8859f845b 100644 --- a/tensorflow/python/profiler/internal/run_metadata_test.py +++ b/tensorflow/python/profiler/internal/run_metadata_test.py @@ -26,6 +26,7 @@ from tensorflow.core.protobuf import config_pb2 from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.client import session from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import variables @@ -154,6 +155,7 @@ class RunMetadataTest(test.TestCase): # deallocates the memory after matmul started. self.assertGreater(random_allocs[1].alloc_micros, mm.all_start_micros) + @test_util.run_deprecated_v1 def testCPU(self): ops.reset_default_graph() with ops.device('/cpu:0'): @@ -167,6 +169,7 @@ class RunMetadataTest(test.TestCase): ret = _extract_node(run_meta, 'MatMul:MatMul') self.assertEqual(len(ret), 0) + @test_util.run_deprecated_v1 def testLoopCPU(self): ops.reset_default_graph() with ops.device('/cpu:0'): diff --git a/tensorflow/python/profiler/pprof_profiler_test.py b/tensorflow/python/profiler/pprof_profiler_test.py index 11a3487360..120a0d0eaa 100644 --- a/tensorflow/python/profiler/pprof_profiler_test.py +++ b/tensorflow/python/profiler/pprof_profiler_test.py @@ -24,6 +24,7 @@ from proto import profile_pb2 from tensorflow.core.framework import step_stats_pb2 from tensorflow.core.protobuf import config_pb2 from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -135,6 +136,7 @@ comment: 9 profile.ParseFromString(profile_contents) self.assertEquals(expected_proto, str(profile)) + @test_util.run_deprecated_v1 def testProfileWithWhileLoop(self): options = config_pb2.RunOptions() options.trace_level = config_pb2.RunOptions.FULL_TRACE diff --git a/tensorflow/python/profiler/profile_context_test.py b/tensorflow/python/profiler/profile_context_test.py index 680cd71d1f..885f08ca4b 100644 --- a/tensorflow/python/profiler/profile_context_test.py +++ b/tensorflow/python/profiler/profile_context_test.py @@ -21,6 +21,7 @@ import os from tensorflow.python.client import session from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import gfile from tensorflow.python.platform import test @@ -35,6 +36,7 @@ builder = option_builder.ProfileOptionBuilder class ProfilerContextTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasics(self): ops.reset_default_graph() outfile = os.path.join(test.get_temp_dir(), "dump") @@ -69,6 +71,7 @@ class ProfilerContextTest(test.TestCase): with gfile.Open(outfile, "r") as f: self.assertEqual(profile_str, f.read()) + @test_util.run_deprecated_v1 def testAutoTracingInDeubMode(self): ops.reset_default_graph() x = lib.BuildFullModel() @@ -90,6 +93,7 @@ class ProfilerContextTest(test.TestCase): for f in gfile.ListDirectory(test.get_temp_dir()): self.assertFalse("run_meta" in f) + @test_util.run_deprecated_v1 def testDisabled(self): ops.reset_default_graph() x = lib.BuildFullModel() diff --git a/tensorflow/python/profiler/profiler_test.py b/tensorflow/python/profiler/profiler_test.py index eacb7d21e6..e4f7361e5d 100644 --- a/tensorflow/python/profiler/profiler_test.py +++ b/tensorflow/python/profiler/profiler_test.py @@ -21,6 +21,7 @@ import os from tensorflow.core.protobuf import config_pb2 from tensorflow.python.client import session from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import gfile from tensorflow.python.platform import test @@ -35,6 +36,7 @@ builder = option_builder.ProfileOptionBuilder class ProfilerTest(test.TestCase): + @test_util.run_deprecated_v1 def testProfileBasic(self): ops.reset_default_graph() outfile = os.path.join(test.get_temp_dir(), 'dump') @@ -171,6 +173,7 @@ class ProfilerTest(test.TestCase): checker = advice_pb.checkers['ExpensiveOperationChecker'] self.assertGreater(len(checker.reports), 0) + @test_util.run_deprecated_v1 def testMultipleProfilePerStep(self): ops.reset_default_graph() opts = (builder(builder.trainable_variables_parameter()) diff --git a/tensorflow/python/saved_model/loader_test.py b/tensorflow/python/saved_model/loader_test.py index 3378bf08cd..3b7f0b250e 100644 --- a/tensorflow/python/saved_model/loader_test.py +++ b/tensorflow/python/saved_model/loader_test.py @@ -26,6 +26,7 @@ from absl.testing import parameterized from tensorflow.python.client import session from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables @@ -93,6 +94,7 @@ class SavedModelLoaderTest(test.TestCase, parameterized.TestCase): super(SavedModelLoaderTest, self).tearDown() shutil.rmtree(test.get_temp_dir(), ignore_errors=True) + @test_util.run_deprecated_v1 def test_load_function(self, builder_cls): self.export_simple_graph(builder_cls) loader = loader_impl.SavedModelLoader(SIMPLE_ADD_SAVED_MODEL) @@ -108,6 +110,7 @@ class SavedModelLoaderTest(test.TestCase, parameterized.TestCase): self.assertEqual(5, sess.graph.get_tensor_by_name("x:0").eval()) self.assertEqual(7, sess.graph.get_tensor_by_name("y:0").eval()) + @test_util.run_deprecated_v1 def test_load_graph(self, builder_cls): self.export_simple_graph(builder_cls) loader = loader_impl.SavedModelLoader(SIMPLE_ADD_SAVED_MODEL) @@ -127,6 +130,7 @@ class SavedModelLoaderTest(test.TestCase, parameterized.TestCase): with self.assertRaises(errors.FailedPreconditionError): self.evaluate(y) + @test_util.run_deprecated_v1 def test_load_with_import_scope(self, builder_cls): self.export_graph_with_main_op(builder_cls) loader = loader_impl.SavedModelLoader(SAVED_MODEL_WITH_MAIN_OP) @@ -157,6 +161,7 @@ class SavedModelLoaderTest(test.TestCase, parameterized.TestCase): self.assertEqual(5, sess.graph.get_tensor_by_name("baa/x:0").eval()) self.assertEqual(7, sess.graph.get_tensor_by_name("baa/y:0").eval()) + @test_util.run_deprecated_v1 def test_restore_variables(self, builder_cls): self.export_graph_with_main_op(builder_cls) loader = loader_impl.SavedModelLoader(SAVED_MODEL_WITH_MAIN_OP) @@ -174,6 +179,7 @@ class SavedModelLoaderTest(test.TestCase, parameterized.TestCase): loader.restore_variables(sess, tf_saver.Saver()) self.assertEqual(55, self.evaluate(z)) + @test_util.run_deprecated_v1 def test_run_init_op(self, builder_cls): self.export_graph_with_main_op(builder_cls) loader = loader_impl.SavedModelLoader(SAVED_MODEL_WITH_MAIN_OP) @@ -206,6 +212,7 @@ class SavedModelLoaderTest(test.TestCase, parameterized.TestCase): with self.assertRaises(RuntimeError): loader.get_meta_graph_def_from_tags(["not_a_graph"]) + @test_util.run_deprecated_v1 def test_load_saved_model_with_no_variables(self, builder_cls): """Test that SavedModel runs saver when there appear to be no variables. diff --git a/tensorflow/python/saved_model/save_test.py b/tensorflow/python/saved_model/save_test.py index 8fb28039a4..ef0a92fddd 100644 --- a/tensorflow/python/saved_model/save_test.py +++ b/tensorflow/python/saved_model/save_test.py @@ -282,6 +282,7 @@ class SaveTest(test.TestCase): {"out": model(array_ops.ones([1, 4]))}, self._import_and_infer(save_dir, {"x": [[1., 1., 1., 1.]]})) + @test_util.run_deprecated_v1 def test_export_functional_keras_model_after_fit(self): x = input_layer.Input((1,)) y = core.Dense(1, name="y")(x) diff --git a/tensorflow/python/saved_model/saved_model_test.py b/tensorflow/python/saved_model/saved_model_test.py index efcd21cce3..0f18fb1a01 100644 --- a/tensorflow/python/saved_model/saved_model_test.py +++ b/tensorflow/python/saved_model/saved_model_test.py @@ -199,6 +199,7 @@ class SavedModelTest(SavedModelTestBase): constants.SAVED_MODEL_FILENAME_PBTXT): loader.load(sess, ["foo"], export_dir) + @test_util.run_deprecated_v1 def testVerifySessionGraphUsage(self): export_dir = self._get_export_dir("test_verify_session_graph_usage") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -219,6 +220,7 @@ class SavedModelTest(SavedModelTestBase): self.assertEqual( 42, ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)[0].eval()) + @test_util.run_deprecated_v1 def testSequence(self): export_dir = self._get_export_dir("test_sequence") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -236,6 +238,7 @@ class SavedModelTest(SavedModelTestBase): self.assertRaises(AssertionError, builder.add_meta_graph_and_variables, sess, ["baz"]) + @test_util.run_deprecated_v1 def testTags(self): export_dir = self._get_export_dir("test_tags") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -325,6 +328,7 @@ class SavedModelTest(SavedModelTestBase): self.assertRaises(RuntimeError, loader.load, sess, ["foo", "baz"], export_dir) + @test_util.run_deprecated_v1 def testVariables(self): export_dir = self._get_export_dir("test_variables") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -377,6 +381,7 @@ class SavedModelTest(SavedModelTestBase): self.assertRaises(errors.NotFoundError, loader.load, sess, ["baz"], export_dir) + @test_util.run_deprecated_v1 def testGraphWithoutVariables(self): export_dir = self._get_export_dir("test_graph_has_variables") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -412,6 +417,7 @@ class SavedModelTest(SavedModelTestBase): c = a * b self.assertEqual(30.0, self.evaluate(c)) + @test_util.run_deprecated_v1 def testNoOverwrite(self): export_dir = self._get_export_dir("test_no_overwrite") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -436,6 +442,7 @@ class SavedModelTest(SavedModelTestBase): self.assertRaises(AssertionError, saved_model_builder._SavedModelBuilder, export_dir) + @test_util.run_deprecated_v1 def testSaveAsText(self): export_dir = self._get_export_dir("test_astext") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -467,6 +474,7 @@ class SavedModelTest(SavedModelTestBase): self.assertEqual( 42, ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)[0].eval()) + @test_util.run_deprecated_v1 def testCollections(self): export_dir = self._get_export_dir("test_collections") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -517,6 +525,7 @@ class SavedModelTest(SavedModelTestBase): self.assertEqual(len(ops.get_collection("foo_vars")), 0) + @test_util.run_deprecated_v1 def testSignatureDefs(self): export_dir = self._get_export_dir("test_signature_defs") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -604,6 +613,7 @@ class SavedModelTest(SavedModelTestBase): self._validate_sig_def_keys(builder, valid_tensor_info, constants.TRAIN_OP_SIGNATURE_KEY) + @test_util.run_deprecated_v1 def testSignatureDefValidationSucceedsWithName(self): tensor_with_name = meta_graph_pb2.TensorInfo() tensor_with_name.name = "foo" @@ -617,6 +627,7 @@ class SavedModelTest(SavedModelTestBase): builder = saved_model_builder._SavedModelBuilder(export_dir) self._validate_outputs_tensor_info_accept(builder, tensor_with_name) + @test_util.run_deprecated_v1 def testSignatureDefValidationSucceedsWithCoo(self): tensor_with_coo = meta_graph_pb2.TensorInfo() # TODO(soergel) test validation of each of the fields of coo_sparse @@ -631,6 +642,7 @@ class SavedModelTest(SavedModelTestBase): builder = saved_model_builder._SavedModelBuilder(export_dir) self._validate_outputs_tensor_info_accept(builder, tensor_with_coo) + @test_util.run_deprecated_v1 def testAssets(self): export_dir = self._get_export_dir("test_assets") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -662,6 +674,7 @@ class SavedModelTest(SavedModelTestBase): compat.as_bytes("ignored.txt")) self.assertFalse(file_io.file_exists(ignored_asset_path)) + @test_util.run_deprecated_v1 def testAssetsNameCollisionDiffFile(self): export_dir = self._get_export_dir("test_assets_name_collision_diff_file") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -693,6 +706,7 @@ class SavedModelTest(SavedModelTestBase): "asset_file_tensor_1:0", asset_id=1) + @test_util.run_deprecated_v1 def testAssetsNameCollisionSameFilepath(self): export_dir = self._get_export_dir("test_assets_name_collision_same_path") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -730,6 +744,7 @@ class SavedModelTest(SavedModelTestBase): compat.as_bytes("hello42.txt_1")) self.assertFalse(file_io.file_exists(ignored_asset_path)) + @test_util.run_deprecated_v1 def testAssetsNameCollisionSameFile(self): export_dir = self._get_export_dir("test_assets_name_collision_same_file") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -767,6 +782,7 @@ class SavedModelTest(SavedModelTestBase): compat.as_bytes("hello42.txt_1")) self.assertFalse(file_io.file_exists(ignored_asset_path)) + @test_util.run_deprecated_v1 def testAssetsNameCollisionManyFiles(self): export_dir = self._get_export_dir("test_assets_name_collision_many_files") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -838,6 +854,7 @@ class SavedModelTest(SavedModelTestBase): # the main_op, following a restore. self.assertEqual(3, ops.get_collection("v")[2].eval()) + @test_util.run_deprecated_v1 def testTrainOp(self): export_dir = self._get_export_dir("test_train_op") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -865,6 +882,7 @@ class SavedModelTest(SavedModelTestBase): self.assertIsInstance( loader_impl.get_train_op(meta_graph_def), ops.Tensor) + @test_util.run_deprecated_v1 def testTrainOpGroup(self): export_dir = self._get_export_dir("test_train_op_group") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -892,6 +910,7 @@ class SavedModelTest(SavedModelTestBase): self.assertIsInstance( loader_impl.get_train_op(meta_graph_def), ops.Operation) + @test_util.run_deprecated_v1 def testTrainOpAfterVariables(self): export_dir = self._get_export_dir("test_train_op_after_variables") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -922,6 +941,7 @@ class SavedModelTest(SavedModelTestBase): loader.load(sess, ["pre_foo"], export_dir) self.assertFalse(ops.get_collection(constants.TRAIN_OP_KEY)) + @test_util.run_deprecated_v1 def testMultipleAssets(self): export_dir = self._get_export_dir("test_multiple_assets") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -962,6 +982,7 @@ class SavedModelTest(SavedModelTestBase): self._validate_assets(export_dir, bar_graph.asset_file_def, "bar.txt", "content_bar", "asset_file_tensor:0") + @test_util.run_deprecated_v1 def testDuplicateAssets(self): export_dir = self._get_export_dir("test_duplicate_assets") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1008,6 +1029,7 @@ class SavedModelTest(SavedModelTestBase): self._validate_assets(export_dir, bar_graph.asset_file_def, "foo.txt", "content_foo", "asset_file_tensor:0") + @test_util.run_deprecated_v1 def testOp(self): export_dir = self._get_export_dir("test_op") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1080,6 +1102,7 @@ class SavedModelTest(SavedModelTestBase): self.assertEqual(b"k1", v1.keys().eval()) self.assertEqual(3.0, v1.values().eval()) + @test_util.run_deprecated_v1 def testCustomSaver(self): export_dir = self._get_export_dir("test_custom_saver") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1102,6 +1125,7 @@ class SavedModelTest(SavedModelTestBase): self.assertEqual( saved_graph.saver_def.restore_op_name, "my_saver/restore_all") + @test_util.run_deprecated_v1 def testNoCustomSaver(self): export_dir = self._get_export_dir("test_no_custom_saver") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1124,6 +1148,7 @@ class SavedModelTest(SavedModelTestBase): self.assertEqual( saved_graph.saver_def.restore_op_name, "save/restore_all") + @test_util.run_deprecated_v1 def testMultipleCustomSavers(self): export_dir = self._get_export_dir("test_multiple_custom_savers") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1154,6 +1179,7 @@ class SavedModelTest(SavedModelTestBase): _validate_custom_saver("tag_1", "save_1/restore_all") _validate_custom_saver("tag_2", "save_2/restore_all") + @test_util.run_deprecated_v1 def testImportScope(self): export_dir = self._get_export_dir("test_scoped_assets") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1205,6 +1231,7 @@ class SavedModelTest(SavedModelTestBase): ops.get_default_graph().get_tensor_by_name( "scope_name/constant_tensor_name:0").eval()) + @test_util.run_deprecated_v1 def testClearDevices(self): export_dir = self._get_export_dir("test_clear_devices") builder = saved_model_builder._SavedModelBuilder(export_dir) @@ -1323,6 +1350,7 @@ class SavedModelV1Test(SavedModelTestBase): self.assertEqual(expected_asset_file_name, asset.filename) self.assertEqual(expected_asset_tensor_name, asset.tensor_info.name) + @test_util.run_deprecated_v1 def testWritingAssetsToCollection(self): export_dir = self._get_export_dir("test_writing_assets_to_collection") builder = saved_model_builder.SavedModelBuilder(export_dir) @@ -1355,12 +1383,14 @@ class SavedModelV1Test(SavedModelTestBase): compat.as_bytes("ignored.txt")) self.assertFalse(file_io.file_exists(ignored_asset_path)) + @test_util.run_deprecated_v1 def testLegacyInitOpWithNonEmptyCollection(self): export_dir = self._get_export_dir( "test_legacy_init_op_with_non_empty_collection") self._testInitOpsWithNonEmptyCollection(export_dir, constants.LEGACY_INIT_OP_KEY) + @test_util.run_deprecated_v1 def testMainOpWithNonEmptyCollection(self): export_dir = self._get_export_dir("test_main_op_with_non_empty_collection") self._testInitOpsWithNonEmptyCollection(export_dir, constants.MAIN_OP_KEY) @@ -1464,6 +1494,7 @@ class SavedModelV1Test(SavedModelTestBase): self.assertIn("T", node_def.attr) self.assertIn("Tout", node_def.attr) + @test_util.run_deprecated_v1 def testLegacyInitOp(self): export_dir = self._get_export_dir("test_legacy_init_op") builder = saved_model_builder.SavedModelBuilder(export_dir) diff --git a/tensorflow/python/saved_model/signature_def_utils_test.py b/tensorflow/python/saved_model/signature_def_utils_test.py index cc0fd8ce05..53c452359f 100644 --- a/tensorflow/python/saved_model/signature_def_utils_test.py +++ b/tensorflow/python/saved_model/signature_def_utils_test.py @@ -22,6 +22,7 @@ from tensorflow.core.framework import types_pb2 from tensorflow.core.protobuf import meta_graph_pb2 from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -59,6 +60,7 @@ def _make_signature(inputs, outputs, name=None): class SignatureDefUtilsTest(test.TestCase): + @test_util.run_deprecated_v1 def testBuildSignatureDef(self): x = array_ops.placeholder(dtypes.float32, 1, name="x") x_tensor_info = utils.build_tensor_info(x) @@ -89,6 +91,7 @@ class SignatureDefUtilsTest(test.TestCase): self.assertEqual(types_pb2.DT_FLOAT, y_tensor_info_actual.dtype) self.assertEqual(0, len(y_tensor_info_actual.tensor_shape.dim)) + @test_util.run_deprecated_v1 def testRegressionSignatureDef(self): input1 = constant_op.constant("a", name="input-1") output1 = constant_op.constant(2.2, name="output-1") @@ -114,6 +117,7 @@ class SignatureDefUtilsTest(test.TestCase): self.assertEqual(types_pb2.DT_FLOAT, y_tensor_info_actual.dtype) self.assertEqual(0, len(y_tensor_info_actual.tensor_shape.dim)) + @test_util.run_deprecated_v1 def testClassificationSignatureDef(self): input1 = constant_op.constant("a", name="input-1") output1 = constant_op.constant("b", name="output-1") @@ -145,6 +149,7 @@ class SignatureDefUtilsTest(test.TestCase): self.assertEqual(types_pb2.DT_FLOAT, scores_tensor_info_actual.dtype) self.assertEqual(0, len(scores_tensor_info_actual.tensor_shape.dim)) + @test_util.run_deprecated_v1 def testPredictionSignatureDef(self): input1 = constant_op.constant("a", name="input-1") input2 = constant_op.constant("b", name="input-2") @@ -181,11 +186,13 @@ class SignatureDefUtilsTest(test.TestCase): self.assertEqual(types_pb2.DT_STRING, output2_tensor_info_actual.dtype) self.assertEqual(0, len(output2_tensor_info_actual.tensor_shape.dim)) + @test_util.run_deprecated_v1 def testTrainSignatureDef(self): self._testSupervisedSignatureDef( signature_def_utils_impl.supervised_train_signature_def, signature_constants.SUPERVISED_TRAIN_METHOD_NAME) + @test_util.run_deprecated_v1 def testEvalSignatureDef(self): self._testSupervisedSignatureDef( signature_def_utils_impl.supervised_eval_signature_def, @@ -239,11 +246,13 @@ class SignatureDefUtilsTest(test.TestCase): self.assertEqual( types_pb2.DT_FLOAT, signature_def.outputs["metrics/value"].dtype) + @test_util.run_deprecated_v1 def testTrainSignatureDefMissingInputs(self): self._testSupervisedSignatureDefMissingInputs( signature_def_utils_impl.supervised_train_signature_def, signature_constants.SUPERVISED_TRAIN_METHOD_NAME) + @test_util.run_deprecated_v1 def testEvalSignatureDefMissingInputs(self): self._testSupervisedSignatureDefMissingInputs( signature_def_utils_impl.supervised_eval_signature_def, diff --git a/tensorflow/python/saved_model/simple_save_test.py b/tensorflow/python/saved_model/simple_save_test.py index 0d0665072a..21c2e9df2f 100644 --- a/tensorflow/python/saved_model/simple_save_test.py +++ b/tensorflow/python/saved_model/simple_save_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import os from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.saved_model import loader @@ -53,6 +54,7 @@ class SimpleSaveTest(test.TestCase): self.assertEqual(actual_tensor_info.tensor_shape.dim[i].size, expected_tensor.shape[i]) + @test_util.run_deprecated_v1 def testSimpleSave(self): """Test simple_save that uses the default parameters.""" export_dir = os.path.join(test.get_temp_dir(), diff --git a/tensorflow/python/summary/summary_test.py b/tensorflow/python/summary/summary_test.py index cacc28cc59..64f0f315c5 100644 --- a/tensorflow/python/summary/summary_test.py +++ b/tensorflow/python/summary/summary_test.py @@ -30,6 +30,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -38,6 +39,7 @@ from tensorflow.python.summary import summary as summary_lib class SummaryTest(test.TestCase): + @test_util.run_deprecated_v1 def testScalarSummary(self): with self.cached_session() as s: i = constant_op.constant(3) @@ -51,6 +53,7 @@ class SummaryTest(test.TestCase): self.assertEqual(values[0].tag, 'outer/inner') self.assertEqual(values[0].simple_value, 3.0) + @test_util.run_deprecated_v1 def testScalarSummaryWithFamily(self): with self.cached_session() as s: i = constant_op.constant(7) @@ -74,6 +77,7 @@ class SummaryTest(test.TestCase): self.assertEqual(values[0].tag, 'family/outer/family/inner_1') self.assertEqual(values[0].simple_value, 7.0) + @test_util.run_deprecated_v1 def testSummarizingVariable(self): with self.cached_session() as s: c = constant_op.constant(42.0) @@ -89,6 +93,7 @@ class SummaryTest(test.TestCase): self.assertEqual(value.tag, 'summary') self.assertEqual(value.simple_value, 42.0) + @test_util.run_deprecated_v1 def testImageSummary(self): with self.cached_session() as s: i = array_ops.ones((5, 4, 4, 3)) @@ -103,6 +108,7 @@ class SummaryTest(test.TestCase): expected = sorted('outer/inner/image/{}'.format(i) for i in xrange(3)) self.assertEqual(tags, expected) + @test_util.run_deprecated_v1 def testImageSummaryWithFamily(self): with self.cached_session() as s: i = array_ops.ones((5, 2, 3, 1)) @@ -119,6 +125,7 @@ class SummaryTest(test.TestCase): for i in xrange(3)) self.assertEqual(tags, expected) + @test_util.run_deprecated_v1 def testHistogramSummary(self): with self.cached_session() as s: i = array_ops.ones((5, 4, 4, 3)) @@ -130,6 +137,7 @@ class SummaryTest(test.TestCase): self.assertEqual(len(summary.value), 1) self.assertEqual(summary.value[0].tag, 'outer/inner') + @test_util.run_deprecated_v1 def testHistogramSummaryWithFamily(self): with self.cached_session() as s: i = array_ops.ones((5, 4, 4, 3)) @@ -148,6 +156,7 @@ class SummaryTest(test.TestCase): const = constant_op.constant(10, dtype=dtype) summary_lib.histogram('h', const) + @test_util.run_deprecated_v1 def testAudioSummary(self): with self.cached_session() as s: i = array_ops.ones((5, 3, 4)) @@ -162,6 +171,7 @@ class SummaryTest(test.TestCase): expected = sorted('outer/inner/audio/{}'.format(i) for i in xrange(3)) self.assertEqual(tags, expected) + @test_util.run_deprecated_v1 def testAudioSummaryWithFamily(self): with self.cached_session() as s: i = array_ops.ones((5, 3, 4)) @@ -178,6 +188,7 @@ class SummaryTest(test.TestCase): for i in xrange(3)) self.assertEqual(tags, expected) + @test_util.run_deprecated_v1 def testTextSummary(self): with self.cached_session(): with self.assertRaises(ValueError): @@ -193,6 +204,7 @@ class SummaryTest(test.TestCase): summ = summary_lib.text('foo', array_ops.constant('one')) self.assertEqual(summ.op.type, 'TensorSummaryV2') + @test_util.run_deprecated_v1 def testSummaryNameConversion(self): c = constant_op.constant(3) s = summary_lib.scalar('name with spaces', c) @@ -204,6 +216,7 @@ class SummaryTest(test.TestCase): s3 = summary_lib.scalar('/name/with/leading/slash', c) self.assertEqual(s3.op.name, 'name/with/leading/slash') + @test_util.run_deprecated_v1 def testSummaryWithFamilyMetaGraphExport(self): with ops.name_scope('outer'): i = constant_op.constant(11) diff --git a/tensorflow/python/summary/writer/writer_test.py b/tensorflow/python/summary/writer/writer_test.py index 20b62e5016..d702ddc0a2 100644 --- a/tensorflow/python/summary/writer/writer_test.py +++ b/tensorflow/python/summary/writer/writer_test.py @@ -35,6 +35,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import summary_ops_v2 from tensorflow.python.platform import gfile from tensorflow.python.platform import test @@ -100,6 +101,7 @@ class FileWriterTestCase(test.TestCase): # We should be done. self.assertRaises(StopIteration, lambda: next(rr)) + @test_util.run_deprecated_v1 def testAddingSummaryGraphAndRunMetadata(self): test_dir = self._CleanTestDir("basics") sw = self._FileWriter(test_dir) @@ -173,6 +175,7 @@ class FileWriterTestCase(test.TestCase): # We should be done. self.assertRaises(StopIteration, lambda: next(rr)) + @test_util.run_deprecated_v1 def testGraphAsNamed(self): test_dir = self._CleanTestDir("basics_named_graph") with ops.Graph().as_default() as g: @@ -181,6 +184,7 @@ class FileWriterTestCase(test.TestCase): sw.close() self._assertEventsWithGraph(test_dir, g, True) + @test_util.run_deprecated_v1 def testGraphAsPositional(self): test_dir = self._CleanTestDir("basics_positional_graph") with ops.Graph().as_default() as g: @@ -189,6 +193,7 @@ class FileWriterTestCase(test.TestCase): sw.close() self._assertEventsWithGraph(test_dir, g, True) + @test_util.run_deprecated_v1 def testGraphDefAsNamed(self): test_dir = self._CleanTestDir("basics_named_graph_def") with ops.Graph().as_default() as g: @@ -198,6 +203,7 @@ class FileWriterTestCase(test.TestCase): sw.close() self._assertEventsWithGraph(test_dir, g, False) + @test_util.run_deprecated_v1 def testGraphDefAsPositional(self): test_dir = self._CleanTestDir("basics_positional_graph_def") with ops.Graph().as_default() as g: @@ -207,6 +213,7 @@ class FileWriterTestCase(test.TestCase): sw.close() self._assertEventsWithGraph(test_dir, g, False) + @test_util.run_deprecated_v1 def testGraphAndGraphDef(self): with self.assertRaises(ValueError): test_dir = self._CleanTestDir("basics_graph_and_graph_def") @@ -216,12 +223,14 @@ class FileWriterTestCase(test.TestCase): sw = self._FileWriter(test_dir, graph=g, graph_def=gd) sw.close() + @test_util.run_deprecated_v1 def testNeitherGraphNorGraphDef(self): with self.assertRaises(TypeError): test_dir = self._CleanTestDir("basics_string_instead_of_graph") sw = self._FileWriter(test_dir, "string instead of graph object") sw.close() + @test_util.run_deprecated_v1 def testCloseAndReopen(self): test_dir = self._CleanTestDir("close_and_reopen") sw = self._FileWriter(test_dir) @@ -265,6 +274,7 @@ class FileWriterTestCase(test.TestCase): # We should be done. self.assertRaises(StopIteration, lambda: next(rr)) + @test_util.run_deprecated_v1 def testNonBlockingClose(self): test_dir = self._CleanTestDir("non_blocking_close") sw = self._FileWriter(test_dir) @@ -274,6 +284,7 @@ class FileWriterTestCase(test.TestCase): sw.close() self._assertRecent(time_before_close) + @test_util.run_deprecated_v1 def testUseAfterClose(self): test_dir = self._CleanTestDir("use_after_close") sw = self._FileWriter(test_dir) @@ -289,6 +300,7 @@ class FileWriterTestCase(test.TestCase): for w in triggered: self.assertEqual(w.category, UserWarning) + @test_util.run_deprecated_v1 def testWithStatement(self): test_dir = self._CleanTestDir("with_statement") with self._FileWriter(test_dir) as sw: @@ -299,6 +311,7 @@ class FileWriterTestCase(test.TestCase): # Checks that values returned from session Run() calls are added correctly to # summaries. These are numpy types so we need to check they fit in the # protocol buffers correctly. + @test_util.run_deprecated_v1 def testAddingSummariesFromSessionRunCalls(self): test_dir = self._CleanTestDir("global_step") sw = self._FileWriter(test_dir) @@ -345,6 +358,7 @@ class FileWriterTestCase(test.TestCase): # We should be done. self.assertRaises(StopIteration, lambda: next(rr)) + @test_util.run_deprecated_v1 def testPluginMetadataStrippedFromSubsequentEvents(self): test_dir = self._CleanTestDir("basics") sw = self._FileWriter(test_dir) @@ -404,6 +418,7 @@ class FileWriterTestCase(test.TestCase): # We should be done. self.assertRaises(StopIteration, lambda: next(rr)) + @test_util.run_deprecated_v1 def testFileWriterWithSuffix(self): test_dir = self._CleanTestDir("test_suffix") sw = self._FileWriter(test_dir, filename_suffix="_test_suffix") diff --git a/tensorflow/python/tools/freeze_graph_test.py b/tensorflow/python/tools/freeze_graph_test.py index 5dc14a6961..efdf7dd2cf 100644 --- a/tensorflow/python/tools/freeze_graph_test.py +++ b/tensorflow/python/tools/freeze_graph_test.py @@ -161,9 +161,11 @@ class FreezeGraphTest(test_util.TensorFlowTestCase): },) builder.save(as_text=True) + @test_util.run_deprecated_v1 def testFreezeGraphV1(self): self._testFreezeGraph(saver_pb2.SaverDef.V1) + @test_util.run_deprecated_v1 def testFreezeGraphV2(self): self._testFreezeGraph(saver_pb2.SaverDef.V2) diff --git a/tensorflow/python/tools/optimize_for_inference_test.py b/tensorflow/python/tools/optimize_for_inference_test.py index 10bfb0dc70..310776ff1b 100644 --- a/tensorflow/python/tools/optimize_for_inference_test.py +++ b/tensorflow/python/tools/optimize_for_inference_test.py @@ -128,6 +128,7 @@ class OptimizeForInferenceTest(test.TestCase): graph_def, [], [add_name], dtypes.float32.as_datatype_enum) self.assertProtoEquals(expected_output, output) + @test_util.run_deprecated_v1 def testFoldBatchNorms(self): with self.cached_session() as sess: inputs = [1, 4, 2, 5, 3, 6, -1, -4, -2, -5, -3, -6] @@ -171,6 +172,7 @@ class OptimizeForInferenceTest(test.TestCase): for node in optimized_graph_def.node: self.assertNotEqual("BatchNormWithGlobalNormalization", node.op) + @test_util.run_deprecated_v1 def testFoldFusedBatchNorms(self): for data_format, use_gpu in [("NHWC", False), ("NCHW", True)]: with self.cached_session(use_gpu=use_gpu) as sess: @@ -222,6 +224,7 @@ class OptimizeForInferenceTest(test.TestCase): for node in optimized_graph_def.node: self.assertNotEqual("FusedBatchNorm", node.op) + @test_util.run_deprecated_v1 def testFuseResizePadAndConv(self): with self.cached_session() as sess: inputs = [1, 4, 2, 5, 3, 6, -1, -4, -2, -5, -3, -6] @@ -253,6 +256,7 @@ class OptimizeForInferenceTest(test.TestCase): self.assertNotEqual("MirrorPad", node.op) self.assertNotEqual("ResizeBilinear", node.op) + @test_util.run_deprecated_v1 def testFuseResizeAndConv(self): with self.cached_session() as sess: inputs = [1, 4, 2, 5, 3, 6, -1, -4, -2, -5, -3, -6] @@ -282,6 +286,7 @@ class OptimizeForInferenceTest(test.TestCase): self.assertNotEqual("MirrorPad", node.op) + @test_util.run_deprecated_v1 def testFusePadAndConv(self): with self.cached_session() as sess: inputs = [1, 4, 2, 5, 3, 6, -1, -4, -2, -5, -3, -6] diff --git a/tensorflow/python/training/adadelta_test.py b/tensorflow/python/training/adadelta_test.py index 7cbaf1039f..0e5af5a922 100644 --- a/tensorflow/python/training/adadelta_test.py +++ b/tensorflow/python/training/adadelta_test.py @@ -166,6 +166,7 @@ class AdadeltaOptimizerTest(test.TestCase): with context.eager_mode(): self.doTestBasic(use_resource=True, use_callable_params=True) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/training/adagrad_da_test.py b/tensorflow/python/training/adagrad_da_test.py index c7c47206a9..aacfe6faf4 100644 --- a/tensorflow/python/training/adagrad_da_test.py +++ b/tensorflow/python/training/adagrad_da_test.py @@ -22,6 +22,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -73,12 +74,15 @@ class AdagradDAOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.094821, -0.189358]), v1_val) + @test_util.run_deprecated_v1 def testAdagradDAWithoutRegularizationBasic1(self): self.doTestAdagradDAwithoutRegularizationBasic1() + @test_util.run_deprecated_v1 def testResourceAdagradDAWithoutRegularizationBasic1(self): self.doTestAdagradDAwithoutRegularizationBasic1(use_resource=True) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -100,6 +104,7 @@ class AdagradDAOptimizerTest(test.TestCase): self.evaluate(var0), rtol=0.01) + @test_util.run_deprecated_v1 def testAdagradDAwithoutRegularizationBasic2(self): for dtype in [dtypes.float64, dtypes.float32]: with self.cached_session() as sess: @@ -132,6 +137,7 @@ class AdagradDAOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.094821, -0.189358]), v1_val) + @test_util.run_deprecated_v1 def testAdagradDAWithL1(self): for dtype in [dtypes.float64, dtypes.float32]: with self.cached_session() as sess: @@ -164,6 +170,7 @@ class AdagradDAOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.085339, -0.17989]), v1_val) + @test_util.run_deprecated_v1 def testAdagradDAWithL1_L2(self): for dtype in [dtypes.float64, dtypes.float32]: with self.cached_session() as sess: diff --git a/tensorflow/python/training/adagrad_test.py b/tensorflow/python/training/adagrad_test.py index 962e65c41f..da26fcdb7f 100644 --- a/tensorflow/python/training/adagrad_test.py +++ b/tensorflow/python/training/adagrad_test.py @@ -96,6 +96,7 @@ class AdagradOptimizerTest(test.TestCase): def testBasicLocked(self): self.doTestBasic(use_locking=True) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -116,6 +117,7 @@ class AdagradOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -142,6 +144,7 @@ class AdagradOptimizerTest(test.TestCase): np.array([2.715679168701172, 3.715679168701172]), self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseBasic(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -173,6 +176,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([[3.0], [3.715679168701172]]), self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseRepeatedIndices(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -203,6 +207,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllClose(aggregated_update_var.eval(), self.evaluate(repeated_index_update_var)) + @test_util.run_deprecated_v1 def testSparseRepeatedIndicesResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -227,6 +232,7 @@ class AdagradOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( self.evaluate(var_repeated), self.evaluate(var_aggregated)) + @test_util.run_deprecated_v1 def testSparseStability(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -263,6 +269,7 @@ class AdagradOptimizerTest(test.TestCase): -0.01029443 ]]), self.evaluate(var0)) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -299,6 +306,7 @@ class AdagradOptimizerTest(test.TestCase): np.array([2.715679168701172, 3.715679168701172]), self.evaluate(var1)) + @test_util.run_deprecated_v1 def testDynamicShapeVariable_Ok(self): with self.cached_session(): v = variable_scope.get_variable("v", initializer=constant_op.constant(1.), @@ -307,6 +315,7 @@ class AdagradOptimizerTest(test.TestCase): # Creating optimizer should cause no exception. adagrad.AdagradOptimizer(3.0, initial_accumulator_value=0.1) + @test_util.run_deprecated_v1 def testDynamicShapeVariableWithCallableInit(self): var0 = variable_scope.get_variable("var0", initializer=constant_op.constant(1.), diff --git a/tensorflow/python/training/adam_test.py b/tensorflow/python/training/adam_test.py index 87dad0a8a6..b0bae27577 100644 --- a/tensorflow/python/training/adam_test.py +++ b/tensorflow/python/training/adam_test.py @@ -102,12 +102,15 @@ class AdamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparse(self): self.doTestSparse(use_resource=False) + @test_util.run_deprecated_v1 def testResourceSparse(self): self.doTestSparse(use_resource=True) + @test_util.run_deprecated_v1 def testSparseDevicePlacement(self): for index_dtype in [dtypes.int32, dtypes.int64]: with self.cached_session(force_gpu=test.is_gpu_available()): @@ -121,6 +124,7 @@ class AdamOptimizerTest(test.TestCase): variables.global_variables_initializer().run() minimize_op.run() + @test_util.run_deprecated_v1 def testSparseRepeatedIndices(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -236,6 +240,7 @@ class AdamOptimizerTest(test.TestCase): with context.eager_mode(): self.doTestBasic(use_resource=True, use_callable_params=True) + @test_util.run_deprecated_v1 def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -274,6 +279,7 @@ class AdamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/training/basic_loops_test.py b/tensorflow/python/training/basic_loops_test.py index 5f5718e64a..511a8334d5 100644 --- a/tensorflow/python/training/basic_loops_test.py +++ b/tensorflow/python/training/basic_loops_test.py @@ -23,6 +23,7 @@ import shutil from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.training import basic_loops from tensorflow.python.training import supervisor @@ -37,6 +38,7 @@ def _test_dir(test_name): class BasicTrainLoopTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasicTrainLoop(self): logdir = _test_dir("basic_train_loop") sv = supervisor.Supervisor(logdir=logdir) @@ -55,6 +57,7 @@ class BasicTrainLoopTest(test.TestCase): sv, train_fn, args=(sv, "y"), kwargs={"a": "A"}) self.assertEqual(3, num_calls[0]) + @test_util.run_deprecated_v1 def testBasicTrainLoopExceptionAborts(self): logdir = _test_dir("basic_train_loop_exception_aborts") sv = supervisor.Supervisor(logdir=logdir) @@ -71,6 +74,7 @@ class BasicTrainLoopTest(test.TestCase): with self.assertRaisesRegexp(RuntimeError, "Failed"): basic_loops.basic_train_loop(sv, train_fn) + @test_util.run_deprecated_v1 def testBasicTrainLoopRetryOnAborted(self): logdir = _test_dir("basic_train_loop_exception_aborts") sv = supervisor.Supervisor(logdir=logdir) diff --git a/tensorflow/python/training/basic_session_run_hooks_test.py b/tensorflow/python/training/basic_session_run_hooks_test.py index 03810b57e3..8e54a14f47 100644 --- a/tensorflow/python/training/basic_session_run_hooks_test.py +++ b/tensorflow/python/training/basic_session_run_hooks_test.py @@ -34,6 +34,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import state_ops @@ -91,10 +92,12 @@ class MockCheckpointSaverListener( class SecondOrStepTimerTest(test.TestCase): + @test_util.run_deprecated_v1 def test_raise_in_both_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.SecondOrStepTimer(every_secs=2.0, every_steps=10) + @test_util.run_deprecated_v1 def test_raise_in_none_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.SecondOrStepTimer() @@ -413,11 +416,13 @@ class CheckpointSaverHookTest(test.TestCase): basic_session_run_hooks.CheckpointSaverHook( self.model_dir, saver=self.scaffold.saver, scaffold=self.scaffold) + @test_util.run_deprecated_v1 def test_raise_in_both_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.CheckpointSaverHook( self.model_dir, save_secs=10, save_steps=20) + @test_util.run_deprecated_v1 def test_raise_in_none_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.CheckpointSaverHook(self.model_dir) @@ -1143,11 +1148,13 @@ class SummarySaverHookTest(test.TestCase): basic_session_run_hooks.SummarySaverHook( scaffold=monitored_session.Scaffold(), summary_op=self.summary_op) + @test_util.run_deprecated_v1 def test_raise_in_both_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.SummarySaverHook( save_secs=10, save_steps=20, summary_writer=self.summary_writer) + @test_util.run_deprecated_v1 def test_raise_in_none_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.SummarySaverHook( @@ -1478,10 +1485,12 @@ class ProfilerHookTest(test.TestCase): def _count_timeline_files(self): return len(gfile.Glob(self.filepattern)) + @test_util.run_deprecated_v1 def test_raise_in_both_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.ProfilerHook(save_secs=10, save_steps=20) + @test_util.run_deprecated_v1 def test_raise_in_none_secs_and_steps(self): with self.assertRaises(ValueError): basic_session_run_hooks.ProfilerHook(save_secs=None, save_steps=None) diff --git a/tensorflow/python/training/checkpoint_management_test.py b/tensorflow/python/training/checkpoint_management_test.py index b61ed17531..8606ec4a20 100644 --- a/tensorflow/python/training/checkpoint_management_test.py +++ b/tensorflow/python/training/checkpoint_management_test.py @@ -62,6 +62,7 @@ class LatestCheckpointWithRelativePaths(test.TestCase): finally: shutil.rmtree(tempdir) + @test_util.run_deprecated_v1 def testNameCollision(self): # Make sure we have a clean directory to work in. with self.tempDir() as tempdir: @@ -99,6 +100,7 @@ class LatestCheckpointWithRelativePaths(test.TestCase): self.assertIsNotNone( checkpoint_management.latest_checkpoint(traindir)) + @test_util.run_deprecated_v1 def testRelativePath(self): # Make sure we have a clean directory to work in. with self.tempDir() as tempdir: @@ -270,6 +272,7 @@ class SaverUtilsTest(test.TestCase): def tearDown(self): gfile.DeleteRecursively(self._base_dir) + @test_util.run_deprecated_v1 def testCheckpointExists(self): for sharded in (False, True): for version in (saver_pb2.SaverDef.V2, saver_pb2.SaverDef.V1): @@ -288,6 +291,7 @@ class SaverUtilsTest(test.TestCase): ckpt_prefix = checkpoint_management.latest_checkpoint(self._base_dir) self.assertTrue(checkpoint_management.checkpoint_exists(ckpt_prefix)) + @test_util.run_deprecated_v1 def testGetCheckpointMtimes(self): prefixes = [] for version in (saver_pb2.SaverDef.V2, saver_pb2.SaverDef.V1): @@ -302,6 +306,7 @@ class SaverUtilsTest(test.TestCase): self.assertEqual(2, len(mtimes)) self.assertTrue(mtimes[1] >= mtimes[0]) + @test_util.run_deprecated_v1 def testRemoveCheckpoint(self): for sharded in (False, True): for version in (saver_pb2.SaverDef.V2, saver_pb2.SaverDef.V1): diff --git a/tensorflow/python/training/device_setter_test.py b/tensorflow/python/training/device_setter_test.py index 85b75502ab..3cff87b326 100644 --- a/tensorflow/python/training/device_setter_test.py +++ b/tensorflow/python/training/device_setter_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -33,6 +34,7 @@ class DeviceSetterTest(test.TestCase): "worker": ["worker0:2222", "worker1:2222", "worker2:2222"] }) + @test_util.run_deprecated_v1 def testCPUOverride(self): with ops.device( device_setter.replica_device_setter(cluster=self._cluster_spec)): @@ -47,12 +49,14 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:ps/task:1", w.initializer.device) self.assertDeviceEqual("/job:worker/cpu:0", a.device) + @test_util.run_deprecated_v1 def testResource(self): with ops.device( device_setter.replica_device_setter(cluster=self._cluster_spec)): v = resource_variable_ops.ResourceVariable([1, 2]) self.assertDeviceEqual("/job:ps/task:0", v.device) + @test_util.run_deprecated_v1 def testPS2TasksWithClusterSpecClass(self): with ops.device( device_setter.replica_device_setter(cluster=self._cluster_spec)): @@ -65,6 +69,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:ps/task:1", w.initializer.device) self.assertDeviceEqual("/job:worker", a.device) + @test_util.run_deprecated_v1 def testPS2TasksPinVariableToJob(self): with ops.device( device_setter.replica_device_setter(cluster=self._cluster_spec)): @@ -82,6 +87,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:ps/task:1", x.initializer.device) self.assertDeviceEqual("/job:worker", a.device) + @test_util.run_deprecated_v1 def testPS2TasksUseCpuForPS(self): with ops.device( device_setter.replica_device_setter(ps_tasks=1, ps_device="/cpu:0")): @@ -95,6 +101,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:moon/cpu:0", w.initializer.device) self.assertDeviceEqual("/job:worker", a.device) + @test_util.run_deprecated_v1 def testPS2TasksNoMerging(self): with ops.device( device_setter.replica_device_setter( @@ -109,6 +116,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:ps", w.initializer.device) self.assertDeviceEqual("/job:worker", a.device) + @test_util.run_deprecated_v1 def testPS2TasksWithClusterSpecDict(self): with ops.device( device_setter.replica_device_setter(cluster=self._cluster_spec.as_dict( @@ -122,6 +130,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:ps/task:1", w.initializer.device) self.assertDeviceEqual("/job:worker", a.device) + @test_util.run_deprecated_v1 def testPS2TasksWithClusterDef(self): with ops.device( device_setter.replica_device_setter( @@ -135,6 +144,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:ps/task:1", w.initializer.device) self.assertDeviceEqual("/job:worker", a.device) + @test_util.run_deprecated_v1 def testPS2TasksWithDevice(self): cluster_spec = server_lib.ClusterSpec({ "sun": ["sun0:2222", "sun1:2222", "sun2:2222"], @@ -155,6 +165,7 @@ class DeviceSetterTest(test.TestCase): self.assertDeviceEqual("/job:moon/task:1", w.initializer.device) self.assertDeviceEqual("/job:sun", a.device) + @test_util.run_deprecated_v1 def testPS2TasksWithCPUConstraint(self): cluster_spec = server_lib.ClusterSpec({ "sun": ["sun0:2222", "sun1:2222", "sun2:2222"], diff --git a/tensorflow/python/training/ftrl_test.py b/tensorflow/python/training/ftrl_test.py index 70b5db31f8..39b299c64a 100644 --- a/tensorflow/python/training/ftrl_test.py +++ b/tensorflow/python/training/ftrl_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -68,12 +69,15 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.28432083, -0.56694895]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithoutRegularization(self): self.doTestFtrlwithoutRegularization(use_resource=False) + @test_util.run_deprecated_v1 def testResourceFtrlWithoutRegularization(self): self.doTestFtrlwithoutRegularization(use_resource=True) + @test_util.run_deprecated_v1 def testFtrlwithoutRegularization2(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session() as sess: @@ -103,6 +107,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.28232238, -0.56096673]), v1_val) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -121,6 +126,7 @@ class FtrlOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testFtrlWithL1(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session() as sess: @@ -150,6 +156,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.93460727, -1.86147261]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL1_L2(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session() as sess: @@ -180,6 +187,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.02406147, -0.04830509]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL1_L2_L2Shrinkage(self): """Test the new FTRL op with support for l2 shrinkage. @@ -217,6 +225,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType( np.array([-0.14378493, -0.13229476]), v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL1_L2_L2ShrinkageSparse(self): """Tests the new FTRL op with support for l2 shrinkage on sparse grads.""" for dtype in [dtypes.half, dtypes.float32]: @@ -251,6 +260,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([[-0.22578995], [2.]], v0_val) self.assertAllCloseAccordingToType([[4.], [-0.13229476]], v1_val) + @test_util.run_deprecated_v1 def testFtrlWithL2ShrinkageDoesNotChangeLrSchedule(self): """Verifies that l2 shrinkage in FTRL does not change lr schedule.""" for dtype in [dtypes.half, dtypes.float32]: @@ -335,6 +345,7 @@ class FtrlOptimizerTest(test.TestCase): # with Adagrad. # So, basing on these two properties, we test if our implementation of # FTRL-Proximal performs same updates as Adagrad or GradientDescent. + @test_util.run_deprecated_v1 def testEquivAdagradwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): @@ -355,6 +366,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(val0, val2) self.assertAllCloseAccordingToType(val1, val3) + @test_util.run_deprecated_v1 def testEquivSparseAdagradwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): @@ -378,6 +390,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(val0, val2) self.assertAllCloseAccordingToType(val1, val3) + @test_util.run_deprecated_v1 def testEquivSparseGradientDescentwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): @@ -401,6 +414,7 @@ class FtrlOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(val0, val2) self.assertAllCloseAccordingToType(val1, val3) + @test_util.run_deprecated_v1 def testEquivGradientDescentwithoutRegularization(self): for dtype in [dtypes.half, dtypes.float32]: with self.cached_session(): diff --git a/tensorflow/python/training/gradient_descent_test.py b/tensorflow/python/training/gradient_descent_test.py index 2028e7b4b0..5a6c5cfa74 100644 --- a/tensorflow/python/training/gradient_descent_test.py +++ b/tensorflow/python/training/gradient_descent_test.py @@ -24,6 +24,7 @@ from tensorflow.python.eager import function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -35,6 +36,7 @@ from tensorflow.python.training import gradient_descent class GradientDescentOptimizerTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -58,6 +60,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.evaluate(var1)) self.assertEqual(0, len(optimizer.variables())) + @test_util.run_deprecated_v1 def testBasicResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -83,6 +86,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([3.0 - 3.0 * 0.01, 4.0 - 3.0 * 0.01], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testBasicCallableParams(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -109,6 +113,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([3.0 - 3.0 * 0.01, 4.0 - 3.0 * 0.01], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testMinimizeResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -135,6 +140,7 @@ class GradientDescentOptimizerTest(test.TestCase): [[1.0 - np_grad * 4.0, 2.0 - np_grad * 5.0]], self.evaluate(var0)) self.assertAllCloseAccordingToType([3.0 - np_grad], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -162,6 +168,7 @@ class GradientDescentOptimizerTest(test.TestCase): [[1.0 - np_grad * 4.0, 2.0 - np_grad * 5.0]], self.evaluate(var0)) self.assertAllCloseAccordingToType([3.0 - np_grad], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -184,6 +191,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([3.0 - 3.0 * 0.01, 4.0 - 3.0 * 0.01], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testGradWrtRef(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -195,6 +203,7 @@ class GradientDescentOptimizerTest(test.TestCase): for grad, _ in grads_and_vars: self.assertAllCloseAccordingToType([1.0], self.evaluate(grad)) + @test_util.run_deprecated_v1 def testWithGlobalStep(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -218,6 +227,7 @@ class GradientDescentOptimizerTest(test.TestCase): self.evaluate(var1)) self.assertAllCloseAccordingToType(1, self.evaluate(global_step)) + @test_util.run_deprecated_v1 def testSparseBasic(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/training/input_test.py b/tensorflow/python/training/input_test.py index 327f087138..a3d268a017 100644 --- a/tensorflow/python/training/input_test.py +++ b/tensorflow/python/training/input_test.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables @@ -41,6 +42,7 @@ from tensorflow.python.util import compat class MatchFilenamesOnceTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def test(self): temp_dir = self.get_temp_dir() filenames = [os.path.join(temp_dir, n) for n in os.listdir(temp_dir)] @@ -68,6 +70,7 @@ class MatchFilenamesOnceTest(test_lib.TestCase): class LimitEpochsTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testNoLimit(self): with self.cached_session(): seven = constant_op.constant(7) @@ -76,6 +79,7 @@ class LimitEpochsTest(test_lib.TestCase): for _ in range(100): self.assertEqual(7, self.evaluate(seven_forever)) + @test_util.run_deprecated_v1 def testLimit(self): with self.cached_session(): love_me = constant_op.constant("Love Me") @@ -90,6 +94,7 @@ class LimitEpochsTest(test_lib.TestCase): class InputProducerTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testNoShuffle(self): with self.cached_session(): input_tensor = [[1, 2, 3, 4], @@ -114,6 +119,7 @@ class InputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testNoShapeInference(self): with self.cached_session(): # Disable shape inference for the input. @@ -139,6 +145,7 @@ class InputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testShapeError(self): input_tensor = array_ops.placeholder(dtypes.float32, None) with self.assertRaisesRegexp(ValueError, "fully defined shape"): @@ -147,6 +154,7 @@ class InputProducerTest(test_lib.TestCase): class StringInputProducerTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testNoShuffle(self): with self.cached_session(): strings = [b"to", b"be", b"or", b"not", b"to", b"be"] @@ -169,6 +177,7 @@ class StringInputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testShuffle(self): with self.cached_session(): strings = [b"a", b"b", b"c"] @@ -214,6 +223,7 @@ class StringInputProducerTest(test_lib.TestCase): with self.assertRaises(ValueError): _ = inp.string_input_producer([]) + @test_util.run_deprecated_v1 def testNullString(self): # Runtime check for empty string list. This is slightly oblique: # The queue runner should die with an assertion error on the null @@ -233,6 +243,7 @@ class StringInputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): strings = [b"to", b"be", b"or", b"not", b"to", b"be"] @@ -241,6 +252,7 @@ class StringInputProducerTest(test_lib.TestCase): self.assertProtoEquals("s: 'SHARED_NAME_XYZ'", queue.queue_ref.op.node_def.attr["shared_name"]) + @test_util.run_deprecated_v1 def testConstructionRace(self): with self.cached_session() as sess: strings = [b"to", b"be", b"or", b"not", b"to", b"be"] @@ -263,6 +275,7 @@ class StringInputProducerTest(test_lib.TestCase): class RangeInputProducerTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testNoShuffle(self): with self.cached_session(): num_epochs = 3 @@ -285,6 +298,7 @@ class RangeInputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testShuffle(self): with self.cached_session(): num_epochs = 200 @@ -324,6 +338,7 @@ class RangeInputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): range_size = 5 @@ -335,6 +350,7 @@ class RangeInputProducerTest(test_lib.TestCase): class SliceInputProducerTest(test_lib.TestCase): + @test_util.run_deprecated_v1 def testNoShuffle(self): with self.cached_session() as sess: num_epochs = 3 @@ -359,6 +375,7 @@ class SliceInputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testShuffle(self): with self.cached_session() as sess: num_epochs = 1200 @@ -403,6 +420,7 @@ class SliceInputProducerTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): source_strings = ["A", "B", "D", "G"] @@ -495,12 +513,15 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testOneThread(self): self._testOneThreadHelper(use_dict=False) + @test_util.run_deprecated_v1 def testOneThreadDict(self): self._testOneThreadHelper(use_dict=True) + @test_util.run_deprecated_v1 def testUint32DataTypes(self): values = constant_op.constant([0, 1, 2, 3, 4, 5], dtype=dtypes.uint32) batched = inp.batch([values], batch_size=2) @@ -512,6 +533,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testUint64DataTypes(self): values = constant_op.constant([0, 1, 2, 3, 4, 5], dtype=dtypes.uint64) batched = inp.batch([values], batch_size=2) @@ -523,6 +545,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testOneThreadDynamicPad(self): with self.cached_session() as sess: batch_size = 10 @@ -553,6 +576,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testOneThreadEnqueueMany(self): with self.cached_session() as sess: batch_size = 10 @@ -588,6 +612,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testManyThreads(self): with self.cached_session() as sess: batch_size = 10 @@ -628,6 +653,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testOneThreadSmallerBatch(self): with self.cached_session() as sess: batch_size = 10 @@ -685,6 +711,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testManyThreadsSmallerBatch(self): with self.cached_session() as sess: batch_size = 10 @@ -740,6 +767,7 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): batch_size = 10 @@ -757,12 +785,14 @@ class BatchTest(test_lib.TestCase): "s: 'SHARED_NAME_XYZ'", batched[0].op.inputs[0].op.node_def.attr["shared_name"]) + @test_util.run_deprecated_v1 def testCannotInferRankError(self): with self.cached_session(): x = array_ops.placeholder(dtype=dtypes.int64) with self.assertRaisesRegexp(ValueError, "Cannot infer Tensor's rank"): inp.batch([x], batch_size=2) + @test_util.run_deprecated_v1 def testBatchedSparseTensorInferredShape(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -770,6 +800,7 @@ class BatchTest(test_lib.TestCase): batched = inp.batch([sparse], batch_size=2) self.assertAllEqual((2,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testBatchedSparseTensorInferredShapeEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -777,6 +808,7 @@ class BatchTest(test_lib.TestCase): batched = inp.batch([sparse], batch_size=2, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testBatchedSparseTensorInferredShapeUnknownRank(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -786,6 +818,7 @@ class BatchTest(test_lib.TestCase): batched = inp.batch([sparse], batch_size=2) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testBatchedSparseTensorInferredShapeUnknownRankEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -795,6 +828,7 @@ class BatchTest(test_lib.TestCase): batched = inp.batch([sparse], batch_size=2, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testSingleElementDict(self): x = inp.batch({"c": [12, 12]}, batch_size=8) self.assertAllEqual((8, 2), x["c"].get_shape().as_list()) @@ -838,24 +872,31 @@ class BatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSingleThreadKeepInput(self): self._testKeepInputHelper(1, False) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(1, True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInput(self): self._testKeepInputHelper(5, False) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(5, True) + @test_util.run_deprecated_v1 def testMaybeEnqueuePerExample(self): self._testKeepInputHelper(1, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testMultipleThreadMaybeEnqueuePerExample(self): self._testKeepInputHelper(5, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testInvalidKeepInputVector(self): # Can't have vector `keep_input` with `enqueue_many=False`. with self.assertRaisesRegexp(ValueError, "`keep_input` cannot be a vector"): @@ -877,6 +918,7 @@ class BatchTest(test_lib.TestCase): batch_size=1, enqueue_many=True) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShape(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -884,6 +926,7 @@ class BatchTest(test_lib.TestCase): batched = inp.maybe_batch([sparse], keep_input=True, batch_size=2) self.assertAllEqual((2,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -892,6 +935,7 @@ class BatchTest(test_lib.TestCase): [sparse], keep_input=True, batch_size=2, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueManyPerExample(self): sparse = sparse_tensor.SparseTensor( indices=[[0], [0]], values=[1.0, 2.0], dense_shape=[2]) @@ -900,6 +944,7 @@ class BatchTest(test_lib.TestCase): [sparse], keep_input=[True, False], batch_size=2, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRank(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -909,6 +954,7 @@ class BatchTest(test_lib.TestCase): batched = inp.maybe_batch([sparse], keep_input=True, batch_size=2) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -919,6 +965,7 @@ class BatchTest(test_lib.TestCase): [sparse], keep_input=True, batch_size=2, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankPerExample(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -929,6 +976,7 @@ class BatchTest(test_lib.TestCase): [sparse], keep_input=[True, False], batch_size=2, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchCorrectValues(self): sparse_t = sparse_tensor.SparseTensor( indices=[[0, 1], [0, 2], [1, 0], [1, 3]], @@ -1055,12 +1103,15 @@ class BatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testTwoThreads(self): self._testTwoThreadsHelper(use_dict=False) + @test_util.run_deprecated_v1 def testTwoThreadsDict(self): self._testTwoThreadsHelper(use_dict=True) + @test_util.run_deprecated_v1 def testMismatchedDictKeys(self): with self.assertRaisesRegexp(ValueError, "must have the same keys"): inp.batch_join( @@ -1075,6 +1126,7 @@ class BatchJoinTest(test_lib.TestCase): }], batch_size=8) + @test_util.run_deprecated_v1 def testTwoThreadsDynamicPad(self): with self.cached_session() as sess: # Two threads, the first generates (0..69, ["a"] * 1..70). @@ -1152,6 +1204,7 @@ class BatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testTwoThreadsSmallerBatch(self): with self.cached_session() as sess: extra_elements = 2 @@ -1253,6 +1306,7 @@ class BatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testTwoThreadsDynamicPadSmallerBatch(self): with self.cached_session() as sess: extra_elements = 2 @@ -1351,6 +1405,7 @@ class BatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): batch_size = 10 @@ -1373,12 +1428,14 @@ class BatchJoinTest(test_lib.TestCase): "s: 'SHARED_NAME_XYZ'", batched[0].op.inputs[0].op.node_def.attr["shared_name"]) + @test_util.run_deprecated_v1 def testCannotInferRankError(self): with self.cached_session(): x = array_ops.placeholder(dtype=dtypes.int64) with self.assertRaisesRegexp(ValueError, "Cannot infer Tensor's rank"): inp.batch_join([[x]], batch_size=2) + @test_util.run_deprecated_v1 def testSingleElementDict(self): x = inp.batch_join([{"c": [12, 12]}], batch_size=8) self.assertAllEqual((8, 2), x["c"].get_shape().as_list()) @@ -1425,24 +1482,31 @@ class BatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSingleThreadKeepInput(self): self._testKeepInputHelper(1, False) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(1, True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInput(self): self._testKeepInputHelper(5, False) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(5, True) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputPerExample(self): self._testKeepInputHelper(1, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputPerExample(self): self._testKeepInputHelper(5, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testInvalidKeepInputVector(self): # Can't have vector `keep_input` with `enqueue_many=False`. with self.assertRaisesRegexp(ValueError, "`keep_input` cannot be a vector"): @@ -1464,6 +1528,7 @@ class BatchJoinTest(test_lib.TestCase): batch_size=1, enqueue_many=True) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShape(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -1471,6 +1536,7 @@ class BatchJoinTest(test_lib.TestCase): batched = inp.maybe_batch_join([[sparse]], keep_input=True, batch_size=2) self.assertAllEqual((2,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -1479,6 +1545,7 @@ class BatchJoinTest(test_lib.TestCase): [[sparse]], keep_input=True, batch_size=2, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueManyPerExample(self): sparse = sparse_tensor.SparseTensor( indices=[[0], [0]], values=[1.0, 2.0], dense_shape=[2]) @@ -1487,6 +1554,7 @@ class BatchJoinTest(test_lib.TestCase): [[sparse]], keep_input=[True, False], batch_size=2, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRank(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -1496,6 +1564,7 @@ class BatchJoinTest(test_lib.TestCase): batched = inp.maybe_batch_join([[sparse]], keep_input=True, batch_size=2) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -1506,6 +1575,7 @@ class BatchJoinTest(test_lib.TestCase): [[sparse]], keep_input=True, batch_size=2, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankPerExample(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -1516,6 +1586,7 @@ class BatchJoinTest(test_lib.TestCase): [[sparse]], keep_input=[True, False], batch_size=2, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchCorrectValues(self): sparse = sparse_tensor.SparseTensor( indices=[[0, 1], [0, 2], [1, 0], [1, 3]], @@ -1601,12 +1672,15 @@ class ShuffleBatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testOneThread(self): self._testOneThreadHelper(use_dict=False) + @test_util.run_deprecated_v1 def testOneThreadDict(self): self._testOneThreadHelper(use_dict=True) + @test_util.run_deprecated_v1 def testOneThreadSmallerBatch(self): with self.cached_session() as sess: batch_size = 10 @@ -1663,6 +1737,7 @@ class ShuffleBatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testManyThreads(self): with self.cached_session() as sess: batch_size = 10 @@ -1710,6 +1785,7 @@ class ShuffleBatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testManyThreadsSmallerBatch(self): with self.cached_session() as sess: batch_size = 10 @@ -1768,6 +1844,7 @@ class ShuffleBatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): batch_size = 10 @@ -1828,24 +1905,31 @@ class ShuffleBatchTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSingleThreadKeepInput(self): self._testKeepInputHelper(1, False) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(1, True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInput(self): self._testKeepInputHelper(5, False) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(5, True) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputPerExample(self): self._testKeepInputHelper(1, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputPerExample(self): self._testKeepInputHelper(5, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testInvalidKeepInputVector(self): # Can't have vector `keep_input` with `enqueue_many=False`. with self.assertRaisesRegexp(ValueError, "`keep_input` cannot be a vector"): @@ -1864,6 +1948,7 @@ class ShuffleBatchTest(test_lib.TestCase): keep_input=array_ops.placeholder(dtypes.bool), enqueue_many=True) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShape(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -1871,6 +1956,7 @@ class ShuffleBatchTest(test_lib.TestCase): batched = inp.maybe_shuffle_batch([sparse], 2, 10, 1, True) self.assertAllEqual((2,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -1879,6 +1965,7 @@ class ShuffleBatchTest(test_lib.TestCase): [sparse], 2, 10, 1, True, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueManyPerExample(self): sparse = sparse_tensor.SparseTensor( indices=[[0], [0]], values=[1.0, 2.0], dense_shape=[2]) @@ -1887,6 +1974,7 @@ class ShuffleBatchTest(test_lib.TestCase): [sparse], 2, 10, 1, [True, False], enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRank(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -1896,6 +1984,7 @@ class ShuffleBatchTest(test_lib.TestCase): batched = inp.maybe_shuffle_batch([sparse], 2, 10, 1, True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -1906,6 +1995,7 @@ class ShuffleBatchTest(test_lib.TestCase): [sparse], 2, 10, 1, True, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankPerExample(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -2024,12 +2114,15 @@ class ShuffleBatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testTwoThreads(self): self._testTwoThreadsHelper(use_dict=False) + @test_util.run_deprecated_v1 def testTwoThreadsDict(self): self._testTwoThreadsHelper(use_dict=True) + @test_util.run_deprecated_v1 def testTwoThreadsSmallerBatch(self): with self.cached_session() as sess: # Two threads, the first generates (0..26, "a"). @@ -2133,6 +2226,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testMismatchedDictKeys(self): with self.assertRaisesRegexp(ValueError, "must have the same keys"): inp.shuffle_batch_join( @@ -2150,6 +2244,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): min_after_dequeue=16, seed=223607) + @test_util.run_deprecated_v1 def testSharedName(self): with self.cached_session(): batch_size = 10 @@ -2214,24 +2309,31 @@ class ShuffleBatchJoinTest(test_lib.TestCase): for thread in threads: thread.join() + @test_util.run_deprecated_v1 def testSingleThreadKeepInput(self): self._testKeepInputHelper(1, False) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(1, True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInput(self): self._testKeepInputHelper(5, False) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputEnqueueMany(self): self._testKeepInputHelper(5, True) + @test_util.run_deprecated_v1 def testSingleThreadKeepInputPerExample(self): self._testKeepInputHelper(1, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testMultipleThreadKeepInputPerExample(self): self._testKeepInputHelper(5, True, keep_input_vector=True) + @test_util.run_deprecated_v1 def testInvalidKeepInputVector(self): # Can't have vector `keep_input` with `enqueue_many=False`. with self.assertRaisesRegexp(ValueError, "`keep_input` cannot be a vector"): @@ -2253,6 +2355,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): keep_input=array_ops.placeholder(dtypes.bool), enqueue_many=True) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShape(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -2260,6 +2363,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): batched = inp.maybe_shuffle_batch_join([[sparse]], 2, 10, 1, True) self.assertAllEqual((2,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=[[0]], values=[1.0], dense_shape=[1]) @@ -2268,6 +2372,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): [[sparse]], 2, 10, 1, True, enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeEnqueueManyPerExample(self): sparse = sparse_tensor.SparseTensor( indices=[[0], [0]], values=[1.0, 2.0], dense_shape=[2]) @@ -2276,6 +2381,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): [[sparse]], 2, 10, 1, [True, False], enqueue_many=True) self.assertAllEqual((1,), batched.dense_shape.get_shape().as_list()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRank(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -2285,6 +2391,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): batched = inp.maybe_shuffle_batch_join([[sparse]], 2, 10, 1, True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankEnqueueMany(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), @@ -2295,6 +2402,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): [[sparse]], 2, 10, 1, True, enqueue_many=True) self.assertIs(None, batched.dense_shape.get_shape().num_elements()) + @test_util.run_deprecated_v1 def testMaybeBatchedSparseTensorInferredShapeUnknownRankPerExample(self): sparse = sparse_tensor.SparseTensor( indices=array_ops.placeholder(dtypes.int64), diff --git a/tensorflow/python/training/learning_rate_decay_test.py b/tensorflow/python/training/learning_rate_decay_test.py index 9c31c0924f..9de5bc8168 100644 --- a/tensorflow/python/training/learning_rate_decay_test.py +++ b/tensorflow/python/training/learning_rate_decay_test.py @@ -61,6 +61,7 @@ class LRDecayTest(test_util.TensorFlowTestCase): self.evaluate(step.assign(100)) self.assertAllClose(self.evaluate(decayed_lr), expected, 1e-6) + @test_util.run_deprecated_v1 def testVariables(self): step = variables.VariableV1(1) assign_1 = step.assign(1) @@ -100,6 +101,7 @@ class LRDecayTest(test_util.TensorFlowTestCase): self.assertAllClose(self.evaluate(decayed_lr), 0.001, 1e-6) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testPiecewiseConstantEdgeCases(self): x_int = resource_variable_ops.ResourceVariable( 0, dtype=variables.dtypes.int32) diff --git a/tensorflow/python/training/learning_rate_decay_v2_test.py b/tensorflow/python/training/learning_rate_decay_v2_test.py index 354ddb25be..cb96773e29 100644 --- a/tensorflow/python/training/learning_rate_decay_v2_test.py +++ b/tensorflow/python/training/learning_rate_decay_v2_test.py @@ -61,6 +61,7 @@ class LRDecayTestV2(test_util.TensorFlowTestCase): self.evaluate(step.assign(100)) self.assertAllClose(self.evaluate(decayed_lr()), expected, 1e-6) + @test_util.run_deprecated_v1 def testVariables(self): step = variables.Variable(1) assign_1 = step.assign(1) diff --git a/tensorflow/python/training/momentum_test.py b/tensorflow/python/training/momentum_test.py index b6cac6addf..ba155fa6c6 100644 --- a/tensorflow/python/training/momentum_test.py +++ b/tensorflow/python/training/momentum_test.py @@ -160,6 +160,7 @@ class MomentumOptimizerTest(test.TestCase): self.assertStartsWith(optimizer_variables[1].name, "var3") self.assertEquals(2, len(optimizer_variables)) + @test_util.run_deprecated_v1 def testNesterovMomentum(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -186,6 +187,7 @@ class MomentumOptimizerTest(test.TestCase): self.assertAllClose(var0_np, self.evaluate(var0)) self.assertAllClose(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testSparseNesterovMomentum(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -280,6 +282,7 @@ class MomentumOptimizerTest(test.TestCase): self.evaluate(sgd_op) self.assertAllCloseAccordingToType([[1, 1], [0, 0]], self.evaluate(var0)) + @test_util.run_deprecated_v1 def testTensorLearningRateAndMomentum(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -440,6 +443,7 @@ class MomentumOptimizerTest(test.TestCase): # pylint: enable=line-too-long return db_grad, db_out + @test_util.run_deprecated_v1 def testLikeDistBeliefMom01(self): with self.cached_session(): db_grad, db_out = self._dbParamsMom01() @@ -453,6 +457,7 @@ class MomentumOptimizerTest(test.TestCase): mom_update.run(feed_dict={grads0: db_grad[i]}) self.assertAllClose(np.array(db_out[i]), self.evaluate(var0)) + @test_util.run_deprecated_v1 def testSparse(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -534,6 +539,7 @@ class MomentumOptimizerTest(test.TestCase): ]), self.evaluate(var1)[2]) + @test_util.run_deprecated_v1 def testSharing(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/training/monitored_session_test.py b/tensorflow/python/training/monitored_session_test.py index 2ceb387ec3..9dbcfa52b7 100644 --- a/tensorflow/python/training/monitored_session_test.py +++ b/tensorflow/python/training/monitored_session_test.py @@ -37,6 +37,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import resource_variable_ops @@ -504,6 +505,7 @@ class StopAtNSession(monitored_session._WrappedSession): class WrappedSessionTest(test.TestCase): """_WrappedSession tests.""" + @test_util.run_deprecated_v1 def test_properties(self): with self.cached_session() as sess: constant_op.constant(0.0) @@ -511,6 +513,7 @@ class WrappedSessionTest(test.TestCase): self.assertEquals(sess.graph, wrapped_sess.graph) self.assertEquals(sess.sess_str, wrapped_sess.sess_str) + @test_util.run_deprecated_v1 def test_should_stop_on_close(self): with self.cached_session() as sess: wrapped_sess = monitored_session._WrappedSession(sess) @@ -518,6 +521,7 @@ class WrappedSessionTest(test.TestCase): wrapped_sess.close() self.assertTrue(wrapped_sess.should_stop()) + @test_util.run_deprecated_v1 def test_should_stop_uses_check_stop(self): with self.cached_session() as sess: wrapped_sess = StopAtNSession(sess, 3) @@ -526,6 +530,7 @@ class WrappedSessionTest(test.TestCase): self.assertFalse(wrapped_sess.should_stop()) self.assertTrue(wrapped_sess.should_stop()) + @test_util.run_deprecated_v1 def test_should_stop_delegates_to_wrapped_session(self): with self.cached_session() as sess: wrapped_sess0 = StopAtNSession(sess, 4) @@ -544,6 +549,7 @@ class WrappedSessionTest(test.TestCase): wrapped_sess.close() self.assertTrue(wrapped_sess.should_stop()) + @test_util.run_deprecated_v1 def test_run(self): with self.cached_session() as sess: c = constant_op.constant(0) @@ -561,6 +567,7 @@ def busy_wait_for_coord_stop(coord): class CoordinatedSessionTest(test.TestCase): """_CoordinatedSession tests.""" + @test_util.run_deprecated_v1 def test_properties(self): with self.cached_session() as sess: constant_op.constant(0.0) @@ -569,6 +576,7 @@ class CoordinatedSessionTest(test.TestCase): self.assertEquals(sess.graph, coord_sess.graph) self.assertEquals(sess.sess_str, coord_sess.sess_str) + @test_util.run_deprecated_v1 def test_run(self): with self.cached_session() as sess: c = constant_op.constant(0) @@ -577,6 +585,7 @@ class CoordinatedSessionTest(test.TestCase): coord_sess = monitored_session._CoordinatedSession(sess, coord) self.assertEqual(42, coord_sess.run(v, feed_dict={c: 42})) + @test_util.run_deprecated_v1 def test_should_stop_on_close(self): with self.cached_session() as sess: coord = coordinator.Coordinator() @@ -585,6 +594,7 @@ class CoordinatedSessionTest(test.TestCase): coord_sess.close() self.assertTrue(coord_sess.should_stop()) + @test_util.run_deprecated_v1 def test_should_stop_on_coord_stop(self): with self.cached_session() as sess: coord = coordinator.Coordinator() @@ -593,6 +603,7 @@ class CoordinatedSessionTest(test.TestCase): coord.request_stop() self.assertTrue(coord_sess.should_stop()) + @test_util.run_deprecated_v1 def test_dont_request_stop_on_exception_in_main_thread(self): with self.cached_session() as sess: c = constant_op.constant(0) @@ -607,6 +618,7 @@ class CoordinatedSessionTest(test.TestCase): self.assertFalse(coord.should_stop()) self.assertFalse(coord_sess.should_stop()) + @test_util.run_deprecated_v1 def test_stop_threads_on_close_after_exception(self): with self.cached_session() as sess: c = constant_op.constant(0) @@ -654,6 +666,7 @@ class CoordinatedSessionTest(test.TestCase): self.assertTrue(coord.should_stop()) self.assertTrue(coord_sess.should_stop()) + @test_util.run_deprecated_v1 def test_propagates_exception_trace(self): assertion = control_flow_ops.Assert(False, ['This should fail.']) with self.cached_session() as sess: @@ -801,6 +814,7 @@ class RecoverableSessionTest(test.TestCase): def create_session(self): return self._sess + @test_util.run_deprecated_v1 def test_properties(self): with self.cached_session() as sess: constant_op.constant(0.0) @@ -809,6 +823,7 @@ class RecoverableSessionTest(test.TestCase): self.assertEquals(sess.graph, recoverable_sess.graph) self.assertEquals(sess.sess_str, recoverable_sess.sess_str) + @test_util.run_deprecated_v1 def test_run(self): with self.cached_session() as sess: c = constant_op.constant(0) @@ -817,6 +832,7 @@ class RecoverableSessionTest(test.TestCase): self._SessionReturner(sess)) self.assertEqual(51, recoverable_sess.run(v, feed_dict={c: 51})) + @test_util.run_deprecated_v1 def test_recovery(self): with self.cached_session() as sess: @@ -863,6 +879,7 @@ class RecoverableSessionTest(test.TestCase): with self.assertRaisesRegexp(IndexError, 'pop from empty list'): recoverable_sess.run(v, feed_dict={c: -12}) + @test_util.run_deprecated_v1 def test_recovery_from_coordinator_exception(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -888,6 +905,7 @@ class RecoverableSessionTest(test.TestCase): self.assertFalse(session.should_stop()) self.assertEqual(2, session_creator.number_of_sessions_created) + @test_util.run_deprecated_v1 def test_recovery_from_non_preemption_in_coordinator(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -917,6 +935,7 @@ class RecoverableSessionTest(test.TestCase): with self.assertRaises(errors_impl.UnknownError): session.close() + @test_util.run_deprecated_v1 def test_recovery_from_session_getting_stuck(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -941,6 +960,7 @@ class RecoverableSessionTest(test.TestCase): self.assertFalse(session.should_stop()) self.assertEqual(2, session_creator.number_of_sessions_created) + @test_util.run_deprecated_v1 def test_step_fn_recovery_from_coordinator_exception_when_run_hooks(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -971,6 +991,7 @@ class RecoverableSessionTest(test.TestCase): self.assertFalse(session.should_stop()) self.assertEqual(2, session_creator.number_of_sessions_created) + @test_util.run_deprecated_v1 def test_recovery_from_non_preemption_in_coordinator_when_run_hooks(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -1005,6 +1026,7 @@ class RecoverableSessionTest(test.TestCase): with self.assertRaises(errors_impl.UnknownError): session.close() + @test_util.run_deprecated_v1 def test_recovery_from_session_getting_stuck_when_run_hooks(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -1049,6 +1071,7 @@ class RecoverableSessionTest(test.TestCase): # exception. return session + @test_util.run_deprecated_v1 def test_step_fn_recovery_from_coordinator_exception_with_raw_session(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -1081,6 +1104,7 @@ class RecoverableSessionTest(test.TestCase): self.assertFalse(session.should_stop()) self.assertEqual(2, session_creator.number_of_sessions_created) + @test_util.run_deprecated_v1 def test_recovery_from_non_preemption_in_coordinator_with_raw_session(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -1118,6 +1142,7 @@ class RecoverableSessionTest(test.TestCase): with self.assertRaises(errors_impl.UnknownError): session.close() + @test_util.run_deprecated_v1 def test_recovery_from_session_getting_stuck_with_raw_session(self): with self.cached_session() as test_session: session_creator = CountingSessionCreator(test_session) @@ -1443,6 +1468,7 @@ class MonitoredSessionTest(test.TestCase): # This set of tests, verifies the supervised session behavior when exceptions # are raised next to the innermost session run() call. + @test_util.run_deprecated_v1 def test_recovery(self): logdir = _test_dir(self.get_temp_dir(), 'test_recovery') with ops.Graph().as_default(): @@ -1795,6 +1821,7 @@ class MonitoredSessionTest(test.TestCase): isinstance(hook.run_metadata_list[0], config_pb2.RunMetadata)) self.assertGreater(len(hook.run_metadata_list[0].partition_graphs), 0) + @test_util.run_deprecated_v1 def test_with_statement_and_close(self): # Test case for https://github.com/tensorflow/tensorflow/issues/12224 # where close() inside the with should have a better error message. diff --git a/tensorflow/python/training/moving_averages_test.py b/tensorflow/python/training/moving_averages_test.py index 6ce5de6663..b15f7377f0 100644 --- a/tensorflow/python/training/moving_averages_test.py +++ b/tensorflow/python/training/moving_averages_test.py @@ -35,6 +35,7 @@ from tensorflow.python.training import saver as saver_lib class MovingAveragesTest(test.TestCase): + @test_util.run_deprecated_v1 def testAssignMovingAverageWithoutZeroDebias(self): with self.cached_session(): var = variables.Variable([10.0, 11.0]) @@ -49,6 +50,7 @@ class MovingAveragesTest(test.TestCase): [10.0 * 0.25 + 1.0 * (1.0 - 0.25), 11.0 * 0.25 + 2.0 * (1.0 - 0.25)], self.evaluate(var)) + @test_util.run_deprecated_v1 def testAssignMovingAverage(self): with self.cached_session(): var = variables.Variable([0.0, 0.0]) @@ -62,6 +64,7 @@ class MovingAveragesTest(test.TestCase): [1.0 * (1.0 - 0.25) / (1 - 0.25), 2.0 * (1.0 - 0.25) / (1 - 0.25)], self.evaluate(var)) + @test_util.run_deprecated_v1 def testAssignMovingAverageNewNamingMultipleCalls(self): with variable_scope.variable_scope("scope1") as vs1: with variable_scope.variable_scope("scope2"): @@ -76,6 +79,7 @@ class MovingAveragesTest(test.TestCase): actual_names = [v.name for v in vs1.global_variables()] self.assertSetEqual(set(expected_names), set(actual_names)) + @test_util.run_deprecated_v1 def testAssignMovingAverageNewNamingMultipleCallsWithReuse(self): with variable_scope.variable_scope("scope1") as vs1: var = variable_scope.get_variable("Var", shape=[]) @@ -86,6 +90,7 @@ class MovingAveragesTest(test.TestCase): moving_averages.assign_moving_average(var, 0.0, 0.99) moving_averages.assign_moving_average(var, 0.0, 0.99) + @test_util.run_deprecated_v1 def testWeightedMovingAverage(self): with self.cached_session() as sess: decay = 0.5 @@ -111,6 +116,7 @@ class MovingAveragesTest(test.TestCase): denominator_2 = denominator_1 * decay + weight_2 * (1.0 - decay) self.assertAllClose(numerator_2 / denominator_2, wma_array) + @test_util.run_deprecated_v1 def testWeightedMovingAverageBfloat16(self): bfloat16 = pywrap_tensorflow.TF_bfloat16_type() with self.cached_session() as sess: @@ -213,32 +219,38 @@ class ExponentialMovingAverageTest(test.TestCase): (10.0 + 30.0) * (1 - dk)) / _Scale(dk, 2), dim) self.assertAllClose(expected, self.evaluate(avg2)) + @test_util.run_deprecated_v1 def testAverageVariablesNoNumUpdates_Scalar(self): with self.cached_session(): ema = moving_averages.ExponentialMovingAverage(0.25) self._CheckDecay(ema, actual_decay=0.25, dim=1) + @test_util.run_deprecated_v1 def testAverageVariablesNoNumUpdates_Scalar_Debias(self): with self.cached_session(): ema = moving_averages.ExponentialMovingAverage(0.25, zero_debias=True) self._CheckDecay(ema, actual_decay=0.25, dim=1) + @test_util.run_deprecated_v1 def testAverageVariablesNoNumUpdates_Vector(self): with self.cached_session(): ema = moving_averages.ExponentialMovingAverage(0.25) self._CheckDecay(ema, actual_decay=0.25, dim=5) + @test_util.run_deprecated_v1 def testAverageVariablesNoNumUpdates_Vector_Debias(self): with self.cached_session(): ema = moving_averages.ExponentialMovingAverage(0.25, zero_debias=True) self._CheckDecay(ema, actual_decay=0.25, dim=5) + @test_util.run_deprecated_v1 def testAverageVariablesNumUpdates_Scalar(self): with self.cached_session(): # With num_updates 1, the decay applied is 0.1818 ema = moving_averages.ExponentialMovingAverage(0.25, num_updates=1) self._CheckDecay(ema, actual_decay=0.181818, dim=1) + @test_util.run_deprecated_v1 def testAverageVariablesNumUpdates_Scalar_Debias(self): with self.cached_session(): # With num_updates 1, the decay applied is 0.1818 @@ -246,12 +258,14 @@ class ExponentialMovingAverageTest(test.TestCase): 0.25, num_updates=1, zero_debias=True) self._CheckDecay(ema, actual_decay=0.181818, dim=1) + @test_util.run_deprecated_v1 def testAverageVariablesNumUpdates_Vector(self): with self.cached_session(): # With num_updates 1, the decay applied is 0.1818 ema = moving_averages.ExponentialMovingAverage(0.25, num_updates=1) self._CheckDecay(ema, actual_decay=0.181818, dim=5) + @test_util.run_deprecated_v1 def testAverageVariablesNumUpdates_Vector_Debias(self): with self.cached_session(): # With num_updates 1, the decay applied is 0.1818 @@ -259,6 +273,7 @@ class ExponentialMovingAverageTest(test.TestCase): 0.25, num_updates=1, zero_debias=True) self._CheckDecay(ema, actual_decay=0.181818, dim=5) + @test_util.run_deprecated_v1 def testAverageVariablesWithControlDeps(self): with self.cached_session() as sess: v0 = variables.Variable(0, name="v0") @@ -284,6 +299,7 @@ class ExponentialMovingAverageTest(test.TestCase): self.assertEqual([17.5], self.evaluate(v1_avg)) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testBasicEager(self): v0 = variables.Variable(1.0) v1 = variables.Variable(2.0) @@ -339,9 +355,11 @@ class ExponentialMovingAverageTest(test.TestCase): self.assertEqual(ema.average(v1).op.name, ema.average_name(v1)) self.assertEqual(ema.average(tensor2).op.name, ema.average_name(tensor2)) + @test_util.run_deprecated_v1 def testAverageVariablesNames(self): self.averageVariablesNamesHelper(zero_debias=True) + @test_util.run_deprecated_v1 def testAverageVariablesNamesNoDebias(self): self.averageVariablesNamesHelper(zero_debias=False) @@ -387,12 +405,15 @@ class ExponentialMovingAverageTest(test.TestCase): self.assertEqual( ema.average(tensor2).op.name, ema.average_name(tensor2)) + @test_util.run_deprecated_v1 def testAverageVariablesNamesRespectScope(self): self.averageVariablesNamesRespectScopeHelper(zero_debias=True) + @test_util.run_deprecated_v1 def testAverageVariablesNamesRespectScopeNoDebias(self): self.averageVariablesNamesRespectScopeHelper(zero_debias=False) + @test_util.run_deprecated_v1 def testSubsetAverageVariablesNames(self): with self.cached_session(): v0 = variables.Variable(10.0, name="v0") @@ -421,6 +442,7 @@ class ExponentialMovingAverageTest(test.TestCase): self.assertEqual(ema.average(v1).op.name, ema.average_name(v1)) self.assertEqual(ema.average(tensor2).op.name, ema.average_name(tensor2)) + @test_util.run_deprecated_v1 def testAverageVariablesDeviceAssignment(self): with ops.device("/job:dev_v0"): v0 = variables.Variable(10.0, name="v0") @@ -451,6 +473,7 @@ class ExponentialMovingAverageTest(test.TestCase): _ = saver_lib.import_meta_graph(meta_graph) return graph_copy + @test_util.run_deprecated_v1 def testImportedGraphVariablesToRestore(self): g = ops.Graph() with g.as_default(): diff --git a/tensorflow/python/training/optimizer_test.py b/tensorflow/python/training/optimizer_test.py index 5ed0a30285..e175b5a799 100644 --- a/tensorflow/python/training/optimizer_test.py +++ b/tensorflow/python/training/optimizer_test.py @@ -62,6 +62,7 @@ class OptimizerTest(test.TestCase): self.assertAllClose([-14., -13.], self.evaluate(var0)) self.assertAllClose([-6., -5.], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testAggregationMethod(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -87,6 +88,7 @@ class OptimizerTest(test.TestCase): self.assertAllClose([-14., -13.], self.evaluate(var0)) self.assertAllClose([-6., -5.], self.evaluate(var1)) + @test_util.run_deprecated_v1 def testPrecomputedGradient(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -230,6 +232,7 @@ class OptimizerTest(test.TestCase): with self.assertRaises(NotImplementedError): sgd_op.apply_gradients(grads_and_vars) + @test_util.run_deprecated_v1 def testTrainOp(self): with self.cached_session(): var0 = variables.Variable([1.0, 2.0]) @@ -241,6 +244,7 @@ class OptimizerTest(test.TestCase): opt_op = sgd_op.minimize(cost, global_step, [var0, var1]) self.assertTrue(opt_op in ops.get_collection(ops.GraphKeys.TRAIN_OP)) + @test_util.run_deprecated_v1 def testConstraint(self): constraint_01 = lambda x: clip_ops.clip_by_value(x, -0.1, 0.) constraint_0 = lambda x: clip_ops.clip_by_value(x, 0., 1.) diff --git a/tensorflow/python/training/proximal_adagrad_test.py b/tensorflow/python/training/proximal_adagrad_test.py index 9d46a6682d..ce214ac418 100644 --- a/tensorflow/python/training/proximal_adagrad_test.py +++ b/tensorflow/python/training/proximal_adagrad_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -64,12 +65,15 @@ class ProximalAdagradOptimizerTest(test.TestCase): self.assertStartsWith(opt_vars[1].name, var1._shared_name) self.assertEqual(2, len(opt_vars)) + @test_util.run_deprecated_v1 def testProximalAdagradwithoutRegularization(self): self.doTestProximalAdagradwithoutRegularization(use_resource=False) + @test_util.run_deprecated_v1 def testResourceProximalAdagradwithoutRegularization(self): self.doTestProximalAdagradwithoutRegularization(use_resource=True) + @test_util.run_deprecated_v1 def testProximalAdagradwithoutRegularization2(self): with self.cached_session() as sess: var0 = variables.Variable([1.0, 2.0]) @@ -96,6 +100,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): self.assertAllClose(np.array([-1.60261, -2.296985]), v0_val) self.assertAllClose(np.array([3.715679, 2.433051]), v1_val) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -114,6 +119,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testProximalAdagradWithL1(self): with self.cached_session() as sess: var0 = variables.Variable([1.0, 2.0]) @@ -140,6 +146,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): self.assertAllClose(np.array([-6.663634, -9.190331]), v0_val) self.assertAllClose(np.array([2.959304, 1.029232]), v1_val) + @test_util.run_deprecated_v1 def testProximalAdagradWithL1_L2(self): with self.cached_session() as sess: var0 = variables.Variable([1.0, 2.0]) @@ -206,6 +213,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): v0_val, v1_val = self.evaluate([var0, var1]) return v0_val, v1_val + @test_util.run_deprecated_v1 def testEquivAdagradwithoutRegularization(self): with self.cached_session(): val0, val1 = self.applyOptimizer( @@ -223,6 +231,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): self.assertAllClose(val0, val2) self.assertAllClose(val1, val3) + @test_util.run_deprecated_v1 def testEquivSparseAdagradwithoutRegularization(self): with self.cached_session(): val0, val1 = self.applyOptimizer( diff --git a/tensorflow/python/training/proximal_gradient_descent_test.py b/tensorflow/python/training/proximal_gradient_descent_test.py index 8797b308eb..25b206605d 100644 --- a/tensorflow/python/training/proximal_gradient_descent_test.py +++ b/tensorflow/python/training/proximal_gradient_descent_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import embedding_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -62,12 +63,15 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): self.assertAllClose(np.array([-0.9, -1.8]), v0_val) self.assertAllClose(np.array([-0.09, -0.18]), v1_val) + @test_util.run_deprecated_v1 def testProximalGradientDescentwithoutRegularization(self): self.doTestProximalGradientDescentwithoutRegularization(use_resource=False) + @test_util.run_deprecated_v1 def testResourceProximalGradientDescentwithoutRegularization(self): self.doTestProximalGradientDescentwithoutRegularization(use_resource=True) + @test_util.run_deprecated_v1 def testProximalGradientDescentwithoutRegularization2(self): with self.cached_session() as sess: var0 = variables.Variable([1.0, 2.0]) @@ -92,6 +96,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): self.assertAllClose(np.array([0.1, 0.2]), v0_val) self.assertAllClose(np.array([3.91, 2.82]), v1_val) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -111,6 +116,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testProximalGradientDescentWithL1_L2(self): with self.cached_session() as sess: var0 = variables.Variable([1.0, 2.0]) @@ -174,6 +180,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): v0_val, v1_val = self.evaluate([var0, var1]) return v0_val, v1_val + @test_util.run_deprecated_v1 def testEquivSparseGradientDescentwithoutRegularization(self): with self.cached_session(): val0, val1 = self.applyOptimizer( @@ -190,6 +197,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): self.assertAllClose(val0, val2) self.assertAllClose(val1, val3) + @test_util.run_deprecated_v1 def testEquivGradientDescentwithoutRegularization(self): with self.cached_session(): val0, val1 = self.applyOptimizer( diff --git a/tensorflow/python/training/quantize_training_test.py b/tensorflow/python/training/quantize_training_test.py index 07fd488563..62e783f200 100644 --- a/tensorflow/python/training/quantize_training_test.py +++ b/tensorflow/python/training/quantize_training_test.py @@ -25,6 +25,7 @@ from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import importer from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -52,6 +53,7 @@ class PywrapQuantizeTrainingTest(test.TestCase): # Test that save/restoring works for EMA variables generated in the # quantized training rewrite. + @test_util.run_deprecated_v1 def testQuantizedSaveRestore(self): save_path = os.path.join(self.get_temp_dir(), 'quantized_save_restore') diff --git a/tensorflow/python/training/queue_runner_test.py b/tensorflow/python/training/queue_runner_test.py index 65c2c13d8b..4113cecf55 100644 --- a/tensorflow/python/training/queue_runner_test.py +++ b/tensorflow/python/training/queue_runner_test.py @@ -26,6 +26,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import variables @@ -40,6 +41,7 @@ _MockOp = collections.namedtuple("MockOp", ["name"]) class QueueRunnerTest(test.TestCase): + @test_util.run_deprecated_v1 def testBasic(self): with self.cached_session() as sess: # CountUpTo will raise OUT_OF_RANGE when it reaches the count. @@ -60,6 +62,7 @@ class QueueRunnerTest(test.TestCase): # The variable should be 3. self.assertEqual(3, self.evaluate(var)) + @test_util.run_deprecated_v1 def testTwoOps(self): with self.cached_session() as sess: # CountUpTo will raise OUT_OF_RANGE when it reaches the count. @@ -83,6 +86,7 @@ class QueueRunnerTest(test.TestCase): self.assertEqual(3, self.evaluate(var0)) self.assertEqual(30, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testExceptionsCaptured(self): with self.cached_session() as sess: queue = data_flow_ops.FIFOQueue(10, dtypes.float32) @@ -99,6 +103,7 @@ class QueueRunnerTest(test.TestCase): self.assertTrue("Operation not in the graph" in str(exceptions[0])) self.assertTrue("Operation not in the graph" in str(exceptions[1])) + @test_util.run_deprecated_v1 def testRealDequeueEnqueue(self): with self.cached_session() as sess: q0 = data_flow_ops.FIFOQueue(3, dtypes.float32) @@ -127,6 +132,7 @@ class QueueRunnerTest(test.TestCase): with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed"): self.evaluate(dequeue1) + @test_util.run_deprecated_v1 def testRespectCoordShouldStop(self): with self.cached_session() as sess: # CountUpTo will raise OUT_OF_RANGE when it reaches the count. @@ -151,6 +157,7 @@ class QueueRunnerTest(test.TestCase): # The variable should be 0. self.assertEqual(0, self.evaluate(var)) + @test_util.run_deprecated_v1 def testRequestStopOnException(self): with self.cached_session() as sess: queue = data_flow_ops.FIFOQueue(10, dtypes.float32) @@ -163,6 +170,7 @@ class QueueRunnerTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "Operation not in the graph"): coord.join() + @test_util.run_deprecated_v1 def testGracePeriod(self): with self.cached_session() as sess: # The enqueue will quickly block. @@ -180,6 +188,7 @@ class QueueRunnerTest(test.TestCase): # the queue to be closed and the enqueue to terminate. coord.join(stop_grace_period_secs=1.0) + @test_util.run_deprecated_v1 def testMultipleSessions(self): with self.cached_session() as sess: with session.Session() as other_sess: @@ -195,6 +204,7 @@ class QueueRunnerTest(test.TestCase): other_threads = qr.create_threads(other_sess, coord=coord) self.assertEqual(len(threads), len(other_threads)) + @test_util.run_deprecated_v1 def testIgnoreMultiStarts(self): with self.cached_session() as sess: # CountUpTo will raise OUT_OF_RANGE when it reaches the count. @@ -211,6 +221,7 @@ class QueueRunnerTest(test.TestCase): new_threads = qr.create_threads(sess, coord=coord) self.assertEqual([], new_threads) + @test_util.run_deprecated_v1 def testThreads(self): with self.cached_session() as sess: # CountUpTo will raise OUT_OF_RANGE when it reaches the count. @@ -238,6 +249,7 @@ class QueueRunnerTest(test.TestCase): self.assertEqual(1, len(exceptions)) self.assertTrue("Operation not in the graph" in str(exceptions[0])) + @test_util.run_deprecated_v1 def testName(self): with ops.name_scope("scope"): queue = data_flow_ops.FIFOQueue(10, dtypes.float32, name="queue") @@ -247,6 +259,7 @@ class QueueRunnerTest(test.TestCase): self.assertEqual( 1, len(ops.get_collection(ops.GraphKeys.QUEUE_RUNNERS, "scope"))) + @test_util.run_deprecated_v1 def testStartQueueRunners(self): # CountUpTo will raise OUT_OF_RANGE when it reaches the count. zero64 = constant_op.constant(0, dtype=dtypes.int64) @@ -265,6 +278,7 @@ class QueueRunnerTest(test.TestCase): # The variable should be 3. self.assertEqual(3, self.evaluate(var)) + @test_util.run_deprecated_v1 def testStartQueueRunnersRaisesIfNotASession(self): zero64 = constant_op.constant(0, dtype=dtypes.int64) var = variables.VariableV1(zero64) @@ -278,6 +292,7 @@ class QueueRunnerTest(test.TestCase): with self.assertRaisesRegexp(TypeError, "tf.Session"): queue_runner_impl.start_queue_runners("NotASession") + @test_util.run_deprecated_v1 def testStartQueueRunnersIgnoresMonitoredSession(self): zero64 = constant_op.constant(0, dtype=dtypes.int64) var = variables.VariableV1(zero64) @@ -292,6 +307,7 @@ class QueueRunnerTest(test.TestCase): monitored_session.MonitoredSession()) self.assertFalse(threads) + @test_util.run_deprecated_v1 def testStartQueueRunnersNonDefaultGraph(self): # CountUpTo will raise OUT_OF_RANGE when it reaches the count. graph = ops.Graph() diff --git a/tensorflow/python/training/rmsprop_test.py b/tensorflow/python/training/rmsprop_test.py index a9b8954e39..8f029d5310 100644 --- a/tensorflow/python/training/rmsprop_test.py +++ b/tensorflow/python/training/rmsprop_test.py @@ -89,6 +89,7 @@ class RMSPropOptimizerTest(test.TestCase): var_t[gindex] = var[gindex] - mom_t[gindex] return var_t, mg_t, rms_t, mom_t + @test_util.run_deprecated_v1 def testDense(self): # TODO(yori): Use ParameterizedTest when available for (dtype, learning_rate, decay, momentum, @@ -164,6 +165,7 @@ class RMSPropOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -187,6 +189,7 @@ class RMSPropOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testMinimizeSparseResourceVariableCentered(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -210,6 +213,7 @@ class RMSPropOptimizerTest(test.TestCase): self.evaluate(var0), atol=0.01) + @test_util.run_deprecated_v1 def testSparse(self): # TODO(yori): Use ParameterizedTest when available for (dtype, learning_rate, decay, @@ -286,6 +290,7 @@ class RMSPropOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + @test_util.run_deprecated_v1 def testWithoutMomentum(self): for dtype in [dtypes.half, dtypes.float32]: with test_util.use_gpu(): @@ -354,6 +359,7 @@ class RMSPropOptimizerTest(test.TestCase): (0.01 * 2.0 / math.sqrt(0.90001 * 0.9 + 1e-5 + 1.0)) ]), self.evaluate(var1)) + @test_util.run_deprecated_v1 def testWithMomentum(self): for dtype in [dtypes.half, dtypes.float32]: with test_util.use_gpu(): diff --git a/tensorflow/python/training/saver_test.py b/tensorflow/python/training/saver_test.py index 6b2177b0bb..40b7c0d5a7 100644 --- a/tensorflow/python/training/saver_test.py +++ b/tensorflow/python/training/saver_test.py @@ -170,6 +170,7 @@ class SaverTest(test.TestCase): def testResourceBasic(self): self.basicSaveRestore(resource_variable_ops.ResourceVariable) + @test_util.run_deprecated_v1 def testResourceColocation(self): partitioner = partitioned_variables.fixed_size_partitioner(num_shards=2) with ops_lib.device("/job:ps/device:GPU:0"): @@ -300,6 +301,7 @@ class SaverTest(test.TestCase): not op.name.startswith("saver2/save/"))] self.assertEqual(ops_in_saver2_scope_but_not_save_scope, []) + @test_util.run_deprecated_v1 def testSaveCopyRestoreWithSaveRelativePaths(self): """Save, copy checkpoint dir and restore from copied dir. @@ -369,6 +371,7 @@ class SaverTest(test.TestCase): self.assertEqual(b"k1", v2.keys().eval()) self.assertEqual(30.0, v2.values().eval()) + @test_util.run_deprecated_v1 def testFilenameTensor(self): v0 = variables.VariableV1(0, name="v0") filename = b"somerandomfilename" @@ -387,6 +390,7 @@ class SaverTest(test.TestCase): ValueError, "The passed save_path is not a valid checkpoint:"): save.restore(sess, "invalid path") + @test_util.run_deprecated_v1 def testInt64(self): save_path = os.path.join(self.get_temp_dir(), "int64") @@ -462,6 +466,7 @@ class SaverTest(test.TestCase): # Verify non-duplicate names work. saver_module.Saver({"v0": v0, "v2": v2.saveable}) + @test_util.run_deprecated_v1 def testBasicsWithListOfVariables(self): save_path = os.path.join(self.get_temp_dir(), "basics_with_list") @@ -557,6 +562,7 @@ class SaverTest(test.TestCase): # The cached readers should know to re-read the file. self._SaveAndLoad("var1", 1.1, 2.2, save_path) + @test_util.run_deprecated_v1 def testAllowEmpty(self): save_path = os.path.join(self.get_temp_dir(), "allow_empty") with self.cached_session() as sess: @@ -661,6 +667,7 @@ class SaverTest(test.TestCase): self.assertAllClose(1.0, one.eval()) self.assertAllClose([2.0, 2.0, 2.0], twos.eval()) + @test_util.run_deprecated_v1 def testReshape(self): save_path = os.path.join(self.get_temp_dir(), "variables_reshape") with session.Session("", graph=ops_lib.Graph()) as sess: @@ -719,6 +726,7 @@ class SaverTest(test.TestCase): def testSaveWithGlobalStepWithPadding(self): self.testSaveWithGlobalStep(pad_step_number=True) + @test_util.run_deprecated_v1 def testSaveToNonexistingPath(self): file_io.write_string_to_file( os.path.join(self.get_temp_dir(), "actually_a_file"), "") @@ -761,6 +769,7 @@ class SaverTest(test.TestCase): error_msg_template = "Parent directory of {} doesn't exist, can't save." self.assertEqual(error_msg_template.format(save_path), str(exc)) + @test_util.run_deprecated_v1 def testSaveToURI(self): # ParseURI functions don't work on Windows yet. # TODO(jhseu): Remove this check when it works. @@ -982,6 +991,7 @@ class SaveRestoreShardedTest(test.TestCase): checkpoint_management.latest_checkpoint(self.get_temp_dir()), os.path.join(self.get_temp_dir(), "sharded_basics")) + @test_util.run_deprecated_v1 def testSaverDef(self): with self.cached_session(): v0 = variables.VariableV1(123, name="v0") @@ -1087,9 +1097,11 @@ class SaveRestoreShardedTest(test.TestCase): num_shards=3)) self.assertAllEqual(saved_full, restored_full) + @test_util.run_deprecated_v1 def testPartitionedVariable(self): self._testPartitionedVariables(use_resource=False) + @test_util.run_deprecated_v1 def testPartitionedResourceVariable(self): self._testPartitionedVariables(use_resource=True) @@ -1184,6 +1196,7 @@ class MaxToKeepTest(test.TestCase): # Deleted by the first helper. self.assertFalse(checkpoint_management.checkpoint_exists(s3)) + @test_util.run_deprecated_v1 def testNonSharded(self): save_dir = self._get_test_dir("max_to_keep_non_sharded") @@ -1421,6 +1434,7 @@ class MaxToKeepTest(test.TestCase): self.assertTrue( gfile.Exists(checkpoint_management.meta_graph_filename(s3))) + @test_util.run_deprecated_v1 def testNoMaxToKeep(self): save_dir = self._get_test_dir("no_max_to_keep") save_dir2 = self._get_test_dir("max_to_keep_0") @@ -1449,6 +1463,7 @@ class MaxToKeepTest(test.TestCase): self.assertEqual([], save2.last_checkpoints) self.assertTrue(checkpoint_management.checkpoint_exists(s2)) + @test_util.run_deprecated_v1 def testNoMetaGraph(self): save_dir = self._get_test_dir("no_meta_graph") @@ -1472,6 +1487,7 @@ class KeepCheckpointEveryNHoursTest(test.TestCase): @test_util.run_in_graph_and_eager_modes @test.mock.patch.object(saver_module, "time") + @test_util.run_deprecated_v1 def testNonSharded(self, mock_time): save_dir = self._get_test_dir("keep_checkpoint_every_n_hours") @@ -1591,6 +1607,7 @@ class SaveRestoreWithVariableNameMap(test.TestCase): self.assertEqual(20.0, self.evaluate(v1)) @test_util.run_in_graph_and_eager_modes + @test_util.run_deprecated_v1 def testNonReshapeResourceVariable(self): self._testNonReshape(resource_variable_ops.ResourceVariable) @@ -1605,6 +1622,7 @@ class MetaGraphTest(test.TestCase): gfile.MakeDirs(test_dir) return test_dir + @test_util.run_deprecated_v1 def testAddCollectionDef(self): test_dir = self._get_test_dir("good_collection") filename = os.path.join(test_dir, "metafile") @@ -1754,11 +1772,13 @@ class MetaGraphTest(test.TestCase): v1 = sess.graph.get_tensor_by_name("v1:0") self.assertEqual(11.0, v1.eval()) + @test_util.run_deprecated_v1 def testMultiSaverCollection(self): test_dir = self._get_test_dir("saver_collection") self._testMultiSaverCollectionSave(test_dir) self._testMultiSaverCollectionRestore(test_dir) + @test_util.run_deprecated_v1 def testClearExtraneousSavers(self): test_dir = self._get_test_dir("clear_extraneous_savers") filename = os.path.join(test_dir, "metafile") @@ -1813,6 +1833,7 @@ class MetaGraphTest(test.TestCase): self.assertEqual(33, len(meta_graph_def0.graph_def.node)) self.assertEqual(21, len(meta_graph_def1.graph_def.node)) + @test_util.run_deprecated_v1 def testBinaryAndTextFormat(self): test_dir = self._get_test_dir("binary_and_text") filename = os.path.join(test_dir, "metafile") @@ -1845,6 +1866,7 @@ class MetaGraphTest(test.TestCase): lambda e: "does not exist"): saver_module.import_meta_graph(filename) + @test_util.run_deprecated_v1 def testSliceVariable(self): test_dir = self._get_test_dir("slice_saver") filename = os.path.join(test_dir, "metafile") @@ -1985,6 +2007,7 @@ class MetaGraphTest(test.TestCase): train_op = ops_lib.get_collection("train_op")[0] self.evaluate(train_op) + @test_util.run_deprecated_v1 def testGraphExtension(self): test_dir = self._get_test_dir("graph_extension") self._testGraphExtensionSave(test_dir) @@ -2070,6 +2093,7 @@ class MetaGraphTest(test.TestCase): return i + 1, x + r self._testWhileLoopAndGradientSerDes(body) + @test_util.run_deprecated_v1 def testNestedControlFlowSerDes(self): # Test while loop in a cond in a while loop. # pylint: disable=g-long-lambda @@ -2098,6 +2122,7 @@ class MetaGraphTest(test.TestCase): lambda: math_ops.multiply(x, -1.0)))) # pylint: enable=g-long-lambda + @test_util.run_deprecated_v1 def testStrippedOpListDef(self): with self.cached_session(): # Creates a graph. @@ -2135,6 +2160,7 @@ class MetaGraphTest(test.TestCase): self.assertEqual(o.summary, "") self.assertEqual(o.description, "") + @test_util.run_deprecated_v1 def testStripDefaultValuedAttrs(self): """Verifies that default valued attrs are stripped, unless disabled.""" @@ -2171,6 +2197,7 @@ class MetaGraphTest(test.TestCase): self.assertIn("T", node_def.attr) self.assertIn("Tout", node_def.attr) + @test_util.run_deprecated_v1 def testImportIntoNamescope(self): # Test that we can import a meta graph into a namescope. test_dir = self._get_test_dir("import_into_namescope") @@ -2241,6 +2268,7 @@ class MetaGraphTest(test.TestCase): filename + ".meta", graph=graph_2, import_scope="my_scope") self.assertIsInstance(new_saver_3, saver_module.Saver) + @test_util.run_deprecated_v1 def testImportIntoImplicitNamescope(self): # Test that we can import a meta graph into an implicit namescope. test_dir = self._get_test_dir("import_into_namescope") @@ -2363,6 +2391,7 @@ class CheckpointReaderTest(test.TestCase): _WRITE_VERSION = saver_pb2.SaverDef.V1 + @test_util.run_deprecated_v1 def testDebugString(self): # Builds a graph. v0 = variables.VariableV1( @@ -2594,6 +2623,7 @@ class ScopedGraphTest(test.TestCase): # Verifies that we can save the subgraph under "hidden1" and restore it # into "new_hidden1" in the new graph. + @test_util.run_deprecated_v1 def testScopedSaveAndRestore(self): test_dir = self._get_test_dir("scoped_export_import") ckpt_filename = "ckpt" @@ -2603,6 +2633,7 @@ class ScopedGraphTest(test.TestCase): # Verifies that we can copy the subgraph under "hidden1" and copy it # to different name scope in the same graph or different graph. + @test_util.run_deprecated_v1 def testCopyScopedGraph(self): test_dir = self._get_test_dir("scoped_copy") saver0_ckpt = os.path.join(test_dir, "saver0.ckpt") @@ -2659,6 +2690,7 @@ class ScopedGraphTest(test.TestCase): saver3.restore(sess, saver0_ckpt) self.assertAllClose(expected, sess.run("new_hidden1/relu:0")) + @test_util.run_deprecated_v1 def testExportGraphDefWithScope(self): test_dir = self._get_test_dir("export_graph_def") saver0_ckpt = os.path.join(test_dir, "saver0.ckpt") @@ -2695,6 +2727,7 @@ class ScopedGraphTest(test.TestCase): saver3.restore(sess, saver0_ckpt) self.assertAllClose(expected, sess.run("new_hidden1/relu:0")) + @test_util.run_deprecated_v1 def testSerializeSaverWithScope(self): test_dir = self._get_test_dir("export_graph_def") saver1_ckpt = os.path.join(test_dir, "saver1.ckpt") @@ -2955,6 +2988,7 @@ class CheckpointableCompatibilityTests(test.TestCase): # exception" block in Python 3. self.assertNotIn("NewCheckpointReader", cs.exception.message) + @test_util.run_deprecated_v1 def testGraphChangedForRestoreErrorRaised(self): checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") @@ -2976,6 +3010,7 @@ class CheckpointableCompatibilityTests(test.TestCase): "a mismatch between the current graph and the graph"): a_saver.restore(sess=sess, save_path=save_path) + @test_util.run_deprecated_v1 def testLoadFromObjectBasedGraph(self): checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") diff --git a/tensorflow/python/training/server_lib_multiple_containers_test.py b/tensorflow/python/training/server_lib_multiple_containers_test.py index f599e9b55b..fb6118942b 100644 --- a/tensorflow/python/training/server_lib_multiple_containers_test.py +++ b/tensorflow/python/training/server_lib_multiple_containers_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.client import session from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.training import server_lib @@ -33,6 +34,7 @@ class MultipleContainersTest(test.TestCase): # TODO(b/34465411): Starting multiple servers with different configurations # in the same test is flaky. Move this test case back into # "server_lib_test.py" when this is no longer the case. + @test_util.run_deprecated_v1 def testMultipleContainers(self): with ops.container("test0"): v0 = variables.Variable(1.0, name="v0") diff --git a/tensorflow/python/training/server_lib_same_variables_clear_container_test.py b/tensorflow/python/training/server_lib_same_variables_clear_container_test.py index 3a5eb712c6..e0ab21bbd9 100644 --- a/tensorflow/python/training/server_lib_same_variables_clear_container_test.py +++ b/tensorflow/python/training/server_lib_same_variables_clear_container_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.client import session from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.training import server_lib @@ -32,6 +33,7 @@ class SameVariablesClearContainerTest(test.TestCase): # TODO(b/34465411): Starting multiple servers with different configurations # in the same test is flaky. Move this test case back into # "server_lib_test.py" when this is no longer the case. + @test_util.run_deprecated_v1 def testSameVariablesClearContainer(self): # Starts two servers with different names so they map to different # resource "containers". diff --git a/tensorflow/python/training/server_lib_same_variables_clear_test.py b/tensorflow/python/training/server_lib_same_variables_clear_test.py index 4682f1ab84..7b147af6c5 100644 --- a/tensorflow/python/training/server_lib_same_variables_clear_test.py +++ b/tensorflow/python/training/server_lib_same_variables_clear_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.client import session from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -32,6 +33,7 @@ class SameVariablesClearTest(test.TestCase): # TODO(b/34465411): Starting multiple servers with different configurations # in the same test is flaky. Move this test case back into # "server_lib_test.py" when this is no longer the case. + @test_util.run_deprecated_v1 def testSameVariablesClear(self): server = server_lib.Server.create_local_server() diff --git a/tensorflow/python/training/server_lib_same_variables_no_clear_test.py b/tensorflow/python/training/server_lib_same_variables_no_clear_test.py index 5aa7f45c2b..1b2d588f44 100644 --- a/tensorflow/python/training/server_lib_same_variables_no_clear_test.py +++ b/tensorflow/python/training/server_lib_same_variables_no_clear_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.client import session from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test @@ -33,6 +34,7 @@ class SameVariablesNoClearTest(test.TestCase): # TODO(b/34465411): Starting multiple servers with different configurations # in the same test is flaky. Move this test case back into # "server_lib_test.py" when this is no longer the case. + @test_util.run_deprecated_v1 def testSameVariablesNoClear(self): server = server_lib.Server.create_local_server() diff --git a/tensorflow/python/training/server_lib_sparse_job_test.py b/tensorflow/python/training/server_lib_sparse_job_test.py index 8c2745b51a..93b06e6216 100644 --- a/tensorflow/python/training/server_lib_sparse_job_test.py +++ b/tensorflow/python/training/server_lib_sparse_job_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.client import session from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.training import server_lib @@ -30,6 +31,7 @@ class SparseJobTest(test.TestCase): # TODO(b/34465411): Starting multiple servers with different configurations # in the same test is flaky. Move this test case back into # "server_lib_test.py" when this is no longer the case. + @test_util.run_deprecated_v1 def testSparseJob(self): server = server_lib.Server({"local": {37: "localhost:0"}}) with ops.device("/job:local/task:37"): diff --git a/tensorflow/python/training/session_manager_test.py b/tensorflow/python/training/session_manager_test.py index 2b5c3b01de..4294ffa851 100644 --- a/tensorflow/python/training/session_manager_test.py +++ b/tensorflow/python/training/session_manager_test.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import variables @@ -68,6 +69,7 @@ class SessionManagerTest(test.TestCase): "", init_fn=lambda sess: sess.run(v.initializer)) self.assertAllClose([125], sess.run(v)) + @test_util.run_deprecated_v1 def testPrepareSessionFails(self): checkpoint_dir = os.path.join(self.get_temp_dir(), "prepare_session") checkpoint_dir2 = os.path.join(self.get_temp_dir(), "prepare_session2") @@ -152,6 +154,7 @@ class SessionManagerTest(test.TestCase): sess.graph.get_tensor_by_name("v:0")).eval(session=sess)) self.assertEquals(1, sess.run(v)) + @test_util.run_deprecated_v1 def testRecoverSession(self): # Create a checkpoint. checkpoint_dir = os.path.join(self.get_temp_dir(), "recover_session") @@ -206,6 +209,7 @@ class SessionManagerTest(test.TestCase): variables.global_variables()), local_init_op=None) + @test_util.run_deprecated_v1 def testRecoverSessionWithReadyForLocalInitOp(self): # Create a checkpoint. checkpoint_dir = os.path.join(self.get_temp_dir(), @@ -259,6 +263,7 @@ class SessionManagerTest(test.TestCase): self.assertEquals(1, sess.run(v)) self.assertEquals(1, sess.run(w)) + @test_util.run_deprecated_v1 def testRecoverSessionWithReadyForLocalInitOpFailsToReadyLocal(self): # We use ready_for_local_init_op=tf.report_uninitialized_variables(), # which causes recover_session to not run local_init_op, and to return @@ -315,6 +320,7 @@ class SessionManagerTest(test.TestCase): sess.graph.get_tensor_by_name("w:0")).eval(session=sess)) self.assertEquals(1, sess.run(v)) + @test_util.run_deprecated_v1 def testRecoverSessionNoChkptStillRunsLocalInitOp(self): # This test checks for backwards compatibility. # In particular, we continue to ensure that recover_session will execute @@ -343,6 +349,7 @@ class SessionManagerTest(test.TestCase): sess.graph.get_tensor_by_name("w:0")).eval(session=sess)) self.assertEquals(1, sess.run(w)) + @test_util.run_deprecated_v1 def testRecoverSessionFailsStillRunsLocalInitOp(self): # Create a checkpoint. checkpoint_dir = os.path.join( @@ -386,6 +393,7 @@ class SessionManagerTest(test.TestCase): sess.graph.get_tensor_by_name("w:0")).eval(session=sess)) self.assertEquals(1, sess.run(w)) + @test_util.run_deprecated_v1 def testWaitForSessionLocalInit(self): server = server_lib.Server.create_local_server() with ops.Graph().as_default() as graph: @@ -437,6 +445,7 @@ class SessionManagerTest(test.TestCase): # because of overly restrictive ready_for_local_init_op sm.wait_for_session("", max_wait_secs=3) + @test_util.run_deprecated_v1 def testWaitForSessionInsufficientReadyForLocalInitCheck(self): with ops.Graph().as_default() as graph: v = variables.VariableV1(1, name="v") @@ -454,6 +463,7 @@ class SessionManagerTest(test.TestCase): "Session was not ready after waiting.*"): sm.wait_for_session("", max_wait_secs=3) + @test_util.run_deprecated_v1 def testPrepareSessionWithReadyForLocalInitOp(self): with ops.Graph().as_default(): v = variables.VariableV1(1, name="v") @@ -493,6 +503,7 @@ class SessionManagerTest(test.TestCase): self.assertEquals(1, sess.run(w)) self.assertEquals(3, sess.run(x)) + @test_util.run_deprecated_v1 def testPrepareSessionWithPartialInitOp(self): with ops.Graph().as_default(): v = variables.VariableV1(1, name="v") @@ -559,6 +570,7 @@ class SessionManagerTest(test.TestCase): self.assertEquals(1, sess.run(w_res)) self.assertEquals(3, sess.run(x_res)) + @test_util.run_deprecated_v1 def testPrepareSessionWithCyclicInitializer(self): # Regression test. Previously Variable._build_initializer_expr would enter # into an infinite recursion when the variable's initial_value involved @@ -632,6 +644,7 @@ class SessionManagerTest(test.TestCase): "Init operations did not make model ready for local_init"): sm2.prepare_session("", init_op=None) + @test_util.run_deprecated_v1 def testPrepareSessionWithInsufficientReadyForLocalInitCheck(self): with ops.Graph().as_default(): v = variables.VariableV1(1, name="v") @@ -684,6 +697,7 @@ class ObsoleteSessionManagerTest(test.TestCase): "", init_fn=lambda sess: sess.run(v.initializer)) self.assertAllClose([125], sess.run(v)) + @test_util.run_deprecated_v1 def testPrepareSessionFails(self): checkpoint_dir = os.path.join(self.get_temp_dir(), "prepare_session") checkpoint_dir2 = os.path.join(self.get_temp_dir(), "prepare_session2") @@ -745,6 +759,7 @@ class ObsoleteSessionManagerTest(test.TestCase): variables.is_variable_initialized( sess.graph.get_tensor_by_name("v:0")).eval(session=sess)) + @test_util.run_deprecated_v1 def testRecoverSession(self): # Create a checkpoint. checkpoint_dir = os.path.join(self.get_temp_dir(), "recover_session") diff --git a/tensorflow/python/training/slot_creator_test.py b/tensorflow/python/training/slot_creator_test.py index 382c15bb55..1f26aaa434 100644 --- a/tensorflow/python/training/slot_creator_test.py +++ b/tensorflow/python/training/slot_creator_test.py @@ -21,6 +21,7 @@ from __future__ import print_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import variable_scope @@ -31,6 +32,7 @@ from tensorflow.python.training import slot_creator class SlotCreatorTest(test.TestCase): + @test_util.run_deprecated_v1 def testCreateSlotFromVariable(self): with self.cached_session(): v = variables.Variable([1.0, 2.5], name="var") @@ -43,6 +45,7 @@ class SlotCreatorTest(test.TestCase): self.assertEqual(dtypes.float32, slot.dtype.base_dtype) self.assertAllEqual([1.0, 2.5], self.evaluate(slot)) + @test_util.run_deprecated_v1 def testCreateSlotFromTensor(self): with self.cached_session(): v = constant_op.constant([1.0, 2.5], name="const") @@ -55,6 +58,7 @@ class SlotCreatorTest(test.TestCase): self.assertEqual(dtypes.float32, slot.dtype.base_dtype) self.assertAllEqual([2.0, 5.0], self.evaluate(slot)) + @test_util.run_deprecated_v1 def testCreateZerosSlotFromVariable(self): with self.cached_session(): v = variables.Variable([1.0, 2.5], name="var") @@ -69,6 +73,7 @@ class SlotCreatorTest(test.TestCase): self.assertEqual(dtypes.float64, slot.dtype.base_dtype) self.assertAllEqual([0.0, 0.0], self.evaluate(slot)) + @test_util.run_deprecated_v1 def testCreateZerosSlotFromDynamicShapedVariable(self): with self.cached_session(): dyn_shape = constant_op.constant([2], dtype=dtypes.int32) @@ -90,6 +95,7 @@ class SlotCreatorTest(test.TestCase): self.assertEqual(dtypes.float64, slot.dtype.base_dtype) self.assertAllEqual([0.0, 0.0], self.evaluate(slot)) + @test_util.run_deprecated_v1 def testCreateZerosSlotFromTensor(self): with self.cached_session(): v = constant_op.constant([1.0, 2.5], name="const") @@ -103,6 +109,7 @@ class SlotCreatorTest(test.TestCase): self.assertEqual(dtypes.float32, slot.dtype.base_dtype) self.assertAllEqual([0.0, 0.0], self.evaluate(slot)) + @test_util.run_deprecated_v1 def testCreateZerosSlotFromDynamicShapedTensor(self): with self.cached_session(): v = random_ops.random_uniform([2], dtype=dtypes.float64) @@ -118,6 +125,7 @@ class SlotCreatorTest(test.TestCase): self.assertEqual(dtypes.float64, slot.dtype.base_dtype) self.assertAllEqual([0.0, 0.0], self.evaluate(slot)) + @test_util.run_deprecated_v1 def testCreateSlotFromVariableRespectsScope(self): # See discussion on #2740. with self.cached_session(): diff --git a/tensorflow/python/training/supervisor_test.py b/tensorflow/python/training/supervisor_test.py index 9dc88d78cc..f6505acc9a 100644 --- a/tensorflow/python/training/supervisor_test.py +++ b/tensorflow/python/training/supervisor_test.py @@ -35,6 +35,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import io_ops from tensorflow.python.ops import parsing_ops @@ -420,6 +421,7 @@ class SupervisorTest(test.TestCase): with self.assertRaisesRegexp(RuntimeError, "requires a summary writer"): sv.summary_computed(sess, sess.run(summ)) + @test_util.run_deprecated_v1 def testLogdirButExplicitlyNoSummaryWriter(self): logdir = self._test_dir("explicit_no_summary_writer") with ops.Graph().as_default(): @@ -505,6 +507,7 @@ class SupervisorTest(test.TestCase): sv = supervisor.Supervisor(logdir="", session_manager=sm) sv.prepare_or_wait_for_session("") + @test_util.run_deprecated_v1 def testInitOp(self): logdir = self._test_dir("default_init_op") with ops.Graph().as_default(): @@ -514,6 +517,7 @@ class SupervisorTest(test.TestCase): self.assertAllClose([1.0, 2.0, 3.0], sess.run(v)) sv.stop() + @test_util.run_deprecated_v1 def testInitFn(self): logdir = self._test_dir("default_init_op") with ops.Graph().as_default(): @@ -527,6 +531,7 @@ class SupervisorTest(test.TestCase): self.assertAllClose([1.0, 2.0, 3.0], sess.run(v)) sv.stop() + @test_util.run_deprecated_v1 def testInitOpWithFeedDict(self): logdir = self._test_dir("feed_dict_init_op") with ops.Graph().as_default(): @@ -540,6 +545,7 @@ class SupervisorTest(test.TestCase): self.assertAllClose([1.0, 2.0, 3.0], sess.run(v)) sv.stop() + @test_util.run_deprecated_v1 def testReadyForLocalInitOp(self): server = server_lib.Server.create_local_server() logdir = self._test_dir("default_ready_for_local_init_op") @@ -582,6 +588,7 @@ class SupervisorTest(test.TestCase): sv0.stop() sv1.stop() + @test_util.run_deprecated_v1 def testReadyForLocalInitOpRestoreFromCheckpoint(self): server = server_lib.Server.create_local_server() logdir = self._test_dir("ready_for_local_init_op_restore") @@ -713,6 +720,7 @@ class SupervisorTest(test.TestCase): "Variables not initialized: w"): sv.prepare_or_wait_for_session(server.target) + @test_util.run_deprecated_v1 def testSetupFail(self): logdir = self._test_dir("setup_fail") with ops.Graph().as_default(): @@ -723,6 +731,7 @@ class SupervisorTest(test.TestCase): variables.VariableV1([1.0, 2.0, 3.0], name="v") supervisor.Supervisor(logdir=logdir, is_chief=False) + @test_util.run_deprecated_v1 def testDefaultGlobalStep(self): logdir = self._test_dir("default_global_step") with ops.Graph().as_default(): @@ -732,6 +741,7 @@ class SupervisorTest(test.TestCase): self.assertEquals(287, sess.run(sv.global_step)) sv.stop() + @test_util.run_deprecated_v1 def testRestoreFromMetaGraph(self): logdir = self._test_dir("restore_from_meta_graph") with ops.Graph().as_default(): @@ -753,6 +763,7 @@ class SupervisorTest(test.TestCase): # This test is based on the fact that the standard services start # right away and get to run once before sv.stop() returns. # We still sleep a bit to make the test robust. + @test_util.run_deprecated_v1 def testStandardServicesWithoutGlobalStep(self): logdir = self._test_dir("standard_services_without_global_step") # Create a checkpoint. @@ -803,6 +814,7 @@ class SupervisorTest(test.TestCase): # Same as testStandardServicesNoGlobalStep but with a global step. # We should get a summary about the step time. + @test_util.run_deprecated_v1 def testStandardServicesWithGlobalStep(self): logdir = self._test_dir("standard_services_with_global_step") # Create a checkpoint. diff --git a/tensorflow/python/training/training_ops_test.py b/tensorflow/python/training/training_ops_test.py index 929dd74ac6..51f49ca081 100644 --- a/tensorflow/python/training/training_ops_test.py +++ b/tensorflow/python/training/training_ops_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.framework.test_util import TensorFlowTestCase # Import resource_variable_ops for the variables-to-tensor implicit conversion. from tensorflow.python.ops import resource_variable_ops # pylint: disable=unused-import @@ -59,6 +60,7 @@ class TrainingOpsTest(TensorFlowTestCase): self.assertShapeEqual(out, apply_sgd) self.assertAllCloseAccordingToType(x - alpha * delta, out) + @test_util.run_deprecated_v1 def testApplyGradientDescent(self): for (dtype, use_gpu) in itertools.product( [np.float16, np.float32, np.float64], [False, True]): @@ -127,6 +129,7 @@ class TrainingOpsTest(TensorFlowTestCase): self.assertAllClose(linear_update, self.evaluate(linear)) self.assertAllClose(expected_out, out) + @test_util.run_deprecated_v1 def testApplyAdagrad(self): for (dtype, use_gpu) in itertools.product( [np.float16, np.float32, np.float64], [False, True]): @@ -136,6 +139,7 @@ class TrainingOpsTest(TensorFlowTestCase): grad = np.arange(100).astype(dtype) self._testTypesForAdagrad(x, y, lr, grad, use_gpu) + @test_util.run_deprecated_v1 def testApplyFtrl(self): for dtype in [np.float16, np.float32, np.float64]: x = np.arange(100).astype(dtype) @@ -207,6 +211,7 @@ class TrainingOpsTest(TensorFlowTestCase): self.assertAllCloseAccordingToType(y[index] + grad[i] * grad[i], self.evaluate(accum)[index]) + @test_util.run_deprecated_v1 def testSparseApplyAdagrad(self): for (dtype, index_type) in itertools.product( [np.float16, np.float32, np.float64], [np.int32, np.int64]): @@ -220,6 +225,7 @@ class TrainingOpsTest(TensorFlowTestCase): indices = np.array([0, 2]).astype(index_type) self._testTypesForSparseAdagrad(x, y, lr, grad, indices) + @test_util.run_deprecated_v1 def testSparseApplyAdagradDim1(self): for (dtype, index_type) in itertools.product( [np.float16, np.float32, np.float64], [np.int32, np.int64]): @@ -233,6 +239,7 @@ class TrainingOpsTest(TensorFlowTestCase): indices = np.array([0, 2]).astype(index_type) self._testTypesForSparseAdagrad(x, y, lr, grad, indices) + @test_util.run_deprecated_v1 def testSparseApplyFtrlDim1(self): for (dtype, index_type) in itertools.product( [np.float16, np.float32, np.float64], [np.int32, np.int64]): @@ -248,6 +255,7 @@ class TrainingOpsTest(TensorFlowTestCase): indices = np.array([0, 2]).astype(index_type) self._testTypesForSparseFtrl(x, y, z, lr, grad, indices) + @test_util.run_deprecated_v1 def testApplyAdam(self): for dtype, use_gpu in itertools.product( [np.float16, np.float32, np.float64], [False, True]): diff --git a/tensorflow/python/training/training_util_test.py b/tensorflow/python/training/training_util_test.py index ba64e785ac..3317008fce 100644 --- a/tensorflow/python/training/training_util_test.py +++ b/tensorflow/python/training/training_util_test.py @@ -20,6 +20,7 @@ from __future__ import print_function from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.training import monitored_session @@ -46,6 +47,7 @@ class GlobalStepTest(test.TestCase): self.assertRaisesRegexp(TypeError, 'does not have integer type', training_util.get_global_step, g) + @test_util.run_deprecated_v1 def test_invalid_shape(self): with ops.Graph().as_default() as g: self.assertIsNone(training_util.get_global_step()) @@ -70,6 +72,7 @@ class GlobalStepTest(test.TestCase): training_util.create_global_step, g) self._assert_global_step(training_util.create_global_step(ops.Graph())) + @test_util.run_deprecated_v1 def test_get_global_step(self): with ops.Graph().as_default() as g: self.assertIsNone(training_util.get_global_step()) diff --git a/tensorflow/python/util/deprecation_test.py b/tensorflow/python/util/deprecation_test.py index 34cbca52a1..035c416d79 100644 --- a/tensorflow/python/util/deprecation_test.py +++ b/tensorflow/python/util/deprecation_test.py @@ -19,6 +19,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import deprecation @@ -174,6 +175,7 @@ class DeprecationTest(test.TestCase): set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_with_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -214,6 +216,7 @@ class DeprecationTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_with_one_line_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -239,6 +242,7 @@ class DeprecationTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_no_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -488,6 +492,7 @@ class DeprecatedArgsTest(test.TestCase): deprecation.deprecated_args(date, instructions, "missing")(_fn) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_with_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -535,6 +540,7 @@ class DeprecatedArgsTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_with_one_line_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -565,6 +571,7 @@ class DeprecatedArgsTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_no_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -595,6 +602,7 @@ class DeprecatedArgsTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_varargs(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -615,6 +623,7 @@ class DeprecatedArgsTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_kwargs(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -635,6 +644,7 @@ class DeprecatedArgsTest(test.TestCase): self._assert_subset(set(["after " + date, instructions]), set(args[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_positional_and_named(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -660,6 +670,7 @@ class DeprecatedArgsTest(test.TestCase): set(args2[1:])) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_positional_and_named_with_ok_vals(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -692,6 +703,7 @@ class DeprecatedArgsTest(test.TestCase): self.assertEqual(0, mock_warning.call_count) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_deprecated_args_once(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -708,6 +720,7 @@ class DeprecatedArgsTest(test.TestCase): self.assertEqual(1, mock_warning.call_count) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_deprecated_multiple_args_once_each(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -752,6 +765,7 @@ class DeprecatedArgValuesTest(test.TestCase): deprecation.deprecated_arg_values(date, instructions) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_with_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -804,6 +818,7 @@ class DeprecatedArgValuesTest(test.TestCase): self.assertEqual(2, mock_warning.call_count) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_with_one_line_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." @@ -839,6 +854,7 @@ class DeprecatedArgValuesTest(test.TestCase): self.assertEqual(2, mock_warning.call_count) @test.mock.patch.object(logging, "warning", autospec=True) + @test_util.run_deprecated_v1 def test_static_fn_no_doc(self, mock_warning): date = "2016-07-04" instructions = "This is how you update..." diff --git a/tensorflow/python/util/nest_test.py b/tensorflow/python/util/nest_test.py index 997a3c5c36..d0d0c5f793 100644 --- a/tensorflow/python/util/nest_test.py +++ b/tensorflow/python/util/nest_test.py @@ -482,6 +482,7 @@ class NestTest(parameterized.TestCase, test.TestCase): self.assertEqual(nt.a[1][::-1], rev_nt.a[1]) self.assertEqual(nt.b[::-1], rev_nt.b) + @test_util.run_deprecated_v1 def testMapStructureOverPlaceholders(self): inp_a = (array_ops.placeholder(dtypes.float32, shape=[3, 4]), array_ops.placeholder(dtypes.float32, shape=[3, 7])) diff --git a/tensorflow/python/util/tf_should_use_test.py b/tensorflow/python/util/tf_should_use_test.py index cde67c4e4f..65d848cf2a 100644 --- a/tensorflow/python/util/tf_should_use_test.py +++ b/tensorflow/python/util/tf_should_use_test.py @@ -24,6 +24,7 @@ import gc import sys from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging from tensorflow.python.util import tf_should_use @@ -39,6 +40,7 @@ def reroute_error(): class TfShouldUseTest(test.TestCase): + @test_util.run_deprecated_v1 def testAddShouldUseWarningWhenNotUsed(self): c = constant_op.constant(0, name='blah0') def in_this_function(): @@ -52,6 +54,7 @@ class TfShouldUseTest(test.TestCase): self.assertIn('in_this_function', msg) self.assertFalse(gc.garbage) + @test_util.run_deprecated_v1 def testAddShouldUseFatalWhenNotUsed(self): c = constant_op.constant(0, name='blah0') def in_this_function(): @@ -74,6 +77,7 @@ class TfShouldUseTest(test.TestCase): error.assert_not_called() fatal.assert_not_called() + @test_util.run_deprecated_v1 def testAddShouldUseWarningWhenUsedWithAdd(self): def add(h): _ = h + 1 @@ -81,6 +85,7 @@ class TfShouldUseTest(test.TestCase): gc.collect() self.assertFalse(gc.garbage) + @test_util.run_deprecated_v1 def testAddShouldUseWarningWhenUsedWithGetName(self): def get_name(h): _ = h.name @@ -88,6 +93,7 @@ class TfShouldUseTest(test.TestCase): gc.collect() self.assertFalse(gc.garbage) + @test_util.run_deprecated_v1 def testShouldUseResult(self): @tf_should_use.should_use_result def return_const(value): @@ -101,6 +107,7 @@ class TfShouldUseTest(test.TestCase): gc.collect() self.assertFalse(gc.garbage) + @test_util.run_deprecated_v1 def testShouldUseResultWhenNotReallyUsed(self): @tf_should_use.should_use_result def return_const(value): diff --git a/tensorflow/tools/api/tests/api_compatibility_test.py b/tensorflow/tools/api/tests/api_compatibility_test.py index cba6246fef..e7f23a1174 100644 --- a/tensorflow/tools/api/tests/api_compatibility_test.py +++ b/tensorflow/tools/api/tests/api_compatibility_test.py @@ -39,6 +39,7 @@ from google.protobuf import message from google.protobuf import text_format from tensorflow.python.lib.io import file_io +from tensorflow.python.framework import test_util from tensorflow.python.platform import resource_loader from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging as logging @@ -310,6 +311,7 @@ class ApiCompatibilityTest(test.TestCase): update_goldens=FLAGS.update_goldens, api_version=api_version) + @test_util.run_deprecated_v1 def testAPIBackwardsCompatibility(self): api_version = 1 golden_file_pattern = os.path.join( @@ -328,6 +330,7 @@ class ApiCompatibilityTest(test.TestCase): 'tensorflow.python.util.lazy_loader.LazyLoader' in str(type(tf.contrib))) + @test_util.run_deprecated_v1 def testAPIBackwardsCompatibilityV1(self): api_version = 1 golden_file_pattern = os.path.join( -- GitLab From 70eca712206b644acb2f089dca69b14f68bdac77 Mon Sep 17 00:00:00 2001 From: Ruoxin Sang Date: Thu, 29 Nov 2018 15:33:27 -0800 Subject: [PATCH 590/672] Do not create unnecessary placeholders when cloning the model in DistributionStrategy in predict mode. PiperOrigin-RevId: 223423532 --- .../keras/engine/training_distributed.py | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/tensorflow/python/keras/engine/training_distributed.py b/tensorflow/python/keras/engine/training_distributed.py index d16832318c..49050f0a97 100644 --- a/tensorflow/python/keras/engine/training_distributed.py +++ b/tensorflow/python/keras/engine/training_distributed.py @@ -485,7 +485,17 @@ def experimental_predict_loop(model, iterator, verbose=0, steps=None): ] -def _clone_and_build_model(model, inputs=None, targets=None): +def _custom_compile_for_predict(model): + """Custom compile for TPU predict mode.""" + model.total_loss = None + model._fit_function = None + model._eval_function = None + model.train_function = None + model.test_function = None + model.predict_function = None + + +def _clone_and_build_model(model, inputs=None, targets=None, mode=None): """Clone and build the given keras_model.""" # We need to set the import here since we run into a circular dependency # error. @@ -512,15 +522,18 @@ def _clone_and_build_model(model, inputs=None, targets=None): if isinstance(targets, tuple): targets = nest.flatten(targets) - cloned_model.compile( - optimizer, - model.loss, - metrics=metrics_module.clone_metrics(model._compile_metrics), - loss_weights=model.loss_weights, - sample_weight_mode=model.sample_weight_mode, - weighted_metrics=metrics_module.clone_metrics( - model._compile_weighted_metrics), - target_tensors=targets) + if mode == _Mode.PREDICT: + _custom_compile_for_predict(cloned_model) + else: + cloned_model.compile( + optimizer, + model.loss, + metrics=metrics_module.clone_metrics(model._compile_metrics), + loss_weights=model.loss_weights, + sample_weight_mode=model.sample_weight_mode, + weighted_metrics=metrics_module.clone_metrics( + model._compile_weighted_metrics), + target_tensors=targets) return cloned_model @@ -529,7 +542,7 @@ def clone_model_on_replicas(model, strategy, make_callback_model=False, """Create a cloned model on each replica.""" with strategy.scope(): grouped_model = strategy.extended.call_for_each_replica( - _clone_and_build_model, args=(model, inputs, targets)) + _clone_and_build_model, args=(model, inputs, targets, mode)) if mode is _Mode.TRAIN: model._grouped_model_train = grouped_model elif mode is _Mode.TEST: -- GitLab From b4a07298f812aa15a94f8e498f284f8f780bbd20 Mon Sep 17 00:00:00 2001 From: Yanhui Liang Date: Thu, 29 Nov 2018 15:34:13 -0800 Subject: [PATCH 591/672] Update canned estimator with EstimatorV2 PiperOrigin-RevId: 223423661 --- .../v1/tensorflow.estimator.-baseline-classifier.pbtxt | 1 - .../v1/tensorflow.estimator.-baseline-regressor.pbtxt | 1 - .../golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt | 1 - ...rflow.estimator.-d-n-n-linear-combined-classifier.pbtxt | 1 - ...orflow.estimator.-d-n-n-linear-combined-regressor.pbtxt | 1 - .../golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt | 1 - .../v1/tensorflow.estimator.-linear-classifier.pbtxt | 1 - .../golden/v1/tensorflow.estimator.-linear-regressor.pbtxt | 1 - .../v2/tensorflow.estimator.-baseline-classifier.pbtxt | 5 ----- .../v2/tensorflow.estimator.-baseline-estimator.pbtxt | 7 +------ .../v2/tensorflow.estimator.-baseline-regressor.pbtxt | 5 ----- .../golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt | 5 ----- .../golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt | 7 +------ ...rflow.estimator.-d-n-n-linear-combined-classifier.pbtxt | 5 ----- ...orflow.estimator.-d-n-n-linear-combined-estimator.pbtxt | 7 +------ ...orflow.estimator.-d-n-n-linear-combined-regressor.pbtxt | 5 ----- .../golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt | 5 ----- .../v2/tensorflow.estimator.-linear-classifier.pbtxt | 5 ----- .../golden/v2/tensorflow.estimator.-linear-estimator.pbtxt | 7 +------ .../golden/v2/tensorflow.estimator.-linear-regressor.pbtxt | 5 ----- 20 files changed, 4 insertions(+), 72 deletions(-) diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt index 225742539d..ee3a72bfce 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.BaselineClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt index 5c51767d56..3874b84d5a 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.BaselineRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt index a142ca3290..b54133b294 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt index 85a20828a0..5a1d85a9b1 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNLinearCombinedClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt index e05c7ce0a2..db4780e4c0 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNLinearCombinedRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt index fc3b1d9813..a44e719099 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt index d213551c0b..2c8e82517b 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.LinearClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt index 004dfccb3b..1bdc6124fe 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.LinearRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt index 22cbcf08f1..efe9e74697 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.BaselineClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt index 38b27f735f..382d392f39 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.BaselineEstimator" tf_class { - is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt index a965042b41..a7300bf06b 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.BaselineRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt index f6bd4d2121..a540085aba 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt index 09e0d38192..d1b29d670a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNEstimator" tf_class { - is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt index 60627cc197..f6c3910a9f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNLinearCombinedClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt index e311f96d3d..b78527279c 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNLinearCombinedEstimator" tf_class { - is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt index dc6aca25dd..9133f0d3b2 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNLinearCombinedRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt index 7338abc1d9..a58d733302 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.DNNRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt index 6559c581fb..47de660a38 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.LinearClassifier" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt index 2148374fde..66a127606a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.LinearEstimator" tf_class { - is_instance: "" - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt index e6ea074ff8..5c094fe131 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.estimator.LinearRegressor" tf_class { is_instance: "" - is_instance: "" is_instance: "" is_instance: "" member { @@ -40,10 +39,6 @@ tf_class { name: "export_saved_model" argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } - member_method { - name: "export_savedmodel" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'strip_default_attrs\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'False\'], " - } member_method { name: "get_variable_names" argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" -- GitLab From 57c274383a5edeffc475df5c97b0a9cd994722a3 Mon Sep 17 00:00:00 2001 From: Mingsheng Hong Date: Thu, 29 Nov 2018 15:44:13 -0800 Subject: [PATCH 592/672] Fixed a bug in the AttrBuilder related experimental C APIs, where the string value `attr_name` passed into `TF_AttrBuilderSetType()` could get destroyed before a subsequent call to `TF_AttrBuilderCheckCanRunOnDevice()` on the same `builder`. That is a use-after-free error, since `builder` stores a string_view version of `attr_name`, and uses it in the latter API call. PiperOrigin-RevId: 223425447 --- tensorflow/c/c_api_experimental.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc index 0c593185db..3693cc8599 100644 --- a/tensorflow/c/c_api_experimental.cc +++ b/tensorflow/c/c_api_experimental.cc @@ -8799,6 +8799,10 @@ void TF_MakeInternalErrorStatus(TF_Status* status, const char* errMsg) { // This builder is used in the eager API to build a NodeDef. struct TF_AttrBuilder : public tensorflow::AttrBuilder { using tensorflow::AttrBuilder::AttrBuilder; + // The string buffers to make sure that any `attr_name` we pass into + // `builder->Set()` will outlive the subsequent + // `TF_AttrBuilderCheckCanRunOnDevice()` call(s) on the same `builder`. + std::set attr_names; }; TF_AttrBuilder* TF_NewAttrBuilder(const char* op_name) { @@ -8809,13 +8813,15 @@ void TF_DeleteAttrBuilder(TF_AttrBuilder* builder) { delete builder; } void TF_AttrBuilderSetType(TF_AttrBuilder* builder, const char* attr_name, TF_DataType value) { - builder->Set(attr_name, static_cast(value)); + auto iter = builder->attr_names.insert(attr_name).first; + builder->Set((*iter).c_str(), static_cast(value)); } void TF_AttrBuilderSetTypeList(TF_AttrBuilder* builder, const char* attr_name, const TF_DataType* values, int num_values) { + auto iter = builder->attr_names.insert(attr_name).first; builder->Set( - attr_name, + (*iter).c_str(), tensorflow::gtl::ArraySlice( reinterpret_cast(values), num_values)); } -- GitLab From 5261e4dc3fed1ba6b209f203335767cf50797b42 Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 29 Nov 2018 16:10:20 -0800 Subject: [PATCH 593/672] Add testNestOutputs to tf.function PiperOrigin-RevId: 223429927 --- tensorflow/python/eager/function_test.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tensorflow/python/eager/function_test.py b/tensorflow/python/eager/function_test.py index e47c5083a3..d2cd407d80 100644 --- a/tensorflow/python/eager/function_test.py +++ b/tensorflow/python/eager/function_test.py @@ -147,6 +147,24 @@ class FunctionTest(test.TestCase, parameterized.TestCase): out = a_times_b(pair({'a': t}, {'b': t})) self.assertAllEqual(out, math_ops.matmul(t, t).numpy()) + def testNestedOutputsGraphMode(self): + matmul = def_function.function(math_ops.matmul) + + pair = collections.namedtuple('pair', ['a', 'b']) + + # TODO(b/120222989) remove autograph=False. + @def_function.function(autograph=False) + def pairs_mul(pair_a, pair_b): + return pair(matmul(pair_a.a, pair_b.a), matmul(pair_a.b, pair_b.b)) + + a = constant_op.constant([[1.0, 2.0], [1.0, 2.0]]) + b = constant_op.constant([[3.0, 4.0], [3.0, 4.0]]) + + out = pairs_mul(pair(a, b), pair(b, a)) + expected = pair(math_ops.matmul(a, b).numpy(), + math_ops.matmul(b, a).numpy()) + self.assertAllClose(out, expected) + def testGraphEagerIsolation(self): @function.defun -- GitLab From 0b87511ae234d3d54f06c7b12e8fcfa7361ecb48 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Thu, 29 Nov 2018 16:15:20 -0800 Subject: [PATCH 594/672] Add publicly available corpus and dictionary for decode_wav_fuzz. PiperOrigin-RevId: 223430684 --- tensorflow/core/kernels/fuzzing/BUILD | 4 ++++ .../02cc44cdfec1d9d0d0c66c5a5f40d3d20e4c4c3a | Bin 0 -> 11564 bytes .../087e1d7fae1c1ddcbaa3b5f822a171ad15498186 | Bin 0 -> 146 bytes .../0f61c33027394a0f14d29dcd22f405cad943b7cf | Bin 0 -> 29936 bytes .../10cdebea1659c21a0248f88654ae41f62786abf1 | Bin 0 -> 58657 bytes .../126e68def9fd973a100e0f66cadf09448a716b57 | Bin 0 -> 9209 bytes .../1275d41ebf8788ce3a949352e4bc654b04012da3 | Bin 0 -> 70 bytes .../1a7f1c407fb3864ddb559f88f373a21d1be51584 | Bin 0 -> 35640 bytes .../1c3e1c91f187f6bcea86f172ff5bbbd955a9654d | Bin 0 -> 57 bytes .../300fe1e0a47543037cbf0243b6756c9aa48799c4 | Bin 0 -> 72238 bytes .../31ec5b0134bedcfe283f4978e6e65b7d35d5d4ad | Bin 0 -> 26123 bytes .../4e7cbb27667bcfca92838aa8020749990013a9b1 | Bin 0 -> 66423 bytes .../585e469231d202812bfba8285fb30c8e31c857b9 | Bin 0 -> 70833 bytes .../58eab6bc2386e2ef43fe4f55cb6ad3611399d5de | Bin 0 -> 22 bytes .../63448c6a9feb8c72b3e82af4d735ec2e62ddd328 | Bin 0 -> 58203 bytes .../6874d5b1c7a64b596c61f24877d422e89bebe58b | Bin 0 -> 25086 bytes .../7501f79cb067da108020579ed654349c7933d22f | Bin 0 -> 54715 bytes .../782051f8120182b860c7fe1b265179cfa2fe03fd | Bin 0 -> 66439 bytes .../793feab2deb35e284a975f6527d76a8be5540fe6 | Bin 0 -> 61 bytes .../7f41ec3a9805c6b8f3656c4f9f6d0ff7dbf8a329 | Bin 0 -> 6150 bytes .../8210dc595a2652f2f812093b01e239e7918ea065 | Bin 0 -> 55329 bytes .../8dffe4c5c26d891b578fd2ea4b9adfc0c96ad5f7 | Bin 0 -> 71409 bytes .../91d787a9298ddc015efa783a92c4bdba8af0d7de | Bin 0 -> 44 bytes .../92c065286f956f086e977556358f6b54b12bcacc | Bin 0 -> 315 bytes .../a35c9bb71792b60a13dea23a41b41847ad4b93d6 | Bin 0 -> 44 bytes .../a6ea960c7b4d42772888280277b26e645ceee904 | Bin 0 -> 22470 bytes .../aa526aa853333f0bb11804b5243df411452cecd2 | Bin 0 -> 21331 bytes .../ca533cd26c7ca6bf69e62351b265ded496fdf1d9 | Bin 0 -> 52741 bytes .../f38c61da15f2cb7a39ff02e69f0b00e99f37ec86 | Bin 0 -> 66555 bytes .../f88f1012473e6cfcc9b39b2552f682b2f73eff8c | Bin 0 -> 54757 bytes .../fa79819c5de04bc06c69bec3fa7f2e982826ea2f | Bin 0 -> 20280 bytes .../fce08de222896ac3a20657a3b4f42d5b6c54a96a | Bin 0 -> 69522 bytes .../fuzzing/dictionaries/decode_wav.dict | 4 ++++ 33 files changed, 8 insertions(+) create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/02cc44cdfec1d9d0d0c66c5a5f40d3d20e4c4c3a create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/087e1d7fae1c1ddcbaa3b5f822a171ad15498186 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/0f61c33027394a0f14d29dcd22f405cad943b7cf create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/10cdebea1659c21a0248f88654ae41f62786abf1 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/126e68def9fd973a100e0f66cadf09448a716b57 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/1275d41ebf8788ce3a949352e4bc654b04012da3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/1a7f1c407fb3864ddb559f88f373a21d1be51584 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/1c3e1c91f187f6bcea86f172ff5bbbd955a9654d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/300fe1e0a47543037cbf0243b6756c9aa48799c4 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/31ec5b0134bedcfe283f4978e6e65b7d35d5d4ad create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/4e7cbb27667bcfca92838aa8020749990013a9b1 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/585e469231d202812bfba8285fb30c8e31c857b9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/58eab6bc2386e2ef43fe4f55cb6ad3611399d5de create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/63448c6a9feb8c72b3e82af4d735ec2e62ddd328 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/6874d5b1c7a64b596c61f24877d422e89bebe58b create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/7501f79cb067da108020579ed654349c7933d22f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/782051f8120182b860c7fe1b265179cfa2fe03fd create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/793feab2deb35e284a975f6527d76a8be5540fe6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/7f41ec3a9805c6b8f3656c4f9f6d0ff7dbf8a329 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/8210dc595a2652f2f812093b01e239e7918ea065 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/8dffe4c5c26d891b578fd2ea4b9adfc0c96ad5f7 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/91d787a9298ddc015efa783a92c4bdba8af0d7de create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/92c065286f956f086e977556358f6b54b12bcacc create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/a35c9bb71792b60a13dea23a41b41847ad4b93d6 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/a6ea960c7b4d42772888280277b26e645ceee904 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/aa526aa853333f0bb11804b5243df411452cecd2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/ca533cd26c7ca6bf69e62351b265ded496fdf1d9 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/f38c61da15f2cb7a39ff02e69f0b00e99f37ec86 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/f88f1012473e6cfcc9b39b2552f682b2f73eff8c create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/fa79819c5de04bc06c69bec3fa7f2e982826ea2f create mode 100644 tensorflow/core/kernels/fuzzing/corpus/decode_wav/fce08de222896ac3a20657a3b4f42d5b6c54a96a create mode 100644 tensorflow/core/kernels/fuzzing/dictionaries/decode_wav.dict diff --git a/tensorflow/core/kernels/fuzzing/BUILD b/tensorflow/core/kernels/fuzzing/BUILD index bb92057bb6..72088e0de2 100644 --- a/tensorflow/core/kernels/fuzzing/BUILD +++ b/tensorflow/core/kernels/fuzzing/BUILD @@ -53,6 +53,10 @@ tf_oss_fuzz_dict("decode_png") tf_ops_fuzz_target_lib("decode_wav") +tf_oss_fuzz_corpus("decode_wav") + +tf_oss_fuzz_dict("decode_wav") + tf_ops_fuzz_target_lib("example_proto_fast_parsing") tf_ops_fuzz_target_lib("parse_tensor_op") diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/02cc44cdfec1d9d0d0c66c5a5f40d3d20e4c4c3a b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/02cc44cdfec1d9d0d0c66c5a5f40d3d20e4c4c3a new file mode 100644 index 0000000000000000000000000000000000000000..2a65e0e2559eea919bdbb661370c679fdbdd7e26 GIT binary patch literal 11564 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/0f61c33027394a0f14d29dcd22f405cad943b7cf b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/0f61c33027394a0f14d29dcd22f405cad943b7cf new file mode 100644 index 0000000000000000000000000000000000000000..8cda165c8c791847ddaffdecd62f503c42a2895f GIT binary patch literal 29936 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/10cdebea1659c21a0248f88654ae41f62786abf1 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/10cdebea1659c21a0248f88654ae41f62786abf1 new file mode 100644 index 0000000000000000000000000000000000000000..4afe44dd91c3038dfa26d06730b2213c1d98dc50 GIT binary patch literal 58657 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/126e68def9fd973a100e0f66cadf09448a716b57 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/126e68def9fd973a100e0f66cadf09448a716b57 new file mode 100644 index 0000000000000000000000000000000000000000..9b2d29856d1483ced1b8ea3cf55f53182947451f GIT binary patch literal 9209 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 b->m)?{4e_L{F8eQSJ3Mpu0Pg%=QnvK>-x{8 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 R=+gSpBNRrDP{2Gw0RZrq*DC-3 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/1c3e1c91f187f6bcea86f172ff5bbbd955a9654d b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/1c3e1c91f187f6bcea86f172ff5bbbd955a9654d new file mode 100644 index 0000000000000000000000000000000000000000..611b38b71d541c68be9e6397dc4366c75a951532 GIT binary patch literal 57 zcmWIYbaQJ+V`K<-40BD(Em06)U|?WmU}SJv!@$rH!N|bG01{z<0gw;_14tAADvt+| literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/300fe1e0a47543037cbf0243b6756c9aa48799c4 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/300fe1e0a47543037cbf0243b6756c9aa48799c4 new file mode 100644 index 0000000000000000000000000000000000000000..fcf8360b277d0f051e111ce38d6fd4e33a2c17e1 GIT binary patch literal 72238 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
p|CUUfqAK?1t+tjXQexoFAw@s(GyY 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 Z|9tcF@Xt>_SN+oZ4Otty=hvH`O#nK_LPY=o literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/4e7cbb27667bcfca92838aa8020749990013a9b1 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/4e7cbb27667bcfca92838aa8020749990013a9b1 new file mode 100644 index 0000000000000000000000000000000000000000..898584d96f6bfcd76ebed9dcde3b7df88442af78 GIT binary patch literal 66423 zcmWIYbaQJ+V`K<-40BD(Em06)U|?WmU}SJv!@$rH!N|bG01{z<0&gh&4@$$Rp#T5> z!`P$rXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1J zhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kin zXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeD zjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2By2#kinpbY`G zLF=+nhmD57Xb6mkz-S1N83K-E>KoNI8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71* zAut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqaiRF0;3@? z8UmvsFd71*Aut*OqaiRF0;3^7-w^mu381f2M{OGofzc2c4S~@R7!85Z5Eu=C(GVC7 zfzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c z4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7_=eKFlb#i>afue7!85Z5Eu=C(GVC7fzc2c z4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C z(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7{nnkx)65|N6x6zMnhmU1V%$( yGz3ONU^E0qLtr!nMnhmU1V%$(Gz3OY2>cy6ULE!6Xb6mg(GVC7fzc2kHv|Buph`Ue literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/585e469231d202812bfba8285fb30c8e31c857b9 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/585e469231d202812bfba8285fb30c8e31c857b9 new file mode 100644 index 0000000000000000000000000000000000000000..a4994c208300b6cba20708367337667fbbd8dabc GIT binary patch literal 70833 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 a^1bW(=WkKp9KW@FJN=E}yZQIV?~4Iw^;b^- literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/6874d5b1c7a64b596c61f24877d422e89bebe58b b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/6874d5b1c7a64b596c61f24877d422e89bebe58b new file mode 100644 index 0000000000000000000000000000000000000000..e054ad5f14723fa1bd5829725e38de4a681cb3e8 GIT binary patch literal 25086 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 y{p6Aw_lRRg8j`jT93%@Qt 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/782051f8120182b860c7fe1b265179cfa2fe03fd b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/782051f8120182b860c7fe1b265179cfa2fe03fd new file mode 100644 index 0000000000000000000000000000000000000000..a0d8a6ec48c983fc3870d173c5b4c73eb474eecd GIT binary patch literal 66439 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/8210dc595a2652f2f812093b01e239e7918ea065 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/8210dc595a2652f2f812093b01e239e7918ea065 new file mode 100644 index 0000000000000000000000000000000000000000..46316baf29ff126da46159bf6c16fb11eb9cb23e GIT binary patch literal 55329 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/92c065286f956f086e977556358f6b54b12bcacc b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/92c065286f956f086e977556358f6b54b12bcacc new file mode 100644 index 0000000000000000000000000000000000000000..77b8f518b4c46b2cef89bd7a12f23ea49c8505ab GIT binary patch literal 315 zcmWIYbaQJ+V`K<-40BD(Em06)U|?WmU|@7v!@$rH!N|bGAi$84Sdti%#>nvK>-x_I z->m)?{4e^=_jBtX4Q40y*Bqvt(d;>Fh3t%M-cp)OEX;u%6S(Ja1#z9{>E>(X!)`t! z11|GTG0cAgHD8KNli8bzkpezysmri*M&?Dd?Bcy{mw@XqCC;Cm_X I_Q|U-0IQK?#{d8T literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/a35c9bb71792b60a13dea23a41b41847ad4b93d6 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/a35c9bb71792b60a13dea23a41b41847ad4b93d6 new file mode 100644 index 0000000000000000000000000000000000000000..45d6b6fa606fe4a25d00476bd4ff785bb80fbba4 GIT binary patch literal 44 xcmWIYbaQJ+V`K<-40BD(Em06)U|?WmU}SJv!@$tt&B(ySAi$842vQZ~2>{n92^atX literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/a6ea960c7b4d42772888280277b26e645ceee904 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/a6ea960c7b4d42772888280277b26e645ceee904 new file mode 100644 index 0000000000000000000000000000000000000000..14954c595882e6d35c5f77f36dfcb9ad315c606c GIT binary patch literal 22470 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≫`yR2!n1|AgzgJ8^LO(d=MCUp!;{NBmun{1O-@;k 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�`dIeu@6Q!K)xX{NxZ<7Ro2-{L&mTRvfBE&r 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

2u?j5^`Y2=~c!F;R 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/f38c61da15f2cb7a39ff02e69f0b00e99f37ec86 b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/f38c61da15f2cb7a39ff02e69f0b00e99f37ec86 new file mode 100644 index 0000000000000000000000000000000000000000..0900eb1352b10576bebda11b0e2b943d77877d57 GIT binary patch literal 66555 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

p|CUUfqAK?1t+tjXQexoFAw@s(GyY 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 rum@O>EoE$4hU literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/fa79819c5de04bc06c69bec3fa7f2e982826ea2f b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/fa79819c5de04bc06c69bec3fa7f2e982826ea2f new file mode 100644 index 0000000000000000000000000000000000000000..2fd41a34fe5b503756e93b68aaa4f90301a78950 GIT binary patch literal 20280 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 literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/decode_wav/fce08de222896ac3a20657a3b4f42d5b6c54a96a b/tensorflow/core/kernels/fuzzing/corpus/decode_wav/fce08de222896ac3a20657a3b4f42d5b6c54a96a new file mode 100644 index 0000000000000000000000000000000000000000..35a99bc97d93c9beeea6a917453685fabf853ab2 GIT binary patch literal 69522 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 K7!3h>hX4Te88qSm literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/dictionaries/decode_wav.dict b/tensorflow/core/kernels/fuzzing/dictionaries/decode_wav.dict new file mode 100644 index 0000000000..eab65386ce --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/dictionaries/decode_wav.dict @@ -0,0 +1,4 @@ +header_RIFF="RIFF" +header_WAVE="WAVE" +section_fmt="fmt " +section_data="data" -- GitLab From 26592d4bb9d9e0ca4262c04fb9497e1583981114 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 16:16:11 -0800 Subject: [PATCH 595/672] disable a failing test in oss env. PiperOrigin-RevId: 223430806 --- tensorflow/python/keras/BUILD | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index 48cdbf1e66..a573fd5cfb 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -754,7 +754,10 @@ py_test( size = "enormous", srcs = ["engine/training_generator_test.py"], srcs_version = "PY2AND3", - tags = ["notsan"], + tags = [ + "no_oss", + "notsan", + ], deps = [ ":keras", "//tensorflow/python:client_testlib", -- GitLab From 0ec0dbe21a74956ec3a31d775e7679b9e8d2d03e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 16:16:17 -0800 Subject: [PATCH 596/672] Improving error reporting in LogDump. PiperOrigin-RevId: 223430822 --- tensorflow/lite/toco/tooling_util.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tensorflow/lite/toco/tooling_util.cc b/tensorflow/lite/toco/tooling_util.cc index 44fa658f9c..d0cc799424 100644 --- a/tensorflow/lite/toco/tooling_util.cc +++ b/tensorflow/lite/toco/tooling_util.cc @@ -536,12 +536,12 @@ void DumpGraphvizVideoFrame(const Model& model) { if (!dump_hashes.count(hash)) { LOG(INFO) << "DUMPING GRAPHVIZ VIDEO FRAME: " << dump_id; dump_hashes.insert(hash); - CHECK(port::file::SetContents( - port::file::JoinPath( - dump_options.dump_graphviz, - toco::port::StringF("toco_video_%05d.dot", dump_id)), - graphviz_dump, port::file::Defaults()) - .ok()); + const auto result = port::file::SetContents( + port::file::JoinPath( + dump_options.dump_graphviz, + toco::port::StringF("toco_video_%05d.dot", dump_id)), + graphviz_dump, port::file::Defaults()); + QCHECK(result.ok()) << result.error_message(); dump_id++; } } @@ -555,14 +555,13 @@ void LogDump(int log_level, const string& message, const Model& model) { string graphviz_dump; DumpGraphviz(model, &graphviz_dump); - CHECK(port::file::SetContents( - port::file::JoinPath( - dump_options.dump_graphviz, - absl::StrCat("toco_", - absl::StrReplaceAll(message, {{" ", "_"}}), - ".dot")), - graphviz_dump, port::file::Defaults()) - .ok()); + const auto result = port::file::SetContents( + port::file::JoinPath( + dump_options.dump_graphviz, + absl::StrCat("toco_", absl::StrReplaceAll(message, {{" ", "_"}}), + ".dot")), + graphviz_dump, port::file::Defaults()); + QCHECK(result.ok()) << result.error_message(); } if (!VLOG_IS_ON(log_level)) { -- GitLab From 4ce74c4b95d31bf28301a3b7b3c65a43266d1954 Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Thu, 29 Nov 2018 16:18:27 -0800 Subject: [PATCH 597/672] Internal change. PiperOrigin-RevId: 223431155 --- tensorflow/contrib/distribute/python/BUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/tensorflow/contrib/distribute/python/BUILD b/tensorflow/contrib/distribute/python/BUILD index 38ce0b2b8e..249258def3 100644 --- a/tensorflow/contrib/distribute/python/BUILD +++ b/tensorflow/contrib/distribute/python/BUILD @@ -436,7 +436,6 @@ cuda_py_test( cuda_py_test( name = "estimator_training_test", - size = "large", srcs = ["estimator_training_test.py"], additional_deps = [ ":collective_all_reduce_strategy", -- GitLab From 895ce1cdb897c00d671a93a2263faa31b7ff7006 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 16:28:24 -0800 Subject: [PATCH 598/672] Fix build PiperOrigin-RevId: 223432621 --- tensorflow/lite/interpreter_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/lite/interpreter_test.cc b/tensorflow/lite/interpreter_test.cc index 2e0dc77dcd..09b8832b4d 100644 --- a/tensorflow/lite/interpreter_test.cc +++ b/tensorflow/lite/interpreter_test.cc @@ -1099,8 +1099,8 @@ class TestDelegate : public ::testing::Test { }; delegate_.CopyFromBufferHandle = [](TfLiteContext* context, TfLiteDelegate* delegate, - TfLiteBufferHandle buffer_handle, void* data, - size_t size) -> TfLiteStatus { + TfLiteBufferHandle buffer_handle, + TfLiteTensor* output) -> TfLiteStatus { // TODO(ycling): Implement tests to test buffer copying logic. return kTfLiteOk; }; -- GitLab From 96e9c4e6844254876a3e258ca79ec046c45d7b02 Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Thu, 29 Nov 2018 16:39:54 -0800 Subject: [PATCH 599/672] Update error messages in tflite_convert. PiperOrigin-RevId: 223434427 --- tensorflow/lite/python/convert_saved_model.py | 13 +++++++++++-- .../lite/python/convert_saved_model_test.py | 16 +++++++++++++++- tensorflow/lite/python/lite.py | 11 ++++++----- tensorflow/lite/python/lite_test.py | 17 +++++++++++++++-- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/tensorflow/lite/python/convert_saved_model.py b/tensorflow/lite/python/convert_saved_model.py index ad7c87109c..f8d986b746 100644 --- a/tensorflow/lite/python/convert_saved_model.py +++ b/tensorflow/lite/python/convert_saved_model.py @@ -199,7 +199,9 @@ def set_tensor_shapes(tensors, shapes): integers representing input shapes (e.g., {"foo": : [1, 16, 16, 3]}). Raises: - ValueError: `shapes` contains an invalid tensor. + ValueError: + `shapes` contains an invalid tensor. + `shapes` contains an invalid shape for a valid tensor. """ if shapes: tensor_names_to_tensor = {tensor_name(tensor): tensor for tensor in tensors} @@ -208,7 +210,14 @@ def set_tensor_shapes(tensors, shapes): raise ValueError("Invalid tensor \'{}\' found in tensor shapes " "map.".format(name)) if shape is not None: - tensor_names_to_tensor[name].set_shape(shape) + tensor = tensor_names_to_tensor[name] + try: + tensor.set_shape(shape) + except ValueError as error: + message = ("The shape of tensor '{0}' cannot be changed from {1} to " + "{2}. {3}".format(name, tensor.get_shape(), shape, + str(error))) + raise ValueError(message) def freeze_saved_model(saved_model_dir, input_arrays, input_shapes, diff --git a/tensorflow/lite/python/convert_saved_model_test.py b/tensorflow/lite/python/convert_saved_model_test.py index 0d32c34391..76113853ca 100644 --- a/tensorflow/lite/python/convert_saved_model_test.py +++ b/tensorflow/lite/python/convert_saved_model_test.py @@ -75,7 +75,8 @@ class TensorFunctionsTest(test_util.TensorFlowTestCase): convert_saved_model.set_tensor_shapes([tensor], {"Placeholder": [1, 3, 5]}) self.assertEqual([1, 3, 5], tensor.shape.as_list()) - def testSetTensorShapeInvalid(self): + def testSetTensorShapeArrayInvalid(self): + # Tests set_tensor_shape where the tensor name passed in doesn't exist. tensor = array_ops.placeholder(shape=[None, 3, 5], dtype=dtypes.float32) self.assertEqual([None, 3, 5], tensor.shape.as_list()) @@ -87,6 +88,19 @@ class TensorFunctionsTest(test_util.TensorFlowTestCase): str(error.exception)) self.assertEqual([None, 3, 5], tensor.shape.as_list()) + def testSetTensorShapeDimensionInvalid(self): + # Tests set_tensor_shape where the shape passed in is incompatiable. + tensor = array_ops.placeholder(shape=[None, 3, 5], dtype=dtypes.float32) + self.assertEqual([None, 3, 5], tensor.shape.as_list()) + + with self.assertRaises(ValueError) as error: + convert_saved_model.set_tensor_shapes([tensor], + {"Placeholder": [1, 5, 5]}) + self.assertIn( + "The shape of tensor 'Placeholder' cannot be changed from " + "(?, 3, 5) to [1, 5, 5].", str(error.exception)) + self.assertEqual([None, 3, 5], tensor.shape.as_list()) + def testSetTensorShapeEmpty(self): tensor = array_ops.placeholder(shape=[None, 3, 5], dtype=dtypes.float32) self.assertEqual([None, 3, 5], tensor.shape.as_list()) diff --git a/tensorflow/lite/python/lite.py b/tensorflow/lite/python/lite.py index 1fb5618466..1b20ff2f92 100644 --- a/tensorflow/lite/python/lite.py +++ b/tensorflow/lite/python/lite.py @@ -400,15 +400,16 @@ class TFLiteConverter(object): # Checks dimensions in input tensor. if self._has_valid_tensors(): for tensor in self._input_tensors: - if not tensor.get_shape(): + shape = tensor.get_shape() + if not shape or not shape.as_list(): raise ValueError("Provide an input shape for input array " "'{0}'.".format(_tensor_name(tensor))) - shape = tensor.get_shape().as_list() - if None in shape[1:]: + shape_list = shape.as_list() + if None in shape_list[1:]: raise ValueError( "None is only supported in the 1st dimension. Tensor '{0}' has " - "invalid shape '{1}'.".format(_tensor_name(tensor), shape)) - elif shape[0] is None: + "invalid shape '{1}'.".format(_tensor_name(tensor), shape_list)) + elif shape_list[0] is None: self._set_batch_size(batch_size=1) # Get quantization stats. Ensures there is one stat per name if the stats diff --git a/tensorflow/lite/python/lite_test.py b/tensorflow/lite/python/lite_test.py index 8832247f3c..1ae0d3c3ed 100644 --- a/tensorflow/lite/python/lite_test.py +++ b/tensorflow/lite/python/lite_test.py @@ -182,7 +182,20 @@ class FromSessionTest(test_util.TensorFlowTestCase): out_tensor = in_tensor + in_tensor sess = session.Session() - # Test invalid shape. None after 1st dimension. + # Test None as shape. + converter = lite.TFLiteConverter.from_session(sess, [in_tensor], + [out_tensor]) + with self.assertRaises(ValueError) as error: + converter.convert() + self.assertEqual('Provide an input shape for input array \'Placeholder\'.', + str(error.exception)) + + def testSizeEmptyInvalid(self): + in_tensor = array_ops.placeholder(dtype=dtypes.float32, shape=[]) + out_tensor = in_tensor + in_tensor + sess = session.Session() + + # Test empty shape. converter = lite.TFLiteConverter.from_session(sess, [in_tensor], [out_tensor]) with self.assertRaises(ValueError) as error: @@ -190,7 +203,7 @@ class FromSessionTest(test_util.TensorFlowTestCase): self.assertEqual('Provide an input shape for input array \'Placeholder\'.', str(error.exception)) - def testBatchSizeInvalid(self): + def testSizeInvalid(self): in_tensor = array_ops.placeholder( shape=[1, None, 16, 3], dtype=dtypes.float32) out_tensor = in_tensor + in_tensor -- GitLab From a196998315720712bd650531aa8273bbc910b991 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 17:12:21 -0800 Subject: [PATCH 600/672] * Create Fingerprint() method for HloModule, HloInstruction, and HloComputation for hashing to accelerate checking identical HLO modules. * Make HloRunner's CreateExecutable method public so that an HLO graph can be compiled without running. Make HloRunner's ExecuteWithDeviceBuffers method accept an executable that has already been compiled. These two changes enable parallelizing compilation of multiple configs of each HLO op. PiperOrigin-RevId: 223439459 --- .../compiler/xla/service/hlo_computation.cc | 2 ++ .../compiler/xla/service/hlo_computation.h | 6 ++++ .../compiler/xla/service/hlo_instruction.cc | 20 +++++++++++ .../compiler/xla/service/hlo_instruction.h | 12 ++++++- .../compiler/xla/service/hlo_instructions.cc | 4 +++ .../compiler/xla/service/hlo_instructions.h | 2 ++ tensorflow/compiler/xla/service/hlo_module.h | 6 ++++ tensorflow/compiler/xla/service/hlo_runner.cc | 34 +++++++++++++++++++ tensorflow/compiler/xla/service/hlo_runner.h | 20 ++++++++--- 9 files changed, 100 insertions(+), 6 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_computation.cc b/tensorflow/compiler/xla/service/hlo_computation.cc index d06c2207cb..ff122b529b 100644 --- a/tensorflow/compiler/xla/service/hlo_computation.cc +++ b/tensorflow/compiler/xla/service/hlo_computation.cc @@ -711,6 +711,8 @@ bool HloComputation::operator==(const HloComputation& other) const { return eq(root_instruction(), other.root_instruction()); } +uint64 HloComputation::Hash() const { return root_instruction()->Hash(); } + Status HloComputation::ReplaceWithNewInstruction( HloInstruction* old_instruction, std::unique_ptr new_instruction) { diff --git a/tensorflow/compiler/xla/service/hlo_computation.h b/tensorflow/compiler/xla/service/hlo_computation.h index be1ce33696..c584e4c7ca 100644 --- a/tensorflow/compiler/xla/service/hlo_computation.h +++ b/tensorflow/compiler/xla/service/hlo_computation.h @@ -264,6 +264,12 @@ class HloComputation { // Return whether `*this` and `other` are functionally equivalent. bool operator==(const HloComputation& other) const; + // Generates a hash value of an HLO computation. Hash considers + // information on opcode, shape, operands, and typically a root instruction. + // This function returns the same hash value for equivalent HLO computations, + // with respect to HloInstruction::Identical() method. + uint64 Hash() const; + // Replaces old instruction with newly created instruction. Removes old // instruction from computation. Updates uses and root instruction. Status ReplaceWithNewInstruction( diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index 36a7a5029b..21b1dbc167 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -1760,6 +1760,26 @@ bool HloInstruction::IdenticalSlowPath( return false; } +uint64 HloInstruction::Hash() const { + using tensorflow::Hash64Combine; + + uint64 hash_value = Hash64Combine(0, static_cast(opcode())); + hash_value = Hash64Combine(hash_value, ShapeUtil::Hash(shape())); + + if (!IsCrossModuleAllReduce()) { + if (!operands().empty()) { + for (size_t i = 0; i < operands().size(); ++i) { + hash_value = Hash64Combine(hash_value, operand(i)->Hash()); + } + } + } + + hash_value = Hash64Combine(hash_value, InnerHash()); + return hash_value; +} + +uint64 HloInstruction::InnerHash() const { return 13; } + void HloInstruction::RemoveUser(HloInstruction* user) { auto set_it = user_set_.find(user); CHECK(set_it != user_set_.end()); diff --git a/tensorflow/compiler/xla/service/hlo_instruction.h b/tensorflow/compiler/xla/service/hlo_instruction.h index 8569e86b83..a54716217d 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.h +++ b/tensorflow/compiler/xla/service/hlo_instruction.h @@ -888,7 +888,7 @@ class HloInstruction { // Two AllReduces are Identical if they have the same all_reduce_id. // Their operands don't have to be Identical. - if (!this->IsCrossModuleAllReduce()) { + if (!IsCrossModuleAllReduce()) { // Use an explicit loop rather than ContainerEquals, because copying // around std::functions may be too expensive in some cases. for (size_t i = 0; i < operands().size(); ++i) { @@ -905,6 +905,12 @@ class HloInstruction { return IdenticalSlowPath(other, eq_computations); } + // Generates a hash value of an HLO instruction. Hash considers + // information on opcode, shape, operands, and typically a root instruction. + // This function returns the same hash value for equivalent HLO instructions, + // with respect to HloInstruction::Identical() method. + uint64 Hash() const; + // Returns whether the instruction has a constant operand. bool HasConstantOperand() const; @@ -1613,6 +1619,10 @@ class HloInstruction { const std::function& eq_computations) const; + // Generates a hash value specific to a particular type of an instruction. + // This function typically considers the inner root instruction. + virtual uint64 InnerHash() const; + // Creates an n-ary elementwise operation. static std::unique_ptr CreateNary( const Shape& shape, HloOpcode opcode, diff --git a/tensorflow/compiler/xla/service/hlo_instructions.cc b/tensorflow/compiler/xla/service/hlo_instructions.cc index 6a57b75488..1ea02cf9c0 100644 --- a/tensorflow/compiler/xla/service/hlo_instructions.cc +++ b/tensorflow/compiler/xla/service/hlo_instructions.cc @@ -1372,6 +1372,10 @@ bool HloFusionInstruction::IdenticalSlowPath( other.fused_instructions_computation()); } +uint64 HloFusionInstruction::InnerHash() const { + return fused_instructions_computation()->Hash(); +} + std::unique_ptr HloFusionInstruction::CloneWithNewOperandsImpl( const Shape& shape, absl::Span new_operands, HloCloneContext* context) const { diff --git a/tensorflow/compiler/xla/service/hlo_instructions.h b/tensorflow/compiler/xla/service/hlo_instructions.h index e35c6e9150..b5c28137a1 100644 --- a/tensorflow/compiler/xla/service/hlo_instructions.h +++ b/tensorflow/compiler/xla/service/hlo_instructions.h @@ -743,6 +743,8 @@ class HloFusionInstruction : public HloInstruction { const HloInstruction& other, const std::function& eq_computations) const override; + uint64 InnerHash() const override; + // Implementation for non-common logic of CloneWithNewOperands. std::unique_ptr CloneWithNewOperandsImpl( const Shape& shape, absl::Span new_operands, diff --git a/tensorflow/compiler/xla/service/hlo_module.h b/tensorflow/compiler/xla/service/hlo_module.h index 66622a1d26..7b9cbf9a53 100644 --- a/tensorflow/compiler/xla/service/hlo_module.h +++ b/tensorflow/compiler/xla/service/hlo_module.h @@ -132,6 +132,12 @@ class HloModule { return config_.entry_computation_layout(); } + // Generates a hash value of an HLO module. Hash considers + // information on opcode, shape, operands, and typically a root instruction. + // This function returns the same hash value for equivalent HLO modules, + // with respect to HloInstruction::Identical() method. + uint64 Hash() const { return entry_computation()->Hash(); } + // Gets the computations in this module. // // Returns a view of HloComputation*s, so you can iterate over this in the diff --git a/tensorflow/compiler/xla/service/hlo_runner.cc b/tensorflow/compiler/xla/service/hlo_runner.cc index 3f0ca342b4..5a9b820a9d 100644 --- a/tensorflow/compiler/xla/service/hlo_runner.cc +++ b/tensorflow/compiler/xla/service/hlo_runner.cc @@ -205,6 +205,40 @@ StatusOr HloRunner::ExecuteWithDeviceBuffers( /*profile=*/profile); } +StatusOr HloRunner::ExecuteWithDeviceBuffers( + std::unique_ptr executable, + const absl::Span arguments, + ExecutionProfile* profile) { + // Get service run options. + se::Stream stream(backend().default_stream_executor()); + stream.Init(); + ServiceExecutableRunOptions service_run_options = + GetServiceRunOptionsForDevice(backend().default_device_ordinal(), &stream, + nullptr); + + TF_ASSIGN_OR_RETURN( + ScopedShapedBuffer retval, + executable->ExecuteOnStreamWrapper(&service_run_options, + /*profile=*/profile, arguments)); + TF_RETURN_IF_ERROR(stream.BlockHostUntilDone()); + return std::move(retval); +} + +StatusOr HloRunner::ExecuteWithDeviceBuffers( + std::unique_ptr executable, + const absl::Span arguments, + ExecutionProfile* profile) { + std::vector argument_pointers; + argument_pointers.reserve(arguments.size()); + for (const auto& argument : arguments) { + argument_pointers.push_back(&argument); + } + return ExecuteWithDeviceBuffers( + /*executable=*/std::move(executable), + /*arguments=*/argument_pointers, + /*profile=*/profile); +} + StatusOr> HloRunner::ExecuteReplicated( std::unique_ptr module, const ReplicatedExecuteOptions& options) { diff --git a/tensorflow/compiler/xla/service/hlo_runner.h b/tensorflow/compiler/xla/service/hlo_runner.h index 2e934bf66a..bb792cf8c9 100644 --- a/tensorflow/compiler/xla/service/hlo_runner.h +++ b/tensorflow/compiler/xla/service/hlo_runner.h @@ -136,6 +136,21 @@ class HloRunner { const absl::Span arguments, bool run_hlo_passes = true, ExecutionProfile* profile = nullptr); + StatusOr ExecuteWithDeviceBuffers( + std::unique_ptr executable, + const absl::Span arguments, + ExecutionProfile* profile = nullptr); + + StatusOr ExecuteWithDeviceBuffers( + std::unique_ptr executable, + const absl::Span arguments, + ExecutionProfile* profile = nullptr); + + // Creates an executable object given an HLO module. If run_hlo_passes is + // true, the HLO passes will be run as part of compilation. + StatusOr> CreateExecutable( + std::unique_ptr module, bool run_hlo_passes); + // Executes a given HLO module into a set of replicas, and returns a map // with the replica number as key, and the corresponding returned literal as // value. @@ -152,11 +167,6 @@ class HloRunner { const Backend& backend() const; private: - // Creates an executable object given an HLO module. If run_hlo_passes is - // true, the HLO passes will be run before. - StatusOr> CreateExecutable( - std::unique_ptr module, bool run_hlo_passes); - // Creates a ServiceExecutableRunOptions object to configure a run on device, // using the provided stream object. If device_assignment is not nullptr, it // will be used to configure the replication parameters. Replicated executions -- GitLab From a245fa2ecaf8d0d2d19eb680f73b5e960b9dd184 Mon Sep 17 00:00:00 2001 From: Priya Gupta Date: Thu, 29 Nov 2018 17:16:48 -0800 Subject: [PATCH 601/672] Distribution Strategy: Enable eager mode in Keras with MirroredStrategy (Part 1). Will update tests in follow ups. PiperOrigin-RevId: 223440045 --- .../distribute/python/examples/keras_mnist.py | 9 +++- .../contrib/distribute/python/keras_test.py | 2 +- .../tpu/python/tpu/keras_tpu_variables.py | 4 ++ tensorflow/python/framework/func_graph.py | 2 +- tensorflow/python/keras/backend.py | 2 +- .../engine/distributed_training_utils.py | 41 ++++++++++------- tensorflow/python/keras/engine/training.py | 10 ++-- .../keras/engine/training_distributed.py | 46 +++++++++++++++++-- .../python/keras/optimizer_v2/optimizer_v2.py | 2 +- tensorflow/python/training/optimizer.py | 11 +++-- 10 files changed, 95 insertions(+), 34 deletions(-) diff --git a/tensorflow/contrib/distribute/python/examples/keras_mnist.py b/tensorflow/contrib/distribute/python/examples/keras_mnist.py index 0fd3acd045..8b6487252d 100644 --- a/tensorflow/contrib/distribute/python/examples/keras_mnist.py +++ b/tensorflow/contrib/distribute/python/examples/keras_mnist.py @@ -102,18 +102,23 @@ def main(_): # Build the train and eval datasets from the MNIST data. Also return the # input shape which is constructed based on the `image_data_format` # i.e channels_first or channels_last. + tf.enable_eager_execution() + train_ds, eval_ds, input_shape = get_input_datasets() model = get_model(input_shape) # Instantiate the MirroredStrategy object. If we don't specify `num_gpus` or # the `devices` argument then all the GPUs available on the machine are used. - strategy = tf.contrib.distribute.MirroredStrategy() + strategy = tf.contrib.distribute.MirroredStrategy(['/gpu:0', '/cpu:0']) + + # TODO(priyag): Use RMSPropOptimizer when it works with eager mode. + optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001) # Compile the model by passing the distribution strategy object to the # `distribute` argument. `fit`, `evaluate` and `predict` will be distributed # based on the strategy instantiated. model.compile(loss=tf.keras.losses.categorical_crossentropy, - optimizer=tf.train.RMSPropOptimizer(learning_rate=0.001), + optimizer=optimizer, metrics=['accuracy'], distribute=strategy) diff --git a/tensorflow/contrib/distribute/python/keras_test.py b/tensorflow/contrib/distribute/python/keras_test.py index 6a006cc85f..435f10358f 100644 --- a/tensorflow/contrib/distribute/python/keras_test.py +++ b/tensorflow/contrib/distribute/python/keras_test.py @@ -27,6 +27,7 @@ from tensorflow.contrib.distribute.python import tpu_strategy from tensorflow.python import keras from tensorflow.python.data.ops import dataset_ops from tensorflow.python.distribute import values +from tensorflow.python.eager import test from tensorflow.python.estimator import keras as keras_lib from tensorflow.python.estimator import run_config as run_config_lib from tensorflow.python.framework import constant_op @@ -38,7 +39,6 @@ from tensorflow.python.keras.engine import distributed_training_utils from tensorflow.python.keras.optimizer_v2 import gradient_descent as gradient_descent_keras from tensorflow.python.ops.parsing_ops import gen_parsing_ops from tensorflow.python.platform import gfile -from tensorflow.python.platform import test from tensorflow.python.summary.writer import writer_cache from tensorflow.python.training import gradient_descent from tensorflow.python.training import rmsprop diff --git a/tensorflow/contrib/tpu/python/tpu/keras_tpu_variables.py b/tensorflow/contrib/tpu/python/tpu/keras_tpu_variables.py index 28d3a93851..8b0b240dc7 100644 --- a/tensorflow/contrib/tpu/python/tpu/keras_tpu_variables.py +++ b/tensorflow/contrib/tpu/python/tpu/keras_tpu_variables.py @@ -217,6 +217,10 @@ class ReplicatedVariable(object): def get(self): return self._primary_var + @property + def _in_graph_mode(self): + return self._primary_var._in_graph_mode # pylint: disable=protected-access + def _should_act_as_resource_variable(self): """Pass resource_variable_ops.is_resource_variable check.""" pass diff --git a/tensorflow/python/framework/func_graph.py b/tensorflow/python/framework/func_graph.py index a8a7948b99..f74d072e8e 100644 --- a/tensorflow/python/framework/func_graph.py +++ b/tensorflow/python/framework/func_graph.py @@ -113,7 +113,7 @@ class FuncGraph(ops.Graph): # this stack from the default graph even in eager mode. Maybe it should be # part of the eager context? This would also allow us to remove a # get_default_graph() call from the function cache lookup. - self._distribution_strategy_stack = graph._distribution_strategy_stack + self._distribution_strategy_stack = list(graph._distribution_strategy_stack) # We ignore device placements from any outer scopes while tracing the # function when possible, to avoid hard-coding them in the function # graph. "Default" placements come from the PartitionedCallOp's placement, diff --git a/tensorflow/python/keras/backend.py b/tensorflow/python/keras/backend.py index c7654642d0..7dae203f8a 100644 --- a/tensorflow/python/keras/backend.py +++ b/tensorflow/python/keras/backend.py @@ -3188,7 +3188,7 @@ def function(inputs, outputs, updates=None, name=None, **kwargs): Raises: ValueError: if invalid kwargs are passed in or if in eager execution. """ - if context.executing_eagerly(): + if ops.executing_eagerly_outside_functions(): if kwargs: raise ValueError('Session keyword arguments are not support during ' 'eager execution. You passed: %s' % (kwargs,)) diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index c587287ff9..d100182381 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -54,14 +54,18 @@ def set_weights(distribution_strategy, dist_model, weights): num_param = len(layer.weights) layer_weights = weights[:num_param] for sw, w in zip(layer.weights, layer_weights): - assign_ops.append(distribution_strategy.unwrap(sw.assign(w))) - + if ops.executing_eagerly_outside_functions(): + sw.assign(w) + else: + assign_ops.append(distribution_strategy.unwrap(sw.assign(w))) weights = weights[num_param:] - K.get_session().run(assign_ops) + + if not ops.executing_eagerly_outside_functions(): + K.get_session().run(assign_ops) def unwrap_values(distribution_strategy, grouped_inputs, grouped_outputs, - grouped_updates, grouped_session_args, + grouped_updates=None, grouped_session_args=None, with_loss_tensor=False): """Unwrap and return the list of values contained in the PerDevice parameters. @@ -103,20 +107,25 @@ def unwrap_values(distribution_strategy, grouped_inputs, grouped_outputs, all_outputs = flatten_perdevice_values(distribution_strategy, grouped_outputs) - all_updates = flatten_perdevice_values(distribution_strategy, - grouped_updates) + if grouped_updates: + all_updates = flatten_perdevice_values(distribution_strategy, + grouped_updates) + else: + all_updates = None all_session_args = {} - grouped_feed_dict = grouped_session_args.get('feed_dict') - if grouped_feed_dict: - all_session_args['feed_dict'] = flatten_perdevice_values( - distribution_strategy, grouped_feed_dict) - - grouped_fetches = grouped_session_args.get('fetches') - if grouped_fetches: - all_session_args['fetches'] = flatten_perdevice_values( - distribution_strategy, grouped_fetches) - + if grouped_session_args: + grouped_feed_dict = grouped_session_args.get('feed_dict') + if grouped_feed_dict: + all_session_args['feed_dict'] = flatten_perdevice_values( + distribution_strategy, grouped_feed_dict) + + grouped_fetches = grouped_session_args.get('fetches') + if grouped_fetches: + all_session_args['fetches'] = flatten_perdevice_values( + distribution_strategy, grouped_fetches) + + # TODO(priyag): Return only non empty/None values return all_inputs, all_outputs, all_updates, all_session_args diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index 1094e549d7..a66d8866bd 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -500,9 +500,6 @@ class Model(Network): raise NotImplementedError( 'optimizer must be an instance of ' 'tf.train.Optimizer, not a %s' % type(optimizer)) - if self.run_eagerly: - raise NotImplementedError('DistributionStrategy is not supported ' - 'when running a model eagerly.') if sample_weight_mode: raise NotImplementedError('sample_weight_mode is not supported with ' 'DistributionStrategy.') @@ -1064,7 +1061,9 @@ class Model(Network): with self._distribution_strategy.scope(): iterator = self._distribution_strategy.make_dataset_iterator(x) - K.get_session().run(iterator.initialize()) + init_op = iterator.initialize() + if not context.executing_eagerly(): + K.get_session().run(init_op) training_utils.validate_iterator_input(x, y, sample_weight, validation_split) @@ -1795,7 +1794,8 @@ class Model(Network): initial_epoch=initial_epoch, steps_per_epoch=steps_per_epoch, validation_steps=validation_steps) - elif isinstance(x, iterator_ops.EagerIterator): + elif (isinstance(x, iterator_ops.EagerIterator) and + not self._distribution_strategy): return training_generator.fit_generator( self, x, diff --git a/tensorflow/python/keras/engine/training_distributed.py b/tensorflow/python/keras/engine/training_distributed.py index 49050f0a97..7cf961b9ec 100644 --- a/tensorflow/python/keras/engine/training_distributed.py +++ b/tensorflow/python/keras/engine/training_distributed.py @@ -19,10 +19,12 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import enum +import enum # pylint: disable=g-bad-import-order import numpy as np +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import reduce_util as ds_reduce_util +from tensorflow.python.eager import context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors @@ -36,7 +38,6 @@ from tensorflow.python.keras.utils.generic_utils import Progbar from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging -from tensorflow.python.distribute import distribute_lib from tensorflow.python.util import nest @@ -540,7 +541,7 @@ def _clone_and_build_model(model, inputs=None, targets=None, mode=None): def clone_model_on_replicas(model, strategy, make_callback_model=False, inputs=None, targets=None, mode=None): """Create a cloned model on each replica.""" - with strategy.scope(): + with K.get_graph().as_default(), strategy.scope(): grouped_model = strategy.extended.call_for_each_replica( _clone_and_build_model, args=(model, inputs, targets, mode)) if mode is _Mode.TRAIN: @@ -583,6 +584,9 @@ def _get_input_from_iterator(iterator, model): def _get_execution_function(model, mode): """Get function to run one step of distributed model execution.""" + if context.executing_eagerly(): + return _get_eager_execution_function(model, mode) + strategy = model._distribution_strategy if not model._grouped_model: clone_model_on_replicas( @@ -627,6 +631,40 @@ def _get_execution_function(model, mode): **all_session_args) +def _get_eager_execution_function(model, mode): + """Get function to run one step of distributed model eager execution.""" + strategy = model._distribution_strategy + if not model._grouped_model: + clone_model_on_replicas( + model, strategy, make_callback_model=(mode == 'train')) + + def _per_device_function(model): + f = model._get_execution_function(mode) + return (f.inputs, f.outputs) + + # NOTE(priyag): Try creating a new FuncGraph within DS scope instead of using + # the global one. + with K.get_graph().as_default(), strategy.scope(): + # Create train ops on each of the devices when we call + # `_per_device_fit_function`. + (grouped_inputs, grouped_outputs) = strategy.call_for_each_replica( + _per_device_function, args=(model._grouped_model,)) + + # Unwrap all the per device values returned from `call_for_each_replica`. + # Unwrapping per device values gives you a list of values that can be + # used to construct a new train function that is composed of inptus/outputs + # on all the devices over which the model is distributed. + (all_inputs, all_outputs, _, _) = distributed_training_utils.unwrap_values( + strategy, + grouped_inputs, + grouped_outputs) + + return K.function( + all_inputs, + all_outputs, + name='eager_distributed_{}_function'.format(mode)) + + def _prepare_feed_values(model, inputs, targets, sample_weights, mode): """Prepare feed values to the model execution function. @@ -653,7 +691,7 @@ def _prepare_feed_values(model, inputs, targets, sample_weights, mode): None for _ in range(len(model.outputs) * strategy.num_replicas_in_sync) ] ins = inputs + targets + sample_weights - if mode == 'train' and not isinstance(K.learning_phase(), int): + if mode == 'train' and not isinstance(K.symbolic_learning_phase(), int): ins += [True] return ins diff --git a/tensorflow/python/keras/optimizer_v2/optimizer_v2.py b/tensorflow/python/keras/optimizer_v2/optimizer_v2.py index 0101ea8b97..9c8fff0fe4 100644 --- a/tensorflow/python/keras/optimizer_v2/optimizer_v2.py +++ b/tensorflow/python/keras/optimizer_v2/optimizer_v2.py @@ -329,7 +329,7 @@ class OptimizerV2(optimizer_v1.Optimizer): for grad, var in grads_and_vars: scope_name = ("" if ops.executing_eagerly_outside_functions() else "_" + var.op.name) - with ops.name_scope("update" + scope_name), ops.colocate_with(var): + with ops.name_scope("update" + scope_name): update_ops.append(update_grad_to_var(grad, var)) # control dependencies does not work in per replica mode, please change # this once b/118841692 is fixed. diff --git a/tensorflow/python/training/optimizer.py b/tensorflow/python/training/optimizer.py index 900afeed6c..bf9a79660b 100644 --- a/tensorflow/python/training/optimizer.py +++ b/tensorflow/python/training/optimizer.py @@ -201,8 +201,7 @@ def _get_processor(v): return _TensorProcessor(v) else: return _DenseResourceVariableProcessor(v) - if isinstance( - v, resource_variable_ops.ResourceVariable) and not v._in_graph_mode: # pylint: disable=protected-access + if resource_variable_ops.is_resource_variable(v) and not v._in_graph_mode: # pylint: disable=protected-access # True if and only if `v` was initialized eagerly. return _DenseResourceVariableProcessor(v) if v.op.type == "VarHandleOp": @@ -682,7 +681,13 @@ class Optimizer( "Gradient must be a Tensor, IndexedSlices, or None: %s" % g) p = _get_processor(v) - scope_name = "" if context.executing_eagerly() else v.op.name + if context.executing_eagerly() or ( + resource_variable_ops.is_resource_variable(v) and + not v._in_graph_mode): # pylint: disable=protected-access + scope_name = v.name.split(":")[0] + else: + scope_name = v.op.name + # device_policy is set because non-mirrored tensors will be read in # `update_op`. `_resource_apply_dense`, `lr_t`, `beta1_t` and `beta2_t` # is an example. -- GitLab From 814a6c24e4dfcf220a3b9ea429ad88b07fa81818 Mon Sep 17 00:00:00 2001 From: wenxizhu Date: Fri, 30 Nov 2018 09:24:23 +0800 Subject: [PATCH 602/672] Fix format for clang-format check. --- tensorflow/core/graph/mkl_layout_pass.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index edea296c3b..1c1a6ce652 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2700,8 +2700,8 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( for (const Edge* e : transpose_to_nchw->out_edges()) { if (!e->IsControlEdge()) { const int kTransposeWithMklOpOutputSlot = 0; - DCHECK((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, - e->dst(), e->dst_input())); + DCHECK((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, e->dst(), + e->dst_input())); } } -- GitLab From 341376d20fbfc392431d72cb6a40192bc368bac9 Mon Sep 17 00:00:00 2001 From: Anna R Date: Thu, 29 Nov 2018 17:17:59 -0800 Subject: [PATCH 603/672] Internal change. PiperOrigin-RevId: 223440182 --- tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh | 2 +- tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh b/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh index 32438260b4..5990caa50c 100644 --- a/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh +++ b/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh @@ -58,7 +58,7 @@ PY_TEST_DIR="py_test_dir" SKIP_TEST=0 RELEASE_BUILD=0 TEST_TARGET="//${PY_TEST_DIR}/tensorflow/python/..." -EXTRA_BUILD_FLAGS=${ADDITIONAL_BUILD_ARGS:-} +EXTRA_BUILD_FLAGS=${EXTRA_BUILD_FLAGS:-} # --skip_test Skip running tests # --enable_remote_cache Add options to enable remote cache for build and test diff --git a/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh b/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh index 6a701fc5a1..1bca2a6f88 100644 --- a/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh +++ b/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh @@ -58,7 +58,7 @@ PY_TEST_DIR="py_test_dir" SKIP_TEST=0 RELEASE_BUILD=0 TEST_TARGET="//${PY_TEST_DIR}/tensorflow/python/..." -EXTRA_BUILD_FLAGS=${ADDITIONAL_BUILD_ARGS:-} +EXTRA_BUILD_FLAGS=${EXTRA_BUILD_FLAGS:-} # --skip_test Skip running tests # --enable_remote_cache Add options to enable remote cache for build and test -- GitLab From a386016a3b2fd58631152fbfec4907f48b09ad49 Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Thu, 29 Nov 2018 17:18:46 -0800 Subject: [PATCH 604/672] Fix @tf.function signatures with unspecified default arguments Surprisingly not much impact on the signature+call benchmarks. Before: MicroBenchmarks.benchmark_defun_with_signature 8423 examples/sec MicroBenchmarks.benchmark_defun_with_signature_and_kwargs 7135 examples/sec After MicroBenchmarks.benchmark_defun_with_signature 8277 examples/sec MicroBenchmarks.benchmark_defun_with_signature_and_kwargs 7032 examples/sec PiperOrigin-RevId: 223440258 --- tensorflow/python/eager/def_function_test.py | 6 ++++++ tensorflow/python/eager/function.py | 11 ++++++++--- tensorflow/python/eager/function_test.py | 5 +++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/eager/def_function_test.py b/tensorflow/python/eager/def_function_test.py index da85735c47..4100a10044 100644 --- a/tensorflow/python/eager/def_function_test.py +++ b/tensorflow/python/eager/def_function_test.py @@ -214,6 +214,12 @@ class DefFunctionTest(test.TestCase): def_function.function(functools.partial(lambda x, y: x + y, 1.))( constant_op.constant(2.))) + def test_unspecified_default_argument(self): + wrapped = def_function.function( + lambda x, y=2: x + y, + input_signature=[tensor_spec.TensorSpec((), dtypes.int32)]) + self.assertEqual(3, wrapped(constant_op.constant(1)).numpy()) + def test_optimizer(self): x = constant_op.constant([[3., 4.]]) y = constant_op.constant([2.]) diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index d9c16aa7b8..9d05a660b1 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -1088,16 +1088,21 @@ class PolymorphicFunction(object): return inputs, kwargs else: assert not kwargs + signature_relevant_inputs = inputs[:len(self._input_signature)] try: - nest.assert_same_structure(self._input_signature, inputs) + nest.assert_same_structure(self._input_signature, + signature_relevant_inputs) except (ValueError, TypeError): raise ValueError("Structure of Python function inputs does not match " "input_signature.") - if any(not pywrap_tensorflow.IsTensor(arg) for arg in flat_inputs): + signature_inputs_flat = nest.flatten(signature_relevant_inputs) + if any(not pywrap_tensorflow.IsTensor(arg) + for arg in signature_inputs_flat): raise ValueError("When input_signature is provided, all inputs to " "the Python function must be Tensors.") if any(not spec.is_compatible_with(other) - for spec, other in zip(self._flat_input_signature, flat_inputs)): + for spec, other in zip(self._flat_input_signature, + signature_inputs_flat)): raise ValueError("Python inputs incompatible with input_signature: " "inputs (%s), input_signature (%s)" % (str(inputs), str(self._input_signature))) diff --git a/tensorflow/python/eager/function_test.py b/tensorflow/python/eager/function_test.py index d2cd407d80..2f3eff6d6a 100644 --- a/tensorflow/python/eager/function_test.py +++ b/tensorflow/python/eager/function_test.py @@ -1289,8 +1289,9 @@ class FunctionTest(test.TestCase, parameterized.TestCase): defined(array_ops.ones([2, 1])) # Wrong number of arguments. - with self.assertRaisesRegexp(ValueError, - 'Structure of Python function inputs.*'): + with self.assertRaisesRegexp( + ValueError, + 'Arguments and signature arguments do not match.*'): defined(array_ops.ones([2]), array_ops.ones([2])) with self.assertRaisesRegexp(ValueError, 'Structure of Python function inputs.*'): -- GitLab From 48714769a1df93198fecddb39e809871b89e210b Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Thu, 29 Nov 2018 17:20:04 -0800 Subject: [PATCH 605/672] Register ops that can update/add/sub tensors. PiperOrigin-RevId: 223440399 --- .../api_def/base_api/api_def_ScatterNd.pbtxt | 4 + .../base_api/api_def_TensorScatterAdd.pbtxt | 94 ++++++++++ .../base_api/api_def_TensorScatterSub.pbtxt | 94 ++++++++++ .../api_def_TensorScatterUpdate.pbtxt | 106 +++++++++++ tensorflow/core/kernels/BUILD | 1 + tensorflow/core/kernels/scatter_nd_op.cc | 164 ++++++++++++++++++ tensorflow/core/ops/array_ops.cc | 58 ++++++- .../kernel_tests/scatter_nd_ops_test.py | 51 ++++++ tensorflow/python/ops/array_grad.py | 26 +++ .../tools/api/golden/v1/tensorflow.pbtxt | 12 ++ .../tools/api/golden/v2/tensorflow.pbtxt | 12 ++ 11 files changed, 614 insertions(+), 8 deletions(-) create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorScatterAdd.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorScatterSub.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_TensorScatterUpdate.pbtxt diff --git a/tensorflow/core/api_def/base_api/api_def_ScatterNd.pbtxt b/tensorflow/core/api_def/base_api/api_def_ScatterNd.pbtxt index 0b5917d428..41955cfbfa 100644 --- a/tensorflow/core/api_def/base_api/api_def_ScatterNd.pbtxt +++ b/tensorflow/core/api_def/base_api/api_def_ScatterNd.pbtxt @@ -32,6 +32,10 @@ slices within a tensor (initially zero for numeric, empty for string) of the given `shape` according to indices. This operator is the inverse of the `tf.gather_nd` operator which extracts values or slices from a given tensor. +This operation is similar to tensor_scatter_add, except that the tensor is +zero-initialized. Calling `tf.scatter_nd(indices, values, shape)` is identical +to `tensor_scatter_add(tf.zeros(shape, values.dtype), indices, values)` + If `indices` contains duplicates, then their updates are accumulated (summed). **WARNING**: The order in which updates are applied is nondeterministic, so the diff --git a/tensorflow/core/api_def/base_api/api_def_TensorScatterAdd.pbtxt b/tensorflow/core/api_def/base_api/api_def_TensorScatterAdd.pbtxt new file mode 100644 index 0000000000..1634e51c3c --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_TensorScatterAdd.pbtxt @@ -0,0 +1,94 @@ +op { + graph_op_name: "TensorScatterAdd" + in_arg { + name: "tensor" + description: < + + + +In Python, this scatter operation would look like this: + +```python + indices = tf.constant([[4], [3], [1], [7]]) + updates = tf.constant([9, 10, 11, 12]) + tensor = tf.ones([8], dtype=tf.int32) + updated = tf.tensor_scatter_update(tensor, indices, updates) + with tf.Session() as sess: + print(sess.run(scatter)) +``` + +The resulting tensor would look like this: + + [1, 11, 1, 10, 9, 1, 1, 12] + +We can also, insert entire slices of a higher rank tensor all at once. For +example, if we wanted to insert two slices in the first dimension of a +rank-3 tensor with two matrices of new values. + +In Python, this scatter operation would look like this: + +```python + indices = tf.constant([[0], [2]]) + updates = tf.constant([[[5, 5, 5, 5], [6, 6, 6, 6], + [7, 7, 7, 7], [8, 8, 8, 8]], + [[5, 5, 5, 5], [6, 6, 6, 6], + [7, 7, 7, 7], [8, 8, 8, 8]]]) + tensor = tf.ones([4, 4, 4]) + updated = tf.tensor_scatter_update(tensor, indices, updates) + with tf.Session() as sess: + print(sess.run(scatter)) +``` + +The resulting tensor would look like this: + + [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]], + [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], + [[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]], + [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]] + +Note that on CPU, if an out of bound index is found, an error is returned. +On GPU, if an out of bound index is found, the index is ignored. +END +} diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index 986b21045d..be21d403e4 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -4589,6 +4589,7 @@ tf_kernel_library( ":dense_update_functor", ":training_op_helpers", ":variable_ops", + ":inplace_ops", ], ) diff --git a/tensorflow/core/kernels/scatter_nd_op.cc b/tensorflow/core/kernels/scatter_nd_op.cc index fd54c6d6d7..63bb793fdc 100644 --- a/tensorflow/core/kernels/scatter_nd_op.cc +++ b/tensorflow/core/kernels/scatter_nd_op.cc @@ -29,6 +29,7 @@ limitations under the License. #include "tensorflow/core/kernels/bounds_check.h" #include "tensorflow/core/kernels/dense_update_functor.h" #include "tensorflow/core/kernels/fill_functor.h" +#include "tensorflow/core/kernels/inplace_ops_functor.h" #include "tensorflow/core/kernels/training_op_helpers.h" #include "tensorflow/core/kernels/variable_ops.h" #include "tensorflow/core/lib/strings/str_util.h" @@ -121,6 +122,90 @@ class ScatterNdOp : public OpKernel { } }; +template +class TensorScatterOp : public OpKernel { + public: + explicit TensorScatterOp(OpKernelConstruction* c) : OpKernel(c) { + const DataType dt = DataTypeToEnum::v(); + const DataType index_t = DataTypeToEnum::v(); + OP_REQUIRES_OK(c, c->MatchSignature({dt, index_t, dt}, {dt})); + } + + void Compute(OpKernelContext* c) override { + const Tensor& input = c->input(0); + const Tensor& indices = c->input(1); + const Tensor& updates = c->input(2); + + OP_REQUIRES(c, indices.shape().dims() >= 1, + errors::InvalidArgument( + "Indices shape must have rank at least one. Found:", + indices.shape().DebugString())); + OP_REQUIRES(c, updates.shape().dims() >= 1, + errors::InvalidArgument( + "Updates shape must have rank at least one. Found:", + updates.shape().DebugString())); + + TensorShape shape = input.shape(); + + OP_REQUIRES( + c, + (shape.num_elements() > 0 || (indices.shape().num_elements() == 0 && + updates.shape().num_elements() == 0)), + errors::InvalidArgument( + "Indices and updates specified for empty output shape")); + + const int64 outer_dims = indices.shape().dims() - 1; + + for (int i = 0; i < outer_dims; ++i) { + OP_REQUIRES(c, indices.shape().dim_size(i) == updates.shape().dim_size(i), + errors::InvalidArgument( + "Outer dimensions of indices and update must match. " + "Indices shape: ", + indices.shape().DebugString(), + ", updates shape:", updates.shape().DebugString())); + } + + const int64 ix = indices.shape().dim_size(outer_dims); + OP_REQUIRES( + c, updates.shape().dims() - outer_dims == shape.dims() - ix, + errors::InvalidArgument("Inner dimensions of output shape must match " + "inner dimensions of updates shape. Output: ", + shape.DebugString(), + " updates: ", updates.shape().DebugString())); + for (int i = 0; i + outer_dims < updates.shape().dims(); ++i) { + OP_REQUIRES( + c, updates.shape().dim_size(i + outer_dims) == shape.dim_size(ix + i), + errors::InvalidArgument( + "The inner ", shape.dims() - ix, + " dimensions of output.shape=", shape.DebugString(), + " must match the inner ", updates.shape().dims() - outer_dims, + " dimensions of updates.shape=", updates.shape().DebugString())); + } + + std::unique_ptr forwarded_input = c->forward_input( + 2, 0, input.dtype(), shape, DEVICE_MEMORY, AllocatorAttributes()); + + if (forwarded_input == nullptr) { + // We were not able to forward the input, so we deep copy the tensor and + // set the output. + Tensor* out; + OP_REQUIRES_OK(c, c->allocate_output(0, input.shape(), &out)); + + OP_REQUIRES_OK(c, tensorflow::functor::DoCopy(c->eigen_device(), + input, out)); + OP_REQUIRES_OK(c, + functor::DoScatterNd( + c, indices, updates, shape, out, false /*allocate*/)); + } else { + // Output forwarded, so simply perform the scatter. + OP_REQUIRES_OK(c, functor::DoScatterNd( + c, indices, updates, shape, forwarded_input.get(), + false /*allocate*/)); + } + } +}; + template class ScatterNdUpdateOp : public OpKernel { @@ -282,6 +367,56 @@ TF_CALL_bool(REGISTER_SCATTER_ND_ADD_SUB_CPU); TF_CALL_bool(REGISTER_SCATTER_ND_UPDATE_CPU); TF_CALL_bool(REGISTER_SCATTER_ND_CPU); +#define REGISTER_SCATTER_ND_TENSOR_UPDATE_TYPE_INDEX_TYPE(type, index_type, \ + dev) \ + REGISTER_KERNEL_BUILDER(Name("TensorScatterUpdate") \ + .Device(DEVICE_##dev) \ + .TypeConstraint("T") \ + .TypeConstraint("Tindices"), \ + TensorScatterOp) + +#define REGISTER_SCATTER_ND_TENSOR_ADD_TYPE_INDEX_TYPE(type, index_type, dev) \ + REGISTER_KERNEL_BUILDER(Name("TensorScatterAdd") \ + .Device(DEVICE_##dev) \ + .TypeConstraint("T") \ + .TypeConstraint("Tindices"), \ + TensorScatterOp) + +#define REGISTER_SCATTER_ND_TENSOR_SUB_TYPE_INDEX_TYPE(type, index_type, dev) \ + REGISTER_KERNEL_BUILDER(Name("TensorScatterSub") \ + .Device(DEVICE_##dev) \ + .TypeConstraint("T") \ + .TypeConstraint("Tindices"), \ + TensorScatterOp) + +#define REGISTER_SCATTER_ND_TENSOR_UPDATE_CPU(type) \ + REGISTER_SCATTER_ND_TENSOR_UPDATE_TYPE_INDEX_TYPE(type, int32, CPU); \ + REGISTER_SCATTER_ND_TENSOR_UPDATE_TYPE_INDEX_TYPE(type, int64, CPU); + +#define REGISTER_SCATTER_ND_TENSOR_ADD_CPU(type) \ + REGISTER_SCATTER_ND_TENSOR_ADD_TYPE_INDEX_TYPE(type, int32, CPU); \ + REGISTER_SCATTER_ND_TENSOR_ADD_TYPE_INDEX_TYPE(type, int64, CPU); + +#define REGISTER_SCATTER_ND_TENSOR_SUB_CPU(type) \ + REGISTER_SCATTER_ND_TENSOR_SUB_TYPE_INDEX_TYPE(type, int32, CPU); \ + REGISTER_SCATTER_ND_TENSOR_SUB_TYPE_INDEX_TYPE(type, int64, CPU); + +#define REGISTER_SCATTER_ND_TENSOR_CPU(type) \ + REGISTER_SCATTER_ND_TENSOR_UPDATE_CPU(type); \ + REGISTER_SCATTER_ND_TENSOR_ADD_CPU(type); \ + REGISTER_SCATTER_ND_TENSOR_SUB_CPU(type); + +// Register TensorScatterUpdate/Add/Sub for all number types. +TF_CALL_NUMBER_TYPES(REGISTER_SCATTER_ND_TENSOR_CPU); +// Register only TensorScatterUpdate for string/bool types as well. +TF_CALL_string(REGISTER_SCATTER_ND_TENSOR_UPDATE_CPU); +TF_CALL_bool(REGISTER_SCATTER_ND_TENSOR_UPDATE_CPU); + +#undef REGISTER_SCATTER_ND_TENSOR_CPU + // Registers GPU kernels. #if GOOGLE_CUDA @@ -319,6 +454,25 @@ TF_CALL_GPU_NUMBER_TYPES_NO_HALF(REGISTER_SCATTER_ND_UPDATE_SYCL); #undef REGISTER_SCATTER_ND_UPDATE_SYCL #endif // TENSORFLOW_USE_SYCL +#define REGISTER_SCATTER_ND_TENSOR_UPDATE_GPU(type) \ + REGISTER_SCATTER_ND_TENSOR_UPDATE_TYPE_INDEX_TYPE(type, int32, GPU); \ + REGISTER_SCATTER_ND_TENSOR_UPDATE_TYPE_INDEX_TYPE(type, int64, GPU); + +#define REGISTER_SCATTER_ND_TENSOR_ADD_GPU(type) \ + REGISTER_SCATTER_ND_TENSOR_ADD_TYPE_INDEX_TYPE(type, int32, GPU); \ + REGISTER_SCATTER_ND_TENSOR_ADD_TYPE_INDEX_TYPE(type, int64, GPU); + +#define REGISTER_SCATTER_ND_TENSOR_SUB_GPU(type) \ + REGISTER_SCATTER_ND_TENSOR_SUB_TYPE_INDEX_TYPE(type, int32, GPU); \ + REGISTER_SCATTER_ND_TENSOR_SUB_TYPE_INDEX_TYPE(type, int64, GPU); + +#define REGISTER_SCATTER_ND_TENSOR_GPU(type) \ + REGISTER_SCATTER_ND_TENSOR_ADD_GPU(type); \ + REGISTER_SCATTER_ND_TENSOR_UPDATE_GPU(type); \ + REGISTER_SCATTER_ND_TENSOR_SUB_GPU(type); + +TF_CALL_GPU_NUMBER_TYPES_NO_HALF(REGISTER_SCATTER_ND_TENSOR_GPU); + #undef REGISTER_SCATTER_ND_ADD #undef REGISTER_SCATTER_ND_ADD_SUB #undef REGISTER_SCATTER_ND_ADD_SUB_CPU @@ -328,6 +482,16 @@ TF_CALL_GPU_NUMBER_TYPES_NO_HALF(REGISTER_SCATTER_ND_UPDATE_SYCL); #undef REGISTER_SCATTER_ND_UPDATE_GPU #undef REGISTER_SCATTER_ND_KERNEL #undef REGISTER_SCATTER_ND_KERNEL_INDEX +#undef REGISTER_SCATTER_ND_TENSOR_TYPE_INDEX_TYPE +#undef REGISTER_SCATTER_ND_TENSOR_CPU +#undef REGISTER_SCATTER_ND_TENSOR_GPU +#undef REGISTER_SCATTER_ND_TENSOR_UPDATE_TYPE_INDEX_TYPE +#undef REGISTER_SCATTER_ND_TENSOR_ADD_TYPE_INDEX_TYPE +#undef REGISTER_SCATTER_ND_TENSOR_SUB_TYPE_INDEX_TYPE +#undef REGISTER_SCATTER_ND_TENSOR_UPDATE_GPU +#undef REGISTER_SCATTER_ND_TENSOR_ADD_GPU +#undef REGISTER_SCATTER_ND_TENSOR_SUB_GPU +#undef REGISTER_SCATTER_ND_TENSOR_GPU #endif // GOOGLE_CUDA diff --git a/tensorflow/core/ops/array_ops.cc b/tensorflow/core/ops/array_ops.cc index e07a35a63d..281e2996ed 100644 --- a/tensorflow/core/ops/array_ops.cc +++ b/tensorflow/core/ops/array_ops.cc @@ -2881,14 +2881,9 @@ REGISTER_OP("QuantizedInstanceNorm") namespace { -Status ScatterNdShape(InferenceContext* c) { - ShapeHandle indices_shape; - TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &indices_shape)); - ShapeHandle updates_shape; - TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 1, &updates_shape)); - ShapeHandle output_shape; - TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(2, &output_shape)); - +Status ScatterNdShapeHelper(InferenceContext* c, ShapeHandle indices_shape, + ShapeHandle updates_shape, + ShapeHandle output_shape) { if (c->Value(c->NumElements(output_shape)) == 0 && (c->Value(c->NumElements(indices_shape)) > 0 || c->Value(c->NumElements(updates_shape)) > 0)) { @@ -2943,6 +2938,26 @@ Status ScatterNdShape(InferenceContext* c) { return Status::OK(); } +Status ScatterNdShape(InferenceContext* c) { + ShapeHandle indices_shape; + TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &indices_shape)); + ShapeHandle updates_shape; + TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 1, &updates_shape)); + ShapeHandle output_shape; + TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(2, &output_shape)); + return ScatterNdShapeHelper(c, indices_shape, updates_shape, output_shape); +} + +Status ScatterNdTensorShape(InferenceContext* c) { + ShapeHandle output_shape; + TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &output_shape)); + ShapeHandle indices_shape; + TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 1, &indices_shape)); + ShapeHandle updates_shape; + TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(2), 1, &updates_shape)); + return ScatterNdShapeHelper(c, indices_shape, updates_shape, output_shape); +} + } // namespace REGISTER_OP("UpperBound") @@ -2982,6 +2997,33 @@ REGISTER_OP("ScatterNd") .Attr("Tindices: {int32, int64}") .SetShapeFn(ScatterNdShape); +REGISTER_OP("TensorScatterUpdate") + .Input("tensor: T") + .Input("indices: Tindices") + .Input("updates: T") + .Output("output: T") + .Attr("T: type") + .Attr("Tindices: {int32, int64}") + .SetShapeFn(ScatterNdTensorShape); + +REGISTER_OP("TensorScatterAdd") + .Input("tensor: T") + .Input("indices: Tindices") + .Input("updates: T") + .Output("output: T") + .Attr("T: type") + .Attr("Tindices: {int32, int64}") + .SetShapeFn(ScatterNdTensorShape); + +REGISTER_OP("TensorScatterSub") + .Input("tensor: T") + .Input("indices: Tindices") + .Input("updates: T") + .Output("output: T") + .Attr("T: type") + .Attr("Tindices: {int32, int64}") + .SetShapeFn(ScatterNdTensorShape); + REGISTER_OP("ScatterNdNonAliasingAdd") .Input("input: T") .Input("indices: Tindices") diff --git a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py index 298db1547a..c1241ba87e 100644 --- a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py +++ b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops +from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import state_ops @@ -698,5 +699,55 @@ class ScatterNdNonAliasingAddTest(ScatterNdTest): pass +class ScatterNdTensorTest(test.TestCase): + + @test_util.run_in_graph_and_eager_modes + def testUpdateAddSub(self): + indices = constant_op.constant([[4], [3], [1], [7]]) + updates = constant_op.constant([9, 10, 11, 12], dtype=dtypes.float32) + t = array_ops.ones([8], dtype=dtypes.float32) + assigned = array_ops.tensor_scatter_update(t, indices, updates) + added = array_ops.tensor_scatter_add(t, indices, updates) + subbed = array_ops.tensor_scatter_sub(t, indices, updates) + + self.assertAllEqual(assigned, + constant_op.constant([1, 11, 1, 10, 9, 1, 1, 12])) + self.assertAllEqual(added, + constant_op.constant([1, 12, 1, 11, 10, 1, 1, 13])) + self.assertAllEqual(subbed, + constant_op.constant([1, -10, 1, -9, -8, 1, 1, -11])) + + def testUpdateAddSubGradients(self): + + with self.cached_session(): + indices = constant_op.constant([[3], [1]]) + updates = constant_op.constant([9, 10], dtype=dtypes.float32) + x = array_ops.ones([4], dtype=dtypes.float32) + + assigned = array_ops.tensor_scatter_update(x, indices, updates) + added = array_ops.tensor_scatter_add(x, indices, updates) + subbed = array_ops.tensor_scatter_sub(x, indices, updates) + + err_assigned = gradient_checker.compute_gradient_error( + x, [4], assigned, [4]) + err_added = gradient_checker.compute_gradient_error(x, [4], added, [4]) + err_subbed = gradient_checker.compute_gradient_error(x, [4], subbed, [4]) + + self.assertLess(err_assigned, 2e-4) + self.assertLess(err_added, 2e-4) + self.assertLess(err_subbed, 2e-4) + + err_assigned_wrt_updates = gradient_checker.compute_gradient_error( + updates, [2], assigned, [4]) + err_added_wrt_updates = gradient_checker.compute_gradient_error( + updates, [2], added, [4]) + err_subbed_wrt_updates = gradient_checker.compute_gradient_error( + updates, [2], subbed, [4]) + + self.assertLess(err_assigned_wrt_updates, 2e-4) + self.assertLess(err_added_wrt_updates, 2e-4) + self.assertLess(err_subbed_wrt_updates, 2e-4) + + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/ops/array_grad.py b/tensorflow/python/ops/array_grad.py index 6edc193361..45e741ef22 100644 --- a/tensorflow/python/ops/array_grad.py +++ b/tensorflow/python/ops/array_grad.py @@ -802,6 +802,32 @@ def _ScatterNdGrad(op, grad): return [None, updates_grad, None] +@ops.RegisterGradient("TensorScatterUpdate") +def _TensorScatterUpdateGrad(op, grad): + indices = op.inputs[1] + updates_grad = array_ops.gather_nd(grad, indices) + tensor_grad = array_ops.tensor_scatter_update( + array_ops.identity(grad), indices, + array_ops.zeros_like(op.inputs[2], dtype=grad.dtype)) + return [tensor_grad, None, updates_grad] + + +@ops.RegisterGradient("TensorScatterAdd") +def _TensorScatterAddGrad(op, grad): + indices = op.inputs[1] + updates_grad = array_ops.gather_nd(grad, indices) + tensor_grad = array_ops.identity(grad) + return [tensor_grad, None, updates_grad] + + +@ops.RegisterGradient("TensorScatterSub") +def _TensorScatterSubGrad(op, grad): + indices = op.inputs[1] + updates_grad = array_ops.gather_nd(grad, indices) + tensor_grad = array_ops.identity(grad) + return [tensor_grad, None, -updates_grad] + + @ops.RegisterGradient("ScatterNdNonAliasingAdd") def _ScatterNdNonAliasingAddGrad(op, grad): indices = op.inputs[1] diff --git a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt index 9c836c5bf8..490b4a847f 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt @@ -2176,6 +2176,18 @@ tf_module { name: "tanh" argspec: "args=[\'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "tensor_scatter_add" + argspec: "args=[\'tensor\', \'indices\', \'updates\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "tensor_scatter_sub" + argspec: "args=[\'tensor\', \'indices\', \'updates\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "tensor_scatter_update" + argspec: "args=[\'tensor\', \'indices\', \'updates\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "tensordot" argspec: "args=[\'a\', \'b\', \'axes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 2a30688b46..f5e1545657 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -1052,6 +1052,18 @@ tf_module { name: "tanh" argspec: "args=[\'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } + member_method { + name: "tensor_scatter_add" + argspec: "args=[\'tensor\', \'indices\', \'updates\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "tensor_scatter_sub" + argspec: "args=[\'tensor\', \'indices\', \'updates\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "tensor_scatter_update" + argspec: "args=[\'tensor\', \'indices\', \'updates\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "tensordot" argspec: "args=[\'a\', \'b\', \'axes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " -- GitLab From 326d3eec59d054838cb6e05e44b6458cedc395a5 Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Thu, 29 Nov 2018 18:11:03 -0800 Subject: [PATCH 606/672] Fixed issue with tflite_convert. PiperOrigin-RevId: 223446248 --- tensorflow/lite/python/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/python/convert.py b/tensorflow/lite/python/convert.py index 756c9daabe..198612f6fe 100644 --- a/tensorflow/lite/python/convert.py +++ b/tensorflow/lite/python/convert.py @@ -335,7 +335,7 @@ def build_toco_convert_protos(input_tensors, model.change_concat_input_ranges = change_concat_input_ranges for idx, input_tensor in enumerate(input_tensors): input_array = model.input_arrays.add() - if toco.inference_input_type == lite_constants.QUANTIZED_UINT8: + if toco.inference_input_type == _types_pb2.QUANTIZED_UINT8: input_array.mean_value, input_array.std_value = quantized_input_stats[idx] input_array.name = tensor_name(input_tensor) if input_shapes is None: -- GitLab From 1b41f3573ee7dff801b33fe504335a60fa839abd Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 18:23:18 -0800 Subject: [PATCH 607/672] Update ops-related pbtxt files. PiperOrigin-RevId: 223447396 --- .../core/ops/compat/ops_history.v1.pbtxt | 99 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 99 +++++++++++++++++++ 2 files changed, 198 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index 414964ad3f..6f3db65918 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -76017,6 +76017,105 @@ op { } } } +op { + name: "TensorScatterAdd" + input_arg { + name: "tensor" + type_attr: "T" + } + input_arg { + name: "indices" + type_attr: "Tindices" + } + input_arg { + name: "updates" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + } + attr { + name: "Tindices" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} +op { + name: "TensorScatterSub" + input_arg { + name: "tensor" + type_attr: "T" + } + input_arg { + name: "indices" + type_attr: "Tindices" + } + input_arg { + name: "updates" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + } + attr { + name: "Tindices" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} +op { + name: "TensorScatterUpdate" + input_arg { + name: "tensor" + type_attr: "T" + } + input_arg { + name: "indices" + type_attr: "Tindices" + } + input_arg { + name: "updates" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + } + attr { + name: "Tindices" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} op { name: "TensorSliceDataset" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index eae87da6b5..08aafc064e 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -36431,6 +36431,105 @@ op { } } } +op { + name: "TensorScatterAdd" + input_arg { + name: "tensor" + type_attr: "T" + } + input_arg { + name: "indices" + type_attr: "Tindices" + } + input_arg { + name: "updates" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + } + attr { + name: "Tindices" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} +op { + name: "TensorScatterSub" + input_arg { + name: "tensor" + type_attr: "T" + } + input_arg { + name: "indices" + type_attr: "Tindices" + } + input_arg { + name: "updates" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + } + attr { + name: "Tindices" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} +op { + name: "TensorScatterUpdate" + input_arg { + name: "tensor" + type_attr: "T" + } + input_arg { + name: "indices" + type_attr: "Tindices" + } + input_arg { + name: "updates" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "T" + type: "type" + } + attr { + name: "Tindices" + type: "type" + allowed_values { + list { + type: DT_INT32 + type: DT_INT64 + } + } + } +} op { name: "TensorSliceDataset" input_arg { -- GitLab From 3c6b48c7aa8d152439cc54f960e5b463b13093cd Mon Sep 17 00:00:00 2001 From: Yu-Cheng Ling Date: Thu, 29 Nov 2018 18:42:05 -0800 Subject: [PATCH 608/672] Bump TFLite iOS examples to use 1.12.0 CocoaPod PiperOrigin-RevId: 223449051 --- tensorflow/lite/examples/ios/camera/Podfile | 2 +- tensorflow/lite/examples/ios/simple/Podfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/lite/examples/ios/camera/Podfile b/tensorflow/lite/examples/ios/camera/Podfile index f460693122..96a0d23426 100644 --- a/tensorflow/lite/examples/ios/camera/Podfile +++ b/tensorflow/lite/examples/ios/camera/Podfile @@ -2,4 +2,4 @@ platform :ios, '8.0' inhibit_all_warnings! target 'tflite_camera_example' - pod 'TensorFlowLite', '1.10.1' + pod 'TensorFlowLite', '1.12.0' diff --git a/tensorflow/lite/examples/ios/simple/Podfile b/tensorflow/lite/examples/ios/simple/Podfile index ddb77088d9..931b72c1f5 100644 --- a/tensorflow/lite/examples/ios/simple/Podfile +++ b/tensorflow/lite/examples/ios/simple/Podfile @@ -2,4 +2,4 @@ platform :ios, '8.0' inhibit_all_warnings! target 'tflite_simple_example' - pod 'TensorFlowLite', '1.10.1' + pod 'TensorFlowLite', '1.12.0' -- GitLab From acbd910f8abf6b4b2f946eeac3bc77f3a6c832ce Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Thu, 29 Nov 2018 18:55:57 -0800 Subject: [PATCH 609/672] Disable runtime error in TF2 if colocation cannot be guaranteed PiperOrigin-RevId: 223450181 --- tensorflow/python/framework/importer.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/framework/importer.py b/tensorflow/python/framework/importer.py index 71ebfd6ceb..98c7aeccc4 100644 --- a/tensorflow/python/framework/importer.py +++ b/tensorflow/python/framework/importer.py @@ -21,6 +21,7 @@ import contextlib from tensorflow.core.framework import graph_pb2 from tensorflow.python import pywrap_tensorflow as c_api +from tensorflow.python import tf2 from tensorflow.python.framework import c_api_util from tensorflow.python.framework import device as pydev from tensorflow.python.framework import errors @@ -253,7 +254,9 @@ def _ProcessNewOps(graph): # Find any device in the list of colocated ops that have a device, if it # exists. We assume that if multiple ops have devices, they refer to the # same device. Otherwise, a runtime error will occur since the colocation - # property cannot be guaranteed. + # property cannot be guaranteed. Note in TF2 colocations have been removed + # from the public API and will be considered a hint, so there is no runtime + # error. # # One possible improvement is to try to check for compatibility of all # devices in this list at import time here, which would require @@ -262,6 +265,10 @@ def _ProcessNewOps(graph): try: coloc_op = graph._get_operation_by_name_unsafe(coloc_op_name) # pylint: disable=protected-access except KeyError: + # Do not error in TF2 if the colocation cannot be guaranteed + if tf2.enabled(): + continue + raise ValueError('Specified colocation to an op that ' 'does not exist during import: %s in %s' % (coloc_op_name, op.name)) -- GitLab From af4417be821c1e0e1af2d4324fd3e5cac2ac9887 Mon Sep 17 00:00:00 2001 From: Dan Moldovan Date: Thu, 29 Nov 2018 19:02:18 -0800 Subject: [PATCH 610/672] Avoid inspecting the decorators of a call's target function when the target is a lambda - they don't have decorators. PiperOrigin-RevId: 223450702 --- .../python/autograph/converters/call_trees.py | 5 +++++ .../python/autograph/converters/call_trees_test.py | 14 ++++++++++++++ .../python/autograph/core/converter_testing.py | 6 ++++-- tensorflow/python/autograph/core/naming.py | 5 ++--- tensorflow/python/autograph/pyct/inspect_utils.py | 8 ++++++++ .../python/autograph/pyct/inspect_utils_test.py | 7 +++++++ 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/autograph/converters/call_trees.py b/tensorflow/python/autograph/converters/call_trees.py index 55cea89126..4a8af42e69 100644 --- a/tensorflow/python/autograph/converters/call_trees.py +++ b/tensorflow/python/autograph/converters/call_trees.py @@ -140,6 +140,11 @@ class CallTreeTransformer(converter.Base): if target_entity is not None: + # Currently, lambdas are always converted. + # TODO(mdan): Allow markers of the kind f = ag.do_not_convert(lambda: ...) + if inspect_utils.islambda(target_entity): + return True + # This may be reached when "calling" a callable attribute of an object. # For example: # diff --git a/tensorflow/python/autograph/converters/call_trees_test.py b/tensorflow/python/autograph/converters/call_trees_test.py index 9d760167a9..b2a740020c 100644 --- a/tensorflow/python/autograph/converters/call_trees_test.py +++ b/tensorflow/python/autograph/converters/call_trees_test.py @@ -85,6 +85,20 @@ class CallTreesTest(converter_testing.TestCase): tc = TestClass() self.assertEquals(3, result.test_fn_2(tc, 1)) + def test_known_called_lambda(self): + + l = lambda x: x + + def test_fn(a): + return l(a) + + ns = {'l': l} + node, ctx = self.prepare(test_fn, ns) + node = call_trees.transform(node, ctx) + + with self.compiled(node, ns) as result: + self.assertEquals(1, result.test_fn(1)) + def test_py_func_known_function(self): def test_fn(): diff --git a/tensorflow/python/autograph/core/converter_testing.py b/tensorflow/python/autograph/core/converter_testing.py index 7b0608d03f..f1374081d3 100644 --- a/tensorflow/python/autograph/core/converter_testing.py +++ b/tensorflow/python/autograph/core/converter_testing.py @@ -32,6 +32,7 @@ from tensorflow.python.autograph.core import errors from tensorflow.python.autograph.core import function_wrapping from tensorflow.python.autograph.lang import special_functions from tensorflow.python.autograph.pyct import compiler +from tensorflow.python.autograph.pyct import inspect_utils from tensorflow.python.autograph.pyct import origin_info from tensorflow.python.autograph.pyct import parser from tensorflow.python.autograph.pyct import pretty_printer @@ -43,7 +44,7 @@ def imported_decorator(f): return lambda a: f(a) + 1 -# TODO(mdan): We might be able to use the real namer here. +# TODO(mdan): We should use the real namer here. class FakeNamer(object): """A fake namer that uses a global counter to generate unique names.""" @@ -61,7 +62,8 @@ class FakeNamer(object): original_fqn, live_entity=None, owner_type=None): - del live_entity + if inspect_utils.islambda(live_entity): + return None, False if owner_type is not None: return None, False return ('renamed_%s' % '_'.join(original_fqn)), True diff --git a/tensorflow/python/autograph/core/naming.py b/tensorflow/python/autograph/core/naming.py index 43fcbcfc03..b8d79daeba 100644 --- a/tensorflow/python/autograph/core/naming.py +++ b/tensorflow/python/autograph/core/naming.py @@ -18,8 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.autograph.pyct import inspect_utils from tensorflow.python.autograph.pyct import qual_names -from tensorflow.python.util import tf_inspect class Namer(object): @@ -77,8 +77,7 @@ class Namer(object): if not self.recursive: return None, False - if (live_entity is not None and tf_inspect.isfunction(live_entity) and - live_entity.__name__ == ''): + if (live_entity is not None and inspect_utils.islambda(live_entity)): return None, False if owner_type is not None and owner_type not in self.partial_types: diff --git a/tensorflow/python/autograph/pyct/inspect_utils.py b/tensorflow/python/autograph/pyct/inspect_utils.py index 4d56b93671..2319430d09 100644 --- a/tensorflow/python/autograph/pyct/inspect_utils.py +++ b/tensorflow/python/autograph/pyct/inspect_utils.py @@ -46,6 +46,14 @@ if six.PY2: SPECIAL_BUILTINS['xrange'] = xrange +def islambda(f): + if not tf_inspect.isfunction(f): + return False + if not hasattr(f, '__name__'): + return False + return f.__name__ == '' + + def isbuiltin(f): """Returns True if the argument is a built-in function.""" if f in SPECIAL_BUILTINS.values(): diff --git a/tensorflow/python/autograph/pyct/inspect_utils_test.py b/tensorflow/python/autograph/pyct/inspect_utils_test.py index 622e3bafc0..7e8466d58e 100644 --- a/tensorflow/python/autograph/pyct/inspect_utils_test.py +++ b/tensorflow/python/autograph/pyct/inspect_utils_test.py @@ -95,6 +95,13 @@ def free_factory(): class InspectUtilsTest(test.TestCase): + def test_islambda(self): + def test_fn(): + pass + + self.assertTrue(inspect_utils.islambda(lambda x: x)) + self.assertFalse(inspect_utils.islambda(test_fn)) + def test_getnamespace_globals(self): ns = inspect_utils.getnamespace(factory) self.assertEqual(ns['free_function'], free_function) -- GitLab From 19a1dd5268a67bb2fb0c1b034e9c0d6f63db230b Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Thu, 29 Nov 2018 19:09:19 -0800 Subject: [PATCH 611/672] [XLA] Make pattern_matchers work with gMock. This lets us unify the HLO pattern matchers and the HLO gmock matchers (in a later patch). Unifying these two APIs is useful because then we don't have to learn two APIs, and we don't have to implement features twice. This change: - Adds and tests the DescribeTo and MatchAndExplain APIs (this is the major change) - Uses these new gmock matchers in a few tests as a proof of concept. - Rewrites the is-constant-scalar API to use a true matcher rather than a std::function predicate matcher. This is necessary to get a user-friendly DescribeTo message rather than "I don't know what this std::function does." - Adds EffectiveScalarConstant helpers along with the old ScalarConstant helpers and then uses these within while_loop_simplifier. - Adds some missing simple op matchers: Tuple, Convolution, Pad, etc. - Adds a Parameter(n) matcher. - Adds Op().Is(), which matches a particular HloInstruction*, which is used in while_loop_simplifier. - Updates documentation to reflect new functions (both added here and added in earlier patches). - Tightens up the documentation. It was getting pretty long, and I made it longer. - Changes implementation of FooAnyOrder so that it returns an Op rather than an AnyOf. This lets you do AddAnyOrder(...).IsScalar(), whereas before this was a compile error. - Changes the implementation of FooAnyOrder so it uses a custom matcher rather than an AnyOf, in service of better DescribeTo messages. - Implements "and" folding, i.e. AllOf, X, Y, ...> => AllOf in the service of better DescribeTo messages. PiperOrigin-RevId: 223451504 --- tensorflow/compiler/xla/service/BUILD | 33 + .../xla/service/hlo_constant_folding_test.cc | 33 +- .../compiler/xla/service/hlo_parser_test.cc | 34 +- .../xla/service/layout_assignment_test.cc | 54 +- .../compiler/xla/service/pattern_matcher.h | 1264 ++++++++++++++--- .../xla/service/pattern_matcher_gmock.h | 92 ++ .../xla/service/pattern_matcher_gmock_test.cc | 76 + .../xla/service/pattern_matcher_test.cc | 474 ++++++- .../xla/service/while_loop_simplifier.cc | 27 +- 9 files changed, 1839 insertions(+), 248 deletions(-) create mode 100644 tensorflow/compiler/xla/service/pattern_matcher_gmock.h create mode 100644 tensorflow/compiler/xla/service/pattern_matcher_gmock_test.cc diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index 1bd04d2785..429b4e490c 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -408,9 +408,36 @@ tf_cc_test( ":hlo", ":pattern_matcher", "//tensorflow/compiler/xla:shape_util", + "//tensorflow/compiler/xla:test", "//tensorflow/compiler/xla/service:hlo_parser", "//tensorflow/compiler/xla/tests:xla_internal_test_main", "//tensorflow/core:test", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "pattern_matcher_gmock", + testonly = 1, + hdrs = ["pattern_matcher_gmock.h"], + deps = [ + ":pattern_matcher", + "//tensorflow/compiler/xla:test", + "//tensorflow/core:test", + ], +) + +tf_cc_test( + name = "pattern_matcher_gmock_test", + srcs = ["pattern_matcher_gmock_test.cc"], + deps = [ + ":hlo", + ":pattern_matcher", + ":pattern_matcher_gmock", + "//tensorflow/compiler/xla:shape_util", + "//tensorflow/compiler/xla:test", + "//tensorflow/compiler/xla/tests:xla_internal_test_main", + "//tensorflow/core:test", ], ) @@ -2631,6 +2658,8 @@ tf_cc_test( ":hlo", ":hlo_matchers", ":layout_assignment", + ":pattern_matcher", + ":pattern_matcher_gmock", "//tensorflow/compiler/xla:literal", "//tensorflow/compiler/xla:shape_layout", "//tensorflow/compiler/xla:shape_util", @@ -2775,6 +2804,8 @@ tf_cc_test( ":hlo_matchers", ":hlo_parser", ":hlo_pass", + ":pattern_matcher", + ":pattern_matcher_gmock", "//tensorflow/compiler/xla:literal", "//tensorflow/compiler/xla:shape_util", "//tensorflow/compiler/xla:test", @@ -3535,6 +3566,8 @@ tf_cc_test( ":hlo_casting_utils", ":hlo_matchers", ":hlo_parser", + ":pattern_matcher", + ":pattern_matcher_gmock", "//tensorflow/compiler/xla:test_helpers", "//tensorflow/compiler/xla:window_util", "//tensorflow/core:lib", diff --git a/tensorflow/compiler/xla/service/hlo_constant_folding_test.cc b/tensorflow/compiler/xla/service/hlo_constant_folding_test.cc index d12f920722..4f81dc94e5 100644 --- a/tensorflow/compiler/xla/service/hlo_constant_folding_test.cc +++ b/tensorflow/compiler/xla/service/hlo_constant_folding_test.cc @@ -22,21 +22,22 @@ limitations under the License. #include "tensorflow/compiler/xla/literal.h" #include "tensorflow/compiler/xla/service/hlo_computation.h" #include "tensorflow/compiler/xla/service/hlo_instruction.h" -#include "tensorflow/compiler/xla/service/hlo_matchers.h" #include "tensorflow/compiler/xla/service/hlo_opcode.h" #include "tensorflow/compiler/xla/service/hlo_parser.h" #include "tensorflow/compiler/xla/service/hlo_pass_fix.h" +#include "tensorflow/compiler/xla/service/pattern_matcher.h" +#include "tensorflow/compiler/xla/service/pattern_matcher_gmock.h" #include "tensorflow/compiler/xla/shape_util.h" #include "tensorflow/compiler/xla/test.h" #include "tensorflow/compiler/xla/tests/hlo_test_base.h" #include "tensorflow/compiler/xla/tests/literal_test_util.h" #include "tensorflow/compiler/xla/types.h" -namespace op = xla::testing::opcode_matchers; - namespace xla { namespace { +namespace m = xla::match; + using HloConstantFoldingTest = HloTestBase; TEST_F(HloConstantFoldingTest, ConvertF32ToS64) { @@ -49,13 +50,14 @@ TEST_F(HloConstantFoldingTest, ConvertF32ToS64) { auto module = CreateNewVerifiedModule(); auto computation = module->AddEntryComputation(builder.Build()); - EXPECT_THAT(computation->root_instruction(), op::Convert(input)); + EXPECT_THAT(computation->root_instruction(), + GmockMatch(m::Convert().WithOperand(0, m::Op().Is(input)))); HloConstantFolding const_folder; TF_ASSERT_OK_AND_ASSIGN(bool result, const_folder.Run(module.get())); EXPECT_TRUE(result); - EXPECT_THAT(computation->root_instruction(), op::Constant()); + EXPECT_THAT(computation->root_instruction(), GmockMatch(m::Constant())); EXPECT_EQ(computation->root_instruction()->literal().GetFirstElement(), 42); } @@ -70,13 +72,14 @@ TEST_F(HloConstantFoldingTest, ConvertS64ToF32) { auto module = CreateNewVerifiedModule(); auto computation = module->AddEntryComputation(builder.Build()); - EXPECT_THAT(computation->root_instruction(), op::Convert(input)); + EXPECT_THAT(computation->root_instruction(), + GmockMatch(m::Convert().WithOperand(0, m::Op().Is(input)))); HloConstantFolding const_folder; TF_ASSERT_OK_AND_ASSIGN(bool result, const_folder.Run(module.get())); EXPECT_TRUE(result); - EXPECT_THAT(computation->root_instruction(), op::Constant()); + EXPECT_THAT(computation->root_instruction(), GmockMatch(m::Constant())); EXPECT_EQ(computation->root_instruction()->literal().GetFirstElement(), 42.0f); } @@ -91,13 +94,14 @@ TEST_F(HloConstantFoldingTest, ConvertF32ArrayToS64Array) { auto module = CreateNewVerifiedModule(); auto computation = module->AddEntryComputation(builder.Build()); - EXPECT_THAT(computation->root_instruction(), op::Convert(input)); + EXPECT_THAT(computation->root_instruction(), + GmockMatch(m::Convert().WithOperand(0, m::Op().Is(input)))); HloConstantFolding const_folder; TF_ASSERT_OK_AND_ASSIGN(bool result, const_folder.Run(module.get())); EXPECT_TRUE(result); - EXPECT_THAT(computation->root_instruction(), op::Constant()); + EXPECT_THAT(computation->root_instruction(), GmockMatch(m::Constant())); EXPECT_EQ(computation->root_instruction()->literal().Get({0}), 42); EXPECT_EQ(computation->root_instruction()->literal().Get({1}), 19); } @@ -138,7 +142,7 @@ TEST_F(HloConstantFoldingTest, Concatenate) { EXPECT_TRUE(result); HloInstruction* root = computation->root_instruction(); - EXPECT_THAT(root, op::Constant()); + EXPECT_THAT(root, GmockMatch(m::Constant())); EXPECT_TRUE(ShapeUtil::Equal(root->shape(), shape)); } } @@ -165,7 +169,7 @@ TEST_F(HloConstantFoldingTest, Slice) { EXPECT_TRUE(result); HloInstruction* root = computation->root_instruction(); - EXPECT_THAT(root, op::Constant()); + EXPECT_THAT(root, GmockMatch(m::Constant())); EXPECT_TRUE(ShapeUtil::Equal(root->shape(), shape)); } @@ -190,7 +194,7 @@ TEST_F(HloConstantFoldingTest, TransposeConstantFold) { EXPECT_TRUE(result); HloInstruction* root = computation->root_instruction(); - EXPECT_THAT(root, op::Constant()); + EXPECT_THAT(root, GmockMatch(m::Constant())); EXPECT_TRUE(ShapeUtil::Compatible(root->shape(), shape)); using NativeT = typename primitive_util::PrimitiveTypeToNative::type; @@ -240,7 +244,8 @@ TEST_F(HloConstantFoldingTest, ConstantFoldReduceNoLayout) { TF_ASSERT_OK_AND_ASSIGN(bool result, const_folder.Run(m.get())); EXPECT_FALSE(result); - EXPECT_THAT(m->entry_computation()->root_instruction(), op::Reduce()); + EXPECT_THAT(m->entry_computation()->root_instruction(), + GmockMatch(m::Reduce())); } const char* const kConstantFoldLargePad = R"( @@ -260,7 +265,7 @@ TEST_F(HloConstantFoldingTest, DoesNotFoldLargePad) { EXPECT_FALSE(result); EXPECT_THAT(module->entry_computation()->root_instruction(), - op::Pad(op::Constant(), op::Constant())); + GmockMatch(m::Pad(m::Constant(), m::Constant()))); } } // namespace diff --git a/tensorflow/compiler/xla/service/hlo_parser_test.cc b/tensorflow/compiler/xla/service/hlo_parser_test.cc index f13f7504ee..ab71f011ac 100644 --- a/tensorflow/compiler/xla/service/hlo_parser_test.cc +++ b/tensorflow/compiler/xla/service/hlo_parser_test.cc @@ -21,7 +21,8 @@ limitations under the License. #include "absl/strings/string_view.h" #include "tensorflow/compiler/xla/service/hlo_casting_utils.h" #include "tensorflow/compiler/xla/service/hlo_instructions.h" -#include "tensorflow/compiler/xla/service/hlo_matchers.h" +#include "tensorflow/compiler/xla/service/pattern_matcher.h" +#include "tensorflow/compiler/xla/service/pattern_matcher_gmock.h" #include "tensorflow/compiler/xla/window_util.h" #include "tensorflow/core/lib/core/status_test_util.h" #include "tensorflow/core/platform/test.h" @@ -29,7 +30,7 @@ limitations under the License. namespace xla { namespace { -namespace op = ::xla::testing::opcode_matchers; +namespace m = ::xla::match; using absl::string_view; struct TestData { @@ -1893,7 +1894,8 @@ ENTRY ReduceR3ToR2 { )"; TF_ASSERT_OK_AND_ASSIGN(auto module, ParseHloString(original)); ASSERT_NE(module->entry_computation(), nullptr); - EXPECT_THAT(module->entry_computation()->root_instruction(), op::Reduce()); + EXPECT_THAT(module->entry_computation()->root_instruction(), + GmockMatch(m::Reduce())); } TEST_F(HloParserTest, ParseSharding) { @@ -1953,7 +1955,7 @@ TEST(HloParserSingleOpTest, SingleOp) { const HloComputation* computation = module->entry_computation(); ASSERT_NE(computation, nullptr); EXPECT_THAT(computation->root_instruction(), - op::Multiply(op::Parameter(0), op::Parameter(1))); + GmockMatch(m::Multiply(m::Parameter(0), m::Parameter(1)))); } TEST(HloParserSingleOpTest, SingleOpNoShapeProducesError) { @@ -1981,7 +1983,7 @@ TEST(HloParserSingleOpTest, SingleOpNoNames) { const HloComputation* computation = module->entry_computation(); ASSERT_NE(computation, nullptr); EXPECT_THAT(computation->root_instruction(), - op::Multiply(op::Parameter(0), op::Parameter(1))); + GmockMatch(m::Multiply(m::Parameter(0), m::Parameter(1)))); } TEST(HloParserSingleOpTest, CanonicalOp) { @@ -1990,7 +1992,7 @@ TEST(HloParserSingleOpTest, CanonicalOp) { const HloComputation* computation = module->entry_computation(); ASSERT_NE(computation, nullptr); EXPECT_THAT(computation->root_instruction(), - op::Multiply(op::Parameter(0), op::Parameter(1))); + GmockMatch(m::Multiply(m::Parameter(0), m::Parameter(1)))); EXPECT_EQ( computation->root_instruction()->ToString(HloPrintOptions::Canonical()), text); @@ -2044,7 +2046,11 @@ TEST(HloParserSingleOpTest, SingleOpWithNested) { const HloComputation* computation = module->entry_computation(); ASSERT_NE(computation, nullptr); EXPECT_THAT(computation->root_instruction(), - op::Fusion(op::Parameter(0), op::Parameter(1))); + GmockMatch(m::Op() + .WithOpcode(HloOpcode::kFusion) + .WithNumOperands(2) + .WithOperand(0, m::Parameter(0)) + .WithOperand(1, m::Parameter(1)))); } TEST(HloParserSingleOpTest, SingleOpWithNested_DoesNotExist) { @@ -2088,7 +2094,7 @@ TEST(HloParserSingleOpTest, ConvolutionTrivialFeatureGroupCount) { const HloComputation* computation = module->entry_computation(); ASSERT_NE(computation, nullptr); EXPECT_THAT(computation->root_instruction(), - op::Convolution(op::Parameter(0), op::Parameter(1))); + GmockMatch(m::Convolution(m::Parameter(0), m::Parameter(1)))); auto* convolution = Cast(computation->root_instruction()); EXPECT_EQ(convolution->feature_group_count(), 1); @@ -2152,8 +2158,10 @@ ENTRY %axpy.v5 (alpha: f32[], x: f32[2,4], y: f32[2,4]) -> f32[2,4] { module->schedule().is_computation_scheduled(module->entry_computation())); EXPECT_THAT( module->schedule().sequence(module->entry_computation()).instructions(), - ::testing::ElementsAre(op::Parameter(), op::Broadcast(), op::Parameter(), - op::Multiply(), op::Parameter(), op::Add())); + ::testing::ElementsAre( + GmockMatch(m::Parameter()), GmockMatch(m::Broadcast()), + GmockMatch(m::Parameter()), GmockMatch(m::Multiply()), + GmockMatch(m::Parameter()), GmockMatch(m::Add()))); } TEST_F(HloParserTest, IsScheduledIsTrueDifferentOrder) { @@ -2179,8 +2187,10 @@ ENTRY %axpy.v5 (alpha: f32[], x: f32[2,4], y: f32[2,4]) -> f32[2,4] { module->schedule().is_computation_scheduled(module->entry_computation())); EXPECT_THAT( module->schedule().sequence(module->entry_computation()).instructions(), - ::testing::ElementsAre(op::Parameter(), op::Parameter(), op::Parameter(), - op::Broadcast(), op::Multiply(), op::Add())); + ::testing::ElementsAre( + GmockMatch(m::Parameter()), GmockMatch(m::Parameter()), + GmockMatch(m::Parameter()), GmockMatch(m::Broadcast()), + GmockMatch(m::Multiply()), GmockMatch(m::Add()))); } TEST_F(HloParserTest, CustomCallWrongNumberofOperandConstraints) { diff --git a/tensorflow/compiler/xla/service/layout_assignment_test.cc b/tensorflow/compiler/xla/service/layout_assignment_test.cc index 61d8a0a4e6..311bd78905 100644 --- a/tensorflow/compiler/xla/service/layout_assignment_test.cc +++ b/tensorflow/compiler/xla/service/layout_assignment_test.cc @@ -31,6 +31,8 @@ limitations under the License. #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_opcode.h" #include "tensorflow/compiler/xla/service/hlo_parser.h" +#include "tensorflow/compiler/xla/service/pattern_matcher.h" +#include "tensorflow/compiler/xla/service/pattern_matcher_gmock.h" #include "tensorflow/compiler/xla/shape_layout.h" #include "tensorflow/compiler/xla/shape_util.h" #include "tensorflow/compiler/xla/test.h" @@ -42,11 +44,10 @@ limitations under the License. #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/status_test_util.h" -namespace op = xla::testing::opcode_matchers; - namespace xla { namespace { +namespace m = xla::match; using ::testing::ElementsAre; class LayoutAssignmentTest : public HloTestBase { @@ -342,7 +343,8 @@ TEST_F(LayoutAssignmentTest, ConflictingLayoutTuple) { // Verify the structure of the HLO graph. EXPECT_THAT(root, - op::Tuple(op::Tuple(constant), op::Tuple(op::Copy(constant)))); + GmockMatch(m::Tuple(m::Tuple(m::Op().Is(constant)), + m::Tuple(m::Copy(m::Op().Is(constant)))))); } TEST_F(LayoutAssignmentTest, ElementwiseAndReshape) { @@ -946,9 +948,11 @@ TEST_F(LayoutAssignmentTest, CopySliceOperandToAvoidImplicitLayoutChange) { HloInstruction* root = compiled_module->entry_computation()->root_instruction(); Shape shape_copy = ShapeUtil::MakeShapeWithLayout(F32, {4, 5}, {1, 0}); - EXPECT_THAT(root, op::Add(op::Parameter(), - op::Slice(AllOf(op::Copy(op::Parameter(1)), - op::ShapeWithLayout(shape_copy))))); + EXPECT_THAT( + root, + GmockMatch(m::Add( + m::Parameter(), + m::Slice(m::Copy(m::Parameter(1)).WithShapeEqualTo(&shape_copy))))); } TEST_F(LayoutAssignmentTest, CopyDSliceOperandToAvoidImplicitLayoutChange) { @@ -976,10 +980,11 @@ TEST_F(LayoutAssignmentTest, CopyDSliceOperandToAvoidImplicitLayoutChange) { compiled_module->entry_computation()->root_instruction(); Shape shape_copy = ShapeUtil::MakeShapeWithLayout(F32, {4, 5}, {1, 0}); EXPECT_THAT(root, - op::Add(op::Parameter(), - op::DynamicSlice(AllOf(op::Copy(op::Parameter(1)), - op::ShapeWithLayout(shape_copy)), - op::Parameter(2)))); + GmockMatch(m::Add( + m::Parameter(), + m::DynamicSlice( + m::Copy(m::Parameter(1)).WithShapeEqualTo(&shape_copy), + m::Parameter(2))))); } TEST_F(LayoutAssignmentTest, CopyConcatOperandToAvoidImplicitLayoutChange) { @@ -1007,11 +1012,12 @@ TEST_F(LayoutAssignmentTest, CopyConcatOperandToAvoidImplicitLayoutChange) { HloInstruction* root = compiled_module->entry_computation()->root_instruction(); Shape shape_copy = ShapeUtil::MakeShapeWithLayout(F32, {3, 5}, {1, 0}); - EXPECT_THAT(root, - op::Add(op::Parameter(), - op::Concatenate(AllOf(op::Copy(op::Parameter(1)), - op::ShapeWithLayout(shape_copy)), - op::Parameter(2)))); + EXPECT_THAT( + root, + GmockMatch(m::Add( + m::Parameter(), + m::Concatenate(m::Copy(m::Parameter(1)).WithShapeEqualTo(&shape_copy), + m::Parameter(2))))); } TEST_F(LayoutAssignmentTest, @@ -1038,7 +1044,8 @@ TEST_F(LayoutAssignmentTest, .ConsumeValueOrDie(); HloInstruction* root = compiled_module->entry_computation()->root_instruction(); - EXPECT_THAT(root, op::Convolution(op::Parameter(0), op::Parameter(1))); + EXPECT_THAT(root, + GmockMatch(m::Convolution(m::Parameter(0), m::Parameter(1)))); } TEST_F(LayoutAssignmentTest, PropagatingLayoutFromResultToOperand) { @@ -1062,8 +1069,9 @@ TEST_F(LayoutAssignmentTest, PropagatingLayoutFromResultToOperand) { HloInstruction* root = compiled_module->entry_computation()->root_instruction(); Shape shape_copy = ShapeUtil::MakeShapeWithLayout(F32, {4, 5}, {0, 1}); - EXPECT_THAT(root, op::Slice(AllOf(op::Copy(op::Parameter(0)), - op::ShapeWithLayout(shape_copy)))); + EXPECT_THAT(root, + GmockMatch(m::Slice( + m::Copy(m::Parameter(0)).WithShapeEqualTo(&shape_copy)))); } TEST_F(LayoutAssignmentTest, TupleCopyOnLayoutMismatch) { @@ -1149,7 +1157,7 @@ ENTRY %CustomCallWithNotLayoutConstrained (p: f32[42,2,3]) -> f32[1,2,3,4] { AssignLayouts(m.get(), &computation_layout); HloInstruction* root = m->entry_computation()->root_instruction(); - ASSERT_THAT(root, op::CustomCall(op::Parameter())); + ASSERT_THAT(root, GmockMatch(m::CustomCall(m::Parameter()))); ExpectLayoutIs(root->shape(), {3, 2, 0, 1}); ExpectLayoutIs(root->operand(0)->shape(), {0, 2, 1}); } @@ -1165,7 +1173,7 @@ ENTRY %CustomCallWithNotLayoutConstrained (p: f32[42,2,3]) -> f32[1,2,3,4] { AssignLayouts(m.get(), &computation_layout); HloInstruction* root = m->entry_computation()->root_instruction(); - ASSERT_THAT(root, op::CustomCall(op::Parameter())); + ASSERT_THAT(root, GmockMatch(m::CustomCall(m::Parameter()))); ExpectLayoutIs(root->shape(), {0, 2, 3, 1}); ExpectLayoutIs(root->operand(0)->shape(), {0, 1, 2}); } @@ -1196,7 +1204,7 @@ ENTRY %CustomCallWithLayoutConstraints (p0: f32[4,4], p1: f32[2,3]) -> f32[1,2,3 // The custom call should be partially encapsulated in kCopy instructions // because of the layout mismatches. ASSERT_THAT(m->entry_computation()->root_instruction(), - op::Copy(op::CustomCall(op::Copy(), op::Parameter()))); + GmockMatch(m::Copy(m::CustomCall(m::Copy(), m::Parameter())))); const HloInstruction* custom_call = m->entry_computation()->root_instruction()->operand(0); @@ -1222,7 +1230,7 @@ ENTRY %CustomCallLayoutConstrainedZeroOperands () -> f32[1,2,3,4] { AssignLayouts(m.get(), &computation_layout); ASSERT_THAT(m->entry_computation()->root_instruction(), - op::Copy(op::CustomCall())); + GmockMatch(m::Copy(m::CustomCall()))); const HloInstruction* custom_call = m->entry_computation()->root_instruction()->operand(0); @@ -1256,7 +1264,7 @@ ENTRY %CustomCallLayoutConstrainedTupleOperand (p0: f32[4,4], p1: f32[2,3]) -> f ExpectLayoutIs(root->shape(), {2, 1, 0, 3}); ASSERT_THAT(m->entry_computation()->root_instruction(), - op::Copy(op::CustomCall(op::Tuple()))); + GmockMatch(m::Copy(m::CustomCall(m::Tuple())))); const HloInstruction* custom_call = m->entry_computation()->root_instruction()->operand(0); diff --git a/tensorflow/compiler/xla/service/pattern_matcher.h b/tensorflow/compiler/xla/service/pattern_matcher.h index f196d9b7f5..fb1645d9b2 100644 --- a/tensorflow/compiler/xla/service/pattern_matcher.h +++ b/tensorflow/compiler/xla/service/pattern_matcher.h @@ -16,6 +16,7 @@ limitations under the License. #ifndef TENSORFLOW_COMPILER_XLA_SERVICE_PATTERN_MATCHER_H_ #define TENSORFLOW_COMPILER_XLA_SERVICE_PATTERN_MATCHER_H_ +#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" #include "absl/utility/utility.h" #include "tensorflow/compiler/xla/layout_util.h" @@ -44,32 +45,45 @@ namespace xla { // // This pattern will match Add instructions whose first operand is a constant. // -// Each pattern type has the following modifiers: +// Each pattern type has the following modifiers, which are described where +// nontrivial. // // Op(): -// - WithName: match operations with the given name -// - WithOpcode: match operations with the given opcode -// - WithShape: match operations whose shape matches the given pattern -// - WithOperand: match operations whose operand matches the given pattern +// - Is: is the given HloInstruction* (i.e. pointer equality) +// - WithName +// - WithOpcode +// - WithoutOpcode: anything other than the given opcode +// - WithShape: instr's shape matches the given pattern +// - WithShapeEqualTo: instr's shape is equal to the given Shape +// - WithShapeCompatibleTo: instr's shape is compatible with the given Shape +// - WithNumOperands +// - WithOperand: operand at the given index matches the given pattern +// - IsConstant +// - IsNonConstant +// - IsConstantScalar/IsEffectiveConstantScalar: Optionally accepts a value, +// e.g. IsConstantScalar() or IsConstantScalar(42). +// - WithFusionKind +// - WithTupleIndex: get-tuple-element operations with the given tuple index // // Shape(): -// - EqualTo: matches shapes that are equal to the argument -// - CompatibleTo: matches shapes that are compatible to the argument -// - IsScalar/IsArray/IsTuple: matches scalar/array/tuple shapes -// - IsDenseArray/IsSparseArray: matches arrays with dense/sparse format -// - WithLayout: match shapes whose layout matches the given pattern -// - WithLayoutEqualTo: matches shapes whose layouts equal the argument -// - WithSubshape: matches tuple shapes whose subshape matches the given -// pattern -// - WithSubshapeEqualTo: matches shapes with a subshape equal the argument -// - WithElementType: matches array/scalar shapes with the given element -// type -// - WithRank: matches array/scalar types with the given rank +// - EqualTo +// - CompatibleTo +// - IsScalar/IsEffectiveScalar/IsArray/IsTuple +// - IsDenseArray/IsSparseArray +// - WithLayout: layout shape's layout matches the given pattern (e.g. +// Layout().WithDenseFormat()) +// - WithLayoutEqualTo: shape's layout equals the argument (i.e. another +// Layout, but not the result of Layout().foo()) +// - WithSubshape: shape is a tuple whose subshape matches the given pattern +// (e.g. Shape().IsScalar()). +// - WithSubshapeEqualTo: shape is a tuple with a subshape equal to the arg +// (i.e. another Shape, but not the result of Shape().foo()) +// - WithElementType: shape is an array/scalar with the given elem type +// - WithRank: shape is an array/scalar with the given rank // // Layout(): -// - EqualTo: matches layouts that are equal to the argument -// - WithDenseFormat/WithSparseFormat: matches layouts with dense/sparse -// format +// - EqualTo +// - WithDenseFormat/WithSparseFormat // // Op(), Shape(), and Layout() may be passed an argument of type // HloInstruction**, Shape**, or Layout**, respectively, or const versions of @@ -82,53 +96,55 @@ namespace xla { // CHECK(Match(foo, // match::Op().WithOperand(0, match::Op(&matched_operand)))); // -// Helpers are provided for common nullary, unary, binary, and ternary -// instructions. These helpers can be called with no arguments, in which case -// they will match any instruction matching the opcode. They may also be called -// with matches for the operands and with an optional capture. (The capture must -// be the first argument.) Some examples of these helpers and their equivalents -// are provided below. -// +// Helpers are provided for most HLO instructions. These helpers can be called +// with no arguments, in which case they will match any instruction matching the +// opcode. They may also be called with matches for the operands and with an +// optional capture. (The capture must be the first argument.) Some examples of +// these helpers and their equivalents are provided below. + // Example nullary instruction: // Parameter() == Op().WithOpcode(HloOpcode::kParameter) // Parameter(&a) == Op(&a).WithOpcode(HloOpcode::kParameter) // // Example unary instruction: -// Abs() == Op().WithOpcode(HloOpcode::kAbs) -// Abs(Op(&a)) == Op().WithOpcode(HloOpcode::kAbs) -// .WithOperand(0, Op(&a))) -// Abs(&a, Op(&b)) == Op(&a).WithOpcode(HloOpcode::kAbs) -// .WithOperand(0, Op(&b)) +// Abs() == Op().WithOpcode(HloOpcode::kAbs) +// Abs(Op(&a)) == Op().WithOpcode(HloOpcode::kAbs) +// .WithOperand(0, Op(&a))) +// Abs(&a, Op(&b)) == Op(&a).WithOpcode(HloOpcode::kAbs) +// .WithOperand(0, Op(&b)) +// +// Commutative binary instructions have a special form that accepts either order +// of args, e.g.: // -// Example binary instruction: -// Add() == Op().WithOpcode(HloOpcode::kAdd) -// Add(Op(&a), Op(&b)) == Op().WithOpcode(HloOpcode::kAdd) -// .WithOperand(0, Op(&a)) -// .WithOperand(1, Op(&b)) -// Add(&a, Op(&b), Op(&c)) == Op(&a).WithOpcode(HloOpcode::kAdd) -// .WithOperand(0, Op(&b)) -// .WithOperand(1, Op(&c)) +// AddAnyOrder(Parameter(1), Abs()) == +// Op().WithOpcode(HloOpcode::kAdd) +// .WithBinaryOperandsAnyOrder(Op().WithParameterNum(1), Abs()); // -// Example ternary instruction: -// Clamp() == Op().WithOpcode(HloOpcode::kClamp) -// Clamp(Op(&a), Op(&b), Op(&c)) == Op().WithOpcode(HloOpcode::kClamp) -// .WithOperand(0, Op(&a)) -// .WithOperand(1, Op(&b)) -// .WithOperand(2, Op(&c)) -// Clamp(&a, Op(&b), Op(&c), Op(&d)) == Op(&a).WithOpcode(HloOpcode::kClamp) -// .WithOperand(0, Op(&b)) -// .WithOperand(1, Op(&c)) -// .WithOperand(2, Op(&d)) +// MultiplyAnyOrder(&a, Parameter(), Abs()) // Captures the mul in `a`. // +// The following additional helpers are provided. In all cases, `&a` is +// optional. +// +// ConstantScalar(&a) == Op(&a).IsConstantScalar(); +// ConstantScalar(&a, v) == Op(&a).IsConstantScalar(v); +// ConstantEffectiveScalar(&a) == Op(&a).IsConstantEffectiveScalar(); +// ConstantEffectiveScalar(&a, v) == Op(&a).IsConstantEffectiveScalar(&a, v) +// NonConstant(&a) == Op(&a).IsNonConstant() +// GetTupleElement(&a, b, index) == Op(&a).WithTupleIndex(index) +// .WithOperand(0, b); +// Parameter(&a, n) == Op(&a).WithParameterNum(n); struct MatchOption { // If true, actually capture matched item into the user pointer. bool capture; + + // An explanation for why we failed to match is streamed here, if not-null. + std::ostream* explain_os; }; template bool Match(Value* value, const Pattern& pattern, - MatchOption option = {/*.capture=*/true}) { + MatchOption option = {/*.capture=*/true, /*.explain_os=*/nullptr}) { if (option.capture) { auto new_option = option; new_option.capture = false; @@ -143,6 +159,77 @@ namespace match { namespace detail { +// Macro for streaming to option.explain_os if it's not null. +// +// EXPLAIN << "value of foo(): " << foo() +// +#pragma push_macro("EXPLAIN") +#define EXPLAIN \ + if (option.explain_os) *option.explain_os + +// kIndentInc is the additional number of spaces that we indent by when we +// increase the indent "by one". +enum { + kIndentInc = 2, +}; + +// Writes a newline and then `indent` spaces. +// +// We follow an unintuitive convention in this file's pretty-printers: Indents +// are performed by the caller, not the callee. For example, if you want to +// print +// +// foo: +// - bar +// +// you'd do: +// +// Foo::DescribeTo(std::ostream* os, int64 indent) { +// *os << "foo:"; +// Indent(os, indent) // Create a newline at the *current* indent level. +// *os << " - "; +// bar.DescribeTo(os, indent + 3); // + 3 because strlen(" * ") == 3. +// } +// +// Bar::DescribeTo(std::ostream* os, int64 indent) { *os << "bar"; } +// +// Notice that Bar::DescribeTo() does not call Indent; the indenting is +// performed by Foo. This convention allows the caller to decide whether a +// matcher is preceded by a newline, which is important e.g. for the AllOf +// matcher. +// +// (Incidentally, indenting in Match's explanations is handled differently. +// Indents are a common case in DescribeTo [we're printing a whole tree], but +// they're a special case in Match [we're printing only a path through the tree +// that encounters a failing node]. Indents in Match only appear when we +// encounter a failing disjunction, so we just handle them as a special case +// there.) +inline void Indent(std::ostream* os, int64 indent) { + *os << "\n"; + for (int64 i = 0; i < indent; ++i) { + *os << " "; + } +} + +// SFINAE template that determines whether T declares a static member +// kIsTrivialMatcher. +// +// Trivial matchers get special treatment. For example, when printing +// a conjunction of matchers, we don't print "and" after a trivial matcher. This +// yields e.g. +// "a shape compatible with f32[1,2]" +// rather than +// "a shape AND compatible with f32[1,2]" +template +struct IsTrivialMatcher { + static constexpr bool value = false; +}; +template +struct IsTrivialMatcher::type> { + static constexpr bool value = true; +}; + template class AllOfPattern { public: @@ -162,10 +249,19 @@ class AllOfPattern { return matched; } + void DescribeTo(std::ostream* os, int64 indent = 0) const { + DescribeToImpl(os, std::integral_constant(), indent); + } + + // Accessor for patterns_. Please don't use this outside of this file. + const std::tuple& patterns() const { return patterns_; } + private: template bool MatchImpl(ItemType* item, MatchOption option, std::integral_constant) const { + // We don't need to do any EXPLAINing here; it's all correctly handled by + // our sub-matchers (if any fail). return std::get(patterns_).Match(item, option) && MatchImpl(item, option, std::integral_constant()); } @@ -176,6 +272,73 @@ class AllOfPattern { return true; } + // Pretty-printing a conjunction has some special cases to make it easy to + // read in the simple (common) case. + // + // If sizeof...(Patterns) == 1, prints as e.g. + // + // a shape + // + // If sizeof...(Patterns) == 2 and patterns_[0] is a trivial matcher (e.g. "a + // shape") prints as + // + // a shape compatible with f32[1,2] + // + // If sizeof...(Patterns) > 2 and patterns_[0] is a trivial matcher, prints as + // + // a shape: + // * compatible with f32[1,2] AND + // * that represents a scalar + // + // Otherwise prints as: + // + // all of: + // * foo AND + // * bar + // + template + void DescribeToImpl(std::ostream* os, std::integral_constant, + int64 indent) const { + constexpr bool first_is_trivial = + IsTrivialMatcher(patterns_))>::type>::value; + constexpr bool is_last = index == sizeof...(Patterns) - 1; + const auto& submatcher = std::get(patterns_); + + auto print_bulleted_item = [&] { + *os << " * "; + submatcher.DescribeTo(os, indent + 3); + if (!is_last) { + *os << " AND"; + Indent(os, indent); + } + }; + + if (index == 0) { + if (first_is_trivial || is_last) { + submatcher.DescribeTo(os, indent + kIndentInc); + if (sizeof...(Patterns) > 2) { + *os << ":"; + Indent(os, indent); + } + } else { + *os << "all of:"; + Indent(os, indent); + print_bulleted_item(); + } + } else if (first_is_trivial && index == 1 && sizeof...(Patterns) == 2) { + *os << " "; + submatcher.DescribeTo(os, indent); + } else { + print_bulleted_item(); + } + DescribeToImpl(os, std::integral_constant(), indent); + } + + void DescribeToImpl(std::ostream* os, + std::integral_constant, + int64 indent) const {} + std::tuple patterns_; }; @@ -183,10 +346,6 @@ class AllOfPattern { // Returns a pattern that represents the conjunction of all input patterns. All // patterns need to match in order to have the AllOf pattern match. -// -// TODO(timshen): Currently AllOf is still nested, e.g. AllOf, B> is -// not AllOf. We might want to flatten the AllOf type structure if the -// C++ compile error message gets annoying. template detail::AllOfPattern::type, Patterns...> AllOf( const Patterns&... patterns) { @@ -194,6 +353,25 @@ detail::AllOfPattern::type, Patterns...> AllOf( Patterns...>(patterns...); } +// AllOf, X, Y, ...> => AllOf. +// +// This transformation is necessary for good pretty-printing. +template +detail::AllOfPattern::type, InnerPs..., + OuterPs...> +AllOf(const detail::AllOfPattern& inner_p, + const OuterPs&... outer_ps) { + // Invoke constructor of AllOfPattern. + auto make_all_of = [](const InnerPs&... inner_ps, + const OuterPs&... outer_ps) { + return detail::AllOfPattern::type, + InnerPs..., OuterPs...>(inner_ps..., + outer_ps...); + }; + return absl::apply(make_all_of, std::tuple_cat(inner_p.patterns(), + std::make_tuple(outer_ps...))); +} + namespace detail { template @@ -204,8 +382,18 @@ class LayoutPattern; class LayoutPatternBaseImpl { public: bool Match(const ::xla::Layout* layout, MatchOption option) const { - return layout != nullptr; + if (layout == nullptr) { + EXPLAIN << "Layout is null"; + return false; + } + return true; } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "a layout"; + } + + static constexpr bool kIsTrivialMatcher = true; }; // A LayoutPattern implementation that matches only if the layout equals a @@ -216,7 +404,17 @@ class LayoutPatternEqualImpl { : layout_(layout) {} bool Match(const ::xla::Layout* layout, MatchOption option) const { - return LayoutUtil::Equal(*layout_, *layout); + if (!LayoutUtil::Equal(*layout_, *layout)) { + EXPLAIN << "Layout " << LayoutUtil::HumanString(*layout) + << " is not equal to expected " + << LayoutUtil::HumanString(*layout_); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "equal to " << LayoutUtil::HumanString(*layout_); } private: @@ -230,7 +428,16 @@ class LayoutPatternFormatImpl { explicit constexpr LayoutPatternFormatImpl(Format format) : format_(format) {} bool Match(const ::xla::Layout* layout, MatchOption option) const { - return layout->format() == format_; + if (layout->format() != format_) { + EXPLAIN << "Layout has format " << Format_Name(layout->format()) + << " but expected " << Format_Name(format_); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with format " << Format_Name(format_); } private: @@ -242,11 +449,13 @@ template class LayoutPattern { private: template - LayoutPattern> - AppendImpl(NewImpl new_impl) const { - return LayoutPattern>( - AllOf(impl_, std::move(new_impl)), matched_layout_); + auto AppendImpl(NewImpl new_impl) const + -> LayoutPattern(std::declval(), + std::move(new_impl)))> { + auto new_allof = AllOf(impl_, std::move(new_impl)); + return LayoutPattern(std::move(new_allof), + matched_layout_); } public: @@ -276,6 +485,10 @@ class LayoutPattern { return false; } + void DescribeTo(std::ostream* os, int64 indent = 0) const { + impl_.DescribeTo(os, indent); + } + // Modifies the pattern to match only if the layout equals the given proto. // The layout must outlive the returned pattern. constexpr auto EqualTo(const ::xla::Layout* layout) const @@ -306,19 +519,48 @@ class AnyOfPattern { explicit AnyOfPattern(const Patterns&... patterns) : patterns_(patterns...) {} bool Match(const Item* item, MatchOption option) const { - return MatchImpl(item, option, std::integral_constant()); + return MatchImpl(item, option); } bool Match(Item* item, MatchOption option) const { - return MatchImpl(item, option, std::integral_constant()); + return MatchImpl(item, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "any of:"; + Indent(os, indent); + DescribeToImpl(os, std::integral_constant(), indent); } private: + template + bool MatchImpl(ItemType* item, MatchOption option) const { + // If we're generating an explanation, buffer it until we know we failed. + absl::optional explanation; + MatchOption new_option = option; + if (option.explain_os) { + new_option.explain_os = &explanation.emplace(); + } + bool rv = MatchRecursiveImpl(item, new_option, + std::integral_constant()); + if (!rv && option.explain_os) { + EXPLAIN << "None of the following matchers succeeded:"; + EXPLAIN << explanation->str(); + } + return rv; + } + template - bool MatchImpl(ItemType* item, MatchOption option, - std::integral_constant) const { + bool MatchRecursiveImpl(ItemType* item, MatchOption option, + std::integral_constant) const { auto new_option = option; new_option.capture = false; + + absl::optional explanation; + if (option.explain_os) { + new_option.explain_os = &explanation.emplace(); + } + // Try to match the sub-pattern without capturing behavior. if (std::get(patterns_).Match(item, new_option)) { // Capture the branch. @@ -337,20 +579,46 @@ class AnyOfPattern { // AnyOf will be a runtime number indicate which sub-pattern is matched. // Then we run another pass to do captures only with the help of the // trace. - bool ret = std::get(patterns_).Match(item, option); - DCHECK(ret); + bool matched = std::get(patterns_).Match(item, option); + DCHECK(matched); } return true; } - return MatchImpl(item, option, std::integral_constant()); + if (option.explain_os) { + EXPLAIN << "\nMatcher #" << index + 1; + EXPLAIN << "\n - "; + std::get(patterns_).DescribeTo(option.explain_os, /*indent=*/3); + EXPLAIN << "\nfailed with"; + EXPLAIN << "\n - "; + EXPLAIN << absl::StrReplaceAll(explanation->str(), {{"\n", "\n "}}); + } + return MatchRecursiveImpl(item, option, + std::integral_constant()); } template - bool MatchImpl(ItemType* item, MatchOption option, - std::integral_constant) const { + bool MatchRecursiveImpl( + ItemType* item, MatchOption option, + std::integral_constant) const { return false; } + template + void DescribeToImpl(std::ostream* os, std::integral_constant, + int64 indent) const { + *os << " - "; + std::get(patterns_).DescribeTo(os, indent + 3); + if (index != sizeof...(Patterns) - 1) { + *os << " OR"; + Indent(os, indent); + } + DescribeToImpl(os, std::integral_constant(), indent); + } + + void DescribeToImpl(std::ostream* os, + std::integral_constant, + int64 indent) const {} + std::tuple patterns_; }; @@ -395,8 +663,17 @@ class ShapePattern; class ShapePatternBaseImpl { public: bool Match(const ::xla::Shape* shape, MatchOption option) const { + if (shape == nullptr) { + EXPLAIN << "Shape is null"; + } return shape != nullptr; } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "a shape"; + } + + static constexpr bool kIsTrivialMatcher = true; }; // A ShapePattern implementation that matches only if the shape equals a Shape @@ -407,7 +684,16 @@ class ShapePatternEqualImpl { : shape_(shape) {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::Equal(*shape_, *shape); + if (!ShapeUtil::Equal(*shape_, *shape)) { + EXPLAIN << "Shape not equal to " + << ShapeUtil::HumanStringWithLayout(*shape_); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "equal to " << ShapeUtil::HumanStringWithLayout(*shape_); } private: @@ -422,7 +708,16 @@ class ShapePatternCompatibleImpl { : shape_(shape) {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::Compatible(*shape_, *shape); + if (!ShapeUtil::Compatible(*shape_, *shape)) { + EXPLAIN << "Shape not compatible with " + << ShapeUtil::HumanString(*shape_); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "compatible with " << ShapeUtil::HumanString(*shape_); } private: @@ -437,7 +732,16 @@ class ShapePatternElementTypeImpl { : element_type_(element_type) {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return shape->element_type() == element_type_; + if (shape->element_type() != element_type_) { + EXPLAIN << "Shape does not have element type " + << PrimitiveType_Name(element_type_); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with element type " << PrimitiveType_Name(element_type_); } private: @@ -450,7 +754,15 @@ class ShapePatternIsScalarImpl { explicit constexpr ShapePatternIsScalarImpl() {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::IsScalar(*shape); + if (!ShapeUtil::IsScalar(*shape)) { + EXPLAIN << "Shape is not a scalar"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "that represents a scalar"; } }; @@ -460,7 +772,15 @@ class ShapePatternIsArrayImpl { explicit constexpr ShapePatternIsArrayImpl() {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::IsArray(*shape); + if (!ShapeUtil::IsArray(*shape)) { + EXPLAIN << "Shape is not an array"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "that represents an array"; } }; @@ -470,7 +790,34 @@ class ShapePatternIsTupleImpl { explicit constexpr ShapePatternIsTupleImpl() {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::IsTuple(*shape); + if (!ShapeUtil::IsTuple(*shape)) { + EXPLAIN << "Shape is not a tuple"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "that represents a tuple"; + } +}; + +// A ShapePattern implementation that matches only if the shape is an effective +// scalar. +class ShapePatternEffectiveScalarImpl { + public: + explicit constexpr ShapePatternEffectiveScalarImpl() {} + + bool Match(const ::xla::Shape* shape, MatchOption option) const { + if (!ShapeUtil::IsEffectiveScalar(*shape)) { + EXPLAIN << "Shape is not an effective scalar"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "that is an effective scalar"; } }; @@ -481,7 +828,23 @@ class ShapePatternRankImpl { explicit constexpr ShapePatternRankImpl(int64 rank) : rank_(rank) {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::Rank(*shape) == rank_; + if (ShapeUtil::Rank(*shape) != rank_) { + if (rank_ == 0) { + EXPLAIN << "Shape is not a scalar"; + } else { + EXPLAIN << "Shape does not have rank " << rank_; + } + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + if (rank_ == 0) { + *os << "that is a scalar"; + } else { + *os << "that has " << rank_ << " dimension" << (rank_ != 1 ? "s" : ""); + } } private: @@ -503,8 +866,21 @@ class ShapePatternLayoutImpl { } bool Match(Shape* shape, MatchOption option) const { - return LayoutUtil::HasLayout(*shape) && - layout_.Match(shape->mutable_layout(), option); + if (!LayoutUtil::HasLayout(*shape)) { + EXPLAIN << "Shape does not have a layout"; + return false; + } + if (!layout_.Match(shape->mutable_layout(), option)) { + EXPLAIN << "\nin layout"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with"; + Indent(os, indent + kIndentInc); + layout_.DescribeTo(os, indent + kIndentInc); } private: @@ -522,17 +898,40 @@ class ShapePatternSubshapeImpl { : index_(index), subshape_(subshape) {} bool Match(const ::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::IndexIsValid(*shape, index_) && - subshape_.Match(&ShapeUtil::GetSubshape(*shape, index_), option); + return MatchImpl(shape, option); } bool Match(::xla::Shape* shape, MatchOption option) const { - return ShapeUtil::IndexIsValid(*shape, index_) && - subshape_.Match(ShapeUtil::GetMutableSubshape(shape, index_), - option); + return MatchImpl(shape, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with subshape at index " << index_.ToString() << " which is"; + Indent(os, indent + kIndentInc); + subshape_.DescribeTo(os, indent + kIndentInc); } private: + Shape* GetSubshape(Shape* shape) const { + return ShapeUtil::GetMutableSubshape(shape, index_); + } + const Shape* GetSubshape(const Shape* shape) const { + return &ShapeUtil::GetSubshape(*shape, index_); + } + + template + bool MatchImpl(ShapeType* shape, MatchOption option) const { + if (!ShapeUtil::IndexIsValid(*shape, index_)) { + EXPLAIN << "No subshape at " << index_.ToString(); + return false; + } + if (!subshape_.Match(GetSubshape(shape), option)) { + EXPLAIN << "\nin subshape at " << index_.ToString(); + return false; + } + return true; + } + ShapeIndexView index_; ShapePattern subshape_; }; @@ -542,10 +941,12 @@ template class ShapePattern { private: template - ShapePattern> AppendImpl( - NewImpl new_impl) const { - return ShapePattern>( - AllOf(impl_, std::move(new_impl)), matched_shape_); + auto AppendImpl(NewImpl new_impl) const + -> ShapePattern(std::declval(), + std::move(new_impl)))> { + auto new_all_of = AllOf(impl_, std::move(new_impl)); + return ShapePattern(std::move(new_all_of), + matched_shape_); } public: @@ -560,6 +961,11 @@ class ShapePattern { } return true; } + if (shape) { + EXPLAIN << "\nin " + << (shape->has_layout() ? ShapeUtil::HumanStringWithLayout(*shape) + : ShapeUtil::HumanString(*shape)); + } return false; } @@ -571,9 +977,16 @@ class ShapePattern { } return true; } + EXPLAIN << "\nin " + << (shape->has_layout() ? ShapeUtil::HumanStringWithLayout(*shape) + : ShapeUtil::HumanString(*shape)); return false; } + void DescribeTo(std::ostream* os, int64 indent = 0) const { + return impl_.DescribeTo(os, indent); + } + // Modifies the pattern to match only if the shape equals the given proto. // The layout must outlive the returned pattern. constexpr auto EqualTo(const ::xla::Shape* shape) const @@ -612,6 +1025,11 @@ class ShapePattern { return AppendImpl(ShapePatternIsTupleImpl()); } + constexpr auto IsEffectiveScalar() const + -> decltype(this->AppendImpl(ShapePatternEffectiveScalarImpl())) { + return AppendImpl(ShapePatternEffectiveScalarImpl()); + } + // Modifies the pattern to match only if the shape has the given rank. constexpr auto WithRank(int64 rank) const -> decltype(this->AppendImpl(ShapePatternRankImpl(rank))) { @@ -706,6 +1124,15 @@ Shape(::xla::Shape** matched_shape) { namespace detail { +// Overloads to get a const or non-const operand out of an instruction. +inline HloInstruction* HloOperand(HloInstruction* instr, int64 idx) { + return instr->mutable_operand(idx); +} +inline const HloInstruction* HloOperand(const HloInstruction* instr, + int64 idx) { + return instr->operand(idx); +} + template class HloInstructionPattern; @@ -714,8 +1141,18 @@ class HloInstructionPattern; class HloInstructionPatternBaseImpl { public: bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return inst != nullptr; + if (inst == nullptr) { + EXPLAIN << "HloInstruction* is null"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "an HloInstruction"; } + + static constexpr bool kIsTrivialMatcher = true; }; // An HloInstructionPattern implementation that matches only if the instruction @@ -726,13 +1163,44 @@ class HloInstructionPatternNameImpl { : name_(name) {} bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return inst->name() == name_; + if (inst->name() != name_) { + EXPLAIN << "HloInstruction not named \"" << name_ << "\""; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "named \"" << name_ << "\""; } private: absl::string_view name_; }; +// An HloInstructionPattern implementation that matches only if the instruction +// equals a particular pointer. +class HloInstructionIsImpl { + public: + explicit HloInstructionIsImpl(const HloInstruction* inst) : inst_(inst) {} + + bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { + if (inst != inst_) { + EXPLAIN << "HloInstruction " << inst << " is not " << inst_ << " (" + << inst_->ToShortString() << ")"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "which is " << inst_ << " (" << inst_->ToShortString() << ")"; + } + + private: + const HloInstruction* inst_; +}; + // An HloInstructionPattern implementation that matches only if the instruction // has a given opcode. class HloInstructionPatternOpcodeImpl { @@ -742,7 +1210,25 @@ class HloInstructionPatternOpcodeImpl { : opcode_(opcode), invert_(invert) {} bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return (invert_ ^ (inst->opcode() == opcode_)); + if (invert_ && inst->opcode() == opcode_) { + EXPLAIN << "HloInstruction has opcode " << HloOpcodeString(opcode_) + << ", expected anything else"; + return false; + } + if (!invert_ && inst->opcode() != opcode_) { + EXPLAIN << "HloInstruction doesn't have opcode " + << HloOpcodeString(opcode_); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + if (!invert_) { + *os << "with opcode " << HloOpcodeString(opcode_); + } else { + *os << "with any opcode other than " << HloOpcodeString(opcode_); + } } private: @@ -757,8 +1243,17 @@ class HloInstructionPatternNumOperandsImpl { explicit constexpr HloInstructionPatternNumOperandsImpl(int64 num_operands) : num_operands_(num_operands) {} - bool Match(const ::xla::HloInstruction* inst, MatchOption /*option*/) const { - return inst->operand_count() == num_operands_; + bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { + if (inst->operand_count() != num_operands_) { + EXPLAIN << "HloInstruction doesn't have " << num_operands_ << " operands"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with " << num_operands_ << " operand" + << (num_operands_ != 1 ? "s" : ""); } private: @@ -775,11 +1270,25 @@ class HloInstructionPatternShapeImpl { : shape_(shape) {} bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return shape_.Match(&inst->shape(), option); + if (!shape_.Match(&inst->shape(), option)) { + EXPLAIN << "\nin output shape"; + return false; + } + return true; } bool Match(::xla::HloInstruction* inst, MatchOption option) const { - return shape_.Match(inst->mutable_shape(), option); + if (!shape_.Match(inst->mutable_shape(), option)) { + EXPLAIN << "\nin output shape"; + return false; + } + return true; + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "outputting"; + Indent(os, indent + kIndentInc); + shape_.DescribeTo(os, indent + kIndentInc); } private: @@ -797,20 +1306,197 @@ class HloInstructionPatternOperandImpl { : operand_index_(operand_index), operand_(operand) {} bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return operand_index_ < inst->operand_count() && - operand_.Match(inst->operand(operand_index_), option); + return MatchImpl(inst, option); } bool Match(::xla::HloInstruction* inst, MatchOption option) const { - return operand_index_ < inst->operand_count() && - operand_.Match(inst->mutable_operand(operand_index_), option); + return MatchImpl(inst, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with operand " << operand_index_ << " which is:"; + Indent(os, indent + kIndentInc); + operand_.DescribeTo(os, indent + kIndentInc); } private: + template + bool MatchImpl(HloInstructionType* inst, MatchOption option) const { + if (operand_index_ >= inst->operand_count()) { + EXPLAIN << "desired operand index " << operand_index_ + << " is out of bounds"; + return false; + } + if (!operand_.Match(HloOperand(inst, operand_index_), option)) { + EXPLAIN << "\nin operand " << operand_index_; + return false; + } + return true; + } + int64 operand_index_; HloInstructionPattern operand_; }; +// Matches a binary instruction whose operands come in any order. +template +class HloInstructionPatternBinaryOperandsAnyOrderImpl { + public: + explicit constexpr HloInstructionPatternBinaryOperandsAnyOrderImpl( + const HloInstructionPattern& op1, + const HloInstructionPattern& op2) + : op1_(op1), op2_(op2) {} + + bool Match(HloInstruction* inst, MatchOption option) const { + return MatchImpl(inst, option); + } + + bool Match(const HloInstruction* inst, MatchOption option) const { + return MatchImpl(inst, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with two operands in either order:"; + Indent(os, indent); + *os << " - "; + op1_.DescribeTo(os, indent + 3); + Indent(os, indent); + *os << " - "; + op2_.DescribeTo(os, indent + 3); + } + + private: + HloInstruction* operand(HloInstruction* inst, int64 idx) const { + return inst->mutable_operand(idx); + } + const HloInstruction* operand(const HloInstruction* inst, int64 idx) const { + return inst->operand(idx); + } + + template + bool MatchImpl(HloInstructionType* inst, MatchOption option) const { + // We could implement this using AnyOf and AllOf matchers, but the templates + // get pretty difficult to debug, since any compile error herein becomes + // not-an-error via SFINAE. Also this way lets us give better messages on + // failure. + if (inst->operand_count() != 2) { + EXPLAIN << "HloInstruction did not have two operands"; + return false; + } + + // If we're not generating explanations, this is pretty simple. + if (!option.explain_os) { + auto try_match = [&](int64 idx1, int64 idx2) { + MatchOption new_option = option; + new_option.capture = false; + if (op1_.Match(operand(inst, idx1), new_option) && + op2_.Match(operand(inst, idx2), new_option)) { + if (option.capture) { + bool matched = op1_.Match(operand(inst, idx1), option) && + op2_.Match(operand(inst, idx2), option); + DCHECK(matched); + } + return true; + } + return false; + }; + return try_match(0, 1) || try_match(1, 0); + } + + // If we are generating explanations, we have some work to do in order to + // generate a helpful error. + // + // First, try all four operand/matcher combinations, recording the + // failure explanations separately from option.explain_os. matches[i][j] + // tells us if matcher_i matches operand j. + bool matches[/*matcher*/ 2][/*operand*/ 2]; + std::stringstream explanations[/*matcher*/ 2][/*operand*/ 2]; + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + MatchOption new_option = option; + new_option.capture = false; + new_option.explain_os = &explanations[i][j]; + matches[i][j] = i == 0 ? op1_.Match(operand(inst, j), new_option) + : op2_.Match(operand(inst, j), new_option); + } + } + + // Check if the match succeeded. + for (int i = 0; i < 2; ++i) { + if (matches[0][i] && matches[1][(i + 1) % 2]) { + // Rerun the matches with capture enabled if necessary. + if (option.capture) { + auto* operand1 = operand(inst, i); + auto* operand2 = operand(inst, (i + 1) % 2); + bool matched = + op1_.Match(operand1, option) && op2_.Match(operand2, option); + DCHECK(matched); + } + return true; + } + } + + auto describe_matcher = [&](int matcher_idx) { + EXPLAIN << "\n - "; + if (matcher_idx == 0) { + op1_.DescribeTo(option.explain_os, /*indent=*/3); + } else { + CHECK_EQ(matcher_idx, 1); + op2_.DescribeTo(option.explain_os, /*indent=*/3); + } + for (int i = 0; i < 2; ++i) { + if (matches[matcher_idx][/*operand*/ i]) { + continue; + } + EXPLAIN << "\ndoes not match " << (i == 0 ? "LHS" : "RHS") << ":\n"; + EXPLAIN << " - "; + EXPLAIN << absl::StrReplaceAll( + explanations[matcher_idx][/*operand*/ i].str(), {{"\n", "\n "}}); + } + }; + + // If we failed to match, one of the following is true: + // 1. op1 (op2) matches neither LHS nor RHS, or + // 2. op1 and op2 both match LHS (RHS), but neither matches RHS (LHS). + // We print different explanations depending on which case we're in. + + // Case 1. + bool wrote_explanation = false; + for (int i = 0; !wrote_explanation && i < 2; ++i) { + if (!matches[i][0] && !matches[i][1]) { + EXPLAIN << "HloInstruction's operands (ignoring order) did not match " + << (i == 0 ? "first" : "second") << " matcher. Specifically,"; + describe_matcher(i); + wrote_explanation = true; + } + } + + // Case 2. + for (int i = 0; !wrote_explanation && i < 2; ++i) { + if (matches[/*matcher*/ 0][/*operand*/ i] && + matches[/*matcher*/ 1][/*operand*/ i]) { + CHECK(!matches[0][(i + 1) % 2]); + CHECK(!matches[1][(i + 1) % 2]); + CHECK(!wrote_explanation); + EXPLAIN << "HloInstruction's " << (i == 1 ? "LHS" : "RHS") + << " operand did not match either of the two matchers. " + "Specifically,"; + describe_matcher(0); + EXPLAIN << "\nand"; + describe_matcher(1); + wrote_explanation = true; + } + } + + CHECK(wrote_explanation); + return false; + } + + HloInstructionPattern op1_; + HloInstructionPattern op2_; +}; + // An HloInstructionPattern implementation that matches only if the instruction // is a fusion node with a particular kind. class HloInstructionPatternFusionKindImpl { @@ -820,14 +1506,32 @@ class HloInstructionPatternFusionKindImpl { : kind_(kind) {} bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return inst->opcode() == HloOpcode::kFusion && inst->fusion_kind() == kind_; + return MatchImpl(inst, option); } bool Match(::xla::HloInstruction* inst, MatchOption option) const { - return inst->opcode() == HloOpcode::kFusion && inst->fusion_kind() == kind_; + return MatchImpl(inst, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "with fusion kind " << ToString(kind_); } private: + template + bool MatchImpl(HloInstructionType* inst, MatchOption option) const { + if (inst->opcode() != HloOpcode::kFusion) { + EXPLAIN << "HloInstruction does not have fusion kind " << ToString(kind_) + << "; it's not a fusion"; + return false; + } + if (inst->fusion_kind() != kind_) { + EXPLAIN << "HloInstruction does not have fusion kind " << ToString(kind_); + return false; + } + return true; + } + ::xla::HloInstruction::FusionKind kind_; }; @@ -839,47 +1543,153 @@ class HloInstructionPatternTupleIndexImpl { : tuple_index_(tuple_index) {} bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { - return inst->opcode() == HloOpcode::kGetTupleElement && - inst->tuple_index() == tuple_index_; + return MatchImpl(inst, option); } bool Match(::xla::HloInstruction* inst, MatchOption option) const { - return inst->opcode() == HloOpcode::kGetTupleElement && - inst->tuple_index() == tuple_index_; + return MatchImpl(inst, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "which is a GTE with index " << tuple_index_; } private: + template + bool MatchImpl(HloInstructionType* inst, MatchOption option) const { + if (inst->opcode() != HloOpcode::kGetTupleElement) { + EXPLAIN << "HloInstruction is not a GTE with index " << tuple_index_ + << "; it's not a GTE at all"; + return false; + } + if (inst->tuple_index() != tuple_index_) { + EXPLAIN << "HloInstruction is not a GTE with index " << tuple_index_; + return false; + } + return true; + } + int64 tuple_index_; }; -template -class HloPredicatePatternImpl { +class HloInstructionPatternParameterNumImpl { public: - explicit HloPredicatePatternImpl(Predicate pred) : pred_(std::move(pred)) {} + explicit constexpr HloInstructionPatternParameterNumImpl(int64 parameter_num) + : parameter_num_(parameter_num) {} - bool Match(const ItemType* item, MatchOption option) const { - return pred_(item); + bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { + return MatchImpl(inst, option); } - bool Match(ItemType* item, MatchOption option) const { return pred_(item); } + bool Match(::xla::HloInstruction* inst, MatchOption option) const { + return MatchImpl(inst, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "which is parameter " << parameter_num_; + } private: - Predicate pred_; + template + bool MatchImpl(HloInstructionType* inst, MatchOption option) const { + if (inst->opcode() != HloOpcode::kParameter || + inst->parameter_number() != parameter_num_) { + EXPLAIN << "HloInstruction is not parameter " << parameter_num_; + return false; + } + return true; + } + + int64 parameter_num_; }; -struct PatternFriend; +// Matches a constant scalar or effective scalar, optionally with a given value. +template +class HloConstantScalarImpl { + public: + explicit constexpr HloConstantScalarImpl(bool match_effective_scalar) + : val_(absl::nullopt), match_effective_scalar_(match_effective_scalar) {} + + constexpr HloConstantScalarImpl(ScalarTy val, bool match_effective_scalar) + : val_(val), match_effective_scalar_(match_effective_scalar) {} + + bool Match(const ::xla::HloInstruction* inst, MatchOption option) const { + return MatchImpl(inst, option); + } + + bool Match(::xla::HloInstruction* inst, MatchOption option) const { + return MatchImpl(inst, option); + } + + void DescribeTo(std::ostream* os, int64 indent = 0) const { + *os << "which is a constant " + << (match_effective_scalar_ ? "effective " : "") << "scalar"; + if (val_.has_value()) { + *os << " with value " << *val_; + } + } + + private: + template + bool MatchImpl(InstTy* inst, MatchOption option) const { + const auto* const_inst = DynCast(inst); + if (!const_inst) { + EXPLAIN << "HloInstruction is not a constant"; + return false; + } + if (match_effective_scalar_ && + !ShapeUtil::IsEffectiveScalar(inst->shape())) { + EXPLAIN << "HloInstruction is not an effective scalar"; + return false; + } + if (!match_effective_scalar_ && !ShapeUtil::IsScalar(inst->shape())) { + EXPLAIN << "HloInstruction is not a scalar"; + return false; + } + if (!val_.has_value()) { + return true; + } + + // Check that literal == static_cast(val) and + // val == static_cast(literal). This is sufficient to ensure that + // the two constant scalars are actually "equal". + auto val_literal = LiteralUtil::CreateR0(*val_); + auto literal_r0_or = const_inst->literal().Reshape({}); + auto val_as_literal_ty_or = + val_literal.Convert(const_inst->shape().element_type()); + if (!literal_r0_or.ok() || !val_as_literal_ty_or.ok()) { + EXPLAIN << "could not construct relevant Literals (how did this happen?)"; + return false; + } + auto literal_r0 = std::move(literal_r0_or).ValueOrDie(); + auto val_as_literal_ty = std::move(val_as_literal_ty_or).ValueOrDie(); + auto literal_r0_as_val_ty_or = + literal_r0.Convert(val_literal.shape().element_type()); + bool rv = literal_r0_as_val_ty_or.ok() && // + literal_r0_as_val_ty_or.ValueOrDie() == val_literal && + literal_r0 == val_as_literal_ty; + if (!rv) { + EXPLAIN << "HloInstruction's constant value " << literal_r0.ToString() + << " did not match expected value " << *val_; + } + return rv; + } + + absl::optional val_; + bool match_effective_scalar_; +}; // A pattern that matches HloInstructions. template class HloInstructionPattern { private: template - HloInstructionPattern> - AppendImpl(NewImpl new_impl) const { - return HloInstructionPattern< - HloInstructionType, AllOfPattern<::xla::HloInstruction, Impl, NewImpl>>( - AllOf(impl_, std::move(new_impl)), matched_inst_); + auto AppendImpl(NewImpl new_impl) const -> HloInstructionPattern< + HloInstructionType, decltype(AllOf( + std::declval(), std::move(new_impl)))> { + auto new_allof = AllOf(impl_, std::move(new_impl)); + return HloInstructionPattern( + std::move(new_allof), matched_inst_); } public: @@ -895,6 +1705,12 @@ class HloInstructionPattern { } return true; } + if (inst != nullptr) { + EXPLAIN << "\nin " + << inst->ToString(HloPrintOptions() + .set_print_metadata(false) + .set_print_percent(false)); + } return false; } @@ -906,6 +1722,10 @@ class HloInstructionPattern { } return true; } + EXPLAIN << "\nin " + << inst->ToString(HloPrintOptions() + .set_print_metadata(false) + .set_print_percent(false)); return false; } @@ -935,12 +1755,47 @@ class HloInstructionPattern { return AppendImpl(HloInstructionPatternOpcodeImpl(opcode, true)); } + constexpr auto Is(const HloInstruction* instr) const + -> decltype(this->AppendImpl(HloInstructionIsImpl(instr))) { + return AppendImpl(HloInstructionIsImpl(instr)); + } + // Modifies the pattern to match only if the instruction is a constant. constexpr auto IsConstant() const -> decltype(this->WithOpcode(HloOpcode::kConstant)) { return WithOpcode(HloOpcode::kConstant); } + constexpr auto IsConstantScalar() const -> decltype(this->AppendImpl( + HloConstantScalarImpl(/*match_effective_scalar=*/false))) { + return AppendImpl( + HloConstantScalarImpl(/*match_effective_scalar=*/false)); + } + + // This does not check that T has the same type as the instruction, so e.g. + // IsConstantScalar(1.0) may match a constant of shape int32[]. + template + constexpr auto IsConstantScalar(const ScalarTy& val) const + -> decltype(this->AppendImpl(HloConstantScalarImpl( + val, /*match_effective_scalar=*/false))) { + return AppendImpl( + HloConstantScalarImpl(val, /*match_effective_scalar=*/false)); + } + + constexpr auto IsConstantEffectiveScalar() const -> decltype(this->AppendImpl( + HloConstantScalarImpl(/*match_effective_scalar=*/true))) { + return AppendImpl( + HloConstantScalarImpl(/*match_effective_scalar=*/true)); + } + + template + constexpr auto IsConstantEffectiveScalar(const ScalarTy& val) const + -> decltype(this->AppendImpl(HloConstantScalarImpl( + val, /*match_effective_scalar=*/true))) { + return AppendImpl( + HloConstantScalarImpl(val, /*match_effective_scalar=*/true)); + } + // Modifies the pattern to match only if the instruction is not a constant. constexpr auto IsNonConstant() const -> decltype(this->WithoutOpcode(HloOpcode::kConstant)) { @@ -957,6 +1812,22 @@ class HloInstructionPattern { HloInstructionPatternShapeImpl(shape)); } + // Make this a templated function to work around gcc 4.9.4 template infinite + // recursion bug. + template + constexpr auto WithShapeEqualTo(const ::xla::Shape* shape) + -> decltype(this->WithShape(Shape().EqualTo(shape))) { + return WithShape(Shape().EqualTo(shape)); + } + + // Make this a templated function to work around gcc 4.9.4 template infinite + // recursion bug. + template + constexpr auto WithShapeCompatibleTo(const ::xla::Shape* shape) + -> decltype(this->WithShape(Shape().CompatibleTo(shape))) { + return WithShape(Shape().CompatibleTo(shape)); + } + // Modifies the pattern to match only if the instruction has an operand that // matches the given pattern. template @@ -971,6 +1842,20 @@ class HloInstructionPattern { operand_index, operand)); } + template + constexpr auto WithBinaryOperandsAnyOrder( + const HloInstructionPattern& op1, + const HloInstructionPattern& op2) const + -> decltype(this->AppendImpl( + HloInstructionPatternBinaryOperandsAnyOrderImpl< + OperandType1, OperandImpl1, OperandType2, OperandImpl2>(op1, + op2))) { + return AppendImpl( + HloInstructionPatternBinaryOperandsAnyOrderImpl< + OperandType1, OperandImpl1, OperandType2, OperandImpl2>(op1, op2)); + } + // Modifies the pattern to match only if the instruction is a fusion node with // the given kind. constexpr auto WithFusionKind(HloInstruction::FusionKind kind) const @@ -985,17 +1870,18 @@ class HloInstructionPattern { return AppendImpl(HloInstructionPatternTupleIndexImpl(tuple_index)); } - private: - template - constexpr auto WithPredicate(Predicate pred) const -> decltype( - this->AppendImpl(HloPredicatePatternImpl( - std::move(pred)))) { - return AppendImpl( - HloPredicatePatternImpl(std::move(pred))); + // Modifies the pattern to match only if the instruction is a parameter + // with the given parameter number. + constexpr auto WithParameterNum(int64 parameter_num) const -> decltype( + this->AppendImpl(HloInstructionPatternParameterNumImpl(parameter_num))) { + return AppendImpl(HloInstructionPatternParameterNumImpl(parameter_num)); } - friend struct PatternFriend; + void DescribeTo(std::ostream* os, int64 indent = 0) const { + impl_.DescribeTo(os, indent); + } + private: Impl impl_; HloInstructionType** matched_inst_; }; @@ -1090,6 +1976,7 @@ XLA_UNOP_PATTERN(Reverse) XLA_UNOP_PATTERN(SendDone) XLA_UNOP_PATTERN(Sign) XLA_UNOP_PATTERN(Sin) +XLA_UNOP_PATTERN(Slice) XLA_UNOP_PATTERN(Sort) XLA_UNOP_PATTERN(Tanh) XLA_UNOP_PATTERN(Transpose) @@ -1127,25 +2014,32 @@ XLA_UNOP_PATTERN(Transpose) #define XLA_COMMUTATIVE_BINOP_PATTERN(NAME) \ XLA_BINOP_PATTERN(NAME) \ \ - template \ - inline auto NAME##AnyOrder(Lhs&& lhs, Rhs&& rhs) \ - ->decltype(AnyOf(NAME(lhs, rhs), NAME(rhs, lhs))) { \ - return AnyOf(NAME(lhs, rhs), NAME(rhs, lhs)); \ - } \ - \ template \ inline auto NAME##AnyOrder(HloInstructionType** matched_inst, Lhs&& lhs, \ Rhs&& rhs) \ - ->decltype(AnyOf(NAME(matched_inst, lhs, rhs), \ - NAME(matched_inst, rhs, lhs))) { \ - return AnyOf(NAME(matched_inst, lhs, rhs), \ - NAME(matched_inst, rhs, lhs)); \ + ->decltype(Op(matched_inst) \ + .WithOpcode(HloOpcode::k##NAME) \ + .WithBinaryOperandsAnyOrder(std::forward(lhs), \ + std::forward(rhs))) { \ + return Op(matched_inst) \ + .WithOpcode(HloOpcode::k##NAME) \ + .WithBinaryOperandsAnyOrder(std::forward(lhs), \ + std::forward(rhs)); \ + } \ + template \ + inline auto NAME##AnyOrder(Lhs&& lhs, Rhs&& rhs) \ + ->decltype(NAME##AnyOrder( \ + nullptr, std::forward(lhs), std::forward(rhs))) { \ + return NAME##AnyOrder(nullptr, std::forward(lhs), \ + std::forward(rhs)); \ } XLA_COMMUTATIVE_BINOP_PATTERN(Add) XLA_BINOP_PATTERN(Atan2) XLA_BINOP_PATTERN(Divide) XLA_BINOP_PATTERN(Complex) +XLA_BINOP_PATTERN(Convolution) XLA_BINOP_PATTERN(Dot) +XLA_BINOP_PATTERN(DynamicSlice) XLA_COMMUTATIVE_BINOP_PATTERN(Eq) XLA_BINOP_PATTERN(Gather) XLA_BINOP_PATTERN(Ge) @@ -1157,6 +2051,7 @@ XLA_COMMUTATIVE_BINOP_PATTERN(Minimum) XLA_COMMUTATIVE_BINOP_PATTERN(Multiply) XLA_COMMUTATIVE_BINOP_PATTERN(Ne) XLA_BINOP_PATTERN(Outfeed) +XLA_BINOP_PATTERN(Pad) XLA_BINOP_PATTERN(Power) XLA_BINOP_PATTERN(Remainder) XLA_BINOP_PATTERN(Send) @@ -1257,31 +2152,9 @@ inline auto WithOperands(Matcher&& m, int64 operand_num, FirstArg&& first_arg, // We could implement all ops as "variadic" ops, but it would make the // already-bad compile errors even worse. XLA_VARIADIC_OP_PATTERN(Concatenate); +XLA_VARIADIC_OP_PATTERN(CustomCall); XLA_VARIADIC_OP_PATTERN(Reduce); - -namespace detail { -struct PatternFriend { - template - static auto ConstantScalar(T constant) -> decltype( - Constant() - .WithShape(match::Shape().IsScalar()) - .WithPredicate( - std::declval>())) { - std::function pred = - [constant](const HloInstruction* instr) { - const auto& literal = Cast(instr)->literal(); - auto status_or_const = LiteralUtil::CreateR0(constant).Convert( - literal.shape().element_type()); - return status_or_const.ok() && - literal == status_or_const.ConsumeValueOrDie(); - }; - - return Constant() - .WithShape(match::Shape().IsScalar()) - .WithPredicate(std::move(pred)); - } -}; -} // namespace detail +XLA_VARIADIC_OP_PATTERN(Tuple); // Helpers for matching non-constant instructions. inline auto NonConstant() -> decltype(Op().IsNonConstant()) { @@ -1320,14 +2193,71 @@ inline auto GetTupleElement(HloInstructionType** matched_inst, Arg&& arg, .WithTupleIndex(tuple_index); } -template -inline auto ConstantScalar(T constant) - -> decltype(detail::PatternFriend::ConstantScalar(constant)) { - return detail::PatternFriend::ConstantScalar(constant); +// Add overloads for Parameter which take an int64 specifying the parameter +// number. +inline auto Parameter(int64 parameter_num) -> decltype( + Op().WithOpcode(HloOpcode::kParameter).WithParameterNum(parameter_num)) { + return Op().WithOpcode(HloOpcode::kParameter).WithParameterNum(parameter_num); +} +template +inline auto Parameter(HloInstructionType** matched_inst, int64 parameter_num) + -> decltype(Op(matched_inst) + .WithOpcode(HloOpcode::kParameter) + .WithParameterNum(parameter_num)) { + return Op(matched_inst) + .WithOpcode(HloOpcode::kParameter) + .WithParameterNum(parameter_num); +} + +inline auto ConstantScalar() -> decltype(Op().IsConstantScalar()) { + return Op().IsConstantScalar(); +} + +template +inline auto ConstantScalar(HloInstructionType** matched_inst) + -> decltype(Op(matched_inst).IsConstantScalar()) { + return Op(matched_inst).IsConstantScalar(); +} + +template +inline auto ConstantScalar(ScalarTy val) + -> decltype(Op().IsConstantScalar(val)) { + return Op().IsConstantScalar(val); +} + +template +inline auto ConstantScalar(HloInstructionType** matched_inst, ScalarTy val) + -> decltype(Op(matched_inst).IsConstantScalar(val)) { + return Op(matched_inst).IsConstantScalar(val); +} + +inline auto ConstantEffectiveScalar() -> decltype(Op().IsConstantScalar()) { + return Op().IsConstantEffectiveScalar(); +} + +template +inline auto ConstantEffectiveScalar(HloInstructionType** matched_inst) + -> decltype(Op(matched_inst).IsConstantScalar()) { + return Op(matched_inst).IsConstantEffectiveScalar(); +} + +template +inline auto ConstantEffectiveScalar(ScalarTy val) + -> decltype(Op().IsConstantEffectiveScalar(val)) { + return Op().IsConstantEffectiveScalar(val); +} + +template +inline auto ConstantEffectiveScalar(HloInstructionType** matched_inst, + ScalarTy val) + -> decltype(Op(matched_inst).IsConstantEffectiveScalar(val)) { + return Op(matched_inst).IsConstantEffectiveScalar(val); } } // namespace match } // namespace xla +#undef EXPLAIN +#pragma pop_macro("EXPLAIN") #endif // TENSORFLOW_COMPILER_XLA_SERVICE_PATTERN_MATCHER_H_ diff --git a/tensorflow/compiler/xla/service/pattern_matcher_gmock.h b/tensorflow/compiler/xla/service/pattern_matcher_gmock.h new file mode 100644 index 0000000000..8fe2d10a11 --- /dev/null +++ b/tensorflow/compiler/xla/service/pattern_matcher_gmock.h @@ -0,0 +1,92 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_PATTERN_MATCHER_GMOCK_H_ +#define TENSORFLOW_COMPILER_XLA_SERVICE_PATTERN_MATCHER_GMOCK_H_ + +#include +#include "tensorflow/compiler/xla/service/pattern_matcher.h" +#include "tensorflow/compiler/xla/test.h" +#include "tensorflow/core/platform/test.h" + +namespace xla { + +namespace pattern_matcher_gmock_detail { +template +class GmockMatcher { + public: + explicit GmockMatcher(Pattern p) : pattern_(std::move(p)) {} + + // In service of better error messages, list out the overloads explicitly + // rather than just using a template. gMock's polymorphism plus + // pattern_matcher yields some pretty gnarly stuff. + bool MatchAndExplain(const Layout& l, + ::testing::MatchResultListener* listener) const { + return MatchAndExplainImpl(&l, listener); + } + bool MatchAndExplain(const Layout* l, + ::testing::MatchResultListener* listener) const { + return MatchAndExplainImpl(l, listener); + } + + bool MatchAndExplain(const Shape& s, + ::testing::MatchResultListener* listener) const { + return MatchAndExplainImpl(&s, listener); + } + bool MatchAndExplain(const Shape* s, + ::testing::MatchResultListener* listener) const { + return MatchAndExplainImpl(s, listener); + } + + bool MatchAndExplain(const HloInstruction& instr, + ::testing::MatchResultListener* listener) const { + return MatchAndExplainImpl(&instr, listener); + } + bool MatchAndExplain(const HloInstruction* instr, + ::testing::MatchResultListener* listener) const { + return MatchAndExplainImpl(instr, listener); + } + + void DescribeTo(std::ostream* os) const { pattern_.DescribeTo(os); } + + void DescribeNegationTo(std::ostream* os) const { + *os << "is NOT: "; + DescribeTo(os); + } + + private: + template + bool MatchAndExplainImpl(const T* t, + ::testing::MatchResultListener* listener) const { + MatchOption options{/*.capture=*/true, /*.explain_os=*/listener->stream()}; + return Match(t, pattern_, options); + } + + Pattern pattern_; +}; +} // namespace pattern_matcher_gmock_detail + +template +::testing::PolymorphicMatcher< + pattern_matcher_gmock_detail::GmockMatcher> +GmockMatch(Pattern&& p) { + return ::testing::MakePolymorphicMatcher( + pattern_matcher_gmock_detail::GmockMatcher( + std::forward(p))); +} + +} // namespace xla + +#endif // TENSORFLOW_COMPILER_XLA_SERVICE_PATTERN_MATCHER_GMOCK_H_ diff --git a/tensorflow/compiler/xla/service/pattern_matcher_gmock_test.cc b/tensorflow/compiler/xla/service/pattern_matcher_gmock_test.cc new file mode 100644 index 0000000000..9ca2fb05c1 --- /dev/null +++ b/tensorflow/compiler/xla/service/pattern_matcher_gmock_test.cc @@ -0,0 +1,76 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/compiler/xla/service/pattern_matcher_gmock.h" +#include "tensorflow/compiler/xla/service/pattern_matcher.h" +#include "tensorflow/compiler/xla/shape_util.h" +#include "tensorflow/compiler/xla/test.h" +#include "tensorflow/core/platform/test.h" + +namespace xla { +namespace { + +namespace m = ::xla::match; +using ::testing::Eq; +using ::testing::Not; + +template +string Describe(const ::testing::Matcher& m) { + std::stringstream ss; + m.DescribeTo(&ss); + return ss.str(); +} + +template +string Explain( + const MatchedTy& val, + const ::testing::Matcher::type>& m) { + ::testing::StringMatchResultListener listener; + EXPECT_THAT(val, ::testing::Not(m)); // For the error message. + EXPECT_FALSE(m.MatchAndExplain(val, &listener)); + return listener.str(); +} + +// This file tests the GmockMatch function. The actual explanation and +// description returned by matchers is tested in pattern_matchers_test. +TEST(PatternMatcherGmock, MatchShape) { + Shape s = ShapeUtil::MakeShape(F32, {10, 100}); + // You can pass const Shape& or a const Shape*. + EXPECT_THAT(s, GmockMatch(m::Shape())); + EXPECT_THAT(&s, Not(GmockMatch(m::Shape().WithElementType(F16)))); + EXPECT_THAT(Describe(GmockMatch(m::Shape().IsArray())), + "a shape that represents an array"); +} + +TEST(PatternMatcherGmock, MatchLayout) { + Layout l = LayoutUtil::MakeLayout({0, 1}); + EXPECT_THAT(l, GmockMatch(m::Layout())); + EXPECT_THAT(&l, Not(GmockMatch(m::Layout().WithSparseFormat()))); + EXPECT_THAT(Describe(GmockMatch(m::Layout().WithSparseFormat())), + "a layout with format SPARSE"); +} + +TEST(PatternMatchGmock, MatchInstruction) { + auto instr = + HloInstruction::CreateParameter(0, ShapeUtil::MakeShape(F32, {42}), "p"); + EXPECT_THAT(instr.get(), GmockMatch(m::Parameter())); + EXPECT_THAT(*instr, GmockMatch(m::Parameter(0))); + EXPECT_THAT(*instr, Not(GmockMatch(m::Parameter(1)))); + EXPECT_THAT(Describe(GmockMatch(m::Parameter())), + "an HloInstruction with opcode parameter"); +} + +} // anonymous namespace +} // namespace xla diff --git a/tensorflow/compiler/xla/service/pattern_matcher_test.cc b/tensorflow/compiler/xla/service/pattern_matcher_test.cc index 3f74273517..13886fa6f5 100644 --- a/tensorflow/compiler/xla/service/pattern_matcher_test.cc +++ b/tensorflow/compiler/xla/service/pattern_matcher_test.cc @@ -14,14 +14,18 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/compiler/xla/service/pattern_matcher.h" +#include "absl/strings/str_cat.h" #include "tensorflow/compiler/xla/service/hlo_instruction.h" #include "tensorflow/compiler/xla/service/hlo_opcode.h" #include "tensorflow/compiler/xla/service/hlo_parser.h" +#include "tensorflow/compiler/xla/test.h" #include "tensorflow/core/platform/test.h" namespace xla { namespace { +namespace m = match; + TEST(PatternMatcherTest, AddOp) { constexpr char kModuleStr[] = R"(HloModule two_plus_two_module ENTRY %two_plus_two_computation () -> f32[] { @@ -229,23 +233,74 @@ TEST(PatternMatcherTest, AnyOf) { } TEST(PatternMatcherTest, ConstantScalar) { - constexpr char kModuleStr[] = R"( - HloModule test_module ENTRY test { ROOT constant = f16[] constant(42) })"; - TF_ASSERT_OK_AND_ASSIGN(auto hlo_module, ParseHloString(kModuleStr)); - auto* root = hlo_module->entry_computation()->root_instruction(); - - EXPECT_TRUE(Match(root, match::ConstantScalar(42))); - EXPECT_FALSE(Match(root, match::ConstantScalar(41))); - EXPECT_FALSE(Match(root, match::ConstantScalar(0))); -} + using match::ConstantEffectiveScalar; + using match::ConstantScalar; + using match::Op; + using match::Tuple; -TEST(PatternMatcherTest, NoMatchConstantScalar) { constexpr char kModuleStr[] = R"( - HloModule test_module ENTRY test { ROOT v = f16[] parameter(0) })"; + HloModule test_module + ENTRY test { + a = s32[] constant(1) + b = s32[1,1] constant(s32[1,1]{{2}}) + c = s32[1,2] constant(s32[1,2]{{2,2}}) + d = f32[] constant(1) + e = f32[] constant(1.25) + ROOT tuple = (s32[], s32[1,1], s32[1,2], f32[], f32[]) tuple(a,b,c,d,e) + })"; TF_ASSERT_OK_AND_ASSIGN(auto hlo_module, ParseHloString(kModuleStr)); auto* root = hlo_module->entry_computation()->root_instruction(); - EXPECT_FALSE(Match(root, match::ConstantScalar(42))); + const HloInstruction* a = root->operand(0); + const HloInstruction* b = root->operand(1); + const HloInstruction* c = root->operand(2); + const HloInstruction* d = root->operand(3); + const HloInstruction* e = root->operand(4); + EXPECT_TRUE(Match(a, ConstantScalar())); + EXPECT_TRUE(Match(a, ConstantScalar(1))); + EXPECT_TRUE(Match(a, ConstantEffectiveScalar())); + EXPECT_TRUE(Match(a, ConstantEffectiveScalar(1))); + EXPECT_FALSE(Match(a, ConstantScalar(2))); + EXPECT_FALSE(Match(a, ConstantScalar(2.01))); + EXPECT_FALSE(Match(a, ConstantEffectiveScalar(2))); + EXPECT_FALSE(Match(a, ConstantEffectiveScalar(1.01))); + + EXPECT_FALSE(Match(b, ConstantScalar())); + EXPECT_FALSE(Match(b, ConstantScalar(2))); + EXPECT_TRUE(Match(b, ConstantEffectiveScalar())); + EXPECT_TRUE(Match(b, ConstantEffectiveScalar(2))); + + EXPECT_FALSE(Match(c, ConstantScalar())); + EXPECT_FALSE(Match(c, ConstantScalar(2))); + EXPECT_FALSE(Match(c, ConstantEffectiveScalar())); + EXPECT_FALSE(Match(c, ConstantEffectiveScalar(2))); + + EXPECT_TRUE(Match(d, ConstantScalar(1))); + EXPECT_TRUE(Match(d, ConstantEffectiveScalar(1))); + EXPECT_TRUE(Match(d, ConstantScalar(1.0))); + EXPECT_TRUE(Match(d, ConstantEffectiveScalar(1.0))); + + EXPECT_TRUE(Match(e, ConstantScalar(1.25f))); + EXPECT_TRUE(Match(e, ConstantScalar(1.25))); + EXPECT_TRUE(Match(e, ConstantEffectiveScalar(1.25))); + EXPECT_FALSE(Match(e, ConstantScalar(1))); + EXPECT_FALSE(Match(e, ConstantEffectiveScalar(1))); + + const HloInstruction* instr = nullptr; + EXPECT_TRUE(Match(a, ConstantScalar(&instr))); + EXPECT_EQ(instr, a); + + instr = nullptr; + EXPECT_TRUE(Match(a, ConstantScalar(&instr, 1))); + EXPECT_EQ(instr, a); + + instr = nullptr; + EXPECT_TRUE(Match(a, ConstantEffectiveScalar(&instr))); + EXPECT_EQ(instr, a); + + instr = nullptr; + EXPECT_TRUE(Match(a, ConstantEffectiveScalar(&instr, 1))); + EXPECT_EQ(instr, a); } TEST(PatternMatcherTest, MultiplyAnyOrder) { @@ -267,6 +322,15 @@ TEST(PatternMatcherTest, MultiplyAnyOrder) { root, MultiplyAnyOrder(&instr, ConstantScalar(42), ConstantScalar(52)))); EXPECT_TRUE(Match( root, MultiplyAnyOrder(&instr, ConstantScalar(52), ConstantScalar(42)))); + + // Check that MultiplyAnyOrder exposes the same API as Op(), so we can call + // e.g. IsNonConstant() on it. + EXPECT_TRUE(Match( + root, MultiplyAnyOrder(&instr, ConstantScalar(42), ConstantScalar(52)) + .IsNonConstant())); + EXPECT_TRUE( + Match(root, MultiplyAnyOrder(ConstantScalar(42), ConstantScalar(52)) + .IsNonConstant())); } TEST(PatternMatcherTest, AnyOfShortCircuit) { @@ -315,14 +379,22 @@ TEST(PatternMatcherTest, AllOf) { TF_ASSERT_OK_AND_ASSIGN(auto hlo_module, ParseHloString(kModuleStr)); auto* root = hlo_module->entry_computation()->root_instruction(); + auto f16_scalar = ShapeUtil::MakeShape(F16, {}); + auto f16_pattern = Constant().WithShapeEqualTo(&f16_scalar); + auto f16_compatible_pattern = Constant().WithShapeCompatibleTo(&f16_scalar); auto scalar_pattern = Constant().WithShape(match::Shape().IsScalar()); - auto f16_pattern = Constant().WithShape(match::Shape().WithElementType(F16)); ASSERT_TRUE(Match(root, scalar_pattern)); ASSERT_TRUE(Match(root, f16_pattern)); - EXPECT_TRUE(Match(root, AllOf(scalar_pattern, f16_pattern))); - EXPECT_TRUE(Match(root, AllOf(f16_pattern, scalar_pattern))); + ASSERT_TRUE(Match(root, f16_compatible_pattern)); + EXPECT_TRUE(Match(root, AllOf(scalar_pattern, f16_pattern, + f16_compatible_pattern))); + EXPECT_TRUE( + Match(root, AllOf(f16_pattern, f16_compatible_pattern, + scalar_pattern))); EXPECT_FALSE( Match(root, AllOf(Broadcast(Op()), f16_pattern))); + EXPECT_FALSE(Match( + root, AllOf(Broadcast(Op()), f16_compatible_pattern))); EXPECT_FALSE( Match(root, AllOf(Broadcast(Op()), scalar_pattern))); } @@ -431,5 +503,377 @@ TEST(PatternMatcherTest, TestConcat) { Reshape(ConstantScalar(4))))); } +template +string Description(const Pattern& pattern) { + std::stringstream ss; + pattern.DescribeTo(&ss); + return ss.str(); +} + +template +string Explanation(Elem* elem, const Pattern& pattern) { + std::stringstream ss; + MatchOption options{/*.capture=*/true, /*.explain_os=*/&ss}; + Match(elem, pattern, options); + return ss.str(); +} +template +string Explanation(const std::unique_ptr& elem, const Pattern& pattern) { + return Explanation(elem.get(), pattern); +} +template +string Explanation(const Elem& elem, const Pattern& pattern) { + return Explanation(&elem, pattern); +} + +// Helper macro for checking a pattern's description and the explanation printed +// when attempting to match (and presumably failing) on a given object. +// +// We use a macro rather than a function because we want good line numbers in +// errors. We use this rather than writing a helper that returns a pair of +// (description, explanation) and doing something like +// +// EXPECT_THAT(DescAndExplanation(...), ::testing::Pair(..., ...)); +// +// because EXPECT_EQ prints a unified diff if multiline string comparison fails, +// while EXPECT_THAT does not. This unified diff makes the errors much easier +// to read. +#define EXPECT_DESC_AND_EXPLANATION(elem, pattern, expected_desc, \ + expected_explanation) \ + do { \ + EXPECT_EQ(Description(pattern), (expected_desc)); \ + EXPECT_EQ(Explanation((elem), (pattern)), expected_explanation); \ + } while (0) + +TEST(PatternMatcherTest, LayoutDescribeToAndExplain) { + auto layout = LayoutUtil::MakeLayout({1, 2}); + auto layout2 = LayoutUtil::MakeLayout({2, 2}); + + EXPECT_DESC_AND_EXPLANATION(static_cast(nullptr), m::Layout(), + "a layout", "Layout is null"); + EXPECT_DESC_AND_EXPLANATION(layout2, m::Layout().EqualTo(&layout), + "a layout equal to {1,2}", + "Layout {2,2} is not equal to expected {1,2}"); + EXPECT_DESC_AND_EXPLANATION(layout2, m::Layout().WithSparseFormat(), + "a layout with format SPARSE", + "Layout has format DENSE but expected SPARSE"); + EXPECT_DESC_AND_EXPLANATION(layout, + m::Layout().EqualTo(&layout).WithSparseFormat(), + "a layout:\n" + " * equal to {1,2} AND\n" + " * with format SPARSE", + "Layout has format DENSE but expected SPARSE"); +} + +TEST(PatternMatcherTest, ShapeDescribeToAndExplain) { + auto shape = ShapeUtil::MakeShapeWithLayout(F32, {1, 2}, {0, 1}); + auto layout = shape.layout(); + + EXPECT_DESC_AND_EXPLANATION(static_cast(nullptr), m::Shape(), + "a shape", "Shape is null"); + EXPECT_DESC_AND_EXPLANATION( + ShapeUtil::MakeShapeWithLayout(F32, {1, 2}, {1, 0}), + m::Shape().EqualTo(&shape), "a shape equal to f32[1,2]{0,1}", + "Shape not equal to f32[1,2]{0,1}\n" + "in f32[1,2]{1,0}"); + EXPECT_DESC_AND_EXPLANATION(ShapeUtil::MakeShape(F32, {2, 2}), + m::Shape().CompatibleTo(&shape), + "a shape compatible with f32[1,2]", + "Shape not compatible with f32[1,2]\n" + "in f32[2,2]{1,0}"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().WithElementType(F16), + "a shape with element type F16", + "Shape does not have element type F16\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().IsScalar(), + "a shape that represents a scalar", + "Shape is not a scalar\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(ShapeUtil::MakeNil(), m::Shape().IsArray(), + "a shape that represents an array", + "Shape is not an array\n" + "in ()"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().IsTuple(), + "a shape that represents a tuple", + "Shape is not a tuple\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().IsEffectiveScalar(), + "a shape that is an effective scalar", + "Shape is not an effective scalar\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().WithRank(42), + "a shape that has 42 dimensions", + "Shape does not have rank 42\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().WithRank(0), + "a shape that is a scalar", + "Shape is not a scalar\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(shape, m::Shape().WithRank(1).IsArray(), + "a shape:\n" + " * that has 1 dimension AND\n" + " * that represents an array", + "Shape does not have rank 1\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(ShapeUtil::MakeNil(), + m::Shape().IsArray().WithRank(1), + "a shape:\n" + " * that represents an array AND\n" + " * that has 1 dimension", + "Shape is not an array\n" + "in ()"); + EXPECT_DESC_AND_EXPLANATION( + ShapeUtil::MakeShapeWithLayout(F32, {1, 2}, {1, 0}), + m::Shape().WithLayoutEqualTo(&layout), + "a shape with\n a layout equal to {0,1}", + "Layout {1,0} is not equal to expected {0,1}\n" + "in f32[1,2]{1,0}"); + EXPECT_DESC_AND_EXPLANATION( + shape, m::Shape().WithLayout(m::Layout().WithSparseFormat()), + "a shape with\n a layout with format SPARSE", + "Layout has format DENSE but expected SPARSE\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION(shape, + m::Shape().WithSubshapeEqualTo({10}, &shape), + "a shape with subshape at index {10} which is\n" + " a shape equal to f32[1,2]{0,1}", + "No subshape at {10}\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION( + ShapeUtil::MakeTupleShape({ShapeUtil::MakeShape(F32, {2, 2})}), + m::Shape().WithSubshapeEqualTo({0}, &shape), + "a shape with subshape at index {0} which is\n" + " a shape equal to f32[1,2]{0,1}", + "Shape not equal to f32[1,2]{0,1}\n" + "in f32[2,2]{1,0}\n" + "in subshape at {0}\n" + "in (f32[2,2])"); + EXPECT_DESC_AND_EXPLANATION(shape, + m::Shape().WithSubshapeCompatibleTo({10}, &shape), + "a shape with subshape at index {10} which is\n" + " a shape compatible with f32[1,2]", + "No subshape at {10}\n" + "in f32[1,2]{0,1}"); + EXPECT_DESC_AND_EXPLANATION( + ShapeUtil::MakeTupleShape({ShapeUtil::MakeShape(F32, {2, 2})}), + m::Shape().WithSubshapeCompatibleTo({0}, &shape), + "a shape with subshape at index {0} which is\n" + " a shape compatible with f32[1,2]", + "Shape not compatible with f32[1,2]\n" + "in f32[2,2]{1,0}\n" + "in subshape at {0}\n" + "in (f32[2,2])"); + EXPECT_DESC_AND_EXPLANATION( + ShapeUtil::MakeTupleShape({ShapeUtil::MakeTupleShape({shape})}), + m::Shape().WithSubshape({0, 0}, m::Shape().IsScalar()), + "a shape with subshape at index {0,0} which is\n" + " a shape that represents a scalar", + "Shape is not a scalar\n" + "in f32[1,2]{0,1}\n" + "in subshape at {0,0}\n" + "in ((f32[1,2]))"); +} + +std::unique_ptr SetName(absl::string_view name, + std::unique_ptr instr) { + instr->SetAndSanitizeName(string(name)); + return instr; +} + +TEST(PatternMatcherTest, HloInstructionDescribeToAndExplain) { + std::unique_ptr iota = + SetName("i", HloInstruction::CreateIota(ShapeUtil::MakeShape(S32, {42}), + /*iota_dimension=*/0)); + std::unique_ptr constant = + SetName("c", HloInstruction::CreateConstant(LiteralUtil::CreateR0(0))); + + EXPECT_DESC_AND_EXPLANATION(static_cast(nullptr), + m::Op(), "an HloInstruction", + "HloInstruction* is null"); + EXPECT_DESC_AND_EXPLANATION(iota, m::Op().WithName("foo"), + "an HloInstruction named \"foo\"", + "HloInstruction not named \"foo\"\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION(iota, m::Op().WithOpcode(HloOpcode::kAdd), + "an HloInstruction with opcode add", + "HloInstruction doesn't have opcode add\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION( + constant, m::Op().IsNonConstant(), + "an HloInstruction with any opcode other than constant", + "HloInstruction has opcode constant, expected anything else\n" + "in c = s32[] constant(0)"); + EXPECT_DESC_AND_EXPLANATION(iota, m::Op().WithNumOperands(42), + "an HloInstruction with 42 operands", + "HloInstruction doesn't have 42 operands\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION(iota, m::Op().WithShape(m::Shape().IsTuple()), + "an HloInstruction outputting\n" + " a shape that represents a tuple", + "Shape is not a tuple\n" + "in s32[42]{0}\n" + "in output shape\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION( + iota, m::Op().WithOperand(2, m::Op().WithOpcode(HloOpcode::kAdd)), + "an HloInstruction with operand 2 which is:\n" + " an HloInstruction with opcode add", + "desired operand index 2 is out of bounds\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + + EXPECT_DESC_AND_EXPLANATION( + SetName("a", HloInstruction::CreateBinary(ShapeUtil::MakeShape(S32, {}), + HloOpcode::kAdd, constant.get(), + constant.get())), + m::Op().WithOperand(1, m::Op().IsNonConstant()), + "an HloInstruction with operand 1 which is:\n" + " an HloInstruction with any opcode other than constant", + "HloInstruction has opcode constant, expected anything else\n" + "in c = s32[] constant(0)\n" + "in operand 1\n" + "in a = s32[] add(s32[] c, s32[] c)"); + EXPECT_DESC_AND_EXPLANATION( + iota, m::Op().WithFusionKind(HloInstruction::FusionKind::kLoop), + "an HloInstruction with fusion kind kLoop", + "HloInstruction does not have fusion kind kLoop; it's not a fusion\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION( + iota, m::Op().WithTupleIndex(42), + "an HloInstruction which is a GTE with index 42", + "HloInstruction is not a GTE with index 42; it's not a GTE at all\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION(iota, m::Op().IsConstantScalar(), + "an HloInstruction which is a constant scalar", + "HloInstruction is not a constant\n" + "in i = s32[42]{0} iota(), iota_dimension=0"); + EXPECT_DESC_AND_EXPLANATION( + SetName("c", HloInstruction::CreateConstant( + LiteralUtil::CreateR1({1, 2}))), + m::Op().IsConstantEffectiveScalar(), + "an HloInstruction which is a constant effective scalar", + "HloInstruction is not an effective scalar\n" + "in c = s32[2]{0} constant({1, 2})"); + EXPECT_DESC_AND_EXPLANATION( + SetName("c", HloInstruction::CreateConstant(LiteralUtil::CreateR0(10))), + m::Op().IsConstantScalar(42), + "an HloInstruction which is a constant scalar with value 42", + "HloInstruction's constant value 10 did not match expected value 42\n" + "in c = s32[] constant(10)"); + EXPECT_DESC_AND_EXPLANATION( + SetName("c", HloInstruction::CreateConstant(LiteralUtil::CreateR0(2.25))), + m::Op().IsConstantEffectiveScalar(1.25), + "an HloInstruction which is a constant effective scalar with value 1.25", + "HloInstruction's constant value 2.25 did not match expected value 1.25\n" + "in c = f64[] constant(2.25)"); + EXPECT_DESC_AND_EXPLANATION( + constant, m::Op().Is(iota.get()), + absl::StrCat("an HloInstruction which is 0x", absl::Hex(iota.get()), " (", + iota->ToShortString(), ")"), + absl::StrCat("HloInstruction 0x", absl::Hex(constant.get()), " is not 0x", + absl::Hex(iota.get()), " (", iota->ToShortString(), ")\n", + "in c = s32[] constant(0)")); +} + +TEST(PatternMatcherTest, HloInstructionMatcherAnyOrderDescribeTo) { + auto scalar_s32 = ShapeUtil::MakeShape(S32, {}); + EXPECT_DESC_AND_EXPLANATION( + SetName("a", HloInstruction::CreateBinary( + scalar_s32, HloOpcode::kAdd, + SetName("b", HloInstruction::CreateConstant( + LiteralUtil::CreateR0(0))) + .get(), + SetName("c", HloInstruction::CreateConstant( + LiteralUtil::CreateR0(0))) + .get())), + m::AddAnyOrder(m::Op().WithName("b"), m::Op().WithName("bar")), + "an HloInstruction:\n" + " * with opcode add AND\n" + " * with two operands in either order:\n" + " - an HloInstruction named \"b\"\n" + " - an HloInstruction named \"bar\"", + "HloInstruction's operands (ignoring order) did not match second " + "matcher. Specifically,\n" + " - an HloInstruction named \"bar\"\n" + "does not match LHS:\n" + " - HloInstruction not named \"bar\"\n" + " in b = s32[] constant(0)\n" + "does not match RHS:\n" + " - HloInstruction not named \"bar\"\n" + " in c = s32[] constant(0)\n" + "in a = s32[] add(s32[] b, s32[] c)"); + + EXPECT_DESC_AND_EXPLANATION( + SetName("a", + HloInstruction::CreateBinary( + scalar_s32, HloOpcode::kAdd, + HloInstruction::CreateParameter(0, scalar_s32, "p").get(), + SetName("c", HloInstruction::CreateConstant( + LiteralUtil::CreateR0(0))) + .get())), + m::AddAnyOrder(m::Op().IsConstantScalar(), m::Op().IsConstant()), + "an HloInstruction:\n" + " * with opcode add AND\n" + " * with two operands in either order:\n" + " - an HloInstruction which is a constant scalar\n" + " - an HloInstruction with opcode constant", + "HloInstruction's LHS operand did not match either of the two matchers. " + "Specifically,\n" + " - an HloInstruction which is a constant scalar\n" + "does not match LHS:\n" + " - HloInstruction is not a constant\n" + " in p = s32[] parameter(0)\n" + "and\n" + " - an HloInstruction with opcode constant\n" + "does not match LHS:\n" + " - HloInstruction doesn't have opcode constant\n" + " in p = s32[] parameter(0)\n" + "in a = s32[] add(s32[] p, s32[] c)"); +} + +TEST(PatternMatcherTest, AnyOfMatcherDescribeToAndExplain) { + EXPECT_DESC_AND_EXPLANATION( + SetName("c", HloInstruction::CreateConstant(LiteralUtil::CreateR0(0))), + m::AnyOf(m::Op().WithName("foo"), + m::Op().WithName("bar")), + "any of:\n" + " - an HloInstruction named \"foo\" OR\n" + " - an HloInstruction named \"bar\"", + "None of the following matchers succeeded:\n" + "Matcher #1\n" + " - an HloInstruction named \"foo\"\n" + "failed with\n" + " - HloInstruction not named \"foo\"\n" + " in c = s32[] constant(0)\n" + "Matcher #2\n" + " - an HloInstruction named \"bar\"\n" + "failed with\n" + " - HloInstruction not named \"bar\"\n" + " in c = s32[] constant(0)"); +} + +TEST(PatternMatcherTest, Parameter) { + auto param = + HloInstruction::CreateParameter(1, ShapeUtil::MakeShape(F32, {}), "p1"); + auto non_param = + SetName("c", HloInstruction::CreateConstant(LiteralUtil::CreateR0(0))); + EXPECT_FALSE(Match(param.get(), m::Parameter(0))); + EXPECT_TRUE(Match(param.get(), m::Parameter())); + EXPECT_TRUE(Match(param.get(), m::Parameter(1))); + EXPECT_FALSE(Match(non_param.get(), m::Parameter())); + EXPECT_FALSE(Match(non_param.get(), m::Parameter(1))); + + EXPECT_DESC_AND_EXPLANATION(non_param, m::Parameter(1), + "an HloInstruction:\n" + " * with opcode parameter AND\n" + " * which is parameter 1", + "HloInstruction doesn't have opcode parameter\n" + "in c = s32[] constant(0)"); + EXPECT_EQ(Explanation(HloInstruction::CreateParameter( + 0, ShapeUtil::MakeShape(F32, {}), "p0"), + m::Parameter(1)), + "HloInstruction is not parameter 1\n" + "in p0 = f32[] parameter(0)"); +} + } // namespace } // namespace xla diff --git a/tensorflow/compiler/xla/service/while_loop_simplifier.cc b/tensorflow/compiler/xla/service/while_loop_simplifier.cc index c4790a7f19..d30f67dd81 100644 --- a/tensorflow/compiler/xla/service/while_loop_simplifier.cc +++ b/tensorflow/compiler/xla/service/while_loop_simplifier.cc @@ -526,16 +526,14 @@ static StatusOr TryPropagateConstant(HloInstruction* while_op) { // performance by forcing us to copy constants. absl::flat_hash_map index_to_constant; for (int i = 0; i < root_operands.size(); i++) { - HloInstruction* instr = root_operands[i]; - if (instr->opcode() == HloOpcode::kGetTupleElement && - instr->tuple_index() == i && instr->operand(0) == while_body_param && - ShapeUtil::IsScalar(instr->shape())) { - auto tuple_element = while_init->operand(i); - if (tuple_element->IsConstant()) { - VLOG(3) << "Found loop invariant tuple element " << i << " " - << tuple_element->ToString(); - index_to_constant[i] = tuple_element; - } + const HloInstruction* init_tuple_elem = nullptr; + if (Match(root_operands[i], + m::GetTupleElement(m::Op().Is(while_body_param), i) + .WithShape(m::Shape().IsScalar())) && + Match(while_init->operand(i), m::Constant(&init_tuple_elem))) { + VLOG(3) << "Found loop invariant tuple element " << i << " " + << init_tuple_elem->ToString(); + index_to_constant[i] = init_tuple_elem; } } @@ -793,16 +791,11 @@ static StatusOr TryMergeInductionVariables( // Maps the tuple index of each induction variable to its constant increment. absl::flat_hash_map induction_vars; for (int64 i = 0; i < while_body_root->operand_count(); ++i) { - const auto& elem_shape = while_body_root->operand(i)->shape(); - if (!ShapeUtil::IsEffectiveScalar(elem_shape) || - elem_shape.element_type() != elem_ty) { - continue; - } - HloInstruction* constant; if (!Match(while_body_root->mutable_operand(i), m::AddAnyOrder(m::GetTupleElement(m::Parameter(), i), - m::Constant(&constant)))) { + m::ConstantScalar(&constant)) + .WithShape(m::Shape().WithElementType(elem_ty)))) { continue; } if (!trip_counter && constant->literal().IsAll(1) && -- GitLab From 2f2931b682634e6c5c88d6bb9fb8ddd971439bc8 Mon Sep 17 00:00:00 2001 From: Rohan Jain Date: Thu, 29 Nov 2018 20:50:18 -0800 Subject: [PATCH 612/672] Changing the prefetch_to_device implementation to copy_to_device.prefetch instead. This removes the dependency on FunctionBufferingResource which we want to deprecate. PiperOrigin-RevId: 223459089 --- tensorflow/contrib/eager/python/datasets.py | 12 - .../contrib/eager/python/datasets_test.py | 13 - .../kernel_tests/prefetch_to_device_test.py | 54 ++-- .../data/experimental/ops/prefetching_ops.py | 239 +----------------- 4 files changed, 19 insertions(+), 299 deletions(-) diff --git a/tensorflow/contrib/eager/python/datasets.py b/tensorflow/contrib/eager/python/datasets.py index db77a39626..34614b86a7 100644 --- a/tensorflow/contrib/eager/python/datasets.py +++ b/tensorflow/contrib/eager/python/datasets.py @@ -19,7 +19,6 @@ from __future__ import division from __future__ import print_function from tensorflow.python.data.experimental.ops import prefetching_ops -from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import iterator_ops from tensorflow.python.eager import context from tensorflow.python.framework import ops @@ -53,17 +52,6 @@ class Iterator(iterator_ops.EagerIterator): TypeError: If `dataset` is an unsupported type. RuntimeError: When invoked without eager execution enabled. """ - # pylint: disable=protected-access - if (isinstance(dataset, prefetching_ops._PrefetchToDeviceDataset) - or (isinstance(dataset, dataset_ops.DatasetV1Adapter) - and isinstance( - dataset._dataset, prefetching_ops._PrefetchToDeviceDataset))): - raise TypeError( - "`tf.data.experimental.prefetch_to_device()` is not compatible with " - "`tf.contrib.eager.Iterator`. Use `for ... in dataset:` to iterate " - "over the dataset instead.") - # pylint: enable=protected-access - if not context.context().device_spec.device_type: is_remote_device = False else: diff --git a/tensorflow/contrib/eager/python/datasets_test.py b/tensorflow/contrib/eager/python/datasets_test.py index 6a508fc6ba..257d02057a 100644 --- a/tensorflow/contrib/eager/python/datasets_test.py +++ b/tensorflow/contrib/eager/python/datasets_test.py @@ -26,7 +26,6 @@ import numpy as np from tensorflow.contrib import lookup from tensorflow.contrib.eager.python import datasets from tensorflow.python.data import Dataset -from tensorflow.python.data.experimental.ops import prefetching_ops from tensorflow.python.data.experimental.ops import threadpool from tensorflow.python.data.experimental.ops import unique from tensorflow.python.eager import test @@ -208,18 +207,6 @@ class IteratorTest(test.TestCase): y = math_ops.add(x, x) self.assertAllEqual([0., 2.], y.numpy()) - def testTensorsExplicitPrefetchToDevice(self): - ds = Dataset.from_tensor_slices([0., 1.]) - ds = ds.apply(prefetching_ops.prefetch_to_device(test.gpu_device_name())) - - with self.assertRaisesRegexp(TypeError, 'prefetch_to_device'): - datasets.Iterator(ds) - - for i, x in enumerate(ds): - with ops.device(test.gpu_device_name()): - x = math_ops.add(x, x) - self.assertEqual(float(i) + float(i), x.numpy()) - def testOverrideThreadPool(self): def get_thread_id(_): diff --git a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py index 56befc9e7d..c64bb2d299 100644 --- a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py @@ -37,12 +37,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): device_dataset = host_dataset.apply( prefetching_ops.prefetch_to_device("/cpu:1")) - # NOTE(mrry): This device block creates the "host" dataset and iterator on - # /cpu:0, and ensures that the prefetching is across devices. In typical use - # this would not be necessary, because the GPU device would not support any - # of the dataset-related ops. - with ops.device("/cpu:0"): + with ops.device("/cpu:1"): iterator = device_dataset.make_one_shot_iterator() + next_element = iterator.get_next() self.assertEqual(host_dataset.output_types, device_dataset.output_types) self.assertEqual(host_dataset.output_types, iterator.output_types) @@ -51,12 +48,11 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): self.assertEqual(host_dataset.output_classes, device_dataset.output_classes) self.assertEqual(host_dataset.output_classes, iterator.output_classes) - next_element = iterator.get_next() self.assertEqual(dtypes.int64, next_element.dtype) self.assertEqual([], next_element.shape) worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) - with self.test_session(config=worker_config) as sess: + with self.test_session(config=worker_config): for i in range(10): self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): @@ -69,12 +65,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): prefetching_ops.prefetch_to_device( "/job:localhost/replica:0/task:0/device:CPU:0")) - # NOTE(mrry): This device block creates the "host" dataset and iterator on - # /cpu:0, and ensures that the prefetching is across devices. In typical use - # this would not be necessary, because the GPU device would not support any - # of the dataset-related ops. - with ops.device("/cpu:0"): + with ops.device("/cpu:1"): iterator = device_dataset.make_one_shot_iterator() + next_element = iterator.get_next() self.assertEqual(host_dataset.output_types, device_dataset.output_types) self.assertEqual(host_dataset.output_types, iterator.output_types) @@ -83,11 +76,10 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): self.assertEqual(host_dataset.output_classes, device_dataset.output_classes) self.assertEqual(host_dataset.output_classes, iterator.output_classes) - next_element = iterator.get_next() self.assertEqual(dtypes.int64, next_element.dtype) self.assertEqual([], next_element.shape) - with self.cached_session() as sess: + with self.cached_session(): for i in range(10): self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): @@ -99,12 +91,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): device_dataset = host_dataset.apply( prefetching_ops.prefetch_to_device("/cpu:1")) - # NOTE(mrry): This device block creates the "host" dataset and iterator on - # /cpu:0, and ensures that the prefetching is across devices. In typical use - # this would not be necessary, because the GPU device would not support any - # of the dataset-related ops. - with ops.device("/cpu:0"): + with ops.device("/cpu:1"): iterator = device_dataset.make_one_shot_iterator() + next_element = iterator.get_next() self.assertEqual(host_dataset.output_types, device_dataset.output_types) self.assertEqual(host_dataset.output_types, iterator.output_types) @@ -113,12 +102,11 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): self.assertEqual(host_dataset.output_classes, device_dataset.output_classes) self.assertEqual(host_dataset.output_classes, iterator.output_classes) - next_element = iterator.get_next() self.assertEqual(dtypes.int64, next_element["a"].dtype) self.assertEqual([], next_element["a"].shape) worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) - with self.test_session(config=worker_config) as sess: + with self.test_session(config=worker_config): for i in range(10): self.assertEqual({"a": i}, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): @@ -134,12 +122,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): device_dataset = host_dataset.apply( prefetching_ops.prefetch_to_device("/cpu:1")) - # NOTE(mrry): This device block creates the "host" dataset and iterator on - # /cpu:0, and ensures that the prefetching is across devices. In typical use - # this would not be necessary, because the GPU device would not support any - # of the dataset-related ops. - with ops.device("/cpu:0"): + with ops.device("/cpu:1"): iterator = device_dataset.make_one_shot_iterator() + next_element = iterator.get_next() self.assertEqual(host_dataset.output_types, device_dataset.output_types) self.assertEqual(host_dataset.output_types, iterator.output_types) @@ -148,11 +133,10 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): self.assertEqual(host_dataset.output_classes, device_dataset.output_classes) self.assertEqual(host_dataset.output_classes, iterator.output_classes) - next_element = iterator.get_next() self.assertEqual(dtypes.int64, next_element.dtype) worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) - with self.test_session(config=worker_config) as sess: + with self.test_session(config=worker_config): for i in range(10): actual = self.evaluate(next_element) self.assertAllEqual([i], actual.values) @@ -172,7 +156,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): iterator = device_dataset.make_one_shot_iterator() next_element = iterator.get_next() - with self.cached_session() as sess: + with self.cached_session(): for i in range(10): self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): @@ -184,12 +168,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): device_dataset = host_dataset.apply( prefetching_ops.prefetch_to_device("/cpu:1")) - # NOTE(mrry): This device block creates the "host" dataset and iterator on - # /cpu:0, and ensures that the prefetching is across devices. In typical use - # this would not be necessary, because the GPU device would not support any - # of the dataset-related ops. - with ops.device("/cpu:0"): + with ops.device("/cpu:1"): iterator = device_dataset.make_initializable_iterator() + next_element = iterator.get_next() self.assertEqual(host_dataset.output_types, device_dataset.output_types) self.assertEqual(host_dataset.output_types, iterator.output_types) @@ -198,12 +179,11 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): self.assertEqual(host_dataset.output_classes, device_dataset.output_classes) self.assertEqual(host_dataset.output_classes, iterator.output_classes) - next_element = iterator.get_next() self.assertEqual(dtypes.int64, next_element.dtype) self.assertEqual([], next_element.shape) worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) - with self.test_session(config=worker_config) as sess: + with self.test_session(config=worker_config): self.evaluate(iterator.initializer) for i in range(5): self.assertEqual(i, self.evaluate(next_element)) @@ -224,7 +204,7 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): iterator = device_dataset.make_initializable_iterator() next_element = iterator.get_next() - with self.cached_session() as sess: + with self.cached_session(): self.evaluate(iterator.initializer) for i in range(5): self.assertEqual(i, self.evaluate(next_element)) diff --git a/tensorflow/python/data/experimental/ops/prefetching_ops.py b/tensorflow/python/data/experimental/ops/prefetching_ops.py index 1c4e14ce32..0c14c589f6 100644 --- a/tensorflow/python/data/experimental/ops/prefetching_ops.py +++ b/tensorflow/python/data/experimental/ops/prefetching_ops.py @@ -17,13 +17,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import warnings - from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.util import nest from tensorflow.python.data.util import sparse -from tensorflow.python.eager import context from tensorflow.python.eager import function from tensorflow.python.framework import device as framework_device from tensorflow.python.framework import dtypes @@ -90,239 +87,6 @@ def function_buffering_resource_reset(function_buffer_resource, name=None): function_buffer_resource=function_buffer_resource, name=name) -# pylint: disable=protected-access -class _PrefetchToDeviceIterator(object): - """A replacement for `tf.data.Iterator` that prefetches to another device. - - Args: - input_dataset: The input dataset - one_shot: If true, we make a one shot iterator that's already initialized. - device: A fully specified device string where we want to prefetch to - buffer_size: Size of the prefetching buffer. - shared_name: (Optional.) If non-empty, the returned iterator will be - shared under the given name across multiple sessions that share the - same devices (e.g. when using a remote server). - - Returns: - An Iterator type object. - """ - - def __init__(self, - input_dataset, - one_shot, - device, - buffer_size, - shared_name=None): - self._input_dataset = input_dataset - self._get_next_call_count = 0 - self._one_shot = one_shot - if shared_name is None: - shared_name = "" - - if self._one_shot: - self._input_iterator = input_dataset.make_one_shot_iterator() - else: - self._input_iterator = iterator_ops.Iterator.from_structure( - self._input_dataset.output_types, self._input_dataset.output_shapes, - shared_name, self._input_dataset.output_classes) - input_iterator_handle = self._input_iterator.string_handle() - - @function.defun(input_signature=[tensor_spec.TensorSpec([], dtypes.string)]) - # handle is a scalar `tf.Tensor` of type `tf.string` - def _prefetch_fn(handle): - """Prefetches one element from `input_iterator`.""" - remote_iterator = iterator_ops.Iterator.from_string_handle( - handle, self._input_iterator.output_types, - self._input_iterator.output_shapes, - self._input_iterator.output_classes) - ret = remote_iterator.get_next() - return nest.flatten(sparse.serialize_sparse_tensors(ret)) - - self._prefetch_fn = _prefetch_fn._get_concrete_function_internal() # pylint: disable=protected-access - - iterator_device = ged_ops.experimental_iterator_get_device( - self._input_iterator._iterator_resource) - - with ops.device(device): - self._buffering_resource = function_buffering_resource( - f=self._prefetch_fn, - target_device=iterator_device, - string_arg=input_iterator_handle, - buffer_size=buffer_size, - shared_name=shared_name, - output_types=nest.flatten( - sparse.as_dense_types(self._input_dataset.output_types, - self._input_dataset.output_classes))) - - if not self._one_shot: - reset_op = function_buffering_resource_reset(self._buffering_resource) - with ops.control_dependencies([reset_op]): - self._initializer = self._input_iterator.make_initializer( - self._input_dataset) - - def get_next(self, name=None): - """See `tf.data.Iterator.get_next`.""" - self._get_next_call_count += 1 - if self._get_next_call_count > iterator_ops.GET_NEXT_CALL_WARNING_THRESHOLD: - warnings.warn(iterator_ops.GET_NEXT_CALL_WARNING_MESSAGE) - - flat_ret = ged_ops.experimental_function_buffering_resource_get_next( - self._buffering_resource, - output_types=nest.flatten( - sparse.as_dense_types(self.output_types, self.output_classes)), - name=name) - - ret = sparse.deserialize_sparse_tensors( - nest.pack_sequence_as(self.output_types, flat_ret), - self.output_types, self.output_shapes, self.output_classes) - - for tensor, shape in zip( - nest.flatten(ret), nest.flatten(self.output_shapes)): - if isinstance(tensor, ops.Tensor): - tensor.set_shape(shape) - - return ret - - @property - def initializer(self): - if self._one_shot: - raise NotImplementedError("Can't initialize a one_shot_iterator") - return self._initializer - - @property - def output_classes(self): - return self._input_dataset.output_classes - - @property - def output_shapes(self): - return self._input_dataset.output_shapes - - @property - def output_types(self): - return self._input_dataset.output_types - - -class _PrefetchToDeviceEagerIterator(iterator_ops.EagerIterator): - """A replacement for `tf.data.Iterator` that prefetches to another device. - - Args: - input_dataset: The input dataset - one_shot: If true, we make a one shot iterator that's already initialized. - device: A fully specified device string where we want to prefetch to - buffer_size: Size of the prefetching buffer. - shared_name: (Optional.) If non-empty, the returned iterator will be - shared under the given name across multiple sessions that share the - same devices (e.g. when using a remote server). - - Returns: - An Iterator type object. - """ - - def __init__(self, - input_dataset, - device, - buffer_size): - with ops.device("/device:CPU:0"): - super(_PrefetchToDeviceEagerIterator, self).__init__(input_dataset) - input_iterator_handle = gen_dataset_ops.iterator_to_string_handle( - self._resource) - - self._device = device - - @function.defun(input_signature=[tensor_spec.TensorSpec([], dtypes.string)]) - def _prefetch_fn(handle): - """Prefetches one element from `input_iterator`.""" - remote_iterator = iterator_ops.Iterator.from_string_handle( - handle, self.output_types, self.output_shapes, self.output_classes) - ret = remote_iterator.get_next() - return nest.flatten(sparse.serialize_sparse_tensors(ret)) - - self._prefetch_fn = _prefetch_fn._get_concrete_function_internal() # pylint: disable=protected-access - - with ops.device(device): - self._buffering_resource = function_buffering_resource( - f=self._prefetch_fn, - output_types=self._flat_output_types, - target_device=ged_ops.experimental_iterator_get_device( - self._resource), - string_arg=input_iterator_handle, - buffer_size=buffer_size, - shared_name=iterator_ops._generate_shared_name( - "function_buffer_resource")) - - def _next_internal(self): - """Returns a nested structure of `tf.Tensor`s containing the next element. - """ - # This runs in sync mode as iterators use an error status to communicate - # that there is no more data to iterate over. - # TODO(b/77291417): Fix - with context.execution_mode(context.SYNC): - with ops.device(self._device): - flat_ret = ged_ops.experimental_function_buffering_resource_get_next( - function_buffer_resource=self._buffering_resource, - output_types=self._flat_output_types) - return self._element_structure._from_tensor_list(flat_ret) -# pylint: enable=protected-access - - -class _PrefetchToDeviceDataset(dataset_ops.UnaryUnchangedStructureDataset): - """A `Dataset` whose iterator prefetches elements to another device.""" - - def __init__(self, input_dataset, device, buffer_size): - super(_PrefetchToDeviceDataset, self).__init__(input_dataset) - self._input_dataset = input_dataset - self._device = device - self._buffer_size = buffer_size if buffer_size is not None else 1 - - # The static analysis cannot tell that the eager iterator's superclass has - # a `next()` method. - # pylint: disable=non-iterator-returned - def __iter__(self): - """Creates an `Iterator` for enumerating the elements of this dataset. - - The returned iterator implements the Python iterator protocol and therefore - can only be used in eager mode. - - Returns: - An `Iterator` over the elements of this dataset. - - Raises: - RuntimeError: If eager execution is enabled. - """ - if context.executing_eagerly(): - return _PrefetchToDeviceEagerIterator(self._input_dataset, self._device, - self._buffer_size) - else: - raise RuntimeError("dataset.__iter__() is only supported when eager " - "execution is enabled.") - # pylint: enable=non-iterator-returned - - def make_one_shot_iterator(self): - if context.executing_eagerly(): - return _PrefetchToDeviceEagerIterator(self._input_dataset, self._device, - self._buffer_size) - else: - return _PrefetchToDeviceIterator(self._input_dataset, one_shot=True, - device=self._device, - buffer_size=self._buffer_size) - - def make_initializable_iterator(self, shared_name=None): - return _PrefetchToDeviceIterator( - self._input_dataset, - one_shot=False, - device=self._device, - buffer_size=self._buffer_size, - shared_name=shared_name) - - def _as_variant_tensor(self): - # TODO(mrry): Raise this error earlier (e.g. when one of the Dataset - # transformation methods is called. - # TODO(mrry): Investigate support for chaining further transformations after - # the prefetch, including GPU support. - raise NotImplementedError("`prefetch_to_device()` must be the last " - "transformation in a dataset pipeline.") - - @tf_export("data.experimental.prefetch_to_device") def prefetch_to_device(device, buffer_size=None): """A transformation that prefetches dataset values to the given `device`. @@ -340,7 +104,8 @@ def prefetch_to_device(device, buffer_size=None): `tf.data.Dataset.apply`. """ def _apply_fn(dataset): - return _PrefetchToDeviceDataset(dataset, device, buffer_size) + return _CopyToDeviceDataset( + dataset, target_device=device).prefetch(buffer_size) return _apply_fn -- GitLab From ecf27945d551bea2ebccb1262d28f2b89ecd61bd Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 21:04:42 -0800 Subject: [PATCH 613/672] QuantizedDepthwiseConvKernel should be able to handle dilation. PiperOrigin-RevId: 223460312 --- .../internal/optimized/depthwiseconv_uint8.h | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8.h b/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8.h index 5317cea884..d3dca799a7 100644 --- a/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8.h +++ b/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8.h @@ -1499,22 +1499,26 @@ void QuantizedDepthwiseConvAccumRow(int stride, int dilation_factor, int out_x_loop_end_unclampled = 0; if (kAllowStrided) { if (stride == 2) { - out_x_loop_start_unclampled = (pad_width - filter_x + 1) / 2; + out_x_loop_start_unclampled = + (pad_width - dilation_factor * filter_x + 1) / 2; out_x_loop_end_unclampled = - (pad_width + input_width - filter_x + 1) / 2; + (pad_width + input_width - dilation_factor * filter_x + 1) / 2; } else if (stride == 4) { - out_x_loop_start_unclampled = (pad_width - filter_x + 3) / 4; + out_x_loop_start_unclampled = + (pad_width - dilation_factor * filter_x + 3) / 4; out_x_loop_end_unclampled = - (pad_width + input_width - filter_x + 3) / 4; + (pad_width + input_width - dilation_factor * filter_x + 3) / 4; } else { out_x_loop_start_unclampled = - (pad_width - filter_x + stride - 1) / stride; - out_x_loop_end_unclampled = - (pad_width + input_width - filter_x + stride - 1) / stride; + (pad_width - dilation_factor * filter_x + stride - 1) / stride; + out_x_loop_end_unclampled = (pad_width + input_width - + dilation_factor * filter_x + stride - 1) / + stride; } } else { - out_x_loop_start_unclampled = pad_width - filter_x; - out_x_loop_end_unclampled = pad_width + input_width - filter_x; + out_x_loop_start_unclampled = pad_width - dilation_factor * filter_x; + out_x_loop_end_unclampled = + pad_width + input_width - dilation_factor * filter_x; } // The kernel will have to iterate on the segment of the // output row that starts at out_x_loop_start and out_x_loop_end. @@ -1525,7 +1529,8 @@ void QuantizedDepthwiseConvAccumRow(int stride, int dilation_factor, int32* acc_buffer_ptr = acc_buffer + (out_x_loop_start - out_x_buffer_start) * output_depth; - const int in_x_origin = (out_x_loop_start * stride) - pad_width + filter_x; + const int in_x_origin = + (out_x_loop_start * stride) - pad_width + dilation_factor * filter_x; const uint8* input_ptr = input_data + in_x_origin * input_depth; const int num_output_pixels = out_x_loop_end - out_x_loop_start; QuantizedDepthwiseConvKernel< @@ -1703,8 +1708,7 @@ inline void DepthwiseConvGeneral( FIXED_DEPTH_MULTIPLIER) \ if (!row_accum_func && (stride_width == 1 || ALLOW_STRIDED) && \ (input_depth == FIXED_INPUT_DEPTH || FIXED_INPUT_DEPTH == 0) && \ - depth_multiplier == FIXED_DEPTH_MULTIPLIER && \ - dilation_width_factor == 1 && dilation_height_factor == 1) { \ + depth_multiplier == FIXED_DEPTH_MULTIPLIER) { \ row_accum_func = \ QuantizedDepthwiseConvAccumRow; \ -- GitLab From 4186d29da6cdfaaa5e43c46c76ee07c74e7edb13 Mon Sep 17 00:00:00 2001 From: Ruoxin Sang Date: Thu, 29 Nov 2018 21:20:48 -0800 Subject: [PATCH 614/672] Move training loop from device to host in TPUStrategy. PiperOrigin-RevId: 223461384 --- .../contrib/distribute/python/keras_test.py | 10 ++- .../contrib/distribute/python/tpu_strategy.py | 71 +++++++++++++------ .../contrib/tpu/python/tpu/training_loop.py | 4 +- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/tensorflow/contrib/distribute/python/keras_test.py b/tensorflow/contrib/distribute/python/keras_test.py index 435f10358f..1d00281974 100644 --- a/tensorflow/contrib/distribute/python/keras_test.py +++ b/tensorflow/contrib/distribute/python/keras_test.py @@ -1267,9 +1267,17 @@ class TestDistributionStrategyCorrectness(test.TestCase, # We have initialized the model to the same weight for the distribution # and non-distribution run. model.set_weights(initial_weights) + # TODO(b/120245072): Also use gradient_descent_keras.SGD for + # TPUStrategy. + # pylint: disable=line-too-long + if with_distribution and with_distribution.__class__.__name__ == 'TPUStrategy': + # pylint: enable=line-too-long + optimizer = gradient_descent.GradientDescentOptimizer(0.5) + else: + optimizer = gradient_descent_keras.SGD(0.5) model.compile( loss=keras.losses.mean_squared_error, - optimizer=gradient_descent_keras.SGD(0.5), + optimizer=optimizer, distribute=with_distribution) training_inputs, eval_inputs, predict_inputs = ( diff --git a/tensorflow/contrib/distribute/python/tpu_strategy.py b/tensorflow/contrib/distribute/python/tpu_strategy.py index 1f302fdde8..39ed8f7cf1 100644 --- a/tensorflow/contrib/distribute/python/tpu_strategy.py +++ b/tensorflow/contrib/distribute/python/tpu_strategy.py @@ -276,9 +276,9 @@ class TPUExtended(distribute_lib.DistributionStrategyExtended): initial_loop_values = {} initial_loop_values = nest.flatten(initial_loop_values) ctx = values.MultiStepContext() - def run_fn(*args, **kwargs): + + def run_fn(): """Single step on the TPU device.""" - del args, kwargs fn_inputs = dequeue_fn() if not isinstance(fn_inputs, tuple): fn_inputs = (fn_inputs,) @@ -290,11 +290,6 @@ class TPUExtended(distribute_lib.DistributionStrategyExtended): else: return fn_result - # TODO(sourabhbajaj): The input to while loop should be based on the output - # type of the step_fn - def iterate_on_tpu(): - return training_loop.repeat(iterations, run_fn, initial_loop_values) - # We capture the control_flow_context at this point, before we run `fn` # inside a while_loop and TPU replicate context. This is useful in cases # where we might need to exit these contexts and get back to the outer @@ -304,24 +299,56 @@ class TPUExtended(distribute_lib.DistributionStrategyExtended): self._outer_control_flow_context = ( ops.get_default_graph()._get_control_flow_context()) # pylint: disable=protected-access - replicate_inputs = [[]] * self._num_replicas_in_sync - replicate_outputs = tpu.replicate(iterate_on_tpu, replicate_inputs) + def rewrite_fn(*args): + """The rewritten step fn running on TPU.""" + del args + replicate_inputs = [[]] * self._num_replicas_in_sync + replicate_outputs = tpu.replicate(run_fn, replicate_inputs) + + # If run_fn has tensor outputs, tpu.replicate returns a list of list. We + # will flatten it in this case. If run_fn has no tensor outputs, + # tpu.replicate returns a list of no_ops, we will keep the output as it + # is. + if isinstance(replicate_outputs[0], list): + replicate_outputs = nest.flatten(replicate_outputs) + + return replicate_outputs + + # TODO(sourabhbajaj): The input to while loop should be based on the output + # type of the step_fn + assert isinstance(initial_loop_values, list) + initial_loop_values = initial_loop_values * self._num_replicas_in_sync + + # Put the while loop op on host 0. + with ops.device(self.get_host_cpu_device(0)): + replicate_outputs = training_loop.repeat(iterations, rewrite_fn, + initial_loop_values) + del self._outer_control_flow_context ctx.run_op = control_flow_ops.group(replicate_outputs, enqueue_ops) - # Filter out any ops from the outputs, typically this would be the case - # when there were no tensor outputs. - last_step_tensor_outputs = [x for x in replicate_outputs - if not isinstance(x, ops.Operation)] - - # Outputs are currently of the structure (grouped by device) - # [[output0_device0, output1_device0, output2_device0], - # [output0_device1, output1_device1, output2_device1]] - # Convert this to the following structure instead: (grouped by output) - # [[output0_device0, output0_device1], - # [output1_device0, output1_device1], - # [output2_device0, output2_device1]] - last_step_tensor_outputs = [list(x) for x in zip(*last_step_tensor_outputs)] + if isinstance(replicate_outputs, list): + # Filter out any ops from the outputs, typically this would be the case + # when there were no tensor outputs. + last_step_tensor_outputs = [ + x for x in replicate_outputs if not isinstance(x, ops.Operation) + ] + + # Outputs are currently of the structure (flattened) + # [output0_device0, output1_device0, output2_device0, + # output0_device1, output1_device1, output2_device1, + # ...] + # Convert this to the following structure instead: (grouped by output) + # [[output0_device0, output0_device1], + # [output1_device0, output1_device1], + # [output2_device0, output2_device1]] + output_num = len(last_step_tensor_outputs) // self._num_replicas_in_sync + last_step_tensor_outputs = [ + last_step_tensor_outputs[i::output_num] for i in range(output_num) + ] + else: + # no tensors returned. + last_step_tensor_outputs = [] # Convert replicate_outputs to the original dict structure of # last_step_outputs. diff --git a/tensorflow/contrib/tpu/python/tpu/training_loop.py b/tensorflow/contrib/tpu/python/tpu/training_loop.py index b6c350ecd7..0187b4bec6 100644 --- a/tensorflow/contrib/tpu/python/tpu/training_loop.py +++ b/tensorflow/contrib/tpu/python/tpu/training_loop.py @@ -166,8 +166,8 @@ def while_loop(condition, body, inputs=None, infeed_queue=None, name=None): # control dependencies from any side-effecting operations. if input_arity == 0: inputs = [array_ops.constant(0)] - return control_flow_ops.while_loop(condition_wrapper, body_wrapper, inputs, - name="") + return control_flow_ops.while_loop( + condition_wrapper, body_wrapper, inputs, name="", parallel_iterations=1) def repeat(n, body, inputs=None, infeed_queue=None, name=None): -- GitLab From 2520a5e545b2703793facb1cc27598fc2fc083ce Mon Sep 17 00:00:00 2001 From: Rohan Jain Date: Thu, 29 Nov 2018 21:40:35 -0800 Subject: [PATCH 615/672] Getting rid of all FunctionBufferingResource code. PiperOrigin-RevId: 223462860 --- ...xperimentalFunctionBufferingResource.pbtxt | 58 --- ...ntalFunctionBufferingResourceGetNext.pbtxt | 25 - ...mentalFunctionBufferingResourceReset.pbtxt | 13 - .../data/experimental/prefetching_kernels.cc | 428 ------------------ .../core/ops/compat/ops_history.v1.pbtxt | 62 --- .../core/ops/experimental_dataset_ops.cc | 21 - .../data/experimental/kernel_tests/BUILD | 21 - .../function_buffering_resource_test.py | 252 ----------- .../data/experimental/ops/prefetching_ops.py | 53 --- 9 files changed, 933 deletions(-) delete mode 100644 tensorflow/core/api_def/base_api/api_def_ExperimentalFunctionBufferingResource.pbtxt delete mode 100644 tensorflow/core/api_def/base_api/api_def_ExperimentalFunctionBufferingResourceGetNext.pbtxt delete mode 100644 tensorflow/core/api_def/base_api/api_def_ExperimentalFunctionBufferingResourceReset.pbtxt delete mode 100644 tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py diff --git a/tensorflow/core/api_def/base_api/api_def_ExperimentalFunctionBufferingResource.pbtxt b/tensorflow/core/api_def/base_api/api_def_ExperimentalFunctionBufferingResource.pbtxt deleted file mode 100644 index 66511eff60..0000000000 --- a/tensorflow/core/api_def/base_api/api_def_ExperimentalFunctionBufferingResource.pbtxt +++ /dev/null @@ -1,58 +0,0 @@ -op { - graph_op_name: "ExperimentalFunctionBufferingResource" - in_arg { - name: "string_arg" - description: <

a<}`@ryZol_#Xz#9YbW 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%0D(dy+X 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 diff --git a/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index b/tensorflow/contrib/tensorrt/test/quantization_mnist_test_data/model.ckpt-14070.index deleted file mode 100644 index d338a78f056628943e0d7a59899e11fa5444b717..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 961 zcmZQzVB=tvV&Y(A;O0(BElD(tFUT)XE#hDlV$fhQT~;k<#lp^Ogb-9<(O@w>WoOgF zz%7)VpI2s-qMwwRSj@pF#3IDRp`gH_(ZFb$JojM&H> zkg}UI);9?;$%C!IqDB;?CVPk2LpFBdctd0#I4E?;X*4jIx~>RW#f$0%2Zas=kd$AJ zPr4A27aSBiltAKF-@j|*WK+QE1qC4{4hMw}6^(`iET%#23!?d16|wmNs_qF3SmB)< zJ`NEkMGRj+RW0EJt2!33+KPcoG$l2!I2GmsX;u{RphgFm!UnL^oaVv^C7z#p<=5#SjC>p$sdH_ zZbnF7)c{M&RCmQPaPz0<NO#21&O7I1J1F(@>A)zsiHozOD*J_7>-!%Id61||^W y(DO~%Aes?G9Qd?w0|O&-2E%JM5Em@gvh&&A4{RKN+4w<1_;L8}hHjNo_uBx6l+IZI diff --git a/tensorflow/core/grappler/optimizers/layout_optimizer.cc b/tensorflow/core/grappler/optimizers/layout_optimizer.cc index 790b6955a5..f4653505f7 100644 --- a/tensorflow/core/grappler/optimizers/layout_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/layout_optimizer.cc @@ -108,7 +108,6 @@ std::set GetOpsFormatAgnostic() { "Conj", "Cos", "Cosh", - "Dequantize", "Digamma", "Div", "Elu", -- GitLab From 89deaf06c19a3eb1d5236d328b6b8cdde7238271 Mon Sep 17 00:00:00 2001 From: Yunxing Dai Date: Wed, 21 Nov 2018 15:48:04 -0800 Subject: [PATCH 243/672] Monkey patch _os_exit to make sure exit handlers are proper called. PiperOrigin-RevId: 222470718 --- tensorflow/compiler/tests/xla_test.py | 5 +++++ tensorflow/python/platform/googletest.py | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/tests/xla_test.py b/tensorflow/compiler/tests/xla_test.py index 98a41981cf..d15c073457 100644 --- a/tensorflow/compiler/tests/xla_test.py +++ b/tensorflow/compiler/tests/xla_test.py @@ -22,6 +22,7 @@ import contextlib import os import random import re +import sys import numpy as np @@ -38,6 +39,10 @@ from tensorflow.python.platform import flags from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging as logging +# TODO(b/35678764): Disable monkeypatched exit handlers once we find a proper +# solution to invoke exit handlers during program exit. +test._googletest.SetOSExit(sys.exit) + FLAGS = flags.FLAGS flags.DEFINE_string('test_device', None, diff --git a/tensorflow/python/platform/googletest.py b/tensorflow/python/platform/googletest.py index 8141cf92c5..c8312c153e 100644 --- a/tensorflow/python/platform/googletest.py +++ b/tensorflow/python/platform/googletest.py @@ -47,6 +47,13 @@ unittest_main = main # directory only once per test binary invocation. _googletest_temp_dir = '' +_os_exit = sys.exit + + +def SetOSExit(exit_func): + global _os_exit + _os_exit = exit_func + # pylint: disable=invalid-name # pylint: disable=undefined-variable @@ -61,7 +68,7 @@ def g_main(argv): except IOError: sys.stderr.write('Error opening TEST_SHARD_STATUS_FILE (%s). Exiting.' % os.environ['TEST_SHARD_STATUS_FILE']) - sys.exit(1) + _os_exit(1) finally: if f is not None: f.close() -- GitLab From f96b9ab51fbad077eb75af8595dcd7779a01b97b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 15:55:03 -0800 Subject: [PATCH 244/672] This CL marks the `ReduceDataset` op as not differentiable, to avoid crashes when it gets caught inside functions whose gradients are computed. PiperOrigin-RevId: 222471432 --- tensorflow/python/data/ops/dataset_ops.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index d040d17322..bd57c9f1d5 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -57,6 +57,9 @@ from tensorflow.python.util import function_utils from tensorflow.python.util.tf_export import tf_export +ops.NotDifferentiable("ReduceDataset") + + @tf_export("data.Dataset", v1=[]) @six.add_metaclass(abc.ABCMeta) class DatasetV2(object): -- GitLab From f51e2622b14c3e359396bdc33732813602f9af68 Mon Sep 17 00:00:00 2001 From: Taylor Robie Date: Wed, 21 Nov 2018 15:59:30 -0800 Subject: [PATCH 245/672] remove deprecated `squeeze_dims` arg from `tf.squeeze` PiperOrigin-RevId: 222471820 --- tensorflow/python/ops/array_ops.py | 8 +++++++- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 2 +- tensorflow/tools/compatibility/tf_upgrade_v2.py | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 0f80a28d7f..8e9b8950bc 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -3057,7 +3057,7 @@ def sequence_mask(lengths, maxlen=None, dtype=dtypes.bool, name=None): return gen_math_ops.cast(result, dtype) -@tf_export("squeeze") +@tf_export(v1=["squeeze"]) @deprecation.deprecated_args(None, "Use the `axis` argument instead", "squeeze_dims") def squeeze(input, axis=None, name=None, squeeze_dims=None): @@ -3107,6 +3107,12 @@ def squeeze(input, axis=None, name=None, squeeze_dims=None): return gen_array_ops.squeeze(input, axis, name) +@tf_export("squeeze", v1=[]) +def squeeze_v2(input, axis=None, name=None): + # pylint: disable=redefined-builtin + return squeeze(input, axis, name) + + @tf_export("where") def where(condition, x=None, y=None, name=None): """Return the elements, either from `x` or `y`, depending on the `condition`. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index f3099f7d82..b4b4827584 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -1058,7 +1058,7 @@ tf_module { } member_method { name: "squeeze" - argspec: "args=[\'input\', \'axis\', \'name\', \'squeeze_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'input\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "stack" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 86c6caa6fe..05e839aa9d 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -198,6 +198,9 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "keep_dims": "keepdims", "reduction_indices": "axis" }, + "tf.squeeze": { + "squeeze_dims": "axis", + }, } # Mapping from function to the new name of the function -- GitLab From 7dcf314bcea609f552830122e9f94625c8687d7e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 16:18:17 -0800 Subject: [PATCH 246/672] Update ops-related pbtxt files. PiperOrigin-RevId: 222473956 --- .../core/ops/compat/ops_history.v1.pbtxt | 54 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 54 +++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index dd1aaf966e..309154d74d 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -21969,6 +21969,33 @@ op { } is_stateful: true } +op { + name: "ExperimentalMaxIntraOpParallelismDataset" + input_arg { + name: "input_dataset" + type: DT_VARIANT + } + input_arg { + name: "max_intra_op_parallelism" + type: DT_INT64 + } + output_arg { + name: "handle" + type: DT_VARIANT + } + attr { + name: "output_types" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "output_shapes" + type: "list(shape)" + has_minimum: true + minimum: 1 + } +} op { name: "ExperimentalNonSerializableDataset" input_arg { @@ -22040,6 +22067,33 @@ op { minimum: 1 } } +op { + name: "ExperimentalPrivateThreadPoolDataset" + input_arg { + name: "input_dataset" + type: DT_VARIANT + } + input_arg { + name: "num_threads" + type: DT_INT64 + } + output_arg { + name: "handle" + type: DT_VARIANT + } + attr { + name: "output_types" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "output_shapes" + type: "list(shape)" + has_minimum: true + minimum: 1 + } +} op { name: "ExperimentalSleepDataset" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index bc35ce7513..f690635558 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -10432,6 +10432,33 @@ op { } is_stateful: true } +op { + name: "ExperimentalMaxIntraOpParallelismDataset" + input_arg { + name: "input_dataset" + type: DT_VARIANT + } + input_arg { + name: "max_intra_op_parallelism" + type: DT_INT64 + } + output_arg { + name: "handle" + type: DT_VARIANT + } + attr { + name: "output_types" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "output_shapes" + type: "list(shape)" + has_minimum: true + minimum: 1 + } +} op { name: "ExperimentalNonSerializableDataset" input_arg { @@ -10503,6 +10530,33 @@ op { minimum: 1 } } +op { + name: "ExperimentalPrivateThreadPoolDataset" + input_arg { + name: "input_dataset" + type: DT_VARIANT + } + input_arg { + name: "num_threads" + type: DT_INT64 + } + output_arg { + name: "handle" + type: DT_VARIANT + } + attr { + name: "output_types" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "output_shapes" + type: "list(shape)" + has_minimum: true + minimum: 1 + } +} op { name: "ExperimentalSleepDataset" input_arg { -- GitLab From 8dcb3b69eb561be3d607a109041ed225395dad53 Mon Sep 17 00:00:00 2001 From: Kay Zhu Date: Wed, 21 Nov 2018 16:24:20 -0800 Subject: [PATCH 247/672] [XLA] Add tests for DotGeneral where LHS and RHS are not of equal rank. PiperOrigin-RevId: 222474570 --- .../compiler/xla/tests/dot_operation_test.cc | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tensorflow/compiler/xla/tests/dot_operation_test.cc b/tensorflow/compiler/xla/tests/dot_operation_test.cc index 6c0847a875..25091b8d5d 100644 --- a/tensorflow/compiler/xla/tests/dot_operation_test.cc +++ b/tensorflow/compiler/xla/tests/dot_operation_test.cc @@ -637,6 +637,76 @@ XLA_TYPED_TEST(DotOperationTest_F16F32F64CF64, GeneralMatMul) { {x_data.get(), y_data.get()}, this->error_spec_); } +#ifndef XLA_TEST_BACKEND_CPU +// TODO(b/74459949): failed on CPU on 2018-10-29. +XLA_TYPED_TEST(DotOperationTest_F16F32F64CF64, GeneralMatMulR3LhsR2Rhs) { + using T = TypeParam; + + XlaBuilder builder(this->TestName()); + auto x = + Parameter(&builder, 0, ShapeUtil::MakeShapeWithType({2, 2, 2}), "x"); + auto y = Parameter(&builder, 1, ShapeUtil::MakeShapeWithType({2, 2}), "y"); + + DotDimensionNumbers dnums; + dnums.add_lhs_contracting_dimensions(1); + dnums.add_rhs_contracting_dimensions(1); + dnums.add_lhs_batch_dimensions(0); + dnums.add_rhs_batch_dimensions(0); + + DotGeneral(x, y, dnums); + + auto x_data = + this->client_ + ->TransferToServer(LiteralUtil::CreateR3FromArray3D( + {{{1.0f, 2.0f}, {3.0f, 4.0f}}, {{5.0f, 6.0f}, {7.0f, 8.0f}}})) + .ConsumeValueOrDie(); + + auto y_data = this->client_ + ->TransferToServer(LiteralUtil::CreateR2FromArray2D( + {{1.0f, 0.0f}, {0.0f, 1.0f}})) + .ConsumeValueOrDie(); + + this->template ComputeAndCompareR2( + &builder, + /*expected=*/{{1.0f, 2.0f}, {7.0f, 8.0f}}, {x_data.get(), y_data.get()}, + this->error_spec_); +} + +// TODO(b/74459949): failed on CPU on 2018-10-29. +XLA_TYPED_TEST(DotOperationTest_F16F32F64CF64, GeneralMatMulR2LhsR3Rhs) { + using T = TypeParam; + + XlaBuilder builder(this->TestName()); + auto x = Parameter(&builder, 0, ShapeUtil::MakeShapeWithType({2, 2}), "x"); + auto y = + Parameter(&builder, 1, ShapeUtil::MakeShapeWithType({2, 2, 2}), "y"); + + DotDimensionNumbers dnums; + dnums.add_lhs_contracting_dimensions(1); + dnums.add_rhs_contracting_dimensions(1); + dnums.add_lhs_batch_dimensions(0); + dnums.add_rhs_batch_dimensions(0); + + DotGeneral(x, y, dnums); + + auto x_data = this->client_ + ->TransferToServer(LiteralUtil::CreateR2FromArray2D( + {{1.0f, 0.0f}, {0.0f, 1.0f}})) + .ConsumeValueOrDie(); + + auto y_data = + this->client_ + ->TransferToServer(LiteralUtil::CreateR3FromArray3D( + {{{1.0f, 2.0f}, {3.0f, 4.0f}}, {{5.0f, 6.0f}, {7.0f, 8.0f}}})) + .ConsumeValueOrDie(); + + this->template ComputeAndCompareR2( + &builder, + /*expected=*/{{1.0f, 2.0f}, {7.0f, 8.0f}}, {x_data.get(), y_data.get()}, + this->error_spec_); +} +#endif // XLA_TEST_BACKEND_CPU + XLA_TYPED_TEST(DotOperationTest_F16F32F64CF64, GeneralMatMulMultipleBatch) { using T = TypeParam; -- GitLab From 8b663936f830ae4223901753767fe41d5e87ee20 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 16:29:42 -0800 Subject: [PATCH 248/672] This CL switches isinstance(x, dataset_ops.Dataset) checks to compare against dataset_ops.DatasetV2 PiperOrigin-RevId: 222475047 --- tensorflow/contrib/tpu/python/tpu/datasets.py | 2 +- tensorflow/contrib/tpu/python/tpu/keras_support.py | 10 +++++----- tensorflow/contrib/tpu/python/tpu/tpu_estimator.py | 2 +- tensorflow/python/autograph/operators/control_flow.py | 2 +- tensorflow/python/distribute/values.py | 2 +- .../python/keras/engine/distributed_training_utils.py | 2 +- tensorflow/python/keras/engine/training.py | 10 +++++----- tensorflow/python/keras/engine/training_generator.py | 2 +- tensorflow/python/training/distribute.py | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tensorflow/contrib/tpu/python/tpu/datasets.py b/tensorflow/contrib/tpu/python/tpu/datasets.py index c694e9c1bc..d61c824eab 100644 --- a/tensorflow/contrib/tpu/python/tpu/datasets.py +++ b/tensorflow/contrib/tpu/python/tpu/datasets.py @@ -133,7 +133,7 @@ def StreamingFilesDataset(files, with ops.device('/job:%s' % file_reader_job): if isinstance(files, str): source_dataset = dataset_ops.Dataset.list_files(files) - elif isinstance(files, dataset_ops.Dataset): + elif isinstance(files, dataset_ops.DatasetV2): source_dataset = files else: raise ValueError('files was not a string or a dataset: %s' % files) diff --git a/tensorflow/contrib/tpu/python/tpu/keras_support.py b/tensorflow/contrib/tpu/python/tpu/keras_support.py index 73753cd918..c4db4aa0c7 100644 --- a/tensorflow/contrib/tpu/python/tpu/keras_support.py +++ b/tensorflow/contrib/tpu/python/tpu/keras_support.py @@ -769,7 +769,7 @@ class TPUDatasetInfeedManager(TPUInfeedManager): def _verify_dataset_shape(self, dataset): """Verifies a dataset is of an appropriate shape for TPUs.""" - if not isinstance(dataset, dataset_ops.Dataset): + if not isinstance(dataset, dataset_ops.DatasetV2): raise ValueError('The function passed as the `x` parameter did not ' 'return a `tf.data.Dataset`.') if not isinstance(dataset.output_classes, tuple): @@ -1465,7 +1465,7 @@ class KerasTPUModel(models.Model): assert not self._numpy_to_infeed_manager_list # Ensure empty. infeed_managers = [] # Managers to clean up at the end of the fit call. - if isinstance(x, dataset_ops.Dataset): + if isinstance(x, dataset_ops.DatasetV2): # TODO(b/111413240): Support taking a tf.data.Dataset directly. raise ValueError( 'Taking a Dataset directly is not yet supported. Please ' @@ -1491,7 +1491,7 @@ class KerasTPUModel(models.Model): y = infeed_manager.dummy_y infeed_managers.append((x, infeed_manager)) - if isinstance(validation_data, dataset_ops.Dataset): + if isinstance(validation_data, dataset_ops.DatasetV2): # TODO(b/111413240): Support taking a tf.data.Dataset directly. raise ValueError( 'Taking a Dataset directly is not yet supported. Please ' @@ -1550,7 +1550,7 @@ class KerasTPUModel(models.Model): with _tpu_session_context(): # Managers to clean up at the end of the evaluate call. infeed_managers = [] - if isinstance(x, dataset_ops.Dataset): + if isinstance(x, dataset_ops.DatasetV2): # TODO(b/111413240): Support taking a tf.data.Dataset directly. raise ValueError( 'Taking a Dataset directly is not yet supported. Please ' @@ -1922,7 +1922,7 @@ class KerasTPUModel(models.Model): if validation_data: if (isinstance(validation_data, iterator_ops.Iterator) or isinstance(validation_data, iterator_ops.EagerIterator) or - isinstance(validation_data, dataset_ops.Dataset)): + isinstance(validation_data, dataset_ops.DatasetV2)): raise ValueError('KerasTPUModel cannot handle a Dataset or Iterator ' 'for validation_data. Please instead pass a function ' 'that returns a `tf.data.Dataset`.') diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 9525121ebb..2aaf65881b 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -3072,7 +3072,7 @@ class _Inputs(object): @staticmethod def from_input_fn(return_values): """Returns an `_Inputs` instance according to `input_fn` return value.""" - if isinstance(return_values, dataset_ops.Dataset): + if isinstance(return_values, dataset_ops.DatasetV2): dataset = return_values return _Inputs(dataset=dataset) diff --git a/tensorflow/python/autograph/operators/control_flow.py b/tensorflow/python/autograph/operators/control_flow.py index 6eedd695a7..1a35efedfa 100644 --- a/tensorflow/python/autograph/operators/control_flow.py +++ b/tensorflow/python/autograph/operators/control_flow.py @@ -61,7 +61,7 @@ def for_stmt(iter_, extra_test, body, init_state): """ if tensor_util.is_tensor(iter_): return _known_len_for_stmt(iter_, extra_test, body, init_state) - elif isinstance(iter_, dataset_ops.Dataset): + elif isinstance(iter_, dataset_ops.DatasetV2): return _dataset_for_stmt(iter_, extra_test, body, init_state) else: return _py_for_stmt(iter_, extra_test, body, init_state) diff --git a/tensorflow/python/distribute/values.py b/tensorflow/python/distribute/values.py index 5f69323bff..727e491a2f 100644 --- a/tensorflow/python/distribute/values.py +++ b/tensorflow/python/distribute/values.py @@ -1433,7 +1433,7 @@ class InputFunctionIterator(InputIteratorImpl): # TODO(priyag): We should probably explicitly specify CPU device on worker. with ops.device(worker): result = input_fn(ctx) - if not isinstance(result, dataset_ops.Dataset): + if not isinstance(result, dataset_ops.DatasetV2): raise ValueError("input_fn must return a tf.data.Dataset.") iterator = _SingleWorkerDatasetIterator(result, worker, devices) iterators.append(iterator) diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index 7d915544fc..881f8b36ca 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -381,7 +381,7 @@ def validate_inputs(x, y, distribution_strategy): if is_tpu_strategy(distribution_strategy): for i in [x, y]: - if isinstance(i, dataset_ops.Dataset): + if isinstance(i, dataset_ops.DatasetV2): shapes = nest.flatten(i.output_shapes) try: s = next(s for s in shapes if not s.is_fully_defined()) diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index 56f069c057..888d8eb942 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -1000,7 +1000,7 @@ class Model(Network): # TODO(anjalisridhar): Remove this check once we refactor the # _standardize_user_data code path. This check is already present elsewhere # in the codebase. - if check_steps and isinstance(x, dataset_ops.Dataset) and steps is None: + if check_steps and isinstance(x, dataset_ops.DatasetV2) and steps is None: raise ValueError('When using Datasets as input, ' 'you should specify the `{steps_name}` argument.' .format(steps_name=steps_name)) @@ -1043,7 +1043,7 @@ class Model(Network): x = dataset_ops.Dataset.from_tensor_slices(var_x) x = x.batch(batch_size, drop_remainder=drop_remainder) - assert isinstance(x, dataset_ops.Dataset) + assert isinstance(x, dataset_ops.DatasetV2) with self._distribution_strategy.scope(): iterator = self._distribution_strategy.make_dataset_iterator(x) @@ -1132,7 +1132,7 @@ class Model(Network): shuffle=shuffle) return iterator, None, None - if isinstance(x, dataset_ops.Dataset): + if isinstance(x, dataset_ops.DatasetV2): if context.executing_eagerly(): x = x.make_one_shot_iterator() else: @@ -1691,7 +1691,7 @@ class Model(Network): if validation_data: if (isinstance(validation_data, iterator_ops.Iterator) or isinstance(validation_data, iterator_ops.EagerIterator) or - isinstance(validation_data, dataset_ops.Dataset)): + isinstance(validation_data, dataset_ops.DatasetV2)): val_x = validation_data val_y = None val_sample_weight = None @@ -2195,7 +2195,7 @@ class Model(Network): inputs, _, _ = self._standardize_user_data(x) if self.run_eagerly: if (isinstance(inputs, iterator_ops.EagerIterator) or - (isinstance(inputs, dataset_ops.Dataset))): + (isinstance(inputs, dataset_ops.DatasetV2))): inputs = training_utils.cast_if_floating_dtype(inputs) elif isinstance(inputs, collections.Sequence): inputs = [ diff --git a/tensorflow/python/keras/engine/training_generator.py b/tensorflow/python/keras/engine/training_generator.py index 45247a2751..988bed5170 100644 --- a/tensorflow/python/keras/engine/training_generator.py +++ b/tensorflow/python/keras/engine/training_generator.py @@ -67,7 +67,7 @@ def fit_generator(model, else: raise ValueError('Please specify the `steps_per_epoch` argument.') - if (isinstance(validation_data, dataset_ops.Dataset) and + if (isinstance(validation_data, dataset_ops.DatasetV2) and context.executing_eagerly()): validation_data = validation_data.make_one_shot_iterator() val_gen = (data_utils.is_generator_or_sequence(validation_data) or diff --git a/tensorflow/python/training/distribute.py b/tensorflow/python/training/distribute.py index f930a89f99..ba3334108b 100644 --- a/tensorflow/python/training/distribute.py +++ b/tensorflow/python/training/distribute.py @@ -991,7 +991,7 @@ class DistributionStrategyExtended(object): def _call_dataset_fn(self, dataset_fn): """Call the `dataset_fn` with `input_context` as argument.""" result = dataset_fn() - if not isinstance(result, dataset_ops.Dataset): + if not isinstance(result, dataset_ops.DatasetV2): raise ValueError( "dataset_fn() must return a tf.data.Dataset when using a " "tf.distribute.Strategy.") -- GitLab From 2ecbae0e9cab99682187a6ffbce03e154fbf51bb Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 21 Nov 2018 16:35:40 -0800 Subject: [PATCH 249/672] Move gfile.* functions to io.gfile.* and change API for TF 2.0. PiperOrigin-RevId: 222475688 --- tensorflow/python/lib/io/file_io.py | 239 +++++++++++++++--- .../tools/api/generator/api_init_files.bzl | 1 - .../tools/api/generator/api_init_files_v1.bzl | 1 + .../api/golden/v1/tensorflow.io.gfile.pbtxt | 51 ++++ .../tools/api/golden/v1/tensorflow.io.pbtxt | 4 + .../api/golden/v2/tensorflow.gfile.pbtxt | 47 ---- .../api/golden/v2/tensorflow.io.gfile.pbtxt | 44 ++++ .../tools/api/golden/v2/tensorflow.pbtxt | 4 - tensorflow/tools/compatibility/renames_v2.py | 19 +- .../tools/compatibility/tf_upgrade_v2.py | 47 ++++ 10 files changed, 374 insertions(+), 83 deletions(-) create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.gfile.pbtxt diff --git a/tensorflow/python/lib/io/file_io.py b/tensorflow/python/lib/io/file_io.py index c8aa5311d9..645cf8e95c 100644 --- a/tensorflow/python/lib/io/file_io.py +++ b/tensorflow/python/lib/io/file_io.py @@ -258,7 +258,7 @@ def file_exists(filename): return file_exists_v2(filename) -@tf_export("io.gfile.exists", v1=[]) +@tf_export("io.gfile.exists") def file_exists_v2(path): """Determines whether a path exists or not. @@ -280,7 +280,7 @@ def file_exists_v2(path): return True -@tf_export("gfile.Remove") +@tf_export(v1=["gfile.Remove"]) def delete_file(filename): """Deletes the file located at 'filename'. @@ -291,8 +291,22 @@ def delete_file(filename): errors.OpError: Propagates any errors reported by the FileSystem API. E.g., NotFoundError if the file does not exist. """ + delete_file_v2(filename) + + +@tf_export("io.gfile.remove") +def delete_file_v2(path): + """Deletes the path located at 'path'. + + Args: + path: string, a path + + Raises: + errors.OpError: Propagates any errors reported by the FileSystem API. E.g., + NotFoundError if the path does not exist. + """ with errors.raise_exception_on_not_ok_status() as status: - pywrap_tensorflow.DeleteFile(compat.as_bytes(filename), status) + pywrap_tensorflow.DeleteFile(compat.as_bytes(path), status) def read_file_to_string(filename, binary_mode=False): @@ -331,7 +345,7 @@ def write_string_to_file(filename, file_content): f.write(file_content) -@tf_export("gfile.Glob") +@tf_export(v1=["gfile.Glob"]) def get_matching_files(filename): """Returns a list of files that match the given pattern(s). @@ -341,28 +355,44 @@ def get_matching_files(filename): Returns: A list of strings containing filenames that match the given pattern(s). + Raises: + errors.OpError: If there are filesystem / directory listing errors. + """ + return get_matching_files_v2(filename) + + +@tf_export("io.gfile.glob") +def get_matching_files_v2(pattern): + """Returns a list of files that match the given pattern(s). + + Args: + pattern: string or iterable of strings. The glob pattern(s). + + Returns: + A list of strings containing filenames that match the given pattern(s). + Raises: errors.OpError: If there are filesystem / directory listing errors. """ with errors.raise_exception_on_not_ok_status() as status: - if isinstance(filename, six.string_types): + if isinstance(pattern, six.string_types): return [ # Convert the filenames to string from bytes. compat.as_str_any(matching_filename) for matching_filename in pywrap_tensorflow.GetMatchingFiles( - compat.as_bytes(filename), status) + compat.as_bytes(pattern), status) ] else: return [ # Convert the filenames to string from bytes. compat.as_str_any(matching_filename) - for single_filename in filename + for single_filename in pattern for matching_filename in pywrap_tensorflow.GetMatchingFiles( compat.as_bytes(single_filename), status) ] -@tf_export("gfile.MkDir") +@tf_export(v1=["gfile.MkDir"]) def create_dir(dirname): """Creates a directory with the name 'dirname'. @@ -373,14 +403,31 @@ def create_dir(dirname): The parent directories need to exist. Use recursive_create_dir instead if there is the possibility that the parent dirs don't exist. + Raises: + errors.OpError: If the operation fails. + """ + create_dir_v2(dirname) + + +@tf_export("io.gfile.mkdir") +def create_dir_v2(path): + """Creates a directory with the name given by 'path'. + + Args: + path: string, name of the directory to be created + + Notes: + The parent directories need to exist. Use recursive_create_dir instead if + there is the possibility that the parent dirs don't exist. + Raises: errors.OpError: If the operation fails. """ with errors.raise_exception_on_not_ok_status() as status: - pywrap_tensorflow.CreateDir(compat.as_bytes(dirname), status) + pywrap_tensorflow.CreateDir(compat.as_bytes(path), status) -@tf_export("gfile.MakeDirs") +@tf_export(v1=["gfile.MakeDirs"]) def recursive_create_dir(dirname): """Creates a directory and all parent/intermediate directories. @@ -389,14 +436,29 @@ def recursive_create_dir(dirname): Args: dirname: string, name of the directory to be created + Raises: + errors.OpError: If the operation fails. + """ + recursive_create_dir_v2(dirname) + + +@tf_export("io.gfile.makedirs") +def recursive_create_dir_v2(path): + """Creates a directory and all parent/intermediate directories. + + It succeeds if path already exists and is writable. + + Args: + path: string, name of the directory to be created + Raises: errors.OpError: If the operation fails. """ with errors.raise_exception_on_not_ok_status() as status: - pywrap_tensorflow.RecursivelyCreateDir(compat.as_bytes(dirname), status) + pywrap_tensorflow.RecursivelyCreateDir(compat.as_bytes(path), status) -@tf_export("gfile.Copy") +@tf_export(v1=["gfile.Copy"]) def copy(oldpath, newpath, overwrite=False): """Copies data from oldpath to newpath. @@ -406,15 +468,31 @@ def copy(oldpath, newpath, overwrite=False): overwrite: boolean, if false its an error for newpath to be occupied by an existing file. + Raises: + errors.OpError: If the operation fails. + """ + copy_v2(oldpath, newpath, overwrite) + + +@tf_export("io.gfile.copy") +def copy_v2(src, dst, overwrite=False): + """Copies data from src to dst. + + Args: + src: string, name of the file whose contents need to be copied + dst: string, name of the file to which to copy to + overwrite: boolean, if false its an error for newpath to be occupied by an + existing file. + Raises: errors.OpError: If the operation fails. """ with errors.raise_exception_on_not_ok_status() as status: pywrap_tensorflow.CopyFile( - compat.as_bytes(oldpath), compat.as_bytes(newpath), overwrite, status) + compat.as_bytes(src), compat.as_bytes(dst), overwrite, status) -@tf_export("gfile.Rename") +@tf_export(v1=["gfile.Rename"]) def rename(oldname, newname, overwrite=False): """Rename or move a file / directory. @@ -424,12 +502,28 @@ def rename(oldname, newname, overwrite=False): overwrite: boolean, if false it's an error for `newname` to be occupied by an existing file. + Raises: + errors.OpError: If the operation fails. + """ + rename_v2(oldname, newname, overwrite) + + +@tf_export("io.gfile.rename") +def rename_v2(src, dst, overwrite): + """Rename or move a file / directory. + + Args: + src: string, pathname for a file + dst: string, pathname to which the file needs to be moved + overwrite: boolean, if false it's an error for `dst` to be occupied by + an existing file. + Raises: errors.OpError: If the operation fails. """ with errors.raise_exception_on_not_ok_status() as status: pywrap_tensorflow.RenameFile( - compat.as_bytes(oldname), compat.as_bytes(newname), overwrite, status) + compat.as_bytes(src), compat.as_bytes(dst), overwrite, status) def atomic_write_string_to_file(filename, contents, overwrite=True): @@ -456,35 +550,61 @@ def atomic_write_string_to_file(filename, contents, overwrite=True): raise -@tf_export("gfile.DeleteRecursively") +@tf_export(v1=["gfile.DeleteRecursively"]) def delete_recursively(dirname): """Deletes everything under dirname recursively. Args: dirname: string, a path to a directory + Raises: + errors.OpError: If the operation fails. + """ + delete_recursively_v2(dirname) + + +@tf_export("io.gfile.rmtree") +def delete_recursively_v2(path): + """Deletes everything under path recursively. + + Args: + path: string, a path + Raises: errors.OpError: If the operation fails. """ with errors.raise_exception_on_not_ok_status() as status: - pywrap_tensorflow.DeleteRecursively(compat.as_bytes(dirname), status) + pywrap_tensorflow.DeleteRecursively(compat.as_bytes(path), status) -@tf_export("gfile.IsDirectory") +@tf_export(v1=["gfile.IsDirectory"]) def is_directory(dirname): """Returns whether the path is a directory or not. Args: dirname: string, path to a potential directory + Returns: + True, if the path is a directory; False otherwise + """ + return is_directory_v2(dirname) + + +@tf_export("io.gfile.isdir") +def is_directory_v2(path): + """Returns whether the path is a directory or not. + + Args: + path: string, path to a potential directory + Returns: True, if the path is a directory; False otherwise """ status = c_api_util.ScopedTFStatus() - return pywrap_tensorflow.IsDirectory(compat.as_bytes(dirname), status) + return pywrap_tensorflow.IsDirectory(compat.as_bytes(path), status) -@tf_export("gfile.ListDirectory") +@tf_export(v1=["gfile.ListDirectory"]) def list_directory(dirname): """Returns a list of entries contained within a directory. @@ -500,7 +620,26 @@ def list_directory(dirname): Raises: errors.NotFoundError if directory doesn't exist """ - if not is_directory(dirname): + return list_directory_v2(dirname) + + +@tf_export("io.gfile.listdir") +def list_directory_v2(path): + """Returns a list of entries contained within a directory. + + The list is in arbitrary order. It does not contain the special entries "." + and "..". + + Args: + path: string, path to a directory + + Returns: + [filename1, filename2, ... filenameN] as strings + + Raises: + errors.NotFoundError if directory doesn't exist + """ + if not is_directory(path): raise errors.NotFoundError(None, None, "Could not find directory") with errors.raise_exception_on_not_ok_status() as status: # Convert each element to string, since the return values of the @@ -508,11 +647,11 @@ def list_directory(dirname): return [ compat.as_str_any(filename) for filename in pywrap_tensorflow.GetChildren( - compat.as_bytes(dirname), status) + compat.as_bytes(path), status) ] -@tf_export("gfile.Walk") +@tf_export(v1=["gfile.Walk"]) def walk(top, in_order=True): """Recursive directory tree generator for directories. @@ -522,6 +661,27 @@ def walk(top, in_order=True): Errors that happen while listing directories are ignored. + Yields: + Each yield is a 3-tuple: the pathname of a directory, followed by lists of + all its subdirectories and leaf files. + (dirname, [subdirname, subdirname, ...], [filename, filename, ...]) + as strings + """ + return walk_v2(top, in_order) + + +@tf_export("io.gfile.walk") +def walk_v2(top, topdown, onerror=None): + """Recursive directory tree generator for directories. + + Args: + top: string, a Directory name + topdown: bool, Traverse pre order if True, post order if False. + onerror: optional handler for errors. Should be a function, it will be + called with the error as argument. Rethrowing the error aborts the walk. + + Errors that happen while listing directories are ignored. + Yields: Each yield is a 3-tuple: the pathname of a directory, followed by lists of all its subdirectories and leaf files. @@ -531,8 +691,11 @@ def walk(top, in_order=True): top = compat.as_str_any(top) try: listing = list_directory(top) - except errors.NotFoundError: - return + except errors.NotFoundError as err: + if onerror: + onerror(err) + else: + return files = [] subdirs = [] @@ -545,18 +708,18 @@ def walk(top, in_order=True): here = (top, subdirs, files) - if in_order: + if topdown: yield here for subdir in subdirs: - for subitem in walk(os.path.join(top, subdir), in_order): + for subitem in walk_v2(os.path.join(top, subdir), topdown, onerror=onerror): yield subitem - if not in_order: + if not topdown: yield here -@tf_export("gfile.Stat") +@tf_export(v1=["gfile.Stat"]) def stat(filename): """Returns file statistics for a given path. @@ -566,12 +729,28 @@ def stat(filename): Returns: FileStatistics struct that contains information about the path + Raises: + errors.OpError: If the operation fails. + """ + return stat_v2(filename) + + +@tf_export("io.gfile.stat") +def stat_v2(path): + """Returns file statistics for a given path. + + Args: + path: string, path to a file + + Returns: + FileStatistics struct that contains information about the path + Raises: errors.OpError: If the operation fails. """ file_statistics = pywrap_tensorflow.FileStatistics() with errors.raise_exception_on_not_ok_status() as status: - pywrap_tensorflow.Stat(compat.as_bytes(filename), file_statistics, status) + pywrap_tensorflow.Stat(compat.as_bytes(path), file_statistics, status) return file_statistics diff --git a/tensorflow/python/tools/api/generator/api_init_files.bzl b/tensorflow/python/tools/api/generator/api_init_files.bzl index b41a1bc8f6..3517c11cc9 100644 --- a/tensorflow/python/tools/api/generator/api_init_files.bzl +++ b/tensorflow/python/tools/api/generator/api_init_files.bzl @@ -14,7 +14,6 @@ TENSORFLOW_API_INIT_FILES = [ "errors/__init__.py", "experimental/__init__.py", "feature_column/__init__.py", - "gfile/__init__.py", "io/gfile/__init__.py", "graph_util/__init__.py", "image/__init__.py", diff --git a/tensorflow/python/tools/api/generator/api_init_files_v1.bzl b/tensorflow/python/tools/api/generator/api_init_files_v1.bzl index 0fadec00ab..e35b9c4374 100644 --- a/tensorflow/python/tools/api/generator/api_init_files_v1.bzl +++ b/tensorflow/python/tools/api/generator/api_init_files_v1.bzl @@ -17,6 +17,7 @@ TENSORFLOW_API_INIT_FILES_V1 = [ "experimental/__init__.py", "feature_column/__init__.py", "gfile/__init__.py", + "io/gfile/__init__.py", "graph_util/__init__.py", "image/__init__.py", "io/__init__.py", diff --git a/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt new file mode 100644 index 0000000000..e5aba7eff9 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt @@ -0,0 +1,51 @@ +path: "tensorflow.io.gfile" +tf_module { + member_method { + name: "copy" + argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=[\'False\'], " + } + member_method { + name: "exists" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "glob" + argspec: "args=[\'pattern\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "isdir" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "listdir" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "makedirs" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "mkdir" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "remove" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "rename" + argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "rmtree" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "stat" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "walk" + argspec: "args=[\'top\', \'topdown\', \'onerror\'], varargs=None, keywords=None, defaults=[\'None\'], " + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt index fee12594ee..b760ec3890 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.io.pbtxt @@ -44,6 +44,10 @@ tf_module { name: "VarLenFeature" mtype: "" } + member { + name: "gfile" + mtype: "" + } member_method { name: "decode_and_crop_jpeg" argspec: "args=[\'contents\', \'crop_window\', \'channels\', \'ratio\', \'fancy_upscaling\', \'try_recover_truncated\', \'acceptable_fraction\', \'dct_method\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'1\', \'True\', \'False\', \'1\', \'\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.gfile.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.gfile.pbtxt deleted file mode 100644 index 74d0a0579e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.gfile.pbtxt +++ /dev/null @@ -1,47 +0,0 @@ -path: "tensorflow.gfile" -tf_module { - member_method { - name: "Copy" - argspec: "args=[\'oldpath\', \'newpath\', \'overwrite\'], varargs=None, keywords=None, defaults=[\'False\'], " - } - member_method { - name: "DeleteRecursively" - argspec: "args=[\'dirname\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "Glob" - argspec: "args=[\'filename\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "IsDirectory" - argspec: "args=[\'dirname\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "ListDirectory" - argspec: "args=[\'dirname\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "MakeDirs" - argspec: "args=[\'dirname\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "MkDir" - argspec: "args=[\'dirname\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "Remove" - argspec: "args=[\'filename\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "Rename" - argspec: "args=[\'oldname\', \'newname\', \'overwrite\'], varargs=None, keywords=None, defaults=[\'False\'], " - } - member_method { - name: "Stat" - argspec: "args=[\'filename\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "Walk" - argspec: "args=[\'top\', \'in_order\'], varargs=None, keywords=None, defaults=[\'True\'], " - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt index 59652cb063..e5aba7eff9 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt @@ -1,7 +1,51 @@ path: "tensorflow.io.gfile" tf_module { + member_method { + name: "copy" + argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=[\'False\'], " + } member_method { name: "exists" argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" } + member_method { + name: "glob" + argspec: "args=[\'pattern\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "isdir" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "listdir" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "makedirs" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "mkdir" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "remove" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "rename" + argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "rmtree" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "stat" + argspec: "args=[\'path\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "walk" + argspec: "args=[\'top\', \'topdown\', \'onerror\'], varargs=None, keywords=None, defaults=[\'None\'], " + } } diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index b4b4827584..99751504ae 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -220,10 +220,6 @@ tf_module { name: "float64" mtype: "" } - member { - name: "gfile" - mtype: "" - } member { name: "glorot_uniform_initializer" mtype: "" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 474686d612..dc47796a7c 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -155,7 +155,7 @@ renames = { 'tf.erf': 'tf.math.erf', 'tf.erfc': 'tf.math.erfc', 'tf.expm1': 'tf.math.expm1', - 'tf.extract_image_patches': 'tf.image.extract_image_patches', + 'tf.extract_image_patches': 'tf.compat.v1.extract_image_patches', 'tf.fake_quant_with_min_max_args': 'tf.quantization.fake_quant_with_min_max_args', 'tf.fake_quant_with_min_max_args_gradient': 'tf.quantization.fake_quant_with_min_max_args_gradient', 'tf.fake_quant_with_min_max_vars': 'tf.quantization.fake_quant_with_min_max_vars', @@ -179,10 +179,21 @@ renames = { 'tf.get_session_tensor': 'tf.compat.v1.get_session_tensor', 'tf.get_variable': 'tf.compat.v1.get_variable', 'tf.get_variable_scope': 'tf.compat.v1.get_variable_scope', + 'tf.gfile.Copy': 'tf.compat.v1.gfile.Copy', + 'tf.gfile.DeleteRecursively': 'tf.compat.v1.gfile.DeleteRecursively', 'tf.gfile.Exists': 'tf.compat.v1.gfile.Exists', 'tf.gfile.FastGFile': 'tf.compat.v1.gfile.FastGFile', 'tf.gfile.GFile': 'tf.compat.v1.gfile.GFile', + 'tf.gfile.Glob': 'tf.compat.v1.gfile.Glob', + 'tf.gfile.IsDirectory': 'tf.compat.v1.gfile.IsDirectory', + 'tf.gfile.ListDirectory': 'tf.compat.v1.gfile.ListDirectory', + 'tf.gfile.MakeDirs': 'tf.compat.v1.gfile.MakeDirs', + 'tf.gfile.MkDir': 'tf.compat.v1.gfile.MkDir', 'tf.gfile.Open': 'tf.compat.v1.gfile.Open', + 'tf.gfile.Remove': 'tf.compat.v1.gfile.Remove', + 'tf.gfile.Rename': 'tf.compat.v1.gfile.Rename', + 'tf.gfile.Stat': 'tf.compat.v1.gfile.Stat', + 'tf.gfile.Walk': 'tf.compat.v1.gfile.Walk', 'tf.global_norm': 'tf.linalg.global_norm', 'tf.global_variables': 'tf.compat.v1.global_variables', 'tf.global_variables_initializer': 'tf.compat.v1.global_variables_initializer', @@ -308,12 +319,16 @@ renames = { 'tf.matrix_solve_ls': 'tf.linalg.lstsq', 'tf.matrix_transpose': 'tf.linalg.transpose', 'tf.matrix_triangular_solve': 'tf.linalg.triangular_solve', + 'tf.metrics.accuracy': 'tf.compat.v1.metrics.accuracy', + 'tf.metrics.mean': 'tf.compat.v1.metrics.mean', 'tf.min_max_variable_partitioner': 'tf.compat.v1.min_max_variable_partitioner', 'tf.model_variables': 'tf.compat.v1.model_variables', 'tf.moving_average_variables': 'tf.compat.v1.moving_average_variables', 'tf.multinomial': 'tf.compat.v1.multinomial', + 'tf.nn.bidirectional_dynamic_rnn': 'tf.compat.v1.nn.bidirectional_dynamic_rnn', 'tf.nn.conv3d_backprop_filter_v2': 'tf.nn.conv3d_backprop_filter', 'tf.nn.ctc_beam_search_decoder_v2': 'tf.nn.ctc_beam_search_decoder', + 'tf.nn.ctc_loss_v2': 'tf.nn.ctc_loss', 'tf.nn.depthwise_conv2d_native': 'tf.compat.v1.nn.depthwise_conv2d_native', 'tf.nn.depthwise_conv2d_native_backprop_filter': 'tf.nn.depthwise_conv2d_backprop_filter', 'tf.nn.depthwise_conv2d_native_backprop_input': 'tf.nn.depthwise_conv2d_backprop_input', @@ -328,7 +343,9 @@ renames = { 'tf.nn.rnn_cell.BasicRNNCell': 'tf.compat.v1.nn.rnn_cell.BasicRNNCell', 'tf.nn.rnn_cell.GRUCell': 'tf.compat.v1.nn.rnn_cell.GRUCell', 'tf.nn.rnn_cell.LSTMCell': 'tf.compat.v1.nn.rnn_cell.LSTMCell', + 'tf.nn.rnn_cell.MultiRNNCell': 'tf.compat.v1.nn.rnn_cell.MultiRNNCell', 'tf.nn.softmax_cross_entropy_with_logits_v2': 'tf.nn.softmax_cross_entropy_with_logits', + 'tf.nn.static_bidirectional_rnn': 'tf.compat.v1.nn.static_bidirectional_rnn', 'tf.nn.static_rnn': 'tf.compat.v1.nn.static_rnn', 'tf.nn.uniform_candidate_sampler': 'tf.random.uniform_candidate_sampler', 'tf.nn.xw_plus_b': 'tf.compat.v1.nn.xw_plus_b', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 05e839aa9d..b8cf21b29c 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -111,6 +111,41 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.gfile.Exists": { "filename": "path", }, + "tf.gfile.Remove": { + "filename": "path", + }, + "tf.gfile.Stat": { + "filename": "path", + }, + "tf.gfile.Glob": { + "filename": "pattern", + }, + "tf.gfile.MkDir": { + "dirname": "path", + }, + "tf.gfile.MakeDirs": { + "dirname": "path", + }, + "tf.gfile.DeleteRecursively": { + "dirname": "path", + }, + "tf.gfile.IsDirectory": { + "dirname": "path", + }, + "tf.gfile.ListDirectory": { + "dirname": "path", + }, + "tf.gfile.Copy": { + "oldpath": "src", + "newpath": "dst", + }, + "tf.gfile.Rename": { + "oldpath": "src", + "newpath": "dst", + }, + "tf.gfile.Walk": { + "in_order": "topdown", + }, "tf.random.stateless_multinomial": { "output_dtype": "dtype", }, @@ -212,6 +247,18 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # These renames happen after the arguments have been processed. self.symbol_renames.update({ "tf.batch_to_space_nd": "tf.batch_to_space", + "tf.gfile.Copy": "tf.io.gfile.Copy", + "tf.gfile.DeleteRecursively": "tf.io.gfile.DeleteRecursively", + "tf.gfile.Exists": "tf.io.gfile.Exists", + "tf.gfile.Glob": "tf.io.gfile.Glob", + "tf.gfile.IsDirectory": "tf.io.gfile.IsDirectory", + "tf.gfile.ListDirectory": "tf.io.gfile.ListDirectory", + "tf.gfile.MakeDirs": "tf.io.gfile.MakeDirs", + "tf.gfile.MkDir": "tf.io.gfile.MkDir", + "tf.gfile.Remove": "tf.io.gfile.Remove", + "tf.gfile.Rename": "tf.io.gfile.Rename", + "tf.gfile.Stat": "tf.io.gfile.Stat", + "tf.gfile.Walk": "tf.io.gfile.Walk", "tf.contrib.data.AUTOTUNE": "tf.data.experimental.AUTOTUNE", "tf.contrib.data.Counter": "tf.data.experimental.Counter", "tf.contrib.data.CheckpointInputPipelineHook": "tf.data.experimental.CheckpointInputPipelineHook", -- GitLab From afda578147523be4a302f5a785c1e8e32d6650f4 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 16:46:58 -0800 Subject: [PATCH 250/672] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 222476857 --- tensorflow/go/op/wrappers.go | 142 +++++++++++++++++------------------ 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index 9b59c03e55..ab7294e5a1 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -5661,6 +5661,77 @@ func MapSize(scope *Scope, dtypes []tf.DataType, optional ...MapSizeAttr) (size return op.Output(0) } +// MapUnstageAttr is an optional argument to MapUnstage. +type MapUnstageAttr func(optionalAttr) + +// MapUnstageCapacity sets the optional capacity attribute to value. +// If not specified, defaults to 0 +// +// REQUIRES: value >= 0 +func MapUnstageCapacity(value int64) MapUnstageAttr { + return func(m optionalAttr) { + m["capacity"] = value + } +} + +// MapUnstageMemoryLimit sets the optional memory_limit attribute to value. +// If not specified, defaults to 0 +// +// REQUIRES: value >= 0 +func MapUnstageMemoryLimit(value int64) MapUnstageAttr { + return func(m optionalAttr) { + m["memory_limit"] = value + } +} + +// MapUnstageContainer sets the optional container attribute to value. +// If not specified, defaults to "" +func MapUnstageContainer(value string) MapUnstageAttr { + return func(m optionalAttr) { + m["container"] = value + } +} + +// MapUnstageSharedName sets the optional shared_name attribute to value. +// If not specified, defaults to "" +func MapUnstageSharedName(value string) MapUnstageAttr { + return func(m optionalAttr) { + m["shared_name"] = value + } +} + +// Op removes and returns the values associated with the key +// +// from the underlying container. If the underlying container +// does not contain this key, the op will block until it does. +func MapUnstage(scope *Scope, key tf.Output, indices tf.Output, dtypes []tf.DataType, optional ...MapUnstageAttr) (values []tf.Output) { + if scope.Err() != nil { + return + } + attrs := map[string]interface{}{"dtypes": dtypes} + for _, a := range optional { + a(attrs) + } + opspec := tf.OpSpec{ + Type: "MapUnstage", + Input: []tf.Input{ + key, indices, + }, + Attrs: attrs, + } + op := scope.AddOperation(opspec) + if scope.Err() != nil { + return + } + var idx int + var err error + if values, idx, err = makeOutputList(op, idx, "values"); err != nil { + scope.UpdateErr("MapUnstage", err) + return + } + return values +} + // Compute the regularized incomplete beta integral \\(I_x(a, b)\\). // // The regularized incomplete beta integral is defined as: @@ -33926,74 +33997,3 @@ func MapStage(scope *Scope, key tf.Output, indices tf.Output, values []tf.Output } return scope.AddOperation(opspec) } - -// MapUnstageAttr is an optional argument to MapUnstage. -type MapUnstageAttr func(optionalAttr) - -// MapUnstageCapacity sets the optional capacity attribute to value. -// If not specified, defaults to 0 -// -// REQUIRES: value >= 0 -func MapUnstageCapacity(value int64) MapUnstageAttr { - return func(m optionalAttr) { - m["capacity"] = value - } -} - -// MapUnstageMemoryLimit sets the optional memory_limit attribute to value. -// If not specified, defaults to 0 -// -// REQUIRES: value >= 0 -func MapUnstageMemoryLimit(value int64) MapUnstageAttr { - return func(m optionalAttr) { - m["memory_limit"] = value - } -} - -// MapUnstageContainer sets the optional container attribute to value. -// If not specified, defaults to "" -func MapUnstageContainer(value string) MapUnstageAttr { - return func(m optionalAttr) { - m["container"] = value - } -} - -// MapUnstageSharedName sets the optional shared_name attribute to value. -// If not specified, defaults to "" -func MapUnstageSharedName(value string) MapUnstageAttr { - return func(m optionalAttr) { - m["shared_name"] = value - } -} - -// Op removes and returns the values associated with the key -// -// from the underlying container. If the underlying container -// does not contain this key, the op will block until it does. -func MapUnstage(scope *Scope, key tf.Output, indices tf.Output, dtypes []tf.DataType, optional ...MapUnstageAttr) (values []tf.Output) { - if scope.Err() != nil { - return - } - attrs := map[string]interface{}{"dtypes": dtypes} - for _, a := range optional { - a(attrs) - } - opspec := tf.OpSpec{ - Type: "MapUnstage", - Input: []tf.Input{ - key, indices, - }, - Attrs: attrs, - } - op := scope.AddOperation(opspec) - if scope.Err() != nil { - return - } - var idx int - var err error - if values, idx, err = makeOutputList(op, idx, "values"); err != nil { - scope.UpdateErr("MapUnstage", err) - return - } - return values -} -- GitLab From 1a0e8eb4d6524d9381f495d13521b98fed8c5ca7 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 21 Nov 2018 18:03:17 -0800 Subject: [PATCH 251/672] Make {Stateless}Multinomial return a matrix even when num_samples=0 PiperOrigin-RevId: 222482965 --- .../compiler/tests/categorical_op_test.py | 21 +++++++++++++++++++ .../compiler/tf2xla/kernels/categorical_op.cc | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/tests/categorical_op_test.py b/tensorflow/compiler/tests/categorical_op_test.py index f17e84df13..f4918e50dc 100644 --- a/tensorflow/compiler/tests/categorical_op_test.py +++ b/tensorflow/compiler/tests/categorical_op_test.py @@ -169,6 +169,27 @@ class CategoricalTest(xla_test.XLATestCase): for s1, v1 in values: self.assertEqual(s0 == s1, np.all(v0 == v1)) + def testEmpty(self): + with self.cached_session() as sess: + with self.test_scope(): + x = random_ops.multinomial( + array_ops.zeros([42, 40]), 0, output_dtype=dtypes.int32) + y = sess.run(x) + self.assertEqual(y.shape, (42, 0)) + + def testEmptyStateless(self): + with self.cached_session() as sess: + with self.test_scope(): + seed_t = array_ops.placeholder(dtypes.int32, shape=[2]) + x = stateless_random_ops.stateless_multinomial( + array_ops.zeros([42, 40]), + 0, + seed=seed_t, + output_dtype=dtypes.int32) + y = sess.run(x, {seed_t: [0x12345678, 0xabcdef12]}) + self.assertEqual(y.shape, (42, 0)) + + if __name__ == '__main__': googletest.main() diff --git a/tensorflow/compiler/tf2xla/kernels/categorical_op.cc b/tensorflow/compiler/tf2xla/kernels/categorical_op.cc index 3e398fff95..7199b9b6fe 100644 --- a/tensorflow/compiler/tf2xla/kernels/categorical_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/categorical_op.cc @@ -62,7 +62,7 @@ class CategoricalOp : public XlaOpKernel { xla::Shape uniform_shape; int class_dimension; - if (num_samples > 1) { + if (num_samples != 1) { std::array uniform_shape_array = { {batch_size, num_samples, num_classes}}; xla::PrimitiveType uniform_xla_type; -- GitLab From 0dad8cfde287c4ffcff059f1df24dfd2aa5ae662 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 18:20:17 -0800 Subject: [PATCH 252/672] This CL updates the Keras model microbenchmarks in the eager benchmarks_test to reflect Keras's updated execution modes. PiperOrigin-RevId: 222484074 --- tensorflow/python/eager/benchmarks_test.py | 58 +++++++++------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/tensorflow/python/eager/benchmarks_test.py b/tensorflow/python/eager/benchmarks_test.py index 886715867c..31a7efca82 100644 --- a/tensorflow/python/eager/benchmarks_test.py +++ b/tensorflow/python/eager/benchmarks_test.py @@ -80,7 +80,6 @@ class SubclassedKerasModel(keras.Model): def __init__(self, initializer="ones"): super(SubclassedKerasModel, self).__init__() - self._can_use_graph_functions = True self.layer_a = keras.layers.Dense( 64, kernel_initializer=initializer, bias_initializer="zeros") self.layer_b = keras.layers.Dense( @@ -733,38 +732,38 @@ class MicroBenchmarks(test.Benchmark): assert np.equal(func(), make_keras_model()(data)).all() self._run(func, 30000) - def _benchmark_keras_model_fit(self, model): + def _benchmark_keras_model_fit(self, model, run_eagerly=False): data = random_ops.random_uniform((10, 10), minval=-1, maxval=1) labels = random_ops.random_uniform((10, 10), minval=-1, maxval=1) dataset = dataset_ops.Dataset.from_tensors((data, labels)).repeat() model.compile( gradient_descent.GradientDescentOptimizer(learning_rate=0.001), - loss="mse") + loss="mse", run_eagerly=run_eagerly) func = lambda: model.fit(dataset, epochs=1, steps_per_epoch=1000, verbose=0) # First call is more expensive (creates variables etc.), discount that. model.fit(dataset, epochs=1, steps_per_epoch=1, verbose=0) self._run(func, 1) - def _benchmark_keras_model_evaluate(self, model): + def _benchmark_keras_model_evaluate(self, model, run_eagerly=False): data = random_ops.random_uniform((10, 10), minval=-1, maxval=1) labels = random_ops.random_uniform((10, 10), minval=-1, maxval=1) dataset = dataset_ops.Dataset.from_tensors((data, labels)).repeat() model.compile( gradient_descent.GradientDescentOptimizer(learning_rate=0.001), - loss="mse") + loss="mse", run_eagerly=run_eagerly) func = lambda: model.evaluate(dataset, steps=1000, verbose=0) # First call is more expensive (creates variables etc.), discount that. model.evaluate(dataset, steps=1, verbose=0) self._run(func, 1) - def _benchmark_keras_model_predict(self, model): + def _benchmark_keras_model_predict(self, model, run_eagerly=False): data = random_ops.random_uniform((10, 10), minval=-1, maxval=1) dataset = dataset_ops.Dataset.from_tensors(tuple([data])).repeat() model.compile( gradient_descent.GradientDescentOptimizer(learning_rate=0.001), - loss="mse") + loss="mse", run_eagerly=run_eagerly) func = lambda: model.predict(dataset, steps=1000, verbose=0) # First call is more expensive (creates variables etc.), discount that. model.predict(dataset, steps=1, verbose=0) @@ -780,10 +779,9 @@ class MicroBenchmarks(test.Benchmark): model = SubclassedKerasModel(initializer="glorot_uniform") self._benchmark_keras_model_fit(model) - def benchmark_keras_model_subclassed_fit_disable_defun(self): + def benchmark_keras_model_subclassed_fit_run_model_eagerly(self): model = SubclassedKerasModel(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_fit(model) + self._benchmark_keras_model_fit(model, run_eagerly=True) def benchmark_keras_model_functional_fit(self): model = make_keras_model(initializer="glorot_uniform") @@ -794,10 +792,9 @@ class MicroBenchmarks(test.Benchmark): model = make_keras_model(initializer="glorot_uniform") self._benchmark_keras_model_fit(model) - def benchmark_keras_model_functional_fit_disable_defun(self): + def benchmark_keras_model_functional_fit_run_model_eagerly(self): model = make_keras_model(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_fit(model) + self._benchmark_keras_model_fit(model, run_eagerly=True) def benchmark_keras_model_sequential_fit(self): model = make_sequential_keras_model(initializer="glorot_uniform") @@ -808,64 +805,57 @@ class MicroBenchmarks(test.Benchmark): model = make_sequential_keras_model(initializer="glorot_uniform") self._benchmark_keras_model_fit(model) - def benchmark_keras_model_sequential_fit_disable_defun(self): + def benchmark_keras_model_sequential_fit_run_model_eagerly(self): model = make_sequential_keras_model(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_fit(model) + self._benchmark_keras_model_fit(model, run_eagerly=True) def benchmark_keras_model_subclassed_evaluate(self): model = SubclassedKerasModel(initializer="glorot_uniform") self._benchmark_keras_model_evaluate(model) - def benchmark_keras_model_subclassed_evaluate_disable_defun(self): + def benchmark_keras_model_subclassed_evaluate_run_model_eagerly(self): model = SubclassedKerasModel(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_evaluate(model) + self._benchmark_keras_model_evaluate(model, run_eagerly=True) def benchmark_keras_model_functional_evaluate(self): model = make_keras_model(initializer="glorot_uniform") self._benchmark_keras_model_evaluate(model) - def benchmark_keras_model_functional_evaluate_disable_defun(self): + def benchmark_keras_model_functional_evaluate_run_model_eagerly(self): model = make_keras_model(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_evaluate(model) + self._benchmark_keras_model_evaluate(model, run_eagerly=True) def benchmark_keras_model_sequential_evaluate(self): model = make_sequential_keras_model(initializer="glorot_uniform") self._benchmark_keras_model_evaluate(model) - def benchmark_keras_model_sequential_evaluate_disable_defun(self): + def benchmark_keras_model_sequential_evaluate_run_model_eagerly(self): model = make_sequential_keras_model(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_evaluate(model) + self._benchmark_keras_model_evaluate(model, run_eagerly=True) def benchmark_keras_model_subclassed_predict(self): model = SubclassedKerasModel(initializer="glorot_uniform") self._benchmark_keras_model_predict(model) - def benchmark_keras_model_subclassed_predict_disable_defun(self): + def benchmark_keras_model_subclassed_predict_run_model_eagerly(self): model = SubclassedKerasModel(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_predict(model) + self._benchmark_keras_model_predict(model, run_eagerly=True) def benchmark_keras_model_functional_predict(self): model = make_keras_model(initializer="glorot_uniform") self._benchmark_keras_model_predict(model) - def benchmark_keras_model_functional_predict_disable_defun(self): + def benchmark_keras_model_functional_predict_run_model_eagerly(self): model = make_keras_model(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_predict(model) + self._benchmark_keras_model_predict(model, run_eagerly=True) def benchmark_keras_model_sequential_predict(self): model = make_sequential_keras_model(initializer="glorot_uniform") self._benchmark_keras_model_predict(model) - def benchmark_keras_model_sequential_predict_disable_defun(self): + def benchmark_keras_model_sequential_predict_run_model_eagerly(self): model = make_sequential_keras_model(initializer="glorot_uniform") - model._can_use_graph_functions = False - self._benchmark_keras_model_predict(model) + self._benchmark_keras_model_predict(model, run_eagerly=True) def benchmarkScan(self): elems = math_ops.range(1600) -- GitLab From 824bf4c67f01364b23be5c69fe5365ef35dc779a Mon Sep 17 00:00:00 2001 From: Kay Zhu Date: Wed, 21 Nov 2018 18:20:43 -0800 Subject: [PATCH 253/672] [TF2XLA] Conditionally include tf2xla/kernels:resampler_ops as contrib/resampler:resampler_ops_kernels' dependency based on whether XLA is enabled. Also move compiler/tests/resampler_ops_test.py to contrib/resampler/xla/resampler_ops_xla_test.py instead. PiperOrigin-RevId: 222484109 --- tensorflow/compiler/tests/BUILD | 21 ------------ tensorflow/contrib/resampler/BUILD | 32 +++++++++++++++++-- .../resampler/xla/resampler_ops_xla_test.py} | 0 3 files changed, 30 insertions(+), 23 deletions(-) rename tensorflow/{compiler/tests/resampler_ops_test.py => contrib/resampler/xla/resampler_ops_xla_test.py} (100%) diff --git a/tensorflow/compiler/tests/BUILD b/tensorflow/compiler/tests/BUILD index 2b88a64fed..bc3d60b90e 100644 --- a/tensorflow/compiler/tests/BUILD +++ b/tensorflow/compiler/tests/BUILD @@ -375,27 +375,6 @@ tf_xla_py_test( ], ) -tf_xla_py_test( - name = "resampler_ops_test", - size = "small", - srcs = ["resampler_ops_test.py"], - disabled_backends = [ - # TODO(b/74459949) Support BatchDot in CPU backend. - "cpu", - "cpu_ondemand", - ], - # TODO(b/112295522): figure out how to make OSS build pass. - tags = ["no_oss"], - deps = [ - ":xla_test", - "//tensorflow/contrib/resampler:resampler_ops", - "//tensorflow/contrib/resampler:resampler_py", - "//tensorflow/python:array_ops", - "//tensorflow/python:client_testlib", - "//tensorflow/python:platform_test", - ], -) - tf_xla_py_test( name = "dynamic_stitch_test", size = "small", diff --git a/tensorflow/contrib/resampler/BUILD b/tensorflow/contrib/resampler/BUILD index 38fcca0311..bbf1099675 100644 --- a/tensorflow/contrib/resampler/BUILD +++ b/tensorflow/contrib/resampler/BUILD @@ -13,6 +13,7 @@ load( ) load("//tensorflow:tensorflow.bzl", "cuda_py_test") load("//tensorflow:tensorflow.bzl", "tf_custom_op_py_library") +load("//tensorflow/compiler/tests:build_defs.bzl", "tf_xla_py_test") tf_custom_op_py_library( name = "resampler_py", @@ -50,10 +51,14 @@ tf_kernel_library( prefix = "resampler_ops", deps = [ ":resampler_ops_op_lib", - "//tensorflow/compiler/tf2xla/kernels:resampler_ops", "//tensorflow/core:framework", "//tensorflow/core:lib", - ], + ] + select({ + "//tensorflow:with_xla_support": [ + "//tensorflow/compiler/tf2xla/kernels:resampler_ops", + ], + "//conditions:default": [], + }), alwayslink = 1, ) @@ -94,3 +99,26 @@ cuda_py_test( "//tensorflow/python:array_ops", ], ) + +tf_xla_py_test( + name = "resampler_ops_xla_test", + size = "small", + srcs = ["xla/resampler_ops_xla_test.py"], + disabled_backends = [ + # TODO(b/74459949) Support BatchDot in CPU backend. + "cpu", + "cpu_ondemand", + ], + # TODO(b/112295522): the OSS build will not likely work in the short to medium term, currently it is blocked by the fact that bazel does not allow py_library to depend on cc_library: https://github.com/bazelbuild/bazel/issues/701 which may not be resolvable. + tags = ["no_oss"], + deps = [ + "//tensorflow/compiler/tests:xla_test", + "//tensorflow/compiler/tf2xla/kernels:resampler_ops", + "//tensorflow/contrib/resampler:resampler_ops", + "//tensorflow/contrib/resampler:resampler_py", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:platform_test", + "//third_party/py/numpy", + ], +) diff --git a/tensorflow/compiler/tests/resampler_ops_test.py b/tensorflow/contrib/resampler/xla/resampler_ops_xla_test.py similarity index 100% rename from tensorflow/compiler/tests/resampler_ops_test.py rename to tensorflow/contrib/resampler/xla/resampler_ops_xla_test.py -- GitLab From 1e4e6328c516ff9d5e861d64bc0d7626c579e670 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Wed, 21 Nov 2018 18:31:12 -0800 Subject: [PATCH 254/672] [tf.data] Moving the (experimental) MatchingFiles dataset implementation to the experimental source subtree. Since the transformation is not exposed in the API, this CL has no effect on the API. PiperOrigin-RevId: 222484670 --- ...def_ExperimentalMatchingFilesDataset.pbtxt | 4 + .../api_def_MatchingFilesDataset.pbtxt | 4 - tensorflow/core/kernels/data/BUILD | 13 --- .../core/kernels/data/experimental/BUILD | 13 +++ .../matching_files_dataset_op.cc | 5 +- .../core/ops/compat/ops_history.v1.pbtxt | 12 -- tensorflow/core/ops/dataset_ops.cc | 12 -- .../core/ops/experimental_dataset_ops.cc | 12 ++ .../python/data/experimental/benchmarks/BUILD | 17 +++ .../benchmarks/matching_files_benchmark.py | 101 +++++++++++++++++ .../data/experimental/kernel_tests/BUILD | 19 ++++ .../kernel_tests/matching_files_test.py} | 105 ++++-------------- .../kernel_tests/serialization/BUILD | 1 + ...tching_files_dataset_serialization_test.py | 4 +- tensorflow/python/data/experimental/ops/BUILD | 12 ++ .../data/experimental/ops/matching_files.py | 51 +++++++++ tensorflow/python/data/kernel_tests/BUILD | 44 +++++--- tensorflow/python/data/ops/dataset_ops.py | 24 ---- 18 files changed, 283 insertions(+), 170 deletions(-) create mode 100644 tensorflow/core/api_def/base_api/api_def_ExperimentalMatchingFilesDataset.pbtxt delete mode 100644 tensorflow/core/api_def/base_api/api_def_MatchingFilesDataset.pbtxt rename tensorflow/core/kernels/data/{ => experimental}/matching_files_dataset_op.cc (99%) create mode 100644 tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py rename tensorflow/python/data/{kernel_tests/matching_files_dataset_op_test.py => experimental/kernel_tests/matching_files_test.py} (62%) create mode 100644 tensorflow/python/data/experimental/ops/matching_files.py diff --git a/tensorflow/core/api_def/base_api/api_def_ExperimentalMatchingFilesDataset.pbtxt b/tensorflow/core/api_def/base_api/api_def_ExperimentalMatchingFilesDataset.pbtxt new file mode 100644 index 0000000000..993a798149 --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_ExperimentalMatchingFilesDataset.pbtxt @@ -0,0 +1,4 @@ +op { + graph_op_name: "ExperimentalMatchingFilesDataset" + visibility: HIDDEN +} diff --git a/tensorflow/core/api_def/base_api/api_def_MatchingFilesDataset.pbtxt b/tensorflow/core/api_def/base_api/api_def_MatchingFilesDataset.pbtxt deleted file mode 100644 index ab2a33108d..0000000000 --- a/tensorflow/core/api_def/base_api/api_def_MatchingFilesDataset.pbtxt +++ /dev/null @@ -1,4 +0,0 @@ -op { - graph_op_name: "MatchingFilesDataset" - visibility: HIDDEN -} diff --git a/tensorflow/core/kernels/data/BUILD b/tensorflow/core/kernels/data/BUILD index b7ccf5f70e..7192684e2d 100644 --- a/tensorflow/core/kernels/data/BUILD +++ b/tensorflow/core/kernels/data/BUILD @@ -662,18 +662,6 @@ tf_kernel_library( ], ) -tf_kernel_library( - name = "matching_files_dataset_op", - srcs = ["matching_files_dataset_op.cc"], - deps = [ - ":dataset", - "//tensorflow/core:dataset_ops_op_lib", - "//tensorflow/core:framework", - "//tensorflow/core:lib", - "//tensorflow/core:lib_internal", - ], -) - tf_kernel_library( name = "model_dataset_op", srcs = ["model_dataset_op.cc"], @@ -718,7 +706,6 @@ tf_kernel_library( ":map_and_batch_dataset_op", ":map_dataset_op", ":map_defun_op", - ":matching_files_dataset_op", ":model_dataset_op", ":multi_device_iterator_ops", ":optimize_dataset_op", diff --git a/tensorflow/core/kernels/data/experimental/BUILD b/tensorflow/core/kernels/data/experimental/BUILD index 1a18864ecf..958c42a22a 100644 --- a/tensorflow/core/kernels/data/experimental/BUILD +++ b/tensorflow/core/kernels/data/experimental/BUILD @@ -157,6 +157,18 @@ tf_kernel_library( ], ) +tf_kernel_library( + name = "matching_files_dataset_op", + srcs = ["matching_files_dataset_op.cc"], + deps = [ + "//tensorflow/core:experimental_dataset_ops_op_lib", + "//tensorflow/core:framework", + "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", + "//tensorflow/core/kernels/data:dataset", + ], +) + tf_kernel_library( name = "dataset_kernels", deps = [ @@ -166,6 +178,7 @@ tf_kernel_library( ":ignore_errors_dataset_op", ":indexed_dataset", ":lmdb_dataset_op", + ":matching_files_dataset_op", ":non_serializable_dataset_op", ":numa_map_and_batch_dataset_op", ":prefetching_kernels", diff --git a/tensorflow/core/kernels/data/matching_files_dataset_op.cc b/tensorflow/core/kernels/data/experimental/matching_files_dataset_op.cc similarity index 99% rename from tensorflow/core/kernels/data/matching_files_dataset_op.cc rename to tensorflow/core/kernels/data/experimental/matching_files_dataset_op.cc index d36b9e7e78..aa27a13416 100644 --- a/tensorflow/core/kernels/data/matching_files_dataset_op.cc +++ b/tensorflow/core/kernels/data/experimental/matching_files_dataset_op.cc @@ -366,8 +366,9 @@ class MatchingFilesDatasetOp : public DatasetOpKernel { }; }; -REGISTER_KERNEL_BUILDER(Name("MatchingFilesDataset").Device(DEVICE_CPU), - MatchingFilesDatasetOp); +REGISTER_KERNEL_BUILDER( + Name("ExperimentalMatchingFilesDataset").Device(DEVICE_CPU), + MatchingFilesDatasetOp); } // namespace } // namespace data diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index 309154d74d..efb2f5ed03 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -31544,18 +31544,6 @@ op { type: DT_STRING } } -op { - name: "MatchingFilesDataset" - input_arg { - name: "patterns" - type: DT_STRING - } - output_arg { - name: "handle" - type: DT_VARIANT - } - is_stateful: true -} op { name: "MatrixBandPart" input_arg { diff --git a/tensorflow/core/ops/dataset_ops.cc b/tensorflow/core/ops/dataset_ops.cc index 8402f250f9..e7212b7004 100644 --- a/tensorflow/core/ops/dataset_ops.cc +++ b/tensorflow/core/ops/dataset_ops.cc @@ -622,18 +622,6 @@ REGISTER_OP("TextLineDataset") return shape_inference::ScalarShape(c); }); -REGISTER_OP("MatchingFilesDataset") - .Input("patterns: string") - .Output("handle: variant") - .SetIsStateful() // TODO(b/65524810): Source dataset ops must be marked - // stateful to inhibit constant folding. - .SetShapeFn([](shape_inference::InferenceContext* c) { - shape_inference::ShapeHandle unused; - // `patterns` must be a scalar or a vector. - TF_RETURN_IF_ERROR(c->WithRankAtMost(c->input(0), 1, &unused)); - return shape_inference::ScalarShape(c); - }); - REGISTER_OP("SqlDataset") .Input("driver_name: string") .Input("data_source_name: string") diff --git a/tensorflow/core/ops/experimental_dataset_ops.cc b/tensorflow/core/ops/experimental_dataset_ops.cc index e9987f568c..aebe0bf984 100644 --- a/tensorflow/core/ops/experimental_dataset_ops.cc +++ b/tensorflow/core/ops/experimental_dataset_ops.cc @@ -86,6 +86,18 @@ REGISTER_OP("ExperimentalMapDataset") .Attr("use_inter_op_parallelism: bool = true") .SetShapeFn(shape_inference::ScalarShape); +REGISTER_OP("ExperimentalMatchingFilesDataset") + .Input("patterns: string") + .Output("handle: variant") + .SetIsStateful() // TODO(b/65524810): Source dataset ops must be marked + // stateful to inhibit constant folding. + .SetShapeFn([](shape_inference::InferenceContext* c) { + shape_inference::ShapeHandle unused; + // `patterns` must be a scalar or a vector. + TF_RETURN_IF_ERROR(c->WithRankAtMost(c->input(0), 1, &unused)); + return shape_inference::ScalarShape(c); + }); + REGISTER_OP("ExperimentalNonSerializableDataset") .Input("input_dataset: variant") .Output("handle: variant") diff --git a/tensorflow/python/data/experimental/benchmarks/BUILD b/tensorflow/python/data/experimental/benchmarks/BUILD index b89fbe7757..c48647a218 100644 --- a/tensorflow/python/data/experimental/benchmarks/BUILD +++ b/tensorflow/python/data/experimental/benchmarks/BUILD @@ -41,3 +41,20 @@ py_test( "//third_party/py/numpy", ], ) + +py_test( + name = "matching_files_benchmark", + size = "small", + srcs = ["matching_files_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:util", + "//tensorflow/python/data/experimental/ops:matching_files", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) diff --git a/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py b/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py new file mode 100644 index 0000000000..d0d979dbd4 --- /dev/null +++ b/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py @@ -0,0 +1,101 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmark for the experimental `MatchingFilesDataset`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import shutil +import tempfile +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.experimental.ops import matching_files +from tensorflow.python.framework import errors +from tensorflow.python.framework import ops +from tensorflow.python.platform import test + + +class MatchingFilesBenchmark(test.Benchmark): + """Benchmark for the experimental `MatchingFilesDataset`.""" + + def benchmarkNestedDirectories(self): + tmp_dir = tempfile.mkdtemp() + width = 500 + depth = 10 + for i in range(width): + for j in range(depth): + new_base = os.path.join(tmp_dir, str(i), + *[str(dir_name) for dir_name in range(j)]) + os.makedirs(new_base) + child_files = ['a.py', 'b.pyc'] if j < depth - 1 else ['c.txt', 'd.log'] + for f in child_files: + filename = os.path.join(new_base, f) + open(filename, 'w').close() + + patterns = [ + os.path.join(tmp_dir, os.path.join(*['**' + for _ in range(depth)]), suffix) + for suffix in ['*.txt', '*.log'] + ] + + deltas = [] + iters = 3 + for _ in range(iters): + with ops.Graph().as_default(): + dataset = matching_files.MatchingFilesDataset(patterns) + next_element = dataset.make_one_shot_iterator().get_next() + + with session.Session() as sess: + sub_deltas = [] + while True: + try: + start = time.time() + sess.run(next_element) + end = time.time() + sub_deltas.append(end - start) + except errors.OutOfRangeError: + break + deltas.append(sub_deltas) + + median_deltas = np.median(deltas, axis=0) + print('Nested directory size (width*depth): %d*%d Median wall time: ' + '%fs (read first filename), %fs (read second filename), avg %fs' + ' (read %d more filenames)' % + (width, depth, median_deltas[0], median_deltas[1], + np.average(median_deltas[2:]), len(median_deltas) - 2)) + self.report_benchmark( + iters=iters, + wall_time=np.sum(median_deltas), + extras={ + 'read first file:': + median_deltas[0], + 'read second file:': + median_deltas[1], + 'avg time for reading %d more filenames:' % + (len(median_deltas) - 2): + np.average(median_deltas[2:]) + }, + name='benchmark_matching_files_dataset_nesteddirectory(%d*%d)' % + (width, depth)) + + shutil.rmtree(tmp_dir, ignore_errors=True) + + +if __name__ == '__main__': + test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/BUILD b/tensorflow/python/data/experimental/kernel_tests/BUILD index a7c306817c..ba5c6f7b17 100644 --- a/tensorflow/python/data/experimental/kernel_tests/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/BUILD @@ -371,6 +371,25 @@ py_test( ], ) +py_test( + name = "matching_files_test", + size = "small", + srcs = ["matching_files_test.py"], + srcs_version = "PY2AND3", + tags = ["no_pip"], + deps = [ + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:util", + "//tensorflow/python/data/experimental/ops:matching_files", + "//tensorflow/python/data/kernel_tests:test_base", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + py_test( name = "override_threadpool_test", size = "small", diff --git a/tensorflow/python/data/kernel_tests/matching_files_dataset_op_test.py b/tensorflow/python/data/experimental/kernel_tests/matching_files_test.py similarity index 62% rename from tensorflow/python/data/kernel_tests/matching_files_dataset_op_test.py rename to tensorflow/python/data/experimental/kernel_tests/matching_files_test.py index 4d86ec4228..938dd4aff4 100644 --- a/tensorflow/python/data/kernel_tests/matching_files_dataset_op_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/matching_files_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for the private `MatchingFilesDataset`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -20,20 +20,15 @@ from __future__ import print_function import os import shutil import tempfile -import time -import numpy as np - -from tensorflow.python.client import session +from tensorflow.python.data.experimental.ops import matching_files from tensorflow.python.data.kernel_tests import test_base -from tensorflow.python.data.ops.dataset_ops import MatchingFilesDataset from tensorflow.python.framework import errors -from tensorflow.python.framework import ops from tensorflow.python.platform import test from tensorflow.python.util import compat -class MatchingFilesDatasetTest(test_base.DatasetTestBase): +class MatchingFilesTest(test_base.DatasetTestBase): def setUp(self): self.tmp_dir = tempfile.mkdtemp() @@ -46,31 +41,34 @@ class MatchingFilesDatasetTest(test_base.DatasetTestBase): open(os.path.join(self.tmp_dir, filename), 'a').close() def testNonExistingDirectory(self): - """Test the MatchingFiles dataset with a non-existing directory""" + """Test the MatchingFiles dataset with a non-existing directory.""" self.tmp_dir = os.path.join(self.tmp_dir, 'nonexistingdir') - dataset = MatchingFilesDataset(os.path.join(self.tmp_dir, '*')) + dataset = matching_files.MatchingFilesDataset( + os.path.join(self.tmp_dir, '*')) with self.cached_session() as sess: next_element = dataset.make_one_shot_iterator().get_next() with self.assertRaises(errors.NotFoundError): sess.run(next_element) def testEmptyDirectory(self): - """Test the MatchingFiles dataset with an empty directory""" + """Test the MatchingFiles dataset with an empty directory.""" - dataset = MatchingFilesDataset(os.path.join(self.tmp_dir, '*')) + dataset = matching_files.MatchingFilesDataset( + os.path.join(self.tmp_dir, '*')) with self.cached_session() as sess: next_element = dataset.make_one_shot_iterator().get_next() with self.assertRaises(errors.NotFoundError): sess.run(next_element) def testSimpleDirectory(self): - """Test the MatchingFiles dataset with a simple directory""" + """Test the MatchingFiles dataset with a simple directory.""" filenames = ['a', 'b', 'c'] self._touchTempFiles(filenames) - dataset = MatchingFilesDataset(os.path.join(self.tmp_dir, '*')) + dataset = matching_files.MatchingFilesDataset( + os.path.join(self.tmp_dir, '*')) with self.cached_session() as sess: next_element = dataset.make_one_shot_iterator().get_next() @@ -86,12 +84,13 @@ class MatchingFilesDatasetTest(test_base.DatasetTestBase): sess.run(next_element) def testFileSuffixes(self): - """Test the MatchingFiles dataset using the suffixes of filename""" + """Test the MatchingFiles dataset using the suffixes of filename.""" filenames = ['a.txt', 'b.py', 'c.py', 'd.pyc'] self._touchTempFiles(filenames) - dataset = MatchingFilesDataset(os.path.join(self.tmp_dir, '*.py')) + dataset = matching_files.MatchingFilesDataset( + os.path.join(self.tmp_dir, '*.py')) with self.cached_session() as sess: next_element = dataset.make_one_shot_iterator().get_next() expected_filenames = [] @@ -106,12 +105,13 @@ class MatchingFilesDatasetTest(test_base.DatasetTestBase): sess.run(next_element) def testFileMiddles(self): - """Test the MatchingFiles dataset using the middles of filename""" + """Test the MatchingFiles dataset using the middles of filename.""" filenames = ['aa.txt', 'bb.py', 'bbc.pyc', 'cc.pyc'] self._touchTempFiles(filenames) - dataset = MatchingFilesDataset(os.path.join(self.tmp_dir, 'b*.py*')) + dataset = matching_files.MatchingFilesDataset( + os.path.join(self.tmp_dir, 'b*.py*')) with self.cached_session() as sess: next_element = dataset.make_one_shot_iterator().get_next() expected_filenames = [] @@ -126,7 +126,7 @@ class MatchingFilesDatasetTest(test_base.DatasetTestBase): sess.run(next_element) def testNestedDirectories(self): - """Test the MatchingFiles dataset with nested directories""" + """Test the MatchingFiles dataset with nested directories.""" filenames = [] width = 8 @@ -147,7 +147,7 @@ class MatchingFilesDatasetTest(test_base.DatasetTestBase): suffix) for suffix in ['*.txt', '*.log'] ] - dataset = MatchingFilesDataset(patterns) + dataset = matching_files.MatchingFilesDataset(patterns) with self.cached_session() as sess: next_element = dataset.make_one_shot_iterator().get_next() expected_filenames = [ @@ -165,70 +165,5 @@ class MatchingFilesDatasetTest(test_base.DatasetTestBase): self.assertItemsEqual(expected_filenames, actual_filenames) -class MatchingFilesDatasetBenchmark(test.Benchmark): - - def benchmarkNestedDirectories(self): - tmp_dir = tempfile.mkdtemp() - width = 500 - depth = 10 - for i in range(width): - for j in range(depth): - new_base = os.path.join(tmp_dir, str(i), - *[str(dir_name) for dir_name in range(j)]) - os.makedirs(new_base) - child_files = ['a.py', 'b.pyc'] if j < depth - 1 else ['c.txt', 'd.log'] - for f in child_files: - filename = os.path.join(new_base, f) - open(filename, 'w').close() - - patterns = [ - os.path.join(tmp_dir, os.path.join(*['**' - for _ in range(depth)]), suffix) - for suffix in ['*.txt', '*.log'] - ] - - deltas = [] - iters = 3 - for _ in range(iters): - with ops.Graph().as_default(): - dataset = MatchingFilesDataset(patterns) - next_element = dataset.make_one_shot_iterator().get_next() - - with session.Session() as sess: - sub_deltas = [] - while True: - try: - start = time.time() - sess.run(next_element) - end = time.time() - sub_deltas.append(end - start) - except errors.OutOfRangeError: - break - deltas.append(sub_deltas) - - median_deltas = np.median(deltas, axis=0) - print('Nested directory size (width*depth): %d*%d Median wall time: ' - '%fs (read first filename), %fs (read second filename), avg %fs' - ' (read %d more filenames)' % - (width, depth, median_deltas[0], median_deltas[1], - np.average(median_deltas[2:]), len(median_deltas) - 2)) - self.report_benchmark( - iters=iters, - wall_time=np.sum(median_deltas), - extras={ - 'read first file:': - median_deltas[0], - 'read second file:': - median_deltas[1], - 'avg time for reading %d more filenames:' % - (len(median_deltas) - 2): - np.average(median_deltas[2:]) - }, - name='benchmark_matching_files_dataset_nesteddirectory(%d*%d)' % - (width, depth)) - - shutil.rmtree(tmp_dir, ignore_errors=True) - - if __name__ == '__main__': test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/BUILD b/tensorflow/python/data/experimental/kernel_tests/serialization/BUILD index 079c5309a8..c724987b24 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/BUILD @@ -361,6 +361,7 @@ py_test( deps = [ ":dataset_serialization_test_base", "//tensorflow/python:client_testlib", + "//tensorflow/python/data/experimental/ops:matching_files", "//tensorflow/python/data/ops:dataset_ops", "//third_party/py/numpy", ], diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/matching_files_dataset_serialization_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/matching_files_dataset_serialization_test.py index 7edb200d2e..c026e97835 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/matching_files_dataset_serialization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/matching_files_dataset_serialization_test.py @@ -22,7 +22,7 @@ import shutil import tempfile from tensorflow.python.data.experimental.kernel_tests.serialization import dataset_serialization_test_base -from tensorflow.python.data.ops.dataset_ops import MatchingFilesDataset +from tensorflow.python.data.experimental.ops import matching_files from tensorflow.python.platform import test @@ -30,7 +30,7 @@ class MatchingFilesDatasetSerializationTest( dataset_serialization_test_base.DatasetSerializationTestBase): def _build_iterator_graph(self, test_patterns): - return MatchingFilesDataset(test_patterns) + return matching_files.MatchingFilesDataset(test_patterns) def testMatchingFilesCore(self): tmp_dir = tempfile.mkdtemp() diff --git a/tensorflow/python/data/experimental/ops/BUILD b/tensorflow/python/data/experimental/ops/BUILD index 33c493bf45..f9544857a1 100644 --- a/tensorflow/python/data/experimental/ops/BUILD +++ b/tensorflow/python/data/experimental/ops/BUILD @@ -199,6 +199,17 @@ py_library( ], ) +py_library( + name = "matching_files", + srcs = ["matching_files.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:dataset_ops_gen", + "//tensorflow/python:framework_ops", + "//tensorflow/python:tensor_shape", + ], +) + py_library( name = "optimization", srcs = ["optimization.py"], @@ -397,6 +408,7 @@ py_library( ":indexed_dataset_ops", ":interleave_ops", ":map_defun", + ":matching_files", ":optimization", ":prefetching_ops", ":readers", diff --git a/tensorflow/python/data/experimental/ops/matching_files.py b/tensorflow/python/data/experimental/ops/matching_files.py new file mode 100644 index 0000000000..8398f86e31 --- /dev/null +++ b/tensorflow/python/data/experimental/ops/matching_files.py @@ -0,0 +1,51 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Experimental API for matching input filenames.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_shape +from tensorflow.python.ops import gen_experimental_dataset_ops as ged_ops + + +class MatchingFilesDataset(dataset_ops.DatasetSource): + """A `Dataset` that list the files according to the input patterns.""" + + def __init__(self, patterns): + super(MatchingFilesDataset, self).__init__() + self._patterns = ops.convert_to_tensor( + patterns, dtype=dtypes.string, name="patterns") + + def _as_variant_tensor(self): + return ged_ops.experimental_matching_files_dataset(self._patterns) + + @property + def output_classes(self): + return ops.Tensor + + @property + def output_shapes(self): + return tensor_shape.scalar() + + @property + def output_types(self): + return dtypes.string + + diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index fa1f6d701a..dc89474f49 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -23,6 +23,8 @@ tf_py_test( "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:math_ops", + "//tensorflow/python:session", + "//tensorflow/python:sparse_tensor", "//tensorflow/python:string_ops", "//tensorflow/python:tensor_shape", "//tensorflow/python:util", @@ -42,6 +44,7 @@ tf_py_test( "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", "//tensorflow/python:errors", + "//tensorflow/python:framework_ops", "//tensorflow/python:variables", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/ops:iterator_ops", @@ -100,8 +103,11 @@ tf_py_test( ":test_base", "//third_party/py/numpy", "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", "//tensorflow/python:errors", + "//tensorflow/python:script_ops", + "//tensorflow/python:session", "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/util:sparse", @@ -116,8 +122,12 @@ tf_py_test( ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", + "//tensorflow/core:protos_all_py", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python/data/util:nest", "//tensorflow/python:client_testlib", "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", "//tensorflow/python:sparse_tensor", "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", @@ -137,8 +147,10 @@ tf_py_test( "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", "//tensorflow/python:errors", + "//tensorflow/python:framework_ops", "//tensorflow/python:functional_ops", "//tensorflow/python:math_ops", + "//tensorflow/python:session", "//tensorflow/python:sparse_tensor", "//tensorflow/python/data/ops:dataset_ops", ], @@ -185,7 +197,10 @@ tf_py_test( ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python/data/util:nest", "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", "//tensorflow/python:sparse_tensor", "//tensorflow/python/data/ops:dataset_ops", ], @@ -199,10 +214,12 @@ tf_py_test( ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", + "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", "//tensorflow/python:errors", + "//tensorflow/python:script_ops", "//tensorflow/python:session", "//tensorflow/python:sparse_ops", "//tensorflow/python:sparse_tensor", @@ -266,6 +283,7 @@ tf_py_test( "//tensorflow/python:framework_test_lib", "//tensorflow/python:function", "//tensorflow/python:functional_ops", + "//tensorflow/python:math_ops", "//tensorflow/python:session", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/ops:iterator_ops", @@ -288,6 +306,7 @@ tf_py_test( ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", + "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:constant_op", @@ -301,30 +320,16 @@ tf_py_test( "//tensorflow/python:math_ops", "//tensorflow/python:random_ops", "//tensorflow/python:script_ops", + "//tensorflow/python:session", "//tensorflow/python:sparse_ops", "//tensorflow/python:sparse_tensor", "//tensorflow/python:string_ops", + "//tensorflow/python:tensor_util", "//tensorflow/python:variable_scope", "//tensorflow/python/data/ops:dataset_ops", ], ) -tf_py_test( - name = "matching_files_dataset_op_test", - size = "small", - srcs = ["matching_files_dataset_op_test.py"], - additional_deps = [ - ":test_base", - "//third_party/py/numpy", - "//tensorflow/python:array_ops", - "//tensorflow/python:client_testlib", - "//tensorflow/python:dtypes", - "//tensorflow/python:errors", - "//tensorflow/python:util", - "//tensorflow/python/data/ops:dataset_ops", - ], -) - cuda_py_test( name = "multi_device_iterator_test", size = "medium", @@ -396,6 +401,7 @@ tf_py_test( "//tensorflow/python:dataset_ops_gen", "//tensorflow/python:dtypes", "//tensorflow/python:errors", + "//tensorflow/python:framework_test_lib", "//tensorflow/python:io_ops", "//tensorflow/python:framework_ops", "//tensorflow/python:parsing_ops", @@ -413,6 +419,8 @@ tf_py_test( srcs = ["reader_dataset_ops_test.py"], additional_deps = [ ":test_base", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/eager:context", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:constant_op", @@ -499,10 +507,14 @@ py_library( name = "test_base", srcs = ["test_base.py"], deps = [ + "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:sparse_tensor", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/util:nest", + "//tensorflow/python/eager:context", ], ) diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index bd57c9f1d5..843db18853 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -2769,30 +2769,6 @@ class MapDataset(UnaryDataset): return "Dataset.map()" -class MatchingFilesDataset(DatasetSource): - """A `Dataset` that list the files according to the input patterns.""" - - def __init__(self, patterns): - super(MatchingFilesDataset, self).__init__() - self._patterns = ops.convert_to_tensor( - patterns, dtype=dtypes.string, name="patterns") - - def _as_variant_tensor(self): - return gen_dataset_ops.matching_files_dataset(self._patterns) - - @property - def output_classes(self): - return ops.Tensor - - @property - def output_shapes(self): - return tensor_shape.scalar() - - @property - def output_types(self): - return dtypes.string - - class ParallelMapDataset(MapDataset): """A `Dataset` that maps a function over elements in its input in parallel.""" -- GitLab From 18fe495e72bb711322ca7a361c8b0ffcc901100a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 18:46:38 -0800 Subject: [PATCH 255/672] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 222485786 --- tensorflow/go/op/wrappers.go | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index ab7294e5a1..ad31c335e6 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -3487,30 +3487,6 @@ func BoostedTreesQuantileStreamResourceFlush(scope *Scope, quantile_stream_resou return scope.AddOperation(opspec) } -// Add the quantile summaries to each quantile stream resource. -// -// An op that adds a list of quantile summaries to a quantile stream resource. Each -// summary Tensor is rank 2, containing summaries (value, weight, min_rank, max_rank) -// for a single feature. -// -// Arguments: -// quantile_stream_resource_handle: resource handle referring to a QuantileStreamResource. -// summaries: string; List of Rank 2 Tensor each containing the summaries for a single feature. -// -// Returns the created operation. -func BoostedTreesQuantileStreamResourceAddSummaries(scope *Scope, quantile_stream_resource_handle tf.Output, summaries []tf.Output) (o *tf.Operation) { - if scope.Err() != nil { - return - } - opspec := tf.OpSpec{ - Type: "BoostedTreesQuantileStreamResourceAddSummaries", - Input: []tf.Input{ - quantile_stream_resource_handle, tf.OutputList(summaries), - }, - } - return scope.AddOperation(opspec) -} - // Makes the summary of quantiles for the batch. // // An op that takes a list of tensors and outputs the quantile summaries for each tensor. @@ -30165,6 +30141,30 @@ func ExperimentalDirectedInterleaveDataset(scope *Scope, selector_input_dataset return op.Output(0) } +// Add the quantile summaries to each quantile stream resource. +// +// An op that adds a list of quantile summaries to a quantile stream resource. Each +// summary Tensor is rank 2, containing summaries (value, weight, min_rank, max_rank) +// for a single feature. +// +// Arguments: +// quantile_stream_resource_handle: resource handle referring to a QuantileStreamResource. +// summaries: string; List of Rank 2 Tensor each containing the summaries for a single feature. +// +// Returns the created operation. +func BoostedTreesQuantileStreamResourceAddSummaries(scope *Scope, quantile_stream_resource_handle tf.Output, summaries []tf.Output) (o *tf.Operation) { + if scope.Err() != nil { + return + } + opspec := tf.OpSpec{ + Type: "BoostedTreesQuantileStreamResourceAddSummaries", + Input: []tf.Input{ + quantile_stream_resource_handle, tf.OutputList(summaries), + }, + } + return scope.AddOperation(opspec) +} + // Gets the next element from a FunctionBufferingResource. // // Arguments: -- GitLab From e679321d7829b6b7c06bc7b9ced4017ce492c2af Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Wed, 21 Nov 2018 18:53:31 -0800 Subject: [PATCH 256/672] Add back strategy.configure in non-distribute-coordinator path of Keras' configure_and_create_session. PiperOrigin-RevId: 222486266 --- tensorflow/python/keras/engine/distributed_training_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index 881f8b36ca..fba557ff5b 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -350,6 +350,7 @@ def configure_and_create_session(distribution_strategy): session = session_module.Session( config=dc_session_config, target=worker_context.master_target) else: + distribution_strategy.configure(session_config) session = session_module.Session(config=session_config) K.set_session(session) -- GitLab From abcc0bbc0983c1699d357497441d34e249ef1d6c Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 19:42:04 -0800 Subject: [PATCH 257/672] Automated rollback of commit 209c7dae9368c99598d599cd7aea032417fc7cc2. Revert #22478. PiperOrigin-RevId: 222489301 --- tensorflow/python/keras/integration_test.py | 10 ---------- tensorflow/python/keras/regularizers.py | 15 ++++++--------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/tensorflow/python/keras/integration_test.py b/tensorflow/python/keras/integration_test.py index 25ca9e69e2..3c0f73b1c3 100644 --- a/tensorflow/python/keras/integration_test.py +++ b/tensorflow/python/keras/integration_test.py @@ -26,7 +26,6 @@ from tensorflow.python.keras import testing_utils from tensorflow.python.layers import core as tf_core_layers from tensorflow.python.ops import nn from tensorflow.python.ops import rnn_cell -from tensorflow.python.ops import variable_scope from tensorflow.python.platform import test @@ -313,15 +312,6 @@ class KerasIntegrationTest(test.TestCase): verbose=0) self.assertGreater(history.history['val_acc'][-1], 0.7) - def test_regularizers_with_get_variable(self): - # Test case for GitHub issue 22470. - with self.cached_session(): - v = variable_scope.get_variable( - 'v', - shape=[4, 4], - initializer=keras.initializers.glorot_uniform(), - regularizer=keras.regularizers.l2(0.)) - if __name__ == '__main__': test.main() diff --git a/tensorflow/python/keras/regularizers.py b/tensorflow/python/keras/regularizers.py index cbcdae214f..28b6ad4c65 100644 --- a/tensorflow/python/keras/regularizers.py +++ b/tensorflow/python/keras/regularizers.py @@ -20,7 +20,6 @@ from __future__ import print_function import six -from tensorflow.python.framework import ops from tensorflow.python.keras import backend as K from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object @@ -55,14 +54,12 @@ class L1L2(Regularizer): self.l2 = K.cast_to_floatx(l2) def __call__(self, x): - if self.l1 or self.l2: - regularization = ops.convert_to_tensor(0., dtype=K.floatx()) - if self.l1: - regularization += math_ops.reduce_sum(self.l1 * math_ops.abs(x)) - if self.l2: - regularization += math_ops.reduce_sum(self.l2 * math_ops.square(x)) - return regularization - return None + regularization = 0. + if self.l1: + regularization += math_ops.reduce_sum(self.l1 * math_ops.abs(x)) + if self.l2: + regularization += math_ops.reduce_sum(self.l2 * math_ops.square(x)) + return regularization def get_config(self): return {'l1': float(self.l1), 'l2': float(self.l2)} -- GitLab From e298f543b0a93d2c97323dd47d1816d688029065 Mon Sep 17 00:00:00 2001 From: Eugene Brevdo Date: Wed, 21 Nov 2018 20:04:45 -0800 Subject: [PATCH 258/672] [TF] Better error message when single threaded executor fails. PiperOrigin-RevId: 222490940 --- .../core/kernels/data/single_threaded_executor.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/kernels/data/single_threaded_executor.cc b/tensorflow/core/kernels/data/single_threaded_executor.cc index 5b084a16f0..89e3881037 100644 --- a/tensorflow/core/kernels/data/single_threaded_executor.cc +++ b/tensorflow/core/kernels/data/single_threaded_executor.cc @@ -65,21 +65,28 @@ class SingleThreadedExecutorImpl : public Executor { if (IsRefType(dt)) { return errors::Unimplemented( "Single-threaded executor does not support reference-typed " - "edges."); + "edges. But saw type ", + DataTypeString(dt), " in outputs of node ", n->name()); } } if (n->IsControlFlow()) { return errors::Unimplemented( - "Single-threaded executor does not support control flow."); + "Single-threaded executor does not support control flow. But saw " + "control flow node ", + n->name()); } if (n->IsSend() || n->IsHostSend() || n->IsRecv() || n->IsHostRecv()) { return errors::Unimplemented( - "Single-threaded executor does not support partitioned graphs."); + "Single-threaded executor does not support partitioned graphs. " + "But saw send/recv node ", + n->name()); } if (n->IsCollective()) { return errors::Unimplemented( - "Single-threaded executor does not support collective ops."); + "Single-threaded executor does not support collective ops. But " + "saw collective node ", + n->name()); } KernelState& kernel_state = kernels_[i]; -- GitLab From 4887e11e758a3887421a05dafab8b3ab4051d9c9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 20:18:58 -0800 Subject: [PATCH 259/672] Update ops-related pbtxt files. PiperOrigin-RevId: 222491827 --- .../core/ops/compat/ops_history.v1.pbtxt | 12 ++++++++++ tensorflow/core/ops/ops.pbtxt | 24 +++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index efb2f5ed03..c855f1c4a0 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -21941,6 +21941,18 @@ op { } } } +op { + name: "ExperimentalMatchingFilesDataset" + input_arg { + name: "patterns" + type: DT_STRING + } + output_arg { + name: "handle" + type: DT_VARIANT + } + is_stateful: true +} op { name: "ExperimentalMaterializedIndexDatasetHandle" output_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index f690635558..44cc64dc3b 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -10404,6 +10404,18 @@ op { } } } +op { + name: "ExperimentalMatchingFilesDataset" + input_arg { + name: "patterns" + type: DT_STRING + } + output_arg { + name: "handle" + type: DT_VARIANT + } + is_stateful: true +} op { name: "ExperimentalMaterializedIndexDatasetHandle" output_arg { @@ -15991,18 +16003,6 @@ op { type: DT_STRING } } -op { - name: "MatchingFilesDataset" - input_arg { - name: "patterns" - type: DT_STRING - } - output_arg { - name: "handle" - type: DT_VARIANT - } - is_stateful: true -} op { name: "MatrixBandPart" input_arg { -- GitLab From 84b50a2c0096f570a18b0c7cd00ac45c18ffe57e Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 21 Nov 2018 21:40:29 -0800 Subject: [PATCH 260/672] Change API for io.serialize_sparse and io.serialize_many_sparse for TF 2.0. PiperOrigin-RevId: 222496915 --- tensorflow/python/ops/sparse_ops.py | 54 +++++++++++++++++-- .../tools/api/golden/v2/tensorflow.io.pbtxt | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 2 + 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/ops/sparse_ops.py b/tensorflow/python/ops/sparse_ops.py index 58cd8291e1..e8a0f31d9d 100644 --- a/tensorflow/python/ops/sparse_ops.py +++ b/tensorflow/python/ops/sparse_ops.py @@ -1849,8 +1849,7 @@ def sparse_fill_empty_rows(sp_input, default_value, name=None): dense_shape=sp_input.dense_shape), empty_row_indicator) -@tf_export( - "io.serialize_sparse", v1=["io.serialize_sparse", "serialize_sparse"]) +@tf_export(v1=["io.serialize_sparse", "serialize_sparse"]) @deprecation.deprecated_endpoints("serialize_sparse") def serialize_sparse(sp_input, name=None, out_type=dtypes.string): """Serialize a `SparseTensor` into a 3-vector (1-D `Tensor`) object. @@ -1864,6 +1863,25 @@ def serialize_sparse(sp_input, name=None, out_type=dtypes.string): A 3-vector (1-D `Tensor`), with each column representing the serialized `SparseTensor`'s indices, values, and shape (respectively). + Raises: + TypeError: If `sp_input` is not a `SparseTensor`. + """ + return serialize_sparse_v2(sp_input, out_type, name) + + +@tf_export("io.serialize_sparse", v1=[]) +def serialize_sparse_v2(sp_input, out_type=dtypes.string, name=None): + """Serialize a `SparseTensor` into a 3-vector (1-D `Tensor`) object. + + Args: + sp_input: The input `SparseTensor`. + out_type: The `dtype` to use for serialization. + name: A name prefix for the returned tensors (optional). + + Returns: + A 3-vector (1-D `Tensor`), with each column representing the serialized + `SparseTensor`'s indices, values, and shape (respectively). + Raises: TypeError: If `sp_input` is not a `SparseTensor`. """ @@ -1877,9 +1895,7 @@ def serialize_sparse(sp_input, name=None, out_type=dtypes.string): out_type=out_type) -@tf_export( - "io.serialize_many_sparse", - v1=["io.serialize_many_sparse", "serialize_many_sparse"]) +@tf_export(v1=["io.serialize_many_sparse", "serialize_many_sparse"]) @deprecation.deprecated_endpoints("serialize_many_sparse") def serialize_many_sparse(sp_input, name=None, out_type=dtypes.string): """Serialize `N`-minibatch `SparseTensor` into an `[N, 3]` `Tensor`. @@ -1902,6 +1918,34 @@ def serialize_many_sparse(sp_input, name=None, out_type=dtypes.string): represents serialized `SparseTensor`'s indices, values, and shape (respectively). + Raises: + TypeError: If `sp_input` is not a `SparseTensor`. + """ + return serialize_many_sparse_v2(sp_input, out_type, name) + + +@tf_export("io.serialize_many_sparse", v1=[]) +def serialize_many_sparse_v2(sp_input, out_type=dtypes.string, name=None): + """Serialize `N`-minibatch `SparseTensor` into an `[N, 3]` `Tensor`. + + The `SparseTensor` must have rank `R` greater than 1, and the first dimension + is treated as the minibatch dimension. Elements of the `SparseTensor` + must be sorted in increasing order of this first dimension. The serialized + `SparseTensor` objects going into each row of the output `Tensor` will have + rank `R-1`. + + The minibatch size `N` is extracted from `sparse_shape[0]`. + + Args: + sp_input: The input rank `R` `SparseTensor`. + out_type: The `dtype` to use for serialization. + name: A name prefix for the returned tensors (optional). + + Returns: + A matrix (2-D `Tensor`) with `N` rows and `3` columns. Each column + represents serialized `SparseTensor`'s indices, values, and shape + (respectively). + Raises: TypeError: If `sp_input` is not a `SparseTensor`. """ diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt index d32529876f..98250df803 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt @@ -146,11 +146,11 @@ tf_module { } member_method { name: "serialize_many_sparse" - argspec: "args=[\'sp_input\', \'name\', \'out_type\'], varargs=None, keywords=None, defaults=[\'None\', \"\"], " + argspec: "args=[\'sp_input\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " } member_method { name: "serialize_sparse" - argspec: "args=[\'sp_input\', \'name\', \'out_type\'], varargs=None, keywords=None, defaults=[\'None\', \"\"], " + argspec: "args=[\'sp_input\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " } member_method { name: "serialize_tensor" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index b8cf21b29c..9b14c11614 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -328,6 +328,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # IMPORTANT: order here should correspond to OLD argument order. # We just prepend "arg_name=" to all arguments in function calls. self.function_reorders = { + "tf.io.serialize_sparse": ["sp_input", "name", "out_type"], + "tf.io.serialize_many_sparse": ["sp_input", "name", "out_type"], "tf.argmax": ["input", "axis", "name", "dimension", "output_type"], "tf.argmin": ["input", "axis", "name", "dimension", "output_type"], "tf.batch_to_space": ["input", "crops", "block_size", "name"], -- GitLab From 8be5ec06050a5084eec4f5ba3e2bc62b463e0044 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 21 Nov 2018 22:22:51 -0800 Subject: [PATCH 261/672] Internal changes. PiperOrigin-RevId: 222499496 --- .../internal/reference/reference_ops.h | 8 +- tensorflow/lite/kernels/reduce.cc | 36 ++++++++- tensorflow/lite/testing/generate_examples.py | 74 ++++++++++--------- 3 files changed, 76 insertions(+), 42 deletions(-) diff --git a/tensorflow/lite/kernels/internal/reference/reference_ops.h b/tensorflow/lite/kernels/internal/reference/reference_ops.h index 920f154049..be766ea452 100644 --- a/tensorflow/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/lite/kernels/internal/reference/reference_ops.h @@ -3663,8 +3663,10 @@ inline void Mean(const tflite::MeanParams& op_params, const RuntimeShape& unextended_output_shape, T* output_data) { gemmlowp::ScopedProfilingLabel label("Mean"); - TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); - TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + // Current implementation only supports dimension equals 4 and simultaneous + // reduction over width and height. + TFLITE_CHECK_EQ(unextended_input_shape.DimensionsCount(), 4); + TFLITE_CHECK_LE(unextended_output_shape.DimensionsCount(), 4); const RuntimeShape input_shape = RuntimeShape::ExtendedShape(4, unextended_input_shape); const RuntimeShape output_shape = @@ -3678,8 +3680,6 @@ inline void Mean(const tflite::MeanParams& op_params, const int input_height = input_shape.Dims(1); const int input_width = input_shape.Dims(2); - // The current implementation only supports simultaneous reduction over - // width and height. TFLITE_DCHECK_EQ(op_params.axis_count, 2); TFLITE_DCHECK((op_params.axis[0] == 1 && op_params.axis[1] == 2) || (op_params.axis[0] == 2 && op_params.axis[1] == 1)); diff --git a/tensorflow/lite/kernels/reduce.cc b/tensorflow/lite/kernels/reduce.cc index ed2d475f6d..336e827ca4 100644 --- a/tensorflow/lite/kernels/reduce.cc +++ b/tensorflow/lite/kernels/reduce.cc @@ -20,6 +20,8 @@ limitations under the License. #include "tensorflow/lite/kernels/internal/quantization_util.h" #include "tensorflow/lite/kernels/internal/reference/reference_ops.h" #include "tensorflow/lite/kernels/internal/tensor.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" #include "tensorflow/lite/kernels/kernel_util.h" #include "tensorflow/lite/kernels/op_macros.h" @@ -229,6 +231,17 @@ TfLiteStatus PrepareMeanOrSum(TfLiteContext* context, TfLiteNode* node) { return ResizeTempSum(context, &op_context, temp_sum); } +void ResolveAxis(const int* axis_data, int axis_count, + tflite::MeanParams* op_params) { + int i = 0; + for (; i < axis_count; ++i) { + op_params->axis[i] = static_cast(axis_data[i]); + } + for (; i < 4; ++i) { + op_params->axis[i] = 1; + } +} + template TfLiteStatus EvalMean(TfLiteContext* context, TfLiteNode* node) { OpContext op_context(context, node); @@ -257,9 +270,23 @@ TfLiteStatus EvalMean(TfLiteContext* context, TfLiteNode* node) { if (kernel_type == kReference) { switch (op_context.input->type) { - case kTfLiteFloat32: - TF_LITE_ENSURE(context, TF_LITE_MEAN(reference_ops, float, float)); - break; + case kTfLiteFloat32: { + tflite::MeanParams op_params; + op_params.axis_count = num_axis; + ResolveAxis(GetTensorData(op_context.axis), num_axis, &op_params); + const TfLiteTensor* input = op_context.input; + if (op_context.params->keep_dims && NumDimensions(input) == 4 && + op_params.axis_count == 2 && + ((op_params.axis[0] == 1 && op_params.axis[1] == 2) || + (op_params.axis[0] == 2 && op_params.axis[1] == 1))) { + reference_ops::Mean(op_params, GetTensorShape(input), + GetTensorData(input), + GetTensorShape(op_context.output), + GetTensorData(op_context.output)); + } else { + TF_LITE_ENSURE(context, TF_LITE_MEAN(reference_ops, float, float)); + } + } break; case kTfLiteInt32: TF_LITE_ENSURE(context, TF_LITE_MEAN(reference_ops, int, int64_t)); break; @@ -286,7 +313,8 @@ TfLiteStatus EvalMean(TfLiteContext* context, TfLiteNode* node) { GetTensorData(op_context.axis), num_axis, op_context.params->keep_dims, GetTensorData(temp_index), GetTensorData(resolved_axis), - GetTensorData(temp_sum), /*compute_sum=*/false)); + GetTensorData(temp_sum), + /*compute_sum=*/false)); } break; default: diff --git a/tensorflow/lite/testing/generate_examples.py b/tensorflow/lite/testing/generate_examples.py index b7e549cc5c..5218844299 100644 --- a/tensorflow/lite/testing/generate_examples.py +++ b/tensorflow/lite/testing/generate_examples.py @@ -905,40 +905,46 @@ def make_reduce_tests(reduce_op, def f(zip_path): """Actual function that generates examples.""" - test_parameters = [{ - "input_dtype": [tf.float32, tf.int32, tf.int64], - "input_shape": [[3, 2, 4]], - "axis": [ - 0, 1, 2, [0, 1], [0, 2], [1, 2], [0, 1, 2], [1, 0], [2, 0], - [2, 1], [2, 1, 0], [2, 0, 1], -1, -2, -3, [1, -1], [0, -1], [-1, 0], - [-1, -2, -3], [0, 0, 0], [2, 2, 0], [1, 0, -3, -3] - ], - "const_axis": [True, False], - "keepdims": [True, False], - }, { - "input_dtype": [tf.float32], - "input_shape": [[1, 8, 8, 3]], - "axis": [ - 0, 1, 2, 3, [1, 2], [0, 3], [1, 2, 3], [0, 1, 2, 3], - [3, 2, 1, 0], [3, 1, 0, 2], [2, 0], [3, 0], [3, 1], [1, 0], -1, -2, - -3, -4, [0, -2], [2, 3, -1, 0], [3, 1, 2, -3], [3, -4], [2, 2, 2], - [2, 2, 3], [-3, -3, -4], [-3, 2, 1] - ], - "const_axis": [True, False], - "keepdims": [True, False], - }, { - "input_dtype": [tf.float32], - "input_shape": [[], [1, 8, 8, 3], [3, 2, 4]], - "axis": [[]], # shape is: [0] - "const_axis": [False], - "keepdims": [True, False], - }, { - "input_dtype": [tf.float32], - "input_shape": [[], [1, 8, 8, 3], [3, 2, 4]], - "axis": [None], # shape is: [] - "const_axis": [True], - "keepdims": [True, False], - }] + test_parameters = [ + { + "input_dtype": [tf.float32, tf.int32, tf.int64], + "input_shape": [[3, 3, 2, 4]], + "axis": [ + 0, 1, 2, [0, 1], [0, 2], [1, 2], [0, 1, 2], [1, 0], [2, 0], + [2, 1], [2, 1, 0], [2, 0, 1], -1, -2, -3, [1, -1], [0, -1], + [-1, 0], [-1, -2, -3], [0, 0, 0], [2, 2, 0], [1, 0, -3, -3] + ], + "const_axis": [True, False], + "keepdims": [True, False], + }, + { + "input_dtype": [tf.float32], + "input_shape": [[1, 8, 8, 3]], + "axis": [ + 0, 1, 2, 3, [1, 2], [0, 3], [1, 2, 3], [0, 1, 2, + 3], [3, 2, 1, 0], + [3, 1, 0, 2], [2, 0], [3, 0], [3, 1], [1, 0], -1, -2, -3, -4, + [0, -2], [2, 3, -1, 0], [3, 1, 2, -3], [3, -4], [2, 2, 2], + [2, 2, 3], [-3, -3, -4], [-3, 2, 1] + ], + "const_axis": [True, False], + "keepdims": [True, False], + }, + { + "input_dtype": [tf.float32], + "input_shape": [[], [1, 8, 8, 3], [3, 2, 4]], + "axis": [[]], # shape is: [0] + "const_axis": [False], + "keepdims": [True, False], + }, + { + "input_dtype": [tf.float32], + "input_shape": [[], [1, 8, 8, 3], [3, 2, 4]], + "axis": [None], # shape is: [] + "const_axis": [True], + "keepdims": [True, False], + } + ] def build_graph(parameters): """Build the mean op testing graph.""" -- GitLab From 5594c91a36a9df5c3ae6743ae4b6e763539634da Mon Sep 17 00:00:00 2001 From: Sourabh Bajaj Date: Thu, 22 Nov 2018 00:27:41 -0800 Subject: [PATCH 262/672] Change return of the update op to be a no-op PiperOrigin-RevId: 222506718 --- tensorflow/python/keras/metrics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index c30b953c33..668c56243b 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -676,7 +676,8 @@ class Mean(Metric): update_total_op = state_ops.assign_add(self.total, values) with ops.control_dependencies([update_total_op]): update_count_op = state_ops.assign_add(self.count, num_values) - return ops.convert_to_tensor(update_count_op) + with ops.control_dependencies([update_count_op]): + return control_flow_ops.no_op() def result(self): return math_ops.div_no_nan(self.total, self.count) -- GitLab From 80c7bf2f4b62ed58eab5cedbfe3f9dac3d3d6b62 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 22 Nov 2018 01:02:30 -0800 Subject: [PATCH 263/672] compat: Update forward compatibility horizon to 2018-11-22 PiperOrigin-RevId: 222510434 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 75290f0613..ebe3fdbf53 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 21) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 22) @tf_export("compat.forward_compatible") -- GitLab From 2007e1ba474030fcce840b0b8a599558e7d5998f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 22 Nov 2018 06:18:43 -0800 Subject: [PATCH 264/672] Migrate losses to work with new tensorflow_probability.distributions.Distribution. PiperOrigin-RevId: 222536654 --- .../contrib/gan/python/losses/python/losses_impl.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/gan/python/losses/python/losses_impl.py b/tensorflow/contrib/gan/python/losses/python/losses_impl.py index c91ce2c0f3..a0a86c6337 100644 --- a/tensorflow/contrib/gan/python/losses/python/losses_impl.py +++ b/tensorflow/contrib/gan/python/losses/python/losses_impl.py @@ -36,6 +36,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function + from tensorflow.contrib.framework.python.ops import variables as contrib_variables_lib from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util @@ -45,7 +46,6 @@ from tensorflow.python.ops import gradients_impl from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import variable_scope -from tensorflow.python.ops.distributions import distribution as ds from tensorflow.python.ops.losses import losses from tensorflow.python.ops.losses import util from tensorflow.python.summary import summary @@ -738,11 +738,16 @@ def least_squares_discriminator_loss( def _validate_distributions(distributions): if not isinstance(distributions, (list, tuple)): raise ValueError('`distributions` must be a list or tuple. Instead, ' - 'found %s.', type(distributions)) + 'found %s.' % type(distributions)) for x in distributions: - if not isinstance(x, ds.Distribution): + # We used to check with `isinstance(x, tf.distributions.Distribution)`. + # However, distributions have migrated to `tfp.distributions.Distribution`, + # which is a new code repo, so we can't check this way anymore until + # TF-GAN is migrated to a new repo as well. + # This new check is not sufficient, but is a useful heuristic for now. + if not callable(getattr(x, 'log_prob', None)): raise ValueError('`distributions` must be a list of `Distributions`. ' - 'Instead, found %s.', type(x)) + 'Instead, found %s.' % type(x)) def _validate_information_penalty_inputs( -- GitLab From 72f193b5c9f306d258b289afd7a7977af7b8f5f7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 22 Nov 2018 08:58:03 -0800 Subject: [PATCH 265/672] Automated rollback of commit 54dc404a7d0cb0b39f6bbd92ff008414ce683480. Revert #23808. PiperOrigin-RevId: 222548550 --- configure.py | 1 - tensorflow/BUILD | 6 ------ tensorflow/core/BUILD | 9 ++++----- tools/bazel.rc | 1 - 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/configure.py b/configure.py index dfb87550b1..0b16fe1314 100644 --- a/configure.py +++ b/configure.py @@ -1694,7 +1694,6 @@ def main(): config_info_line('nohdfs', 'Disable HDFS support.') config_info_line('noignite', 'Disable Apacha Ignite support.') config_info_line('nokafka', 'Disable Apache Kafka support.') - config_info_line('nonccl', 'Disable NVIDIA NCCL support.') if __name__ == '__main__': diff --git a/tensorflow/BUILD b/tensorflow/BUILD index fd4b94202a..17577afecb 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -246,12 +246,6 @@ config_setting( visibility = ["//visibility:public"], ) -config_setting( - name = "no_nccl_support", - define_values = {"no_nccl_support": "true"}, - visibility = ["//visibility:public"], -) - # Crosses between platforms and file system libraries not supported on those # platforms due to limitations in nested select() statements. config_setting( diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 1caca0028e..2a8c2718ed 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -95,6 +95,7 @@ load("//tensorflow:tensorflow.bzl", "tf_cc_test_gpu") load("//tensorflow:tensorflow.bzl", "tf_cc_tests_gpu") load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test") load("//tensorflow:tensorflow.bzl", "tf_version_info_genrule") +load("//tensorflow:tensorflow.bzl", "if_not_tx2_llvm_or_windows_cuda") load("//tensorflow:tensorflow.bzl", "tf_cuda_only_cc_test") # For platform specific build config @@ -1402,11 +1403,9 @@ cc_library( "//tensorflow/core/kernels:summary_kernels", "//tensorflow/core/kernels:training_ops", "//tensorflow/core/kernels:word2vec_kernels", - ] + tf_additional_cloud_kernel_deps() + select({ - "//tensorflow:no_nccl_support": [], - "//tensorflow:windows": [], - "//conditions:default": ["//tensorflow/core/kernels:nccl_kernels"], - }) + if_not_windows([ + ] + tf_additional_cloud_kernel_deps() + if_not_tx2_llvm_or_windows_cuda([ + "//tensorflow/core/kernels:nccl_kernels", + ]) + if_not_windows([ "//tensorflow/core/kernels:fact_op", "//tensorflow/core/kernels:array_not_windows", "//tensorflow/core/kernels:math_not_windows", diff --git a/tools/bazel.rc b/tools/bazel.rc index 1fdf51f53e..8c2052ee8a 100644 --- a/tools/bazel.rc +++ b/tools/bazel.rc @@ -72,7 +72,6 @@ build:nogcp --define=no_gcp_support=true build:nohdfs --define=no_hdfs_support=true build:nokafka --define=no_kafka_support=true build:noignite --define=no_ignite_support=true -build:nonccl --define=no_nccl_support=true build --define=use_fast_cpp_protos=true build --define=allow_oversize_protos=true -- GitLab From 4f40e8a5ec282163ea8978d8d83d5b96693c727a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 22 Nov 2018 09:44:59 -0800 Subject: [PATCH 266/672] Improve performance of grouped convolutions PiperOrigin-RevId: 222551854 --- .../convolution_feature_group_converter.cc | 148 +++++++++++++----- ...onvolution_feature_group_converter_test.cc | 20 +-- .../compiler/xla/tests/convolution_test.cc | 64 ++++++++ 3 files changed, 181 insertions(+), 51 deletions(-) diff --git a/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc b/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc index 7f7f1503a0..10c53f15f5 100644 --- a/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc +++ b/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc @@ -142,16 +142,16 @@ std::vector GetMaskIds(int64 group_size, int64 group_count) { // Finally we use the Eq op of these two broadcasted constants and get the // desired mask. HloInstruction* GetExpandedFilterMask( - const Shape& filter_shape, int64 input_feature_dim, - int64 output_feature_dim, int64 group_count, + const Shape& filter_shape, int64 kernel_input_feature_dim, + int64 kernel_output_feature_dim, int64 group_count, const std::function)>& add_instruction) { Shape expanded_filter_shape = - ExpandedFilterShape(filter_shape, group_count, input_feature_dim); + ExpandedFilterShape(filter_shape, group_count, kernel_input_feature_dim); Shape mask_shape = ShapeUtil::MakeShape( S32, AsInt64Slice(expanded_filter_shape.dimensions())); - int64 output_feature = filter_shape.dimensions(output_feature_dim); - int64 group_size = filter_shape.dimensions(input_feature_dim); + int64 output_feature = filter_shape.dimensions(kernel_output_feature_dim); + int64 group_size = filter_shape.dimensions(kernel_input_feature_dim); // Create a 'input_feature' sized linspace and 'output_feature' sized linspace // that will be broadcasted into perpendicular dimensions and compared. @@ -159,15 +159,14 @@ HloInstruction* GetExpandedFilterMask( GetMaskIds(group_size, group_count); const std::vector output_feature_filter_mask = GetMaskIds(output_feature / group_count, group_count); - auto mask1 = add_instruction(HloInstruction::CreateConstant( LiteralUtil::CreateR1(input_feature_filter_mask))); - auto broadcasted_mask1 = add_instruction( - HloInstruction::CreateBroadcast(mask_shape, mask1, {input_feature_dim})); + auto broadcasted_mask1 = add_instruction(HloInstruction::CreateBroadcast( + mask_shape, mask1, {kernel_input_feature_dim})); auto mask2 = add_instruction(HloInstruction::CreateConstant( LiteralUtil::CreateR1(output_feature_filter_mask))); - auto broadcasted_mask2 = add_instruction( - HloInstruction::CreateBroadcast(mask_shape, mask2, {output_feature_dim})); + auto broadcasted_mask2 = add_instruction(HloInstruction::CreateBroadcast( + mask_shape, mask2, {kernel_output_feature_dim})); // Compare the broadcasted output feature linspace to the input feature // linspace to create a diagonal predicate. @@ -189,18 +188,20 @@ Status ConvolutionVisitor::HandleConvolution(HloInstruction* convolution) { }; auto dim_numbers = convolution->convolution_dimension_numbers(); - int64 input_feature_dim = dim_numbers.kernel_input_feature_dimension(); - int64 group_size = filter->shape().dimensions(input_feature_dim); - int64 output_feature_dim = dim_numbers.kernel_output_feature_dimension(); - auto expanded_filter_shape = - ExpandedFilterShape(filter->shape(), group_count, input_feature_dim); - HloInstruction* filter_mask = GetExpandedFilterMask( - filter->shape(), input_feature_dim, output_feature_dim, group_count, add); + int64 kernel_input_feature_dim = dim_numbers.kernel_input_feature_dimension(); + int64 group_size = filter->shape().dimensions(kernel_input_feature_dim); + int64 kernel_output_feature_dim = + dim_numbers.kernel_output_feature_dimension(); + auto expanded_filter_shape = ExpandedFilterShape(filter->shape(), group_count, + kernel_input_feature_dim); + HloInstruction* filter_mask = + GetExpandedFilterMask(filter->shape(), kernel_input_feature_dim, + kernel_output_feature_dim, group_count, add); HloInstruction* expanded_filter; if (group_size == 1) { bool depthwise_separable = - (group_count == filter->shape().dimensions(output_feature_dim)); + (group_count == filter->shape().dimensions(kernel_output_feature_dim)); // If the code generator handles depthwise separable convolutions // inherently, then no filter expansion is needed. if (!filter_expansion_ && depthwise_separable) { @@ -241,39 +242,108 @@ Status ConvolutionVisitor::HandleConvolution(HloInstruction* convolution) { // We want to repeat 'filter' in the 'input_feature_dim' dimension // 'group_count' times. Shape reshaped_filter_shape = - ShapeUtil::DeleteDimension(input_feature_dim, filter->shape()); + ShapeUtil::DeleteDimension(kernel_input_feature_dim, filter->shape()); auto reshaped_filter = add(HloInstruction::CreateReshape(reshaped_filter_shape, filter)); std::vector broadcast_dims; for (int64 i = 0; i < filter->shape().dimensions_size(); ++i) { - if (i == input_feature_dim) { + if (i == kernel_input_feature_dim) { continue; } broadcast_dims.push_back(i); } expanded_filter = add(HloInstruction::CreateBroadcast( expanded_filter_shape, reshaped_filter, broadcast_dims)); + + auto zero = add(HloInstruction::CreateConstant( + LiteralUtil::Zero(expanded_filter_shape.element_type()))); + auto zero_filter = + add(HloInstruction::CreateBroadcast(expanded_filter_shape, zero, {})); + auto new_filter = add(HloInstruction::CreateTernary( + expanded_filter_shape, HloOpcode::kSelect, filter_mask, expanded_filter, + zero_filter)); + + auto new_convolution = HloInstruction::CreateConvolve( + convolution->shape(), convolution->mutable_operand(0), new_filter, + /*feature_group_count=*/1, convolution->window(), dim_numbers, + convolution->precision_config()); + TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( + convolution, std::move(new_convolution))); } else { - // We could possibly also use reshape, broadcast, reshape instead of concat - // here, but it would require more complex code, and for depthwise - // convolution we would never end up in this branch. - std::vector concat_operands(group_count, filter); - expanded_filter = add(HloInstruction::CreateConcatenate( - expanded_filter_shape, concat_operands, input_feature_dim)); + // The filter expansion mechanism adds zeroes in the kernel. + // For an OF = 12, IF = 6, and kernel IF = 2, the expanded filter mask + // would look like (IF on the Y-axis, OF on the X-axis) + // 1 1 1 1 0 0 0 0 0 0 0 0 + // 1 1 1 1 0 0 0 0 0 0 0 0 + // 0 0 0 0 1 1 1 1 0 0 0 0 + // 0 0 0 0 1 1 1 1 0 0 0 0 + // 0 0 0 0 0 0 0 0 1 1 1 1 + // 0 0 0 0 0 0 0 0 1 1 1 1 + // + // Instead of convolving the above with the input, we instead slice the + // kernel into three kernels, each containing islands of 1s from the filter + // above. We also slice the activations in the IF dimension with each slice + // of size = group_size. For each slice, we perform convolutions, and + // concatenate the generated outputs in the output OF dimension. + + std::vector sliced_convolutions; + auto activation = convolution->mutable_operand(0); + std::vector slice_strides(filter->shape().dimensions_size(), 1); + std::vector filter_slice_starts(filter->shape().dimensions_size(), + 0); + std::vector filter_slice_limits(filter->shape().dimensions().begin(), + filter->shape().dimensions().end()); + std::vector activation_slice_starts( + activation->shape().dimensions_size(), 0); + std::vector activation_slice_limits( + activation->shape().dimensions().begin(), + activation->shape().dimensions().end()); + + int64 output_feature = + filter->shape().dimensions(kernel_output_feature_dim); + auto output_feature_dim = dim_numbers.output_feature_dimension(); + int64 filter_slice_width = output_feature / group_count; + + int64 activation_input_feature_dim = dim_numbers.input_feature_dimension(); + + for (int64 i = 0; i < group_count; i++) { + filter_slice_starts[kernel_output_feature_dim] = i * filter_slice_width; + filter_slice_limits[kernel_output_feature_dim] = + (i + 1) * filter_slice_width; + auto filter_sliced_shape = filter->shape(); + filter_sliced_shape.set_dimensions(kernel_output_feature_dim, + filter_slice_width); + auto filter_slice = add(HloInstruction::CreateSlice( + filter_sliced_shape, filter, filter_slice_starts, filter_slice_limits, + slice_strides)); + + activation_slice_starts[activation_input_feature_dim] = i * group_size; + activation_slice_limits[activation_input_feature_dim] = + (i + 1) * group_size; + auto activation_sliced_shape = activation->shape(); + activation_sliced_shape.set_dimensions(activation_input_feature_dim, + group_size); + auto activation_slice = add(HloInstruction::CreateSlice( + activation_sliced_shape, activation, activation_slice_starts, + activation_slice_limits, slice_strides)); + + auto conv_slice_shape = convolution->shape(); + conv_slice_shape.set_dimensions(output_feature_dim, filter_slice_width); + + auto new_convolution = add(HloInstruction::CreateConvolve( + conv_slice_shape, activation_slice, filter_slice, + /*feature_group_count=*/1, convolution->window(), dim_numbers, + convolution->precision_config())); + + sliced_convolutions.push_back(new_convolution); + } + + auto new_conv = HloInstruction::CreateConcatenate( + convolution->shape(), sliced_convolutions, output_feature_dim); + TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( + convolution, std::move(new_conv))); } - auto zero = add(HloInstruction::CreateConstant( - LiteralUtil::Zero(expanded_filter_shape.element_type()))); - auto zero_filter = - add(HloInstruction::CreateBroadcast(expanded_filter_shape, zero, {})); - auto new_filter = add( - HloInstruction::CreateTernary(expanded_filter_shape, HloOpcode::kSelect, - filter_mask, expanded_filter, zero_filter)); - auto new_convolution = HloInstruction::CreateConvolve( - convolution->shape(), convolution->mutable_operand(0), new_filter, - /*feature_group_count=*/1, convolution->window(), dim_numbers, - convolution->precision_config()); - TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( - convolution, std::move(new_convolution))); + return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/convolution_feature_group_converter_test.cc b/tensorflow/compiler/xla/service/convolution_feature_group_converter_test.cc index 28373ebf63..e6bf2143a2 100644 --- a/tensorflow/compiler/xla/service/convolution_feature_group_converter_test.cc +++ b/tensorflow/compiler/xla/service/convolution_feature_group_converter_test.cc @@ -82,18 +82,14 @@ ENTRY %Convolve1D1Window_0.v3 (input: f32[1,2,4], filter: f32[1,2,2]) -> f32[1,2 ConvolutionFeatureGroupConverter converter; ASSERT_TRUE(converter.Run(module.get()).ValueOrDie()); root = computation->root_instruction(); - // Make sure the convolution is converted to one with feature_group_count = 1. - EXPECT_EQ(root->opcode(), HloOpcode::kConvolution); - EXPECT_EQ(root->feature_group_count(), 1); - // Verify that the filter operand has been replaced. - EXPECT_THAT(root->operand(1), - op::Select(op::Eq(op::Broadcast(op::Constant()), - op::Broadcast(op::Constant())), - // We expect to see Concatenate here instead of - // Broadcast, because feature_group_count < input - // feature dimension. - op::Concatenate(op::Parameter(), op::Parameter()), - op::Broadcast(op::Constant()))); + // Make sure the convolution is replaced with a concatenate. + EXPECT_EQ(root->opcode(), HloOpcode::kConcatenate); + // And the operands of the concatenate are convolutions, each with a feature + // group count = 1. + EXPECT_EQ(root->operand(0)->opcode(), HloOpcode::kConvolution); + EXPECT_EQ(root->operand(1)->opcode(), HloOpcode::kConvolution); + EXPECT_EQ(root->operand(0)->feature_group_count(), 1); + EXPECT_EQ(root->operand(1)->feature_group_count(), 1); } } // namespace diff --git a/tensorflow/compiler/xla/tests/convolution_test.cc b/tensorflow/compiler/xla/tests/convolution_test.cc index b52d30fd66..7e81905260 100644 --- a/tensorflow/compiler/xla/tests/convolution_test.cc +++ b/tensorflow/compiler/xla/tests/convolution_test.cc @@ -1346,6 +1346,70 @@ TYPED_TEST(Convolve2D_1x2x2x6_2x2x2x12_Grouped_Valid, Types) { this->RunTest(); } +template +class Convolve2D_1x2x2x1024_2x2x128x512_Grouped_Valid : public ConvolutionTest { + public: + void RunTest() { + XlaBuilder builder(TestName()); + std::vector input_dims = {1, 2, 2, 1024}; + std::vector filter_dims = {2, 2, 128, 512}; + Shape input_shape = ShapeUtil::MakeShapeWithType(input_dims); + Shape filter_shape = ShapeUtil::MakeShapeWithType(filter_dims); + { + auto input = Parameter(&builder, 0, input_shape, "input"); + auto filter = Parameter(&builder, 1, filter_shape, "filter"); + + // Tensorflow dimension numbers for 2D convolution. + ConvolutionDimensionNumbers dnums; + dnums.set_input_batch_dimension(0); + dnums.set_output_batch_dimension(0); + dnums.add_input_spatial_dimensions(1); + dnums.add_output_spatial_dimensions(1); + dnums.add_input_spatial_dimensions(2); + dnums.add_output_spatial_dimensions(2); + dnums.set_input_feature_dimension(3); + dnums.set_output_feature_dimension(3); + dnums.add_kernel_spatial_dimensions(0); + dnums.add_kernel_spatial_dimensions(1); + dnums.set_kernel_input_feature_dimension(2); + dnums.set_kernel_output_feature_dimension(3); + + ConvWithGeneralDimensions(input, filter, {1, 1}, Padding::kValid, dnums, + /*feature_group_count=*/8); + } + + std::vector input_elems(ShapeUtil::ElementsIn(input_shape), + static_cast(1)); + + auto input_r1 = LiteralUtil::CreateR1(input_elems); + auto input_r4 = input_r1.Reshape(input_dims).ConsumeValueOrDie(); + + std::vector filter_elems(ShapeUtil::ElementsIn(filter_shape), + static_cast(2)); + + auto filter_r1 = LiteralUtil::CreateR1(filter_elems); + auto filter_r4 = filter_r1.Reshape(filter_dims).ConsumeValueOrDie(); + + std::vector output_elems(512, static_cast(1024)); + auto expected_r1 = LiteralUtil::CreateR1(output_elems); + auto expected_r4 = expected_r1.Reshape({1, 1, 1, 512}).ConsumeValueOrDie(); + + auto input_literal = + client_->TransferToServer(input_r4).ConsumeValueOrDie(); + auto filter_literal = + client_->TransferToServer(filter_r4).ConsumeValueOrDie(); + + ComputeAndCompareLiteral(&builder, expected_r4, + {input_literal.get(), filter_literal.get()}, + error_spec_); + } +}; + +TYPED_TEST_CASE(Convolve2D_1x2x2x1024_2x2x128x512_Grouped_Valid, TestTypes); +TYPED_TEST(Convolve2D_1x2x2x1024_2x2x128x512_Grouped_Valid, Types) { + this->RunTest(); +} + // Test fixture to run convolution tests with and without convolution // canonicalization enabled. class ConvolveWithAndWithoutCanonicalization -- GitLab From ff2da7862e43aa624ac1f4689ce87eb929df8745 Mon Sep 17 00:00:00 2001 From: Rajagopal Ananthanarayanan Date: Thu, 22 Nov 2018 13:18:15 -0800 Subject: [PATCH 267/672] Automated rollback of commit aaad174baa41472d996c91866883f16d67a844cf PiperOrigin-RevId: 222563233 --- tensorflow/contrib/tpu/BUILD | 1 - .../contrib/tpu/python/tpu/tpu_estimator.py | 31 ++++++------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/tensorflow/contrib/tpu/BUILD b/tensorflow/contrib/tpu/BUILD index 8264462a06..a0a9cb3f31 100644 --- a/tensorflow/contrib/tpu/BUILD +++ b/tensorflow/contrib/tpu/BUILD @@ -78,7 +78,6 @@ py_library( "//tensorflow/python:init_ops", "//tensorflow/python:math_ops", "//tensorflow/python:platform", - "//tensorflow/python:session", "//tensorflow/python:state_ops", "//tensorflow/python:summary", "//tensorflow/python:summary_ops_v2", diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 2aaf65881b..637bd30828 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -45,7 +45,6 @@ from tensorflow.contrib.training.python.training import hparam from tensorflow.core.framework import variable_pb2 from tensorflow.core.framework.summary_pb2 import Summary from tensorflow.core.protobuf import config_pb2 -from tensorflow.python.client import session as tf_session from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest as data_nest from tensorflow.python.estimator import estimator as estimator_lib @@ -413,15 +412,12 @@ class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): enqueue_ops, dequeue_ops, run_infeed_loop_on_coordinator=True, - rendezvous=None, - master=None, - session_config=None): + rendezvous=None): self._master_job = ctx.master_job self._enqueue_ops = enqueue_ops self._dequeue_ops = dequeue_ops self._rendezvous = rendezvous - self._master = master - self._session_config = session_config + self._run_infeed_loop_on_coordinator = run_infeed_loop_on_coordinator self._initial_infeed_sleep_secs = ( ctx.config.tpu_config.initial_infeed_sleep_secs) @@ -433,10 +429,11 @@ class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): def begin(self): logging.info('TPU job name %s', self._master_job) self._iterations_per_loop_var = _create_or_get_iterations_per_loop() - self._init_ops = [] if self._should_initialize_tpu: + self._init_ops = [tpu.initialize_system(job=self._master_job)] self._finalize_ops = [tpu.shutdown_system(job=self._master_job)] else: + self._init_ops = [] self._finalize_ops = [] summary_writer_init_ops = contrib_summary.summary_writer_initializer_op() @@ -478,17 +475,11 @@ class TPUInfeedOutfeedSessionHook(session_run_hook.SessionRunHook): return _OpQueueContext(name=name, target=target, args=args) def after_create_session(self, session, coord): - if self._should_initialize_tpu: - logging.info('Init TPU system') - start = time.time() - with ops.Graph().as_default(): - with tf_session.Session( - self._master, config=self._session_config) as sess: - sess.run(tpu.initialize_system(job=self._master_job)) - logging.info('Initialized TPU in %d seconds', time.time() - start) - + logging.info('Init TPU system') + start = time.time() session.run(self._init_ops, options=config_pb2.RunOptions(timeout_in_ms=5 * 60 * 1000)) + logging.info('Initialized TPU in %d seconds', time.time() - start) self._infeed_controller = self._create_infeed_controller( name='InfeedController', target=self._run_infeed, args=(session,)) @@ -2573,8 +2564,6 @@ class TPUEstimator(estimator_lib.Estimator): run_infeed_loop_on_coordinator=( run_infeed_loop_on_coordinator), rendezvous=self._rendezvous[mode], - master=self._config.master, - session_config=self._session_config, ), InstallSignalHandlerHook() ]) @@ -2677,10 +2666,8 @@ class TPUEstimator(estimator_lib.Estimator): eval_update_ops + host_ops, run_infeed_loop_on_coordinator=( run_infeed_loop_on_coordinator), - rendezvous=self._rendezvous[mode], - master=self._config.master, - session_config=self._session_config, - )] + input_hooks + rendezvous=self._rendezvous[mode]), + ] + input_hooks if eval_hooks: hooks.extend(eval_hooks) -- GitLab From 0158a83cfb495de8a3d08dad8571ce75dc93d87b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 23 Nov 2018 01:02:08 -0800 Subject: [PATCH 268/672] compat: Update forward compatibility horizon to 2018-11-23 PiperOrigin-RevId: 222596771 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index ebe3fdbf53..9150d91409 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 22) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 23) @tf_export("compat.forward_compatible") -- GitLab From 5dbca226d9840a26178c53a509e87133bd1a73b9 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Fri, 23 Nov 2018 01:35:02 -0800 Subject: [PATCH 269/672] Add test case that shows TopK cannot handle minimum int value correctly. PiperOrigin-RevId: 222599761 --- .../compiler/xla/client/lib/sorting_test.cc | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tensorflow/compiler/xla/client/lib/sorting_test.cc b/tensorflow/compiler/xla/client/lib/sorting_test.cc index ebb30d3acc..27ff36c749 100644 --- a/tensorflow/compiler/xla/client/lib/sorting_test.cc +++ b/tensorflow/compiler/xla/client/lib/sorting_test.cc @@ -14,6 +14,9 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/compiler/xla/client/lib/sorting.h" + +#include + #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/test.h" #include "tensorflow/compiler/xla/tests/client_library_test_base.h" @@ -41,6 +44,28 @@ XLA_TEST_F(SortingTest, TopK3From8Indices) { ComputeAndCompareR1(&builder, {0, 1, 2}, {}); } +// TODO(b/119930279): enable this test. +XLA_TEST_F(SortingTest, DISABLED_TopKFullSortMinInt) { + XlaBuilder builder(TestName()); + auto x_rev = ConstantR1(&builder, {std::numeric_limits::min(), + std::numeric_limits::min() + 1, + std::numeric_limits::max()}); + xla::GetTupleElement(xla::TopK(x_rev, 3), 1); + ComputeAndCompareR1(&builder, {2, 1, 0}, {}); +} + +XLA_TEST_F(SortingTest, NOT_TopKFullSortMinInt) { + XlaBuilder builder(TestName()); + auto x_rev = ConstantR1(&builder, {std::numeric_limits::min(), + std::numeric_limits::min() + 1, + std::numeric_limits::max()}); + xla::GetTupleElement(xla::TopK(x_rev, 3), 1); + // TopK currently negates the keys, which doesn't work correctly for + // std::numeric_limits::min(). Therefore, it will sort this key to the + // front instead of to the back. + ComputeAndCompareR1(&builder, {0, 2, 1}, {}); +} + XLA_TEST_F(SortingTest, TopKFullSort) { XlaBuilder builder(TestName()); const int kSize = 16; -- GitLab From 9eb68e9f049b681fe448923da2205200410ea16d Mon Sep 17 00:00:00 2001 From: Sandip Giri Date: Fri, 23 Nov 2018 15:33:08 +0530 Subject: [PATCH 270/672] Updating ppc64le CPU build status link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8af5370bef..b3133ccb25 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ The TensorFlow project strives to abide by generally accepted best practices in Build Type | Status | Artifacts ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- **IBM s390x** | [![Build Status](http://ibmz-ci.osuosl.org/job/TensorFlow_IBMZ_CI/badge/icon)](http://ibmz-ci.osuosl.org/job/TensorFlow_IBMZ_CI/) | TBA -**IBM ppc64le CPU** | [![Build Status](http://powerci.osuosl.org/job/TensorFlow_Ubuntu_16.04_CPU/badge/icon)](http://powerci.osuosl.org/job/TensorFlow_Ubuntu_16.04_CPU/) | TBA +**IBM ppc64le CPU** | [![Build Status](http://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Build/badge/icon)](http://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Build/) | TBA **IBM ppc64le GPU** Nightly | [![Build Status](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/badge/icon)](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/) | [Nightly](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/) **IBM ppc64le GPU** Stable Release | [![Build Status](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/badge/icon)](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/) | [Release](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/) **Linux CPU with Intel® MKL-DNN** Nightly | [![Build Status](https://tensorflow-ci.intel.com/job/tensorflow-mkl-linux-cpu/badge/icon)](https://tensorflow-ci.intel.com/job/tensorflow-mkl-linux-cpu/) | [Nightly](https://tensorflow-ci.intel.com/job/tensorflow-mkl-build-whl-nightly/) -- GitLab From 520d5d5a66f9a0ca2004f4d4fc6698dbc531f9e8 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Fri, 23 Nov 2018 02:59:42 -0800 Subject: [PATCH 271/672] Merge slice operands of concatenate if they are "adjacent". We sometimes have a concatenate that has slices as operands which are slicing along the concatenate dimension and are also adjacent. This can be simplified by combining those slices into one slice and make this the operand of the concatenate. PiperOrigin-RevId: 222606151 --- .../xla/service/algebraic_simplifier.cc | 81 +++++++++++++++++-- .../xla/service/algebraic_simplifier_test.cc | 70 ++++++++++++++++ 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier.cc b/tensorflow/compiler/xla/service/algebraic_simplifier.cc index 56bf3a9f69..0b0502b4ff 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier.cc @@ -96,6 +96,11 @@ bool ReshapeOrCopyIsBitcast( valid_bitcast_callback(operand->shape(), instr->shape()); } +bool IsUnstridedSlice(const HloInstruction* hlo) { + return absl::c_all_of(hlo->slice_strides(), + [](int64 stride) { return stride == 1; }); +} + // AlgebraicSimplifierVisitor traverses the HLO computation and reduces certain // algebraic expressions to simplified forms. Note: This only supports // simplifications that simply look at the operands of an instruction. For the @@ -520,7 +525,74 @@ Status AlgebraicSimplifierVisitor::HandleConcatenate( VLOG(10) << "trying to replace " << concatenate->ToString() << " with " << replacement->ToString(); ReplaceInstructionIfSameShape(concatenate, replacement); - } else if (operands.size() == 2) { + return Status::OK(); + } + + // Check if we can merge "adjacent" slice operands which take slices from the + // same other op. For simplicity we only merge unstrided slices. + int64 concatenate_dimension = concatenate->concatenate_dimension(); + for (int64 i = 0; i < operands.size(); ++i) { + if (operands[i]->opcode() != HloOpcode::kSlice || + !IsUnstridedSlice(operands[i])) { + continue; + } + int64 slice_end = operands[i]->slice_limits(concatenate_dimension); + HloInstruction* slice_operand = operands[i]->mutable_operand(0); + int64 j = i + 1; + while (j < operands.size() && operands[j]->opcode() == HloOpcode::kSlice && + IsUnstridedSlice(operands[j]) && + operands[j]->operand(0) == slice_operand && + operands[j]->slice_starts(concatenate_dimension) == slice_end) { + // Check that all the slice_start values are the same in all other + // dimensions. This implies that the slice_limit values are also the same, + // because operands of concatenate need to have the same shape, and we + // already checked that the slices are unstrided. + bool same_other_starts = true; + for (int64 k = 0; k < operands[j]->slice_starts().size(); ++k) { + if (k == concatenate_dimension) { + continue; + } + if (operands[i]->slice_starts(k) != operands[j]->slice_starts(k)) { + same_other_starts = false; + break; + } + } + if (!same_other_starts) { + break; + } + slice_end = operands[j]->slice_limits(concatenate_dimension); + ++j; + } + if (j - i > 1) { + Shape new_slice_shape = operands[i]->shape(); + new_slice_shape.set_dimensions( + concatenate_dimension, + slice_end - operands[i]->slice_starts(concatenate_dimension)); + auto new_limit_indices = operands[i]->slice_limits(); + new_limit_indices[concatenate_dimension] = slice_end; + auto new_slice_op = + computation_->AddInstruction(HloInstruction::CreateSlice( + new_slice_shape, slice_operand, + /*start_indices=*/operands[i]->slice_starts(), + /*limit_indices=*/new_limit_indices, + /*strides=*/operands[i]->slice_strides())); + std::vector new_operands; + for (int64 k = 0; k < i; ++k) { + new_operands.push_back(operands[k]); + } + new_operands.push_back(new_slice_op); + for (int64 k = j; k < operands.size(); ++k) { + new_operands.push_back(operands[k]); + } + auto replacement = + computation_->AddInstruction(concatenate->CloneWithNewOperands( + concatenate->shape(), new_operands)); + ReplaceInstructionIfSameShape(concatenate, replacement); + return Status::OK(); + } + } + + if (operands.size() == 2) { // A binary concat with a broadcasted scalar as an operand can be converted // into a pad which is simpler to fold into other operations. bool is_effective_low_pad = Match( @@ -536,7 +608,7 @@ Status AlgebraicSimplifierVisitor::HandleConcatenate( padding_config_dim->set_edge_padding_high(0); padding_config_dim->set_edge_padding_low(0); padding_config_dim->set_interior_padding(0); - if (dim == concatenate->concatenate_dimension()) { + if (dim == concatenate_dimension) { if (is_effective_low_pad) { padding_config_dim->set_edge_padding_low( operands[0]->shape().dimensions(dim)); @@ -2010,11 +2082,6 @@ StatusOr AlgebraicSimplifierVisitor::TrySimplifyScalarSlice( return false; } -bool IsUnstridedSlice(const HloInstruction* hlo) { - return absl::c_all_of(hlo->slice_strides(), - [](int64 stride) { return stride == 1; }); -} - StatusOr AlgebraicSimplifierVisitor::TryToReorderSliceAndReshape( HloInstruction* slice) { CHECK_EQ(slice->opcode(), HloOpcode::kSlice); diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc b/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc index 8b8ba2a77d..24c35464ad 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc @@ -1437,6 +1437,76 @@ TEST_F(AlgebraicSimplifierTest, ConcatenateOfBroadcastBecomesPad) { EXPECT_THAT(computation->root_instruction(), op::Pad(param0, param1)); } +TEST_F(AlgebraicSimplifierTest, SimplifyConcatenateOfSlices) { + auto m = CreateNewVerifiedModule(); + Shape r2f32 = ShapeUtil::MakeShape(F32, {100, 99}); + Shape concat_shape = ShapeUtil::MakeShape(F32, {50, 80}); + HloComputation::Builder builder(TestName()); + HloInstruction* param0 = builder.AddInstruction( + HloInstruction::CreateParameter(0, r2f32, "param0")); + HloInstruction* param1 = builder.AddInstruction( + HloInstruction::CreateParameter(1, r2f32, "param1")); + + HloInstruction* slice0 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{0, 0}, + /*limit_indices=*/{50, 10}, /*strides=*/{1, 1})); + + // Cannot merge 'slice0' and 'slice1' because of different start indices in + // dimension 0. + HloInstruction* slice1 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{50, 10}, + /*limit_indices=*/{100, 20}, /*strides=*/{1, 1})); + + // Cannot merge 'slice1' and 'slice2' because of stride in dimension 2. + HloInstruction* slice2 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{50, 20}, + /*limit_indices=*/{100, 40}, /*strides=*/{1, 2})); + + // Cannot merge 'slice2' and 'slice3' because of stride in dimension 2. + HloInstruction* slice3 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{50, 40}, + /*limit_indices=*/{100, 50}, /*strides=*/{1, 1})); + + // Can merge 'slice3' and 'slice4'. + HloInstruction* slice4 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{50, 50}, + /*limit_indices=*/{100, 60}, /*strides=*/{1, 1})); + + // Can merge 'slice4' and 'slice5'. + HloInstruction* slice5 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{50, 60}, + /*limit_indices=*/{100, 70}, /*strides=*/{1, 1})); + + // Cannot merge 'slice5' and 'slice6' because of overlap. + HloInstruction* slice6 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param0, /*start_indices=*/{50, 69}, + /*limit_indices=*/{100, 79}, /*strides=*/{1, 1})); + + // Cannot merge 'slice6' and 'slice7' because of slicing from a different + // parameter. + HloInstruction* slice7 = builder.AddInstruction(HloInstruction::CreateSlice( + ShapeUtil::MakeShape(F32, {50, 10}), param1, /*start_indices=*/{50, 79}, + /*limit_indices=*/{100, 89}, /*strides=*/{1, 1})); + + builder.AddInstruction(HloInstruction::CreateConcatenate( + concat_shape, + {slice0, slice1, slice2, slice3, slice4, slice5, slice6, slice7}, 1)); + auto computation = m->AddEntryComputation(builder.Build()); + + AlgebraicSimplifier simplifier(default_options_); + ASSERT_TRUE(simplifier.Run(m.get()).ValueOrDie()); + EXPECT_THAT( + computation->root_instruction(), + op::Concatenate(op::Slice(param0), op::Slice(param0), op::Slice(param0), + op::Slice(param0), op::Slice(param0), op::Slice(param1))); + // The operand 3 should be a merge of 'slice3', 'slice4' and 'slice5', so its + // shape should have dimensions {50, 30}. + EXPECT_TRUE( + ShapeUtil::Equal(computation->root_instruction()->operand(3)->shape(), + ShapeUtil::MakeShape(F32, {50, 30}))); + EXPECT_EQ(computation->root_instruction()->operand(3)->slice_starts(1), 40); +} + // Test that a simplification which changes layouts is not performed if layout // sensitive is true. TEST_F(AlgebraicSimplifierTest, CopyWithDifferentLayout) { -- GitLab From a1532717be531a75267a34c62566805aa68abf4e Mon Sep 17 00:00:00 2001 From: Yunxing Dai Date: Fri, 23 Nov 2018 14:05:07 -0800 Subject: [PATCH 272/672] Automated rollback of commit 89deaf06c19a3eb1d5236d328b6b8cdde7238271 PiperOrigin-RevId: 222644654 --- tensorflow/compiler/tests/xla_test.py | 5 ----- tensorflow/python/platform/googletest.py | 9 +-------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/tensorflow/compiler/tests/xla_test.py b/tensorflow/compiler/tests/xla_test.py index d15c073457..98a41981cf 100644 --- a/tensorflow/compiler/tests/xla_test.py +++ b/tensorflow/compiler/tests/xla_test.py @@ -22,7 +22,6 @@ import contextlib import os import random import re -import sys import numpy as np @@ -39,10 +38,6 @@ from tensorflow.python.platform import flags from tensorflow.python.platform import test from tensorflow.python.platform import tf_logging as logging -# TODO(b/35678764): Disable monkeypatched exit handlers once we find a proper -# solution to invoke exit handlers during program exit. -test._googletest.SetOSExit(sys.exit) - FLAGS = flags.FLAGS flags.DEFINE_string('test_device', None, diff --git a/tensorflow/python/platform/googletest.py b/tensorflow/python/platform/googletest.py index c8312c153e..8141cf92c5 100644 --- a/tensorflow/python/platform/googletest.py +++ b/tensorflow/python/platform/googletest.py @@ -47,13 +47,6 @@ unittest_main = main # directory only once per test binary invocation. _googletest_temp_dir = '' -_os_exit = sys.exit - - -def SetOSExit(exit_func): - global _os_exit - _os_exit = exit_func - # pylint: disable=invalid-name # pylint: disable=undefined-variable @@ -68,7 +61,7 @@ def g_main(argv): except IOError: sys.stderr.write('Error opening TEST_SHARD_STATUS_FILE (%s). Exiting.' % os.environ['TEST_SHARD_STATUS_FILE']) - _os_exit(1) + sys.exit(1) finally: if f is not None: f.close() -- GitLab From 809ed3c835403564333bfdc06fca512432db4ca1 Mon Sep 17 00:00:00 2001 From: Brennan Saeta Date: Fri, 23 Nov 2018 14:36:05 -0800 Subject: [PATCH 273/672] [Core]: Use unique_ptr in DeviceMgr In order to take advantage of the type system to help enforce ownership, this change refactors DeviceMgr to use std::unique_ptr instead of Device*'s. It also updates all callers to use the new types. PiperOrigin-RevId: 222645861 --- tensorflow/c/eager/BUILD | 1 + tensorflow/c/eager/c_api.cc | 11 +++--- .../compiler/jit/build_xla_ops_pass_test.cc | 8 +--- .../compiler/jit/create_xla_launch_op_test.cc | 6 +-- .../mark_for_compilation_pass_test_helper.cc | 8 +--- .../jit/partially_decluster_pass_test.cc | 6 +-- tensorflow/compiler/jit/xla_cpu_device.cc | 11 +++--- tensorflow/compiler/jit/xla_gpu_device.cc | 10 ++--- .../compiler/jit/xla_interpreter_device.cc | 7 ++-- tensorflow/compiler/tf2xla/xla_compiler.cc | 2 +- tensorflow/core/BUILD | 4 ++ .../collective_executor_mgr_test.cc | 6 +-- .../collective_param_resolver_local_test.cc | 6 +-- .../collective_rma_local_test.cc | 6 +-- .../core/common_runtime/device_factory.cc | 17 +++++---- .../core/common_runtime/device_factory.h | 13 ++++--- tensorflow/core/common_runtime/device_mgr.cc | 37 +++++++++++-------- tensorflow/core/common_runtime/device_mgr.h | 15 ++++---- .../device_resolver_local_test.cc | 6 +-- .../core/common_runtime/device_set_test.cc | 2 +- .../core/common_runtime/direct_session.cc | 4 +- tensorflow/core/common_runtime/eager/BUILD | 1 + .../eager/kernel_and_device_test.cc | 14 ++++--- .../core/common_runtime/executor_test.cc | 8 ++-- .../core/common_runtime/function_test.cc | 7 ++-- .../function_threadpool_test.cc | 6 +-- .../core/common_runtime/gpu/gpu_device.cc | 20 +++++----- .../core/common_runtime/gpu/gpu_device.h | 18 ++++----- .../common_runtime/gpu/gpu_device_factory.cc | 21 +++++------ .../gpu/gpu_device_on_non_gpu_machine_test.cc | 2 +- .../common_runtime/gpu/gpu_device_test.cc | 32 +++++++--------- .../hierarchical_tree_broadcaster_test.cc | 11 +++--- .../kernel_benchmark_testlib.cc | 8 ++-- .../common_runtime/kernel_benchmark_testlib.h | 2 +- tensorflow/core/common_runtime/placer_test.cc | 2 +- .../process_function_library_runtime_test.cc | 18 +++++---- .../core/common_runtime/renamed_device.cc | 14 +++---- .../core/common_runtime/renamed_device.h | 7 ++-- .../core/common_runtime/ring_reducer_test.cc | 11 +++--- .../threadpool_device_factory.cc | 17 +++++---- tensorflow/core/distributed_runtime/BUILD | 1 + ...lective_param_resolver_distributed_test.cc | 11 +++--- .../collective_rma_distributed_test.cc | 11 +++--- .../device_resolver_distributed_test.cc | 13 ++++--- .../eager/eager_service_impl.cc | 6 +-- .../eager/eager_service_impl_test.cc | 9 ++--- .../rpc/grpc_server_lib.cc | 11 ++++-- .../rpc_collective_executor_mgr_test.cc | 6 +-- .../core/distributed_runtime/session_mgr.cc | 4 +- .../distributed_runtime/session_mgr_test.cc | 8 ++-- .../core/grappler/grappler_item_builder.cc | 9 +++-- tensorflow/core/grappler/optimizers/BUILD | 2 +- .../grappler/optimizers/function_optimizer.cc | 9 +++-- tensorflow/core/kernels/data/BUILD | 1 + tensorflow/core/kernels/data/iterator_ops.cc | 6 +-- .../data/single_threaded_executor_test.cc | 8 ++-- tensorflow/lite/delegates/flex/BUILD | 1 + .../lite/delegates/flex/delegate_data.cc | 7 ++-- tensorflow/lite/toco/import_tensorflow.cc | 4 +- tensorflow/python/client/device_lib.i | 7 +--- tensorflow/python/grappler/tf_optimizer.i | 5 +-- 61 files changed, 273 insertions(+), 271 deletions(-) diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD index ba3d8533db..5a0988ed31 100644 --- a/tensorflow/c/eager/BUILD +++ b/tensorflow/c/eager/BUILD @@ -50,6 +50,7 @@ tf_cuda_library( ], "//conditions:default": [], }) + [ + "@com_google_absl//absl/memory", "//tensorflow/core/common_runtime/eager:eager_operation", "//tensorflow/core/distributed_runtime/eager:eager_client", "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client", diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index 192044915f..c9e730ef41 100755 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -21,6 +21,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "tensorflow/c/c_api.h" #include "tensorflow/c/c_api_internal.h" #include "tensorflow/c/eager/c_api_internal.h" @@ -80,7 +81,7 @@ tensorflow::Status GetAllRemoteDevices( const std::vector& remote_workers, tensorflow::WorkerCacheInterface* worker_cache, std::unique_ptr* device_mgr) { - std::vector remote_devices; + std::vector> remote_devices; tensorflow::Status status; // TODO(nareshmodi) do this in parallel instead of serially. for (const string& remote_worker : remote_workers) { @@ -93,7 +94,7 @@ tensorflow::Status GetAllRemoteDevices( status = s; if (s.ok()) { for (tensorflow::Device* d : *devices) { - remote_devices.push_back(d); + remote_devices.emplace_back(d); } } n.Notify(); @@ -101,7 +102,7 @@ tensorflow::Status GetAllRemoteDevices( n.WaitForNotification(); } std::unique_ptr remote_device_mgr( - new tensorflow::DeviceMgr(remote_devices)); + new tensorflow::DeviceMgr(std::move(remote_devices))); TF_RETURN_IF_ERROR(status); @@ -262,13 +263,13 @@ TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx, void TFE_DeleteContextOptions(TFE_ContextOptions* options) { delete options; } TFE_Context* TFE_NewContext(const TFE_ContextOptions* opts, TF_Status* status) { - std::vector devices; + std::vector> devices; status->status = tensorflow::DeviceFactory::AddDevices( opts->session_options.options, "/job:localhost/replica:0/task:0", &devices); if (!status->status.ok()) return nullptr; std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(devices)); + new tensorflow::DeviceMgr(std::move(devices))); tensorflow::Rendezvous* r = new tensorflow::IntraProcessRendezvous(device_mgr.get()); diff --git a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc index 11df946cc1..48a23a4c17 100644 --- a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc +++ b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc @@ -42,14 +42,8 @@ class BuildXlaOpsTest : public ::testing::Test { .ok()); } - void TearDown() override { - for (Device* device : devices_) { - delete device; - } - } - private: - std::vector devices_; + std::vector> devices_; }; using ::tensorflow::testing::FindNodeByName; diff --git a/tensorflow/compiler/jit/create_xla_launch_op_test.cc b/tensorflow/compiler/jit/create_xla_launch_op_test.cc index 7386660762..0f872a480f 100644 --- a/tensorflow/compiler/jit/create_xla_launch_op_test.cc +++ b/tensorflow/compiler/jit/create_xla_launch_op_test.cc @@ -59,8 +59,9 @@ class CreateXlaLaunchOpTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 1}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices_)); + options, "/job:localhost/replica:0/task:0", &devices)); FunctionDefLibrary proto; for (const auto& fdef : flib) { @@ -69,7 +70,7 @@ class CreateXlaLaunchOpTest : public ::testing::Test { lib_def_ = absl::make_unique( OpRegistry::Global(), proto); OptimizerOptions opts; - device_mgr_ = absl::make_unique(devices_); + device_mgr_ = absl::make_unique(std::move(devices)); pflr_ = absl::make_unique( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, /*default_thread_pool=*/nullptr, /*cluster_flr=*/nullptr); @@ -77,7 +78,6 @@ class CreateXlaLaunchOpTest : public ::testing::Test { } FunctionLibraryRuntime* flr_; - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc index d56d0f8ccf..64a3301745 100644 --- a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc +++ b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc @@ -34,15 +34,9 @@ namespace tensorflow { // // It may be worth refactoring out XlaOpRegistry::RegisterCompilationDevice to // make this more direct, but probably not worth it solely for this test. - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(*session_options, "", &devices)); - auto delete_devices = gtl::MakeCleanup([&] { - for (Device* d : devices) { - delete d; - } - }); - GraphOptimizationPassOptions opt_options; opt_options.graph = graph; opt_options.session_options = session_options; diff --git a/tensorflow/compiler/jit/partially_decluster_pass_test.cc b/tensorflow/compiler/jit/partially_decluster_pass_test.cc index 1fc5da5071..38a54cc5ef 100644 --- a/tensorflow/compiler/jit/partially_decluster_pass_test.cc +++ b/tensorflow/compiler/jit/partially_decluster_pass_test.cc @@ -386,7 +386,7 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) { TF_ASSERT_OK(s.ToGraph(graph.get())); // This is needed to register the XLA_GPU device. - std::vector devices; + std::vector> devices; TF_ASSERT_OK(DeviceFactory::AddDevices( SessionOptions(), "/job:localhost/replica:0/task:0", &devices)); @@ -400,10 +400,6 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) { TF_ASSERT_OK(PartiallyDecluster(&graph)); EXPECT_EQ(GetXlaClusterForNode(*n), "cluster_0"); - - for (Device* d : devices) { - delete d; - } } TEST(PartiallyDeclusterPassTest, DontDeclusterNonTensorFlowOps) { diff --git a/tensorflow/compiler/jit/xla_cpu_device.cc b/tensorflow/compiler/jit/xla_cpu_device.cc index 9006dd514b..7df898ad12 100644 --- a/tensorflow/compiler/jit/xla_cpu_device.cc +++ b/tensorflow/compiler/jit/xla_cpu_device.cc @@ -31,12 +31,12 @@ namespace tensorflow { class XlaCpuDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; }; -Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options, - const string& name_prefix, - std::vector* devices) { +Status XlaCpuDeviceFactory::CreateDevices( + const SessionOptions& session_options, const string& name_prefix, + std::vector>* devices) { XlaDeviceFlags* flags = GetXlaDeviceFlags(); bool compile_on_demand = flags->tf_xla_compile_on_demand; @@ -63,8 +63,7 @@ Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options, options.device_ordinal = 0; options.compilation_device_name = DEVICE_CPU_XLA_JIT; options.use_multiple_streams = false; - auto device = absl::make_unique(session_options, options); - devices->push_back(device.release()); + devices->push_back(absl::make_unique(session_options, options)); return Status::OK(); } diff --git a/tensorflow/compiler/jit/xla_gpu_device.cc b/tensorflow/compiler/jit/xla_gpu_device.cc index 4419701695..944f732b99 100644 --- a/tensorflow/compiler/jit/xla_gpu_device.cc +++ b/tensorflow/compiler/jit/xla_gpu_device.cc @@ -29,12 +29,12 @@ namespace tensorflow { class XlaGpuDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; }; -Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options, - const string& name_prefix, - std::vector* devices) { +Status XlaGpuDeviceFactory::CreateDevices( + const SessionOptions& session_options, const string& name_prefix, + std::vector>* devices) { XlaOpRegistry::DeviceRegistration registration; registration.compilation_device_name = DEVICE_GPU_XLA_JIT; registration.autoclustering_policy = @@ -70,7 +70,7 @@ Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options, return status; } - devices->push_back(device.release()); + devices->push_back(std::move(device)); } return Status::OK(); } diff --git a/tensorflow/compiler/jit/xla_interpreter_device.cc b/tensorflow/compiler/jit/xla_interpreter_device.cc index e828bae865..4007309ed1 100644 --- a/tensorflow/compiler/jit/xla_interpreter_device.cc +++ b/tensorflow/compiler/jit/xla_interpreter_device.cc @@ -33,12 +33,12 @@ constexpr std::array kExecAllTypes = { class XlaInterpreterDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; }; Status XlaInterpreterDeviceFactory::CreateDevices( const SessionOptions& session_options, const string& name_prefix, - std::vector* devices) { + std::vector>* devices) { static XlaDeviceOpRegistrations* registrations = RegisterXlaDeviceKernels( DEVICE_XLA_INTERPRETER, DEVICE_INTERPRETER_XLA_JIT); (void)registrations; @@ -61,8 +61,7 @@ Status XlaInterpreterDeviceFactory::CreateDevices( options.device_ordinal = 0; options.compilation_device_name = DEVICE_INTERPRETER_XLA_JIT; options.use_multiple_streams = false; - auto device = absl::make_unique(session_options, options); - devices->push_back(device.release()); + devices->push_back(absl::make_unique(session_options, options)); return Status::OK(); } diff --git a/tensorflow/compiler/tf2xla/xla_compiler.cc b/tensorflow/compiler/tf2xla/xla_compiler.cc index 8036bc6844..2230bfd7d9 100644 --- a/tensorflow/compiler/tf2xla/xla_compiler.cc +++ b/tensorflow/compiler/tf2xla/xla_compiler.cc @@ -380,7 +380,7 @@ XlaCompiler::XlaCompiler(XlaCompiler::Options options) initialization_status_(Status::OK()), next_step_id_(1), device_(new XlaCompilationDevice(SessionOptions(), options_.device_type)), - device_mgr_({device_}) { + device_mgr_(absl::WrapUnique(device_)) { CHECK(!options_.device_type.type_string().empty()); if (options_.populate_resource_manager) { initialization_status_ = diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 2a8c2718ed..1b4371198a 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -2963,6 +2963,7 @@ tf_cuda_library( ":lib_internal", ":proto_text", ":protos_all_cc", + "@com_google_absl//absl/memory", "//third_party/eigen3", "//tensorflow/core/grappler:grappler_item", ] + mkl_deps(), @@ -3816,6 +3817,7 @@ tf_cc_tests_gpu( ":test", ":test_main", ":testlib", + "@com_google_absl//absl/memory", ], ) @@ -3844,6 +3846,7 @@ tf_cc_tests_gpu( ":test", ":test_main", ":testlib", + "@com_google_absl//absl/memory", ], ) @@ -4411,6 +4414,7 @@ tf_cc_test( "//tensorflow/core/kernels:random_ops", "//tensorflow/core/kernels:shape_ops", "//third_party/eigen3", + "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/core/common_runtime/collective_executor_mgr_test.cc b/tensorflow/core/common_runtime/collective_executor_mgr_test.cc index 91994c5731..f3d86aa633 100644 --- a/tensorflow/core/common_runtime/collective_executor_mgr_test.cc +++ b/tensorflow/core/common_runtime/collective_executor_mgr_test.cc @@ -38,8 +38,9 @@ class CollectiveExecutorMgrTest : public ::testing::Test { auto* device_count = options.config.mutable_device_count(); string task_name = "/job:localhost/replica:0/task:0"; device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); std::unique_ptr drl( new DeviceResolverLocal(device_mgr_.get())); std::unique_ptr prl( @@ -50,7 +51,6 @@ class CollectiveExecutorMgrTest : public ::testing::Test { } std::unique_ptr cme_; - std::vector devices_; std::unique_ptr device_mgr_; }; diff --git a/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc b/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc index 9a501b3298..94d889c40d 100644 --- a/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc +++ b/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc @@ -37,8 +37,9 @@ class CollectiveParamResolverLocalTest : public ::testing::Test { string task_name = "/job:localhost/replica:0/task:0"; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); prl_.reset(new CollectiveParamResolverLocal(device_mgr_.get(), drl_.get(), task_name)); @@ -73,7 +74,6 @@ class CollectiveParamResolverLocalTest : public ::testing::Test { } } - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; std::unique_ptr prl_; diff --git a/tensorflow/core/common_runtime/collective_rma_local_test.cc b/tensorflow/core/common_runtime/collective_rma_local_test.cc index a931fe64bd..4263f3a4ad 100644 --- a/tensorflow/core/common_runtime/collective_rma_local_test.cc +++ b/tensorflow/core/common_runtime/collective_rma_local_test.cc @@ -42,8 +42,9 @@ class CollectiveRemoteAccessLocalTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, kTaskName, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, kTaskName, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); prl_.reset(new CollectiveParamResolverLocal(device_mgr_.get(), drl_.get(), kTaskName)); @@ -51,7 +52,6 @@ class CollectiveRemoteAccessLocalTest : public ::testing::Test { kStepId)); } - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; std::unique_ptr prl_; diff --git a/tensorflow/core/common_runtime/device_factory.cc b/tensorflow/core/common_runtime/device_factory.cc index b94900114c..0fad13fe1e 100644 --- a/tensorflow/core/common_runtime/device_factory.cc +++ b/tensorflow/core/common_runtime/device_factory.cc @@ -20,6 +20,7 @@ limitations under the License. #include #include +#include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/logging.h" @@ -89,9 +90,9 @@ DeviceFactory* DeviceFactory::GetFactory(const string& device_type) { return it->second.factory.get(); } -Status DeviceFactory::AddDevices(const SessionOptions& options, - const string& name_prefix, - std::vector* devices) { +Status DeviceFactory::AddDevices( + const SessionOptions& options, const string& name_prefix, + std::vector>* devices) { // CPU first. A CPU device is required. auto cpu_factory = GetFactory("CPU"); if (!cpu_factory) { @@ -116,16 +117,16 @@ Status DeviceFactory::AddDevices(const SessionOptions& options, return Status::OK(); } -Device* DeviceFactory::NewDevice(const string& type, - const SessionOptions& options, - const string& name_prefix) { +std::unique_ptr DeviceFactory::NewDevice(const string& type, + const SessionOptions& options, + const string& name_prefix) { auto device_factory = GetFactory(type); if (!device_factory) { return nullptr; } SessionOptions opt = options; (*opt.config.mutable_device_count())[type] = 1; - std::vector devices; + std::vector> devices; TF_CHECK_OK(device_factory->CreateDevices(opt, name_prefix, &devices)); int expected_num_devices = 1; auto iter = options.config.device_count().find(type); @@ -133,7 +134,7 @@ Device* DeviceFactory::NewDevice(const string& type, expected_num_devices = iter->second; } DCHECK_EQ(devices.size(), static_cast(expected_num_devices)); - return devices[0]; + return std::move(devices[0]); } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/device_factory.h b/tensorflow/core/common_runtime/device_factory.h index db50226fe8..b3cd7adca9 100644 --- a/tensorflow/core/common_runtime/device_factory.h +++ b/tensorflow/core/common_runtime/device_factory.h @@ -40,18 +40,19 @@ class DeviceFactory { // CPU devices are added first. static Status AddDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices); + std::vector>* devices); // Helper for tests. Create a single device of type "type". The // returned device is always numbered zero, so if creating multiple // devices of the same type, supply distinct name_prefix arguments. - static Device* NewDevice(const string& type, const SessionOptions& options, - const string& name_prefix); + static std::unique_ptr NewDevice(const string& type, + const SessionOptions& options, + const string& name_prefix); // Most clients should call AddDevices() instead. - virtual Status CreateDevices(const SessionOptions& options, - const string& name_prefix, - std::vector* devices) = 0; + virtual Status CreateDevices( + const SessionOptions& options, const string& name_prefix, + std::vector>* devices) = 0; // Return the device priority number for a "device_type" string. // diff --git a/tensorflow/core/common_runtime/device_mgr.cc b/tensorflow/core/common_runtime/device_mgr.cc index 470abc1431..1f7d7c4699 100644 --- a/tensorflow/core/common_runtime/device_mgr.cc +++ b/tensorflow/core/common_runtime/device_mgr.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/device_mgr.h" +#include #include #include "tensorflow/core/common_runtime/local_device.h" #include "tensorflow/core/framework/device_attributes.pb.h" @@ -24,32 +25,32 @@ limitations under the License. namespace tensorflow { -DeviceMgr::DeviceMgr(const std::vector& devices) - : name_backing_store_(128) { - for (Device* d : devices) { +DeviceMgr::DeviceMgr(std::vector> devices) + : devices_(std::move(devices)), name_backing_store_(128) { + for (auto& d : devices_) { CHECK(d->device_mgr_ == nullptr); d->device_mgr_ = this; - devices_.push_back(d); - // Register under the (1) full name and (2) canonical name. for (const string& name : DeviceNameUtils::GetNamesForDeviceMappings(d->parsed_name())) { - device_map_[CopyToBackingStore(name)] = d; + device_map_[CopyToBackingStore(name)] = d.get(); } // Register under the (3) local name and (4) legacy local name. for (const string& name : DeviceNameUtils::GetLocalNamesForDeviceMappings(d->parsed_name())) { - device_map_[CopyToBackingStore(name)] = d; + device_map_[CopyToBackingStore(name)] = d.get(); } device_type_counts_[d->device_type()]++; } } -DeviceMgr::~DeviceMgr() { - // TODO(b/37437134): Remove destructor after converting to std::unique_ptr. - for (Device* p : devices_) delete p; -} +DeviceMgr::DeviceMgr(std::unique_ptr device) + : DeviceMgr([&device] { + std::vector> vector; + vector.push_back(std::move(device)); + return vector; + }()) {} StringPiece DeviceMgr::CopyToBackingStore(StringPiece s) { size_t n = s.size(); @@ -61,18 +62,22 @@ StringPiece DeviceMgr::CopyToBackingStore(StringPiece s) { void DeviceMgr::ListDeviceAttributes( std::vector* devices) const { devices->reserve(devices_.size()); - for (Device* dev : devices_) { + for (const auto& dev : devices_) { devices->emplace_back(dev->attributes()); } } std::vector DeviceMgr::ListDevices() const { - return std::vector(devices_.begin(), devices_.end()); + std::vector devices(devices_.size()); + for (size_t i = 0; i < devices_.size(); ++i) { + devices[i] = devices_[i].get(); + } + return devices; } string DeviceMgr::DebugString() const { string out; - for (Device* dev : devices_) { + for (const auto& dev : devices_) { strings::StrAppend(&out, dev->name(), "\n"); } return out; @@ -80,7 +85,7 @@ string DeviceMgr::DebugString() const { string DeviceMgr::DeviceMappingString() const { string out; - for (Device* dev : devices_) { + for (const auto& dev : devices_) { if (!dev->attributes().physical_device_desc().empty()) { strings::StrAppend(&out, dev->name(), " -> ", dev->attributes().physical_device_desc(), "\n"); @@ -107,7 +112,7 @@ Status DeviceMgr::LookupDevice(StringPiece name, Device** device) const { void DeviceMgr::ClearContainers(gtl::ArraySlice containers) const { Status s; - for (Device* dev : devices_) { + for (const auto& dev : devices_) { if (containers.empty()) { s.Update(dev->resource_manager()->Cleanup( dev->resource_manager()->default_container())); diff --git a/tensorflow/core/common_runtime/device_mgr.h b/tensorflow/core/common_runtime/device_mgr.h index c1ff10d9b5..bf8694655a 100644 --- a/tensorflow/core/common_runtime/device_mgr.h +++ b/tensorflow/core/common_runtime/device_mgr.h @@ -16,6 +16,7 @@ limitations under the License. #ifndef TENSORFLOW_CORE_COMMON_RUNTIME_DEVICE_MGR_H_ #define TENSORFLOW_CORE_COMMON_RUNTIME_DEVICE_MGR_H_ +#include #include #include #include @@ -34,15 +35,17 @@ class DeviceAttributes; class DeviceMgr { public: - // Takes ownership of each device in 'devices'. + // Constructs a DeviceMgr from a list of devices. // TODO(zhifengc): Other initialization information. - // TODO(b/37437134): Use std::unique_ptr's to track ownership. - explicit DeviceMgr(const std::vector& devices); - ~DeviceMgr(); + explicit DeviceMgr(std::vector> devices); + + // Constructs a DeviceMgr managing a single device. + explicit DeviceMgr(std::unique_ptr device); // Returns attributes of all devices. void ListDeviceAttributes(std::vector* devices) const; + // Returns raw pointers to the underlying devices. std::vector ListDevices() const; // Returns a string listing all devices. @@ -62,9 +65,7 @@ class DeviceMgr { int NumDeviceType(const string& type) const; private: - // TODO(b/37437134): Use std::unique_ptr's to track ownership. - typedef gtl::InlinedVector DeviceVec; - DeviceVec devices_; + const std::vector> devices_; StringPiece CopyToBackingStore(StringPiece s); diff --git a/tensorflow/core/common_runtime/device_resolver_local_test.cc b/tensorflow/core/common_runtime/device_resolver_local_test.cc index f5a6471ff7..54f1119e13 100644 --- a/tensorflow/core/common_runtime/device_resolver_local_test.cc +++ b/tensorflow/core/common_runtime/device_resolver_local_test.cc @@ -36,12 +36,12 @@ class DeviceResolverLocalTest : public ::testing::Test { string task_name = "/job:localhost/replica:0/task:0"; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); } - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; }; diff --git a/tensorflow/core/common_runtime/device_set_test.cc b/tensorflow/core/common_runtime/device_set_test.cc index fd9c4222a7..6a8c3d14e5 100644 --- a/tensorflow/core/common_runtime/device_set_test.cc +++ b/tensorflow/core/common_runtime/device_set_test.cc @@ -57,7 +57,7 @@ class DeviceSetTest : public ::testing::Test { class DummyFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { return Status::OK(); } }; diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index 40b7071f40..91717328b1 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -155,12 +155,12 @@ class DirectSessionFactory : public SessionFactory { if (options.config.graph_options().build_cost_model() > 0) { EnableCPUAllocatorFullStats(true); } - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); DirectSession* session = - new DirectSession(options, new DeviceMgr(devices), this); + new DirectSession(options, new DeviceMgr(std::move(devices)), this); { mutex_lock l(sessions_lock_); sessions_.push_back(session); diff --git a/tensorflow/core/common_runtime/eager/BUILD b/tensorflow/core/common_runtime/eager/BUILD index a7b618c18b..86890ba07d 100644 --- a/tensorflow/core/common_runtime/eager/BUILD +++ b/tensorflow/core/common_runtime/eager/BUILD @@ -181,6 +181,7 @@ tf_cc_test( "//tensorflow/core:lib", "//tensorflow/core:test", "//tensorflow/core:test_main", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc b/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc index 948bdbcaf5..3ffed3ce32 100644 --- a/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc +++ b/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "tensorflow/cc/client/client_session.h" #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -37,12 +38,13 @@ namespace { class TestEnv { public: TestEnv() : flib_def_(OpRegistry::Global(), {}) { - Device* device = - DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0"); - device_mgr_.reset(new DeviceMgr({device})); - flib_runtime_ = NewFunctionLibraryRuntime(device_mgr_.get(), Env::Default(), - device, TF_GRAPH_DEF_VERSION, - &flib_def_, nullptr, {}, nullptr); + std::vector> devices; + devices.push_back( + DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0")); + device_mgr_ = absl::make_unique(std::move(devices)); + flib_runtime_ = NewFunctionLibraryRuntime( + device_mgr_.get(), Env::Default(), device_mgr_->ListDevices()[0], + TF_GRAPH_DEF_VERSION, &flib_def_, nullptr, {}, nullptr); } FunctionLibraryRuntime* function_library_runtime() const { diff --git a/tensorflow/core/common_runtime/executor_test.cc b/tensorflow/core/common_runtime/executor_test.cc index 7697103faf..c311b2533e 100644 --- a/tensorflow/core/common_runtime/executor_test.cc +++ b/tensorflow/core/common_runtime/executor_test.cc @@ -53,17 +53,17 @@ class ExecutorTest : public ::testing::Test { // when the test completes. CHECK(rendez_->Unref()); delete exec_; - delete device_; } // Resets executor_ with a new executor based on a graph 'gdef'. void Create(std::unique_ptr graph) { const int version = graph->versions().producer(); LocalExecutorParams params; - params.device = device_; + params.device = device_.get(); params.create_kernel = [this, version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_, nullptr, ndef, version, kernel); + return CreateNonCachedKernel(device_.get(), nullptr, ndef, version, + kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -83,7 +83,7 @@ class ExecutorTest : public ::testing::Test { } thread::ThreadPool* thread_pool_ = nullptr; - Device* device_ = nullptr; + std::unique_ptr device_; Executor* exec_ = nullptr; StepStatsCollector step_stats_collector_; StepStats step_stats_; diff --git a/tensorflow/core/common_runtime/function_test.cc b/tensorflow/core/common_runtime/function_test.cc index 13c189fb87..3b4c976685 100644 --- a/tensorflow/core/common_runtime/function_test.cc +++ b/tensorflow/core/common_runtime/function_test.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "absl/strings/numbers.h" #include "absl/strings/str_split.h" #include "tensorflow/cc/ops/array_ops_internal.h" @@ -147,14 +148,15 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 3}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices_)); + options, "/job:localhost/replica:0/task:0", &devices)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); OptimizerOptions opts; - device_mgr_.reset(new DeviceMgr(devices_)); + device_mgr_ = absl::make_unique(std::move(devices)); pflr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); @@ -358,7 +360,6 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { FunctionLibraryRuntime* flr0_; FunctionLibraryRuntime* flr1_; FunctionLibraryRuntime* flr2_; - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/core/common_runtime/function_threadpool_test.cc b/tensorflow/core/common_runtime/function_threadpool_test.cc index 655a68cfc9..bdbe24a70d 100644 --- a/tensorflow/core/common_runtime/function_threadpool_test.cc +++ b/tensorflow/core/common_runtime/function_threadpool_test.cc @@ -54,14 +54,15 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 3}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices_)); + options, "/job:localhost/replica:0/task:0", &devices)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); OptimizerOptions opts; - device_mgr_.reset(new DeviceMgr(devices_)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); pflr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); @@ -194,7 +195,6 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { FunctionLibraryRuntime* flr0_; FunctionLibraryRuntime* flr1_; FunctionLibraryRuntime* flr2_; - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.cc b/tensorflow/core/common_runtime/gpu/gpu_device.cc index 81fea311e1..5152d97fde 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device.cc @@ -907,9 +907,9 @@ Allocator* BaseGPUDevice::GetScopedAllocator(AllocatorAttributes attr, const int BaseGPUDeviceFactory::InterconnectMap::kSameDeviceStrength = 1000; const int BaseGPUDeviceFactory::InterconnectMap::kStreamExecutorStrength = 1; -Status BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, - const string& name_prefix, - std::vector* devices) { +Status BaseGPUDeviceFactory::CreateDevices( + const SessionOptions& options, const string& name_prefix, + std::vector>* devices) { TF_RETURN_IF_ERROR(ValidateGPUMachineManager()); se::Platform* gpu_manager = GPUMachineManager(); if (gpu_manager == nullptr) { @@ -1073,12 +1073,10 @@ static string GetShortDeviceDescription(PlatformGpuId platform_gpu_id, // LINT.ThenChange(//tensorflow/python/platform/test.py) } -Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, - const string& name_prefix, - TfGpuId tf_gpu_id, - int64 memory_limit, - const DeviceLocality& dev_locality, - std::vector* devices) { +Status BaseGPUDeviceFactory::CreateGPUDevice( + const SessionOptions& options, const string& name_prefix, TfGpuId tf_gpu_id, + int64 memory_limit, const DeviceLocality& dev_locality, + std::vector>* devices) { CHECK_GE(tf_gpu_id.value(), 0); const string device_name = strings::StrCat(name_prefix, "/device:GPU:", tf_gpu_id.value()); @@ -1108,7 +1106,7 @@ Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, // different (which should be an error). // // TODO(laigd): report error if memory_limit doesn't match stats.bytes_limit. - BaseGPUDevice* gpu_device = CreateGPUDevice( + std::unique_ptr gpu_device = CreateGPUDevice( options, device_name, static_cast(stats.bytes_limit), dev_locality, tf_gpu_id, GetShortDeviceDescription(platform_gpu_id, desc), gpu_allocator, ProcessState::singleton()->GetCPUAllocator(numa_node)); @@ -1116,7 +1114,7 @@ Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, << (stats.bytes_limit >> 20) << " MB memory) -> physical GPU (" << GetShortDeviceDescription(platform_gpu_id, desc) << ")"; TF_RETURN_IF_ERROR(gpu_device->Init(options)); - devices->push_back(gpu_device); + devices->push_back(std::move(gpu_device)); return Status::OK(); } diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.h b/tensorflow/core/common_runtime/gpu/gpu_device.h index 674e8384d5..d002d02c51 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.h +++ b/tensorflow/core/common_runtime/gpu/gpu_device.h @@ -166,7 +166,7 @@ class BaseGPUDevice : public LocalDevice { class BaseGPUDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; struct InterconnectMap { // Name of interconnect technology, if known. @@ -207,15 +207,13 @@ class BaseGPUDeviceFactory : public DeviceFactory { Status CreateGPUDevice(const SessionOptions& options, const string& name_prefix, TfGpuId tf_gpu_id, int64 memory_limit, const DeviceLocality& dev_locality, - std::vector* devices); - - virtual BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, Bytes memory_limit, - const DeviceLocality& dev_locality, - TfGpuId tf_gpu_id, - const string& physical_device_desc, - Allocator* gpu_allocator, - Allocator* cpu_allocator) = 0; + std::vector>* devices); + + virtual std::unique_ptr CreateGPUDevice( + const SessionOptions& options, const string& name, Bytes memory_limit, + const DeviceLocality& dev_locality, TfGpuId tf_gpu_id, + const string& physical_device_desc, Allocator* gpu_allocator, + Allocator* cpu_allocator) = 0; // Returns into 'ids' the list of valid platform GPU ids, in the order that // they should map to TF GPU ids "/device:GPU:0", "/device:GPU:1", etc, diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc index e1aaf95df6..8dc7197329 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc @@ -59,15 +59,14 @@ class GPUDevice : public BaseGPUDevice { class GPUDeviceFactory : public BaseGPUDeviceFactory { private: - BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, Bytes memory_limit, - const DeviceLocality& locality, - TfGpuId tf_gpu_id, - const string& physical_device_desc, - Allocator* gpu_allocator, - Allocator* cpu_allocator) override { - return new GPUDevice(options, name, memory_limit, locality, tf_gpu_id, - physical_device_desc, gpu_allocator, cpu_allocator); + std::unique_ptr CreateGPUDevice( + const SessionOptions& options, const string& name, Bytes memory_limit, + const DeviceLocality& locality, TfGpuId tf_gpu_id, + const string& physical_device_desc, Allocator* gpu_allocator, + Allocator* cpu_allocator) override { + return absl::make_unique(options, name, memory_limit, locality, + tf_gpu_id, physical_device_desc, + gpu_allocator, cpu_allocator); } }; @@ -108,7 +107,7 @@ class GPUCompatibleCPUDevice : public ThreadPoolDevice { class GPUCompatibleCPUDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { int n = 1; auto iter = options.config.device_count().find("CPU"); if (iter != options.config.device_count().end()) { @@ -116,7 +115,7 @@ class GPUCompatibleCPUDeviceFactory : public DeviceFactory { } for (int i = 0; i < n; i++) { string name = strings::StrCat(name_prefix, "/device:CPU:", i); - devices->push_back(new GPUCompatibleCPUDevice( + devices->push_back(absl::make_unique( options, name, Bytes(256 << 20), DeviceLocality(), cpu_allocator())); } diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc b/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc index 75be6d60b8..58656ec757 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc @@ -33,7 +33,7 @@ namespace { TEST(GPUDeviceOnNonGPUMachineTest, CreateGPUDevicesOnNonGPUMachine) { SessionOptions opts; - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, "/job:localhost/replica:0/task:0", &devices)); EXPECT_TRUE(devices.empty()); diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_test.cc b/tensorflow/core/common_runtime/gpu/gpu_device_test.cc index 36294094e9..ae623b2adb 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_test.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_test.cc @@ -88,7 +88,7 @@ class GPUDeviceTest : public ::testing::Test { TEST_F(GPUDeviceTest, FailedToParseVisibleDeviceList) { SessionOptions opts = MakeSessionOptions("0,abc"); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -97,7 +97,7 @@ TEST_F(GPUDeviceTest, FailedToParseVisibleDeviceList) { TEST_F(GPUDeviceTest, InvalidGpuId) { SessionOptions opts = MakeSessionOptions("100"); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -107,7 +107,7 @@ TEST_F(GPUDeviceTest, InvalidGpuId) { TEST_F(GPUDeviceTest, DuplicateEntryInVisibleDeviceList) { SessionOptions opts = MakeSessionOptions("0,0"); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -117,7 +117,7 @@ TEST_F(GPUDeviceTest, DuplicateEntryInVisibleDeviceList) { TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithMemoryFractionSettings) { SessionOptions opts = MakeSessionOptions("0", 0.1, 1, {{}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -129,7 +129,7 @@ TEST_F(GPUDeviceTest, GpuDeviceCountTooSmall) { // device_count is 0, but with one entry in visible_device_list and one // (empty) VirtualDevices messages. SessionOptions opts = MakeSessionOptions("0", 0, 0, {{}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::UNKNOWN); @@ -141,7 +141,7 @@ TEST_F(GPUDeviceTest, NotEnoughGpuInVisibleDeviceList) { // Single entry in visible_device_list with two (empty) VirtualDevices // messages. SessionOptions opts = MakeSessionOptions("0", 0, 8, {{}, {}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::UNKNOWN); @@ -155,7 +155,7 @@ TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithVisibleDeviceList) { // Three entries in visible_device_list with two (empty) VirtualDevices // messages. SessionOptions opts = MakeSessionOptions("0,1", 0, 8, {{}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -169,39 +169,36 @@ TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithVisibleDeviceList) { TEST_F(GPUDeviceTest, EmptyVirtualDeviceConfig) { // It'll create single virtual device when the virtual device config is empty. SessionOptions opts = MakeSessionOptions("0"); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_GE(devices[0]->attributes().memory_limit(), 0); - gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, SingleVirtualDeviceWithNoMemoryLimit) { // It'll create single virtual device for the gpu in question when // memory_limit_mb is unset. SessionOptions opts = MakeSessionOptions("0", 0, 1, {{}}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_GE(devices[0]->attributes().memory_limit(), 0); - gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, SingleVirtualDeviceWithMemoryLimit) { SessionOptions opts = MakeSessionOptions("0", 0, 1, {{123}}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_EQ(123 << 20, devices[0]->attributes().memory_limit()); - gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, MultipleVirtualDevices) { SessionOptions opts = MakeSessionOptions("0", 0, 1, {{123, 456}}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(2, devices.size()); @@ -219,7 +216,6 @@ TEST_F(GPUDeviceTest, MultipleVirtualDevices) { devices[1]->attributes().locality().links().link(0).type()); EXPECT_EQ(BaseGPUDeviceFactory::InterconnectMap::kSameDeviceStrength, devices[1]->attributes().locality().links().link(0).strength()); - gtl::STLDeleteElements(&devices); } // Enabling unified memory on pre-Pascal GPUs results in an initialization @@ -236,7 +232,7 @@ TEST_F(GPUDeviceTest, UnifiedMemoryUnavailableOnPrePascalGpus) { opts.config.mutable_gpu_options() ->mutable_experimental() ->set_use_unified_memory(true); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INTERNAL); @@ -259,7 +255,7 @@ TEST_F(GPUDeviceTest, UnifiedMemoryAllocation) { } SessionOptions opts = MakeSessionOptions("0", kGpuMemoryFraction); - std::vector devices; + std::vector> devices; TF_ASSERT_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); ASSERT_EQ(1, devices.size()); @@ -278,8 +274,6 @@ TEST_F(GPUDeviceTest, UnifiedMemoryAllocation) { (memory_limit >> 20) << 20); EXPECT_NE(ptr, nullptr); allocator->DeallocateRaw(ptr); - - gtl::STLDeleteElements(&devices); } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc b/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc index 2144eea84f..f0656ff533 100644 --- a/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc +++ b/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/hierarchical_tree_broadcaster.h" #include +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/base_collective_executor.h" #include "tensorflow/core/common_runtime/collective_rma_local.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -217,7 +218,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { << " num_devices_per_worker=" << num_devices_per_worker; int total_num_devices = num_workers * num_devices_per_worker; device_type_ = device_type; - std::vector local_devices; + std::vector> local_devices; SessionOptions sess_opts; sess_opts.env = Env::Default(); Bytes mem_limit(4 << 20); @@ -227,7 +228,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { if (device_type == DEVICE_CPU) { string dev_name = strings::StrCat("/job:worker/replica:0/task:", wi, "/device:CPU:", di); - local_devices.push_back(new ThreadPoolDevice( + local_devices.push_back(absl::make_unique( sess_opts, dev_name, mem_limit, dev_locality, cpu_allocator())); } else if (device_type == DEVICE_GPU && !gpu_devices_.empty()) { int dev_idx = (wi * num_devices_per_worker) + di; @@ -235,7 +236,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { LOG(INFO) << "dev_mgr has access to limited GPUs, reusing for more " "than one ring node."; } else { - local_devices.push_back(gpu_devices_[dev_idx]); + local_devices.push_back(std::move(gpu_devices_[dev_idx])); } } else { LOG(FATAL) << "Unsupported device_type " << device_type; @@ -243,7 +244,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { } } if (!dev_mgr_ || device_type == DEVICE_CPU) { - dev_mgr_.reset(new DeviceMgr(local_devices)); + dev_mgr_.reset(new DeviceMgr(std::move(local_devices))); } if (!gpu_ring_order_) gpu_ring_order_.reset(new string()); dev_resolver_.reset(new DeviceResolverLocal(dev_mgr_.get())); @@ -714,7 +715,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { std::unique_ptr dev_resolver_; std::vector instances_; CollectiveParams col_params_; - std::vector gpu_devices_; + std::vector> gpu_devices_; std::unique_ptr dev_mgr_; std::unique_ptr gpu_ring_order_; mutex mu_; diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc index 1f585a8c24..bdd6c0e87d 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc @@ -75,12 +75,12 @@ Benchmark::Benchmark(const string& device, Graph* g, const int graph_def_version = g->versions().producer(); LocalExecutorParams params; - params.device = device_; + params.device = device_.get(); params.function_library = nullptr; params.create_kernel = [this, graph_def_version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_, nullptr, ndef, graph_def_version, - kernel); + return CreateNonCachedKernel(device_.get(), nullptr, ndef, + graph_def_version, kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -107,7 +107,7 @@ Benchmark::~Benchmark() { // run kernel destructors that may attempt to access state borrowed from // `device_`, such as the resource manager. exec_.reset(); - delete device_; + device_.reset(); delete pool_; } } diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.h b/tensorflow/core/common_runtime/kernel_benchmark_testlib.h index 555b43f655..b1557c50b0 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.h +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.h @@ -55,7 +55,7 @@ class Benchmark { private: thread::ThreadPool* pool_ = nullptr; - Device* device_ = nullptr; + std::unique_ptr device_ = nullptr; Rendezvous* rendez_ = nullptr; std::unique_ptr exec_; diff --git a/tensorflow/core/common_runtime/placer_test.cc b/tensorflow/core/common_runtime/placer_test.cc index 009f905f10..04e77e55f6 100644 --- a/tensorflow/core/common_runtime/placer_test.cc +++ b/tensorflow/core/common_runtime/placer_test.cc @@ -92,7 +92,7 @@ class FakeDevice : public Device { class DummyFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { return Status::OK(); } }; diff --git a/tensorflow/core/common_runtime/process_function_library_runtime_test.cc b/tensorflow/core/common_runtime/process_function_library_runtime_test.cc index cce2308011..21cb62118a 100644 --- a/tensorflow/core/common_runtime/process_function_library_runtime_test.cc +++ b/tensorflow/core/common_runtime/process_function_library_runtime_test.cc @@ -62,9 +62,12 @@ class ProcessFunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 2}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices(options, "/job:a/replica:0/task:0", - &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + &devices)); + device0_ = devices[0].get(); + device1_ = devices[1].get(); + device_mgr_.reset(new DeviceMgr(std::move(devices))); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); @@ -138,8 +141,9 @@ class ProcessFunctionLibraryRuntimeTest : public ::testing::Test { return Status::OK(); } - std::vector devices_; std::unique_ptr device_mgr_; + Device* device0_ = nullptr; // Not owned. (Owned by device_mgr_.) + Device* device1_ = nullptr; // Not owned. (Owned by device_mgr_.) std::unique_ptr lib_def_; std::unique_ptr cluster_flr_; std::unique_ptr proc_flr_; @@ -165,16 +169,16 @@ TEST_F(ProcessFunctionLibraryRuntimeTest, Basic) { FunctionLibraryRuntime* flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/cpu:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[0]); + EXPECT_EQ(flr->device(), device0_); flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/device:CPU:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[0]); + EXPECT_EQ(flr->device(), device0_); flr = proc_flr_->GetFLR("/device:CPU:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[0]); + EXPECT_EQ(flr->device(), device0_); flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/cpu:1"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[1]); + EXPECT_EQ(flr->device(), device1_); flr = proc_flr_->GetFLR("abc"); EXPECT_EQ(flr, nullptr); rendezvous_->Unref(); diff --git a/tensorflow/core/common_runtime/renamed_device.cc b/tensorflow/core/common_runtime/renamed_device.cc index 56766a8df4..45541c35fe 100644 --- a/tensorflow/core/common_runtime/renamed_device.cc +++ b/tensorflow/core/common_runtime/renamed_device.cc @@ -14,15 +14,14 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/common_runtime/renamed_device.h" +#include "absl/memory/memory.h" namespace tensorflow { -// TODO(saeta): Convert to returning a std::unique_ptr? /* static */ -Device* RenamedDevice::NewRenamedDevice(const string& new_base, - Device* underlying, - bool owns_underlying, - bool isolate_session_state) { +std::unique_ptr RenamedDevice::NewRenamedDevice( + const string& new_base, Device* underlying, bool owns_underlying, + bool isolate_session_state) { DeviceNameUtils::ParsedName parsed_name; CHECK(DeviceNameUtils::ParseFullName(new_base, &parsed_name)); DeviceNameUtils::ParsedName underlying_parsed_name = @@ -36,8 +35,9 @@ Device* RenamedDevice::NewRenamedDevice(const string& new_base, parsed_name.id); DeviceAttributes attributes(underlying->attributes()); attributes.set_name(name); - return new RenamedDevice(underlying, attributes, owns_underlying, - isolate_session_state); + // Call absl::WrapUnique to access private constructor. + return absl::WrapUnique(new RenamedDevice( + underlying, attributes, owns_underlying, isolate_session_state)); } RenamedDevice::RenamedDevice(Device* underlying, diff --git a/tensorflow/core/common_runtime/renamed_device.h b/tensorflow/core/common_runtime/renamed_device.h index c00789a556..6d24f496ff 100644 --- a/tensorflow/core/common_runtime/renamed_device.h +++ b/tensorflow/core/common_runtime/renamed_device.h @@ -28,9 +28,10 @@ namespace tensorflow { // session. class RenamedDevice : public Device { public: - static Device* NewRenamedDevice(const string& new_base, Device* underlying, - bool owns_underlying, - bool isolate_session_state); + static std::unique_ptr NewRenamedDevice(const string& new_base, + Device* underlying, + bool owns_underlying, + bool isolate_session_state); ~RenamedDevice() override; diff --git a/tensorflow/core/common_runtime/ring_reducer_test.cc b/tensorflow/core/common_runtime/ring_reducer_test.cc index a271bf7b74..7feb29a6db 100644 --- a/tensorflow/core/common_runtime/ring_reducer_test.cc +++ b/tensorflow/core/common_runtime/ring_reducer_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/ring_reducer.h" #include +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/base_collective_executor.h" #include "tensorflow/core/common_runtime/collective_rma_local.h" #include "tensorflow/core/common_runtime/device.h" @@ -157,7 +158,7 @@ class RingReducerTest : public ::testing::Test { InitGPUDevices(); #endif device_type_ = device_type; - std::vector local_devices; + std::vector> local_devices; SessionOptions sess_opts; sess_opts.env = Env::Default(); Bytes mem_limit(4 << 20); @@ -167,7 +168,7 @@ class RingReducerTest : public ::testing::Test { if (device_type == DEVICE_CPU) { string dev_name = strings::StrCat("/job:worker/replica:0/task:", wi, "/cpu:", di); - local_devices.push_back(new ThreadPoolDevice( + local_devices.push_back(absl::make_unique( sess_opts, dev_name, mem_limit, dev_locality, cpu_allocator())); } else if (device_type == DEVICE_GPU && !gpu_devices_.empty()) { int dev_idx = (wi * num_devices) + di; @@ -175,7 +176,7 @@ class RingReducerTest : public ::testing::Test { LOG(INFO) << "dev_mgr has access to limited GPUs, reusing for more " "than one ring node."; } else { - local_devices.push_back(gpu_devices_[dev_idx]); + local_devices.push_back(std::move(gpu_devices_[dev_idx])); } } else { LOG(FATAL) << "Unsupported device_type " << device_type; @@ -185,7 +186,7 @@ class RingReducerTest : public ::testing::Test { if (!dev_mgr_ || device_type == DEVICE_CPU) { LOG(ERROR) << "resetting dev_mgr for " << local_devices.size() << " devices: "; - dev_mgr_.reset(new DeviceMgr(local_devices)); + dev_mgr_.reset(new DeviceMgr(std::move(local_devices))); } if (!gpu_ring_order_) gpu_ring_order_.reset(new string()); dev_resolver_.reset(new DeviceResolverLocal(dev_mgr_.get())); @@ -544,7 +545,7 @@ class RingReducerTest : public ::testing::Test { std::unique_ptr dev_resolver_; std::vector instances_; CollectiveParams col_params_; - std::vector gpu_devices_; + std::vector> gpu_devices_; std::unique_ptr dev_mgr_; std::unique_ptr gpu_ring_order_; mutex mu_; diff --git a/tensorflow/core/common_runtime/threadpool_device_factory.cc b/tensorflow/core/common_runtime/threadpool_device_factory.cc index c06a4035a7..f9cbb81749 100644 --- a/tensorflow/core/common_runtime/threadpool_device_factory.cc +++ b/tensorflow/core/common_runtime/threadpool_device_factory.cc @@ -13,12 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -// Register a factory that provides CPU devices. -#include "tensorflow/core/common_runtime/threadpool_device.h" - #include + +// Register a factory that provides CPU devices. +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/common_runtime/process_state.h" +#include "tensorflow/core/common_runtime/threadpool_device.h" #include "tensorflow/core/framework/allocator.h" #include "tensorflow/core/platform/numa.h" #include "tensorflow/core/public/session_options.h" @@ -29,7 +30,7 @@ namespace tensorflow { class ThreadPoolDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { int num_numa_nodes = port::NUMANumNodes(); int n = 1; auto iter = options.config.device_count().find("CPU"); @@ -38,7 +39,7 @@ class ThreadPoolDeviceFactory : public DeviceFactory { } for (int i = 0; i < n; i++) { string name = strings::StrCat(name_prefix, "/device:CPU:", i); - ThreadPoolDevice* tpd = nullptr; + std::unique_ptr tpd; if (options.config.experimental().use_numa_affinity()) { int numa_node = i % num_numa_nodes; if (numa_node != i) { @@ -49,15 +50,15 @@ class ThreadPoolDeviceFactory : public DeviceFactory { } DeviceLocality dev_locality; dev_locality.set_numa_node(numa_node); - tpd = new ThreadPoolDevice( + tpd = absl::make_unique( options, name, Bytes(256 << 20), dev_locality, ProcessState::singleton()->GetCPUAllocator(numa_node)); } else { - tpd = new ThreadPoolDevice( + tpd = absl::make_unique( options, name, Bytes(256 << 20), DeviceLocality(), ProcessState::singleton()->GetCPUAllocator(port::kNUMANoAffinity)); } - devices->push_back(tpd); + devices->push_back(std::move(tpd)); } return Status::OK(); diff --git a/tensorflow/core/distributed_runtime/BUILD b/tensorflow/core/distributed_runtime/BUILD index 818324746f..a47da0d6a0 100644 --- a/tensorflow/core/distributed_runtime/BUILD +++ b/tensorflow/core/distributed_runtime/BUILD @@ -624,6 +624,7 @@ tf_cc_test( "//tensorflow/core:test", "//tensorflow/core:test_main", "//tensorflow/core:testlib", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc b/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc index 4eed856759..40b18d321a 100644 --- a/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc @@ -29,7 +29,8 @@ limitations under the License. namespace tensorflow { namespace { -static Device* NewDevice(const string& type, const string& name) { +static std::unique_ptr NewDevice(const string& type, + const string& name) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -40,7 +41,7 @@ static Device* NewDevice(const string& type, const string& name) { attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(3); // a non-default value - return new FakeDevice(attr); + return absl::make_unique(attr); } class FakeWorker : public TestWorkerInterface { @@ -156,16 +157,16 @@ class DeviceResDistTest : public ::testing::Test { void DefineWorker(const ConfigProto& config, const string& worker_name, const string& device_type, int num_devices) { - std::vector devices; + std::vector> devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i))); } - DeviceMgr* dev_mgr = new DeviceMgr(devices); + DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : devices) { + for (auto* d : dev_mgr->ListDevices()) { dv->push_back(d->name()); } DeviceResolverDistributed* dev_res = diff --git a/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc b/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc index 33e1c8f2c3..26f722a6bd 100644 --- a/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc @@ -41,7 +41,8 @@ limitations under the License. namespace tensorflow { namespace { -static Device* NewDevice(const string& type, const string& name) { +static std::unique_ptr NewDevice(const string& type, + const string& name) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -52,7 +53,7 @@ static Device* NewDevice(const string& type, const string& name) { attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(3); // a non-default value - return new FakeDevice(attr); + return absl::make_unique(attr); } static int64 kStepId = 123; @@ -211,16 +212,16 @@ class CollRMADistTest : public ::testing::Test { void DefineWorker(const ConfigProto& config, const string& worker_name, const string& device_type, int num_devices) { - std::vector devices; + std::vector> devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i))); } - DeviceMgr* dev_mgr = new DeviceMgr(devices); + DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : devices) { + for (auto d : dev_mgr->ListDevices()) { dv->push_back(d->name()); } DeviceResolverDistributed* dev_res = diff --git a/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc b/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc index ae44b98bd5..842a2b3b05 100644 --- a/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/distributed_runtime/device_resolver_distributed.h" +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/distributed_runtime/test_utils.h" #include "tensorflow/core/lib/core/notification.h" @@ -41,8 +42,8 @@ class TestableDeviceResolverDistributed : public DeviceResolverDistributed { // Create a fake 'Device' whose only interesting attribute is a non-default // DeviceLocality. -static Device* NewDevice(const string& type, const string& name, - int numa_node) { +static std::unique_ptr NewDevice(const string& type, const string& name, + int numa_node) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -53,7 +54,7 @@ static Device* NewDevice(const string& type, const string& name, attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(numa_node); - return new FakeDevice(attr); + return absl::make_unique(attr); } // Create a fake WorkerInterface that responds to requests without RPCs, @@ -151,19 +152,19 @@ class DeviceResDistTest : public ::testing::Test { void DefineWorker(const string& worker_name, const string& device_type, int num_devices) { - std::vector devices; + std::vector> devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i), i)); } - DeviceMgr* dev_mgr = new DeviceMgr(devices); + DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); TestableDeviceResolverDistributed* dev_res = new TestableDeviceResolverDistributed(dev_mgr, &wc_, worker_name); resolvers_[worker_name] = dev_res; device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : devices) { + for (auto* d : dev_mgr->ListDevices()) { dv->push_back(d->name()); } FakeWorker* fw = new FakeWorker(worker_name, dev_mgr, dev_res); diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc index 5b0a420fad..c66466c0a6 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc @@ -87,7 +87,7 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, return tensorflow::errors::Internal( "invalid eager env_ or env_->rendezvous_mgr."); } - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(tensorflow::DeviceFactory::AddDevices( // TODO(nareshmodi): Correctly set the SessionOptions. @@ -97,12 +97,12 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, request->server_def().task_index()), &devices)); response->mutable_device_attributes()->Reserve(devices.size()); - for (auto& d : devices) { + for (const auto& d : devices) { *response->add_device_attributes() = d->attributes(); } std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(devices)); + new tensorflow::DeviceMgr(std::move(devices))); auto* r = env_->rendezvous_mgr->Find(request->rendezvous_id()); auto session_name = strings::StrCat("eager_", request->rendezvous_id()); diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc index 5ba522c2a2..7a1463e8f0 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc @@ -68,12 +68,9 @@ class EagerServiceImplTest : public ::testing::Test { worker_env_.rendezvous_mgr = &rendezvous_mgr_; worker_env_.session_mgr = session_mgr_.get(); - Device* device = DeviceFactory::NewDevice( - "CPU", {}, "/job:localhost/replica:0/task:0/device:CPU:0"); - - worker_env_.local_devices = {device}; - - device_mgr_.reset(new DeviceMgr(worker_env_.local_devices)); + device_mgr_ = absl::make_unique(DeviceFactory::NewDevice( + "CPU", {}, "/job:localhost/replica:0/task:0/device:CPU:0")); + worker_env_.local_devices = device_mgr_->ListDevices(); worker_env_.device_mgr = device_mgr_.get(); } diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc index ae722fdfe9..cbd5cd927e 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include #include +#include #include "grpc/support/alloc.h" #include "grpcpp/grpcpp.h" @@ -156,10 +157,12 @@ Status GrpcServer::Init( string name_prefix = strings::StrCat("/job:", server_def_.job_name(), "/replica:0", "/task:", server_def_.task_index()); - TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(sess_opts, name_prefix, - &master_env_.local_devices)); - worker_env_.local_devices = master_env_.local_devices; - worker_env_.device_mgr = new DeviceMgr(worker_env_.local_devices); + std::vector> devices; + TF_RETURN_IF_ERROR( + DeviceFactory::AddDevices(sess_opts, name_prefix, &devices)); + worker_env_.device_mgr = new DeviceMgr(std::move(devices)); + master_env_.local_devices = worker_env_.device_mgr->ListDevices(); + worker_env_.local_devices = worker_env_.device_mgr->ListDevices(); worker_env_.rendezvous_mgr = rendezvous_mgr_func == nullptr ? new RpcRendezvousMgr(&worker_env_) : rendezvous_mgr_func(&worker_env_); diff --git a/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc b/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc index 0323300fdd..1c87fe9d92 100644 --- a/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc +++ b/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc @@ -42,8 +42,9 @@ class RpcCollectiveExecutorMgrTest : public ::testing::Test { WorkerCacheInterface* worker_cache = nullptr; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); std::unique_ptr dr(new DeviceResolverDistributed( device_mgr_.get(), worker_cache, task_name)); std::unique_ptr cpr( @@ -57,7 +58,6 @@ class RpcCollectiveExecutorMgrTest : public ::testing::Test { } std::unique_ptr cme_; - std::vector devices_; std::unique_ptr device_mgr_; }; diff --git a/tensorflow/core/distributed_runtime/session_mgr.cc b/tensorflow/core/distributed_runtime/session_mgr.cc index 38833bd202..29fe767e42 100644 --- a/tensorflow/core/distributed_runtime/session_mgr.cc +++ b/tensorflow/core/distributed_runtime/session_mgr.cc @@ -78,13 +78,13 @@ Status SessionMgr::CreateSession(const string& session, if (isolate_session_state) { // Create a private copy of the DeviceMgr for the WorkerSession. - std::vector renamed_devices; + std::vector> renamed_devices; for (Device* d : worker_env_->local_devices) { renamed_devices.push_back(RenamedDevice::NewRenamedDevice( worker_name, d, false, isolate_session_state)); } - auto device_mgr = MakeUnique(renamed_devices); + auto device_mgr = MakeUnique(std::move(renamed_devices)); auto graph_mgr = MakeUnique(worker_env_, device_mgr.get()); worker_session.reset( new WorkerSession(session, worker_name, diff --git a/tensorflow/core/distributed_runtime/session_mgr_test.cc b/tensorflow/core/distributed_runtime/session_mgr_test.cc index 99192119a6..1ab0d20f0b 100644 --- a/tensorflow/core/distributed_runtime/session_mgr_test.cc +++ b/tensorflow/core/distributed_runtime/session_mgr_test.cc @@ -46,11 +46,9 @@ class SessionMgrTest : public ::testing::Test { SessionMgrTest() : mgr_(&env_, "/job:mnist/replica:0/task:0", std::unique_ptr(), factory_) { - Device* device = - FakeDevice::MakeCPU("/job:mnist/replica:0/task:0/device:fakecpu:0") - .release(); - env_.local_devices = {device}; - device_mgr_.reset(new DeviceMgr(env_.local_devices)); + device_mgr_ = absl::make_unique( + FakeDevice::MakeCPU("/job:mnist/replica:0/task:0/device:fakecpu:0")); + env_.local_devices = device_mgr_->ListDevices(); env_.device_mgr = device_mgr_.get(); } diff --git a/tensorflow/core/grappler/grappler_item_builder.cc b/tensorflow/core/grappler/grappler_item_builder.cc index cf99f4908b..e69dfa79d1 100644 --- a/tensorflow/core/grappler/grappler_item_builder.cc +++ b/tensorflow/core/grappler/grappler_item_builder.cc @@ -102,10 +102,11 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, } // Instantiate all variables for function library runtime creation. - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); - std::unique_ptr dvc_mgr(new DeviceMgr(devices)); + Device* cpu_device = devices[0].get(); + std::unique_ptr dvc_mgr(new DeviceMgr(std::move(devices))); FunctionLibraryDefinition function_library(OpRegistry::Global(), graph_def.library()); Env* env = Env::Default(); @@ -124,7 +125,7 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, new ProcessFunctionLibraryRuntime(dvc_mgr.get(), env, graph_def.versions().producer(), &function_library, *optimizer_opts)); - FunctionLibraryRuntime* flr = pflr->GetFLR(devices[0]->name()); + FunctionLibraryRuntime* flr = pflr->GetFLR(cpu_device->name()); // Create the GraphOptimizer to optimize the graph def. GraphConstructorOptions graph_ctor_opts; @@ -137,7 +138,7 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, // Optimize the graph. ::tensorflow::GraphOptimizer optimizer(*optimizer_opts); - optimizer.Optimize(flr, env, devices[0], &graphptr, /*shape_map=*/nullptr); + optimizer.Optimize(flr, env, cpu_device, &graphptr, /*shape_map=*/nullptr); graphptr->ToGraphDef(output_graph_def); // The default values of attributes might have been stripped by the optimizer. diff --git a/tensorflow/core/grappler/optimizers/BUILD b/tensorflow/core/grappler/optimizers/BUILD index b6f989f2c9..8e6629565a 100644 --- a/tensorflow/core/grappler/optimizers/BUILD +++ b/tensorflow/core/grappler/optimizers/BUILD @@ -142,7 +142,6 @@ cc_library( ":graph_optimizer", "//tensorflow/core:core_cpu_base", "//tensorflow/core:framework", - "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler:grappler_item", @@ -150,6 +149,7 @@ cc_library( "//tensorflow/core/grappler:op_types", "//tensorflow/core/grappler:utils", "//tensorflow/core/grappler/utils:functions", + "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/core/grappler/optimizers/function_optimizer.cc b/tensorflow/core/grappler/optimizers/function_optimizer.cc index f99826ddca..f8ddbeb659 100644 --- a/tensorflow/core/grappler/optimizers/function_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/function_optimizer.cc @@ -16,7 +16,9 @@ limitations under the License. #include "tensorflow/core/grappler/optimizers/function_optimizer.h" #include +#include +#include "absl/memory/memory.h" #include "absl/strings/str_replace.h" #include "absl/strings/substitute.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -343,14 +345,15 @@ class FunctionOptimizerContext { DeviceAttributes attr; attr.set_name("/device:CPU:0"); attr.set_device_type("CPU"); - Device* device = new FakeCPUDevice(env, attr); - device_mgr_.reset(new DeviceMgr({device})); + std::vector> devices; + devices.push_back(absl::make_unique(env, attr)); + device_mgr_ = absl::make_unique(std::move(devices)); OptimizerOptions optimizer_opts; optimizer_opts.set_do_function_inlining(true); process_flr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), env, graph_version_, &function_library_, optimizer_opts)); - flr_ = process_flr_->GetFLR(device->name()); + flr_ = process_flr_->GetFLR(device_mgr_->ListDevices()[0]->name()); } } diff --git a/tensorflow/core/kernels/data/BUILD b/tensorflow/core/kernels/data/BUILD index 7192684e2d..dcb6975669 100644 --- a/tensorflow/core/kernels/data/BUILD +++ b/tensorflow/core/kernels/data/BUILD @@ -600,6 +600,7 @@ tf_kernel_library( "//tensorflow/core:protos_all_cc", "//tensorflow/core:session_options", "//tensorflow/core/kernels:ops_util", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/kernels/data/iterator_ops.cc b/tensorflow/core/kernels/data/iterator_ops.cc index 93999dc095..98b67454d5 100644 --- a/tensorflow/core/kernels/data/iterator_ops.cc +++ b/tensorflow/core/kernels/data/iterator_ops.cc @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/kernels/data/iterator_ops.h" +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/graph_runner.h" #include "tensorflow/core/common_runtime/renamed_device.h" #include "tensorflow/core/common_runtime/threadpool_device.h" @@ -545,10 +546,9 @@ FunctionLibraryRuntime* IteratorHandleOp::CreatePrivateFLR( // in its resource manager. The existing device will outlive the // IteratorResource, because we are storing the IteratorResource // in that device's resource manager. - Device* wrapped_device = RenamedDevice::NewRenamedDevice( + *device_mgr = absl::make_unique(RenamedDevice::NewRenamedDevice( ctx->device()->name(), down_cast(ctx->device()), - false /* owns_underlying */, false /* isolate_session_state */); - device_mgr->reset(new DeviceMgr({wrapped_device})); + false /* owns_underlying */, false /* isolate_session_state */)); flib_def->reset(new FunctionLibraryDefinition( *ctx->function_library()->GetFunctionLibraryDefinition())); pflr->reset(new ProcessFunctionLibraryRuntime( diff --git a/tensorflow/core/kernels/data/single_threaded_executor_test.cc b/tensorflow/core/kernels/data/single_threaded_executor_test.cc index 6244e287bb..7bb51fb8b5 100644 --- a/tensorflow/core/kernels/data/single_threaded_executor_test.cc +++ b/tensorflow/core/kernels/data/single_threaded_executor_test.cc @@ -51,17 +51,17 @@ class ExecutorTest : public ::testing::Test { // when the test completes. CHECK(rendez_->Unref()); delete exec_; - delete device_; } // Resets executor_ with a new executor based on a graph 'gdef'. void Create(std::unique_ptr graph) { const int version = graph->versions().producer(); LocalExecutorParams params; - params.device = device_; + params.device = device_.get(); params.create_kernel = [this, version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_, nullptr, ndef, version, kernel); + return CreateNonCachedKernel(device_.get(), nullptr, ndef, version, + kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -86,7 +86,7 @@ class ExecutorTest : public ::testing::Test { return exec_->Run(args); } - Device* device_ = nullptr; + std::unique_ptr device_; Executor* exec_ = nullptr; Executor::Args::Runner runner_; Rendezvous* rendez_ = nullptr; diff --git a/tensorflow/lite/delegates/flex/BUILD b/tensorflow/lite/delegates/flex/BUILD index 222a043a88..63e86899da 100644 --- a/tensorflow/lite/delegates/flex/BUILD +++ b/tensorflow/lite/delegates/flex/BUILD @@ -116,6 +116,7 @@ cc_library( hdrs = ["delegate_data.h"], deps = [ ":buffer_map", + "@com_google_absl//absl/memory", "//tensorflow/core/common_runtime/eager:context", ] + select({ "//tensorflow:android": [ diff --git a/tensorflow/lite/delegates/flex/delegate_data.cc b/tensorflow/lite/delegates/flex/delegate_data.cc index b62479a448..1483a53038 100644 --- a/tensorflow/lite/delegates/flex/delegate_data.cc +++ b/tensorflow/lite/delegates/flex/delegate_data.cc @@ -14,20 +14,21 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/lite/delegates/flex/delegate_data.h" +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/lib/core/status.h" namespace tflite { namespace flex { tensorflow::Status DelegateData::Create(std::unique_ptr* data) { - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(tensorflow::DeviceFactory::AddDevices( tensorflow::SessionOptions(), "/job:localhost/replica:0/task:0", &devices)); - std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(devices)); + std::unique_ptr device_mgr = + absl::make_unique(std::move(devices)); // Note that Rendezvous is ref-counted so it will be automatically deleted. tensorflow::Rendezvous* rendezvous = new tensorflow::IntraProcessRendezvous(device_mgr.get()); diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index 4c3a0717e7..dfeaebca26 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -2012,13 +2012,13 @@ bool InlineAllFunctions(GraphDef* graphdef) { tensorflow::SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 1}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(tensorflow::DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); tensorflow::FunctionLibraryDefinition fld(tensorflow::OpRegistry::Global(), graphdef_copy.library()); - tensorflow::DeviceMgr device_mgr(devices); + tensorflow::DeviceMgr device_mgr(std::move(devices)); tensorflow::OptimizerOptions o_opts; tensorflow::ProcessFunctionLibraryRuntime pflr( &device_mgr, tensorflow::Env::Default(), TF_GRAPH_DEF_VERSION, &fld, diff --git a/tensorflow/python/client/device_lib.i b/tensorflow/python/client/device_lib.i index 944e855cee..3e579152d5 100644 --- a/tensorflow/python/client/device_lib.i +++ b/tensorflow/python/client/device_lib.i @@ -48,17 +48,14 @@ static std::vector ListDevicesWithSessionConfig( std::vector output; SessionOptions options; options.config = config; - std::vector devices; + std::vector> devices; Status status = DeviceFactory::AddDevices( options, "" /* name_prefix */, &devices); if (!status.ok()) { Set_TF_Status_from_Status(out_status, status); } - std::vector> device_holder(devices.begin(), - devices.end()); - - for (const Device* device : devices) { + for (const std::unique_ptr& device : devices) { const DeviceAttributes& attr = device->attributes(); string attr_serialized; if (!attr.SerializeToString(&attr_serialized)) { diff --git a/tensorflow/python/grappler/tf_optimizer.i b/tensorflow/python/grappler/tf_optimizer.i index daa5bc9444..b746c3ec26 100644 --- a/tensorflow/python/grappler/tf_optimizer.i +++ b/tensorflow/python/grappler/tf_optimizer.i @@ -74,13 +74,13 @@ limitations under the License. void DetectDevices(std::unordered_map* device_map) { tensorflow::SessionOptions options; - std::vector devices; + std::vector> devices; tensorflow::Status status = tensorflow::DeviceFactory::AddDevices(options, "", &devices); if (!status.ok()) { return; } - for (const tensorflow::Device* device : devices) { + for (const std::unique_ptr& device : devices) { tensorflow::DeviceProperties& prop = (*device_map)[device->name()]; prop = tensorflow::grappler::GetDeviceInfo(device->parsed_name()); @@ -88,7 +88,6 @@ void DetectDevices(std::unordered_map* dev // available device memory. const tensorflow::DeviceAttributes& attr = device->attributes(); prop.set_memory_size(attr.memory_limit()); - delete device; } } -- GitLab From 50e5b015be1ead47f170013a640bf3028bb0560f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 23 Nov 2018 14:53:40 -0800 Subject: [PATCH 274/672] Automated rollback of commit 809ed3c835403564333bfdc06fca512432db4ca1 PiperOrigin-RevId: 222646553 --- tensorflow/c/eager/BUILD | 1 - tensorflow/c/eager/c_api.cc | 11 +++--- .../compiler/jit/build_xla_ops_pass_test.cc | 8 +++- .../compiler/jit/create_xla_launch_op_test.cc | 6 +-- .../mark_for_compilation_pass_test_helper.cc | 8 +++- .../jit/partially_decluster_pass_test.cc | 6 ++- tensorflow/compiler/jit/xla_cpu_device.cc | 11 +++--- tensorflow/compiler/jit/xla_gpu_device.cc | 10 ++--- .../compiler/jit/xla_interpreter_device.cc | 7 ++-- tensorflow/compiler/tf2xla/xla_compiler.cc | 2 +- tensorflow/core/BUILD | 4 -- .../collective_executor_mgr_test.cc | 6 +-- .../collective_param_resolver_local_test.cc | 6 +-- .../collective_rma_local_test.cc | 6 +-- .../core/common_runtime/device_factory.cc | 17 ++++----- .../core/common_runtime/device_factory.h | 13 +++---- tensorflow/core/common_runtime/device_mgr.cc | 37 ++++++++----------- tensorflow/core/common_runtime/device_mgr.h | 15 ++++---- .../device_resolver_local_test.cc | 6 +-- .../core/common_runtime/device_set_test.cc | 2 +- .../core/common_runtime/direct_session.cc | 4 +- tensorflow/core/common_runtime/eager/BUILD | 1 - .../eager/kernel_and_device_test.cc | 14 +++---- .../core/common_runtime/executor_test.cc | 8 ++-- .../core/common_runtime/function_test.cc | 7 ++-- .../function_threadpool_test.cc | 6 +-- .../core/common_runtime/gpu/gpu_device.cc | 20 +++++----- .../core/common_runtime/gpu/gpu_device.h | 18 +++++---- .../common_runtime/gpu/gpu_device_factory.cc | 21 ++++++----- .../gpu/gpu_device_on_non_gpu_machine_test.cc | 2 +- .../common_runtime/gpu/gpu_device_test.cc | 32 +++++++++------- .../hierarchical_tree_broadcaster_test.cc | 11 +++--- .../kernel_benchmark_testlib.cc | 8 ++-- .../common_runtime/kernel_benchmark_testlib.h | 2 +- tensorflow/core/common_runtime/placer_test.cc | 2 +- .../process_function_library_runtime_test.cc | 18 ++++----- .../core/common_runtime/renamed_device.cc | 14 +++---- .../core/common_runtime/renamed_device.h | 7 ++-- .../core/common_runtime/ring_reducer_test.cc | 11 +++--- .../threadpool_device_factory.cc | 17 ++++----- tensorflow/core/distributed_runtime/BUILD | 1 - ...lective_param_resolver_distributed_test.cc | 11 +++--- .../collective_rma_distributed_test.cc | 11 +++--- .../device_resolver_distributed_test.cc | 13 +++---- .../eager/eager_service_impl.cc | 6 +-- .../eager/eager_service_impl_test.cc | 9 +++-- .../rpc/grpc_server_lib.cc | 11 ++---- .../rpc_collective_executor_mgr_test.cc | 6 +-- .../core/distributed_runtime/session_mgr.cc | 4 +- .../distributed_runtime/session_mgr_test.cc | 8 ++-- .../core/grappler/grappler_item_builder.cc | 9 ++--- tensorflow/core/grappler/optimizers/BUILD | 2 +- .../grappler/optimizers/function_optimizer.cc | 9 ++--- tensorflow/core/kernels/data/BUILD | 1 - tensorflow/core/kernels/data/iterator_ops.cc | 6 +-- .../data/single_threaded_executor_test.cc | 8 ++-- tensorflow/lite/delegates/flex/BUILD | 1 - .../lite/delegates/flex/delegate_data.cc | 7 ++-- tensorflow/lite/toco/import_tensorflow.cc | 4 +- tensorflow/python/client/device_lib.i | 7 +++- tensorflow/python/grappler/tf_optimizer.i | 5 ++- 61 files changed, 271 insertions(+), 273 deletions(-) diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD index 5a0988ed31..ba3d8533db 100644 --- a/tensorflow/c/eager/BUILD +++ b/tensorflow/c/eager/BUILD @@ -50,7 +50,6 @@ tf_cuda_library( ], "//conditions:default": [], }) + [ - "@com_google_absl//absl/memory", "//tensorflow/core/common_runtime/eager:eager_operation", "//tensorflow/core/distributed_runtime/eager:eager_client", "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client", diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index c9e730ef41..192044915f 100755 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -21,7 +21,6 @@ limitations under the License. #include #include -#include "absl/memory/memory.h" #include "tensorflow/c/c_api.h" #include "tensorflow/c/c_api_internal.h" #include "tensorflow/c/eager/c_api_internal.h" @@ -81,7 +80,7 @@ tensorflow::Status GetAllRemoteDevices( const std::vector& remote_workers, tensorflow::WorkerCacheInterface* worker_cache, std::unique_ptr* device_mgr) { - std::vector> remote_devices; + std::vector remote_devices; tensorflow::Status status; // TODO(nareshmodi) do this in parallel instead of serially. for (const string& remote_worker : remote_workers) { @@ -94,7 +93,7 @@ tensorflow::Status GetAllRemoteDevices( status = s; if (s.ok()) { for (tensorflow::Device* d : *devices) { - remote_devices.emplace_back(d); + remote_devices.push_back(d); } } n.Notify(); @@ -102,7 +101,7 @@ tensorflow::Status GetAllRemoteDevices( n.WaitForNotification(); } std::unique_ptr remote_device_mgr( - new tensorflow::DeviceMgr(std::move(remote_devices))); + new tensorflow::DeviceMgr(remote_devices)); TF_RETURN_IF_ERROR(status); @@ -263,13 +262,13 @@ TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx, void TFE_DeleteContextOptions(TFE_ContextOptions* options) { delete options; } TFE_Context* TFE_NewContext(const TFE_ContextOptions* opts, TF_Status* status) { - std::vector> devices; + std::vector devices; status->status = tensorflow::DeviceFactory::AddDevices( opts->session_options.options, "/job:localhost/replica:0/task:0", &devices); if (!status->status.ok()) return nullptr; std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(std::move(devices))); + new tensorflow::DeviceMgr(devices)); tensorflow::Rendezvous* r = new tensorflow::IntraProcessRendezvous(device_mgr.get()); diff --git a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc index 48a23a4c17..11df946cc1 100644 --- a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc +++ b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc @@ -42,8 +42,14 @@ class BuildXlaOpsTest : public ::testing::Test { .ok()); } + void TearDown() override { + for (Device* device : devices_) { + delete device; + } + } + private: - std::vector> devices_; + std::vector devices_; }; using ::tensorflow::testing::FindNodeByName; diff --git a/tensorflow/compiler/jit/create_xla_launch_op_test.cc b/tensorflow/compiler/jit/create_xla_launch_op_test.cc index 0f872a480f..7386660762 100644 --- a/tensorflow/compiler/jit/create_xla_launch_op_test.cc +++ b/tensorflow/compiler/jit/create_xla_launch_op_test.cc @@ -59,9 +59,8 @@ class CreateXlaLaunchOpTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 1}); - std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices)); + options, "/job:localhost/replica:0/task:0", &devices_)); FunctionDefLibrary proto; for (const auto& fdef : flib) { @@ -70,7 +69,7 @@ class CreateXlaLaunchOpTest : public ::testing::Test { lib_def_ = absl::make_unique( OpRegistry::Global(), proto); OptimizerOptions opts; - device_mgr_ = absl::make_unique(std::move(devices)); + device_mgr_ = absl::make_unique(devices_); pflr_ = absl::make_unique( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, /*default_thread_pool=*/nullptr, /*cluster_flr=*/nullptr); @@ -78,6 +77,7 @@ class CreateXlaLaunchOpTest : public ::testing::Test { } FunctionLibraryRuntime* flr_; + std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc index 64a3301745..d56d0f8ccf 100644 --- a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc +++ b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc @@ -34,9 +34,15 @@ namespace tensorflow { // // It may be worth refactoring out XlaOpRegistry::RegisterCompilationDevice to // make this more direct, but probably not worth it solely for this test. - std::vector> devices; + std::vector devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(*session_options, "", &devices)); + auto delete_devices = gtl::MakeCleanup([&] { + for (Device* d : devices) { + delete d; + } + }); + GraphOptimizationPassOptions opt_options; opt_options.graph = graph; opt_options.session_options = session_options; diff --git a/tensorflow/compiler/jit/partially_decluster_pass_test.cc b/tensorflow/compiler/jit/partially_decluster_pass_test.cc index 38a54cc5ef..1fc5da5071 100644 --- a/tensorflow/compiler/jit/partially_decluster_pass_test.cc +++ b/tensorflow/compiler/jit/partially_decluster_pass_test.cc @@ -386,7 +386,7 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) { TF_ASSERT_OK(s.ToGraph(graph.get())); // This is needed to register the XLA_GPU device. - std::vector> devices; + std::vector devices; TF_ASSERT_OK(DeviceFactory::AddDevices( SessionOptions(), "/job:localhost/replica:0/task:0", &devices)); @@ -400,6 +400,10 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) { TF_ASSERT_OK(PartiallyDecluster(&graph)); EXPECT_EQ(GetXlaClusterForNode(*n), "cluster_0"); + + for (Device* d : devices) { + delete d; + } } TEST(PartiallyDeclusterPassTest, DontDeclusterNonTensorFlowOps) { diff --git a/tensorflow/compiler/jit/xla_cpu_device.cc b/tensorflow/compiler/jit/xla_cpu_device.cc index 7df898ad12..9006dd514b 100644 --- a/tensorflow/compiler/jit/xla_cpu_device.cc +++ b/tensorflow/compiler/jit/xla_cpu_device.cc @@ -31,12 +31,12 @@ namespace tensorflow { class XlaCpuDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override; + std::vector* devices) override; }; -Status XlaCpuDeviceFactory::CreateDevices( - const SessionOptions& session_options, const string& name_prefix, - std::vector>* devices) { +Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options, + const string& name_prefix, + std::vector* devices) { XlaDeviceFlags* flags = GetXlaDeviceFlags(); bool compile_on_demand = flags->tf_xla_compile_on_demand; @@ -63,7 +63,8 @@ Status XlaCpuDeviceFactory::CreateDevices( options.device_ordinal = 0; options.compilation_device_name = DEVICE_CPU_XLA_JIT; options.use_multiple_streams = false; - devices->push_back(absl::make_unique(session_options, options)); + auto device = absl::make_unique(session_options, options); + devices->push_back(device.release()); return Status::OK(); } diff --git a/tensorflow/compiler/jit/xla_gpu_device.cc b/tensorflow/compiler/jit/xla_gpu_device.cc index 944f732b99..4419701695 100644 --- a/tensorflow/compiler/jit/xla_gpu_device.cc +++ b/tensorflow/compiler/jit/xla_gpu_device.cc @@ -29,12 +29,12 @@ namespace tensorflow { class XlaGpuDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override; + std::vector* devices) override; }; -Status XlaGpuDeviceFactory::CreateDevices( - const SessionOptions& session_options, const string& name_prefix, - std::vector>* devices) { +Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options, + const string& name_prefix, + std::vector* devices) { XlaOpRegistry::DeviceRegistration registration; registration.compilation_device_name = DEVICE_GPU_XLA_JIT; registration.autoclustering_policy = @@ -70,7 +70,7 @@ Status XlaGpuDeviceFactory::CreateDevices( return status; } - devices->push_back(std::move(device)); + devices->push_back(device.release()); } return Status::OK(); } diff --git a/tensorflow/compiler/jit/xla_interpreter_device.cc b/tensorflow/compiler/jit/xla_interpreter_device.cc index 4007309ed1..e828bae865 100644 --- a/tensorflow/compiler/jit/xla_interpreter_device.cc +++ b/tensorflow/compiler/jit/xla_interpreter_device.cc @@ -33,12 +33,12 @@ constexpr std::array kExecAllTypes = { class XlaInterpreterDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override; + std::vector* devices) override; }; Status XlaInterpreterDeviceFactory::CreateDevices( const SessionOptions& session_options, const string& name_prefix, - std::vector>* devices) { + std::vector* devices) { static XlaDeviceOpRegistrations* registrations = RegisterXlaDeviceKernels( DEVICE_XLA_INTERPRETER, DEVICE_INTERPRETER_XLA_JIT); (void)registrations; @@ -61,7 +61,8 @@ Status XlaInterpreterDeviceFactory::CreateDevices( options.device_ordinal = 0; options.compilation_device_name = DEVICE_INTERPRETER_XLA_JIT; options.use_multiple_streams = false; - devices->push_back(absl::make_unique(session_options, options)); + auto device = absl::make_unique(session_options, options); + devices->push_back(device.release()); return Status::OK(); } diff --git a/tensorflow/compiler/tf2xla/xla_compiler.cc b/tensorflow/compiler/tf2xla/xla_compiler.cc index 2230bfd7d9..8036bc6844 100644 --- a/tensorflow/compiler/tf2xla/xla_compiler.cc +++ b/tensorflow/compiler/tf2xla/xla_compiler.cc @@ -380,7 +380,7 @@ XlaCompiler::XlaCompiler(XlaCompiler::Options options) initialization_status_(Status::OK()), next_step_id_(1), device_(new XlaCompilationDevice(SessionOptions(), options_.device_type)), - device_mgr_(absl::WrapUnique(device_)) { + device_mgr_({device_}) { CHECK(!options_.device_type.type_string().empty()); if (options_.populate_resource_manager) { initialization_status_ = diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 1b4371198a..2a8c2718ed 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -2963,7 +2963,6 @@ tf_cuda_library( ":lib_internal", ":proto_text", ":protos_all_cc", - "@com_google_absl//absl/memory", "//third_party/eigen3", "//tensorflow/core/grappler:grappler_item", ] + mkl_deps(), @@ -3817,7 +3816,6 @@ tf_cc_tests_gpu( ":test", ":test_main", ":testlib", - "@com_google_absl//absl/memory", ], ) @@ -3846,7 +3844,6 @@ tf_cc_tests_gpu( ":test", ":test_main", ":testlib", - "@com_google_absl//absl/memory", ], ) @@ -4414,7 +4411,6 @@ tf_cc_test( "//tensorflow/core/kernels:random_ops", "//tensorflow/core/kernels:shape_ops", "//third_party/eigen3", - "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/core/common_runtime/collective_executor_mgr_test.cc b/tensorflow/core/common_runtime/collective_executor_mgr_test.cc index f3d86aa633..91994c5731 100644 --- a/tensorflow/core/common_runtime/collective_executor_mgr_test.cc +++ b/tensorflow/core/common_runtime/collective_executor_mgr_test.cc @@ -38,9 +38,8 @@ class CollectiveExecutorMgrTest : public ::testing::Test { auto* device_count = options.config.mutable_device_count(); string task_name = "/job:localhost/replica:0/task:0"; device_count->insert({"CPU", NUM_DEVS}); - std::vector> devices; - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); - device_mgr_.reset(new DeviceMgr(std::move(devices))); + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); + device_mgr_.reset(new DeviceMgr(devices_)); std::unique_ptr drl( new DeviceResolverLocal(device_mgr_.get())); std::unique_ptr prl( @@ -51,6 +50,7 @@ class CollectiveExecutorMgrTest : public ::testing::Test { } std::unique_ptr cme_; + std::vector devices_; std::unique_ptr device_mgr_; }; diff --git a/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc b/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc index 94d889c40d..9a501b3298 100644 --- a/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc +++ b/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc @@ -37,9 +37,8 @@ class CollectiveParamResolverLocalTest : public ::testing::Test { string task_name = "/job:localhost/replica:0/task:0"; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - std::vector> devices; - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); - device_mgr_.reset(new DeviceMgr(std::move(devices))); + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); + device_mgr_.reset(new DeviceMgr(devices_)); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); prl_.reset(new CollectiveParamResolverLocal(device_mgr_.get(), drl_.get(), task_name)); @@ -74,6 +73,7 @@ class CollectiveParamResolverLocalTest : public ::testing::Test { } } + std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; std::unique_ptr prl_; diff --git a/tensorflow/core/common_runtime/collective_rma_local_test.cc b/tensorflow/core/common_runtime/collective_rma_local_test.cc index 4263f3a4ad..a931fe64bd 100644 --- a/tensorflow/core/common_runtime/collective_rma_local_test.cc +++ b/tensorflow/core/common_runtime/collective_rma_local_test.cc @@ -42,9 +42,8 @@ class CollectiveRemoteAccessLocalTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - std::vector> devices; - TF_CHECK_OK(DeviceFactory::AddDevices(options, kTaskName, &devices)); - device_mgr_.reset(new DeviceMgr(std::move(devices))); + TF_CHECK_OK(DeviceFactory::AddDevices(options, kTaskName, &devices_)); + device_mgr_.reset(new DeviceMgr(devices_)); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); prl_.reset(new CollectiveParamResolverLocal(device_mgr_.get(), drl_.get(), kTaskName)); @@ -52,6 +51,7 @@ class CollectiveRemoteAccessLocalTest : public ::testing::Test { kStepId)); } + std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; std::unique_ptr prl_; diff --git a/tensorflow/core/common_runtime/device_factory.cc b/tensorflow/core/common_runtime/device_factory.cc index 0fad13fe1e..b94900114c 100644 --- a/tensorflow/core/common_runtime/device_factory.cc +++ b/tensorflow/core/common_runtime/device_factory.cc @@ -20,7 +20,6 @@ limitations under the License. #include #include -#include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/logging.h" @@ -90,9 +89,9 @@ DeviceFactory* DeviceFactory::GetFactory(const string& device_type) { return it->second.factory.get(); } -Status DeviceFactory::AddDevices( - const SessionOptions& options, const string& name_prefix, - std::vector>* devices) { +Status DeviceFactory::AddDevices(const SessionOptions& options, + const string& name_prefix, + std::vector* devices) { // CPU first. A CPU device is required. auto cpu_factory = GetFactory("CPU"); if (!cpu_factory) { @@ -117,16 +116,16 @@ Status DeviceFactory::AddDevices( return Status::OK(); } -std::unique_ptr DeviceFactory::NewDevice(const string& type, - const SessionOptions& options, - const string& name_prefix) { +Device* DeviceFactory::NewDevice(const string& type, + const SessionOptions& options, + const string& name_prefix) { auto device_factory = GetFactory(type); if (!device_factory) { return nullptr; } SessionOptions opt = options; (*opt.config.mutable_device_count())[type] = 1; - std::vector> devices; + std::vector devices; TF_CHECK_OK(device_factory->CreateDevices(opt, name_prefix, &devices)); int expected_num_devices = 1; auto iter = options.config.device_count().find(type); @@ -134,7 +133,7 @@ std::unique_ptr DeviceFactory::NewDevice(const string& type, expected_num_devices = iter->second; } DCHECK_EQ(devices.size(), static_cast(expected_num_devices)); - return std::move(devices[0]); + return devices[0]; } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/device_factory.h b/tensorflow/core/common_runtime/device_factory.h index b3cd7adca9..db50226fe8 100644 --- a/tensorflow/core/common_runtime/device_factory.h +++ b/tensorflow/core/common_runtime/device_factory.h @@ -40,19 +40,18 @@ class DeviceFactory { // CPU devices are added first. static Status AddDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices); + std::vector* devices); // Helper for tests. Create a single device of type "type". The // returned device is always numbered zero, so if creating multiple // devices of the same type, supply distinct name_prefix arguments. - static std::unique_ptr NewDevice(const string& type, - const SessionOptions& options, - const string& name_prefix); + static Device* NewDevice(const string& type, const SessionOptions& options, + const string& name_prefix); // Most clients should call AddDevices() instead. - virtual Status CreateDevices( - const SessionOptions& options, const string& name_prefix, - std::vector>* devices) = 0; + virtual Status CreateDevices(const SessionOptions& options, + const string& name_prefix, + std::vector* devices) = 0; // Return the device priority number for a "device_type" string. // diff --git a/tensorflow/core/common_runtime/device_mgr.cc b/tensorflow/core/common_runtime/device_mgr.cc index 1f7d7c4699..470abc1431 100644 --- a/tensorflow/core/common_runtime/device_mgr.cc +++ b/tensorflow/core/common_runtime/device_mgr.cc @@ -15,7 +15,6 @@ limitations under the License. #include "tensorflow/core/common_runtime/device_mgr.h" -#include #include #include "tensorflow/core/common_runtime/local_device.h" #include "tensorflow/core/framework/device_attributes.pb.h" @@ -25,32 +24,32 @@ limitations under the License. namespace tensorflow { -DeviceMgr::DeviceMgr(std::vector> devices) - : devices_(std::move(devices)), name_backing_store_(128) { - for (auto& d : devices_) { +DeviceMgr::DeviceMgr(const std::vector& devices) + : name_backing_store_(128) { + for (Device* d : devices) { CHECK(d->device_mgr_ == nullptr); d->device_mgr_ = this; + devices_.push_back(d); + // Register under the (1) full name and (2) canonical name. for (const string& name : DeviceNameUtils::GetNamesForDeviceMappings(d->parsed_name())) { - device_map_[CopyToBackingStore(name)] = d.get(); + device_map_[CopyToBackingStore(name)] = d; } // Register under the (3) local name and (4) legacy local name. for (const string& name : DeviceNameUtils::GetLocalNamesForDeviceMappings(d->parsed_name())) { - device_map_[CopyToBackingStore(name)] = d.get(); + device_map_[CopyToBackingStore(name)] = d; } device_type_counts_[d->device_type()]++; } } -DeviceMgr::DeviceMgr(std::unique_ptr device) - : DeviceMgr([&device] { - std::vector> vector; - vector.push_back(std::move(device)); - return vector; - }()) {} +DeviceMgr::~DeviceMgr() { + // TODO(b/37437134): Remove destructor after converting to std::unique_ptr. + for (Device* p : devices_) delete p; +} StringPiece DeviceMgr::CopyToBackingStore(StringPiece s) { size_t n = s.size(); @@ -62,22 +61,18 @@ StringPiece DeviceMgr::CopyToBackingStore(StringPiece s) { void DeviceMgr::ListDeviceAttributes( std::vector* devices) const { devices->reserve(devices_.size()); - for (const auto& dev : devices_) { + for (Device* dev : devices_) { devices->emplace_back(dev->attributes()); } } std::vector DeviceMgr::ListDevices() const { - std::vector devices(devices_.size()); - for (size_t i = 0; i < devices_.size(); ++i) { - devices[i] = devices_[i].get(); - } - return devices; + return std::vector(devices_.begin(), devices_.end()); } string DeviceMgr::DebugString() const { string out; - for (const auto& dev : devices_) { + for (Device* dev : devices_) { strings::StrAppend(&out, dev->name(), "\n"); } return out; @@ -85,7 +80,7 @@ string DeviceMgr::DebugString() const { string DeviceMgr::DeviceMappingString() const { string out; - for (const auto& dev : devices_) { + for (Device* dev : devices_) { if (!dev->attributes().physical_device_desc().empty()) { strings::StrAppend(&out, dev->name(), " -> ", dev->attributes().physical_device_desc(), "\n"); @@ -112,7 +107,7 @@ Status DeviceMgr::LookupDevice(StringPiece name, Device** device) const { void DeviceMgr::ClearContainers(gtl::ArraySlice containers) const { Status s; - for (const auto& dev : devices_) { + for (Device* dev : devices_) { if (containers.empty()) { s.Update(dev->resource_manager()->Cleanup( dev->resource_manager()->default_container())); diff --git a/tensorflow/core/common_runtime/device_mgr.h b/tensorflow/core/common_runtime/device_mgr.h index bf8694655a..c1ff10d9b5 100644 --- a/tensorflow/core/common_runtime/device_mgr.h +++ b/tensorflow/core/common_runtime/device_mgr.h @@ -16,7 +16,6 @@ limitations under the License. #ifndef TENSORFLOW_CORE_COMMON_RUNTIME_DEVICE_MGR_H_ #define TENSORFLOW_CORE_COMMON_RUNTIME_DEVICE_MGR_H_ -#include #include #include #include @@ -35,17 +34,15 @@ class DeviceAttributes; class DeviceMgr { public: - // Constructs a DeviceMgr from a list of devices. + // Takes ownership of each device in 'devices'. // TODO(zhifengc): Other initialization information. - explicit DeviceMgr(std::vector> devices); - - // Constructs a DeviceMgr managing a single device. - explicit DeviceMgr(std::unique_ptr device); + // TODO(b/37437134): Use std::unique_ptr's to track ownership. + explicit DeviceMgr(const std::vector& devices); + ~DeviceMgr(); // Returns attributes of all devices. void ListDeviceAttributes(std::vector* devices) const; - // Returns raw pointers to the underlying devices. std::vector ListDevices() const; // Returns a string listing all devices. @@ -65,7 +62,9 @@ class DeviceMgr { int NumDeviceType(const string& type) const; private: - const std::vector> devices_; + // TODO(b/37437134): Use std::unique_ptr's to track ownership. + typedef gtl::InlinedVector DeviceVec; + DeviceVec devices_; StringPiece CopyToBackingStore(StringPiece s); diff --git a/tensorflow/core/common_runtime/device_resolver_local_test.cc b/tensorflow/core/common_runtime/device_resolver_local_test.cc index 54f1119e13..f5a6471ff7 100644 --- a/tensorflow/core/common_runtime/device_resolver_local_test.cc +++ b/tensorflow/core/common_runtime/device_resolver_local_test.cc @@ -36,12 +36,12 @@ class DeviceResolverLocalTest : public ::testing::Test { string task_name = "/job:localhost/replica:0/task:0"; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - std::vector> devices; - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); - device_mgr_.reset(new DeviceMgr(std::move(devices))); + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); + device_mgr_.reset(new DeviceMgr(devices_)); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); } + std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; }; diff --git a/tensorflow/core/common_runtime/device_set_test.cc b/tensorflow/core/common_runtime/device_set_test.cc index 6a8c3d14e5..fd9c4222a7 100644 --- a/tensorflow/core/common_runtime/device_set_test.cc +++ b/tensorflow/core/common_runtime/device_set_test.cc @@ -57,7 +57,7 @@ class DeviceSetTest : public ::testing::Test { class DummyFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override { + std::vector* devices) override { return Status::OK(); } }; diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index 91717328b1..40b7071f40 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -155,12 +155,12 @@ class DirectSessionFactory : public SessionFactory { if (options.config.graph_options().build_cost_model() > 0) { EnableCPUAllocatorFullStats(true); } - std::vector> devices; + std::vector devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); DirectSession* session = - new DirectSession(options, new DeviceMgr(std::move(devices)), this); + new DirectSession(options, new DeviceMgr(devices), this); { mutex_lock l(sessions_lock_); sessions_.push_back(session); diff --git a/tensorflow/core/common_runtime/eager/BUILD b/tensorflow/core/common_runtime/eager/BUILD index 86890ba07d..a7b618c18b 100644 --- a/tensorflow/core/common_runtime/eager/BUILD +++ b/tensorflow/core/common_runtime/eager/BUILD @@ -181,7 +181,6 @@ tf_cc_test( "//tensorflow/core:lib", "//tensorflow/core:test", "//tensorflow/core:test_main", - "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc b/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc index 3ffed3ce32..948bdbcaf5 100644 --- a/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc +++ b/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc @@ -18,7 +18,6 @@ limitations under the License. #include #include -#include "absl/memory/memory.h" #include "tensorflow/cc/client/client_session.h" #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -38,13 +37,12 @@ namespace { class TestEnv { public: TestEnv() : flib_def_(OpRegistry::Global(), {}) { - std::vector> devices; - devices.push_back( - DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0")); - device_mgr_ = absl::make_unique(std::move(devices)); - flib_runtime_ = NewFunctionLibraryRuntime( - device_mgr_.get(), Env::Default(), device_mgr_->ListDevices()[0], - TF_GRAPH_DEF_VERSION, &flib_def_, nullptr, {}, nullptr); + Device* device = + DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0"); + device_mgr_.reset(new DeviceMgr({device})); + flib_runtime_ = NewFunctionLibraryRuntime(device_mgr_.get(), Env::Default(), + device, TF_GRAPH_DEF_VERSION, + &flib_def_, nullptr, {}, nullptr); } FunctionLibraryRuntime* function_library_runtime() const { diff --git a/tensorflow/core/common_runtime/executor_test.cc b/tensorflow/core/common_runtime/executor_test.cc index c311b2533e..7697103faf 100644 --- a/tensorflow/core/common_runtime/executor_test.cc +++ b/tensorflow/core/common_runtime/executor_test.cc @@ -53,17 +53,17 @@ class ExecutorTest : public ::testing::Test { // when the test completes. CHECK(rendez_->Unref()); delete exec_; + delete device_; } // Resets executor_ with a new executor based on a graph 'gdef'. void Create(std::unique_ptr graph) { const int version = graph->versions().producer(); LocalExecutorParams params; - params.device = device_.get(); + params.device = device_; params.create_kernel = [this, version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_.get(), nullptr, ndef, version, - kernel); + return CreateNonCachedKernel(device_, nullptr, ndef, version, kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -83,7 +83,7 @@ class ExecutorTest : public ::testing::Test { } thread::ThreadPool* thread_pool_ = nullptr; - std::unique_ptr device_; + Device* device_ = nullptr; Executor* exec_ = nullptr; StepStatsCollector step_stats_collector_; StepStats step_stats_; diff --git a/tensorflow/core/common_runtime/function_test.cc b/tensorflow/core/common_runtime/function_test.cc index 3b4c976685..13c189fb87 100644 --- a/tensorflow/core/common_runtime/function_test.cc +++ b/tensorflow/core/common_runtime/function_test.cc @@ -18,7 +18,6 @@ limitations under the License. #include #include -#include "absl/memory/memory.h" #include "absl/strings/numbers.h" #include "absl/strings/str_split.h" #include "tensorflow/cc/ops/array_ops_internal.h" @@ -148,15 +147,14 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 3}); - std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices)); + options, "/job:localhost/replica:0/task:0", &devices_)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); OptimizerOptions opts; - device_mgr_ = absl::make_unique(std::move(devices)); + device_mgr_.reset(new DeviceMgr(devices_)); pflr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); @@ -360,6 +358,7 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { FunctionLibraryRuntime* flr0_; FunctionLibraryRuntime* flr1_; FunctionLibraryRuntime* flr2_; + std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/core/common_runtime/function_threadpool_test.cc b/tensorflow/core/common_runtime/function_threadpool_test.cc index bdbe24a70d..655a68cfc9 100644 --- a/tensorflow/core/common_runtime/function_threadpool_test.cc +++ b/tensorflow/core/common_runtime/function_threadpool_test.cc @@ -54,15 +54,14 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 3}); - std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices)); + options, "/job:localhost/replica:0/task:0", &devices_)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); OptimizerOptions opts; - device_mgr_.reset(new DeviceMgr(std::move(devices))); + device_mgr_.reset(new DeviceMgr(devices_)); pflr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); @@ -195,6 +194,7 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { FunctionLibraryRuntime* flr0_; FunctionLibraryRuntime* flr1_; FunctionLibraryRuntime* flr2_; + std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.cc b/tensorflow/core/common_runtime/gpu/gpu_device.cc index 5152d97fde..81fea311e1 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device.cc @@ -907,9 +907,9 @@ Allocator* BaseGPUDevice::GetScopedAllocator(AllocatorAttributes attr, const int BaseGPUDeviceFactory::InterconnectMap::kSameDeviceStrength = 1000; const int BaseGPUDeviceFactory::InterconnectMap::kStreamExecutorStrength = 1; -Status BaseGPUDeviceFactory::CreateDevices( - const SessionOptions& options, const string& name_prefix, - std::vector>* devices) { +Status BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, + const string& name_prefix, + std::vector* devices) { TF_RETURN_IF_ERROR(ValidateGPUMachineManager()); se::Platform* gpu_manager = GPUMachineManager(); if (gpu_manager == nullptr) { @@ -1073,10 +1073,12 @@ static string GetShortDeviceDescription(PlatformGpuId platform_gpu_id, // LINT.ThenChange(//tensorflow/python/platform/test.py) } -Status BaseGPUDeviceFactory::CreateGPUDevice( - const SessionOptions& options, const string& name_prefix, TfGpuId tf_gpu_id, - int64 memory_limit, const DeviceLocality& dev_locality, - std::vector>* devices) { +Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, + const string& name_prefix, + TfGpuId tf_gpu_id, + int64 memory_limit, + const DeviceLocality& dev_locality, + std::vector* devices) { CHECK_GE(tf_gpu_id.value(), 0); const string device_name = strings::StrCat(name_prefix, "/device:GPU:", tf_gpu_id.value()); @@ -1106,7 +1108,7 @@ Status BaseGPUDeviceFactory::CreateGPUDevice( // different (which should be an error). // // TODO(laigd): report error if memory_limit doesn't match stats.bytes_limit. - std::unique_ptr gpu_device = CreateGPUDevice( + BaseGPUDevice* gpu_device = CreateGPUDevice( options, device_name, static_cast(stats.bytes_limit), dev_locality, tf_gpu_id, GetShortDeviceDescription(platform_gpu_id, desc), gpu_allocator, ProcessState::singleton()->GetCPUAllocator(numa_node)); @@ -1114,7 +1116,7 @@ Status BaseGPUDeviceFactory::CreateGPUDevice( << (stats.bytes_limit >> 20) << " MB memory) -> physical GPU (" << GetShortDeviceDescription(platform_gpu_id, desc) << ")"; TF_RETURN_IF_ERROR(gpu_device->Init(options)); - devices->push_back(std::move(gpu_device)); + devices->push_back(gpu_device); return Status::OK(); } diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.h b/tensorflow/core/common_runtime/gpu/gpu_device.h index d002d02c51..674e8384d5 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.h +++ b/tensorflow/core/common_runtime/gpu/gpu_device.h @@ -166,7 +166,7 @@ class BaseGPUDevice : public LocalDevice { class BaseGPUDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override; + std::vector* devices) override; struct InterconnectMap { // Name of interconnect technology, if known. @@ -207,13 +207,15 @@ class BaseGPUDeviceFactory : public DeviceFactory { Status CreateGPUDevice(const SessionOptions& options, const string& name_prefix, TfGpuId tf_gpu_id, int64 memory_limit, const DeviceLocality& dev_locality, - std::vector>* devices); - - virtual std::unique_ptr CreateGPUDevice( - const SessionOptions& options, const string& name, Bytes memory_limit, - const DeviceLocality& dev_locality, TfGpuId tf_gpu_id, - const string& physical_device_desc, Allocator* gpu_allocator, - Allocator* cpu_allocator) = 0; + std::vector* devices); + + virtual BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, + const string& name, Bytes memory_limit, + const DeviceLocality& dev_locality, + TfGpuId tf_gpu_id, + const string& physical_device_desc, + Allocator* gpu_allocator, + Allocator* cpu_allocator) = 0; // Returns into 'ids' the list of valid platform GPU ids, in the order that // they should map to TF GPU ids "/device:GPU:0", "/device:GPU:1", etc, diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc index 8dc7197329..e1aaf95df6 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc @@ -59,14 +59,15 @@ class GPUDevice : public BaseGPUDevice { class GPUDeviceFactory : public BaseGPUDeviceFactory { private: - std::unique_ptr CreateGPUDevice( - const SessionOptions& options, const string& name, Bytes memory_limit, - const DeviceLocality& locality, TfGpuId tf_gpu_id, - const string& physical_device_desc, Allocator* gpu_allocator, - Allocator* cpu_allocator) override { - return absl::make_unique(options, name, memory_limit, locality, - tf_gpu_id, physical_device_desc, - gpu_allocator, cpu_allocator); + BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, + const string& name, Bytes memory_limit, + const DeviceLocality& locality, + TfGpuId tf_gpu_id, + const string& physical_device_desc, + Allocator* gpu_allocator, + Allocator* cpu_allocator) override { + return new GPUDevice(options, name, memory_limit, locality, tf_gpu_id, + physical_device_desc, gpu_allocator, cpu_allocator); } }; @@ -107,7 +108,7 @@ class GPUCompatibleCPUDevice : public ThreadPoolDevice { class GPUCompatibleCPUDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override { + std::vector* devices) override { int n = 1; auto iter = options.config.device_count().find("CPU"); if (iter != options.config.device_count().end()) { @@ -115,7 +116,7 @@ class GPUCompatibleCPUDeviceFactory : public DeviceFactory { } for (int i = 0; i < n; i++) { string name = strings::StrCat(name_prefix, "/device:CPU:", i); - devices->push_back(absl::make_unique( + devices->push_back(new GPUCompatibleCPUDevice( options, name, Bytes(256 << 20), DeviceLocality(), cpu_allocator())); } diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc b/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc index 58656ec757..75be6d60b8 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc @@ -33,7 +33,7 @@ namespace { TEST(GPUDeviceOnNonGPUMachineTest, CreateGPUDevicesOnNonGPUMachine) { SessionOptions opts; - std::vector> devices; + std::vector devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, "/job:localhost/replica:0/task:0", &devices)); EXPECT_TRUE(devices.empty()); diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_test.cc b/tensorflow/core/common_runtime/gpu/gpu_device_test.cc index ae623b2adb..36294094e9 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_test.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_test.cc @@ -88,7 +88,7 @@ class GPUDeviceTest : public ::testing::Test { TEST_F(GPUDeviceTest, FailedToParseVisibleDeviceList) { SessionOptions opts = MakeSessionOptions("0,abc"); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -97,7 +97,7 @@ TEST_F(GPUDeviceTest, FailedToParseVisibleDeviceList) { TEST_F(GPUDeviceTest, InvalidGpuId) { SessionOptions opts = MakeSessionOptions("100"); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -107,7 +107,7 @@ TEST_F(GPUDeviceTest, InvalidGpuId) { TEST_F(GPUDeviceTest, DuplicateEntryInVisibleDeviceList) { SessionOptions opts = MakeSessionOptions("0,0"); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -117,7 +117,7 @@ TEST_F(GPUDeviceTest, DuplicateEntryInVisibleDeviceList) { TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithMemoryFractionSettings) { SessionOptions opts = MakeSessionOptions("0", 0.1, 1, {{}}); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -129,7 +129,7 @@ TEST_F(GPUDeviceTest, GpuDeviceCountTooSmall) { // device_count is 0, but with one entry in visible_device_list and one // (empty) VirtualDevices messages. SessionOptions opts = MakeSessionOptions("0", 0, 0, {{}}); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::UNKNOWN); @@ -141,7 +141,7 @@ TEST_F(GPUDeviceTest, NotEnoughGpuInVisibleDeviceList) { // Single entry in visible_device_list with two (empty) VirtualDevices // messages. SessionOptions opts = MakeSessionOptions("0", 0, 8, {{}, {}}); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::UNKNOWN); @@ -155,7 +155,7 @@ TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithVisibleDeviceList) { // Three entries in visible_device_list with two (empty) VirtualDevices // messages. SessionOptions opts = MakeSessionOptions("0,1", 0, 8, {{}}); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -169,36 +169,39 @@ TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithVisibleDeviceList) { TEST_F(GPUDeviceTest, EmptyVirtualDeviceConfig) { // It'll create single virtual device when the virtual device config is empty. SessionOptions opts = MakeSessionOptions("0"); - std::vector> devices; + std::vector devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_GE(devices[0]->attributes().memory_limit(), 0); + gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, SingleVirtualDeviceWithNoMemoryLimit) { // It'll create single virtual device for the gpu in question when // memory_limit_mb is unset. SessionOptions opts = MakeSessionOptions("0", 0, 1, {{}}); - std::vector> devices; + std::vector devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_GE(devices[0]->attributes().memory_limit(), 0); + gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, SingleVirtualDeviceWithMemoryLimit) { SessionOptions opts = MakeSessionOptions("0", 0, 1, {{123}}); - std::vector> devices; + std::vector devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_EQ(123 << 20, devices[0]->attributes().memory_limit()); + gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, MultipleVirtualDevices) { SessionOptions opts = MakeSessionOptions("0", 0, 1, {{123, 456}}); - std::vector> devices; + std::vector devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(2, devices.size()); @@ -216,6 +219,7 @@ TEST_F(GPUDeviceTest, MultipleVirtualDevices) { devices[1]->attributes().locality().links().link(0).type()); EXPECT_EQ(BaseGPUDeviceFactory::InterconnectMap::kSameDeviceStrength, devices[1]->attributes().locality().links().link(0).strength()); + gtl::STLDeleteElements(&devices); } // Enabling unified memory on pre-Pascal GPUs results in an initialization @@ -232,7 +236,7 @@ TEST_F(GPUDeviceTest, UnifiedMemoryUnavailableOnPrePascalGpus) { opts.config.mutable_gpu_options() ->mutable_experimental() ->set_use_unified_memory(true); - std::vector> devices; + std::vector devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INTERNAL); @@ -255,7 +259,7 @@ TEST_F(GPUDeviceTest, UnifiedMemoryAllocation) { } SessionOptions opts = MakeSessionOptions("0", kGpuMemoryFraction); - std::vector> devices; + std::vector devices; TF_ASSERT_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); ASSERT_EQ(1, devices.size()); @@ -274,6 +278,8 @@ TEST_F(GPUDeviceTest, UnifiedMemoryAllocation) { (memory_limit >> 20) << 20); EXPECT_NE(ptr, nullptr); allocator->DeallocateRaw(ptr); + + gtl::STLDeleteElements(&devices); } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc b/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc index f0656ff533..2144eea84f 100644 --- a/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc +++ b/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc @@ -15,7 +15,6 @@ limitations under the License. #include "tensorflow/core/common_runtime/hierarchical_tree_broadcaster.h" #include -#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/base_collective_executor.h" #include "tensorflow/core/common_runtime/collective_rma_local.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -218,7 +217,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { << " num_devices_per_worker=" << num_devices_per_worker; int total_num_devices = num_workers * num_devices_per_worker; device_type_ = device_type; - std::vector> local_devices; + std::vector local_devices; SessionOptions sess_opts; sess_opts.env = Env::Default(); Bytes mem_limit(4 << 20); @@ -228,7 +227,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { if (device_type == DEVICE_CPU) { string dev_name = strings::StrCat("/job:worker/replica:0/task:", wi, "/device:CPU:", di); - local_devices.push_back(absl::make_unique( + local_devices.push_back(new ThreadPoolDevice( sess_opts, dev_name, mem_limit, dev_locality, cpu_allocator())); } else if (device_type == DEVICE_GPU && !gpu_devices_.empty()) { int dev_idx = (wi * num_devices_per_worker) + di; @@ -236,7 +235,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { LOG(INFO) << "dev_mgr has access to limited GPUs, reusing for more " "than one ring node."; } else { - local_devices.push_back(std::move(gpu_devices_[dev_idx])); + local_devices.push_back(gpu_devices_[dev_idx]); } } else { LOG(FATAL) << "Unsupported device_type " << device_type; @@ -244,7 +243,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { } } if (!dev_mgr_ || device_type == DEVICE_CPU) { - dev_mgr_.reset(new DeviceMgr(std::move(local_devices))); + dev_mgr_.reset(new DeviceMgr(local_devices)); } if (!gpu_ring_order_) gpu_ring_order_.reset(new string()); dev_resolver_.reset(new DeviceResolverLocal(dev_mgr_.get())); @@ -715,7 +714,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { std::unique_ptr dev_resolver_; std::vector instances_; CollectiveParams col_params_; - std::vector> gpu_devices_; + std::vector gpu_devices_; std::unique_ptr dev_mgr_; std::unique_ptr gpu_ring_order_; mutex mu_; diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc index bdd6c0e87d..1f585a8c24 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc @@ -75,12 +75,12 @@ Benchmark::Benchmark(const string& device, Graph* g, const int graph_def_version = g->versions().producer(); LocalExecutorParams params; - params.device = device_.get(); + params.device = device_; params.function_library = nullptr; params.create_kernel = [this, graph_def_version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_.get(), nullptr, ndef, - graph_def_version, kernel); + return CreateNonCachedKernel(device_, nullptr, ndef, graph_def_version, + kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -107,7 +107,7 @@ Benchmark::~Benchmark() { // run kernel destructors that may attempt to access state borrowed from // `device_`, such as the resource manager. exec_.reset(); - device_.reset(); + delete device_; delete pool_; } } diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.h b/tensorflow/core/common_runtime/kernel_benchmark_testlib.h index b1557c50b0..555b43f655 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.h +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.h @@ -55,7 +55,7 @@ class Benchmark { private: thread::ThreadPool* pool_ = nullptr; - std::unique_ptr device_ = nullptr; + Device* device_ = nullptr; Rendezvous* rendez_ = nullptr; std::unique_ptr exec_; diff --git a/tensorflow/core/common_runtime/placer_test.cc b/tensorflow/core/common_runtime/placer_test.cc index 04e77e55f6..009f905f10 100644 --- a/tensorflow/core/common_runtime/placer_test.cc +++ b/tensorflow/core/common_runtime/placer_test.cc @@ -92,7 +92,7 @@ class FakeDevice : public Device { class DummyFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override { + std::vector* devices) override { return Status::OK(); } }; diff --git a/tensorflow/core/common_runtime/process_function_library_runtime_test.cc b/tensorflow/core/common_runtime/process_function_library_runtime_test.cc index 21cb62118a..cce2308011 100644 --- a/tensorflow/core/common_runtime/process_function_library_runtime_test.cc +++ b/tensorflow/core/common_runtime/process_function_library_runtime_test.cc @@ -62,12 +62,9 @@ class ProcessFunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 2}); - std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices(options, "/job:a/replica:0/task:0", - &devices)); - device0_ = devices[0].get(); - device1_ = devices[1].get(); - device_mgr_.reset(new DeviceMgr(std::move(devices))); + &devices_)); + device_mgr_.reset(new DeviceMgr(devices_)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); @@ -141,9 +138,8 @@ class ProcessFunctionLibraryRuntimeTest : public ::testing::Test { return Status::OK(); } + std::vector devices_; std::unique_ptr device_mgr_; - Device* device0_ = nullptr; // Not owned. (Owned by device_mgr_.) - Device* device1_ = nullptr; // Not owned. (Owned by device_mgr_.) std::unique_ptr lib_def_; std::unique_ptr cluster_flr_; std::unique_ptr proc_flr_; @@ -169,16 +165,16 @@ TEST_F(ProcessFunctionLibraryRuntimeTest, Basic) { FunctionLibraryRuntime* flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/cpu:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), device0_); + EXPECT_EQ(flr->device(), devices_[0]); flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/device:CPU:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), device0_); + EXPECT_EQ(flr->device(), devices_[0]); flr = proc_flr_->GetFLR("/device:CPU:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), device0_); + EXPECT_EQ(flr->device(), devices_[0]); flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/cpu:1"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), device1_); + EXPECT_EQ(flr->device(), devices_[1]); flr = proc_flr_->GetFLR("abc"); EXPECT_EQ(flr, nullptr); rendezvous_->Unref(); diff --git a/tensorflow/core/common_runtime/renamed_device.cc b/tensorflow/core/common_runtime/renamed_device.cc index 45541c35fe..56766a8df4 100644 --- a/tensorflow/core/common_runtime/renamed_device.cc +++ b/tensorflow/core/common_runtime/renamed_device.cc @@ -14,14 +14,15 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/common_runtime/renamed_device.h" -#include "absl/memory/memory.h" namespace tensorflow { +// TODO(saeta): Convert to returning a std::unique_ptr? /* static */ -std::unique_ptr RenamedDevice::NewRenamedDevice( - const string& new_base, Device* underlying, bool owns_underlying, - bool isolate_session_state) { +Device* RenamedDevice::NewRenamedDevice(const string& new_base, + Device* underlying, + bool owns_underlying, + bool isolate_session_state) { DeviceNameUtils::ParsedName parsed_name; CHECK(DeviceNameUtils::ParseFullName(new_base, &parsed_name)); DeviceNameUtils::ParsedName underlying_parsed_name = @@ -35,9 +36,8 @@ std::unique_ptr RenamedDevice::NewRenamedDevice( parsed_name.id); DeviceAttributes attributes(underlying->attributes()); attributes.set_name(name); - // Call absl::WrapUnique to access private constructor. - return absl::WrapUnique(new RenamedDevice( - underlying, attributes, owns_underlying, isolate_session_state)); + return new RenamedDevice(underlying, attributes, owns_underlying, + isolate_session_state); } RenamedDevice::RenamedDevice(Device* underlying, diff --git a/tensorflow/core/common_runtime/renamed_device.h b/tensorflow/core/common_runtime/renamed_device.h index 6d24f496ff..c00789a556 100644 --- a/tensorflow/core/common_runtime/renamed_device.h +++ b/tensorflow/core/common_runtime/renamed_device.h @@ -28,10 +28,9 @@ namespace tensorflow { // session. class RenamedDevice : public Device { public: - static std::unique_ptr NewRenamedDevice(const string& new_base, - Device* underlying, - bool owns_underlying, - bool isolate_session_state); + static Device* NewRenamedDevice(const string& new_base, Device* underlying, + bool owns_underlying, + bool isolate_session_state); ~RenamedDevice() override; diff --git a/tensorflow/core/common_runtime/ring_reducer_test.cc b/tensorflow/core/common_runtime/ring_reducer_test.cc index 7feb29a6db..a271bf7b74 100644 --- a/tensorflow/core/common_runtime/ring_reducer_test.cc +++ b/tensorflow/core/common_runtime/ring_reducer_test.cc @@ -15,7 +15,6 @@ limitations under the License. #include "tensorflow/core/common_runtime/ring_reducer.h" #include -#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/base_collective_executor.h" #include "tensorflow/core/common_runtime/collective_rma_local.h" #include "tensorflow/core/common_runtime/device.h" @@ -158,7 +157,7 @@ class RingReducerTest : public ::testing::Test { InitGPUDevices(); #endif device_type_ = device_type; - std::vector> local_devices; + std::vector local_devices; SessionOptions sess_opts; sess_opts.env = Env::Default(); Bytes mem_limit(4 << 20); @@ -168,7 +167,7 @@ class RingReducerTest : public ::testing::Test { if (device_type == DEVICE_CPU) { string dev_name = strings::StrCat("/job:worker/replica:0/task:", wi, "/cpu:", di); - local_devices.push_back(absl::make_unique( + local_devices.push_back(new ThreadPoolDevice( sess_opts, dev_name, mem_limit, dev_locality, cpu_allocator())); } else if (device_type == DEVICE_GPU && !gpu_devices_.empty()) { int dev_idx = (wi * num_devices) + di; @@ -176,7 +175,7 @@ class RingReducerTest : public ::testing::Test { LOG(INFO) << "dev_mgr has access to limited GPUs, reusing for more " "than one ring node."; } else { - local_devices.push_back(std::move(gpu_devices_[dev_idx])); + local_devices.push_back(gpu_devices_[dev_idx]); } } else { LOG(FATAL) << "Unsupported device_type " << device_type; @@ -186,7 +185,7 @@ class RingReducerTest : public ::testing::Test { if (!dev_mgr_ || device_type == DEVICE_CPU) { LOG(ERROR) << "resetting dev_mgr for " << local_devices.size() << " devices: "; - dev_mgr_.reset(new DeviceMgr(std::move(local_devices))); + dev_mgr_.reset(new DeviceMgr(local_devices)); } if (!gpu_ring_order_) gpu_ring_order_.reset(new string()); dev_resolver_.reset(new DeviceResolverLocal(dev_mgr_.get())); @@ -545,7 +544,7 @@ class RingReducerTest : public ::testing::Test { std::unique_ptr dev_resolver_; std::vector instances_; CollectiveParams col_params_; - std::vector> gpu_devices_; + std::vector gpu_devices_; std::unique_ptr dev_mgr_; std::unique_ptr gpu_ring_order_; mutex mu_; diff --git a/tensorflow/core/common_runtime/threadpool_device_factory.cc b/tensorflow/core/common_runtime/threadpool_device_factory.cc index f9cbb81749..c06a4035a7 100644 --- a/tensorflow/core/common_runtime/threadpool_device_factory.cc +++ b/tensorflow/core/common_runtime/threadpool_device_factory.cc @@ -13,13 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#include - // Register a factory that provides CPU devices. -#include "absl/memory/memory.h" +#include "tensorflow/core/common_runtime/threadpool_device.h" + +#include #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/common_runtime/process_state.h" -#include "tensorflow/core/common_runtime/threadpool_device.h" #include "tensorflow/core/framework/allocator.h" #include "tensorflow/core/platform/numa.h" #include "tensorflow/core/public/session_options.h" @@ -30,7 +29,7 @@ namespace tensorflow { class ThreadPoolDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector>* devices) override { + std::vector* devices) override { int num_numa_nodes = port::NUMANumNodes(); int n = 1; auto iter = options.config.device_count().find("CPU"); @@ -39,7 +38,7 @@ class ThreadPoolDeviceFactory : public DeviceFactory { } for (int i = 0; i < n; i++) { string name = strings::StrCat(name_prefix, "/device:CPU:", i); - std::unique_ptr tpd; + ThreadPoolDevice* tpd = nullptr; if (options.config.experimental().use_numa_affinity()) { int numa_node = i % num_numa_nodes; if (numa_node != i) { @@ -50,15 +49,15 @@ class ThreadPoolDeviceFactory : public DeviceFactory { } DeviceLocality dev_locality; dev_locality.set_numa_node(numa_node); - tpd = absl::make_unique( + tpd = new ThreadPoolDevice( options, name, Bytes(256 << 20), dev_locality, ProcessState::singleton()->GetCPUAllocator(numa_node)); } else { - tpd = absl::make_unique( + tpd = new ThreadPoolDevice( options, name, Bytes(256 << 20), DeviceLocality(), ProcessState::singleton()->GetCPUAllocator(port::kNUMANoAffinity)); } - devices->push_back(std::move(tpd)); + devices->push_back(tpd); } return Status::OK(); diff --git a/tensorflow/core/distributed_runtime/BUILD b/tensorflow/core/distributed_runtime/BUILD index a47da0d6a0..818324746f 100644 --- a/tensorflow/core/distributed_runtime/BUILD +++ b/tensorflow/core/distributed_runtime/BUILD @@ -624,7 +624,6 @@ tf_cc_test( "//tensorflow/core:test", "//tensorflow/core:test_main", "//tensorflow/core:testlib", - "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc b/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc index 40b18d321a..4eed856759 100644 --- a/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc @@ -29,8 +29,7 @@ limitations under the License. namespace tensorflow { namespace { -static std::unique_ptr NewDevice(const string& type, - const string& name) { +static Device* NewDevice(const string& type, const string& name) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -41,7 +40,7 @@ static std::unique_ptr NewDevice(const string& type, attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(3); // a non-default value - return absl::make_unique(attr); + return new FakeDevice(attr); } class FakeWorker : public TestWorkerInterface { @@ -157,16 +156,16 @@ class DeviceResDistTest : public ::testing::Test { void DefineWorker(const ConfigProto& config, const string& worker_name, const string& device_type, int num_devices) { - std::vector> devices; + std::vector devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i))); } - DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); + DeviceMgr* dev_mgr = new DeviceMgr(devices); device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto* d : dev_mgr->ListDevices()) { + for (auto d : devices) { dv->push_back(d->name()); } DeviceResolverDistributed* dev_res = diff --git a/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc b/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc index 26f722a6bd..33e1c8f2c3 100644 --- a/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc @@ -41,8 +41,7 @@ limitations under the License. namespace tensorflow { namespace { -static std::unique_ptr NewDevice(const string& type, - const string& name) { +static Device* NewDevice(const string& type, const string& name) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -53,7 +52,7 @@ static std::unique_ptr NewDevice(const string& type, attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(3); // a non-default value - return absl::make_unique(attr); + return new FakeDevice(attr); } static int64 kStepId = 123; @@ -212,16 +211,16 @@ class CollRMADistTest : public ::testing::Test { void DefineWorker(const ConfigProto& config, const string& worker_name, const string& device_type, int num_devices) { - std::vector> devices; + std::vector devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i))); } - DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); + DeviceMgr* dev_mgr = new DeviceMgr(devices); device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : dev_mgr->ListDevices()) { + for (auto d : devices) { dv->push_back(d->name()); } DeviceResolverDistributed* dev_res = diff --git a/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc b/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc index 842a2b3b05..ae44b98bd5 100644 --- a/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc @@ -15,7 +15,6 @@ limitations under the License. #include "tensorflow/core/distributed_runtime/device_resolver_distributed.h" -#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/distributed_runtime/test_utils.h" #include "tensorflow/core/lib/core/notification.h" @@ -42,8 +41,8 @@ class TestableDeviceResolverDistributed : public DeviceResolverDistributed { // Create a fake 'Device' whose only interesting attribute is a non-default // DeviceLocality. -static std::unique_ptr NewDevice(const string& type, const string& name, - int numa_node) { +static Device* NewDevice(const string& type, const string& name, + int numa_node) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -54,7 +53,7 @@ static std::unique_ptr NewDevice(const string& type, const string& name, attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(numa_node); - return absl::make_unique(attr); + return new FakeDevice(attr); } // Create a fake WorkerInterface that responds to requests without RPCs, @@ -152,19 +151,19 @@ class DeviceResDistTest : public ::testing::Test { void DefineWorker(const string& worker_name, const string& device_type, int num_devices) { - std::vector> devices; + std::vector devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i), i)); } - DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); + DeviceMgr* dev_mgr = new DeviceMgr(devices); TestableDeviceResolverDistributed* dev_res = new TestableDeviceResolverDistributed(dev_mgr, &wc_, worker_name); resolvers_[worker_name] = dev_res; device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto* d : dev_mgr->ListDevices()) { + for (auto d : devices) { dv->push_back(d->name()); } FakeWorker* fw = new FakeWorker(worker_name, dev_mgr, dev_res); diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc index c66466c0a6..5b0a420fad 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc @@ -87,7 +87,7 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, return tensorflow::errors::Internal( "invalid eager env_ or env_->rendezvous_mgr."); } - std::vector> devices; + std::vector devices; TF_RETURN_IF_ERROR(tensorflow::DeviceFactory::AddDevices( // TODO(nareshmodi): Correctly set the SessionOptions. @@ -97,12 +97,12 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, request->server_def().task_index()), &devices)); response->mutable_device_attributes()->Reserve(devices.size()); - for (const auto& d : devices) { + for (auto& d : devices) { *response->add_device_attributes() = d->attributes(); } std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(std::move(devices))); + new tensorflow::DeviceMgr(devices)); auto* r = env_->rendezvous_mgr->Find(request->rendezvous_id()); auto session_name = strings::StrCat("eager_", request->rendezvous_id()); diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc index 7a1463e8f0..5ba522c2a2 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc @@ -68,9 +68,12 @@ class EagerServiceImplTest : public ::testing::Test { worker_env_.rendezvous_mgr = &rendezvous_mgr_; worker_env_.session_mgr = session_mgr_.get(); - device_mgr_ = absl::make_unique(DeviceFactory::NewDevice( - "CPU", {}, "/job:localhost/replica:0/task:0/device:CPU:0")); - worker_env_.local_devices = device_mgr_->ListDevices(); + Device* device = DeviceFactory::NewDevice( + "CPU", {}, "/job:localhost/replica:0/task:0/device:CPU:0"); + + worker_env_.local_devices = {device}; + + device_mgr_.reset(new DeviceMgr(worker_env_.local_devices)); worker_env_.device_mgr = device_mgr_.get(); } diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc index cbd5cd927e..ae722fdfe9 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc @@ -18,7 +18,6 @@ limitations under the License. #include #include #include -#include #include "grpc/support/alloc.h" #include "grpcpp/grpcpp.h" @@ -157,12 +156,10 @@ Status GrpcServer::Init( string name_prefix = strings::StrCat("/job:", server_def_.job_name(), "/replica:0", "/task:", server_def_.task_index()); - std::vector> devices; - TF_RETURN_IF_ERROR( - DeviceFactory::AddDevices(sess_opts, name_prefix, &devices)); - worker_env_.device_mgr = new DeviceMgr(std::move(devices)); - master_env_.local_devices = worker_env_.device_mgr->ListDevices(); - worker_env_.local_devices = worker_env_.device_mgr->ListDevices(); + TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(sess_opts, name_prefix, + &master_env_.local_devices)); + worker_env_.local_devices = master_env_.local_devices; + worker_env_.device_mgr = new DeviceMgr(worker_env_.local_devices); worker_env_.rendezvous_mgr = rendezvous_mgr_func == nullptr ? new RpcRendezvousMgr(&worker_env_) : rendezvous_mgr_func(&worker_env_); diff --git a/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc b/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc index 1c87fe9d92..0323300fdd 100644 --- a/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc +++ b/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc @@ -42,9 +42,8 @@ class RpcCollectiveExecutorMgrTest : public ::testing::Test { WorkerCacheInterface* worker_cache = nullptr; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - std::vector> devices; - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); - device_mgr_.reset(new DeviceMgr(std::move(devices))); + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); + device_mgr_.reset(new DeviceMgr(devices_)); std::unique_ptr dr(new DeviceResolverDistributed( device_mgr_.get(), worker_cache, task_name)); std::unique_ptr cpr( @@ -58,6 +57,7 @@ class RpcCollectiveExecutorMgrTest : public ::testing::Test { } std::unique_ptr cme_; + std::vector devices_; std::unique_ptr device_mgr_; }; diff --git a/tensorflow/core/distributed_runtime/session_mgr.cc b/tensorflow/core/distributed_runtime/session_mgr.cc index 29fe767e42..38833bd202 100644 --- a/tensorflow/core/distributed_runtime/session_mgr.cc +++ b/tensorflow/core/distributed_runtime/session_mgr.cc @@ -78,13 +78,13 @@ Status SessionMgr::CreateSession(const string& session, if (isolate_session_state) { // Create a private copy of the DeviceMgr for the WorkerSession. - std::vector> renamed_devices; + std::vector renamed_devices; for (Device* d : worker_env_->local_devices) { renamed_devices.push_back(RenamedDevice::NewRenamedDevice( worker_name, d, false, isolate_session_state)); } - auto device_mgr = MakeUnique(std::move(renamed_devices)); + auto device_mgr = MakeUnique(renamed_devices); auto graph_mgr = MakeUnique(worker_env_, device_mgr.get()); worker_session.reset( new WorkerSession(session, worker_name, diff --git a/tensorflow/core/distributed_runtime/session_mgr_test.cc b/tensorflow/core/distributed_runtime/session_mgr_test.cc index 1ab0d20f0b..99192119a6 100644 --- a/tensorflow/core/distributed_runtime/session_mgr_test.cc +++ b/tensorflow/core/distributed_runtime/session_mgr_test.cc @@ -46,9 +46,11 @@ class SessionMgrTest : public ::testing::Test { SessionMgrTest() : mgr_(&env_, "/job:mnist/replica:0/task:0", std::unique_ptr(), factory_) { - device_mgr_ = absl::make_unique( - FakeDevice::MakeCPU("/job:mnist/replica:0/task:0/device:fakecpu:0")); - env_.local_devices = device_mgr_->ListDevices(); + Device* device = + FakeDevice::MakeCPU("/job:mnist/replica:0/task:0/device:fakecpu:0") + .release(); + env_.local_devices = {device}; + device_mgr_.reset(new DeviceMgr(env_.local_devices)); env_.device_mgr = device_mgr_.get(); } diff --git a/tensorflow/core/grappler/grappler_item_builder.cc b/tensorflow/core/grappler/grappler_item_builder.cc index e69dfa79d1..cf99f4908b 100644 --- a/tensorflow/core/grappler/grappler_item_builder.cc +++ b/tensorflow/core/grappler/grappler_item_builder.cc @@ -102,11 +102,10 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, } // Instantiate all variables for function library runtime creation. - std::vector> devices; + std::vector devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); - Device* cpu_device = devices[0].get(); - std::unique_ptr dvc_mgr(new DeviceMgr(std::move(devices))); + std::unique_ptr dvc_mgr(new DeviceMgr(devices)); FunctionLibraryDefinition function_library(OpRegistry::Global(), graph_def.library()); Env* env = Env::Default(); @@ -125,7 +124,7 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, new ProcessFunctionLibraryRuntime(dvc_mgr.get(), env, graph_def.versions().producer(), &function_library, *optimizer_opts)); - FunctionLibraryRuntime* flr = pflr->GetFLR(cpu_device->name()); + FunctionLibraryRuntime* flr = pflr->GetFLR(devices[0]->name()); // Create the GraphOptimizer to optimize the graph def. GraphConstructorOptions graph_ctor_opts; @@ -138,7 +137,7 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, // Optimize the graph. ::tensorflow::GraphOptimizer optimizer(*optimizer_opts); - optimizer.Optimize(flr, env, cpu_device, &graphptr, /*shape_map=*/nullptr); + optimizer.Optimize(flr, env, devices[0], &graphptr, /*shape_map=*/nullptr); graphptr->ToGraphDef(output_graph_def); // The default values of attributes might have been stripped by the optimizer. diff --git a/tensorflow/core/grappler/optimizers/BUILD b/tensorflow/core/grappler/optimizers/BUILD index 8e6629565a..b6f989f2c9 100644 --- a/tensorflow/core/grappler/optimizers/BUILD +++ b/tensorflow/core/grappler/optimizers/BUILD @@ -142,6 +142,7 @@ cc_library( ":graph_optimizer", "//tensorflow/core:core_cpu_base", "//tensorflow/core:framework", + "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler:grappler_item", @@ -149,7 +150,6 @@ cc_library( "//tensorflow/core/grappler:op_types", "//tensorflow/core/grappler:utils", "//tensorflow/core/grappler/utils:functions", - "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/core/grappler/optimizers/function_optimizer.cc b/tensorflow/core/grappler/optimizers/function_optimizer.cc index f8ddbeb659..f99826ddca 100644 --- a/tensorflow/core/grappler/optimizers/function_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/function_optimizer.cc @@ -16,9 +16,7 @@ limitations under the License. #include "tensorflow/core/grappler/optimizers/function_optimizer.h" #include -#include -#include "absl/memory/memory.h" #include "absl/strings/str_replace.h" #include "absl/strings/substitute.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -345,15 +343,14 @@ class FunctionOptimizerContext { DeviceAttributes attr; attr.set_name("/device:CPU:0"); attr.set_device_type("CPU"); - std::vector> devices; - devices.push_back(absl::make_unique(env, attr)); - device_mgr_ = absl::make_unique(std::move(devices)); + Device* device = new FakeCPUDevice(env, attr); + device_mgr_.reset(new DeviceMgr({device})); OptimizerOptions optimizer_opts; optimizer_opts.set_do_function_inlining(true); process_flr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), env, graph_version_, &function_library_, optimizer_opts)); - flr_ = process_flr_->GetFLR(device_mgr_->ListDevices()[0]->name()); + flr_ = process_flr_->GetFLR(device->name()); } } diff --git a/tensorflow/core/kernels/data/BUILD b/tensorflow/core/kernels/data/BUILD index dcb6975669..7192684e2d 100644 --- a/tensorflow/core/kernels/data/BUILD +++ b/tensorflow/core/kernels/data/BUILD @@ -600,7 +600,6 @@ tf_kernel_library( "//tensorflow/core:protos_all_cc", "//tensorflow/core:session_options", "//tensorflow/core/kernels:ops_util", - "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/kernels/data/iterator_ops.cc b/tensorflow/core/kernels/data/iterator_ops.cc index 98b67454d5..93999dc095 100644 --- a/tensorflow/core/kernels/data/iterator_ops.cc +++ b/tensorflow/core/kernels/data/iterator_ops.cc @@ -14,7 +14,6 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/kernels/data/iterator_ops.h" -#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/graph_runner.h" #include "tensorflow/core/common_runtime/renamed_device.h" #include "tensorflow/core/common_runtime/threadpool_device.h" @@ -546,9 +545,10 @@ FunctionLibraryRuntime* IteratorHandleOp::CreatePrivateFLR( // in its resource manager. The existing device will outlive the // IteratorResource, because we are storing the IteratorResource // in that device's resource manager. - *device_mgr = absl::make_unique(RenamedDevice::NewRenamedDevice( + Device* wrapped_device = RenamedDevice::NewRenamedDevice( ctx->device()->name(), down_cast(ctx->device()), - false /* owns_underlying */, false /* isolate_session_state */)); + false /* owns_underlying */, false /* isolate_session_state */); + device_mgr->reset(new DeviceMgr({wrapped_device})); flib_def->reset(new FunctionLibraryDefinition( *ctx->function_library()->GetFunctionLibraryDefinition())); pflr->reset(new ProcessFunctionLibraryRuntime( diff --git a/tensorflow/core/kernels/data/single_threaded_executor_test.cc b/tensorflow/core/kernels/data/single_threaded_executor_test.cc index 7bb51fb8b5..6244e287bb 100644 --- a/tensorflow/core/kernels/data/single_threaded_executor_test.cc +++ b/tensorflow/core/kernels/data/single_threaded_executor_test.cc @@ -51,17 +51,17 @@ class ExecutorTest : public ::testing::Test { // when the test completes. CHECK(rendez_->Unref()); delete exec_; + delete device_; } // Resets executor_ with a new executor based on a graph 'gdef'. void Create(std::unique_ptr graph) { const int version = graph->versions().producer(); LocalExecutorParams params; - params.device = device_.get(); + params.device = device_; params.create_kernel = [this, version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_.get(), nullptr, ndef, version, - kernel); + return CreateNonCachedKernel(device_, nullptr, ndef, version, kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -86,7 +86,7 @@ class ExecutorTest : public ::testing::Test { return exec_->Run(args); } - std::unique_ptr device_; + Device* device_ = nullptr; Executor* exec_ = nullptr; Executor::Args::Runner runner_; Rendezvous* rendez_ = nullptr; diff --git a/tensorflow/lite/delegates/flex/BUILD b/tensorflow/lite/delegates/flex/BUILD index 63e86899da..222a043a88 100644 --- a/tensorflow/lite/delegates/flex/BUILD +++ b/tensorflow/lite/delegates/flex/BUILD @@ -116,7 +116,6 @@ cc_library( hdrs = ["delegate_data.h"], deps = [ ":buffer_map", - "@com_google_absl//absl/memory", "//tensorflow/core/common_runtime/eager:context", ] + select({ "//tensorflow:android": [ diff --git a/tensorflow/lite/delegates/flex/delegate_data.cc b/tensorflow/lite/delegates/flex/delegate_data.cc index 1483a53038..b62479a448 100644 --- a/tensorflow/lite/delegates/flex/delegate_data.cc +++ b/tensorflow/lite/delegates/flex/delegate_data.cc @@ -14,21 +14,20 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/lite/delegates/flex/delegate_data.h" -#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/lib/core/status.h" namespace tflite { namespace flex { tensorflow::Status DelegateData::Create(std::unique_ptr* data) { - std::vector> devices; + std::vector devices; TF_RETURN_IF_ERROR(tensorflow::DeviceFactory::AddDevices( tensorflow::SessionOptions(), "/job:localhost/replica:0/task:0", &devices)); - std::unique_ptr device_mgr = - absl::make_unique(std::move(devices)); + std::unique_ptr device_mgr( + new tensorflow::DeviceMgr(devices)); // Note that Rendezvous is ref-counted so it will be automatically deleted. tensorflow::Rendezvous* rendezvous = new tensorflow::IntraProcessRendezvous(device_mgr.get()); diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index dfeaebca26..4c3a0717e7 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -2012,13 +2012,13 @@ bool InlineAllFunctions(GraphDef* graphdef) { tensorflow::SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 1}); - std::vector> devices; + std::vector devices; TF_CHECK_OK(tensorflow::DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); tensorflow::FunctionLibraryDefinition fld(tensorflow::OpRegistry::Global(), graphdef_copy.library()); - tensorflow::DeviceMgr device_mgr(std::move(devices)); + tensorflow::DeviceMgr device_mgr(devices); tensorflow::OptimizerOptions o_opts; tensorflow::ProcessFunctionLibraryRuntime pflr( &device_mgr, tensorflow::Env::Default(), TF_GRAPH_DEF_VERSION, &fld, diff --git a/tensorflow/python/client/device_lib.i b/tensorflow/python/client/device_lib.i index 3e579152d5..944e855cee 100644 --- a/tensorflow/python/client/device_lib.i +++ b/tensorflow/python/client/device_lib.i @@ -48,14 +48,17 @@ static std::vector ListDevicesWithSessionConfig( std::vector output; SessionOptions options; options.config = config; - std::vector> devices; + std::vector devices; Status status = DeviceFactory::AddDevices( options, "" /* name_prefix */, &devices); if (!status.ok()) { Set_TF_Status_from_Status(out_status, status); } - for (const std::unique_ptr& device : devices) { + std::vector> device_holder(devices.begin(), + devices.end()); + + for (const Device* device : devices) { const DeviceAttributes& attr = device->attributes(); string attr_serialized; if (!attr.SerializeToString(&attr_serialized)) { diff --git a/tensorflow/python/grappler/tf_optimizer.i b/tensorflow/python/grappler/tf_optimizer.i index b746c3ec26..daa5bc9444 100644 --- a/tensorflow/python/grappler/tf_optimizer.i +++ b/tensorflow/python/grappler/tf_optimizer.i @@ -74,13 +74,13 @@ limitations under the License. void DetectDevices(std::unordered_map* device_map) { tensorflow::SessionOptions options; - std::vector> devices; + std::vector devices; tensorflow::Status status = tensorflow::DeviceFactory::AddDevices(options, "", &devices); if (!status.ok()) { return; } - for (const std::unique_ptr& device : devices) { + for (const tensorflow::Device* device : devices) { tensorflow::DeviceProperties& prop = (*device_map)[device->name()]; prop = tensorflow::grappler::GetDeviceInfo(device->parsed_name()); @@ -88,6 +88,7 @@ void DetectDevices(std::unordered_map* dev // available device memory. const tensorflow::DeviceAttributes& attr = device->attributes(); prop.set_memory_size(attr.memory_limit()); + delete device; } } -- GitLab From d6e0fd35b4baa11f1b3cc5a07c372322387fb2ad Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Sat, 24 Nov 2018 00:28:12 -0800 Subject: [PATCH 275/672] Add update_config_proto to distribution strategies. PiperOrigin-RevId: 222667946 --- .../python/collective_all_reduce_strategy.py | 20 ++++++--- .../collective_all_reduce_strategy_test.py | 45 +++++++++++++------ .../python/mirrored_strategy_multigpu_test.py | 10 +++++ .../python/parameter_server_strategy.py | 20 ++++++--- .../python/parameter_server_strategy_test.py | 27 +++++++++++ .../contrib/distribute/python/tpu_strategy.py | 14 ++++-- .../python/distribute/mirrored_strategy.py | 8 +++- tensorflow/python/training/distribute.py | 30 ++++++++++++- .../v1/tensorflow.distribute.-strategy.pbtxt | 4 ++ .../v2/tensorflow.distribute.-strategy.pbtxt | 4 ++ 10 files changed, 149 insertions(+), 33 deletions(-) diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py index 906377b739..17323e2741 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py @@ -18,6 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import copy + from tensorflow.contrib.distribute.python import mirrored_strategy from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib @@ -263,13 +265,15 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): self._container_strategy(), self._num_gpus_per_worker, cluster_spec, task_type, task_id) - if not session_config: - return + if session_config: + session_config.CopyFrom(self._update_config_proto(session_config)) + def _update_config_proto(self, config_proto): + updated_config = copy.deepcopy(config_proto) # Enable the scoped allocator optimization for CollectiveOps. This # optimization converts many small all-reduces into fewer larger # all-reduces. - rewrite_options = session_config.graph_options.rewrite_options + rewrite_options = updated_config.graph_options.rewrite_options rewrite_options.scoped_allocator_optimization = ( rewriter_config_pb2.RewriterConfig.ON) # We turn on ScopedAllocator only for CollectiveReduce op, i.e. enable_op = @@ -287,20 +291,22 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): # Collective group leader is needed for collective ops to coordinate # workers. if "chief" in self._cluster_spec.jobs: - session_config.experimental.collective_group_leader = ( + updated_config.experimental.collective_group_leader = ( "/job:chief/replica:0/task:0") else: if "worker" not in self._cluster_spec.jobs: raise ValueError( "You must have `chief` or `worker` jobs in the `cluster_spec`.") - session_config.experimental.collective_group_leader = ( + updated_config.experimental.collective_group_leader = ( "/job:worker/replica:0/task:0") # The device filters prevent communication between workers. - del session_config.device_filters[:] - session_config.device_filters.append( + del updated_config.device_filters[:] + updated_config.device_filters.append( "/job:%s/task:%d" % (self._task_type, self._task_id)) + return updated_config + @property def experimental_between_graph(self): return True diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py index eb2b859aa5..09239ffc72 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py @@ -26,6 +26,7 @@ from tensorflow.contrib.distribute.python import combinations from tensorflow.contrib.distribute.python import multi_worker_test_base from tensorflow.contrib.distribute.python import strategy_test_lib from tensorflow.core.protobuf import config_pb2 +from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python import keras from tensorflow.python.data.ops import dataset_ops from tensorflow.python.distribute import cross_device_utils @@ -56,9 +57,6 @@ class CollectiveAllReduceStrategyTestBase( collective_key_base = 0 def setUp(self): - self._run_options = config_pb2.RunOptions() - self._run_options.experimental.collective_graph_key = 6 - # We use a different key_base for each test so that collective keys won't be # reused. # TODO(yuefengz, tucker): enable it to reuse collective keys in different @@ -145,11 +143,10 @@ class CollectiveAllReduceStrategyTestBase( if context.num_gpus() < d.extended._num_gpus_per_worker: return True - sess.run( - variables.global_variables_initializer(), options=self._run_options) + sess.run(variables.global_variables_initializer()) for i in range(10): - b, a = sess.run((before_out, after_out), options=self._run_options) + b, a = sess.run((before_out, after_out)) if i == 0: before, = b after, = a @@ -234,11 +231,9 @@ class CollectiveAllReduceStrategyTestBase( destinations='/cpu:0'))[0] x = distribution.unwrap(x)[0] - sess.run( - variables.global_variables_initializer(), options=self._run_options) + sess.run(variables.global_variables_initializer()) - x_value, reduced_x_value = sess.run([x, reduced_x], - options=self._run_options) + x_value, reduced_x_value = sess.run([x, reduced_x]) self.assertTrue( np.allclose(x_value, reduced_x_value, atol=1e-5), msg=('x_value = %r, reduced_x_value = %r' % (x_value, @@ -342,6 +337,32 @@ class DistributedCollectiveAllReduceStrategyTest( self._test_input_fn_iterator('worker', 1, num_gpus, input_fn, expected_values) + def testUpdateConfigProto(self): + distribution = collective_all_reduce_strategy.CollectiveAllReduceStrategy( + num_gpus_per_worker=2) + distribution.configure( + cluster_spec=self._cluster_spec, task_type='worker', task_id=1) + + config_proto = config_pb2.ConfigProto(device_filters=['to_be_overridden']) + rewrite_options = config_proto.graph_options.rewrite_options + rewrite_options.scoped_allocator_opts.enable_op.append('to_be_removed') + + new_config = distribution.update_config_proto(config_proto) + + # Verify group leader + self.assertEqual('/job:worker/replica:0/task:0', + new_config.experimental.collective_group_leader) + + # Verify device filters. + self.assertEqual(['/job:worker/task:1'], new_config.device_filters) + + # Verify rewrite options. + new_rewrite_options = new_config.graph_options.rewrite_options + self.assertEqual(rewriter_config_pb2.RewriterConfig.ON, + new_rewrite_options.scoped_allocator_optimization) + self.assertEqual(['CollectiveReduce'], + new_rewrite_options.scoped_allocator_opts.enable_op) + class DistributedCollectiveAllReduceStrategyTestWithChief( CollectiveAllReduceStrategyTestBase, parameterized.TestCase): @@ -352,10 +373,6 @@ class DistributedCollectiveAllReduceStrategyTestWithChief( cls._cluster_spec = multi_worker_test_base.create_in_process_cluster( num_workers=3, num_ps=0, has_chief=True) - def setUp(self): - super(DistributedCollectiveAllReduceStrategyTestWithChief, self).setUp() - self._run_options.experimental.collective_graph_key = 7 - @combinations.generate( combinations.combine(mode=['graph'], num_gpus=[0, 1, 2], required_gpus=1)) def testMinimizeLossGraph(self, num_gpus): diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py index 1027da857d..cf6c7f6879 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py @@ -27,6 +27,7 @@ from tensorflow.contrib.distribute.python import combinations from tensorflow.contrib.distribute.python import mirrored_strategy from tensorflow.contrib.distribute.python import multi_worker_test_base from tensorflow.contrib.distribute.python import strategy_test_lib +from tensorflow.core.protobuf import config_pb2 from tensorflow.python.data.ops import dataset_ops from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values @@ -1372,6 +1373,15 @@ class MultiWorkerMirroredStrategyTest( self._test_input_fn_iterator( iterator, distribution.extended.worker_devices, expected_values, sess) + def testUpdateConfigProto(self, distribution): + distribution.configure(cluster_spec={"worker": ["fake1", "fake2"]}) + + config_proto = config_pb2.ConfigProto() + new_config = distribution.update_config_proto(config_proto) + + # Verify isolate_session_state + self.assertTrue(new_config.isolate_session_state) + class MultiWorkerMirroredStrategyTestWithChief( multi_worker_test_base.MultiWorkerTestBase, diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy.py b/tensorflow/contrib/distribute/python/parameter_server_strategy.py index fc2d2b20c9..d127868525 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy.py @@ -18,6 +18,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import copy + from tensorflow.contrib.distribute.python import mirrored_strategy from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib from tensorflow.python.distribute import multi_worker_util @@ -462,21 +464,27 @@ class ParameterServerExtended(distribute_lib.DistributionStrategyExtended): self._initialize_multi_worker(self._num_gpus_per_worker, self._cluster_spec, task_type, task_id) - if not session_config or not self._cluster_spec: - return + if session_config: + session_config.CopyFrom(self._update_config_proto(session_config)) + + def _update_config_proto(self, config_proto): + updated_config = copy.deepcopy(config_proto) + if not self._cluster_spec: + updated_config.isolate_session_state = True + return updated_config - session_config.isolate_session_state = False + updated_config.isolate_session_state = False - assert self._cluster_spec assert self._task_type assert self._task_id is not None # The device filters prevent communication between workers. if self._task_type not in ["chief", "worker"]: return - del session_config.device_filters[:] - session_config.device_filters.extend( + del updated_config.device_filters[:] + updated_config.device_filters.extend( ["/job:%s/task:%d" % (self._task_type, self._task_id), "/job:ps"]) + return updated_config @property def _num_replicas_in_sync(self): diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py index 1ada6a6ba4..3ea9b90f6f 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py @@ -656,6 +656,33 @@ class ParameterServerStrategyTest(ParameterServerStrategyTestBase, num_gpus_per_worker=context.num_gpus()) self._test_global_step_update(strategy) + def testUpdateConfigProtoMultiWorker(self): + distribution = parameter_server_strategy.ParameterServerStrategy( + num_gpus_per_worker=2) + distribution.configure( + cluster_spec=self._cluster_spec, task_type='worker', task_id=1) + + config_proto = config_pb2.ConfigProto(device_filters=['to_be_overridden']) + + new_config = distribution.update_config_proto(config_proto) + + # Verify device filters. + self.assertEqual(['/job:worker/task:1', '/job:ps'], + new_config.device_filters) + + # Verify isolate_session_state + self.assertFalse(new_config.isolate_session_state) + + def testUpdateConfigProtoLocal(self): + distribution = parameter_server_strategy.ParameterServerStrategy( + num_gpus_per_worker=2) + + config_proto = config_pb2.ConfigProto() + new_config = distribution.update_config_proto(config_proto) + + # Verify isolate_session_state + self.assertTrue(new_config.isolate_session_state) + class ParameterServerStrategyWithChiefTest(ParameterServerStrategyTestBase, parameterized.TestCase): diff --git a/tensorflow/contrib/distribute/python/tpu_strategy.py b/tensorflow/contrib/distribute/python/tpu_strategy.py index 94cf548cb4..3e755242f7 100644 --- a/tensorflow/contrib/distribute/python/tpu_strategy.py +++ b/tensorflow/contrib/distribute/python/tpu_strategy.py @@ -21,6 +21,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import copy import functools from tensorflow.contrib.tpu.python.ops import tpu_ops @@ -539,10 +540,15 @@ class TPUExtended(distribute_lib.DistributionStrategyExtended): task_id=None): del cluster_spec, task_type, task_id if session_config: - session_config.isolate_session_state = True - cluster_spec = self._tpu_cluster_resolver.cluster_spec() - if cluster_spec: - session_config.cluster_def.CopyFrom(cluster_spec.as_cluster_def()) + session_config.CopyFrom(self._update_config_proto(session_config)) + + def _update_config_proto(self, config_proto): + updated_config = copy.deepcopy(config_proto) + updated_config.isolate_session_state = True + cluster_spec = self._tpu_cluster_resolver.cluster_spec() + if cluster_spec: + updated_config.cluster_def.CopyFrom(cluster_spec.as_cluster_def()) + return updated_config # TODO(priyag): Delete this once all strategies use global batch size. @property diff --git a/tensorflow/python/distribute/mirrored_strategy.py b/tensorflow/python/distribute/mirrored_strategy.py index 7ed096b863..7094ed6628 100644 --- a/tensorflow/python/distribute/mirrored_strategy.py +++ b/tensorflow/python/distribute/mirrored_strategy.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function import contextlib +import copy import functools import threading @@ -562,7 +563,7 @@ class MirroredExtended(distribute_lib.DistributionStrategyExtended): del task_type, task_id if session_config: - session_config.isolate_session_state = True + session_config.CopyFrom(self._update_config_proto(session_config)) if cluster_spec: self._initialize_multi_worker(self._num_gpus, cluster_spec) @@ -583,6 +584,11 @@ class MirroredExtended(distribute_lib.DistributionStrategyExtended): self._cross_device_ops = cross_device_ops_lib.choose_the_best( self._devices, session_config=session_config) + def _update_config_proto(self, config_proto): + updated_config = copy.deepcopy(config_proto) + updated_config.isolate_session_state = True + return updated_config + def _get_cross_device_ops(self): if self._cross_device_ops is None: self._cross_device_ops = ( diff --git a/tensorflow/python/training/distribute.py b/tensorflow/python/training/distribute.py index ba3334108b..a976062249 100644 --- a/tensorflow/python/training/distribute.py +++ b/tensorflow/python/training/distribute.py @@ -610,10 +610,35 @@ class DistributionStrategy(object): cluster_spec=None, task_type=None, task_id=None): - """Configures the strategy class.""" + # pylint: disable=g-doc-return-or-yield,g-doc-args + """DEPRECATED: use `update_config_proto` instead. + + Configures the strategy class. + + DEPRECATED: This method's functionality has been split into the strategy + constructor and `update_config_proto`. In the future, we will allow passing + cluster and config_proto to the constructor to configure the strategy. And + `update_config_proto` can be used to update the config_proto based on the + specific strategy. + """ return self._extended._configure( # pylint: disable=protected-access session_config, cluster_spec, task_type, task_id) + def update_config_proto(self, config_proto): + """Returns a copy of `config_proto` modified for use with this strategy. + + The updated config has something needed to run a strategy, e.g. + configuration to run collective ops, or device filters to improve + distributed training performance. + + Args: + config_proto: a `tf.ConfigProto` object. + + Returns: + The updated copy of the `config_proto`. + """ + return self._extended._update_config_proto(config_proto) # pylint: disable=protected-access + @property @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` def should_init(self): @@ -1345,6 +1370,9 @@ class DistributionStrategyExtended(object): """Configures the strategy class.""" del session_config, cluster_spec, task_type, task_id + def _update_config_proto(self, config_proto): + return copy.deepcopy(config_proto) + @property def experimental_should_init(self): """Whether initialization is needed.""" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt index 4fe035b474..f0b0cd0d38 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt @@ -122,6 +122,10 @@ tf_class { name: "update" argspec: "args=[\'self\', \'var\', \'fn\'], varargs=args, keywords=kwargs, defaults=None" } + member_method { + name: "update_config_proto" + argspec: "args=[\'self\', \'config_proto\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "update_non_slot" argspec: "args=[\'self\', \'colocate_with\', \'fn\'], varargs=args, keywords=kwargs, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt index 4fe035b474..f0b0cd0d38 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt @@ -122,6 +122,10 @@ tf_class { name: "update" argspec: "args=[\'self\', \'var\', \'fn\'], varargs=args, keywords=kwargs, defaults=None" } + member_method { + name: "update_config_proto" + argspec: "args=[\'self\', \'config_proto\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "update_non_slot" argspec: "args=[\'self\', \'colocate_with\', \'fn\'], varargs=args, keywords=kwargs, defaults=None" -- GitLab From 2395637465c0b58a7e62460f52029dee56f1538e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sat, 24 Nov 2018 01:02:05 -0800 Subject: [PATCH 276/672] compat: Update forward compatibility horizon to 2018-11-24 PiperOrigin-RevId: 222669714 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 9150d91409..969b95dd0d 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 23) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 24) @tf_export("compat.forward_compatible") -- GitLab From e3a9d2a1eb42a63e6e9c704b3c71488720d1b640 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sat, 24 Nov 2018 08:22:05 -0800 Subject: [PATCH 277/672] Clean up some text in cross_device_ops. PiperOrigin-RevId: 222686318 --- .../python/distribute/cross_device_ops.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tensorflow/python/distribute/cross_device_ops.py b/tensorflow/python/distribute/cross_device_ops.py index de25b718bf..87b6f41eba 100644 --- a/tensorflow/python/distribute/cross_device_ops.py +++ b/tensorflow/python/distribute/cross_device_ops.py @@ -916,15 +916,15 @@ def _choose_all_reduce_algorithm(device_links): def choose_the_best(devices, session_config=None): - """Find the best subclass of CrossDeviceOps given a tensorflow session. + """Find the best subclass of CrossDeviceOps given a session config. Args: - devices: a list of devices passed for distribute strategy. - session_config: a tensorflow session config or None. If None, it will make - deciesion based on all local devices. + devices: a list of devices passed to `tf.distribute.Strategy`. + session_config: a `tf.ConfigProto` or `None`. If `None`, it will make + decision based on all local devices. Returns: - a subclass of CrossDeviceOps. + A subclass of `CrossDeviceOps`. """ requested_devices = set([device_util.canonicalize(d) for d in devices]) machine_devices = device_lib.list_local_devices(session_config=session_config) @@ -937,13 +937,13 @@ def choose_the_best(devices, session_config=None): "Device is available but not used by distribute strategy: %s", d.name) if len(using_devices) != len(requested_devices): - logging.warning("Not all devices in distribute strategy are visible by " - "TensorFlow sessions.") + logging.warning("Not all devices in `tf.distribute.Strategy` are visible " + "to TensorFlow.") return ReductionToOneDeviceCrossDeviceOps() if any(d.device_type.lower() != "gpu" for d in using_devices): - logging.warning("Not all devices in DistributionStrategy are visible to " - "TensorFlow session.") + logging.warning("Not all devices in `tf.distribute.Strategy` are visible " + "to TensorFlow.") return ReductionToOneDeviceCrossDeviceOps() device_links = [[] for _ in range(len(using_devices))] -- GitLab From 2dfefe0b988bb1c6468ae0318825e96459fdfdba Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sat, 24 Nov 2018 10:06:30 -0800 Subject: [PATCH 278/672] Remove DNNEstimator from contrib PiperOrigin-RevId: 222690226 --- tensorflow/contrib/estimator/BUILD | 13 ------- tensorflow/contrib/estimator/__init__.py | 1 - .../contrib/estimator/python/estimator/dnn.py | 32 ----------------- .../python/estimator/dnn_linear_combined.py | 34 ------------------- 4 files changed, 80 deletions(-) delete mode 100644 tensorflow/contrib/estimator/python/estimator/dnn.py delete mode 100644 tensorflow/contrib/estimator/python/estimator/dnn_linear_combined.py diff --git a/tensorflow/contrib/estimator/BUILD b/tensorflow/contrib/estimator/BUILD index 37f253d9c1..a8d3a7d9f3 100644 --- a/tensorflow/contrib/estimator/BUILD +++ b/tensorflow/contrib/estimator/BUILD @@ -16,7 +16,6 @@ py_library( srcs_version = "PY2AND3", deps = [ ":boosted_trees", - ":dnn", ":dnn_with_layer_annotations", ":early_stopping", ":expect_tensorflow_estimator_installed", @@ -47,18 +46,6 @@ py_library( ], ) -py_library( - name = "dnn", - srcs = ["python/estimator/dnn.py"], - srcs_version = "PY2AND3", - deps = [ - ":expect_tensorflow_estimator_installed", - "//tensorflow:tensorflow_py_no_contrib", - "//tensorflow/python/estimator", - "//tensorflow/python/estimator:dnn", - ], -) - py_library( name = "dnn_with_layer_annotations", srcs = ["python/estimator/dnn_with_layer_annotations.py"], diff --git a/tensorflow/contrib/estimator/__init__.py b/tensorflow/contrib/estimator/__init__.py index 80d5962762..d8e13cb793 100644 --- a/tensorflow/contrib/estimator/__init__.py +++ b/tensorflow/contrib/estimator/__init__.py @@ -58,7 +58,6 @@ _allowed_symbols = [ 'multi_label_head', 'poisson_regression_head', 'regression_head', - 'DNNEstimator', 'LinearEstimator', 'boosted_trees_classifier_train_in_memory', 'boosted_trees_regressor_train_in_memory', diff --git a/tensorflow/contrib/estimator/python/estimator/dnn.py b/tensorflow/contrib/estimator/python/estimator/dnn.py deleted file mode 100644 index 10f657df8d..0000000000 --- a/tensorflow/contrib/estimator/python/estimator/dnn.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2018 The TensorFlow Authors. 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. -# ============================================================================== -"""dnn python module. - -Importing from tensorflow.python.estimator is unsupported -and will soon break! -""" -# pylint: disable=unused-import,g-bad-import-order,g-import-not-at-top,wildcard-import - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from tensorflow_estimator.contrib.estimator.python.estimator import dnn - -# Include attrs that start with single underscore. -_HAS_DYNAMIC_ATTRIBUTES = True -dnn.__all__ = [s for s in dir(dnn) if not s.startswith('__')] - -from tensorflow_estimator.contrib.estimator.python.estimator.dnn import * diff --git a/tensorflow/contrib/estimator/python/estimator/dnn_linear_combined.py b/tensorflow/contrib/estimator/python/estimator/dnn_linear_combined.py deleted file mode 100644 index 7894418c4a..0000000000 --- a/tensorflow/contrib/estimator/python/estimator/dnn_linear_combined.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2018 The TensorFlow Authors. 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. -# ============================================================================== -"""dnn_linear_combined python module. - -Importing from tensorflow.python.estimator is unsupported -and will soon break! -""" -# pylint: disable=unused-import,g-bad-import-order,g-import-not-at-top,wildcard-import - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from tensorflow_estimator.contrib.estimator.python.estimator import dnn_linear_combined - -# Include attrs that start with single underscore. -_HAS_DYNAMIC_ATTRIBUTES = True -dnn_linear_combined.__all__ = [ - s for s in dir(dnn_linear_combined) if not s.startswith('__') -] - -from tensorflow_estimator.contrib.estimator.python.estimator.dnn_linear_combined import * -- GitLab From e4149e99dd0767a3ce6f7c240b93eaf5e0843e22 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sat, 24 Nov 2018 10:35:52 -0800 Subject: [PATCH 279/672] Remove LinearEstimator from contrib PiperOrigin-RevId: 222691162 --- tensorflow/contrib/estimator/BUILD | 12 ------- tensorflow/contrib/estimator/__init__.py | 1 - .../estimator/python/estimator/linear.py | 32 ------------------- 3 files changed, 45 deletions(-) delete mode 100644 tensorflow/contrib/estimator/python/estimator/linear.py diff --git a/tensorflow/contrib/estimator/BUILD b/tensorflow/contrib/estimator/BUILD index a8d3a7d9f3..a888379f13 100644 --- a/tensorflow/contrib/estimator/BUILD +++ b/tensorflow/contrib/estimator/BUILD @@ -24,7 +24,6 @@ py_library( ":extenders", ":head", ":hooks", - ":linear", ":logit_fns", ":multi_head", ":replicate_model_fn", @@ -131,17 +130,6 @@ py_library( ], ) -py_library( - name = "linear", - srcs = ["python/estimator/linear.py"], - srcs_version = "PY2AND3", - deps = [ - ":expect_tensorflow_estimator_installed", - "//tensorflow/python/estimator", - "//tensorflow/python/estimator:linear", - ], -) - py_library( name = "logit_fns", srcs = [ diff --git a/tensorflow/contrib/estimator/__init__.py b/tensorflow/contrib/estimator/__init__.py index d8e13cb793..7d61247e7e 100644 --- a/tensorflow/contrib/estimator/__init__.py +++ b/tensorflow/contrib/estimator/__init__.py @@ -58,7 +58,6 @@ _allowed_symbols = [ 'multi_label_head', 'poisson_regression_head', 'regression_head', - 'LinearEstimator', 'boosted_trees_classifier_train_in_memory', 'boosted_trees_regressor_train_in_memory', 'call_logit_fn', diff --git a/tensorflow/contrib/estimator/python/estimator/linear.py b/tensorflow/contrib/estimator/python/estimator/linear.py deleted file mode 100644 index b6a4444f66..0000000000 --- a/tensorflow/contrib/estimator/python/estimator/linear.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2018 The TensorFlow Authors. 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. -# ============================================================================== -"""linear python module. - -Importing from tensorflow.python.estimator is unsupported -and will soon break! -""" -# pylint: disable=unused-import,g-bad-import-order,g-import-not-at-top,wildcard-import - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from tensorflow_estimator.contrib.estimator.python.estimator import linear - -# Include attrs that start with single underscore. -_HAS_DYNAMIC_ATTRIBUTES = True -linear.__all__ = [s for s in dir(linear) if not s.startswith('__')] - -from tensorflow_estimator.contrib.estimator.python.estimator.linear import * -- GitLab From 31ac32eb03415c31066ce5b936c80934d83d84ed Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Sun, 25 Nov 2018 00:47:04 -0800 Subject: [PATCH 280/672] - Adds `MeanSquaredError` V2 loss implementation - Adds support for the V2 losses in Keras. With the new losses the default loss reduction function in Keras has been changed from `weighted_mean` to `sum_over_batch_size`. PiperOrigin-RevId: 222720535 --- .../contrib/keras/api/keras/utils/__init__.py | 1 + tensorflow/python/keras/BUILD | 1 + tensorflow/python/keras/engine/training.py | 29 ++- .../python/keras/engine/training_eager.py | 31 ++- .../python/keras/engine/training_test.py | 32 ++- .../python/keras/engine/training_utils.py | 20 +- tensorflow/python/keras/losses.py | 103 +++++++++ tensorflow/python/keras/losses_test.py | 96 ++++++++ tensorflow/python/keras/metrics.py | 73 +----- tensorflow/python/keras/utils/__init__.py | 1 + tensorflow/python/keras/utils/losses_utils.py | 213 ++++++++++++++++++ tensorflow/python/ops/losses/losses_impl.py | 29 +-- .../v1/tensorflow.losses.-reduction.pbtxt | 1 - .../tensorflow.keras.losses.-reduction.pbtxt | 28 +++ .../golden/v2/tensorflow.keras.losses.pbtxt | 4 + .../v2/tensorflow.losses.-reduction.pbtxt | 4 +- 16 files changed, 547 insertions(+), 119 deletions(-) create mode 100644 tensorflow/python/keras/utils/losses_utils.py create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt diff --git a/tensorflow/contrib/keras/api/keras/utils/__init__.py b/tensorflow/contrib/keras/api/keras/utils/__init__.py index 47cd01b924..3b9fa1b230 100644 --- a/tensorflow/contrib/keras/api/keras/utils/__init__.py +++ b/tensorflow/contrib/keras/api/keras/utils/__init__.py @@ -30,6 +30,7 @@ from tensorflow.python.keras.utils.generic_utils import Progbar from tensorflow.python.keras.utils.generic_utils import serialize_keras_object from tensorflow.python.keras.utils.io_utils import HDF5Matrix from tensorflow.python.keras.utils.layer_utils import convert_all_kernels_in_model +from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions from tensorflow.python.keras.utils.np_utils import normalize from tensorflow.python.keras.utils.np_utils import to_categorical from tensorflow.python.keras.utils.vis_utils import plot_model diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index 540dd03768..fa1cad2359 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -142,6 +142,7 @@ py_library( "regularizers.py", "utils/data_utils.py", "utils/io_utils.py", + "utils/losses_utils.py", ], srcs_version = "PY2AND3", deps = [ diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index 888d8eb942..8c564ed61b 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -41,6 +41,8 @@ from tensorflow.python.keras.engine import training_utils from tensorflow.python.keras.engine.network import Network from tensorflow.python.keras.utils import data_utils from tensorflow.python.keras.utils.generic_utils import slice_arrays +from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions +from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import optimizer as tf_optimizer_module from tensorflow.python.training.checkpointable import base as checkpointable @@ -568,16 +570,16 @@ class Model(Network): '" missing from loss dictionary. We assume ' 'this was done on purpose. The fit and evaluate APIs will not be ' 'expecting any data to be passed to "' + name + '".') - loss_functions.append(losses.get(loss.get(name))) + loss_functions.append(training_utils.get_loss_function(loss.get(name))) elif isinstance(loss, list): if len(loss) != len(self.outputs): raise ValueError('When passing a list as loss, ' 'it should have one entry per model outputs. ' 'The model has ' + str(len(self.outputs)) + ' outputs, but you passed loss=' + str(loss)) - loss_functions = [losses.get(l) for l in loss] + loss_functions = [training_utils.get_loss_function(l) for l in loss] else: - loss_function = losses.get(loss) + loss_function = training_utils.get_loss_function(loss) loss_functions = [loss_function for _ in range(len(self.outputs))] self.loss_functions = loss_functions @@ -730,8 +732,21 @@ class Model(Network): mask = masks[i] loss_weight = loss_weights_list[i] with K.name_scope(self.output_names[i] + '_loss'): - weighted_loss = training_utils.weighted_masked_objective(loss_fn) - output_loss = weighted_loss(y_true, y_pred, sample_weight, mask) + if isinstance(loss_fn, losses.Loss): + if mask is not None: + mask = math_ops.cast(mask, y_pred.dtype) + # Update weights with mask. + if sample_weight is None: + sample_weight = mask + else: + # Update dimensions of weights to match with mask if possible. + mask, _, sample_weight = squeeze_or_expand_dimensions( + mask, None, sample_weight) + sample_weight *= mask + output_loss = loss_fn(y_true, y_pred, sample_weight=sample_weight) + else: + weighted_loss = training_utils.weighted_masked_objective(loss_fn) + output_loss = weighted_loss(y_true, y_pred, sample_weight, mask) if len(self.outputs) > 1: # Keep track of the un-aggregated loss result tensor. @@ -739,8 +754,10 @@ class Model(Network): '_loss'] = output_loss # Keep track of stateful result tensor and function for the loss. + loss_name = loss_fn.name if isinstance( + loss_fn, losses.Loss) else loss_fn.__name__ mean_wrapped_loss = metrics_module.MeanMetricWrapper( - loss_fn, name=loss_fn.__name__) + loss_fn, name=loss_name) result_tensor = training_utils.call_metric_function( mean_wrapped_loss, y_true, diff --git a/tensorflow/python/keras/engine/training_eager.py b/tensorflow/python/keras/engine/training_eager.py index b2dace84aa..cd85c365db 100644 --- a/tensorflow/python/keras/engine/training_eager.py +++ b/tensorflow/python/keras/engine/training_eager.py @@ -31,9 +31,11 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util from tensorflow.python.keras import backend from tensorflow.python.keras import callbacks as cbks +from tensorflow.python.keras import losses as losses_module from tensorflow.python.keras import metrics as metrics_module from tensorflow.python.keras.engine import training_utils from tensorflow.python.keras.utils import generic_utils +from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging @@ -128,11 +130,24 @@ def _model_loss(model, else: weights = None mask = masks[i] - - weighted_masked_fn = training_utils.weighted_masked_objective(loss_fn) with backend.name_scope(model.output_names[i] + '_loss'): - output_loss = weighted_masked_fn( - targets[i], outs[i], weights, mask=mask) + if isinstance(loss_fn, losses_module.Loss): + if mask is not None: + mask = math_ops.cast(mask, outs[i].dtype) + # Update weights with mask. + if weights is None: + weights = mask + else: + # Update dimensions of weights to match with mask if possible. + mask, _, weights = squeeze_or_expand_dimensions( + mask, None, weights) + weights *= mask + output_loss = loss_fn(targets[i], outs[i], sample_weight=weights) + else: + weighted_masked_fn = training_utils.weighted_masked_objective(loss_fn) + output_loss = weighted_masked_fn( + targets[i], outs[i], weights, mask=mask) + # If the number of outputs is 1 then we don't append the loss metric # associated with each model output. When there are multiple outputs # associated with a model, each output's loss is calculated and returned @@ -351,8 +366,10 @@ def iterator_test_loop(model, inputs, steps, verbose=0): output_loss_metrics = [] for i in range(len(model.outputs)): loss_fn = model.loss_functions[i] + loss_name = loss_fn.name if isinstance( + loss_fn, losses_module.Loss) else loss_fn.__name__ mean_wrapped_loss = metrics_module.MeanMetricWrapper( - loss_fn, name=loss_fn.__name__) + loss_fn, name=loss_name) output_loss_metrics.append(mean_wrapped_loss) num_samples = 0 @@ -744,8 +761,10 @@ def fit_loop(model, output_loss_metrics = [] for i in range(len(model.outputs)): loss_fn = model.loss_functions[i] + loss_name = loss_fn.name if isinstance( + loss_fn, losses_module.Loss) else loss_fn.__name__ mean_wrapped_loss = metrics_module.MeanMetricWrapper( - loss_fn, name=loss_fn.__name__) + loss_fn, name=loss_name) output_loss_metrics.append(mean_wrapped_loss) callbacks.on_train_begin() diff --git a/tensorflow/python/keras/engine/training_test.py b/tensorflow/python/keras/engine/training_test.py index 1009ef7138..97dfe6d900 100644 --- a/tensorflow/python/keras/engine/training_test.py +++ b/tensorflow/python/keras/engine/training_test.py @@ -600,6 +600,34 @@ class TrainingTest(test.TestCase): np.ones((10, 10), 'float32'), np.ones((10, 1), 'float32'), epochs=10) self.assertTrue('Epoch 5/10' in mock_stdout.getvalue()) + @tf_test_util.run_in_graph_and_eager_modes + def test_training_with_loss_instance(self): + a = keras.layers.Input(shape=(3,), name='input_a') + b = keras.layers.Input(shape=(3,), name='input_b') + + dense = keras.layers.Dense(4, name='dense') + c = dense(a) + d = dense(b) + e = keras.layers.Dropout(0.5, name='dropout')(c) + + model = keras.models.Model([a, b], [d, e]) + loss_weights = [1., 0.5] + model.compile( + RMSPropOptimizer(learning_rate=0.001), + loss=keras.losses.MeanSquaredError(), + metrics=[metrics_module.CategoricalAccuracy(), 'mae'], + loss_weights=loss_weights) + + input_a_np = np.random.random((10, 3)) + input_b_np = np.random.random((10, 3)) + + output_d_np = np.random.random((10, 4)) + output_e_np = np.random.random((10, 4)) + + model.fit([input_a_np, input_b_np], [output_d_np, output_e_np], + epochs=1, + batch_size=5) + class TestExceptionsAndWarnings(test.TestCase): @@ -1918,7 +1946,7 @@ class TestTrainingWithMetrics(test.TestCase): w = np.array([[3., 4.], [1., 2.]]) outs = model.evaluate(x, y, sample_weight=w) - self.assertArrayNear(outs, [0.3, 0.7, 0.3], .001) + self.assertArrayNear(outs, [0.75, 0.7, 0.3], .001) # Verify that metric value is same with arbitrary weights and batch size. x = np.random.random((50, 2, 1)) @@ -1988,7 +2016,7 @@ class TestTrainingWithMetrics(test.TestCase): # verify that masking is combined with sample weights. w = np.array([3, 2, 4]) scores = model.train_on_batch(x, y, sample_weight=w) - self.assertArrayNear(scores, [0.2, 0.8], 0.1) + self.assertArrayNear(scores, [0.3328, 0.8], 0.001) def test_add_metric_with_tensor_on_model_in_graph_mode(self): with self.cached_session(): diff --git a/tensorflow/python/keras/engine/training_utils.py b/tensorflow/python/keras/engine/training_utils.py index 1735db8b6b..347582aa95 100644 --- a/tensorflow/python/keras/engine/training_utils.py +++ b/tensorflow/python/keras/engine/training_utils.py @@ -35,6 +35,7 @@ from tensorflow.python.keras import backend as K from tensorflow.python.keras import losses from tensorflow.python.keras import metrics as metrics_module from tensorflow.python.keras.engine import base_layer +from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import weights_broadcast_ops @@ -632,15 +633,14 @@ def weighted_masked_objective(fn): weights = mask else: # Update dimensions of weights to match with mask if possible. - mask, _, weights = metrics_module.squeeze_or_expand_dimensions( - mask, None, weights) + mask, _, weights = squeeze_or_expand_dimensions(mask, None, weights) weights *= mask # Apply sample weighting. if weights is not None: # Update dimensions of weights to match with values if possible. - score_array, _, weights = metrics_module.squeeze_or_expand_dimensions( + score_array, _, weights = squeeze_or_expand_dimensions( score_array, None, weights) try: # Broadcast weights if possible. @@ -838,12 +838,22 @@ def call_metric_function(metric_fn, y_true, y_pred, weights=None, mask=None): return metric_fn(y_true, y_pred, sample_weight=mask) # Update dimensions of weights to match with mask. - mask, _, weights = metrics_module.squeeze_or_expand_dimensions( - mask, None, weights) + mask, _, weights = squeeze_or_expand_dimensions(mask, None, weights) weights *= mask return metric_fn(y_true, y_pred, sample_weight=weights) +def get_loss_function(loss): + """Returns the loss function corresponding to the given loss input.""" + if loss is None or isinstance(loss, losses.Loss): + return loss + + # TODO(psv): After we have added all V2 losses, update this function. + if loss in ['mse', 'MSE', 'mean_squared_error']: + return losses.MeanSquaredError() + return losses.get(loss) + + def validate_iterator_input(x, y, sample_weight, validation_split=None): """Validates user input arguments when a dataset iterator is passed. diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index f871ee409e..0e274d4d50 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -19,17 +19,120 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import abc + import six +from tensorflow.python.framework import ops from tensorflow.python.keras import backend as K from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object +from tensorflow.python.keras.utils.losses_utils import compute_weighted_loss +from tensorflow.python.keras.utils.losses_utils import ReductionV2 from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn from tensorflow.python.ops.losses import losses_impl from tensorflow.python.util.tf_export import tf_export +class Loss(object): + """Loss base class. + + To be implemented by subclasses: + * `call()`: Contains the logic for loss calculation using `y_true`, `y_pred`. + + Example subclass implementation: + ``` + class MeanSquaredError(Loss): + def call(self, y_true, y_pred): + y_pred = ops.convert_to_tensor(y_pred) + y_true = math_ops.cast(y_true, y_pred.dtype) + return K.mean(math_ops.square(y_pred - y_true), axis=-1) + ``` + + Args: + reduction: Type of `tf.losses.Reduction` to apply to loss. Default value is + `SUM_OVER_BATCH_SIZE`. + name: Optional name for the op. + """ + + def __init__(self, reduction=ReductionV2.SUM_OVER_BATCH_SIZE, name=None): + self.reduction = reduction + self.name = name + + def __call__(self, y_true, y_pred, sample_weight=None): + """Invokes the `Loss` instance. + + Args: + y_true: Ground truth values. + y_pred: The predicted values. + sample_weight: Optional `Tensor` whose rank is either 0, or the same rank + as `y_true`, or is broadcastable to `y_true`. `sample_weight` acts as a + coefficient for the loss. If a scalar is provided, then the loss is + simply scaled by the given value. If `sample_weight` is a tensor of size + `[batch_size]`, then the total loss for each sample of the batch is + rescaled by the corresponding element in the `sample_weight` vector. If + the shape of `sample_weight` matches the shape of `y_pred`, then the + loss of each measurable element of `y_pred` is scaled by the + corresponding value of `sample_weight`. + + Returns: + Weighted loss float `Tensor`. If `reduction` is `NONE`, this has the same + shape as `y_true`; otherwise, it is scalar. + + Raises: + ValueError: If the shape of `sample_weight` is invalid. + """ + with ops.name_scope(self.name, format(self.__class__.__name__), + (y_pred, y_true, sample_weight)): + losses = self.call(y_true, y_pred) + return compute_weighted_loss( + losses, sample_weight, reduction=self.reduction) + + @classmethod + def from_config(cls, config): + """Instantiates a `Loss` from its config (output of `get_config()`). + + Args: + config: Output of `get_config()`. + + Returns: + A `Loss` instance. + """ + return cls(**config) + + def get_config(self): + return {'reduction': self.reduction, 'name': self.name} + + @abc.abstractmethod + def call(self, y_true, y_pred): + """Invokes the `Loss` instance. + + Args: + y_true: Ground truth values, with the same shape as 'y_pred'. + y_pred: The predicted values. + """ + NotImplementedError('Must be implemented in subclasses.') + + +class MeanSquaredError(Loss): + """Computes the mean of squares of errors between labels and predictions.""" + + def call(self, y_true, y_pred): + """Invokes the `MeanSquaredError` instance. + + Args: + y_true: Ground truth values. + y_pred: The predicted values. + + Returns: + Mean squared error losses. + """ + y_pred = ops.convert_to_tensor(y_pred) + y_true = math_ops.cast(y_true, y_pred.dtype) + return mean_squared_error(y_true, y_pred) + + @tf_export('keras.metrics.mean_squared_error', 'keras.metrics.mse', 'keras.metrics.MSE', diff --git a/tensorflow/python/keras/losses_test.py b/tensorflow/python/keras/losses_test.py index c7015270ac..b056f920ab 100644 --- a/tensorflow/python/keras/losses_test.py +++ b/tensorflow/python/keras/losses_test.py @@ -24,6 +24,9 @@ import shutil import numpy as np from tensorflow.python import keras +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.platform import test try: @@ -138,5 +141,98 @@ class KerasLossesTest(test.TestCase): loaded_model.predict(np.random.rand(128, 2)) +@test_util.run_all_in_graph_and_eager_modes +class MeanSquaredErrorTest(test.TestCase): + + def test_config(self): + mse_obj = keras.losses.MeanSquaredError( + reduction=keras.losses.ReductionV2.SUM, name='mse_1') + self.assertEqual(mse_obj.name, 'mse_1') + self.assertEqual(mse_obj.reduction, keras.losses.ReductionV2.SUM) + + def test_all_correct_unweighted(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3)) + loss = mse_obj(y_true, y_true) + self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) + + def test_unweighted(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mse_obj(y_true, y_pred) + self.assertAlmostEqual(self.evaluate(loss), 49.5, 3) + + def test_scalar_weighted(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mse_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), 113.85, 3) + + def test_sample_weighted(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + sample_weight = constant_op.constant([1.2, 3.4], shape=(2, 1)) + loss = mse_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 767.8 / 6, 3) + + def test_timestep_weighted(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3, 1), + dtype=dtypes.float32) + sample_weight = constant_op.constant([3, 6, 5, 0, 4, 2], shape=(2, 3)) + loss = mse_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 587 / 6, 3) + + def test_zero_weighted(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mse_obj(y_true, y_pred, sample_weight=0) + self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) + + def test_invalid_sample_weight(self): + mse_obj = keras.losses.MeanSquaredError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3, 1)) + sample_weight = constant_op.constant([3, 6, 5, 0], shape=(2, 2)) + with self.assertRaisesRegexp( + ValueError, r'Shapes \(2, 2\) and \(2, 3\) are incompatible'): + mse_obj(y_true, y_pred, sample_weight=sample_weight) + + def test_no_reduction(self): + mse_obj = keras.losses.MeanSquaredError( + reduction=keras.losses.ReductionV2.NONE) + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mse_obj(y_true, y_pred, sample_weight=2.3) + loss = self.evaluate(loss) + self.assertArrayNear(loss, [84.3333, 143.3666], 1e-3) + + def test_sum_reduction(self): + mse_obj = keras.losses.MeanSquaredError( + reduction=keras.losses.ReductionV2.SUM) + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mse_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), 227.69998, 3) + + if __name__ == '__main__': test.main() diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 668c56243b..1ddeb0bee7 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -48,9 +48,9 @@ from tensorflow.python.keras.losses import sparse_categorical_crossentropy from tensorflow.python.keras.losses import squared_hinge from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object +from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops -from tensorflow.python.ops import confusion_matrix from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import init_ops from tensorflow.python.ops import math_ops @@ -172,77 +172,6 @@ def weakmethod(method): return inner -def squeeze_or_expand_dimensions(y_pred, y_true, sample_weight): - """Squeeze or expand last dimension if needed. - - 1. Squeezes last dim of `y_pred` or `y_true` if their rank differs by 1 - (using `confusion_matrix.remove_squeezable_dimensions`). - 2. Squeezes or expands last dim of `sample_weight` if its rank differs by 1 - from the new rank of `y_pred`. - If `sample_weight` is scalar, it is kept scalar. - - This will use static shape if available. Otherwise, it will add graph - operations, which could result in a performance hit. - - Args: - y_pred: Predicted values, a `Tensor` of arbitrary dimensions. - y_true: Optional label `Tensor` whose dimensions match `y_pred`. - sample_weight: Optional weight scalar or `Tensor` whose dimensions match - `y_pred`. - - Returns: - Tuple of `y_pred`, `y_true` and `sample_weight`. Each of them possibly has - the last dimension squeezed, - `sample_weight` could be extended by one dimension. - """ - if y_true is not None: - # squeeze last dim of `y_pred` or `y_true` if their rank differs by 1 - y_true, y_pred = confusion_matrix.remove_squeezable_dimensions( - y_true, y_pred) - - if sample_weight is None: - return y_pred, y_true, None - - sample_weight = ops.convert_to_tensor(sample_weight) - weights_shape = sample_weight.get_shape() - weights_rank = weights_shape.ndims - if weights_rank == 0: # If weights is scalar, do nothing. - return y_pred, y_true, sample_weight - - y_pred_shape = y_pred.get_shape() - y_pred_rank = y_pred_shape.ndims - if (y_pred_rank is not None) and (weights_rank is not None): - # Use static rank. - if weights_rank - y_pred_rank == 1: - sample_weight = array_ops.squeeze(sample_weight, [-1]) - elif y_pred_rank - weights_rank == 1: - sample_weight = array_ops.expand_dims(sample_weight, [-1]) - return y_pred, y_true, sample_weight - - # Use dynamic rank. - weights_rank_tensor = array_ops.rank(sample_weight) - rank_diff = weights_rank_tensor - array_ops.rank(y_pred) - maybe_squeeze_weights = lambda: array_ops.squeeze(sample_weight, [-1]) - - def _maybe_expand_weights(): - return control_flow_ops.cond( - math_ops.equal(rank_diff, - -1), lambda: array_ops.expand_dims(sample_weight, [-1]), - lambda: sample_weight) - - def _maybe_adjust_weights(): - return control_flow_ops.cond( - math_ops.equal(rank_diff, 1), maybe_squeeze_weights, - _maybe_expand_weights) - - # squeeze or expand last dim of `sample_weight` if its rank differs by 1 - # from the new rank of `y_pred`. - sample_weight = control_flow_ops.cond( - math_ops.equal(weights_rank_tensor, 0), lambda: sample_weight, - _maybe_adjust_weights) - return y_pred, y_true, sample_weight - - class _ConfusionMatrix(Enum): TRUE_POSITIVES = 'tp' FALSE_POSITIVES = 'fp' diff --git a/tensorflow/python/keras/utils/__init__.py b/tensorflow/python/keras/utils/__init__.py index 8939044f71..61940ad789 100644 --- a/tensorflow/python/keras/utils/__init__.py +++ b/tensorflow/python/keras/utils/__init__.py @@ -34,6 +34,7 @@ from tensorflow.python.keras.utils.generic_utils import serialize_keras_object from tensorflow.python.keras.utils.io_utils import HDF5Matrix from tensorflow.python.keras.utils.layer_utils import convert_all_kernels_in_model from tensorflow.python.keras.utils.layer_utils import get_source_inputs +from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions from tensorflow.python.keras.utils.multi_gpu_utils import multi_gpu_model from tensorflow.python.keras.utils.np_utils import normalize from tensorflow.python.keras.utils.np_utils import to_categorical diff --git a/tensorflow/python/keras/utils/losses_utils.py b/tensorflow/python/keras/utils/losses_utils.py new file mode 100644 index 0000000000..d11d785356 --- /dev/null +++ b/tensorflow/python/keras/utils/losses_utils.py @@ -0,0 +1,213 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +# pylint: disable=protected-access +"""Utilities related to loss functions.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.keras import backend as K +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import confusion_matrix +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import weights_broadcast_ops +from tensorflow.python.util.tf_export import tf_export + + +@tf_export('losses.Reduction', 'keras.losses.Reduction', v1=[]) +class ReductionV2(object): + """Types of loss reduction. + + Contains the following values: + `NONE`: Un-reduced weighted losses with the same shape as input. + `SUM`: Scalar sum of weighted losses. + `SUM_OVER_BATCH_SIZE`: Scalar `SUM` divided by number of elements in losses. + """ + + NONE = None + SUM = 'sum' + SUM_OVER_BATCH_SIZE = 'sum_over_batch_size' + + @classmethod + def all(cls): + return (cls.NONE, cls.SUM, cls.SUM_OVER_BATCH_SIZE) + + @classmethod + def validate(cls, key): + if key not in cls.all(): + raise ValueError('Invalid Reduction Key %s.' % key) + + +def squeeze_or_expand_dimensions(y_pred, y_true, sample_weight): + """Squeeze or expand last dimension if needed. + + 1. Squeezes last dim of `y_pred` or `y_true` if their rank differs by 1 + (using `confusion_matrix.remove_squeezable_dimensions`). + 2. Squeezes or expands last dim of `sample_weight` if its rank differs by 1 + from the new rank of `y_pred`. + If `sample_weight` is scalar, it is kept scalar. + + This will use static shape if available. Otherwise, it will add graph + operations, which could result in a performance hit. + + Args: + y_pred: Predicted values, a `Tensor` of arbitrary dimensions. + y_true: Optional label `Tensor` whose dimensions match `y_pred`. + sample_weight: Optional weight scalar or `Tensor` whose dimensions match + `y_pred`. + + Returns: + Tuple of `y_pred`, `y_true` and `sample_weight`. Each of them possibly has + the last dimension squeezed, + `sample_weight` could be extended by one dimension. + """ + if y_true is not None: + # squeeze last dim of `y_pred` or `y_true` if their rank differs by 1 + y_true, y_pred = confusion_matrix.remove_squeezable_dimensions( + y_true, y_pred) + + if sample_weight is None: + return y_pred, y_true, None + + sample_weight = ops.convert_to_tensor(sample_weight) + weights_shape = sample_weight.get_shape() + weights_rank = weights_shape.ndims + if weights_rank == 0: # If weights is scalar, do nothing. + return y_pred, y_true, sample_weight + + y_pred_shape = y_pred.get_shape() + y_pred_rank = y_pred_shape.ndims + if (y_pred_rank is not None) and (weights_rank is not None): + # Use static rank. + if weights_rank - y_pred_rank == 1: + sample_weight = array_ops.squeeze(sample_weight, [-1]) + elif y_pred_rank - weights_rank == 1: + sample_weight = array_ops.expand_dims(sample_weight, [-1]) + return y_pred, y_true, sample_weight + + # Use dynamic rank. + weights_rank_tensor = array_ops.rank(sample_weight) + rank_diff = weights_rank_tensor - array_ops.rank(y_pred) + maybe_squeeze_weights = lambda: array_ops.squeeze(sample_weight, [-1]) + + def _maybe_expand_weights(): + return control_flow_ops.cond( + math_ops.equal(rank_diff, + -1), lambda: array_ops.expand_dims(sample_weight, [-1]), + lambda: sample_weight) + + def _maybe_adjust_weights(): + return control_flow_ops.cond( + math_ops.equal(rank_diff, 1), maybe_squeeze_weights, + _maybe_expand_weights) + + # squeeze or expand last dim of `sample_weight` if its rank differs by 1 + # from the new rank of `y_pred`. + sample_weight = control_flow_ops.cond( + math_ops.equal(weights_rank_tensor, 0), lambda: sample_weight, + _maybe_adjust_weights) + return y_pred, y_true, sample_weight + + +def _safe_mean(losses, num_present): + """Computes a safe mean of the losses. + + Args: + losses: `Tensor` whose elements contain individual loss measurements. + num_present: The number of measurable elements in `losses`. + + Returns: + A scalar representing the mean of `losses`. If `num_present` is zero, + then zero is returned. + """ + total_loss = math_ops.reduce_sum(losses) + return math_ops.div_no_nan(total_loss, num_present, name='value') + + +def _num_elements(losses): + """Computes the number of elements in `losses` tensor.""" + with ops.name_scope(None, 'num_elements', values=[losses]) as scope: + return math_ops.cast(array_ops.size(losses, name=scope), dtype=losses.dtype) + + +def _reduce_weighted_loss(weighted_losses, + reduction=ReductionV2.SUM_OVER_BATCH_SIZE): + """Reduces the individual weighted loss measurements.""" + if reduction == ReductionV2.NONE: + loss = weighted_losses + else: + loss = math_ops.reduce_sum(weighted_losses) + if reduction == ReductionV2.SUM_OVER_BATCH_SIZE: + loss = _safe_mean(loss, _num_elements(weighted_losses)) + return loss + + +def compute_weighted_loss(losses, + sample_weight=None, + reduction=ReductionV2.SUM_OVER_BATCH_SIZE, + name=None): + """Computes the weighted loss. + + Args: + losses: `Tensor` of shape `[batch_size, d1, ... dN]`. + sample_weight: Optional `Tensor` whose rank is either 0, or the same rank as + `losses`, or be broadcastable to `losses`. + reduction: Type of `tf.losses.Reduction` to apply to loss. Default value is + `SUM_OVER_BATCH_SIZE`. + name: Optional name for the op. + + Raises: + ValueError: If the shape of `sample_weight` is not compatible with `losses`. + + Returns: + Weighted loss `Tensor` of the same type as `losses`. If `reduction` is + `NONE`, this has the same shape as `losses`; otherwise, it is scalar. + """ + ReductionV2.validate(reduction) + if sample_weight is None: + sample_weight = 1.0 + with ops.name_scope(name, 'weighted_loss', (losses, sample_weight)): + # Save the `reduction` argument for loss normalization when distributing + # to multiple replicas. + # TODO(josh11b): Associate it with the returned op for more precision. + ops.get_default_graph()._last_loss_reduction = reduction # pylint: disable=protected-access + + # Update dimensions of `sample_weight` to match with `losses` if possible. + losses, _, sample_weight = squeeze_or_expand_dimensions( + losses, None, sample_weight) + losses = ops.convert_to_tensor(losses) + input_dtype = losses.dtype + losses = math_ops.to_float(losses) + sample_weight = math_ops.to_float(sample_weight) + + try: + # Broadcast weights if possible. + sample_weight = weights_broadcast_ops.broadcast_weights( + sample_weight, losses) + except ValueError: + # Reduce values to same ndim as weight array. + ndim = K.ndim(losses) + weight_ndim = K.ndim(sample_weight) + losses = K.mean(losses, axis=list(range(weight_ndim, ndim))) + + sample_weight.get_shape().assert_is_compatible_with(losses.get_shape()) + weighted_losses = math_ops.multiply(losses, sample_weight) + # Apply reduction function to the individual weighted losses. + loss = _reduce_weighted_loss(weighted_losses, reduction) + # Convert the result back to the input type. + loss = math_ops.cast(loss, input_dtype) + return loss diff --git a/tensorflow/python/ops/losses/losses_impl.py b/tensorflow/python/ops/losses/losses_impl.py index 0a5b511f82..7c52b28b39 100644 --- a/tensorflow/python/ops/losses/losses_impl.py +++ b/tensorflow/python/ops/losses/losses_impl.py @@ -33,32 +33,8 @@ from tensorflow.python.util.deprecation import deprecated_argument_lookup from tensorflow.python.util.tf_export import tf_export -@tf_export("losses.Reduction", v1=[]) -class ReductionV2(object): - """Types of loss reduction. - - Contains the following values: - `NONE`: Un-reduced weighted losses with the same shape as input. - `SUM`: Scalar sum of weighted losses. - `SUM_OVER_BATCH_SIZE`: Scalar `SUM` divided by number of elements in losses. - """ - - NONE = "none" - SUM = "weighted_sum" - SUM_OVER_BATCH_SIZE = "weighted_sum_over_batch_size" - - @classmethod - def all(cls): - return (cls.NONE, cls.SUM, cls.SUM_OVER_BATCH_SIZE) - - @classmethod - def validate(cls, key): - if key not in cls.all(): - raise ValueError("Invalid Reduction Key %s." % key) - - @tf_export(v1=["losses.Reduction"]) -class Reduction(ReductionV2): +class Reduction(object): """Types of loss reduction. Contains the following values: @@ -71,6 +47,9 @@ class Reduction(ReductionV2): `SUM_BY_NONZERO_WEIGHTS`: Same as `SUM_OVER_NONZERO_WEIGHTS`. """ + NONE = "none" + SUM = "weighted_sum" + SUM_OVER_BATCH_SIZE = "weighted_sum_over_batch_size" MEAN = "weighted_mean" SUM_BY_NONZERO_WEIGHTS = "weighted_sum_by_nonzero_weights" SUM_OVER_NONZERO_WEIGHTS = SUM_BY_NONZERO_WEIGHTS diff --git a/tensorflow/tools/api/golden/v1/tensorflow.losses.-reduction.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.losses.-reduction.pbtxt index b2adb52660..258ad5047e 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.losses.-reduction.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.losses.-reduction.pbtxt @@ -1,7 +1,6 @@ path: "tensorflow.losses.Reduction" tf_class { is_instance: "" - is_instance: "" is_instance: "" member { name: "MEAN" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt new file mode 100644 index 0000000000..031d9b171f --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-reduction.pbtxt @@ -0,0 +1,28 @@ +path: "tensorflow.keras.losses.Reduction" +tf_class { + is_instance: "" + is_instance: "" + member { + name: "NONE" + mtype: "" + } + member { + name: "SUM" + mtype: "" + } + member { + name: "SUM_OVER_BATCH_SIZE" + mtype: "" + } + member_method { + name: "__init__" + } + member_method { + name: "all" + argspec: "args=[\'cls\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "validate" + argspec: "args=[\'cls\', \'key\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt index eca6b91538..8618c6f1c7 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt @@ -1,5 +1,9 @@ path: "tensorflow.keras.losses" tf_module { + member { + name: "Reduction" + mtype: "" + } member_method { name: "KLD" argspec: "args=[\'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt index 6a44e4ce66..ad72e3194a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.losses.-reduction.pbtxt @@ -1,10 +1,10 @@ path: "tensorflow.losses.Reduction" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "NONE" - mtype: "" + mtype: "" } member { name: "SUM" -- GitLab From 8a89ca38630943d8658bb1bee1526cdf1e5c615e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sun, 25 Nov 2018 01:02:13 -0800 Subject: [PATCH 281/672] compat: Update forward compatibility horizon to 2018-11-25 PiperOrigin-RevId: 222721347 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 969b95dd0d..216ab2c0ac 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 24) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 25) @tf_export("compat.forward_compatible") -- GitLab From 09a7d525c8556f6fd90c70f656d131559cf30fd4 Mon Sep 17 00:00:00 2001 From: Bixia Zheng Date: Sun, 25 Nov 2018 14:23:30 -0800 Subject: [PATCH 282/672] [XLA:GPU] Convert the reduction implementation to use tiling scheme. Convert the implementation of scalar reduction, row reduction and column reduction to use EmitTiledKernel, which is a more general kernel tiling implementation that is based on the information defined by an object of TilingScheme. For scalar reduction and row reduction, the new implementation should generate the same optimized code as the old implementation. For column reduction, the old implementation in routine IrEmitterUnnested::EmitColumnReduction uses kTileWidth=2 so that one thread computes the partial results for two elements in the output of each kReduce instruction. The new implementation is equivalent to the old implementation with kTileWidth=1 in this regard. PiperOrigin-RevId: 222752674 --- .../xla/service/gpu/ir_emitter_unnested.cc | 1749 +++++++---------- .../xla/service/gpu/ir_emitter_unnested.h | 107 +- .../xla/service/llvm_ir/kernel_tiling.cc | 2 +- .../xla/service/llvm_ir/kernel_tiling.h | 17 +- 4 files changed, 708 insertions(+), 1167 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc index 52f0ba7aa7..bbe1583c01 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.cc @@ -22,7 +22,6 @@ limitations under the License. #include "tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h" #include "absl/algorithm/container.h" -#include "absl/container/inlined_vector.h" #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "absl/types/optional.h" @@ -548,91 +547,7 @@ Status IrEmitterUnnested::HandleFusion(HloInstruction* fusion) { // TODO(b/112040122): Support variadic reduce. return Unimplemented("Variadic reduce is not supported on GPU"); } - VLOG(3) << "Emitting fused reduction to vector: " << fusion->ToString(); - std::vector> thunks; - absl::Span output_instructions = - root->opcode() == HloOpcode::kTuple - ? root->operands() - : absl::Span(&root, 1); - - // For multi-output fusion emit an initializer for each tuple element. - // Otherwise it's sufficient to just initialize the single output. - HloInstruction* first_reduce = nullptr; - for (int i = 0, e = output_instructions.size(); i != e; ++i) { - if (output_instructions[i]->opcode() == HloOpcode::kReduce) { - TF_ASSIGN_OR_RETURN( - std::unique_ptr initializer_thunk, - BuildInitializerThunk(fusion, output_instructions[i] == root - ? ShapeIndex() - : ShapeIndex({i}))); - thunks.push_back(std::move(initializer_thunk)); - first_reduce = - first_reduce == nullptr ? output_instructions[i] : first_reduce; - } - } - CHECK(first_reduce != nullptr); - std::unique_ptr kernel_thunk = - BuildKernelThunk(fusion, /*implements_whole_instruction=*/false); - GpuElementalIrEmitter elemental_emitter( - hlo_module_config_, ir_emitter_context_->llvm_module(), &b_, - GetNestedComputer()); - FusedIrEmitter fused_emitter(GetGeneratorForOperandIrArrays(fusion), - &elemental_emitter); - TF_RETURN_IF_ERROR(root->Accept(&fused_emitter)); - - // For multi-output fusion CHECK the constraints and feed all the - // reduces into a single loop code generator. Single-output reduce - // fusion is a special case of that. - InlinedVector input_gens; - InlinedVector init_value_gens; - std::vector> - extra_output_gens; - InlinedVector reducers; - InlinedVector reduce_output_shapes; - for (int i = 0, e = output_instructions.size(); i != e; ++i) { - const HloInstruction* inst = output_instructions[i]; - ShapeIndex output_shape_index; - if (root->opcode() == HloOpcode::kTuple) { - output_shape_index = {i}; - } - if (inst->opcode() == HloOpcode::kReduce) { - CHECK(IsReductionToVector(*inst)) - << "Only reductions to vector are supported"; - // Shapes, layouts and dimensions must be the same for all reduces - // inside of this fusion. - CHECK(ShapeUtil::Equal(first_reduce->shape(), inst->shape())); - CHECK(ShapeUtil::Equal(first_reduce->operand(0)->shape(), - inst->operand(0)->shape())); - CHECK(ShapeUtil::Equal(first_reduce->operand(1)->shape(), - inst->operand(1)->shape())); - CHECK(first_reduce->dimensions() == inst->dimensions()); - input_gens.push_back(fused_emitter.GetGenerator(inst->operand(0))); - init_value_gens.push_back( - fused_emitter.GetGenerator(inst->operand(1))); - reducers.push_back(inst->to_apply()); - reduce_output_shapes.push_back(std::move(output_shape_index)); - } else { - // For extra outputs we can relax shape equality to allow different - // types (with the same number of elements). Layouts still have to - // match. - CHECK(ShapeUtil::CompatibleIgnoringElementType( - first_reduce->operand(0)->shape(), inst->shape())); - CHECK(LayoutUtil::Equal(first_reduce->operand(0)->shape().layout(), - inst->shape().layout())); - extra_output_gens.emplace_back(fused_emitter.GetGenerator(inst), - std::move(output_shape_index)); - } - } - const Shape& input_shape = first_reduce->operand(0)->shape(); - TF_CHECK_OK(EmitReductionToVector( - kernel_thunk.get(), first_reduce, input_shape, input_gens, - init_value_gens, first_reduce->dimensions(), reducers, - reduce_output_shapes, extra_output_gens)); - thunks.push_back(std::move(kernel_thunk)); - std::unique_ptr sequential_thunk = - absl::make_unique(std::move(thunks), fusion); - AddThunkToThunkSequence(std::move(sequential_thunk)); - return Status::OK(); + return EmitReductionToVector(fusion); } default: LOG(FATAL) << "Bad opcode for input fusion: " @@ -702,13 +617,12 @@ Status IrEmitterUnnested::HandleCopy(HloInstruction* copy) { } Status IrEmitterUnnested::EmitExtraOutputsForReduce( - const HloInstruction* reduce, const IrArray::Index& index, + const HloInstruction* unnested_hlo, const IrArray::Index& index, absl::Span> extra_output_gens) { for (int i = 0; i != extra_output_gens.size(); ++i) { - const HloInstruction* output = reduce->parent()->FusionInstruction(); llvm::Value* extra_output_address = - GetIrArray(*output, *output, extra_output_gens[i].second) + GetIrArray(*unnested_hlo, *unnested_hlo, extra_output_gens[i].second) .EmitArrayElementAddress(index, &b_, "extra_output_element_address"); TF_ASSIGN_OR_RETURN(llvm::Value* const extra_output_ir_value, @@ -718,984 +632,13 @@ Status IrEmitterUnnested::EmitExtraOutputsForReduce( return Status::OK(); } -Status IrEmitterUnnested::EmitReductionToScalar( - KernelThunk* kernel_thunk, HloInstruction* reduce, const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens) { - // Number of elements processed by a single thread. - constexpr int64 kTileSize = 16; - int64 num_elems = ShapeUtil::ElementsIn(input_shape); - - // Round up the number of tiles to a multiple of the warp size. This is - // necessary for correctness. We launch one thread per tile, and if the - // number of threads isn't a multiple of the number of the warp size, our - // shuffles will read from inactive threads, producing undefined values. - int64 num_tiles = - RoundUpToNearest(CeilOfRatio(num_elems, kTileSize), kWarpSize); - - Shape tiled_input_shape = ShapeUtil::MakeShapeWithLayout( - reduce->shape().element_type(), {num_tiles}, {0}); - LaunchDimensions launch_dimensions = CalculateLaunchDimensions( - tiled_input_shape, ir_emitter_context_->device_description()); - - llvm::Type* index_ty = - GetIndexTypeForKernel(reduce, launch_dimensions.launch_bound(), &b_); - - auto index_typed_constant = [&](uint64 c) -> llvm::Constant* { - return llvm::ConstantInt::get(index_ty, c); - }; - - // Check whether every thread will process a full tile's worth of elements - // without reading outside the bounds of the input. If this is true, we can - // skip some bounds checks in the final algorithm. - bool all_threads_in_bounds = num_tiles * kTileSize == num_elems; - - // __global__ void full_reduce_kernel() { - // x_in_tiles = threadIdx.x + blockIdx.x * blockDim.x; - // x = x_in_tiles * kTileSize; - // - // partial_result = init_value; - // if (all_threads_in_bounds || x + kTileSize <= num_elems) { - // for (i = 0; i < kTileSize; ++i) { - // partial_result = Reducer(partial_result, input[x + i]); - // } - // } else { - // for (i = 0; i < kTileSize; ++i) { - // if (x + i < num_elems) { - // partial_result = Reducer(partial_result, input[x + i]); - // } - // } - // } - // for (i = warpSize / 2; i > 0; i /= 2) { - // partial_result = Reducer(partial_result, - // __shfl_down(partial_result, i)); - // } - // if (lane_id == 0) { - // AtomicReducer(&output[y], partial_result); - // } - // } - // - // // Choose num_blocks and threads_per_block such that: - // // - // // num_blocks * threads_per_block = - // // RoundUpToNextMultipleOf(Ceil(num_elems / kTileSize), warpSize), - // // - // // and threads_per_block is a multiple of warpSize. - // reduce_kernel // - auto loop_body_emitter = [=](const IrArray::Index& tile_index) -> Status { - const int num_reduces = reducers.size(); - llvm::Type* element_ir_type = - llvm_ir::PrimitiveTypeToIrType(input_shape.element_type(), module_); - std::vector partial_reduction_result_addresses; - for (int i = 0; i != num_reduces; ++i) { - llvm::Value* partial_reduction_result_address = - Alloca(element_ir_type, /*ArraySize=*/nullptr, - "partial_reduction_result." + llvm::Twine(i)); - TF_ASSIGN_OR_RETURN(llvm::Value* const init_ir_value, - init_value_gens[i](IrArray::Index(index_ty))); - Store(init_ir_value, partial_reduction_result_address); - partial_reduction_result_addresses.push_back( - partial_reduction_result_address); - } - - llvm::Value* x_in_tiles = tile_index[0]; - x_in_tiles = ZExtOrTrunc(x_in_tiles, index_ty); - - // Emit an inner for-loop that reduces the elements in the tile. - auto emit_tile_element_loop = [=](bool tile_in_bounds) -> Status { - std::unique_ptr tile_element_loop = - llvm_ir::ForLoop::EmitForLoop( - "element_id_in_tile", index_typed_constant(0), - index_typed_constant(kTileSize), index_typed_constant(1), &b_); - - // Emit the body of the partial reduction loop. - llvm_ir::SetToFirstInsertPoint(tile_element_loop->GetBodyBasicBlock(), - &b_); - llvm::Value* x = - NSWAdd(NSWMul(x_in_tiles, index_typed_constant(kTileSize)), - tile_element_loop->GetIndVarValue()); - // Unless we know the tile is entirely in bounds, we have to emit a - // x-in-bounds check before reading from the input. - if (!tile_in_bounds) { - llvm_ir::LlvmIfData if_data = llvm_ir::EmitIfThenElse( - ICmpULT(x, index_typed_constant(num_elems)), "x_in_bounds", &b_); - - // Emit code that reads the input element and accumulates it to - // the partial reduction result. - llvm_ir::SetToFirstInsertPoint(if_data.true_block, &b_); - } - - IrArray::Index input_index( - /*linear=*/x, input_shape, &b_); - llvm::Value* input_address = Alloca(element_ir_type); - for (int i = 0; i != num_reduces; ++i) { - TF_ASSIGN_OR_RETURN(llvm::Value* const input_ir_value, - input_gens[i](input_index)); - Store(input_ir_value, input_address); - TF_RETURN_IF_ERROR(EmitCallToNestedComputation( - *reducers[i], - {partial_reduction_result_addresses[i], input_address}, - partial_reduction_result_addresses[i])); - } - return EmitExtraOutputsForReduce(reduce, input_index, extra_output_gens); - }; - - // x_end = kTileSize + x_in_tiles * kTileSize, i.e., the location that's - // immediately beyond the tile. - llvm::Value* x_end = - NSWAdd(index_typed_constant(kTileSize), - NSWMul(x_in_tiles, index_typed_constant(kTileSize))); - // The tile is entirely in bound if all_threads_in_bounds or - // x_end <= num_elems. - llvm::Value* tile_in_bounds = - Or(ICmpULE(x_end, index_typed_constant(num_elems)), - b_.getInt1(all_threads_in_bounds)); - llvm_ir::LlvmIfData if_tile_in_bounds_data = - llvm_ir::EmitIfThenElse(tile_in_bounds, "tile_in_bounds", &b_); - llvm_ir::SetToFirstInsertPoint(if_tile_in_bounds_data.true_block, &b_); - TF_RETURN_IF_ERROR(emit_tile_element_loop(/*tile_in_bounds=*/true)); - llvm_ir::SetToFirstInsertPoint(if_tile_in_bounds_data.false_block, &b_); - TF_RETURN_IF_ERROR(emit_tile_element_loop(/*tile_in_bounds=*/false)); - - // After the if-then-else statement on tile_in_bounds, emit calls to - // shfl_down that accumulate the partial reduction results of all threads - // from the warp. - llvm_ir::SetToFirstInsertPoint(if_tile_in_bounds_data.after_block, &b_); - int bit_width = llvm_ir::GetSizeInBits(element_ir_type); - // bitcast cannot be applied to aggregate types (even packed ones), so we - // instead bitcast addresses of load/store to intN* of the same bit-width. - llvm::Type* shuffle_ir_type = element_ir_type->isStructTy() - ? b_.getIntNTy(bit_width) - : element_ir_type; - for (int shuffle_distance = kWarpSize / 2; shuffle_distance >= 1; - shuffle_distance /= 2) { - llvm::Value* result_from_other_lane = - Alloca(element_ir_type, nullptr, "result_from_other_lane"); - for (int i = 0; i != num_reduces; ++i) { - llvm::Value* partial_reduction_result = - Load(BitCast(partial_reduction_result_addresses[i], - shuffle_ir_type->getPointerTo()), - "partial_reduction_result"); - CHECK_EQ(launch_dimensions.threads_per_block() % kWarpSize, 0) - << "Requires block size a multiple of the warp size, otherwise we " - "will read undefined elements."; - Store(EmitFullWarpShuffleDown(partial_reduction_result, - b_.getInt32(shuffle_distance), &b_), - BitCast(result_from_other_lane, shuffle_ir_type->getPointerTo())); - TF_RETURN_IF_ERROR(EmitCallToNestedComputation( - *reducers[i], - {partial_reduction_result_addresses[i], result_from_other_lane}, - partial_reduction_result_addresses[i])); - } - } - - const HloInstruction* output = - reduce->IsFused() ? reduce->parent()->FusionInstruction() : reduce; - - // Emit an atomic operation that accumulates the partial reduction result of - // lane 0 (which holds the partially accumulated result for its warp) to the - // output element. - llvm::Value* lane_id = - URem(x_in_tiles, index_typed_constant(kWarpSize), "lane_id"); - llvm_ir::LlvmIfData if_lane_id_is_zero_data = llvm_ir::EmitIfThenElse( - ICmpEQ(lane_id, index_typed_constant(0)), "lane_id_is_zero", &b_); - llvm_ir::SetToFirstInsertPoint(if_lane_id_is_zero_data.true_block, &b_); - - for (int i = 0; i != num_reduces; ++i) { - llvm::Value* output_address = - GetIrArray(*output, *output, reduce_output_shapes[i]) - .EmitArrayElementAddress( - IrArray::Index( - /*linear=*/b_.getInt64(0), - ShapeUtil::GetSubshape(output->shape(), - reduce_output_shapes[i]), - &b_), - &b_, "output_element_address"); - TF_RETURN_IF_ERROR(EmitAtomicOperationForNestedComputation( - *reducers[i], output_address, partial_reduction_result_addresses[i])); - } - return Status::OK(); - }; - - // Emit a parallel loop that iterates through all input tiles, one per thread. - UpdateLaunchDimensions(launch_dimensions, kernel_thunk, - ir_emitter_context_->llvm_module()); - return ParallelLoopEmitter(loop_body_emitter, tiled_input_shape, - launch_dimensions, &b_) - .EmitLoop(IrName(reduce), index_ty); -} - -Status IrEmitterUnnested::EmitColumnReduction( - KernelThunk* kernel_thunk, int64 height, int64 width, - HloInstruction* reduce, const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens) { - // Divide the input matrix into tiles of size KxL. For example, when the - // input matrix is 4x4, K=2, and L=1 the tiled matrix looks like - // - // 0123 - // 0123 - // 4567 - // 4567 // Numbers indicate tile IDs. - // - // Each tile is first partially reduced to a scalar by a thread, and then the - // scalar is accumulated to the output vector using atomic operations. - // - // We choose 128 as the tile size based on empirical evidence. It's big enough - // to reduce the amount of atomic adds in the end, maximizing the memory - // bandwidth. A tile width of 2 allows for high memory bandwidth utilization - // on 16b input data. - constexpr int64 kTileHeight = 128; - constexpr int64 kTileWidth = 2; - - // If the height is not a multiple of kTileHeight, we pad the bottom of the - // input matrix. - const int64 height_in_tiles = CeilOfRatio(height, kTileHeight); - // If width is not a multiple of kTileWidth the rightmost thread will process - // fewer input elements. - const int64 width_in_tiles = CeilOfRatio(width, kTileWidth); - Shape tiled_input_shape = - ShapeUtil::MakeShapeWithLayout(reduce->shape().element_type(), - {height_in_tiles, width_in_tiles}, {1, 0}); - LaunchDimensions launch_dimensions = CalculateLaunchDimensions( - tiled_input_shape, ir_emitter_context_->device_description()); - - // TODO(b/110211620): Convert to use i32 index_type when it is possible. - llvm::Type* index_ty = b_.getInt64Ty(); - - auto index_typed_constant = [&](uint64 c) -> llvm::Constant* { - return llvm::ConstantInt::get(index_ty, c); - }; - - // for (linear_index = threadIdx.x + blockIdx.x * blockDim.x; - // linear_index < height_in_tiles * width_in_tiles; - // linear_index += blockDim.x * gridDim.x) { - // y_in_tiles = linear_index / width_in_tiles; - // x_in_tiles = linear_index % width_in_tiles; - // - // partial_results[kTileWidth] = init_values; - // tile_in_y_bounds = height % kTileHeight == 0 || - // y_in_tiles * kTileHeight + kTileHeight <= height; - // tile_in_x_bounds = width % kTileWidth == 0 || - // x_in_tiles * kTileWidth + kTileWidth <= width; - // // The implementation handles y and x bound checks separately. - // if (tile_in_y_bounds && tile_in_x_bounds) { - // for (y_offset : range(kTileHeight)) { - // y = y_in_tiles * kTileHeight + y_offset; - // for (x_offset : range(kTileWidth)) { - // x = x_in_tiles * kTileWidth + x_offset; - // partial_result = Reducer(partial_result[x_offset], input[y][x]); - // } - // } - // } else { - // for (y_offset : range(kTileHeight)) { - // y = y_in_tiles * kTileHeight + y_offset; - // for (y_offset : range(kTileHeight)) { - // x = x_in_tiles * kTileWidth + x_offset; - // if (y < height && x < width) { - // partial_result = Reducer(partial_result, input[y][x]); - // } - // } - // } - // } - // for (x_offset : range(kTileWidth)) { - // AtomicReducer(&output[x + x_offset], partial_result[x_offset]); - // } - // } - auto loop_body_emitter = [=](const IrArray::Index& tile_index) -> Status { - const int num_reduces = reducers.size(); - // Emit the loop body that reduces one tile. - llvm::Type* element_ir_type = - llvm_ir::PrimitiveTypeToIrType(input_shape.element_type(), module_); - std::vector partial_reduction_result_addresses; - for (int i = 0; i != num_reduces; ++i) { - for (int x_offset = 0; x_offset < kTileWidth; ++x_offset) { - llvm::Value* partial_reduction_result_address = - Alloca(element_ir_type, /*ArraySize=*/nullptr, - "partial_reduction_result." + - llvm::Twine(i * kTileWidth + x_offset)); - TF_ASSIGN_OR_RETURN(llvm::Value* const init_ir_value, - init_value_gens[i](IrArray::Index(index_ty))); - Store(init_ir_value, partial_reduction_result_address); - partial_reduction_result_addresses.push_back( - partial_reduction_result_address); - } - } - - // Emit an inner for-loop that partially reduces the elements in the given - // tile. - llvm::Value* y_in_tiles = tile_index[0]; - llvm::Value* x_in_tiles = tile_index[1]; - - y_in_tiles = ZExtOrTrunc(y_in_tiles, index_ty); - x_in_tiles = ZExtOrTrunc(x_in_tiles, index_ty); - - auto emit_tile_element_loop = [=](bool tile_in_y_bounds, - bool tile_in_x_bounds) -> Status { - std::unique_ptr tile_element_loop = - llvm_ir::ForLoop::EmitForLoop( - "element_id_in_tile", index_typed_constant(0), - index_typed_constant(kTileHeight), index_typed_constant(1), &b_); - - // Emit the body of the partial reduction loop. - llvm_ir::SetToFirstInsertPoint(tile_element_loop->GetBodyBasicBlock(), - &b_); - llvm::Value* y = - NSWAdd(NSWMul(y_in_tiles, index_typed_constant(kTileHeight)), - tile_element_loop->GetIndVarValue()); - - // Unless we know that y is in bounds, we have to emit a check before - // reading from the input. - if (!tile_in_y_bounds) { - llvm_ir::LlvmIfData if_data = llvm_ir::EmitIfThenElse( - ICmpULT(y, index_typed_constant(height)), "y_in_bounds", &b_); - - // Emit code that reads the input element and accumulates it to - // the partial reduction result. - llvm_ir::SetToFirstInsertPoint(if_data.true_block, &b_); - } - for (int x_offset = 0; x_offset < kTileWidth; ++x_offset) { - llvm::Value* x = - NSWAdd(NSWMul(x_in_tiles, index_typed_constant(kTileWidth)), - index_typed_constant(x_offset)); - // Unless we know that x is in bounds, we have to emit a check before - // reading from the input. - if (!tile_in_x_bounds) { - llvm_ir::LlvmIfData if_data = llvm_ir::EmitIfThenElse( - ICmpULT(x, index_typed_constant(width)), "x_in_bounds", &b_); - llvm_ir::SetToFirstInsertPoint(if_data.true_block, &b_); - } - llvm::Value* input_address = Alloca(element_ir_type); - // {y,x} is an index to input_matrix_shape [height,width]. We need to - // convert that to an index to input_shape (the shape of the operand of - // "reduce"). This conversion is composed of a transposition from - // input_shape to normalized_input_shape and a reshape from - // normalized_input_shape to input_matrix_shape. - const Shape normalized_input_shape = - ShapeUtil::MakeShapeWithDescendingLayoutAndSamePhysicalLayout( - input_shape); - auto input_shape_min2maj = LayoutUtil::MinorToMajor(input_shape); - const std::vector transpose_dimension_mapping( - input_shape_min2maj.rbegin(), input_shape_min2maj.rend()); - - const Shape input_matrix_shape = - ShapeUtil::MakeShapeWithDescendingLayout(input_shape.element_type(), - {height, width}); - const IrArray::Index input_matrix_index({y, x}, input_matrix_shape, - &b_); - const IrArray::Index input_index = - input_matrix_index - .SourceIndexOfReshape(input_matrix_shape, - normalized_input_shape, &b_) - .SourceIndexOfTranspose(normalized_input_shape, input_shape, - transpose_dimension_mapping, &b_); - for (int i = 0; i != num_reduces; ++i) { - TF_ASSIGN_OR_RETURN(llvm::Value* const input_ir_value, - input_gens[i](input_index)); - Store(input_ir_value, input_address); - TF_RETURN_IF_ERROR(EmitCallToNestedComputation( - *reducers[i], - {partial_reduction_result_addresses[i * kTileWidth + x_offset], - input_address}, - partial_reduction_result_addresses[i * kTileWidth + x_offset])); - TF_RETURN_IF_ERROR(EmitExtraOutputsForReduce(reduce, input_index, - extra_output_gens)); - } - } - return Status::OK(); - }; - - // y_end = kTileHeight + y_in_tiles * kTileHeight, i.e., the y location - // that's immediately beyond the tile. - llvm::Value* y_end = - NSWAdd(index_typed_constant(kTileHeight), - NSWMul(y_in_tiles, index_typed_constant(kTileHeight))); - // x_end = kTileWidth + x_in_tiles * kTileWidth, i.e., the x location - // that's immediately beyond the tile. - llvm::Value* x_end = - NSWAdd(index_typed_constant(kTileWidth), - NSWMul(x_in_tiles, index_typed_constant(kTileWidth))); - llvm::Value* tile_in_y_bounds = - Or(ICmpULE(y_end, index_typed_constant(height)), - b_.getInt1(height % kTileHeight == 0)); - llvm::Value* tile_in_x_bounds = - Or(ICmpULE(x_end, index_typed_constant(width)), - b_.getInt1(width % kTileWidth == 0)); - // The tile is in y bounds if "height" is a multiple of kTileHeight or - // y_end <= height. - llvm_ir::LlvmIfData if_tile_in_y_bounds_data = - llvm_ir::EmitIfThenElse(tile_in_y_bounds, "tile_in_y_bounds", &b_); - llvm_ir::SetToFirstInsertPoint(if_tile_in_y_bounds_data.true_block, &b_); - // The tile is in x bounds if "width" is a multiple of kTileWidth or - // x_end <= width. - llvm_ir::LlvmIfData if_tile_in_x_bounds_data = - llvm_ir::EmitIfThenElse(tile_in_x_bounds, "tile_in_x_bounds", &b_); - llvm_ir::SetToFirstInsertPoint(if_tile_in_x_bounds_data.true_block, &b_); - TF_RETURN_IF_ERROR(emit_tile_element_loop(/*tile_in_y_bounds=*/true, - /*tile_in_x_bounds=*/true)); - llvm_ir::SetToFirstInsertPoint(if_tile_in_x_bounds_data.false_block, &b_); - TF_RETURN_IF_ERROR(emit_tile_element_loop(/*tile_in_y_bounds=*/true, - /*tile_in_x_bounds=*/false)); - llvm_ir::SetToFirstInsertPoint(if_tile_in_y_bounds_data.false_block, &b_); - if_tile_in_x_bounds_data = - llvm_ir::EmitIfThenElse(tile_in_x_bounds, "tile_in_x_bounds", &b_); - llvm_ir::SetToFirstInsertPoint(if_tile_in_x_bounds_data.true_block, &b_); - TF_RETURN_IF_ERROR(emit_tile_element_loop(/*tile_in_y_bounds=*/false, - /*tile_in_x_bounds=*/true)); - llvm_ir::SetToFirstInsertPoint(if_tile_in_x_bounds_data.false_block, &b_); - TF_RETURN_IF_ERROR(emit_tile_element_loop(/*tile_in_y_bounds=*/false, - /*tile_in_x_bounds=*/false)); - - // After the nested if-then-else statement on tile_in_y_bounds and - // tile_in_x_bounds, emit atomic operations to accumulate the partial - // reduction result to the output element. - llvm_ir::SetToFirstInsertPoint(if_tile_in_y_bounds_data.after_block, &b_); - const HloInstruction* output = - reduce->IsFused() ? reduce->parent()->FusionInstruction() : reduce; - for (int i = 0; i != num_reduces; ++i) { - for (int x_offset = 0; x_offset < kTileWidth; ++x_offset) { - llvm::Value* x = - NSWAdd(NSWMul(x_in_tiles, index_typed_constant(kTileWidth)), - index_typed_constant(x_offset)); - llvm::Value* output_address = - GetIrArray(*output, *output, reduce_output_shapes[i]) - .EmitArrayElementAddress( - IrArray::Index( - x, - ShapeUtil::GetSubshape(output->shape(), - reduce_output_shapes[i]), - &b_), - &b_, "output_element_address"); - TF_RETURN_IF_ERROR(EmitAtomicOperationForNestedComputation( - *reducers[i], output_address, - partial_reduction_result_addresses[i * kTileWidth + x_offset])); - } - } - return Status::OK(); - }; - - // Emit a parallel loop that iterate through all input tiles. - UpdateLaunchDimensions(launch_dimensions, kernel_thunk, - ir_emitter_context_->llvm_module()); - return ParallelLoopEmitter(loop_body_emitter, tiled_input_shape, - launch_dimensions, &b_) - .EmitLoop(IrName(reduce), index_ty); -} - -static std::pair ComputeKernelMappingSchemeForReduction( - int64 depth, int64 width, int64 kWarpSize) { - constexpr int64 kTargetNumElementsPerThread = 64; - int64 x_tile_size = kTargetNumElementsPerThread; - int64 z_tile_size = 1; - - // Only tile along the x dimension with tile size kTargetNumElementsPerThread - // if doing so doesn't require a slow version of loop with bound check on each - // dimension. A more sophisticated heuristics is to enable tile along the - // x dimension with tile size kTargetNumElementsPerThread when either width is - // a factor of (kWarpSize * kTargetNumElementsPerThread) or width is big - // enough so that only a small fraction of the threads execute the slow - // version of loop with bound check. - if (width % (kWarpSize * kTargetNumElementsPerThread) != 0) { - x_tile_size = 8; - z_tile_size = 8; - while (depth % z_tile_size != 0) { - z_tile_size -= 1; - } - } - - return std::pair(x_tile_size, z_tile_size); -} - -Status IrEmitterUnnested::EmitRowReduction( - KernelThunk* kernel_thunk, int64 depth, int64 height, int64 width, - HloInstruction* reduce, const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens) { - // A naive algorithm is: - // 1. Divide the x dimension of the input tensor into tiles of size 1x1xX. - // 2. Partially reduces each tile to a scalar using one thread. - // 3. Accumulates that scalar to the output vector using atomic operations. - // - // for (linear_index = threadIdx.x + blockIdx.x * blockDim.x; - // linear_index < depth * height * width_in_tiles; - // linear_index += blockDim.x * gridDim.x) { - // int x_in_tiles = linear_index % width_in_tiles; - // int y = linear_index / width_in_tiles % height; - // int z = linear_index / (height * width_in_tiles); - // float partial_result = 0; - // for (element_id_in_tile : range(x_tile_size)) { - // int x = x_in_tiles * x_tile_size + element_id_in_tile; - // if (x < width) - // partial_result = reducer(partial_result, input[z][y][x]); - // } - // AtomicReducer(&output[y], partial_result); - // } - // - // Four optimizations are performed. - // - // 1. To coalesce global memory accesses, dilate the tile with a factor of 32 - // (i.e. the warp size). For example, suppose the width is 8x32=256. Instead - // of making each tile consecutive, we let make tile 0 column - // [0,32,64,...,224], tile 1 column [1,33,65,...,225], and so on. This ensures - // that threads in a warp access consecutive memory in one iteration (i.e. - // coalesced). In the above example, the warp that contains thread 0-31 - // accesses column 0-31 in the first iteration, and 32-63 in the second - // iteration, and so on. - // - // 2. Partially accumulate partial reduced results computed by threads in the - // same warp using shfl_down. Using shfl_down is faster than directly using - // atomic operations because shfl_down transfers the data between threads - // using shared memory and threads in the same warp run in lock step (thus no - // extra synchronization needed). See - // https://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/ - // for details. The downside is, to produce correct results when using - // shfl_down, we need to guarantee threads in the same warp work on input - // elements with the same y, so the number of tiles in each row must be a - // multiple of 32. - // - // 3. Specialize the case that the entire tile is in bounds. When that is - // true, we don't need to emit "if(x 0; shuffle_distance /= 2) - // partial_result = Reducer( - // partial_result, - // __shfl_down_sync(CUDA_WARP_ALL, partial_result, shuffle_distance)); - // if (lane_id == 0) - // AtomicReducer(&output[y], partial_result); - // } - // - - int64 x_tile_size; - int64 z_tile_size; - std::tie(x_tile_size, z_tile_size) = - ComputeKernelMappingSchemeForReduction(depth, width, kWarpSize); - - // Round the width in tiles up to the nearest multiple of kWarpSize, so that - // the use of shfl_down is valid. - const int64 width_in_tiles = - RoundUpToNearest(CeilOfRatio(width, x_tile_size), kWarpSize); - Shape tiled_input_shape = ShapeUtil::MakeShapeWithLayout( - reduce->shape().element_type(), - {depth / z_tile_size, height, width_in_tiles}, {2, 1, 0}); - LaunchDimensions launch_dimensions = CalculateLaunchDimensions( - tiled_input_shape, ir_emitter_context_->device_description()); - llvm::Type* index_ty = - GetIndexTypeForKernel(reduce, launch_dimensions.launch_bound(), &b_); - - auto index_typed_constant = [&](uint64 c) -> llvm::Constant* { - return llvm::ConstantInt::get(index_ty, c); - }; - - auto loop_body_emitter = [=](const IrArray::Index& tile_index) { - const int num_reduces = reducers.size(); - llvm::Type* element_ir_type = llvm_ir::PrimitiveTypeToIrType( - input_shape.element_type(), ir_emitter_context_->llvm_module()); - std::vector partial_reduction_result_addresses; - for (int i = 0; i != num_reduces; ++i) { - llvm::Value* partial_reduction_result_address = - Alloca(element_ir_type, /*ArraySize=*/nullptr, - "partial_reduction_result." + llvm::Twine(i)); - TF_ASSIGN_OR_RETURN(llvm::Value* const init_ir_value, - init_value_gens[i](IrArray::Index(index_ty))); - Store(init_ir_value, partial_reduction_result_address); - partial_reduction_result_addresses.push_back( - partial_reduction_result_address); - } - - llvm::Value* z_tile = tile_index[0]; - llvm::Value* y = tile_index[1]; - llvm::Value* x_tile = tile_index[2]; - - x_tile = ZExtOrTrunc(x_tile, index_ty); - - llvm::Value* warp_id = - UDiv(x_tile, index_typed_constant(kWarpSize), "warp_id"); - llvm::Value* lane_id = - URem(x_tile, index_typed_constant(kWarpSize), "lane_id"); - - // The x-location of the last element in this z-x-tile. - // last_x = lane_id + warpSize * (x_tile_size - 1 + warp_id * x_tile_size); - llvm::Value* last_x = NSWAdd( - lane_id, - NSWMul(index_typed_constant(kWarpSize), - NSWAdd(index_typed_constant(x_tile_size - 1), - NSWMul(warp_id, index_typed_constant(x_tile_size))))); - - KernelSupportLibrary ksl( - &b_, - /*unroll_mode=*/xla::llvm_ir::UnrollMode::kFullyUnroll, - /*prevent_vectorization=*/false); - - // Emit a for-loop that partially reduces the elements in the given - // z-x-tile. - auto emit_z_x_tile_element_loop = [&](bool x_tile_in_bounds, - int64 x_tile_loop_bound) -> Status { - auto emit_z_tile_element_loop = [&](llvm::Value* z_indvar) -> Status { - llvm::Value* z = - NSWAdd(z_indvar, NSWMul(index_typed_constant(z_tile_size), z_tile)); - TF_RETURN_IF_ERROR(ksl.For( - "x_tile", - /*start=*/index_typed_constant(0), - /*end=*/index_typed_constant(x_tile_loop_bound), - /*step=*/1, [&](llvm::Value* x_indvar) -> Status { - // x = lane_id + - // warpSize * (element_id_in_x_tile + warp_id * x_tile_size); - llvm::Value* x = NSWAdd( - lane_id, - NSWMul(index_typed_constant(kWarpSize), - NSWAdd(x_indvar, - NSWMul(warp_id, llvm::ConstantInt::get( - index_ty, x_tile_size))))); - - // Unless we know the x-tile is entirely in bounds, we have to - // emit a x-in-bounds check before reading from the input. - if (!x_tile_in_bounds) { - llvm_ir::LlvmIfData if_x_in_bounds_data = - llvm_ir::EmitIfThenElse( - ICmpULT(x, index_typed_constant(width)), "x_in_bounds", - &b_); - // Points b_ to the then-block. - llvm_ir::SetToFirstInsertPoint(if_x_in_bounds_data.true_block, - &b_); - } - - // Emit code that reads the input element and accumulates it - // to the partial reduction result. - llvm::Value* input_address = Alloca(element_ir_type); - { - // {z,y,x} is an index to input_3d_tensor_shape - // [depth,height,width]. We need to convert that to an index - // to input_shape (the shape of the operand of "reduce"). - // This conversion is composed of a transposition from - // input_shape to normalized_input_shape and a reshape from - // normalized_input_shape to input_3d_tensor_shape. - const Shape normalized_input_shape = ShapeUtil:: - MakeShapeWithDescendingLayoutAndSamePhysicalLayout( - input_shape); - auto input_shape_min2maj = - LayoutUtil::MinorToMajor(input_shape); - const std::vector transpose_dimension_mapping( - input_shape_min2maj.rbegin(), input_shape_min2maj.rend()); - const Shape input_3d_tensor_shape = - ShapeUtil::MakeShapeWithDescendingLayout( - input_shape.element_type(), {depth, height, width}); - const IrArray::Index input_3d_tensor_index( - {z, y, x}, input_3d_tensor_shape, &b_); - const IrArray::Index input_index = - input_3d_tensor_index - .SourceIndexOfReshape(input_3d_tensor_shape, - normalized_input_shape, &b_) - .SourceIndexOfTranspose( - normalized_input_shape, input_shape, - transpose_dimension_mapping, &b_); - - for (int i = 0; i != num_reduces; ++i) { - TF_ASSIGN_OR_RETURN(llvm::Value* const input_ir_value, - input_gens[i](input_index)); - Store(input_ir_value, input_address); - TF_RETURN_IF_ERROR(EmitCallToNestedComputation( - *reducers[i], - {partial_reduction_result_addresses[i], input_address}, - partial_reduction_result_addresses[i])); - } - return EmitExtraOutputsForReduce(reduce, input_index, - extra_output_gens); - } - })); - return Status::OK(); - }; - - return ksl.For("z_tile", - /*start=*/index_typed_constant(0), - /*end=*/index_typed_constant(z_tile_size), - /*step=*/1, emit_z_tile_element_loop); - }; - - llvm::Value* tile_in_bounds = - Or(b_.getInt1(width % (x_tile_size * kWarpSize) == 0), - ICmpULT(last_x, index_typed_constant(width))); - - TF_RETURN_IF_ERROR( - ksl.If(tile_in_bounds, - /*true_block_generator=*/ - [&]() -> Status { - return emit_z_x_tile_element_loop(/*x_tile_in_bounds=*/true, - x_tile_size); - }, - /*false_block_generator=*/ - [&]() -> Status { - return emit_z_x_tile_element_loop( - /*x_tile_in_bounds=*/false, - CeilOfRatio(width % (x_tile_size * kWarpSize), kWarpSize)); - })); - - // After accumulating the elements of the z_x_tile, emit calls to - // shfl_down that accumulate the partial reduction results of all - // threads in a warp. - int bit_width = llvm_ir::GetSizeInBits(element_ir_type); - // bitcast cannot be applied to aggregate types (even packed ones), so we - // instead bitcast addresses of load/store to intN* of the same bit-width. - llvm::Type* shuffle_ir_type = element_ir_type->isStructTy() - ? b_.getIntNTy(bit_width) - : element_ir_type; - for (int shuffle_distance = 16; shuffle_distance >= 1; - shuffle_distance /= 2) { - llvm::Value* result_from_other_lane = - Alloca(element_ir_type, nullptr, "result_from_other_lane"); - for (int i = 0; i != num_reduces; ++i) { - llvm::Value* partial_reduction_result = - Load(BitCast(partial_reduction_result_addresses[i], - shuffle_ir_type->getPointerTo()), - "partial_reduction_result"); - CHECK_EQ(launch_dimensions.threads_per_block() % kWarpSize, 0) - << "Requires block size a multiple of the warp size, otherwise we " - "will read undefined elements."; - Store(EmitFullWarpShuffleDown(partial_reduction_result, - b_.getInt32(shuffle_distance), &b_), - BitCast(result_from_other_lane, shuffle_ir_type->getPointerTo())); - TF_RETURN_IF_ERROR(EmitCallToNestedComputation( - *reducers[i], - {partial_reduction_result_addresses[i], result_from_other_lane}, - partial_reduction_result_addresses[i])); - } - } - - const HloInstruction* output = - reduce->IsFused() ? reduce->parent()->FusionInstruction() : reduce; - - // Emit an atomic operation that accumulates the partial reduction result of - // lane 0 (which holds the partially accumulated result for its warp) to the - // output element. - llvm_ir::LlvmIfData if_lane_id_is_zero_data = llvm_ir::EmitIfThenElse( - ICmpEQ(lane_id, index_typed_constant(0)), "lane_id_is_zero", &b_); - llvm_ir::SetToFirstInsertPoint(if_lane_id_is_zero_data.true_block, &b_); - for (int i = 0; i != num_reduces; ++i) { - llvm::Value* output_address = - GetIrArray(*output, *output, reduce_output_shapes[i]) - .EmitArrayElementAddress( - IrArray::Index(y, - ShapeUtil::GetSubshape( - output->shape(), reduce_output_shapes[i]), - &b_), - &b_, "output_element_address"); - // We don't need to emit atomic operations if there is only one tile of - // results. 'depth' is the z dimension, 'width' is the x dimension. - if (z_tile_size >= depth && x_tile_size >= width) { - TF_RETURN_IF_ERROR(EmitCallToNestedComputation( - *reducers[i], - {output_address, partial_reduction_result_addresses[i]}, - output_address)); - } else { - TF_RETURN_IF_ERROR(EmitAtomicOperationForNestedComputation( - *reducers[i], output_address, - partial_reduction_result_addresses[i])); - } - } - return Status::OK(); - }; - - // Emit a parallel loop that iterates through every input tiles. - UpdateLaunchDimensions(launch_dimensions, kernel_thunk, - ir_emitter_context_->llvm_module()); - return ParallelLoopEmitter(loop_body_emitter, tiled_input_shape, - launch_dimensions, &b_) - .EmitLoop(IrName(reduce), index_ty); -} - -// Figures out whether `reduce` is a row or column reduction, and which -// dimensions to reduce, and calls either `EmitRowReduction` or -// `EmitColumnReduction` as appropriate. -// Prerequisite: all the dimensions to keep are contiguous in the input layout -// and, if `reduce` is fused, the fused subgraph is pure -// elementwise. -Status IrEmitterUnnested::EmitReductionToVector( - KernelThunk* kernel_thunk, HloInstruction* reduce, const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span dimensions_to_reduce, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens) { - // This emission requires "reduce" to have an input layout. It is either set - // by LayoutAssignment (for a top-level kReduce) or by InstructionFusion (for - // a fused kReduce). - CHECK(input_shape.has_layout()) << "LayoutAssignment or InstructionFusion " - "doesn't set the input layout of " - << reduce->ToString(); - - // Specialize multi-dimensional-array-to-vector reduction. - std::vector input_dims_to_keep; - for (int64 input_dim = 0; input_dim < ShapeUtil::Rank(input_shape); - ++input_dim) { - if (std::find(dimensions_to_reduce.begin(), dimensions_to_reduce.end(), - input_dim) == dimensions_to_reduce.end()) { - input_dims_to_keep.push_back(input_dim); - } - } - - // Sort the dimensions to keep from minor to major, to facilitate checking - // whether another dimension is major or minor of them. - std::sort(input_dims_to_keep.begin(), input_dims_to_keep.end(), - [&input_shape](int64 dim_a, int64 dim_b) { - return PositionInContainer(LayoutUtil::MinorToMajor(input_shape), - dim_a) < - PositionInContainer(LayoutUtil::MinorToMajor(input_shape), - dim_b); - }); - // Now, if output rank is at least 1, `input_dims_to_keep.front()` is - // minormost and `input_dims_to_keep.back()` is majormost. - - // If the dimensions to keep are minormost, emit a column reduction. As all - // the dimensions to keep are contiguous, by prerequisite of - // `EmitReductionToVector`, we only need to check whether the minormost - // dimension of the input is to keep. - if (ShapeUtil::IsEffectiveScalar(reduce->shape())) { - return EmitReductionToScalar(kernel_thunk, reduce, input_shape, input_gens, - init_value_gens, reducers, - reduce_output_shapes, extra_output_gens); - } else if (input_dims_to_keep.front() == - LayoutUtil::Minor(input_shape.layout(), 0)) { - // Column reduction. Treat the result of "input" as a matrix whose width - // is the most minor dimension and height the product of other dimensions, - // and treat "reduce" as a column reduction of the input matrix. - const int64 width = ShapeUtil::ElementsIn(reduce->shape()); - // "width" can be zero, so don't do - // height = ShapeUtil::ElementsIn(input_shape) / width; - int64 height = 1; - for (int64 input_dim = 0; input_dim < ShapeUtil::Rank(input_shape); - ++input_dim) { - if (!std::count(input_dims_to_keep.begin(), input_dims_to_keep.end(), - input_dim)) { - height *= input_shape.dimensions(input_dim); - } - } - return EmitColumnReduction(kernel_thunk, height, width, reduce, input_shape, - input_gens, init_value_gens, reducers, - reduce_output_shapes, extra_output_gens); - } else { - // Reduce the row dimension of a matrix or reduce dimension 0 and 2 in a - // 3D tensor. The size of dimension 1 (the height) is the size of the - // dimension to keep, the size of dimension 0 (the depth) is the product - // of dimensions that are more major than the dimension to keep, and the - // size of dimension 2 (the width) is the product of more minor - // dimensions. - int64 depth = 1; - int64 width = 1; - for (int64 input_dim = 0; input_dim < ShapeUtil::Rank(input_shape); - ++input_dim) { - if (PositionInContainer(LayoutUtil::MinorToMajor(input_shape), - input_dim) > - PositionInContainer(LayoutUtil::MinorToMajor(input_shape), - input_dims_to_keep.back())) { - depth *= input_shape.dimensions(input_dim); - } else if (PositionInContainer(LayoutUtil::MinorToMajor(input_shape), - input_dim) < - PositionInContainer(LayoutUtil::MinorToMajor(input_shape), - input_dims_to_keep.front())) { - width *= input_shape.dimensions(input_dim); - } - } - const int64 height = ShapeUtil::ElementsIn(reduce->shape()); - return EmitRowReduction(kernel_thunk, depth, height, width, reduce, - input_shape, input_gens, init_value_gens, reducers, - reduce_output_shapes, extra_output_gens); - } -} - Status IrEmitterUnnested::HandleReduce(HloInstruction* reduce) { // TODO(b/112040122): Support multi-output reduce. if (!ShapeUtil::IsArray(reduce->shape())) { return Unimplemented("Multi-output reduce is not supported on GPU"); } - auto input = reduce->operand(0); - auto init_value = reduce->operand(1); - absl::Span dimensions_to_reduce(reduce->dimensions()); - HloComputation* reducer = reduce->to_apply(); - // HandleReduce specializes reduction from a multi-dimensional array to a 1D - // array. The specialized version requires an initializer thunk that - // initializes the output array to the initial value of the reduce. if (IsReductionToVector(*reduce)) { - TF_ASSIGN_OR_RETURN(std::unique_ptr initializer_thunk, - BuildInitializerThunk(reduce)); - std::vector> thunks; - thunks.push_back(std::move(initializer_thunk)); - std::unique_ptr kernel_thunk = - BuildKernelThunk(reduce, /*implements_whole_instruction=*/false); - - TF_CHECK_OK(EmitReductionToVector( - kernel_thunk.get(), reduce, input->shape(), - {[&](const IrArray::Index& index) { - return GetIrArray(*input, *reduce).EmitReadArrayElement(index, &b_); - }}, - {[&](const IrArray::Index& index) { - return GetIrArray(*init_value, *reduce) - .EmitReadArrayElement(index, &b_); - }}, - dimensions_to_reduce, {reducer}, {{}}, {})); - - thunks.push_back(std::move(kernel_thunk)); - - std::unique_ptr sequential_thunk = - absl::make_unique(std::move(thunks), reduce); - AddThunkToThunkSequence(std::move(sequential_thunk)); - return Status::OK(); + return EmitReductionToVector(reduce); } return IrEmitter::HandleReduce(reduce); @@ -1820,7 +763,7 @@ Status IrEmitterUnnested::HandleSelectAndScatter( // Create the inner loop to iterate over the window. llvm_ir::ForLoopNest window_loops(IrName(select_and_scatter, "inner"), &b_, index_type); - std::vector window_size; + DimensionVector window_size; for (const auto& dim : window.dimensions()) { window_size.push_back(dim.size()); CHECK_GT(dim.size(), 0); @@ -3265,7 +2208,8 @@ void EmitPartialTile( builder->CreateAdd(llvm::ConstantInt::get(index_ty, j), x); ksl->IfReturnVoid( - "x_in_tile", builder->CreateICmpULT(x_loc, tile_width), [&] { + loop_name + "_x_in_tile", builder->CreateICmpULT(x_loc, tile_width), + [&] { // tile_height_bound = // ceil(tile_height / num_threads_y) * num_threads_y llvm::Value* ceiling_of_ratio = builder->CreateUDiv( @@ -3282,8 +2226,8 @@ void EmitPartialTile( [&](llvm::Value* y_indvar) { llvm::Value* y_loc = builder->CreateAdd(y_indvar, y); ksl->IfReturnVoid( - "y_in_tile", builder->CreateICmpULT(y_loc, tile_height), - [&] { + loop_name + "_y_in_tile", + builder->CreateICmpULT(y_loc, tile_height), [&] { emit_elem_function( source_idx.AddOffsetToDim( y_indvar, KernelMappingScheme::DimY, builder), @@ -3314,7 +2258,7 @@ void EmitTiledElementalCodeWithBoundsCheck( llvm::Type* index_ty = tile_width->getType(); ksl->IfReturnVoid( - "full_tile", + loop_name + "_full_tile", builder->CreateAnd( builder->CreateICmpEQ(llvm::ConstantInt::get(index_ty, tile_size_x), tile_width), @@ -3405,7 +2349,395 @@ void IrEmitterUnnested::EmitTileElementForFusion( } } -// Emits a block of tiles, given a function object to emit one tile. +// Information to support the code generation for a tiled reduction kernel. +using AddressVector = InlinedVector; +class ReductionCodegenInfo : public IrEmitterUnnested::KernelCodegenInfo { + public: + explicit ReductionCodegenInfo(llvm_ir::KernelMappingScheme* mapping_scheme, + bool is_row_reduction) + : KernelCodegenInfo(mapping_scheme), + current_output_linear_index_address_(nullptr), + current_output_inbound_address_(nullptr), + is_row_reduction_(is_row_reduction) {} + + void SetCurrentOutputLinearIndexAddress(llvm::AllocaInst* a) { + current_output_linear_index_address_ = a; + } + // Returns the address of the memory that stores the linear index of the + // current output. Since we are processing reduction to contiguous physical + // dimensions, this linear index is the linear index of the 1D output array. + llvm::AllocaInst* GetCurrentOutputLinearIndexAddress() const { + return current_output_linear_index_address_; + } + + void SetCurrentOutputInboundAddress(llvm::AllocaInst* a) { + current_output_inbound_address_ = a; + } + + llvm::AllocaInst* GetCurrentOutputInboundAddress() const { + return current_output_inbound_address_; + } + + AddressVector* GetMutablePartialResultAddresses() { + return &partial_result_addresses_; + } + const AddressVector& GetPartialResultAddresses() const { + return partial_result_addresses_; + } + + AddressVector* GetMutableReductionInputAddresses() { + return &reduction_input_addresses_; + } + const AddressVector& GetReductionInputAddresses() const { + return reduction_input_addresses_; + } + + InlinedVector* GetMutableReducers() { return &reducers_; } + const InlinedVector& GetReducers() const { + return reducers_; + } + int GetNumberOfReduces() const { return reducers_.size(); } + + InlinedVector* GetMutableReductionOutputShapeIndices() { + return &reduction_output_shape_indices_; + } + const InlinedVector& GetReductionOutputShapeIndices() const { + return reduction_output_shape_indices_; + } + + bool IsRowReduction() const { return is_row_reduction_; } + + // Return the dimension that is being reduced between DimX and DimY. + int GetReducedDimensionEnum() const { + return IsRowReduction() ? llvm_ir::KernelMappingScheme::DimX + : llvm_ir::KernelMappingScheme::DimY; + } + + // Return the dimension that is being ketp between DimX and DimY. + int GetKeptDimensionEnum() const { + return IsRowReduction() ? llvm_ir::KernelMappingScheme::DimY + : llvm_ir::KernelMappingScheme::DimX; + } + + private: + AddressVector partial_result_addresses_; + AddressVector reduction_input_addresses_; + InlinedVector reducers_; + InlinedVector reduction_output_shape_indices_; + llvm::AllocaInst* current_output_linear_index_address_; + llvm::AllocaInst* current_output_inbound_address_; + bool is_row_reduction_; +}; + +namespace { +// Returns a group of instructions that generate the output for the kernel +// containing the given HLO instruction. The result may be an unnested kReduce +// HLO, a nested kReduce HLO of a kInput fusion, or the operands of the tuple +// for a multiple output fusion. +absl::Span GetOutputInstructions( + HloInstruction* const* reduce_or_tuple_pointer) { + HloOpcode opcode = (*reduce_or_tuple_pointer)->opcode(); + CHECK(opcode == HloOpcode::kReduce || opcode == HloOpcode::kTuple); + return opcode == HloOpcode::kTuple + ? (*reduce_or_tuple_pointer)->operands() + : absl::Span(reduce_or_tuple_pointer, 1); +} + +const HloInstruction* GetFirstReduceInstruction( + absl::Span instructions) { + auto first_reduce_iter = + absl::c_find_if(instructions, [](const HloInstruction* inst) { + return inst->opcode() == HloOpcode::kReduce; + }); + CHECK_NE(first_reduce_iter, instructions.end()); + return *first_reduce_iter; +} + +}; // namespace + +void IrEmitterUnnested::EmitPrologueForOneReduction( + HloInstruction* unnested_hlo, HloInstruction* reduce_inst, int reduce_idx, + KernelCodegenInfo* kernel_info, GpuElementalIrEmitter* elemental_emitter, + ShapeIndex output_shape_index) { + ReductionCodegenInfo* reduction_info = + static_cast(kernel_info); + + InlinedVector* reducers = + reduction_info->GetMutableReducers(); + CHECK(IsReductionToVector(*reduce_inst)); + reducers->push_back(reduce_inst->to_apply()); + + InlinedVector* reduction_output_shape_indices = + reduction_info->GetMutableReductionOutputShapeIndices(); + reduction_output_shape_indices->push_back(std::move(output_shape_index)); + + AddressVector* reduction_input_addresses = + reduction_info->GetMutableReductionInputAddresses(); + llvm::Type* element_type = llvm_ir::PrimitiveTypeToIrType( + reduce_inst->shape().element_type(), ir_emitter_context_->llvm_module()); + llvm::AllocaInst* reduction_input_address = Alloca(element_type); + reduction_input_addresses->push_back(reduction_input_address); + + AddressVector* partial_result_addresses = + reduction_info->GetMutablePartialResultAddresses(); + llvm::AllocaInst* partial_result_address = + Alloca(element_type, /*ArraySize=*/nullptr, + "partial_reduction_result." + llvm::Twine(reduce_idx)); + partial_result_addresses->push_back(partial_result_address); + + // Initialize the partial result with the initial value of the reduction. + llvm::Value* init_ir_value; + if (unnested_hlo->opcode() == HloOpcode::kFusion) { + HloInstruction* init_value_operand = reduce_inst->mutable_operand(1); + FusedIrEmitter fused_emitter(GetGeneratorForOperandIrArrays(unnested_hlo), + elemental_emitter); + + TF_CHECK_OK(init_value_operand->Accept(&fused_emitter)); + init_ir_value = + fused_emitter + .GetGenerator(init_value_operand)(IrArray::Index(b_.getInt32Ty())) + .ValueOrDie(); + } else { + const HloInstruction* init_value = unnested_hlo->operand(1); + init_ir_value = + GetIrArray(*init_value, *unnested_hlo) + .EmitReadArrayElement(IrArray::Index(b_.getInt32Ty()), &b_); + } + + Store(init_ir_value, partial_result_address); +} + +void IrEmitterUnnested::EmitPrologueForReduction( + HloInstruction* unnested_hlo, KernelCodegenInfo* kernel_info) { + VLOG(10) << "Emit prologue for reduction " << unnested_hlo->ToString(); + // Find the unnested kReduce or the tuple that contains a list of kReduce. + HloInstruction* reduce_or_tuple = unnested_hlo->opcode() == HloOpcode::kFusion + ? unnested_hlo->fused_expression_root() + : unnested_hlo; + absl::Span output_instructions = + GetOutputInstructions(&reduce_or_tuple); + ReductionCodegenInfo* reduction_info = + static_cast(kernel_info); + GpuElementalIrEmitter elemental_emitter(hlo_module_config_, + ir_emitter_context_->llvm_module(), + &b_, GetNestedComputer()); + const HloInstruction* first_reduce = nullptr; + for (int i = 0, e = output_instructions.size(); i != e; ++i) { + if (output_instructions[i]->opcode() != HloOpcode::kReduce) { + continue; + } + HloInstruction* reduce_inst = output_instructions[i]; + if (first_reduce == nullptr) { + first_reduce = reduce_inst; + } else { + CHECK(first_reduce->dimensions() == reduce_inst->dimensions()); + } + ShapeIndex output_shape_index; + if (reduce_or_tuple->opcode() == HloOpcode::kTuple) { + output_shape_index = {i}; + } + + EmitPrologueForOneReduction(unnested_hlo, reduce_inst, i, kernel_info, + &elemental_emitter, + std::move(output_shape_index)); + } + + // Allocate stack storage to store the current output linear index and record + // the address of the storage. + reduction_info->SetCurrentOutputLinearIndexAddress( + Alloca(reduction_info->GetIndexType())); + + if (!reduction_info->IsRowReduction()) { + llvm::Type* bool_ty = b_.getInt1Ty(); + llvm::AllocaInst* output_inbound_addr = Alloca(bool_ty); + Store(llvm::ConstantInt::get(bool_ty, 0), output_inbound_addr); + reduction_info->SetCurrentOutputInboundAddress(output_inbound_addr); + } +} + +void IrEmitterUnnested::EmitFullWarpShuffleDownLoopForAllReduces( + const InlinedVector& reducers, + const AddressVector& partial_result_addresses) { + for (int distance = 16; distance >= 1; distance /= 2) { + for (int i = 0; i != reducers.size(); ++i) { + llvm::Type* element_type = + partial_result_addresses[i]->getType()->getElementType(); + int bit_width = llvm_ir::GetSizeInBits(element_type); + llvm::Value* result_from_other_lane = Alloca( + element_type, nullptr, "result_from_other_lane" + llvm::Twine(i)); + // Bitcast cannot be applied to aggregate types (even packed ones), so + // we bitcast addresses of load/store to intN* of the same bit-width. + llvm::Type* shuffled_value_type = + element_type->isStructTy() ? b_.getIntNTy(bit_width) : element_type; + auto convert_pointer_for_shuffle = [&](llvm::Value* ptr) { + return BitCast(ptr, shuffled_value_type->getPointerTo()); + }; + llvm::Value* partial_result = + Load(convert_pointer_for_shuffle(partial_result_addresses[i]), + "partial_reduction_result"); + Store(EmitFullWarpShuffleDown(partial_result, b_.getInt32(distance), &b_), + convert_pointer_for_shuffle(result_from_other_lane)); + TF_CHECK_OK(EmitCallToNestedComputation( + *reducers[i], {partial_result_addresses[i], result_from_other_lane}, + partial_result_addresses[i])); + } + } +} + +void IrEmitterUnnested::EmitEpilogueForReduction( + HloInstruction* unnested_hlo, KernelCodegenInfo* kernel_info) { + ReductionCodegenInfo* reduction_info = + static_cast(kernel_info); + int num_reduces = reduction_info->GetNumberOfReduces(); + const AddressVector& partial_result_addresses = + reduction_info->GetPartialResultAddresses(); + const InlinedVector& reducers = + reduction_info->GetReducers(); + const InlinedVector& reduction_output_shape_indices = + reduction_info->GetReductionOutputShapeIndices(); + + if (reduction_info->IsRowReduction()) { + EmitFullWarpShuffleDownLoopForAllReduces(reducers, + partial_result_addresses); + llvm::Value* lane_id = reduction_info->GetLaneId(); + llvm_ir::LlvmIfData if_lane_id_is_zero_data = llvm_ir::EmitIfThenElse( + ICmpEQ(lane_id, llvm::ConstantInt::get(lane_id->getType(), 0)), + "lane_id_is_zero", &b_); + llvm_ir::SetToFirstInsertPoint(if_lane_id_is_zero_data.true_block, &b_); + } else { + llvm::Value* output_inbound_addr = + reduction_info->GetCurrentOutputInboundAddress(); + llvm::Value* output_inbound = Load(output_inbound_addr); + llvm_ir::LlvmIfData if_output_inbound_data = llvm_ir::EmitIfThenElse( + ICmpEQ(output_inbound, + llvm::ConstantInt::get(output_inbound->getType(), 1)), + "output_inbound", &b_); + llvm_ir::SetToFirstInsertPoint(if_output_inbound_data.true_block, &b_); + } + + // Emit an atomic operation that accumulates the partial reduction to the + // output element. For row reduction, this is only for lane 0 due to the + // if-statement emitted above. + for (int i = 0; i != num_reduces; ++i) { + IrArray::Index element_index( + /*linear=*/Load(reduction_info->GetCurrentOutputLinearIndexAddress(), + "output_linear_addr"), + ShapeUtil::GetSubshape(unnested_hlo->shape(), + reduction_output_shape_indices[i]), + &b_); + llvm::Value* output_address = + GetIrArray(*unnested_hlo, *unnested_hlo, + reduction_output_shape_indices[i]) + .EmitArrayElementAddress(element_index, &b_, + "output_element_address"); + // Do not emit atomic operations if each element in the reduction result is + // computed by one block, that is the dimension being reduced has only one + // block. + const llvm_ir::KernelMappingScheme* mapping_scheme = + reduction_info->GetKernelMappingScheme(); + if (mapping_scheme->GetTileBlockSizeForDimension( + llvm_ir::KernelMappingScheme::DimZ) == 1 && + mapping_scheme->GetTileBlockSizeForDimension( + reduction_info->GetReducedDimensionEnum()) == 1) { + TF_CHECK_OK(EmitCallToNestedComputation( + *reducers[i], {output_address, partial_result_addresses[i]}, + output_address)); + } else { + TF_CHECK_OK(EmitAtomicOperationForNestedComputation( + *reducers[i], output_address, partial_result_addresses[i])); + } + } +} + +void IrEmitterUnnested::EmitTileElementForReduction( + HloInstruction* unnested_hlo, const llvm_ir::IrArray::Index& index, + const KernelCodegenInfo* kernel_info, llvm::Value* y_loc, + llvm::Value* x_loc) { + VLOG(10) << "Emit tile element for reduce " << unnested_hlo->ToString(); + HloInstruction* reduce_or_tuple = unnested_hlo->opcode() == HloOpcode::kFusion + ? unnested_hlo->fused_expression_root() + : unnested_hlo; + llvm_ir::TiledParameterInfo* tiled_param_info = + kernel_info->GetTiledParameterInfo(); + tiled_param_info->set_y(y_loc); + tiled_param_info->set_x(x_loc); + + // Record the linear address for the current reduction. + const ReductionCodegenInfo* reduction_info = + dynamic_cast(kernel_info); + Store(index[reduction_info->GetKeptDimensionEnum()], + reduction_info->GetCurrentOutputLinearIndexAddress()); + if (!reduction_info->IsRowReduction()) { + llvm::Type* bool_ty = b_.getInt1Ty(); + llvm::AllocaInst* output_inbound_addr = + reduction_info->GetCurrentOutputInboundAddress(); + Store(llvm::ConstantInt::get(bool_ty, 1), output_inbound_addr); + } + + InlinedVector input_gens; + std::vector> + extra_output_gens; + GpuElementalIrEmitter elem_emitter(hlo_module_config_, module_, &b_, + GetNestedComputer()); + FusedIrEmitter fused_emitter(GetGeneratorForOperandIrArrays(unnested_hlo), + &elem_emitter); + absl::Span output_instructions = + GetOutputInstructions(&reduce_or_tuple); + // Construct the ElementGenerator for each reduction and extra output in the + // the group of output instructions. + if (unnested_hlo->opcode() == HloOpcode::kFusion) { + fused_emitter.SetTiledParameterInfo(tiled_param_info); + TF_CHECK_OK(unnested_hlo->fused_expression_root()->Accept(&fused_emitter)); + + for (int i = 0, e = output_instructions.size(); i != e; ++i) { + const HloInstruction* inst = output_instructions[i]; + ShapeIndex output_shape_index; + if (reduce_or_tuple->opcode() == HloOpcode::kTuple) { + output_shape_index = {i}; + } + if (inst->opcode() == HloOpcode::kReduce) { + input_gens.push_back(fused_emitter.GetGenerator(inst->operand(0))); + } else { + extra_output_gens.emplace_back(fused_emitter.GetGenerator(inst), + std::move(output_shape_index)); + } + } + } else { + input_gens.push_back([&](const IrArray::Index& index) { + return GetIrArray(*unnested_hlo->operand(0), *unnested_hlo) + .EmitReadArrayElement(index, &b_); + }); + } + + IrArray::Index input_index = + reduction_info->GetKernelMappingScheme()->GetUnnormalizedIndex( + index, + GetFirstReduceInstruction(output_instructions)->operand(0)->shape()); + const AddressVector& partial_reduction_result_addresses = + reduction_info->GetPartialResultAddresses(); + const AddressVector& reduction_input_addresses = + reduction_info->GetReductionInputAddresses(); + const InlinedVector& reducers = + reduction_info->GetReducers(); + + // Emit code to generate the input and perform the reduction computation for + // each reduction instruction. + for (int i = 0; i != reducers.size(); ++i) { + llvm::Value* const input_ir_value = input_gens[i](input_index).ValueOrDie(); + Store(input_ir_value, reduction_input_addresses[i]); + TF_CHECK_OK(EmitCallToNestedComputation( + *reducers[i], + {partial_reduction_result_addresses[i], reduction_input_addresses[i]}, + partial_reduction_result_addresses[i])); + } + + // Emit code to generate the output for the non-reduction instructions in the + // fusion, if any. + TF_CHECK_OK( + EmitExtraOutputsForReduce(unnested_hlo, input_index, extra_output_gens)); +} + +// Emits a kernel for the hlo instruction using the given tiling scheme. void IrEmitterUnnested::EmitBlock(const TileGenerator& emit_one_tile, const KernelCodegenInfo* kernel_info, KernelSupportLibrary& ksl, @@ -3532,7 +2864,6 @@ LaunchDimensions IrEmitterUnnested::EmitKernel( << llvm_ir::DumpToString(*param_shmem_buffers[id]); } - CHECK_EQ(mapping_scheme->GetThreadsPerTile() % kWarpSize, 0); LaunchDimensions launch_dimensions = LaunchDimensions( mapping_scheme->GetNumberOfBlocks(), mapping_scheme->GetThreadsPerTile()); llvm::Type* index_ty = GetIndexTypeForKernel( @@ -3561,6 +2892,7 @@ LaunchDimensions IrEmitterUnnested::EmitKernel( kernel_info->SetLaneId( mapping_scheme->GetNumberOfThreadsForDimensionX() == kWarpSize ? x : nullptr); + kernel_info->SetIndexType(index_ty); KernelSupportLibrary ksl(&b_, llvm_ir::UnrollMode::kDefaultUnroll); // Curry a few parameters to EmitTiledElementalCodeWithBoundsCheck. @@ -3585,29 +2917,31 @@ LaunchDimensions IrEmitterUnnested::EmitKernel( input_tile_origin.AddOffsetToDim(x, KernelMappingScheme::DimX, &b_) .AddOffsetToDim(y, KernelMappingScheme::DimY, &b_); - // Copy input parameter values to shared memory buffers: - // tile[y, x] = input[index] - // Note that tile_width and tile_height are flipped here because we are - // reading a transposed tile. - emit_tiled_elemental_code_with_bounds_check( - input_index, "input", output_tile_bounds[2], output_tile_bounds[1], - [&](const IrArray::Index& index, llvm::Value* y_loc, - llvm::Value* x_loc) { - for (int64 id : tiled_param_ids) { - IrArray& input_in_logical_shape = param_in_reduced_shape_arrays[id]; - llvm::Value* shmem_buffer = param_shmem_buffers[id]; - // TODO(jlebar): Add AA metadata to this store. Tile buffers are - // global variables, so LLVM can't infer much about it. - Store(input_in_logical_shape.EmitReadArrayElement(index, &b_, - "input_element"), - GEP(shmem_buffer, {index_typed_constant(0), y_loc, x_loc})); - } - }); - // If shared memory transpose is needed, wait for all threads to reach this // point, lest we copy a value from tile to output before the other thread // copies it from input to tile. This is `__syncthreads` in CUDA. if (!tiled_param_ids.empty()) { + // Copy input parameter values to shared memory buffers: + // tile[y, x] = input[index] + // Note that tile_width and tile_height are flipped here because we are + // reading a transposed tile. + emit_tiled_elemental_code_with_bounds_check( + input_index, "input", output_tile_bounds[2], output_tile_bounds[1], + [&](const IrArray::Index& index, llvm::Value* y_loc, + llvm::Value* x_loc) { + for (int64 id : tiled_param_ids) { + IrArray& input_in_logical_shape = + param_in_reduced_shape_arrays[id]; + llvm::Value* shmem_buffer = param_shmem_buffers[id]; + // TODO(jlebar): Add AA metadata to this store. Tile buffers are + // global variables, so LLVM can't infer much about it. + Store(input_in_logical_shape.EmitReadArrayElement( + index, &b_, "input_element"), + GEP(shmem_buffer, {index_typed_constant(0), y_loc, x_loc})); + } + }); + + // Wait for all threads to reach this point using `__syncthreads` in CUDA. llvm_ir::EmitCallToIntrinsic(llvm::Intrinsic::nvvm_barrier0, {}, {}, &b_); } @@ -3627,6 +2961,7 @@ LaunchDimensions IrEmitterUnnested::EmitKernel( kernel_generator.GetTileElementGenerator()(unnested_hlo, index, kernel_info, y_loc, x_loc); }); + // If a tile block contains multiple tiles and shared memory buffers are // used, we need to wait for all threads to finish using the shared memory // buffer for the current tile before we move on to process the next tile @@ -3831,6 +3166,246 @@ bool IrEmitterUnnested::CheckAndEmitHloWithTile021(HloInstruction* hlo) { return true; } +namespace { +// Checks that the outputs of a fusion with reduction are consistent. +Status AreFusedReductionOutputsConsistent( + absl::Span output_instructions, + const HloInstruction* first_reduce) { + for (const HloInstruction* inst : output_instructions) { + if (inst->opcode() == HloOpcode::kReduce) { + // Shapes, layouts and dimensions must be the same for all reduces + // inside of this fusion. + TF_RET_CHECK(ShapeUtil::Equal(first_reduce->shape(), inst->shape())); + TF_RET_CHECK(ShapeUtil::Equal(first_reduce->operand(0)->shape(), + inst->operand(0)->shape())); + TF_RET_CHECK(ShapeUtil::Equal(first_reduce->operand(1)->shape(), + inst->operand(1)->shape())); + TF_RET_CHECK(first_reduce->dimensions() == inst->dimensions()); + } else { + // For extra outputs we can relax shape equality to allow different + // types (with the same number of elements). Layouts still have to + // match. + TF_RET_CHECK(ShapeUtil::CompatibleIgnoringElementType( + first_reduce->operand(0)->shape(), inst->shape())); + TF_RET_CHECK(LayoutUtil::Equal(first_reduce->operand(0)->shape().layout(), + inst->shape().layout())); + } + } + return Status::OK(); +} + +// Finds the dimensions to keep for the reduction, sorts and returns the +// dimensions from minor to major. +DimensionVector GetDimensionsToKeepMinorToMajor( + const Shape& input_shape, absl::Span dims_to_reduce) { + DimensionVector input_dims(ShapeUtil::Rank(input_shape), 0); + absl::c_iota(input_dims, 0); + DimensionVector input_dims_to_keep; + for (int input_dim : input_dims) { + auto it = absl::c_find_if(dims_to_reduce, [&](int64 dim_to_reduce) { + return dim_to_reduce == input_dim; + }); + if (it == dims_to_reduce.end()) { + input_dims_to_keep.push_back(input_dim); + } + } + + // Sort the dimensions to keep from minor to major. + absl::c_sort(input_dims_to_keep, [&input_shape](int64 dim_a, int64 dim_b) { + return PositionInContainer(LayoutUtil::MinorToMajor(input_shape), dim_a) < + PositionInContainer(LayoutUtil::MinorToMajor(input_shape), dim_b); + }); + + VLOG(10) << "dims to keep minor to major" + << absl::StrJoin(input_dims_to_keep, ","); + return input_dims_to_keep; +} + +// Given the input shape and dimensions to reduce for the reduction to vector, +// returns : +// num_kept: the number of elements in the contiguous dimensions to keep. +// num_reduced_major: the number of elements in the dimensions to reduce that +// are more major than the dimensions to keep. +// num_reduced_minor: the number of elements in the dimensions to reduce that +// are more minor than the dimensions to kept. +std::tuple GetReductionToVectorDimensions( + const Shape& input_shape, absl::Span dims_to_reduce) { + DimensionVector input_dims_to_keep_minor_to_major = + GetDimensionsToKeepMinorToMajor(input_shape, dims_to_reduce); + CHECK(LayoutUtil::AreDimensionsConsecutive( + input_shape.layout(), input_dims_to_keep_minor_to_major)); + int num_reduced_major = 1, num_kept = 1, num_reduced_minor = 1; + if (input_dims_to_keep_minor_to_major.empty()) { + return std::make_tuple(num_reduced_major, num_kept, num_reduced_minor); + } + DimensionVector input_dims(ShapeUtil::Rank(input_shape), 0); + absl::c_iota(input_dims, 0); + absl::Span minor_to_major = + LayoutUtil::MinorToMajor(input_shape); + for (int input_dim : input_dims) { + int64 curr_dim_size = input_shape.dimensions(input_dim); + if (PositionInContainer(minor_to_major, input_dim) > + PositionInContainer(minor_to_major, + input_dims_to_keep_minor_to_major.back())) { + num_reduced_major *= curr_dim_size; + } else if (PositionInContainer(minor_to_major, input_dim) < + PositionInContainer(minor_to_major, + input_dims_to_keep_minor_to_major.front())) { + num_reduced_minor *= curr_dim_size; + } else { + num_kept *= curr_dim_size; + } + } + + return std::make_tuple(num_reduced_major, num_kept, num_reduced_minor); +} + +std::tuple ComputeMappingSchemeAndReductionKind( + const HloInstruction* first_reduce, llvm::IRBuilder<>* b) { + int64 depth = 1; + int64 height = 1; + int64 width = 1; + bool is_row_reduction = true; + int64 tile_size_x = 1; + int64 tile_size_y = 1; + int64 block_size_y = 1; + int64 block_size_z = 1; + int64 num_threads_x = 1; + int64 num_threads_y = 1; + const Shape& input_shape = first_reduce->operand(0)->shape(); + int64 num_input_elems = ShapeUtil::ElementsIn(input_shape); + int64 num_output_elems = ShapeUtil::ElementsIn(first_reduce->shape()); + int64 num_reduced_major, num_kept, num_reduced_minor; + std::tie(num_reduced_major, num_kept, num_reduced_minor) = + GetReductionToVectorDimensions(input_shape, first_reduce->dimensions()); + CHECK_EQ(num_output_elems, num_kept); + + if (num_kept == 1) { + // Scalar reduction is a special row reduction with depth = height = 1. + width = num_input_elems; + tile_size_x = kWarpSize * 16; + num_threads_x = kWarpSize; + } else if (num_reduced_minor == 1) { + // Column reduction reduces inputs with dimension [height, width], where + // width is the minor dimension, to dimension [width]. + height = num_reduced_major; + width = num_kept; + is_row_reduction = false; + tile_size_x = std::min(kWarpSize, num_kept); + // The old Column reduction algorithm uses kTileHeight = 128. We choose + // tile_size_y * block_size_y = 128 to match the value of kTileHeight. Using + // a non-trivial block_size_y here is a way to avoid unrolling all the 128 + // iterations. + tile_size_y = 32; + block_size_y = 4; + num_threads_x = tile_size_x; + } else { + // Row reduction reduces inputs with dimension [depth, height, width], + // where width is the most minor dimension, to dimension [height] . + depth = num_reduced_major; + height = num_kept; + width = num_reduced_minor; + num_threads_x = kWarpSize; + if (width % (kWarpSize * 64) == 0) { + tile_size_x = kWarpSize * 64; + } else { + tile_size_x = kWarpSize * 8; + block_size_z = 8; + while (depth % block_size_z != 0) { + block_size_z -= 1; + } + } + } + DCHECK_EQ(depth * height * width, num_input_elems); + VLOG(10) << "is_row_reduction " << is_row_reduction << depth << " " << height + << " " << width; + + DimensionVector dims_in_elem{depth, height, width}; + DimensionVector req_block_sizes{block_size_z, block_size_y, 1}; + llvm_ir::KernelMappingScheme mapping_scheme(dims_in_elem, tile_size_y, + tile_size_x, req_block_sizes, + num_threads_y, num_threads_x, b); + return std::make_tuple(mapping_scheme, is_row_reduction); +} + +} // namespace + +Status IrEmitterUnnested::EmitReductionToVector(HloInstruction* unnested_hlo) { + VLOG(10) << "Emitting reduction to vector " << unnested_hlo->ToString(); + + HloInstruction* reduce_or_tuple = unnested_hlo->opcode() == HloOpcode::kFusion + ? unnested_hlo->fused_expression_root() + : unnested_hlo; + absl::Span output_instructions = + GetOutputInstructions(&reduce_or_tuple); + const HloInstruction* first_reduce = + GetFirstReduceInstruction(output_instructions); + + if (output_instructions.size() > 1) { + TF_RETURN_IF_ERROR( + AreFusedReductionOutputsConsistent(output_instructions, first_reduce)); + } + + // Build an initializer thunk to initialize each reduction output. + std::vector> thunks; + for (int i = 0, e = output_instructions.size(); i != e; ++i) { + if (output_instructions[i]->opcode() != HloOpcode::kReduce) { + continue; + } + TF_ASSIGN_OR_RETURN( + std::unique_ptr initializer_thunk, + BuildInitializerThunk(unnested_hlo, + (output_instructions[i] == reduce_or_tuple) + ? ShapeIndex() + : ShapeIndex({i}))); + thunks.push_back(std::move(initializer_thunk)); + } + + // Build a kernel thunk to compute all the outputs. + std::unique_ptr kernel_thunk = + BuildKernelThunk(unnested_hlo, /*implements_whole_instruction=*/false); + + const Shape& input_shape = first_reduce->operand(0)->shape(); + // The layout of a reduction input is either set by LayoutAssignment for + // unnested kReduce or by InstructionFusion for fused kReduce. + CHECK(input_shape.has_layout()) << "LayoutAssignment or InstructionFusion " + "doesn't set the input layout of " + << first_reduce->ToString(); + + bool is_row_reduction; + llvm_ir::KernelMappingScheme mapping_scheme; + std::tie(mapping_scheme, is_row_reduction) = + ComputeMappingSchemeAndReductionKind(first_reduce, &b_); + ReductionCodegenInfo reduction_info(&mapping_scheme, is_row_reduction); + KernelCodeGenerator kernel_generator( + /*tile_element_generator=*/ + [&](HloInstruction* hlo, const llvm_ir::IrArray::Index& index, + const KernelCodegenInfo* kernel_info, llvm::Value* y_loc, + llvm::Value* x_loc) { + EmitTileElementForReduction(hlo, index, kernel_info, y_loc, x_loc); + }, + /*block_prologue_generator=*/ + [&](HloInstruction* hlo, KernelCodegenInfo* kernel_info) { + EmitPrologueForReduction(hlo, kernel_info); + }, + /*block_epilogue_generator*/ + [&](HloInstruction* hlo, KernelCodegenInfo* kernel_info) { + EmitEpilogueForReduction(hlo, kernel_info); + }); + + LaunchDimensions launch_dimensions = + EmitKernel(unnested_hlo, {}, kernel_generator, &reduction_info); + UpdateLaunchDimensions(launch_dimensions, kernel_thunk.get(), + ir_emitter_context_->llvm_module()); + + thunks.push_back(std::move(kernel_thunk)); + std::unique_ptr sequential_thunk = + absl::make_unique(std::move(thunks), unnested_hlo); + AddThunkToThunkSequence(std::move(sequential_thunk)); + + return Status::OK(); +} + Status IrEmitterUnnested::EmitConstantGlobals() { for (const BufferAllocation& allocation : ir_emitter_context_->buffer_assignment().Allocations()) { diff --git a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h index e09ed657a8..85a0e5328c 100644 --- a/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h +++ b/tensorflow/compiler/xla/service/gpu/ir_emitter_unnested.h @@ -16,6 +16,7 @@ limitations under the License. #ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_IR_EMITTER_UNNESTED_H_ #define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_IR_EMITTER_UNNESTED_H_ +#include "absl/container/inlined_vector.h" #include "tensorflow/compiler/xla/service/gpu/ir_emitter.h" #include "tensorflow/compiler/xla/service/gpu/sequential_thunk.h" #include "tensorflow/compiler/xla/service/gpu/thunk.h" @@ -68,9 +69,12 @@ class IrEmitterUnnested : public IrEmitter { explicit KernelCodegenInfo(llvm_ir::KernelMappingScheme* mapping_scheme) : mapping_scheme_(mapping_scheme), tiled_param_info_(nullptr), - lane_id_(nullptr) {} + lane_id_(nullptr), + index_ty_(nullptr) {} + virtual ~KernelCodegenInfo() {} void SetLaneId(llvm::Value* v) { lane_id_ = v; } + void SetIndexType(llvm::Type* t) { index_ty_ = t; } void SetTiledParamInfo(llvm_ir::TiledParameterInfo* tiled_param_info) { CHECK_EQ(tiled_param_info_, nullptr); tiled_param_info_ = tiled_param_info; @@ -83,11 +87,13 @@ class IrEmitterUnnested : public IrEmitter { llvm_ir::TiledParameterInfo* GetTiledParameterInfo() const { return tiled_param_info_; } + llvm::Type* GetIndexType() const { return index_ty_; } private: llvm_ir::KernelMappingScheme* mapping_scheme_; llvm_ir::TiledParameterInfo* tiled_param_info_; llvm::Value* lane_id_; + llvm::Type* index_ty_; }; // A function object to prepare for the code generation for a tile block. @@ -200,82 +206,14 @@ class IrEmitterUnnested : public IrEmitter { // Helper for writing extra outputs from inside a reduce kernel. Status EmitExtraOutputsForReduce( - const HloInstruction* reduce, const llvm_ir::IrArray::Index& index, + const HloInstruction* unnested_hlo, const llvm_ir::IrArray::Index& index, absl::Span> extra_output_gens); - // EmitColumnReduction and EmitRowReduction emit code for column and row - // reduction of a matrix and/or 3D tensor. Row and column reduction have - // different memory access pattern, so for performance their implementations - // are significantly different. + // Generates code for reduction to contiguous dimensions. // - // Emits code that reduces a matrix of shape [height x width] to a vector of - // [width]. Other parameters have the same meaning as those of - // `EmitReductionToVector`. Note that input shape might not be - // [height x width], but can be bitcast to [height x width] with "height" - // being the major dimension. - Status EmitColumnReduction( - KernelThunk* kernel_thunk, int64 height, int64 width, - HloInstruction* reduce, const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens); - - // Emits code that reduces a 3D tensor of shape [depth x height x width] to a - // vector of shape [height]. Other parameters have the same meaning as those - // of `EmitReductionToVector`. Note that input shape might not be - // [depth x height x width], but can be bitcast to [depth x height x width] - // with "depth" being the most major dimension. - Status EmitRowReduction( - KernelThunk* kernel_thunk, int64 depth, int64 height, int64 width, - HloInstruction* reduce, const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens); - - // Emits code that reduces a tensor of arbitrary rank to a scalar. - Status EmitReductionToScalar( - KernelThunk* kernel_thunk, HloInstruction* reduce, - const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens); - - // Figures out whether `reduce` is a row or column reduction, and which - // dimensions to reduce, and calls either `EmitRowReduction` or - // `EmitColumnReduction` as appropriate. `input_shape` is the shape of the - // input array, which is the operand of the Reduce instruction if unfused or - // of the Fusion instruction if fused. `input_gen` and `init_value_gen` - // generate elements of the input and the initial value. Other parameters mean - // the same as for `HandleReduce`. - // - // Multiple reduces can be emitted in the same loop, assuming they have the - // same input and output shapes, and the same reduce dimensions. - // - // extra_output_gens can contain extra generators for intermediate outputs. - // These must have the same shape as the reduce input as they are computed - // when the reduce inputs are being read. - // - // Prerequisite: `IsReductionToVector(*reduce)` - Status EmitReductionToVector( - KernelThunk* kernel_thunk, HloInstruction* reduce, - const Shape& input_shape, - absl::Span input_gens, - absl::Span init_value_gens, - absl::Span dimensions_to_reduce, - absl::Span reducers, - absl::Span reduce_output_shapes, - absl::Span> - extra_output_gens); + // Prerequisite: `IsReductionToVector(*unnested_hlo)` + Status EmitReductionToVector(HloInstruction* unnested_hlo); // Emits code for an in-place scatter, modifying `thunk`s launch dimensions in // the process. `scatter` may be fused, scatter indices are taken from @@ -314,6 +252,29 @@ class IrEmitterUnnested : public IrEmitter { const llvm_ir::IrArray::Index& index, const KernelCodegenInfo* kernel_info, llvm::Value* y_loc, llvm::Value* x_loc); + // Emits code to process a tensor element in a tile for the given input hlo + // that is either a unnested kReduce or a kInput fusion. + void EmitTileElementForReduction(HloInstruction* unnested_hlo, + const llvm_ir::IrArray::Index& index, + const KernelCodegenInfo* kernel_info, + llvm::Value* y_loc, llvm::Value* x_loc); + // Prepares for the code generation for a tile block of a reduction kernel. + void EmitPrologueForReduction(HloInstruction* unnested_hlo, + KernelCodegenInfo* kernel_info); + void EmitPrologueForOneReduction(HloInstruction* unnested_hlo, + HloInstruction* reduce_inst, int reduce_idx, + KernelCodegenInfo* kernel_info, + GpuElementalIrEmitter* elemental_emitter, + ShapeIndex output_shape_index); + // Wraps up the code generation for a tile block of a reduction kernel. + void EmitEpilogueForReduction(HloInstruction* unnested_hlo, + KernelCodegenInfo* kernel_info); + // For each reducer, emits the shuffle-down loop to accumulate the partial + // result to the global result. + void EmitFullWarpShuffleDownLoopForAllReduces( + const absl::InlinedVector& reducers, + const absl::InlinedVector& + partial_result_addresses); // Generates the IrArray for each input of an hlo and returns a vector that // constains such IrArrays. diff --git a/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.cc b/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.cc index c26711e526..1aa85eb8d2 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.cc +++ b/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.cc @@ -120,7 +120,7 @@ KernelMappingScheme::KernelMappingScheme( absl::Span req_block_sizes, int64 num_threads_y, int64 num_threads_x, llvm::IRBuilder<>* b) : b_(b), - dims_in_elems_(dims_in_elems), + dims_in_elems_(dims_in_elems.begin(), dims_in_elems.end()), tile_sizes_{1, tile_size_y, tile_size_x}, num_threads_x_(num_threads_x), num_threads_y_(num_threads_y) { diff --git a/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.h b/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.h index 06002d57b0..7277aeac8a 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.h +++ b/tensorflow/compiler/xla/service/llvm_ir/kernel_tiling.h @@ -90,15 +90,16 @@ class KernelMappingScheme { enum { DimZ = 0, DimY, DimX, DimTot }; public: + KernelMappingScheme() {} // dims_in_elems: the normalized tensor dimensions. // req_block_sizes: the requested block size in number of tiles for each // dimension. The actual block size is set to min(req_block_size, // dims_in_number_of_blocks). - explicit KernelMappingScheme(absl::Span dims_in_elems, - int64 tile_size_y, int64 tile_size_x, - absl::Span req_block_sizes, - int64 num_threads_y, int64 num_threads_x, - llvm::IRBuilder<>* b); + KernelMappingScheme(absl::Span dims_in_elems, int64 tile_size_y, + int64 tile_size_x, + absl::Span req_block_sizes, + int64 num_threads_y, int64 num_threads_x, + llvm::IRBuilder<>* b); absl::Span GetDimensionsInElements() const { return dims_in_elems_; @@ -133,6 +134,10 @@ class KernelMappingScheme { } absl::Span GetBlockSizes() const { return block_sizes_; } + int64 GetTileBlockSizeForDimension(int d) const { + DCHECK(d >= DimZ && d <= DimX); + return dims_in_blocks_[d]; + } int64 GetNumberOfThreadsForDimensionX() const { return num_threads_x_; } int64 GetNumberOfThreadsForDimensionY() const { return num_threads_y_; } @@ -163,7 +168,7 @@ class KernelMappingScheme { private: llvm::IRBuilder<>* b_; // The number of elements in each dimension. - absl::Span dims_in_elems_; + std::vector dims_in_elems_; // The number of elements for each dimension of a tile. std::vector tile_sizes_; -- GitLab From d21436b6fc251e84350efb2a0a1c181a05140a5c Mon Sep 17 00:00:00 2001 From: Pete Warden Date: Sun, 25 Nov 2018 14:46:49 -0800 Subject: [PATCH 283/672] Add input processing to micro speech example PiperOrigin-RevId: 222753537 --- .../micro/examples/micro_speech/BUILD | 79 ++++++++++++ .../examples/micro_speech/audio_provider.cc | 33 +++++ .../examples/micro_speech/audio_provider.h | 36 ++++++ .../micro_speech/audio_provider_test.cc | 44 +++++++ .../examples/micro_speech/feature_provider.cc | 121 ++++++++++++++++++ .../examples/micro_speech/feature_provider.h | 48 +++++++ .../micro_speech/feature_provider_test.cc | 38 ++++++ .../micro_speech/fixed_point/preprocessor.cc | 44 +++---- .../micro/examples/micro_speech/main.cc | 112 ++++++++++++++++ .../examples/micro_speech/model_settings.h | 47 +++++++ .../examples/micro_speech/preprocessor.cc | 36 +++--- .../examples/micro_speech/preprocessor.h | 5 + .../micro/examples/micro_speech/timer.cc | 22 ++++ .../micro/examples/micro_speech/timer.h | 31 +++++ .../micro/examples/micro_speech/timer_test.cc | 46 +++++++ .../experimental/micro/testing/micro_test.h | 18 +++ 16 files changed, 715 insertions(+), 45 deletions(-) create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/main.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD b/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD index 07fb876411..d48eb656b5 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD @@ -34,6 +34,7 @@ tflite_micro_cc_test( tflite_micro_cc_test( name = "preprocessor_reference_test", srcs = [ + "model_settings.h", "no_30ms_sample_data.cc", "no_30ms_sample_data.h", "no_power_spectrum_data.cc", @@ -57,6 +58,7 @@ tflite_micro_cc_test( name = "preprocessor_fixed_test", srcs = [ "fixed_point/preprocessor.cc", + "model_settings.h", "no_30ms_sample_data.cc", "no_30ms_sample_data.h", "no_power_spectrum_data.cc", @@ -74,3 +76,80 @@ tflite_micro_cc_test( "//tensorflow/lite/experimental/micro/testing:micro_test", ], ) + +tflite_micro_cc_test( + name = "audio_provider_test", + srcs = [ + "audio_provider.cc", + "audio_provider.h", + "audio_provider_test.cc", + "model_settings.h", + ], + deps = [ + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + +tflite_micro_cc_test( + name = "feature_provider_test", + srcs = [ + "audio_provider.cc", + "audio_provider.h", + "feature_provider.cc", + "feature_provider.h", + "feature_provider_test.cc", + "model_settings.h", + "preprocessor.cc", + "preprocessor.h", + "timer.cc", + "timer.h", + ], + deps = [ + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + +tflite_micro_cc_test( + name = "timer_test", + srcs = [ + "timer.cc", + "timer.h", + "timer_test.cc", + ], + deps = [ + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + +cc_binary( + name = "micro_speech", + srcs = [ + "audio_provider.cc", + "audio_provider.h", + "feature_provider.cc", + "feature_provider.h", + "main.cc", + "model_settings.h", + "preprocessor.cc", + "preprocessor.h", + "timer.cc", + "timer.h", + "tiny_conv_model_data.cc", + "tiny_conv_model_data.h", + "yes_features_data.cc", + "yes_features_data.h", + ], + deps = [ + "//tensorflow/lite:schema_fbs_version", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/kernels:all_ops_resolver", + "//tensorflow/lite/experimental/micro/kernels:micro_ops", + "//tensorflow/lite/schema:schema_fbs", + ], +) diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc new file mode 100644 index 0000000000..c0365d5690 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc @@ -0,0 +1,33 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" + +namespace { +int16_t g_dummy_audio_data[kMaxAudioSampleSize]; +} // namespace + +TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, + int start_ms, int duration_ms, + int* audio_samples_size, int16_t** audio_samples) { + for (int i = 0; i < kMaxAudioSampleSize; ++i) { + g_dummy_audio_data[i] = 0; + } + *audio_samples_size = kMaxAudioSampleSize; + *audio_samples = g_dummy_audio_data; + return kTfLiteOk; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h new file mode 100644 index 0000000000..7e2442a5e8 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h @@ -0,0 +1,36 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" + +// This is an abstraction around an audio source like a microphone, and is +// expected to return 16-bit PCM sample data for a given point in time. The +// sample data itself should be used as quickly as possible by the caller, since +// to allow memory optimizations there are no guarantees that the samples won't +// be overwritten by new data in the future. In practice, implementations should +// ensure that there's a reasonable time allowed for clients to access the data +// before any reuse. +// The reference implementation can have no platform-specific dependencies, so +// it just returns an array filled with zeros. For real applications, you should +// ensure there's a specialized implementation that accesses hardware APIs. +TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, + int start_ms, int duration_ms, + int* audio_samples_size, int16_t** audio_samples); + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc new file mode 100644 index 0000000000..5f7c7605f0 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc @@ -0,0 +1,44 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(TestAudioProvider) { + tflite::MicroErrorReporter micro_error_reporter; + tflite::ErrorReporter* error_reporter = µ_error_reporter; + + int audio_samples_size = 0; + int16_t* audio_samples = nullptr; + TfLiteStatus get_status = + GetAudioSamples(error_reporter, 0, kFeatureSliceDurationMs, + &audio_samples_size, &audio_samples); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, get_status); + TF_LITE_MICRO_EXPECT_LE(audio_samples_size, kMaxAudioSampleSize); + TF_LITE_MICRO_EXPECT_NE(audio_samples, nullptr); + + // Make sure we can read all of the returned memory locations. + int total = 0; + for (int i = 0; i < audio_samples_size; ++i) { + total += audio_samples[i]; + } +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc new file mode 100644 index 0000000000..c4c52ac0ff --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc @@ -0,0 +1,121 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" + +namespace { +// Stores the timestamp for the previous fetch of audio data, so that we can +// avoid recalculating all the features from scratch if some earlier timeslices +// are still present. +int32_t g_last_time_in_ms = 0; +// Make sure we don't try to use cached information if this is the first call +// into the provider. +bool g_is_first_run = true; +} // namespace + +FeatureProvider::FeatureProvider(int feature_size, uint8_t* feature_data) + : feature_size_(feature_size), feature_data_(feature_data) { + // Initialize the feature data to default values. + for (int n = 0; n < feature_size_; ++n) { + feature_data_[n] = 0; + } +} + +FeatureProvider::~FeatureProvider() {} + +TfLiteStatus FeatureProvider::PopulateFeatureData( + tflite::ErrorReporter* error_reporter, int* how_many_new_slices) { + if (feature_size_ != kFeatureElementCount) { + error_reporter->Report("Requested feature_data_ size %d doesn't match %d", + feature_size_, kFeatureElementCount); + return kTfLiteError; + } + + const int32_t time_in_ms = TimeInMilliseconds(); + // Quantize the time into steps as long as each window stride, so we can + // figure out which audio data we need to fetch. + const int last_step = (g_last_time_in_ms / kFeatureSliceStrideMs); + const int current_step = (time_in_ms / kFeatureSliceStrideMs); + g_last_time_in_ms = time_in_ms; + + int slices_needed = current_step - last_step; + // If this is the first call, make sure we don't use any cached information. + if (g_is_first_run) { + g_is_first_run = false; + slices_needed = kFeatureSliceCount; + } + if (slices_needed > kFeatureSliceCount) { + slices_needed = kFeatureSliceCount; + } + *how_many_new_slices = slices_needed; + + const int slices_to_keep = kFeatureSliceCount - slices_needed; + const int slices_to_drop = kFeatureSliceCount - slices_to_keep; + // If we can avoid recalculating some slices, just move the existing data + // up in the spectrogram, to perform something like this: + // last time = 80ms current time = 120ms + // +-----------+ +-----------+ + // | data@20ms | --> | data@60ms | + // +-----------+ -- +-----------+ + // | data@40ms | -- --> | data@80ms | + // +-----------+ -- -- +-----------+ + // | data@60ms | -- -- | | + // +-----------+ -- +-----------+ + // | data@80ms | -- | | + // +-----------+ +-----------+ + if (slices_to_keep > 0) { + for (int dest_slice = 0; dest_slice < slices_to_keep; ++dest_slice) { + uint8_t* dest_slice_data = + feature_data_ + (dest_slice * kFeatureSliceSize); + const int src_slice = dest_slice + slices_to_drop; + const uint8_t* src_slice_data = + feature_data_ + (src_slice * kFeatureSliceSize); + for (int i = 0; i < kFeatureSliceSize; ++i) { + dest_slice_data[i] = src_slice_data[i]; + } + } + } + // Any slices that need to be filled in with feature data have their + // appropriate audio data pulled, and features calculated for that slice. + if (slices_needed > 0) { + for (int new_slice = slices_to_keep; new_slice < kFeatureSliceCount; + ++new_slice) { + const int new_step = (current_step - kFeatureSliceCount + 1) + new_slice; + const int32_t slice_start_ms = (new_step * kFeatureSliceStrideMs); + int16_t* audio_samples = nullptr; + int audio_samples_size = 0; + GetAudioSamples(error_reporter, slice_start_ms, kFeatureSliceDurationMs, + &audio_samples_size, &audio_samples); + if (audio_samples_size < kMaxAudioSampleSize) { + error_reporter->Report("Audio data size %d too small, want %d", + audio_samples_size, kMaxAudioSampleSize); + return kTfLiteError; + } + uint8_t* new_slice_data = feature_data_ + (new_slice * kFeatureSliceSize); + TfLiteStatus preprocess_status = + Preprocess(error_reporter, audio_samples, audio_samples_size, + kFeatureSliceSize, new_slice_data); + if (preprocess_status != kTfLiteOk) { + return preprocess_status; + } + } + } + return kTfLiteOk; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h new file mode 100644 index 0000000000..a86c56ebf0 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h @@ -0,0 +1,48 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" + +// Binds itself to an area of memory intended to hold the input features for an +// audio-recognition neural network model, and fills that data area with the +// features representing the current audio input, for example from a microphone. +// The audio features themselves are a two-dimensional array, made up of +// horizontal slices representing the frequencies at one point in time, stacked +// on top of each other to form a spectrogram showing how those frequencies +// changed over time. +class FeatureProvider { + public: + // Create the provider, and bind it to an area of memory. This memory should + // remain accessible for the lifetime of the provider object, since subsequent + // calls will fill it with feature data. The provider does no memory + // management of this data. + FeatureProvider(int feature_size, uint8_t* feature_data); + ~FeatureProvider(); + + // Fills the feature data with information from audio inputs, and returns how + // many feature slices were updated. + TfLiteStatus PopulateFeatureData(tflite::ErrorReporter* error_reporter, + int* how_many_new_slices); + + private: + int feature_size_; + uint8_t* feature_data_; +}; + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc new file mode 100644 index 0000000000..1e52aec8d2 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(TestFeatureProvider) { + tflite::MicroErrorReporter micro_error_reporter; + tflite::ErrorReporter* error_reporter = µ_error_reporter; + + uint8_t feature_data[kFeatureElementCount]; + FeatureProvider feature_provider(kFeatureElementCount, feature_data); + + int how_many_new_slices = 0; + TfLiteStatus populate_status = feature_provider.PopulateFeatureData( + error_reporter, &how_many_new_slices); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, populate_status); + TF_LITE_MICRO_EXPECT_EQ(kFeatureSliceCount, how_many_new_slices); +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc index de60c982f3..b623d8d11b 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc @@ -31,6 +31,8 @@ limitations under the License. #include +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" + namespace { // q format notation: qx.y => 1 sign bit, x-1 integer bits, y fraction bits. @@ -66,13 +68,6 @@ inline int32_t FloatToFixed_Q2_30(float input) { return static_cast(roundf(input * (1 << 30))); } -// These constants allow us to allocate fixed-sized arrays on the stack for our -// working memory. -constexpr int kInputSize = 512; -constexpr int kAverageWindowSize = 6; -constexpr int kOutputSize = - ((kInputSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; - // Performs a discrete Fourier transform on the real inputs. This corresponds to // rdft() in the FFT package at http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html, // and to kiss_fftr() in KISSFFT at https://github.com/mborgerding/kissfft. @@ -127,14 +122,14 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output) { // Ensure our input and output data arrays are valid. - if (input_size > kInputSize) { + if (input_size > kMaxAudioSampleSize) { error_reporter->Report("Input size %d larger than %d", input_size, - kInputSize); + kMaxAudioSampleSize); return kTfLiteError; } - if (output_size != kOutputSize) { + if (output_size != kFeatureSliceSize) { error_reporter->Report("Requested output size %d doesn't match %d", - output_size, kOutputSize); + output_size, kFeatureSliceSize); return kTfLiteError; } @@ -142,18 +137,17 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // In a real application, we'd calculate this table once in an initialization // function and store it for repeated reuse. // q1.15 format. - int16_t window_function[kInputSize]; + int16_t window_function[kMaxAudioSampleSize]; CalculatePeriodicHann(input_size, window_function); // Apply the window function to our time series input, and pad it with zeroes // to the next power of two. - int32_t fixed_input[kInputSize]; - for (int i = 0; i < kInputSize; ++i) { + int32_t fixed_input[kMaxAudioSampleSize]; + for (int i = 0; i < kMaxAudioSampleSize; ++i) { if (i < input_size) { // input is int16_t. Treat as q1.15 fixed point value in range [-1,1) // window_function is also q1.15 fixed point number - fixed_input[i] = - Q1_15_FixedMultiply_Q2_30(input[i], window_function[i]); + fixed_input[i] = Q1_15_FixedMultiply_Q2_30(input[i], window_function[i]); } else { fixed_input[i] = 0; } @@ -161,31 +155,31 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // Pull the frequency data from the time series sample. // Calculated in q10.22 format from q2.30 inputs. - int32_t fourier_values[kInputSize]; - CalculateDiscreteFourierTransform(fixed_input, kInputSize, fourier_values); + int32_t fourier_values[kMaxAudioSampleSize]; + CalculateDiscreteFourierTransform(fixed_input, kMaxAudioSampleSize, + fourier_values); // We have the complex numbers giving us information about each frequency // band, but all we want to know is how strong each frequency is, so calculate // the squared magnitude by adding together the squares of each component. - int32_t power_spectrum[kInputSize / 2]; - for (int i = 0; i < (kInputSize / 2); ++i) { + int32_t power_spectrum[kMaxAudioSampleSize / 2]; + for (int i = 0; i < (kMaxAudioSampleSize / 2); ++i) { const int32_t real = fourier_values[(i * 2) + 0]; const int32_t imaginary = fourier_values[(i * 2) + 1]; // q10.22 results - power_spectrum[i] = - Q10_22_FixedMultiply_Q10_22(real, real) + - Q10_22_FixedMultiply_Q10_22(imaginary, imaginary); + power_spectrum[i] = Q10_22_FixedMultiply_Q10_22(real, real) + + Q10_22_FixedMultiply_Q10_22(imaginary, imaginary); } // Finally, reduce the size of the output by averaging together six adjacent // frequencies into each slot, producing an array of 43 values. // Power_spectrum numbers are q10.22. Divide by kAverageWindowSize inside // loop to prevent overflow. - for (int i = 0; i < kOutputSize; ++i) { + for (int i = 0; i < kFeatureSliceSize; ++i) { int32_t average = 0; for (int j = 0; j < kAverageWindowSize; ++j) { const int index = (i * kAverageWindowSize) + j; - if (index < (kInputSize / 2)) { + if (index < (kMaxAudioSampleSize / 2)) { average += power_spectrum[index] / kAverageWindowSize; } } diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc new file mode 100644 index 0000000000..1890c25cf2 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc @@ -0,0 +1,112 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/tiny_conv_model_data.h" +#include "tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/micro_interpreter.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include "tensorflow/lite/version.h" + +int main(int argc, char* argv[]) { + // Set up logging. + tflite::MicroErrorReporter micro_error_reporter; + tflite::ErrorReporter* error_reporter = µ_error_reporter; + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + const tflite::Model* model = ::tflite::GetModel(g_tiny_conv_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + error_reporter->Report( + "Model provided is schema version %d not equal " + "to supported version %d.\n", + model->version(), TFLITE_SCHEMA_VERSION); + return 1; + } + + // This pulls in all the operation implementations we need. + tflite::ops::micro::AllOpsResolver resolver; + + // Create an area of memory to use for input, output, and intermediate arrays. + // The size of this will depend on the model you're using, and may need to be + // determined by experimentation. + const int tensor_arena_size = 10 * 1024; + uint8_t tensor_arena[tensor_arena_size]; + tflite::SimpleTensorAllocator tensor_allocator(tensor_arena, + tensor_arena_size); + + // Build an interpreter to run the model with. + tflite::MicroInterpreter interpreter(model, resolver, &tensor_allocator, + error_reporter); + + // Get information about the memory area to use for the model's input. + TfLiteTensor* model_input = interpreter.input(0); + if ((model_input->dims->size != 4) || (model_input->dims->data[0] != 1) || + (model_input->dims->data[1] != kFeatureSliceCount) || + (model_input->dims->data[2] != kFeatureSliceSize) || + (model_input->type != kTfLiteUInt8)) { + error_reporter->Report("Bad input tensor parameters in model"); + return 1; + } + + // Prepare to access the audio spectrograms from a microphone or other source + // that will provide the inputs to the neural network. + FeatureProvider feature_provider(kFeatureElementCount, + model_input->data.uint8); + + // Keep reading and analysing audio data in an infinite loop. + while (true) { + // Fetch the spectrogram for the current time. + int how_many_new_slices = 0; + TfLiteStatus feature_status = feature_provider.PopulateFeatureData( + error_reporter, &how_many_new_slices); + if (feature_status != kTfLiteOk) { + error_reporter->Report("Feature generation failed"); + return 1; + } + // If no new audio samples have been received since last time, don't bother + // running the network model. + if (how_many_new_slices == 0) { + continue; + } + + // Run the model on the spectrogram input and make sure it succeeds. + TfLiteStatus invoke_status = interpreter.Invoke(); + if (invoke_status != kTfLiteOk) { + error_reporter->Report("Invoke failed"); + return 1; + } + + // The output from the model is a vector containing the scores for each + // kind of prediction, so figure out what the highest scoring category was. + TfLiteTensor* output = interpreter.output(0); + uint8_t top_category_score = 0; + int top_category_index = 0; + for (int category_index = 0; category_index < kCategoryCount; + ++category_index) { + const uint8_t category_score = output->data.uint8[category_index]; + if (category_score > top_category_score) { + top_category_score = category_score; + top_category_index = category_index; + } + } + + error_reporter->Report("Heard %s", kCategoryLabels[top_category_index]); + } + + return 0; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h new file mode 100644 index 0000000000..88369a07ee --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h @@ -0,0 +1,47 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ + +// Keeping these as constant expressions allow us to allocate fixed-sized arrays +// on the stack for our working memory. + +// The size of the input time series data we pass to the FFT to produce the +// frequency information. This has to be a power of two, and since we're dealing +// with 30ms of 16KHz inputs, which means 480 samples, this is the next value. +constexpr int kMaxAudioSampleSize = 512; + +// All of these values are derived from the values used during model training, +// if you change your model you'll need to update these constants. +constexpr int kAverageWindowSize = 6; +constexpr int kFeatureSliceSize = + ((kMaxAudioSampleSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; +constexpr int kFeatureSliceCount = 49; +constexpr int kFeatureElementCount = (kFeatureSliceSize * kFeatureSliceCount); +constexpr int kFeatureSliceStrideMs = 20; +constexpr int kFeatureSliceDurationMs = 30; + +constexpr int kCategoryCount = 4; +constexpr int kSilenceIndex = 0; +constexpr int kUnknownIndex = 1; +constexpr char* kCategoryLabels[kCategoryCount] = { + "silence", + "unknown", + "yes", + "no", +}; + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc index 12f9e22038..f4a7f801cc 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc @@ -28,14 +28,9 @@ limitations under the License. #include -namespace { +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" -// These constants allow us to allocate fixed-sized arrays on the stack for our -// working memory. -constexpr int kInputSize = 512; -constexpr int kAverageWindowSize = 6; -constexpr int kOutputSize = - ((kInputSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; +namespace { // Performs a discrete Fourier transform on the real inputs. This corresponds to // rdft() in the FFT package at http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html, @@ -78,27 +73,27 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output) { // Ensure our input and output data arrays are valid. - if (input_size > kInputSize) { + if (input_size > kMaxAudioSampleSize) { error_reporter->Report("Input size %d larger than %d", input_size, - kInputSize); + kMaxAudioSampleSize); return kTfLiteError; } - if (output_size != kOutputSize) { + if (output_size != kFeatureSliceSize) { error_reporter->Report("Requested output size %d doesn't match %d", - output_size, kOutputSize); + output_size, kFeatureSliceSize); return kTfLiteError; } // Pre-calculate the window function we'll be applying to the input data. // In a real application, we'd calculate this table once in an initialization // function and store it for repeated reuse. - float window_function[kInputSize]; + float window_function[kMaxAudioSampleSize]; CalculatePeriodicHann(input_size, window_function); // Apply the window function to our time series input, and pad it with zeroes // to the next power of two. - float float_input[kInputSize]; - for (int i = 0; i < kInputSize; ++i) { + float float_input[kMaxAudioSampleSize]; + for (int i = 0; i < kMaxAudioSampleSize; ++i) { if (i < input_size) { float_input[i] = (input[i] * window_function[i]) / static_cast(1 << 15); @@ -108,14 +103,15 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, } // Pull the frequency data from the time series sample. - float fourier_values[kInputSize]; - CalculateDiscreteFourierTransform(float_input, kInputSize, fourier_values); + float fourier_values[kMaxAudioSampleSize]; + CalculateDiscreteFourierTransform(float_input, kMaxAudioSampleSize, + fourier_values); // We have the complex numbers giving us information about each frequency // band, but all we want to know is how strong each frequency is, so calculate // the squared magnitude by adding together the squares of each component. - float power_spectrum[kInputSize / 2]; - for (int i = 0; i < (kInputSize / 2); ++i) { + float power_spectrum[kMaxAudioSampleSize / 2]; + for (int i = 0; i < (kMaxAudioSampleSize / 2); ++i) { const float real = fourier_values[(i * 2) + 0]; const float imaginary = fourier_values[(i * 2) + 1]; power_spectrum[i] = (real * real) + (imaginary * imaginary); @@ -123,11 +119,11 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // Finally, reduce the size of the output by averaging together six adjacent // frequencies into each slot, producing an array of 43 values. - for (int i = 0; i < kOutputSize; ++i) { + for (int i = 0; i < kFeatureSliceSize; ++i) { float total = 0.0f; for (int j = 0; j < kAverageWindowSize; ++j) { const int index = (i * kAverageWindowSize) + j; - if (index < (kInputSize / 2)) { + if (index < (kMaxAudioSampleSize / 2)) { total += power_spectrum[index]; } } diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h index dede2a8642..adff790d6c 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h @@ -19,6 +19,11 @@ limitations under the License. #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +// Converts audio sample data into a more compact form that's appropriate for +// feeding into a neural network. There are reference implementations that use +// both floating point and fixed point available, but because the calculations +// involved can be time-consuming, it's recommended that you use or write +// specialized versions for your platform. TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output); diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc new file mode 100644 index 0000000000..6c96a61ab5 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc @@ -0,0 +1,22 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" + +int32_t TimeInMilliseconds() { + static int current_time = 0; + current_time += 100; + return current_time; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h new file mode 100644 index 0000000000..162952844a --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h @@ -0,0 +1,31 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ + +#include + +// Returns the time in milliseconds. There's no contract about what time zero +// represents, the accuracy, or the granularity of the result. Subsequent calls +// will generally not return a lower value, but even that's not guaranteed if +// there's an overflow wraparound. +// The reference implementation of this function just returns a constantly +// incrementing value for each call, since it would need a non-portable platform +// call to access time information. For real applications, you'll need to write +// your own platform-specific implementation. +int32_t TimeInMilliseconds(); + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc new file mode 100644 index 0000000000..83a2dfcc65 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc @@ -0,0 +1,46 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" + +#include + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(TestTimer) { + // Make sure that the technically-undefined overflow behavior we rely on below + // works on this platform. It's still not guaranteed, but at least this is a + // sanity check. + int32_t overflow_value = std::numeric_limits::max(); + overflow_value += 1; + TF_LITE_MICRO_EXPECT_EQ(std::numeric_limits::min(), overflow_value); + + const int32_t first_time = TimeInMilliseconds(); + const int32_t second_time = TimeInMilliseconds(); + + // It's possible that the timer may have wrapped around from +BIG_NUM to + // -BIG_NUM between the first and second calls, since we're storing + // milliseconds in a 32-bit integer. It's not reasonable that the call itself + // would have taken more than 2^31 milliseconds though, so look at the + // difference and rely on integer overflow to ensure it's accurate. + const int32_t time_delta = (second_time - first_time); + TF_LITE_MICRO_EXPECT_LE(0, time_delta); +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/testing/micro_test.h b/tensorflow/lite/experimental/micro/testing/micro_test.h index 10bab05fae..2f20dd5ac7 100644 --- a/tensorflow/lite/experimental/micro/testing/micro_test.h +++ b/tensorflow/lite/experimental/micro/testing/micro_test.h @@ -153,4 +153,22 @@ extern tflite::ErrorReporter* reporter; } \ } while (false) +#define TF_LITE_MICRO_EXPECT_GE(x, y) \ + do { \ + if ((x) < (y)) { \ + micro_test::reporter->Report(#x " >= " #y " failed at %s:%d", __FILE__, \ + __LINE__); \ + micro_test::did_test_fail = true; \ + } \ + } while (false) + +#define TF_LITE_MICRO_EXPECT_LE(x, y) \ + do { \ + if ((x) > (y)) { \ + micro_test::reporter->Report(#x " <= " #y " failed at %s:%d", __FILE__, \ + __LINE__); \ + micro_test::did_test_fail = true; \ + } \ + } while (false) + #endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_TESTING_MICRO_TEST_H_ -- GitLab From a49887b0d24c9c1a97c5915147473bb09f854ebc Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sun, 25 Nov 2018 14:52:14 -0800 Subject: [PATCH 284/672] Automated rollback of commit d21436b6fc251e84350efb2a0a1c181a05140a5c PiperOrigin-RevId: 222753714 --- .../micro/examples/micro_speech/BUILD | 79 ------------ .../examples/micro_speech/audio_provider.cc | 33 ----- .../examples/micro_speech/audio_provider.h | 36 ------ .../micro_speech/audio_provider_test.cc | 44 ------- .../examples/micro_speech/feature_provider.cc | 121 ------------------ .../examples/micro_speech/feature_provider.h | 48 ------- .../micro_speech/feature_provider_test.cc | 38 ------ .../micro_speech/fixed_point/preprocessor.cc | 44 ++++--- .../micro/examples/micro_speech/main.cc | 112 ---------------- .../examples/micro_speech/model_settings.h | 47 ------- .../examples/micro_speech/preprocessor.cc | 36 +++--- .../examples/micro_speech/preprocessor.h | 5 - .../micro/examples/micro_speech/timer.cc | 22 ---- .../micro/examples/micro_speech/timer.h | 31 ----- .../micro/examples/micro_speech/timer_test.cc | 46 ------- .../experimental/micro/testing/micro_test.h | 18 --- 16 files changed, 45 insertions(+), 715 deletions(-) delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/main.cc delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer.h delete mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD b/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD index d48eb656b5..07fb876411 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD @@ -34,7 +34,6 @@ tflite_micro_cc_test( tflite_micro_cc_test( name = "preprocessor_reference_test", srcs = [ - "model_settings.h", "no_30ms_sample_data.cc", "no_30ms_sample_data.h", "no_power_spectrum_data.cc", @@ -58,7 +57,6 @@ tflite_micro_cc_test( name = "preprocessor_fixed_test", srcs = [ "fixed_point/preprocessor.cc", - "model_settings.h", "no_30ms_sample_data.cc", "no_30ms_sample_data.h", "no_power_spectrum_data.cc", @@ -76,80 +74,3 @@ tflite_micro_cc_test( "//tensorflow/lite/experimental/micro/testing:micro_test", ], ) - -tflite_micro_cc_test( - name = "audio_provider_test", - srcs = [ - "audio_provider.cc", - "audio_provider.h", - "audio_provider_test.cc", - "model_settings.h", - ], - deps = [ - "//tensorflow/lite/c:c_api_internal", - "//tensorflow/lite/experimental/micro:micro_framework", - "//tensorflow/lite/experimental/micro/testing:micro_test", - ], -) - -tflite_micro_cc_test( - name = "feature_provider_test", - srcs = [ - "audio_provider.cc", - "audio_provider.h", - "feature_provider.cc", - "feature_provider.h", - "feature_provider_test.cc", - "model_settings.h", - "preprocessor.cc", - "preprocessor.h", - "timer.cc", - "timer.h", - ], - deps = [ - "//tensorflow/lite/c:c_api_internal", - "//tensorflow/lite/experimental/micro:micro_framework", - "//tensorflow/lite/experimental/micro/testing:micro_test", - ], -) - -tflite_micro_cc_test( - name = "timer_test", - srcs = [ - "timer.cc", - "timer.h", - "timer_test.cc", - ], - deps = [ - "//tensorflow/lite/c:c_api_internal", - "//tensorflow/lite/experimental/micro:micro_framework", - "//tensorflow/lite/experimental/micro/testing:micro_test", - ], -) - -cc_binary( - name = "micro_speech", - srcs = [ - "audio_provider.cc", - "audio_provider.h", - "feature_provider.cc", - "feature_provider.h", - "main.cc", - "model_settings.h", - "preprocessor.cc", - "preprocessor.h", - "timer.cc", - "timer.h", - "tiny_conv_model_data.cc", - "tiny_conv_model_data.h", - "yes_features_data.cc", - "yes_features_data.h", - ], - deps = [ - "//tensorflow/lite:schema_fbs_version", - "//tensorflow/lite/experimental/micro:micro_framework", - "//tensorflow/lite/experimental/micro/kernels:all_ops_resolver", - "//tensorflow/lite/experimental/micro/kernels:micro_ops", - "//tensorflow/lite/schema:schema_fbs", - ], -) diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc deleted file mode 100644 index c0365d5690..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" - -namespace { -int16_t g_dummy_audio_data[kMaxAudioSampleSize]; -} // namespace - -TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, - int start_ms, int duration_ms, - int* audio_samples_size, int16_t** audio_samples) { - for (int i = 0; i < kMaxAudioSampleSize; ++i) { - g_dummy_audio_data[i] = 0; - } - *audio_samples_size = kMaxAudioSampleSize; - *audio_samples = g_dummy_audio_data; - return kTfLiteOk; -} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h deleted file mode 100644 index 7e2442a5e8..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ -#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ - -#include "tensorflow/lite/c/c_api_internal.h" -#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" - -// This is an abstraction around an audio source like a microphone, and is -// expected to return 16-bit PCM sample data for a given point in time. The -// sample data itself should be used as quickly as possible by the caller, since -// to allow memory optimizations there are no guarantees that the samples won't -// be overwritten by new data in the future. In practice, implementations should -// ensure that there's a reasonable time allowed for clients to access the data -// before any reuse. -// The reference implementation can have no platform-specific dependencies, so -// it just returns an array filled with zeros. For real applications, you should -// ensure there's a specialized implementation that accesses hardware APIs. -TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, - int start_ms, int duration_ms, - int* audio_samples_size, int16_t** audio_samples); - -#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc deleted file mode 100644 index 5f7c7605f0..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" -#include "tensorflow/lite/c/c_api_internal.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" -#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" -#include "tensorflow/lite/experimental/micro/testing/micro_test.h" - -TF_LITE_MICRO_TESTS_BEGIN - -TF_LITE_MICRO_TEST(TestAudioProvider) { - tflite::MicroErrorReporter micro_error_reporter; - tflite::ErrorReporter* error_reporter = µ_error_reporter; - - int audio_samples_size = 0; - int16_t* audio_samples = nullptr; - TfLiteStatus get_status = - GetAudioSamples(error_reporter, 0, kFeatureSliceDurationMs, - &audio_samples_size, &audio_samples); - TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, get_status); - TF_LITE_MICRO_EXPECT_LE(audio_samples_size, kMaxAudioSampleSize); - TF_LITE_MICRO_EXPECT_NE(audio_samples, nullptr); - - // Make sure we can read all of the returned memory locations. - int total = 0; - for (int i = 0; i < audio_samples_size; ++i) { - total += audio_samples[i]; - } -} - -TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc deleted file mode 100644 index c4c52ac0ff..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" - -namespace { -// Stores the timestamp for the previous fetch of audio data, so that we can -// avoid recalculating all the features from scratch if some earlier timeslices -// are still present. -int32_t g_last_time_in_ms = 0; -// Make sure we don't try to use cached information if this is the first call -// into the provider. -bool g_is_first_run = true; -} // namespace - -FeatureProvider::FeatureProvider(int feature_size, uint8_t* feature_data) - : feature_size_(feature_size), feature_data_(feature_data) { - // Initialize the feature data to default values. - for (int n = 0; n < feature_size_; ++n) { - feature_data_[n] = 0; - } -} - -FeatureProvider::~FeatureProvider() {} - -TfLiteStatus FeatureProvider::PopulateFeatureData( - tflite::ErrorReporter* error_reporter, int* how_many_new_slices) { - if (feature_size_ != kFeatureElementCount) { - error_reporter->Report("Requested feature_data_ size %d doesn't match %d", - feature_size_, kFeatureElementCount); - return kTfLiteError; - } - - const int32_t time_in_ms = TimeInMilliseconds(); - // Quantize the time into steps as long as each window stride, so we can - // figure out which audio data we need to fetch. - const int last_step = (g_last_time_in_ms / kFeatureSliceStrideMs); - const int current_step = (time_in_ms / kFeatureSliceStrideMs); - g_last_time_in_ms = time_in_ms; - - int slices_needed = current_step - last_step; - // If this is the first call, make sure we don't use any cached information. - if (g_is_first_run) { - g_is_first_run = false; - slices_needed = kFeatureSliceCount; - } - if (slices_needed > kFeatureSliceCount) { - slices_needed = kFeatureSliceCount; - } - *how_many_new_slices = slices_needed; - - const int slices_to_keep = kFeatureSliceCount - slices_needed; - const int slices_to_drop = kFeatureSliceCount - slices_to_keep; - // If we can avoid recalculating some slices, just move the existing data - // up in the spectrogram, to perform something like this: - // last time = 80ms current time = 120ms - // +-----------+ +-----------+ - // | data@20ms | --> | data@60ms | - // +-----------+ -- +-----------+ - // | data@40ms | -- --> | data@80ms | - // +-----------+ -- -- +-----------+ - // | data@60ms | -- -- | | - // +-----------+ -- +-----------+ - // | data@80ms | -- | | - // +-----------+ +-----------+ - if (slices_to_keep > 0) { - for (int dest_slice = 0; dest_slice < slices_to_keep; ++dest_slice) { - uint8_t* dest_slice_data = - feature_data_ + (dest_slice * kFeatureSliceSize); - const int src_slice = dest_slice + slices_to_drop; - const uint8_t* src_slice_data = - feature_data_ + (src_slice * kFeatureSliceSize); - for (int i = 0; i < kFeatureSliceSize; ++i) { - dest_slice_data[i] = src_slice_data[i]; - } - } - } - // Any slices that need to be filled in with feature data have their - // appropriate audio data pulled, and features calculated for that slice. - if (slices_needed > 0) { - for (int new_slice = slices_to_keep; new_slice < kFeatureSliceCount; - ++new_slice) { - const int new_step = (current_step - kFeatureSliceCount + 1) + new_slice; - const int32_t slice_start_ms = (new_step * kFeatureSliceStrideMs); - int16_t* audio_samples = nullptr; - int audio_samples_size = 0; - GetAudioSamples(error_reporter, slice_start_ms, kFeatureSliceDurationMs, - &audio_samples_size, &audio_samples); - if (audio_samples_size < kMaxAudioSampleSize) { - error_reporter->Report("Audio data size %d too small, want %d", - audio_samples_size, kMaxAudioSampleSize); - return kTfLiteError; - } - uint8_t* new_slice_data = feature_data_ + (new_slice * kFeatureSliceSize); - TfLiteStatus preprocess_status = - Preprocess(error_reporter, audio_samples, audio_samples_size, - kFeatureSliceSize, new_slice_data); - if (preprocess_status != kTfLiteOk) { - return preprocess_status; - } - } - } - return kTfLiteOk; -} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h deleted file mode 100644 index a86c56ebf0..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ -#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ - -#include "tensorflow/lite/c/c_api_internal.h" -#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" - -// Binds itself to an area of memory intended to hold the input features for an -// audio-recognition neural network model, and fills that data area with the -// features representing the current audio input, for example from a microphone. -// The audio features themselves are a two-dimensional array, made up of -// horizontal slices representing the frequencies at one point in time, stacked -// on top of each other to form a spectrogram showing how those frequencies -// changed over time. -class FeatureProvider { - public: - // Create the provider, and bind it to an area of memory. This memory should - // remain accessible for the lifetime of the provider object, since subsequent - // calls will fill it with feature data. The provider does no memory - // management of this data. - FeatureProvider(int feature_size, uint8_t* feature_data); - ~FeatureProvider(); - - // Fills the feature data with information from audio inputs, and returns how - // many feature slices were updated. - TfLiteStatus PopulateFeatureData(tflite::ErrorReporter* error_reporter, - int* how_many_new_slices); - - private: - int feature_size_; - uint8_t* feature_data_; -}; - -#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc deleted file mode 100644 index 1e52aec8d2..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" -#include "tensorflow/lite/c/c_api_internal.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" -#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" -#include "tensorflow/lite/experimental/micro/testing/micro_test.h" - -TF_LITE_MICRO_TESTS_BEGIN - -TF_LITE_MICRO_TEST(TestFeatureProvider) { - tflite::MicroErrorReporter micro_error_reporter; - tflite::ErrorReporter* error_reporter = µ_error_reporter; - - uint8_t feature_data[kFeatureElementCount]; - FeatureProvider feature_provider(kFeatureElementCount, feature_data); - - int how_many_new_slices = 0; - TfLiteStatus populate_status = feature_provider.PopulateFeatureData( - error_reporter, &how_many_new_slices); - TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, populate_status); - TF_LITE_MICRO_EXPECT_EQ(kFeatureSliceCount, how_many_new_slices); -} - -TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc index b623d8d11b..de60c982f3 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc @@ -31,8 +31,6 @@ limitations under the License. #include -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" - namespace { // q format notation: qx.y => 1 sign bit, x-1 integer bits, y fraction bits. @@ -68,6 +66,13 @@ inline int32_t FloatToFixed_Q2_30(float input) { return static_cast(roundf(input * (1 << 30))); } +// These constants allow us to allocate fixed-sized arrays on the stack for our +// working memory. +constexpr int kInputSize = 512; +constexpr int kAverageWindowSize = 6; +constexpr int kOutputSize = + ((kInputSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; + // Performs a discrete Fourier transform on the real inputs. This corresponds to // rdft() in the FFT package at http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html, // and to kiss_fftr() in KISSFFT at https://github.com/mborgerding/kissfft. @@ -122,14 +127,14 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output) { // Ensure our input and output data arrays are valid. - if (input_size > kMaxAudioSampleSize) { + if (input_size > kInputSize) { error_reporter->Report("Input size %d larger than %d", input_size, - kMaxAudioSampleSize); + kInputSize); return kTfLiteError; } - if (output_size != kFeatureSliceSize) { + if (output_size != kOutputSize) { error_reporter->Report("Requested output size %d doesn't match %d", - output_size, kFeatureSliceSize); + output_size, kOutputSize); return kTfLiteError; } @@ -137,17 +142,18 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // In a real application, we'd calculate this table once in an initialization // function and store it for repeated reuse. // q1.15 format. - int16_t window_function[kMaxAudioSampleSize]; + int16_t window_function[kInputSize]; CalculatePeriodicHann(input_size, window_function); // Apply the window function to our time series input, and pad it with zeroes // to the next power of two. - int32_t fixed_input[kMaxAudioSampleSize]; - for (int i = 0; i < kMaxAudioSampleSize; ++i) { + int32_t fixed_input[kInputSize]; + for (int i = 0; i < kInputSize; ++i) { if (i < input_size) { // input is int16_t. Treat as q1.15 fixed point value in range [-1,1) // window_function is also q1.15 fixed point number - fixed_input[i] = Q1_15_FixedMultiply_Q2_30(input[i], window_function[i]); + fixed_input[i] = + Q1_15_FixedMultiply_Q2_30(input[i], window_function[i]); } else { fixed_input[i] = 0; } @@ -155,31 +161,31 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // Pull the frequency data from the time series sample. // Calculated in q10.22 format from q2.30 inputs. - int32_t fourier_values[kMaxAudioSampleSize]; - CalculateDiscreteFourierTransform(fixed_input, kMaxAudioSampleSize, - fourier_values); + int32_t fourier_values[kInputSize]; + CalculateDiscreteFourierTransform(fixed_input, kInputSize, fourier_values); // We have the complex numbers giving us information about each frequency // band, but all we want to know is how strong each frequency is, so calculate // the squared magnitude by adding together the squares of each component. - int32_t power_spectrum[kMaxAudioSampleSize / 2]; - for (int i = 0; i < (kMaxAudioSampleSize / 2); ++i) { + int32_t power_spectrum[kInputSize / 2]; + for (int i = 0; i < (kInputSize / 2); ++i) { const int32_t real = fourier_values[(i * 2) + 0]; const int32_t imaginary = fourier_values[(i * 2) + 1]; // q10.22 results - power_spectrum[i] = Q10_22_FixedMultiply_Q10_22(real, real) + - Q10_22_FixedMultiply_Q10_22(imaginary, imaginary); + power_spectrum[i] = + Q10_22_FixedMultiply_Q10_22(real, real) + + Q10_22_FixedMultiply_Q10_22(imaginary, imaginary); } // Finally, reduce the size of the output by averaging together six adjacent // frequencies into each slot, producing an array of 43 values. // Power_spectrum numbers are q10.22. Divide by kAverageWindowSize inside // loop to prevent overflow. - for (int i = 0; i < kFeatureSliceSize; ++i) { + for (int i = 0; i < kOutputSize; ++i) { int32_t average = 0; for (int j = 0; j < kAverageWindowSize; ++j) { const int index = (i * kAverageWindowSize) + j; - if (index < (kMaxAudioSampleSize / 2)) { + if (index < (kInputSize / 2)) { average += power_spectrum[index] / kAverageWindowSize; } } diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc deleted file mode 100644 index 1890c25cf2..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" -#include "tensorflow/lite/experimental/micro/examples/micro_speech/tiny_conv_model_data.h" -#include "tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h" -#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" -#include "tensorflow/lite/experimental/micro/micro_interpreter.h" -#include "tensorflow/lite/schema/schema_generated.h" -#include "tensorflow/lite/version.h" - -int main(int argc, char* argv[]) { - // Set up logging. - tflite::MicroErrorReporter micro_error_reporter; - tflite::ErrorReporter* error_reporter = µ_error_reporter; - - // Map the model into a usable data structure. This doesn't involve any - // copying or parsing, it's a very lightweight operation. - const tflite::Model* model = ::tflite::GetModel(g_tiny_conv_model_data); - if (model->version() != TFLITE_SCHEMA_VERSION) { - error_reporter->Report( - "Model provided is schema version %d not equal " - "to supported version %d.\n", - model->version(), TFLITE_SCHEMA_VERSION); - return 1; - } - - // This pulls in all the operation implementations we need. - tflite::ops::micro::AllOpsResolver resolver; - - // Create an area of memory to use for input, output, and intermediate arrays. - // The size of this will depend on the model you're using, and may need to be - // determined by experimentation. - const int tensor_arena_size = 10 * 1024; - uint8_t tensor_arena[tensor_arena_size]; - tflite::SimpleTensorAllocator tensor_allocator(tensor_arena, - tensor_arena_size); - - // Build an interpreter to run the model with. - tflite::MicroInterpreter interpreter(model, resolver, &tensor_allocator, - error_reporter); - - // Get information about the memory area to use for the model's input. - TfLiteTensor* model_input = interpreter.input(0); - if ((model_input->dims->size != 4) || (model_input->dims->data[0] != 1) || - (model_input->dims->data[1] != kFeatureSliceCount) || - (model_input->dims->data[2] != kFeatureSliceSize) || - (model_input->type != kTfLiteUInt8)) { - error_reporter->Report("Bad input tensor parameters in model"); - return 1; - } - - // Prepare to access the audio spectrograms from a microphone or other source - // that will provide the inputs to the neural network. - FeatureProvider feature_provider(kFeatureElementCount, - model_input->data.uint8); - - // Keep reading and analysing audio data in an infinite loop. - while (true) { - // Fetch the spectrogram for the current time. - int how_many_new_slices = 0; - TfLiteStatus feature_status = feature_provider.PopulateFeatureData( - error_reporter, &how_many_new_slices); - if (feature_status != kTfLiteOk) { - error_reporter->Report("Feature generation failed"); - return 1; - } - // If no new audio samples have been received since last time, don't bother - // running the network model. - if (how_many_new_slices == 0) { - continue; - } - - // Run the model on the spectrogram input and make sure it succeeds. - TfLiteStatus invoke_status = interpreter.Invoke(); - if (invoke_status != kTfLiteOk) { - error_reporter->Report("Invoke failed"); - return 1; - } - - // The output from the model is a vector containing the scores for each - // kind of prediction, so figure out what the highest scoring category was. - TfLiteTensor* output = interpreter.output(0); - uint8_t top_category_score = 0; - int top_category_index = 0; - for (int category_index = 0; category_index < kCategoryCount; - ++category_index) { - const uint8_t category_score = output->data.uint8[category_index]; - if (category_score > top_category_score) { - top_category_score = category_score; - top_category_index = category_index; - } - } - - error_reporter->Report("Heard %s", kCategoryLabels[top_category_index]); - } - - return 0; -} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h deleted file mode 100644 index 88369a07ee..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ -#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ - -// Keeping these as constant expressions allow us to allocate fixed-sized arrays -// on the stack for our working memory. - -// The size of the input time series data we pass to the FFT to produce the -// frequency information. This has to be a power of two, and since we're dealing -// with 30ms of 16KHz inputs, which means 480 samples, this is the next value. -constexpr int kMaxAudioSampleSize = 512; - -// All of these values are derived from the values used during model training, -// if you change your model you'll need to update these constants. -constexpr int kAverageWindowSize = 6; -constexpr int kFeatureSliceSize = - ((kMaxAudioSampleSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; -constexpr int kFeatureSliceCount = 49; -constexpr int kFeatureElementCount = (kFeatureSliceSize * kFeatureSliceCount); -constexpr int kFeatureSliceStrideMs = 20; -constexpr int kFeatureSliceDurationMs = 30; - -constexpr int kCategoryCount = 4; -constexpr int kSilenceIndex = 0; -constexpr int kUnknownIndex = 1; -constexpr char* kCategoryLabels[kCategoryCount] = { - "silence", - "unknown", - "yes", - "no", -}; - -#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc index f4a7f801cc..12f9e22038 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc @@ -28,10 +28,15 @@ limitations under the License. #include -#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" - namespace { +// These constants allow us to allocate fixed-sized arrays on the stack for our +// working memory. +constexpr int kInputSize = 512; +constexpr int kAverageWindowSize = 6; +constexpr int kOutputSize = + ((kInputSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; + // Performs a discrete Fourier transform on the real inputs. This corresponds to // rdft() in the FFT package at http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html, // and to kiss_fftr() in KISSFFT at https://github.com/mborgerding/kissfft. @@ -73,27 +78,27 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output) { // Ensure our input and output data arrays are valid. - if (input_size > kMaxAudioSampleSize) { + if (input_size > kInputSize) { error_reporter->Report("Input size %d larger than %d", input_size, - kMaxAudioSampleSize); + kInputSize); return kTfLiteError; } - if (output_size != kFeatureSliceSize) { + if (output_size != kOutputSize) { error_reporter->Report("Requested output size %d doesn't match %d", - output_size, kFeatureSliceSize); + output_size, kOutputSize); return kTfLiteError; } // Pre-calculate the window function we'll be applying to the input data. // In a real application, we'd calculate this table once in an initialization // function and store it for repeated reuse. - float window_function[kMaxAudioSampleSize]; + float window_function[kInputSize]; CalculatePeriodicHann(input_size, window_function); // Apply the window function to our time series input, and pad it with zeroes // to the next power of two. - float float_input[kMaxAudioSampleSize]; - for (int i = 0; i < kMaxAudioSampleSize; ++i) { + float float_input[kInputSize]; + for (int i = 0; i < kInputSize; ++i) { if (i < input_size) { float_input[i] = (input[i] * window_function[i]) / static_cast(1 << 15); @@ -103,15 +108,14 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, } // Pull the frequency data from the time series sample. - float fourier_values[kMaxAudioSampleSize]; - CalculateDiscreteFourierTransform(float_input, kMaxAudioSampleSize, - fourier_values); + float fourier_values[kInputSize]; + CalculateDiscreteFourierTransform(float_input, kInputSize, fourier_values); // We have the complex numbers giving us information about each frequency // band, but all we want to know is how strong each frequency is, so calculate // the squared magnitude by adding together the squares of each component. - float power_spectrum[kMaxAudioSampleSize / 2]; - for (int i = 0; i < (kMaxAudioSampleSize / 2); ++i) { + float power_spectrum[kInputSize / 2]; + for (int i = 0; i < (kInputSize / 2); ++i) { const float real = fourier_values[(i * 2) + 0]; const float imaginary = fourier_values[(i * 2) + 1]; power_spectrum[i] = (real * real) + (imaginary * imaginary); @@ -119,11 +123,11 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // Finally, reduce the size of the output by averaging together six adjacent // frequencies into each slot, producing an array of 43 values. - for (int i = 0; i < kFeatureSliceSize; ++i) { + for (int i = 0; i < kOutputSize; ++i) { float total = 0.0f; for (int j = 0; j < kAverageWindowSize; ++j) { const int index = (i * kAverageWindowSize) + j; - if (index < (kMaxAudioSampleSize / 2)) { + if (index < (kInputSize / 2)) { total += power_spectrum[index]; } } diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h index adff790d6c..dede2a8642 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h @@ -19,11 +19,6 @@ limitations under the License. #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/experimental/micro/micro_error_reporter.h" -// Converts audio sample data into a more compact form that's appropriate for -// feeding into a neural network. There are reference implementations that use -// both floating point and fixed point available, but because the calculations -// involved can be time-consuming, it's recommended that you use or write -// specialized versions for your platform. TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output); diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc deleted file mode 100644 index 6c96a61ab5..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" - -int32_t TimeInMilliseconds() { - static int current_time = 0; - current_time += 100; - return current_time; -} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h deleted file mode 100644 index 162952844a..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ -#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ - -#include - -// Returns the time in milliseconds. There's no contract about what time zero -// represents, the accuracy, or the granularity of the result. Subsequent calls -// will generally not return a lower value, but even that's not guaranteed if -// there's an overflow wraparound. -// The reference implementation of this function just returns a constantly -// incrementing value for each call, since it would need a non-portable platform -// call to access time information. For real applications, you'll need to write -// your own platform-specific implementation. -int32_t TimeInMilliseconds(); - -#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc deleted file mode 100644 index 83a2dfcc65..0000000000 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright 2018 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" - -#include - -#include "tensorflow/lite/c/c_api_internal.h" -#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" -#include "tensorflow/lite/experimental/micro/testing/micro_test.h" - -TF_LITE_MICRO_TESTS_BEGIN - -TF_LITE_MICRO_TEST(TestTimer) { - // Make sure that the technically-undefined overflow behavior we rely on below - // works on this platform. It's still not guaranteed, but at least this is a - // sanity check. - int32_t overflow_value = std::numeric_limits::max(); - overflow_value += 1; - TF_LITE_MICRO_EXPECT_EQ(std::numeric_limits::min(), overflow_value); - - const int32_t first_time = TimeInMilliseconds(); - const int32_t second_time = TimeInMilliseconds(); - - // It's possible that the timer may have wrapped around from +BIG_NUM to - // -BIG_NUM between the first and second calls, since we're storing - // milliseconds in a 32-bit integer. It's not reasonable that the call itself - // would have taken more than 2^31 milliseconds though, so look at the - // difference and rely on integer overflow to ensure it's accurate. - const int32_t time_delta = (second_time - first_time); - TF_LITE_MICRO_EXPECT_LE(0, time_delta); -} - -TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/testing/micro_test.h b/tensorflow/lite/experimental/micro/testing/micro_test.h index 2f20dd5ac7..10bab05fae 100644 --- a/tensorflow/lite/experimental/micro/testing/micro_test.h +++ b/tensorflow/lite/experimental/micro/testing/micro_test.h @@ -153,22 +153,4 @@ extern tflite::ErrorReporter* reporter; } \ } while (false) -#define TF_LITE_MICRO_EXPECT_GE(x, y) \ - do { \ - if ((x) < (y)) { \ - micro_test::reporter->Report(#x " >= " #y " failed at %s:%d", __FILE__, \ - __LINE__); \ - micro_test::did_test_fail = true; \ - } \ - } while (false) - -#define TF_LITE_MICRO_EXPECT_LE(x, y) \ - do { \ - if ((x) > (y)) { \ - micro_test::reporter->Report(#x " <= " #y " failed at %s:%d", __FILE__, \ - __LINE__); \ - micro_test::did_test_fail = true; \ - } \ - } while (false) - #endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_TESTING_MICRO_TEST_H_ -- GitLab From b8ac6cb24927e2688a514dcbd5ca3aeed97f7dfb Mon Sep 17 00:00:00 2001 From: Priya Gupta Date: Sun, 25 Nov 2018 16:39:24 -0800 Subject: [PATCH 285/672] Fix name of upgrade script in example. PiperOrigin-RevId: 222758170 --- tensorflow/tools/compatibility/tf_upgrade_v2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 9b14c11614..33e4f0f442 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -585,8 +585,8 @@ if __name__ == "__main__": description="""Convert a TensorFlow Python file to 2.0 Simple usage: - tf_convert_v2.py --infile foo.py --outfile bar.py - tf_convert_v2.py --intree ~/code/old --outtree ~/code/new + tf_upgrade_v2.py --infile foo.py --outfile bar.py + tf_upgrade_v2.py --intree ~/code/old --outtree ~/code/new """) parser.add_argument( "--infile", -- GitLab From e14e62133cc72bafb2fd3251dc4e6b7116b2f4ad Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sun, 25 Nov 2018 18:01:45 -0800 Subject: [PATCH 286/672] Move distribute.py, distribution_strategy_context.py, and device_util.py from training/ to distribute/. PiperOrigin-RevId: 222761376 --- tensorflow/contrib/distribute/python/BUILD | 12 +- .../python/collective_all_reduce_strategy.py | 2 +- .../contrib/distribute/python/combinations.py | 2 +- .../python/cross_device_ops_test.py | 2 +- .../python/cross_device_utils_test.py | 2 +- .../python/keras_optimizer_v2_test.py | 2 +- .../distribute/python/mirrored_strategy.py | 2 +- .../python/mirrored_strategy_multigpu_test.py | 4 +- .../distribute/python/one_device_strategy.py | 2 +- .../python/parameter_server_strategy.py | 4 +- .../python/parameter_server_strategy_test.py | 4 +- .../distribute/python/strategy_test_lib.py | 2 +- .../contrib/distribute/python/tpu_strategy.py | 4 +- .../contrib/distribute/python/values_test.py | 4 +- tensorflow/python/BUILD | 35 +- tensorflow/python/distribute/BUILD | 74 +- .../python/distribute/cross_device_ops.py | 2 +- tensorflow/python/distribute/device_util.py | 97 + .../device_util_test.py | 2 +- .../python/distribute/distribute_lib.py | 1665 +++++++++++++++++ .../distribute_lib_test.py} | 4 +- .../distribution_strategy_context.py | 236 +++ .../python/distribute/mirrored_strategy.py | 4 +- tensorflow/python/distribute/values.py | 6 +- .../python/tools/api/generator/doc_srcs.py | 2 +- tensorflow/python/training/device_util.py | 81 +- tensorflow/python/training/distribute.py | 1649 +--------------- .../training/distribution_strategy_context.py | 220 +-- ...tensorflow.distribute.-input-context.pbtxt | 2 +- ...nsorflow.distribute.-replica-context.pbtxt | 2 +- ...orflow.distribute.-strategy-extended.pbtxt | 2 +- .../v1/tensorflow.distribute.-strategy.pbtxt | 2 +- ...tensorflow.distribute.-input-context.pbtxt | 2 +- ...nsorflow.distribute.-replica-context.pbtxt | 2 +- ...orflow.distribute.-strategy-extended.pbtxt | 2 +- .../v2/tensorflow.distribute.-strategy.pbtxt | 2 +- 36 files changed, 2118 insertions(+), 2023 deletions(-) create mode 100644 tensorflow/python/distribute/device_util.py rename tensorflow/python/{training => distribute}/device_util_test.py (98%) create mode 100644 tensorflow/python/distribute/distribute_lib.py rename tensorflow/python/{training/distribute_test.py => distribute/distribute_lib_test.py} (98%) create mode 100644 tensorflow/python/distribute/distribution_strategy_context.py diff --git a/tensorflow/contrib/distribute/python/BUILD b/tensorflow/contrib/distribute/python/BUILD index 91282a8c1d..b068ef029f 100644 --- a/tensorflow/contrib/distribute/python/BUILD +++ b/tensorflow/contrib/distribute/python/BUILD @@ -27,13 +27,13 @@ cuda_py_test( "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:constant_op", - "//tensorflow/python:device_util", "//tensorflow/python:errors", "//tensorflow/python:framework_ops", "//tensorflow/python:framework_test_lib", "//tensorflow/python:training", "//tensorflow/python:variable_scope", "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/distribute:device_util", "//tensorflow/python/distribute:values", "//tensorflow/python/eager:context", "//tensorflow/python/eager:test", @@ -49,7 +49,7 @@ py_library( srcs = ["mirrored_strategy.py"], visibility = ["//tensorflow:internal"], deps = [ - "//tensorflow/python:distribute", + "//tensorflow/python/distribute:distribute_lib", "//tensorflow/python/distribute:mirrored_strategy", "//tensorflow/python/distribute:values", ], @@ -114,10 +114,10 @@ py_library( visibility = ["//tensorflow:internal"], deps = [ "//tensorflow/python:array_ops", - "//tensorflow/python:distribute", "//tensorflow/python:dtypes", "//tensorflow/python:framework_ops", "//tensorflow/python:math_ops", + "//tensorflow/python/distribute:distribute_lib", "//tensorflow/python/distribute:reduce_util", "//tensorflow/python/distribute:values", "//tensorflow/python/eager:context", @@ -156,11 +156,11 @@ py_library( "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:constant_op", - "//tensorflow/python:distribute", "//tensorflow/python:framework_ops", "//tensorflow/python:layers", "//tensorflow/python:training", "//tensorflow/python:variables", + "//tensorflow/python/distribute:distribute_lib", "//tensorflow/python/eager:backprop", "//tensorflow/python/eager:context", "//tensorflow/python/eager:test", @@ -181,10 +181,10 @@ py_library( ":tpu_strategy", "//tensorflow/contrib/cluster_resolver:cluster_resolver_pip", "//tensorflow/contrib/optimizer_v2:training", - "//tensorflow/python:distribute", "//tensorflow/python:framework_ops", "//tensorflow/python:training", "//tensorflow/python:util", + "//tensorflow/python/distribute:distribute_lib", "//tensorflow/python/eager:context", "@absl_py//absl/testing:parameterized", ], @@ -229,11 +229,11 @@ cuda_py_test( "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:constant_op", - "//tensorflow/python:distribute", "//tensorflow/python:framework_test_lib", "//tensorflow/python:layers", "//tensorflow/python:state_ops", "//tensorflow/python:variable_scope", + "//tensorflow/python/distribute:distribute_lib", "//tensorflow/python/distribute:values", "//tensorflow/python/eager:context", "//tensorflow/python/eager:test", diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py index 17323e2741..74a0550e81 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py @@ -24,6 +24,7 @@ from tensorflow.contrib.distribute.python import mirrored_strategy from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib from tensorflow.python.distribute import cross_device_utils +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import multi_worker_util from tensorflow.python.distribute import values from tensorflow.python.eager import context @@ -31,7 +32,6 @@ from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import collective_ops from tensorflow.python.platform import tf_logging as logging -from tensorflow.python.training import distribute as distribute_lib # TODO(yuefengz): support in-graph replication. diff --git a/tensorflow/contrib/distribute/python/combinations.py b/tensorflow/contrib/distribute/python/combinations.py index f3ce547f4d..c5ce29a436 100644 --- a/tensorflow/contrib/distribute/python/combinations.py +++ b/tensorflow/contrib/distribute/python/combinations.py @@ -53,11 +53,11 @@ from tensorflow.contrib.distribute.python import tpu_strategy as tpu_lib from tensorflow.contrib.optimizer_v2 import adagrad as adagrad_v2 from tensorflow.contrib.optimizer_v2 import adam as adam_v2 from tensorflow.contrib.optimizer_v2 import gradient_descent as gradient_descent_v2 +from tensorflow.python.distribute import distribution_strategy_context from tensorflow.python.eager import context from tensorflow.python.framework import ops from tensorflow.python.training import adagrad from tensorflow.python.training import adam -from tensorflow.python.training import distribution_strategy_context from tensorflow.python.training import gradient_descent from tensorflow.python.training import rmsprop from tensorflow.python.util import tf_inspect diff --git a/tensorflow/contrib/distribute/python/cross_device_ops_test.py b/tensorflow/contrib/distribute/python/cross_device_ops_test.py index 40410b90be..5d8690beb5 100644 --- a/tensorflow/contrib/distribute/python/cross_device_ops_test.py +++ b/tensorflow/contrib/distribute/python/cross_device_ops_test.py @@ -29,6 +29,7 @@ from tensorflow.contrib.distribute.python import multi_worker_test_base from tensorflow.core.protobuf import config_pb2 from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib from tensorflow.python.distribute import cross_device_utils +from tensorflow.python.distribute import device_util from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values as value_lib from tensorflow.python.eager import context @@ -37,7 +38,6 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops -from tensorflow.python.training import device_util def _make_per_replica(values, devices, regroup=False): diff --git a/tensorflow/contrib/distribute/python/cross_device_utils_test.py b/tensorflow/contrib/distribute/python/cross_device_utils_test.py index 6086eba098..2303a31677 100644 --- a/tensorflow/contrib/distribute/python/cross_device_utils_test.py +++ b/tensorflow/contrib/distribute/python/cross_device_utils_test.py @@ -22,13 +22,13 @@ from absl.testing import parameterized from tensorflow.contrib.distribute.python import combinations from tensorflow.python.distribute import cross_device_utils +from tensorflow.python.distribute import device_util from tensorflow.python.distribute import values as value_lib from tensorflow.python.eager import test from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.ops import math_ops -from tensorflow.python.training import device_util class IndexedSlicesUtilsTest(test.TestCase, parameterized.TestCase): diff --git a/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py b/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py index fba06283ce..6dfd85bcc4 100644 --- a/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py +++ b/tensorflow/contrib/distribute/python/keras_optimizer_v2_test.py @@ -28,6 +28,7 @@ from tensorflow.contrib.distribute.python import combinations from tensorflow.core.protobuf import config_pb2 from tensorflow.python import keras from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.distribute import distribution_strategy_context as ds_context from tensorflow.python.estimator import run_config from tensorflow.python.estimator import training from tensorflow.python.estimator.canned import dnn_linear_combined @@ -46,7 +47,6 @@ from tensorflow.python.ops import variables from tensorflow.python.platform import gfile from tensorflow.python.platform import test from tensorflow.python.summary.writer import writer_cache -from tensorflow.python.training import distribution_strategy_context as ds_context class KerasOptimizerV2IntegrationTest(test.TestCase, parameterized.TestCase): diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy.py b/tensorflow/contrib/distribute/python/mirrored_strategy.py index a3bcc8db88..7719715875 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy.py @@ -20,9 +20,9 @@ from __future__ import print_function import functools +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import mirrored_strategy from tensorflow.python.distribute import values -from tensorflow.python.training import distribute as distribute_lib # pylint: disable=protected-access,invalid-name diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py index cf6c7f6879..b304f63501 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py @@ -29,6 +29,8 @@ from tensorflow.contrib.distribute.python import multi_worker_test_base from tensorflow.contrib.distribute.python import strategy_test_lib from tensorflow.core.protobuf import config_pb2 from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribution_strategy_context as ds_context from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values from tensorflow.python.eager import backprop @@ -48,8 +50,6 @@ from tensorflow.python.ops import rnn_cell_impl from tensorflow.python.ops import state_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables -from tensorflow.python.training import device_util -from tensorflow.python.training import distribution_strategy_context as ds_context from tensorflow.python.training import gradient_descent from tensorflow.python.training import optimizer as optimizer_lib from tensorflow.python.training import server_lib diff --git a/tensorflow/contrib/distribute/python/one_device_strategy.py b/tensorflow/contrib/distribute/python/one_device_strategy.py index 421507232a..7a2e225ca0 100644 --- a/tensorflow/contrib/distribute/python/one_device_strategy.py +++ b/tensorflow/contrib/distribute/python/one_device_strategy.py @@ -20,13 +20,13 @@ from __future__ import print_function import six +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import values from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.util import nest diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy.py b/tensorflow/contrib/distribute/python/parameter_server_strategy.py index d127868525..5615abb751 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy.py @@ -22,6 +22,8 @@ import copy from tensorflow.contrib.distribute.python import mirrored_strategy from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import multi_worker_util from tensorflow.python.distribute import values from tensorflow.python.eager import context @@ -32,8 +34,6 @@ from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import variable_scope as vs from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import device_setter -from tensorflow.python.training import device_util -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.util import nest _LOCAL_CPU = "/device:CPU:0" diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py index 3ea9b90f6f..4debe72ca6 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py @@ -28,6 +28,8 @@ from tensorflow.contrib.distribute.python import parameter_server_strategy from tensorflow.contrib.distribute.python import strategy_test_lib from tensorflow.core.protobuf import config_pb2 from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribution_strategy_context as ds_context from tensorflow.python.distribute import multi_worker_util from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values @@ -46,8 +48,6 @@ from tensorflow.python.ops import partitioned_variables from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables from tensorflow.python.platform import test -from tensorflow.python.training import device_util -from tensorflow.python.training import distribution_strategy_context as ds_context from tensorflow.python.training import training_util CHIEF = run_config.TaskType.CHIEF diff --git a/tensorflow/contrib/distribute/python/strategy_test_lib.py b/tensorflow/contrib/distribute/python/strategy_test_lib.py index 5a8e8ed0dd..756e5bdc1e 100644 --- a/tensorflow/contrib/distribute/python/strategy_test_lib.py +++ b/tensorflow/contrib/distribute/python/strategy_test_lib.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from tensorflow.core.protobuf import config_pb2 +from tensorflow.python.distribute import distribution_strategy_context as ds_context from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values from tensorflow.python.eager import backprop @@ -33,7 +34,6 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables -from tensorflow.python.training import distribution_strategy_context as ds_context from tensorflow.python.training import optimizer diff --git a/tensorflow/contrib/distribute/python/tpu_strategy.py b/tensorflow/contrib/distribute/python/tpu_strategy.py index 3e755242f7..1f302fdde8 100644 --- a/tensorflow/contrib/distribute/python/tpu_strategy.py +++ b/tensorflow/contrib/distribute/python/tpu_strategy.py @@ -29,6 +29,8 @@ from tensorflow.contrib.tpu.python.tpu import tpu from tensorflow.contrib.tpu.python.tpu import tpu_system_metadata as tpu_system_metadata_lib from tensorflow.contrib.tpu.python.tpu import training_loop from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values from tensorflow.python.eager import context @@ -41,8 +43,6 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import variable_scope as vs -from tensorflow.python.training import device_util -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.util import nest diff --git a/tensorflow/contrib/distribute/python/values_test.py b/tensorflow/contrib/distribute/python/values_test.py index 855b9c29ae..538b859f3d 100644 --- a/tensorflow/contrib/distribute/python/values_test.py +++ b/tensorflow/contrib/distribute/python/values_test.py @@ -25,6 +25,8 @@ from tensorflow.contrib.distribute.python import combinations from tensorflow.contrib.distribute.python import multi_worker_test_base from tensorflow.core.protobuf import config_pb2 from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import values from tensorflow.python.eager import context from tensorflow.python.eager import test @@ -39,8 +41,6 @@ from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables as variables_lib -from tensorflow.python.training import device_util -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.training import saver as saver_lib from tensorflow.python.util import nest diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 3def23bc44..5c9e7f5e89 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -3596,9 +3596,7 @@ py_library( srcs = ["training/device_util.py"], srcs_version = "PY2AND3", deps = [ - ":device", - ":framework_ops", - "//tensorflow/python/eager:context", + "//tensorflow/python/distribute:device_util", ], ) @@ -3610,35 +3608,7 @@ py_library( ], srcs_version = "PY2AND3", deps = [ - ":array_ops", - ":constant_op", - ":control_flow_ops", - ":device_util", - ":dtypes", - ":framework_ops", - ":platform", - ":resource_variable_ops", - ":state_ops", - ":util", - ":variable_scope", - "//tensorflow/python/data", - "//tensorflow/python/distribute:reduce_util", - "//tensorflow/python/ops/losses", - "//tensorflow/tools/docs:doc_controls", - ], -) - -py_test( - name = "distribute_test", - size = "small", - srcs = ["training/distribute_test.py"], - srcs_version = "PY2AND3", - deps = [ - ":client_testlib", - ":constant_op", - ":distribute", - ":dtypes", - ":variable_scope", + "//tensorflow/python/distribute:distribute_lib", ], ) @@ -4627,7 +4597,6 @@ cuda_py_tests( "training/basic_loops_test.py", "training/coordinator_test.py", "training/device_setter_test.py", - "training/device_util_test.py", "training/ftrl_test.py", "training/gradient_descent_test.py", "training/learning_rate_decay_test.py", diff --git a/tensorflow/python/distribute/BUILD b/tensorflow/python/distribute/BUILD index 999543d71f..5afbcec3a9 100644 --- a/tensorflow/python/distribute/BUILD +++ b/tensorflow/python/distribute/BUILD @@ -50,6 +50,7 @@ py_library( srcs_version = "PY2AND3", deps = [ ":cross_device_utils", + ":device_util", ":reduce_util", ":values", "//tensorflow/python:array_ops", @@ -58,8 +59,6 @@ py_library( "//tensorflow/python:math_ops", "//tensorflow/python:platform", "//tensorflow/python:resource_variable_ops", - "//tensorflow/python:training", - "//tensorflow/python:variable_scope", "//tensorflow/python/eager:context", "@six_archive//:six", ], @@ -83,6 +82,67 @@ py_library( ], ) +py_library( + name = "device_util", + srcs = ["device_util.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:device", + "//tensorflow/python:framework_ops", + "//tensorflow/python/eager:context", + ], +) + +cuda_py_test( + name = "device_util_test", + srcs = ["device_util_test.py"], + additional_deps = [ + ":device_util", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_ops", + ], +) + +py_library( + name = "distribute_lib", + srcs = [ + "distribute_lib.py", + "distribution_strategy_context.py", + ], + srcs_version = "PY2AND3", + deps = [ + ":device_util", + ":reduce_util", + "//tensorflow/python:array_ops", + "//tensorflow/python:constant_op", + "//tensorflow/python:control_flow_ops", + "//tensorflow/python:dtypes", + "//tensorflow/python:framework_ops", + "//tensorflow/python:platform", + "//tensorflow/python:resource_variable_ops", + "//tensorflow/python:state_ops", + "//tensorflow/python:util", + "//tensorflow/python:variable_scope", + "//tensorflow/python/data", + "//tensorflow/python/ops/losses", + "//tensorflow/tools/docs:doc_controls", + ], +) + +py_test( + name = "distribute_lib_test", + size = "small", + srcs = ["distribute_lib_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":distribute_lib", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:variable_scope", + ], +) + py_library( name = "distribute_config", srcs = [ @@ -144,6 +204,8 @@ py_library( srcs = ["mirrored_strategy.py"], deps = [ ":cross_device_ops", + ":device_util", + ":distribute_lib", ":multi_worker_util", ":reduce_util", ":shared_variable_creator", @@ -153,8 +215,6 @@ py_library( "//tensorflow/python:constant_op", "//tensorflow/python:control_flow_ops", "//tensorflow/python:device", - "//tensorflow/python:device_util", - "//tensorflow/python:distribute", "//tensorflow/python:dtypes", "//tensorflow/python:framework_ops", "//tensorflow/python:pywrap_tensorflow", @@ -195,12 +255,12 @@ cuda_py_test( additional_deps = [ ":input_ops", "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:readers", "//tensorflow/python:errors", "//tensorflow/python:client_testlib", "//tensorflow/python:framework_ops", "//tensorflow/python:framework_test_lib", "//tensorflow/python:io_ops", - "//tensorflow/python/data/ops:readers", "//tensorflow/python:util", ], tags = [ @@ -271,11 +331,11 @@ py_library( name = "values", srcs = ["values.py"], deps = [ + ":device_util", + ":distribute_lib", ":input_ops", "//tensorflow/python:array_ops", "//tensorflow/python:control_flow_ops", - "//tensorflow/python:device_util", - "//tensorflow/python:distribute", "//tensorflow/python:framework_ops", "//tensorflow/python:resource_variable_ops", "//tensorflow/python:training", diff --git a/tensorflow/python/distribute/cross_device_ops.py b/tensorflow/python/distribute/cross_device_ops.py index 87b6f41eba..a88ed62533 100644 --- a/tensorflow/python/distribute/cross_device_ops.py +++ b/tensorflow/python/distribute/cross_device_ops.py @@ -23,6 +23,7 @@ import six from tensorflow.python.client import device_lib from tensorflow.python.distribute import cross_device_utils +from tensorflow.python.distribute import device_util from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import values as value_lib from tensorflow.python.eager import context @@ -31,7 +32,6 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.platform import tf_logging as logging -from tensorflow.python.training import device_util def check_destinations(destinations): diff --git a/tensorflow/python/distribute/device_util.py b/tensorflow/python/distribute/device_util.py new file mode 100644 index 0000000000..70e1ca4b5d --- /dev/null +++ b/tensorflow/python/distribute/device_util.py @@ -0,0 +1,97 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Device-related support functions.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.eager import context +from tensorflow.python.framework import device as tf_device +from tensorflow.python.framework import ops + + +def canonicalize(d, default=None): + """Canonicalize device string. + + If d has missing components, the rest would be deduced from the `default` + argument or from '/replica:0/task:0/device:CPU:0'. For example: + If d = '/cpu:0', default='/job:worker/task:1', it returns + '/job:worker/replica:0/task:1/device:CPU:0'. + If d = '/cpu:0', default='/job:worker', it returns + '/job:worker/replica:0/task:0/device:CPU:0'. + If d = '/gpu:0', default=None, it returns + '/replica:0/task:0/device:GPU:0'. + + Note: This uses "job:localhost" as the default if executing eagerly. + + Args: + d: a device string. + default: a string for default device if d doesn't have all components. + + Returns: + a canonicalized device string. + """ + d = tf_device.DeviceSpec.from_string(d) + assert d.device_type is None or d.device_type == d.device_type.upper(), ( + "Device type '%s' must be all-caps." % (d.device_type,)) + # Fill in missing device fields using defaults. + result = tf_device.DeviceSpec( + replica=0, task=0, device_type="CPU", device_index=0) + if context.executing_eagerly(): + result.job = "localhost" + if default: + result.merge_from(tf_device.DeviceSpec.from_string(default)) + result.merge_from(d) + return result.to_string() + + +def resolve(d): + """Canonicalize `d` with current device as default.""" + return canonicalize(d, default=current()) + + +class _FakeNodeDef(object): + """A fake NodeDef for _FakeOperation.""" + + def __init__(self): + self.op = "" + self.name = "" + + +class _FakeOperation(object): + """A fake Operation object to pass to device functions.""" + + def __init__(self): + self.device = "" + self.type = "" + self.name = "" + self.node_def = _FakeNodeDef() + + def _set_device(self, device): + self.device = ops._device_string(device) # pylint: disable=protected-access + + +def current(): + """Return a string (not canonicalized) for the current device.""" + # TODO(josh11b): Work out how this function interacts with ops.colocate_with. + ctx = context.context() + if ctx.executing_eagerly(): + d = ctx.device_name + else: + op = _FakeOperation() + ops.get_default_graph()._apply_device_functions(op) # pylint: disable=protected-access + d = op.device + return d diff --git a/tensorflow/python/training/device_util_test.py b/tensorflow/python/distribute/device_util_test.py similarity index 98% rename from tensorflow/python/training/device_util_test.py rename to tensorflow/python/distribute/device_util_test.py index cdbb08229d..baecd43c8e 100644 --- a/tensorflow/python/training/device_util_test.py +++ b/tensorflow/python/distribute/device_util_test.py @@ -18,10 +18,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.distribute import device_util from tensorflow.python.eager import context from tensorflow.python.framework import ops from tensorflow.python.platform import test -from tensorflow.python.training import device_util class DeviceUtilTest(test.TestCase): diff --git a/tensorflow/python/distribute/distribute_lib.py b/tensorflow/python/distribute/distribute_lib.py new file mode 100644 index 0000000000..a1f03eab61 --- /dev/null +++ b/tensorflow/python/distribute/distribute_lib.py @@ -0,0 +1,1665 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Library for running a computation across multiple devices.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import copy +import threading +import weakref +import enum + +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribution_strategy_context +from tensorflow.python.distribute import reduce_util +from tensorflow.python.eager import context as eager_context +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import resource_variable_ops +from tensorflow.python.ops import variable_scope +from tensorflow.python.ops.losses import losses_impl +from tensorflow.python.platform import tf_logging +from tensorflow.python.util import nest +from tensorflow.python.util.tf_export import tf_export +from tensorflow.tools.docs import doc_controls + + +# ------------------------------------------------------------------------------ +# Context tracking whether in a strategy.update() or .update_non_slot() call. + + +_update_device = threading.local() + + +def get_update_device(): + """Get the current device if in a `tf.distribute.Strategy.update()` call.""" + try: + return _update_device.current + except AttributeError: + return None + + +class UpdateContext(object): + """Context manager when you are in `update()` or `update_non_slot()`.""" + + def __init__(self, device): + self._device = device + self._old_device = None + + def __enter__(self): + self._old_device = get_update_device() + _update_device.current = self._device + + def __exit__(self, exception_type, exception_value, traceback): + del exception_type, exception_value, traceback + _update_device.current = self._old_device + + +# ------------------------------------------------------------------------------ +# Public utility functions. + + +@tf_export("distribute.get_loss_reduction") +def get_loss_reduction(): + """`tf.distribute.ReduceOp` corresponding to the last loss reduction.""" + loss_reduction = ops.get_default_graph()._last_loss_reduction # pylint: disable=protected-access + if loss_reduction == losses_impl.Reduction.SUM: + return reduce_util.ReduceOp.SUM + return reduce_util.ReduceOp.MEAN + + +# ------------------------------------------------------------------------------ +# Internal API for validating the current thread mode + + +def _require_cross_replica_context_extended(extended): + """Verify in cross-replica context.""" + context = _get_per_thread_mode() + cross_replica = context.cross_replica_context + if cross_replica is not None and cross_replica.extended is extended: + return + strategy = extended._container_strategy() # pylint: disable=protected-access + # We have an error to report, figure out the right message. + if context.distribution_strategy is not strategy: + _wrong_strategy_scope(strategy, context) + assert cross_replica is None + raise RuntimeError("Method requires being in cross-replica context, use " + "get_replica_context().merge_call()") + + +def _wrong_strategy_scope(strategy, context): + # Figure out the right error message. + if not distribution_strategy_context.has_distribution_strategy(): + raise RuntimeError( + 'Need to be inside "with strategy.scope()" for %s' % + (strategy,)) + else: + raise RuntimeError( + "Mixing different tf.distribute.Strategy objects: %s is not %s" % + (context.distribution_strategy, strategy)) + + +def require_replica_context(replica_ctx): + """Verify in `replica_ctx` replica context.""" + context = _get_per_thread_mode() + if context.replica_context is replica_ctx: return + # We have an error to report, figure out the right message. + if context.replica_context is None: + raise RuntimeError("Need to be inside `call_for_each_replica()`") + if context.distribution_strategy is replica_ctx.distribution_strategy: + # Two different ReplicaContexts with the same tf.distribute.Strategy. + raise RuntimeError("Mismatching ReplicaContext.") + raise RuntimeError( + "Mismatching tf.distribute.Strategy objects: %s is not %s." % + (context.distribution_strategy, replica_ctx.distribution_strategy)) + + +def _require_distribution_strategy_scope_strategy(strategy): + """Verify in a `strategy.scope()` in this thread.""" + context = _get_per_thread_mode() + if context.distribution_strategy is strategy: return + _wrong_strategy_scope(strategy, context) + + +def _require_distribution_strategy_scope_extended(extended): + """Verify in a `distribution_strategy.scope()` in this thread.""" + context = _get_per_thread_mode() + if context.distribution_strategy.extended is extended: return + # Report error. + strategy = extended._container_strategy() # pylint: disable=protected-access + _wrong_strategy_scope(strategy, context) + + +# ------------------------------------------------------------------------------ +# Internal context managers used to implement the DistributionStrategy +# base class + + +class _CurrentDistributionContext(object): + """Context manager setting the current `tf.distribute.Strategy`. + + Also: overrides the variable creator and optionally the current device. + """ + + def __init__(self, + strategy, + var_creator_scope, + var_scope=None, + default_device=None): + self._context = distribution_strategy_context._CrossReplicaThreadMode( # pylint: disable=protected-access + strategy) + self._var_creator_scope = var_creator_scope + self._var_scope = var_scope + if default_device: + self._device_scope = ops.device(default_device) + else: + self._device_scope = None + + def __enter__(self): + _push_per_thread_mode(self._context) + if self._var_scope: + self._var_scope.__enter__() + self._var_creator_scope.__enter__() + if self._device_scope: + self._device_scope.__enter__() + return self._context.distribution_strategy + + def __exit__(self, exception_type, exception_value, traceback): + if self._device_scope: + self._device_scope.__exit__(exception_type, exception_value, traceback) + self._var_creator_scope.__exit__(exception_type, exception_value, traceback) + if self._var_scope: + self._var_scope.__exit__(exception_type, exception_value, traceback) + _pop_per_thread_mode() + + +class _SameScopeAgainContext(object): + """Trivial context manager when you are already in `scope()`.""" + + def __init__(self, strategy): + self._distribution_strategy = strategy + + def __enter__(self): + return self._distribution_strategy + + def __exit__(self, exception_type, exception_value, traceback): + del exception_type, exception_value, traceback + + +# TODO(yuefengz): add more replication modes. +@tf_export("distribute.InputReplicationMode") +class InputReplicationMode(enum.Enum): + """Replication mode for input function.""" + + # The input function will be called on each worker independently, creating as + # many input pipelines as number of workers. Replicas will dequeue from the + # local Dataset on their worker. Distribution Strategy doesn't manage any + # state sharing between such separate input pipelines. + PER_WORKER = "PER_WORKER" + + +@tf_export("distribute.InputContext") +class InputContext(object): + """A class wrapping information needed by an input function. + + This is a context class that is passed to the user's input fn and contains + information about the compute replicas and input pipelines. The number of + compute replicas (in sync training) helps compute per input pipeline batch + size from the desired global batch size. Input pipeline information can be + used to return a different subset of the input in each input pipeline (for + e.g. shard the input pipeline, use a different input source etc). + """ + + def __init__(self, + num_input_pipelines=1, + input_pipeline_id=0, + num_replicas_in_sync=1): + """Initializes an InputContext object. + + Args: + num_input_pipelines: the number of input pipelines in a cluster. + input_pipeline_id: the current input pipeline id, should be an int in + [0,`num_input_pipelines`). + num_replicas_in_sync: the number of replicas that are in sync. + """ + self._num_input_pipelines = num_input_pipelines + self._input_pipeline_id = input_pipeline_id + self._num_replicas_in_sync = num_replicas_in_sync + + @property + def num_replicas_in_sync(self): + """Returns the number of compute replicas in sync.""" + return self._num_replicas_in_sync + + @property + def input_pipeline_id(self): + """Returns the input pipeline ID.""" + return self._input_pipeline_id + + @property + def num_input_pipelines(self): + """Returns the number of input pipelines.""" + return self._num_input_pipelines + + def get_per_replica_batch_size(self, global_batch_size): + """Returns the per-replica batch size. + + Args: + global_batch_size: the global batch size which should be divisible by + `num_replicas_in_sync`. + + Returns: + the per-replica batch size. + + Raises: + ValueError: if `global_batch_size` not divisible by + `num_replicas_in_sync`. + """ + if global_batch_size % self._num_replicas_in_sync != 0: + raise ValueError("The `global_batch_size` %r is not divisible by " + "`num_replicas_in_sync` %r " % + (global_batch_size, self._num_replicas_in_sync)) + return global_batch_size // self._num_replicas_in_sync + + +# ------------------------------------------------------------------------------ +# Base classes for all distribution strategies. + + +@tf_export("distribute.Strategy") +class DistributionStrategy(object): + """A list of devices with a state & compute distribution policy. + + See [tensorflow/contrib/distribute/README.md]( + https://www.tensorflow.org/code/tensorflow/contrib/distribute/README.md) + for overview and examples. + """ + + # TODO(josh11b): Raise an exception if variable partitioning requested before + # we add support. + # TODO(josh11b): Also `parameter_device_index` property? + # TODO(josh11b): `map()` + # TODO(josh11b): ClusterSpec/ClusterResolver + # TODO(josh11b): Partitioned computations, state; sharding + # TODO(josh11b): Model parallelism: "replicas" with multiple devices; shuffling + # TODO(josh11b): List of replicas with their worker and parameter devices + # (where the parameter devices may overlap in the ps case). + + def __init__(self, extended): + self._extended = extended + + @property + def extended(self): + """`tf.distribute.StrategyExtended` with additional methods.""" + return self._extended + + def scope(self): + """Returns a context manager selecting this Strategy as current. + + Inside a `with strategy.scope():` code block, this thread + will use a variable creator set by `strategy`, and will + enter its "cross-replica context". + + Returns: + A context manager. + """ + return self._extended._scope(self) # pylint: disable=protected-access + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def read_var(self, v): + """DEPRECATED: use extended.read_var() instead.""" + return self._extended.read_var(v) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def colocate_vars_with(self, colocate_with_variable): + """DEPRECATED: use extended.colocate_vars_with() instead.""" + return self._extended.colocate_vars_with(colocate_with_variable) + + @doc_controls.do_not_generate_docs # DEPRECATED + def distribute_dataset(self, dataset_fn): + """Return a `dataset` split across all replicas. DEPRECATED. + + DEPRECATED: Please use `make_dataset_iterator` or + `make_input_fn_iterator` instead. + + Suitable for providing input to `extended.call_for_each_replica()` by + creating an iterator: + + ``` + def dataset_fn(): + return tf.data.Dataset.from_tensors([[1.]]).repeat() + + with strategy.scope(): + distributed_dataset = strategy.distribute_dataset(dataset_fn) + iterator = distributed_dataset.make_initializable_iterator() + replica_results = strategy.extended.call_for_each_replica( + replica_fn, args=(iterator.get_next(),)) + ``` + + Args: + dataset_fn: A function that returns a `tf.data.Dataset`. + + Returns: + A `PerReplicaDataset` that will produce data for each replica. + """ + return self._extended._distribute_dataset(dataset_fn) # pylint: disable=protected-access + + def make_dataset_iterator(self, dataset): + """Makes an iterator for input provided via input_dataset. + + Data from the given dataset will be distributed evenly across all the + compute replicas. We will assume that the input dataset is batched by the + global batch size. With this assumption, we will make a best effort to + divide each batch across all the replicas (one or more workers). + If this effort fails, an error will be thrown, and the user should instead + use `make_input_fn_iterator` which provides more control to the user, and + does not try to divide a batch across replicas. + + The user could also use `make_input_fn_iterator` if they want to + customize which input is fed to which replica/worker etc. + + Args: + dataset: `tf.data.Dataset` that will be distributed evenly across all + replicas. + + Returns: + An `tf.distribute.InputIterator` which returns inputs for each step of the + computation. User should call `initialize` on the returned iterator. + """ + return self._extended._make_dataset_iterator(dataset) # pylint: disable=protected-access + + def make_input_fn_iterator(self, + input_fn, + replication_mode=InputReplicationMode.PER_WORKER): + """Returns an iterator split across replicas created from an input function. + + The `input_fn` should take an `tf.distribute.InputContext` object where + information about input sharding can be accessed: + + ``` + def input_fn(input_context): + d = tf.data.Dataset.from_tensors([[1.]]).repeat() + return d.shard(input_context.num_input_pipelines, + input_context.input_pipeline_id) + with strategy.scope(): + iterator = strategy.make_input_fn_iterator( + input_fn) + replica_results = strategy.extended.call_for_each_replica( + replica_fn, iterator.get_next()) + ``` + + Args: + input_fn: A function that returns a `tf.data.Dataset`. This function is + expected to take an `tf.distribute.InputContext` object. + replication_mode: an enum value of `tf.distribute.InputReplicationMode`. + Only `PER_WORKER` is supported currently. + + Returns: + An iterator object that can be initialized and fetched next element. + """ + if replication_mode != InputReplicationMode.PER_WORKER: + raise ValueError( + "Input replication mode not supported: %r" % replication_mode) + return self.extended._make_input_fn_iterator( # pylint: disable=protected-access + input_fn, replication_mode=replication_mode) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def broadcast(self, tensor, destinations=None): + """DEPRECATED: use extended.broadcast_to() instead.""" + return self._extended.broadcast_to(tensor, destinations) + + @doc_controls.do_not_generate_docs # Use experimental_initialize() instead. + def initialize(self): + """DEPRECATED: Use `experimental_initialize()` instead.""" + return self._extended._initialize() # pylint: disable=protected-access + + def experimental_initialize(self): + """Any initialization to be done before running any computations. + + In eager mode, it executes any initialization as a side effect. + In graph mode, it creates the initialization ops and returns them. + + For example, TPU initialize_system ops. + + Returns: + A list of ops to execute. + """ + return self._extended._initialize() # pylint: disable=protected-access + + @doc_controls.do_not_generate_docs # Use experimental_finalize() instead. + def finalize(self): + """DEPRECATED: Use `experimental_finalize()` instead.""" + return self._extended._finalize() # pylint: disable=protected-access + + def experimental_finalize(self): + """Any final actions to be done at the end of all computations. + + In eager mode, it executes any finalize actions as a side effect. + In graph mode, it creates the finalize ops and returns them. + + For example, TPU shutdown ops. + + Returns: + A list of ops to execute. + """ + return self._extended._finalize() # pylint: disable=protected-access + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def run_steps_on_dataset(self, fn, iterator, iterations=1, + initial_loop_values=None): + """DEPRECATED: use extended.experimental_run_steps_on_iterator() instead.""" + return self._extended.experimental_run_steps_on_iterator( + fn, iterator, iterations, initial_loop_values) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def call_for_each_replica(self, fn, *args, **kwargs): + """DEPRECATED: use extended.call_for_each_replica() instead.""" + # Handle old *args, **kwargs, and new args=(...), kwargs={...}, to + # allow transition. + a = kwargs.pop("args", None) + if a is not None: + if args: + raise ValueError( + "Can't pass *args and args=... to call_for_each_replica") + args = a + k = kwargs.pop("kwargs", None) + if k is not None: + if kwargs: + raise ValueError( + "Can't pass **kwargs and kwargs=... to call_for_each_replica") + kwargs = k + kwargs.pop("run_concurrently", None) # Ignore old option. + return self._extended.call_for_each_replica(fn, args, kwargs) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def reduce(self, aggregation, value, destinations): + """DEPRECATED: use extended.reduce_to() instead.""" + return self._extended.reduce_to(aggregation, value, destinations) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def batch_reduce(self, aggregation, value_destination_pairs): + """DEPRECATED: use extended.batch_reduce_to() instead.""" + return self._extended.batch_reduce_to(aggregation, value_destination_pairs) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def update(self, var, fn, *args, **kwargs): + """DEPRECATED: use extended.update() instead.""" + group = kwargs.pop("group", True) + # We temporarily support "grouped" in addition to "group" for backward- + # compatibility. + group = kwargs.pop("grouped", True) and group + # Handle old *args, **kwargs, and new args=(...), kwargs={...}, to + # allow transition. + a = kwargs.pop("args", None) + if a is not None: + if args: + raise ValueError( + "Can't pass *args and args=... to update") + args = a + k = kwargs.pop("kwargs", None) + if k is not None: + if kwargs: + raise ValueError( + "Can't pass **kwargs and kwargs=... to update") + kwargs = k + return self._extended.update(var, fn, args, kwargs, group) + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def update_non_slot(self, colocate_with, fn, *args, **kwargs): + """DEPRECATED: use extended.update_non_slot() instead.""" + group = kwargs.pop("group", True) + # We temporarily support "grouped" in addition to "group" for backward- + # compatibility. + group = kwargs.pop("grouped", True) and group + # Handle old *args, **kwargs, and new args=(...), kwargs={...}, to + # allow transition. + a = kwargs.pop("args", None) + if a is not None: + if args: + raise ValueError( + "Can't pass *args and args=... to update_non_slot") + args = a + k = kwargs.pop("kwargs", None) + if k is not None: + if kwargs: + raise ValueError( + "Can't pass **kwargs and kwargs=... to update_non_slot") + kwargs = k + return self._extended.update_non_slot( + colocate_with, fn, args, kwargs, group) + + @doc_controls.do_not_generate_docs # DEPRECATED, -> `DistributedValues` + def unwrap(self, value): + """Returns the list of all per-replica values contained in `value`. + + Args: + value: A value returned by `extended.call_for_each_replica()` or a + variable created in `scope`. + + Returns: + A list of values contained in `value`. If `value` represents a single + value, this returns `[value].` + """ + return self._extended._unwrap(value) # pylint: disable=protected-access + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def value_container(self, value): + """DEPRECATED: use extended.value_container() instead.""" + return self._extended.value_container(value) + + @doc_controls.do_not_generate_docs # DEPRECATED, -> `DistributedValues` + def group(self, value, name=None): + """Shortcut for `tf.group(self.unwrap(value))`.""" + return self._extended._group(value, name) # pylint: disable=protected-access + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def require_static_shapes(self): + """DEPRECATED: use extended.require_static_shapes instead.""" + return self._extended.experimental_require_static_shapes + + @property + def num_replicas_in_sync(self): + """Returns number of replicas over which gradients are aggregated.""" + return self._extended._num_replicas_in_sync # pylint: disable=protected-access + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def worker_devices(self): + """DEPRECATED: use extended.worker_devices instead.""" + return self._extended.worker_devices + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def parameter_devices(self): + """DEPRECATED: use extended.parameter_devices instead.""" + return self._extended.parameter_devices + + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def non_slot_devices(self, var_list): + """DEPRECATED: use extended.non_slot_devices instead.""" + return self._extended.non_slot_devices(var_list) + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def between_graph(self): + """DEPRECATED: use extended.experimental_between_graph instead.""" + return self._extended.experimental_between_graph + + @doc_controls.do_not_generate_docs # DEPRECATED, being replaced by a new API. + def configure(self, + session_config=None, + cluster_spec=None, + task_type=None, + task_id=None): + # pylint: disable=g-doc-return-or-yield,g-doc-args + """DEPRECATED: use `update_config_proto` instead. + + Configures the strategy class. + + DEPRECATED: This method's functionality has been split into the strategy + constructor and `update_config_proto`. In the future, we will allow passing + cluster and config_proto to the constructor to configure the strategy. And + `update_config_proto` can be used to update the config_proto based on the + specific strategy. + """ + return self._extended._configure( # pylint: disable=protected-access + session_config, cluster_spec, task_type, task_id) + + def update_config_proto(self, config_proto): + """Returns a copy of `config_proto` modified for use with this strategy. + + The updated config has something needed to run a strategy, e.g. + configuration to run collective ops, or device filters to improve + distributed training performance. + + Args: + config_proto: a `tf.ConfigProto` object. + + Returns: + The updated copy of the `config_proto`. + """ + return self._extended._update_config_proto(config_proto) # pylint: disable=protected-access + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def should_init(self): + """DEPRECATED: use extended.should_init instead.""" + return self._extended.experimental_should_init + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def should_checkpoint(self): + """DEPRECATED: use extended.should_checkpoint instead.""" + return self._extended.should_checkpoint + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` + def should_save_summary(self): + """DEPRECATED: use extended.should_save_summary instead.""" + return self._extended.should_save_summary + + def __deepcopy__(self, memo): + # First do a regular deepcopy of `self`. + cls = self.__class__ + result = cls.__new__(cls) + memo[id(self)] = result + for k, v in self.__dict__.items(): + setattr(result, k, copy.deepcopy(v, memo)) + # One little fix-up: we want `result._extended` to reference `result` + # instead of `self`. + result._extended._container_strategy_weakref = weakref.ref(result) # pylint: disable=protected-access + return result + + def __copy__(self): + raise RuntimeError("Must only deepcopy DistributionStrategy.") + + +@tf_export("distribute.StrategyExtended") +class DistributionStrategyExtended(object): + """Additional APIs for algorithms that need to be distribution-aware. + + The intent is that you can write an algorithm in a stylized way and + it will be usable with a variety of different + `tf.distribute.Strategy` + implementations. Each descendant will implement a different strategy + for distributing the algorithm across multiple devices/machines. + Furthermore, these changes can be hidden inside the specific layers + and other library classes that need special treatment to run in a + distributed setting, so that most users' model definition code can + run unchanged. The `tf.distribute.Strategy` API works the same way + with eager and graph execution. + + First let's introduce a few high-level concepts: + + * _Data parallelism_ is where we run multiple copies of the model + on different slices of the input data. This is in contrast to + _model parallelism_ where we divide up a single copy of a model + across multiple devices. + Note: we only support data parallelism for now, but + hope to add support for model parallelism in the future. + * A _replica_ is one copy of the model, running on one slice of the + input data. + * _Synchronous_, or more commonly _sync_, training is where the + updates from each replica are aggregated together before updating + the model variables. This is in contrast to _asynchronous_, or + _async_ training, where each replica updates the model variables + independently. + * Furthermore you might run your computation on multiple devices + on one machine (or "host"), or on multiple machines/hosts. + If you are running on multiple machines, you might have a + single master host that drives computation across all of them, + or you might have multiple clients driving the computation + asynchronously. + + To distribute an algorithm, we might use some of these ingredients: + + * Parameter servers: These are hosts that hold a single copy of + parameters/variables. All replicas that want to operate on a variable + retrieve it at the beginning of a step and send an update to be + applied at the end of the step. Can support either sync or async + training. + * Mirrored variables: These are variables that are copied to multiple + devices, where we keep the copies in sync by applying the same + updates to every copy. Normally would only be used with sync training. + * Reductions and Allreduce: A _reduction_ is some method of + aggregating multiple values into one value, like "sum" or + "mean". If doing sync training, we will perform a reduction on the + gradients to a parameter from all replicas before applying the + update. Allreduce is an algorithm for performing a reduction on + values from multiple devices and making the result available on + all of those devices. + * In the future we will have support for TensorFlow's partitioned + variables, where a single variable is split across multiple + devices. + + We have then a few approaches we want to support: + + * Code written (as if) with no knowledge of class `tf.distribute.Strategy`. + This code should work as before, even if some of the layers, etc. + used by that code are written to be distribution-aware. This is done + by having a default `tf.distribute.Strategy` that gives ordinary behavior, + and by default being in a single replica context. + * Ordinary model code that you want to run using a specific + `tf.distribute.Strategy`. This can be as simple as: + + ``` + with my_strategy.scope(): + iterator = my_strategy.make_dataset_iterator(dataset) + session.run(iterator.initialize()) + replica_train_ops = my_strategy.extended.call_for_each_replica( + replica_fn, args=(iterator.get_next(),)) + train_op = my_strategy.group(replica_train_ops) + ``` + + This takes an ordinary `dataset` and `replica_fn` and runs it + distributed using a particular `tf.distribute.Strategy` in + `my_strategy`. Any variables created in `replica_fn` are created + using `my_strategy`'s policy, and library functions called by + `replica_fn` can use the `get_replica_context()` API to get enhanced + behavior in this case. + + * If you want to write a distributed algorithm, you may use any of + the `tf.distribute.Strategy` APIs inside a + `with my_strategy.scope():` block of code. + + Lower-level concepts: + + * Wrapped values: In order to represent values parallel across devices + (either replicas or the devices associated with a particular value), we + wrap them in a "PerReplica" or "Mirrored" object that contains a map + from device to values. "PerReplica" is used when the value may be + different across replicas, and "Mirrored" when the value are the same. + * Unwrapping and merging: Consider calling a function `fn` on multiple + replicas, like `extended.call_for_each_replica(fn, args=[w])` with an + argument `w` that is a wrapped value. This means `w` will have a map taking + replica device `d0` to `w0`, replica device `d1` to `w1`, + etc. `extended.call_for_each_replica()` unwraps `w` before calling `fn`, so + it calls `fn(w0)` on `d0`, `fn(w1)` on `d1`, etc. It then merges the return + values from `fn()`, which can possibly result in wrapped values. For + example, let's say `fn()` returns a tuple with three components: `(x, a, + v0)` from replica 0, `(x, b, v1)` on replica 1, etc. If the first component + is the same object `x` from every replica, then the first component of the + merged result will also be `x`. If the second component is different (`a`, + `b`, ...) from each replica, then the merged value will have a wrapped map + from replica device to the different values. If the third component is the + members of a mirrored variable (`v` maps `d0` to `v0`, `d1` to `v1`, etc.), + then the merged result will be that mirrored variable (`v`). + * Replica context vs. Cross-replica context: _replica context_ is when we + are in some function that is being called once for each replica. + Otherwise we are in cross-replica context, which is useful for + calling `tf.distribute.Strategy` methods which operate across the + replicas (like `reduce_to()`). By default you start in a replica context + (the default "single replica context") and then some methods can + switch you back and forth, as described below. + * Worker devices vs. parameter devices: Most replica computations will + happen on worker devices. Since we don't yet support model + parallelism, there will be one worker device per replica. When using + parameter servers (see above), the set of devices holding + variables may be different, otherwise the parameter devices might + match the worker devices. + * Non-slot devices are some subset of the parameter devices where we + put all the non-slot variables. We need to ensure that all + non-slot variables are allocated on the same device, or mirrored + across the same set of devices. If you have some variable you want + to colocate all the non-slot variables with, you can use + `colocate_vars_with()` to get the remaining non-slot variables on + the same device. Otherwise you can use `non_slot_devices()` to + pick a consistent set of devices to pass to both + `colocate_vars_with()` and `update_non_slot()`. + + When using a `tf.distribute.Strategy`, we have a new type dimension + called _locality_ that says what values are compatible with which + APIs: + + * T: different value for each replica (e.g. a PerReplica-wrapped value). + * M: value is "mirrored" across replicas, i.e. there are copies with the + same value on each replica (e.g. a Mirrored-wrapped value). + * V(`v`): value is "mirrored" across all the devices which have a + copy of variable `v` (also a Mirrored-wrapped value, but over + parameter devices instead of worker devices). + * N: value is "mirrored" across all the "non-slot" devices + + Rules for methods with respect to locality and single-replica vs. + cross-replica context: + + * `with d.scope()`: default single-replica context -> cross-replica context + for `d` + * `with d.extended.colocate_vars_with(v)`: in replica/cross-replica context, + variables will be created with locality V(`v`). That is, if we write + `with d.extended.colocate_vars_with(v1): v2 = tf.get_variable(...)`, + then `v2` will have locality V(`v1`), i.e. locality V(`v2`) will equal + V(`v1`). + * `with d.extended.colocate_vars_with(d.extended.non_slot_devices(...))`: in + replica/cross-replica context, variables will be created with locality N + * `v = tf.get_variable(...)`: in replica/cross-replica context, creates + a variable (which by definition will have locality V(`v`), though + will match another locality if inside a `colocate_vars_with` + scope). + * `d.make_dataset_iterator(dataset)` (or the deprecated + `d.distribute_dataset(dataset).make_one_shot_iterator()`): in cross-replica + context, produces an iterator with locality T + * `d.extended.broadcast_to(t)`: in cross-replica context, produces a value + with locality M + * `d.extended.broadcast_to(t, v)`: in cross-replica context, produces a value + with locality V(`v`) + * `d.extended.call_for_each_replica(fn, ...)`: in cross-replica context, runs + `fn()` in a replica context (and so may call `get_replica_context()` and + use its API, including `merge_call()` to get back to cross-replica + context), once for each replica. May use values with locality T or + M, and any variable. + * `d.extended.reduce_to(m, t, t)`: in cross-replica context, accepts t with + locality T and produces a value with locality M. + * `d.extended.reduce_to(m, t, v)`: in cross-replica context, accepts t with + locality T and produces a value with locality V(`v`). + * `d.extended.batch_reduce_to(m, [(t, v)]): see `d.extended.reduce_to()` + * `d.extended.update(v, fn, ...)`: in cross-replica context, runs `fn()` once + for each device `v` is copied to, all inputs should have locality + V(`v`), output will have locality V(`v`) as well. + * `d.extended.update_non_slot(d.extended.non_slot_devices(), fn)`: in + cross-replica context, like `d.extended.update()` except with locality N. + * `d.extended.read_var(v)`: Gets the (read-only) value of the variable `v` (on + the device determined by the current device scope), aggregating + across replicas for replica-local variables. Frequently, this will be + done automatically when using `v` in an expression or fetching it in + a cross-replica context, but this function can be used to force that + conversion happens at a particular point in time (for example, to + add the result of the conversion to a graph collection). + + The standard pattern for updating variables is to: + + 1. Create an input iterator with `d.make_dataset_iterator()`. + 2. Define each replica `d.extended.call_for_each_replica()` up to the point of + getting a list of gradient, variable pairs. + 3. Call `d.extended.reduce_to(VariableAggregation.SUM, t, v)` or + `d.extended.batch_reduce_to()` to sum the gradients (with locality T) + into values with locality V(`v`). + 4. Call `d.extended.update(v)` for each variable to update its value. + + Steps 3 and 4 are done automatically by class `Optimizer` if you call + its `apply_gradients` method in a replica context. Otherwise you can + manually call its `_distributed_apply` method in a cross-replica context. + + Another thing you might want to do in the middle of your replica function is + an all-reduce of some intermediate value, using `d.extended.reduce_to()` or + `d.extended.batch_reduce_to()`. You simply provide the same tensor as the + input and destination. + + Layers should expect to be called in a replica context, and can use + the `tf.distribute.get_replica_context` function to get a + `tf.distribute.ReplicaContext` object. The + `ReplicaContext` object has a `merge_call()` method for entering + cross-replica context where you can use `reduce_to()` (or + `batch_reduce_to()`) and then optionally `update()` to update state. + + You may use this API whether or not a `tf.distribute.Strategy` is + being used, since there is a default implementation of + `ReplicaContext` and `tf.distribute.Strategy`. + + NOTE for new `tf.distribute.Strategy` implementations: Please put all logic + in a subclass of `tf.distribute.StrategyExtended`. The only code needed for + the `tf.distribute.Strategy` subclass is for instantiating your subclass of + `tf.distribute.StrategyExtended` in the `__init__` method. + """ + + def __init__(self, container_strategy): + self._container_strategy_weakref = weakref.ref(container_strategy) + self._default_device = None + # This property is used to determine if we should set drop_remainder=True + # when creating Datasets from numpy array inputs. + self._require_static_shapes = False + + def _container_strategy(self): + """Get the containing `DistributionStrategy`. + + This should not generally be needed except when creating a new + `ReplicaContext` and to validate that the caller is in the correct + `scope()`. + + Returns: + The `DistributionStrategy` such that `strategy.extended` is `self`. + """ + container_strategy = self._container_strategy_weakref() + assert container_strategy is not None + return container_strategy + + def _scope(self, strategy): + """Implementation of DistributionStrategy.scope().""" + if distribution_strategy_context.has_distribution_strategy(): + _require_cross_replica_context_extended(self) + return _SameScopeAgainContext(strategy) + + def creator_with_resource_vars(*args, **kwargs): + _require_distribution_strategy_scope_extended(self) + kwargs["use_resource"] = True + return self._create_variable(*args, **kwargs) + + def distributed_getter(getter, *args, **kwargs): + if not self._allow_variable_partition(): + if kwargs.pop("partitioner", None) is not None: + tf_logging.log_first_n( + tf_logging.WARN, "Partitioned variables are disabled when using " + "current tf.distribute.Strategy.", 1) + return getter(*args, **kwargs) + + return _CurrentDistributionContext( + strategy, + variable_scope.variable_creator_scope(creator_with_resource_vars), + variable_scope.variable_scope( + variable_scope.get_variable_scope(), + custom_getter=distributed_getter), self._default_device) + + def _allow_variable_partition(self): + return False + + def _create_variable(self, next_creator, *args, **kwargs): + # Note: should support "colocate_with" argument. + raise NotImplementedError("must be implemented in descendants") + + def read_var(self, v): + """Reads the value of a variable. + + Returns the aggregate value of a replica-local variable, or the + (read-only) value of any other variable. + + Args: + v: A variable allocated within the scope of this `tf.distribute.Strategy`. + + Returns: + A tensor representing the value of `v`, aggregated across replicas if + necessary. + """ + raise NotImplementedError("must be implemented in descendants") + + def colocate_vars_with(self, colocate_with_variable): + """Scope that controls which devices variables will be created on. + + No operations should be added to the graph inside this scope, it + should only be used when creating variables (some implementations + work by changing variable creation, others work by using a + tf.colocate_with() scope). + + This may only be used inside `self.scope()`. + + Example usage: + + ``` + with strategy.scope(): + var1 = tf.get_variable(...) + with strategy.extended.colocate_vars_with(v1): + # var2 and var3 will be created on the same device(s) as var1 + var2 = tf.get_variable(...) + var3 = tf.get_variable(...) + + def fn(v1, v2, v3): + # operates on v1 from var1, v2 from var2, and v3 from var3 + + # `fn` runs on every device `v1` is on, `v2` and `v3` will be there too. + strategy.extended.update(v1, fn, args=(v2, v3)) + ``` + + Args: + colocate_with_variable: A created in `self.scope()`. Variables created + while in the returned context manager will be on the same set of + devices as `colocate_with_variable`. + + Returns: + A context manager. + """ + def create_colocated_variable(next_creator, *args, **kwargs): + _require_distribution_strategy_scope_extended(self) + kwargs["use_resource"] = True + kwargs["colocate_with"] = colocate_with_variable + return next_creator(*args, **kwargs) + + _require_distribution_strategy_scope_extended(self) + return variable_scope.variable_creator_scope(create_colocated_variable) + + def _call_dataset_fn(self, dataset_fn): + """Call the `dataset_fn` with `input_context` as argument.""" + result = dataset_fn() + if not isinstance(result, dataset_ops.DatasetV2): + raise ValueError( + "dataset_fn() must return a tf.data.Dataset when using a " + "tf.distribute.Strategy.") + return result + + # TODO(josh11b): `PerReplicaDataset` currently only implements a few methods of + # Dataset API such as make_one_shot_iterator and make_initializable_iterator. + # Extend to implement more functionality of datasets. + def _distribute_dataset(self, dataset_fn): + raise NotImplementedError("must be implemented in descendants") + + def _make_dataset_iterator(self, dataset): + raise NotImplementedError("must be implemented in descendants") + + def _make_input_fn_iterator(self, input_fn, replication_mode): + raise NotImplementedError("must be implemented in descendants") + + def broadcast_to(self, tensor, destinations): + """Mirror a tensor on one device to all worker devices. + + Args: + tensor: A Tensor value to broadcast. + destinations: A mirrored variable, device string, or list of device + strings, specifying the destination devices to copy `tensor` to. + + Returns: + A value mirrored to `destinations` devices. + """ + # TODO(josh11b): More docstring + _require_cross_replica_context_extended(self) + return self._broadcast_to(tensor, destinations) + + def _broadcast_to(self, tensor, destinations): + raise NotImplementedError("must be implemented in descendants") + + def _initialize(self): + return [] + + def _finalize(self): + return [] + + def experimental_run_steps_on_iterator(self, fn, iterator, iterations=1, + initial_loop_values=None): + """Run `fn` with input from `iterator` for `iterations` times. + + This method can be used to run a step function for training a number of + times using input from a dataset. + + Args: + fn: function to run using this distribution strategy. The function must + have the following signature: `def fn(context, inputs)`. + `context` is an instance of `MultiStepContext` that will be passed when + `fn` is run. `context` can be used to specify the outputs to be returned + from `fn` by calling `context.set_last_step_output`. It can also be used + to capture non tensor outputs by `context.set_non_tensor_output`. + See `MultiStepContext` documentation for more information. + `inputs` will have same type/structure as `iterator.get_next()`. + Typically, `fn` will use `call_for_each_replica` method of the strategy + to distribute the computation over multiple replicas. + iterator: Iterator of a dataset that represents the input for `fn`. The + caller is responsible for initializing the iterator as needed. + iterations: (Optional) Number of iterations that `fn` should be run. + Defaults to 1. + initial_loop_values: (Optional) Initial values to be passed into the + loop that runs `fn`. Defaults to `None`. # TODO(priyag): Remove + initial_loop_values argument when we have a mechanism to infer the + outputs of `fn`. + + Returns: + Returns the `MultiStepContext` object which has the following properties, + among other things: + - run_op: An op that runs `fn` `iterations` times. + - last_step_outputs: A dictionary containing tensors set using + `context.set_last_step_output`. Evaluating this returns the value of + the tensors after the last iteration. + - non_tensor_outputs: A dictionatry containing anything that was set by + `fn` by calling `context.set_non_tensor_output`. + """ + _require_cross_replica_context_extended(self) + return self._experimental_run_steps_on_iterator( + fn, iterator, iterations, initial_loop_values) + + def _experimental_run_steps_on_iterator(self, fn, iterator, iterations, + initial_loop_values): + raise NotImplementedError("must be implemented in descendants") + + def call_for_each_replica(self, fn, args=(), kwargs=None): + """Run `fn` once per replica. + + `fn` may call `tf.get_replica_context()` to access methods such as + `replica_id_in_sync_group` and `merge_call()`. + + `merge_call()` is used to communicate between the replicas and + re-enter the cross-replica context. All replicas pause their execution + having encountered a `merge_call()` call. After that the + `merge_fn`-function is executed. Its results are then unwrapped and + given back to each replica call. After that execution resumes until + `fn` is complete or encounters another `merge_call()`. Example: + + ```python + # Called once in "cross-replica" context. + def merge_fn(distribution, three_plus_replica_id): + # sum the values across replicas + return sum(distribution.unwrap(three_plus_replica_id)) + + # Called once per replica in `distribution`, in a "replica" context. + def fn(three): + replica_ctx = tf.get_replica_context() + v = three + replica_ctx.replica_id_in_sync_group + # Computes the sum of the `v` values across all replicas. + s = replica_ctx.merge_call(merge_fn, args=(v,)) + return s + v + + with distribution.scope(): + # in "cross-replica" context + ... + merged_results = distribution.call_for_each_replica(fn, args=[3]) + # merged_results has the values from every replica execution of `fn`. + print(distribution.unwrap(merged_results)) # Prints a list + ``` + + Args: + fn: function to run (will be run once per replica). + args: Tuple or list with positional arguments for `fn`. + kwargs: Dict with keyword arguments for `fn`. + + Returns: + Merged return value of `fn` across all replicas. + """ + _require_cross_replica_context_extended(self) + if kwargs is None: + kwargs = {} + return self._call_for_each_replica(fn, args, kwargs) + + def _call_for_each_replica(self, fn, args, kwargs): + raise NotImplementedError("must be implemented in descendants") + + def reduce_to(self, reduce_op, value, destinations): + """Combine (via e.g. sum or mean) values across replicas. + + Args: + reduce_op: Reduction type, an instance of `tf.distribute.ReduceOp` enum. + DEPRECATED but still accepted values: + `tf.VariableAggregation.SUM`, + `tf.VariableAggregation.MEAN`, + value: A per-replica value with one value per replica. + destinations: A mirrored variable, a per-replica tensor, a device string, + or list of device strings. The return value will be copied to all + destination devices (or all the devices where the `destinations` value + resides). To perform an all-reduction, pass `value` to `destinations`. + + Returns: + A value mirrored to `destinations`. + """ + # TODO(josh11b): More docstring + # TODO(josh11b): Return an unwrapped value if colocate_with is a + # single device. + _require_cross_replica_context_extended(self) + + # TODO(priyag): Remove this when all callers have been updated. + if isinstance(reduce_op, variable_scope.VariableAggregation): + assert reduce_op in [ + variable_scope.VariableAggregation.SUM, + variable_scope.VariableAggregation.MEAN, + ] + reduce_op = reduce_util.ReduceOp.from_variable_aggregation(reduce_op) + return self._reduce_to(reduce_op, value, destinations) + + def _reduce_to(self, reduce_op, value, destinations): + raise NotImplementedError("must be implemented in descendants") + + def batch_reduce_to(self, reduce_op, value_destination_pairs): + """Combine multiple `reduce_to` calls into one for faster execution. + + Args: + reduce_op: Reduction type, an instance of `tf.distribute.ReduceOp` enum. + DEPRECATED but still accepted values: + `tf.VariableAggregation.SUM`, + `tf.VariableAggregation.MEAN`, + value_destination_pairs: A sequence of (value, destinations) + pairs. See `reduce_to()` for a description. + + Returns: + A list of mirrored values, one per pair in `value_destination_pairs`. + """ + # TODO(josh11b): More docstring + _require_cross_replica_context_extended(self) + + # TODO(priyag): Remove this when all callers have been updated. + if isinstance(reduce_op, variable_scope.VariableAggregation): + assert reduce_op in [ + variable_scope.VariableAggregation.SUM, + variable_scope.VariableAggregation.MEAN, + ] + reduce_op = reduce_util.ReduceOp.from_variable_aggregation(reduce_op) + return self._batch_reduce_to(reduce_op, value_destination_pairs) + + def _batch_reduce_to(self, reduce_op, value_destination_pairs): + return [ + self.reduce_to(reduce_op, t, destinations=v) + for t, v in value_destination_pairs + ] + + def update(self, var, fn, args=(), kwargs=None, group=True): + """Run `fn` to update `var` using inputs mirrored to the same devices. + + If `var` is mirrored across multiple devices, then this implements + logic like: + + ``` + results = {} + for device, v in var: + with tf.device(device): + # args and kwargs will be unwrapped if they are mirrored. + results[device] = fn(v, *args, **kwargs) + return merged(results) + ``` + + Otherwise this returns `fn(var, *args, **kwargs)` colocated with `var`. + + Neither `args` nor `kwargs` may contain per-replica values. + If they contain mirrored values, they will be unwrapped before + calling `fn`. + + Args: + var: Variable, possibly mirrored to multiple devices, to operate on. + fn: Function to call. Should take the variable as the first argument. + args: Tuple or list. Additional positional arguments to pass to `fn()`. + kwargs: Dict with keyword arguments to pass to `fn()`. + group: Boolean. Defaults to True. If False, the return value will be + unwrapped. + + Returns: + By default, the merged return value of `fn` across all replicas. The + merged result has dependencies to make sure that if it is evaluated at + all, the side effects (updates) will happen on every replica. If instead + "group=False" is specified, this function will return a nest of lists + where each list has an element per replica, and the caller is responsible + for ensuring all elements are executed. + """ + _require_cross_replica_context_extended(self) + if kwargs is None: + kwargs = {} + return self._update(var, fn, args, kwargs, group) + + def _update(self, var, fn, args, kwargs, group): + raise NotImplementedError("must be implemented in descendants") + + def update_non_slot( + self, colocate_with, fn, args=(), kwargs=None, group=True): + """Runs `fn(*args, **kwargs)` on `colocate_with` devices. + + Args: + colocate_with: The return value of `non_slot_devices()`. + fn: Function to execute. + args: Tuple or list. Positional arguments to pass to `fn()`. + kwargs: Dict with keyword arguments to pass to `fn()`. + group: Boolean. Defaults to True. If False, the return value will be + unwrapped. + + Returns: + Return value of `fn`, possibly merged across devices. + """ + _require_cross_replica_context_extended(self) + if kwargs is None: + kwargs = {} + return self._update_non_slot(colocate_with, fn, args, kwargs, group) + + def _update_non_slot(self, colocate_with, fn, args, kwargs, group): + raise NotImplementedError("must be implemented in descendants") + + def _unwrap(self, distributed_value): + raise NotImplementedError("must be implemented in descendants") + + def value_container(self, value): + """Returns the container that this per-replica `value` belongs to. + + Args: + value: A value returned by `call_for_each_replica()` or a variable + created in `scope()`. + + Returns: + A container that `value` belongs to. + If value does not belong to any container (including the case of + container having been destroyed), returns the value itself. + `value in unwrap(value_container(value))` will always be true. + """ + raise NotImplementedError("must be implemented in descendants") + + def _group(self, value, name=None): + """Shortcut for `tf.group(distribution.unwrap(value))`.""" + value = nest.flatten(self._unwrap(value)) + + if len(value) != 1 or name is not None: + return control_flow_ops.group(value, name=name) + # Special handling for the common case of one op. + v, = value + if hasattr(v, "op"): + v = v.op + return v + + @property + def experimental_require_static_shapes(self): + return self._require_static_shapes + + @property + def _num_replicas_in_sync(self): + """Returns number of replicas over which gradients are aggregated.""" + raise NotImplementedError("must be implemented in descendants") + + @property + def worker_devices(self): + """Returns the list of devices used to run `call_for_each_replica()` calls. + """ + # TODO(josh11b): More docstring + raise NotImplementedError("must be implemented in descendants") + + @property + def parameter_devices(self): + """Returns the list of devices used for variable and `update` placement.""" + # TODO(josh11b): More docstring + raise NotImplementedError("must be implemented in descendants") + + def non_slot_devices(self, var_list): + """Device(s) for non-slot variables. + + Create variables on these devices in a + `with colocate_vars_with(non_slot_devices(...)):` block. + Update those using `update_non_slot()`. + + Args: + var_list: The list of variables being optimized, needed with the + default `tf.distribute.Strategy`. + """ + raise NotImplementedError("must be implemented in descendants") + + @property + def experimental_between_graph(self): + """Whether the strategy uses between-graph replication or not. + + This is expected to return a constant value that will not be changed + throughout its life cycle. + """ + raise NotImplementedError("must be implemented in descendants") + + def _configure(self, + session_config=None, + cluster_spec=None, + task_type=None, + task_id=None): + """Configures the strategy class.""" + del session_config, cluster_spec, task_type, task_id + + def _update_config_proto(self, config_proto): + return copy.deepcopy(config_proto) + + @property + def experimental_should_init(self): + """Whether initialization is needed.""" + raise NotImplementedError("must be implemented in descendants") + + @property + def should_checkpoint(self): + """Whether checkpointing is needed.""" + raise NotImplementedError("must be implemented in descendants") + + @property + def should_save_summary(self): + """Whether saving summaries is needed.""" + raise NotImplementedError("must be implemented in descendants") + + +# A note about the difference between the context managers +# `ReplicaContext` (defined here) and `_CurrentDistributionContext` +# (defined above) used by `DistributionStrategy.scope()`: +# +# * a ReplicaContext is only present during a `call_for_each_replica()` +# call (except during a `merge_run` call) and in such a scope it +# will be returned by calls to `get_replica_context()`. Implementers of new +# DistributionStrategy descendants will frequently also need to +# define a descendant of ReplicaContext, and are responsible for +# entering and exiting this context. +# +# * DistributionStrategy.scope() sets up a variable_creator scope that +# changes variable creation calls (e.g. to make mirrored +# variables). This is intended as an outer scope that users enter once +# around their model creation and graph definition. There is no +# anticipated need to define descendants of _CurrentDistributionContext. +# It sets the current DistributionStrategy for purposes of +# `get_strategy()` and `has_strategy()` +# and switches the thread mode to a "cross-replica context". +@tf_export("distribute.ReplicaContext") +class ReplicaContext(object): + """`tf.distribute.Strategy` API when in a replica context. + + To be used inside your replicated step function, such as in a + `tf.distribute.StrategyExtended.call_for_each_replica` call. + """ + + def __init__(self, strategy, replica_id_in_sync_group): + self._distribution_strategy = strategy + self._thread_context = distribution_strategy_context._InReplicaThreadMode( # pylint: disable=protected-access + self) + self._replica_id_in_sync_group = replica_id_in_sync_group + + def __enter__(self): + _push_per_thread_mode(self._thread_context) + + def __exit__(self, exception_type, exception_value, traceback): + _pop_per_thread_mode() + + def merge_call(self, merge_fn, args=(), kwargs=None): + """Merge args across replicas and run `merge_fn` in a cross-replica context. + + This allows communication and coordination when there are multiple calls + to a model function triggered by a call to + `strategy.extended.call_for_each_replica(model_fn, ...)`. + + See `tf.distribute.StrategyExtended.call_for_each_replica` for an + explanation. + + If not inside a distributed scope, this is equivalent to: + + ``` + strategy = tf.distribute.get_strategy() + with cross-replica-context(strategy): + return merge_fn(strategy, *args, **kwargs) + ``` + + Args: + merge_fn: function that joins arguments from threads that are given as + PerReplica. It accepts `tf.distribute.Strategy` object as + the first argument. + args: List or tuple with positional per-thread arguments for `merge_fn`. + kwargs: Dict with keyword per-thread arguments for `merge_fn`. + + Returns: + The return value of `merge_fn`, except for `PerReplica` values which are + unpacked. + """ + require_replica_context(self) + if kwargs is None: + kwargs = {} + return self._merge_call(merge_fn, args, kwargs) + + def _merge_call(self, merge_fn, args, kwargs): + """Default implementation for single replica.""" + _push_per_thread_mode( # thread-local, so not needed with multiple threads + distribution_strategy_context._CrossReplicaThreadMode( # pylint: disable=protected-access + self._distribution_strategy)) + try: + return merge_fn(self._distribution_strategy, *args, **kwargs) + finally: + _pop_per_thread_mode() + + @property + def num_replicas_in_sync(self): + """Returns number of replicas over which gradients are aggregated.""" + return self._distribution_strategy.num_replicas_in_sync + + @property + def replica_id_in_sync_group(self): + """Which replica is being defined, from 0 to `num_replicas_in_sync - 1`.""" + require_replica_context(self) + return self._replica_id_in_sync_group + + @property + @doc_controls.do_not_generate_docs # DEPRECATED, use `strategy` + def distribution_strategy(self): + """DEPRECATED: use `self.stratgey` instead.""" + return self._distribution_strategy + + @property + def strategy(self): + """The current `tf.distribute.Strategy` object.""" + return self._distribution_strategy + + @property + def devices(self): + """The devices this replica is to be executed on, as a list of strings.""" + require_replica_context(self) + return [device_util.current()] + + # TODO(josh11b): Implement `start_all_reduce(method, t)` for efficient + # all-reduce. It would return a function returning the result of reducing `t` + # across all replicas. The caller would wait to call this function until they + # needed the reduce result, allowing an efficient implementation: + # * With eager execution, the reduction could be performed asynchronously + # in the background, not blocking until the result was needed. + # * When constructing a graph, it could batch up all reduction requests up + # to that point that the first result is needed. Most likely this can be + # implemented in terms of `merge_call()` and `batch_reduce_to()`. + +# ------------------------------------------------------------------------------ + + +class _DefaultDistributionStrategy(DistributionStrategy): + """Default `tf.distribute.Strategy` if none is explicitly selected.""" + + def __init__(self): + super(_DefaultDistributionStrategy, self).__init__( + _DefaultDistributionExtended(self)) + + +class _DefaultDistributionExtended(DistributionStrategyExtended): + """Implementation of _DefaultDistributionStrategy.""" + + def _scope(self, strategy): + """Context manager setting a variable creator and `self` as current.""" + if distribution_strategy_context.has_distribution_strategy(): + raise RuntimeError("Must not nest tf.distribute.Strategy scopes.") + + def creator(next_creator, *args, **kwargs): + _require_distribution_strategy_scope_strategy(strategy) + return next_creator(*args, **kwargs) + + return _CurrentDistributionContext( + strategy, variable_scope.variable_creator_scope(creator)) + + def colocate_vars_with(self, colocate_with_variable): + """Does not require `self.scope`.""" + _require_distribution_strategy_scope_extended(self) + return ops.colocate_with(colocate_with_variable) + + def _distribute_dataset(self, dataset_fn): + return self._call_dataset_fn(dataset_fn) + + def _make_dataset_iterator(self, dataset): + return _DefaultDistributionExtended.DefaultInputIterator(dataset) + + def _make_input_fn_iterator(self, + input_fn, + replication_mode=InputReplicationMode.PER_WORKER): + return input_fn(InputContext()).make_initializable_iterator() + + def _broadcast_to(self, tensor, destinations): + if destinations is None: + return tensor + else: + raise NotImplementedError("TODO") + + def _call_for_each_replica(self, fn, args, kwargs): + with ReplicaContext( + self._container_strategy(), + replica_id_in_sync_group=constant_op.constant(0, dtypes.int32)): + return fn(*args, **kwargs) + + def _reduce_to(self, reduce_op, value, destinations): + # TODO(josh11b): Use destinations? + del reduce_op, destinations + return value + + def _update(self, var, fn, args, kwargs, group): + # The implementations of _update() and _update_non_slot() are identical + # except _update() passes `var` as the first argument to `fn()`. + return self._update_non_slot(var, fn, (var,) + tuple(args), kwargs, group) + + def _update_non_slot(self, colocate_with, fn, args, kwargs, should_group): + # TODO(josh11b): Figure out what we should be passing to UpdateContext() + # once that value is used for something. + with ops.colocate_with(colocate_with), UpdateContext(colocate_with): + result = fn(*args, **kwargs) + if should_group: + return result + else: + return nest.map_structure(self._unwrap, result) + + def read_var(self, replica_local_var): + return array_ops.identity(replica_local_var) + + def _unwrap(self, distributed_value): + return [distributed_value] + + def value_container(self, value): + return value + + @property + def _num_replicas_in_sync(self): + return 1 + + @property + def worker_devices(self): + raise RuntimeError("worker_devices() method unsupported by default " + "tf.distribute.Strategy.") + + @property + def parameter_devices(self): + raise RuntimeError("parameter_devices() method unsupported by default " + "tf.distribute.Strategy.") + + def non_slot_devices(self, var_list): + return min(var_list, key=lambda x: x.name) + + # TODO(priyag): This should inherit from `InputIterator`, once dependency + # issues have been resolved. + class DefaultInputIterator(object): + """Default implementation of `InputIterator` for default strategy.""" + + def __init__(self, dataset): + self._dataset = dataset + if eager_context.executing_eagerly(): + self._iterator = dataset.make_one_shot_iterator() + else: + self._iterator = dataset.make_initializable_iterator() + + def get_next(self): + return self._iterator.get_next() + + def initialize(self): + if eager_context.executing_eagerly(): + self._iterator = self._dataset.make_one_shot_iterator() + return [] + else: + return [self._iterator.initializer] + + # TODO(priyag): Delete this once all strategies use global batch size. + @property + def _global_batch_size(self): + return True + + +# ------------------------------------------------------------------------------ +# We haven't yet implemented deserialization for DistributedVariables. +# So here we catch any attempts to deserialize variables +# when using distribution strategies. +# pylint: disable=protected-access +_original_from_proto = resource_variable_ops._from_proto_fn + + +def _from_proto_fn(v, import_scope=None): + if distribution_strategy_context.has_distribution_strategy(): + raise NotImplementedError( + "Deserialization of variables is not yet supported when using a " + "tf.distribute.Strategy.") + else: + return _original_from_proto(v, import_scope=import_scope) + +resource_variable_ops._from_proto_fn = _from_proto_fn +# pylint: enable=protected-access + + +#------------------------------------------------------------------------------- +# Shorthand for some methods from distribution_strategy_context. +_push_per_thread_mode = distribution_strategy_context._push_per_thread_mode # pylint: disable=protected-access +_get_per_thread_mode = distribution_strategy_context._get_per_thread_mode # pylint: disable=protected-access +_pop_per_thread_mode = distribution_strategy_context._pop_per_thread_mode # pylint: disable=protected-access diff --git a/tensorflow/python/training/distribute_test.py b/tensorflow/python/distribute/distribute_lib_test.py similarity index 98% rename from tensorflow/python/training/distribute_test.py rename to tensorflow/python/distribute/distribute_lib_test.py index 4758e3d3d4..d63d1fe3c3 100644 --- a/tensorflow/python/training/distribute_test.py +++ b/tensorflow/python/distribute/distribute_lib_test.py @@ -18,12 +18,12 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.distribute import distribute_lib +from tensorflow.python.distribute import distribution_strategy_context from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.ops import variable_scope from tensorflow.python.platform import test -from tensorflow.python.training import distribute as distribute_lib -from tensorflow.python.training import distribution_strategy_context class _TestReplicaContext(distribute_lib.ReplicaContext): diff --git a/tensorflow/python/distribute/distribution_strategy_context.py b/tensorflow/python/distribute/distribution_strategy_context.py new file mode 100644 index 0000000000..78e096e286 --- /dev/null +++ b/tensorflow/python/distribute/distribution_strategy_context.py @@ -0,0 +1,236 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Utility to get distribution strategy related contexts.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.util.lazy_loader import LazyLoader +from tensorflow.python.util.tf_export import tf_export + + +# There is a circular dependency between this and `distribute` module. So we +# load it lazily to workaround this. +distribute_lib = LazyLoader( + "distribute_lib", globals(), + "tensorflow.python.distribute.distribute_lib") + +# ------------------------------------------------------------------------------ +# Internal API for setting the current thread mode as being either in a +# replica or cross-replica context for a particular distribution strategy. + + +class _ThreadMode(object): + + def __init__(self, dist, cross, replica): + self.distribution_strategy = dist + self.cross_replica_context = cross + self.replica_context = replica + + +class _CrossReplicaThreadMode(_ThreadMode): + + def __init__(self, distribution_strategy): + _ThreadMode.__init__( + self, distribution_strategy, distribution_strategy, None) + + +class _InReplicaThreadMode(_ThreadMode): + + def __init__(self, replica_ctx): + _ThreadMode.__init__( + self, replica_ctx.distribution_strategy, None, replica_ctx) + + +def _push_per_thread_mode(context): + ops.get_default_graph()._distribution_strategy_stack.append(context) # pylint: disable=protected-access + + +def _pop_per_thread_mode(): + ops.get_default_graph()._distribution_strategy_stack.pop(-1) # pylint: disable=protected-access + + +class _DefaultReplicaThreadMode(_ThreadMode): + """Type of default value returned by `_get_per_thread_mode()`. + + Used when the thread-local stack is empty. + """ + + def __init__(self): + _ThreadMode.__init__(self, _get_default_distribution_strategy(), None, + _get_default_replica_context()) + + +def _get_per_thread_mode(): + try: + return ops.get_default_graph()._distribution_strategy_stack[-1] # pylint: disable=protected-access + except (AttributeError, IndexError): + return _get_default_replica_mode() + + +# ------------------------------------------------------------------------------ +# Public API for accessing the current thread mode + + +@tf_export("distribute.get_replica_context") +def get_replica_context(): + """Returns the current `tf.distribute.ReplicaContext` or `None`. + + Returns `None` if in a cross-replica context. + + Note that execution: + + 1. starts in the default (single-replica) replica context (this function + will return the default `ReplicaContext` object); + 2. switches to cross-replica context (in which case this will return + `None`) when entering a `with tf.distribute.Strategy.scope():` block; + 3. switches to a (non-default) replica context inside + `extended.call_for_each_replica(fn, ...)`; + 4. if `fn` calls `get_replica_context().merge_call(merge_fn, ...)`, then + inside `merge_fn` you are back in the cross-replica context (and again + this function will return `None`). + + Note that you can also go directly from step 1 to 4 to switch to a + cross-replica context for the default `tf.distribute.Strategy`. You may + also switch from the cross-replica context of 4 to a replica context by + calling `extended.call_for_each_replica()`, jumping back to step 3. + + Most `tf.distribute.Strategy` methods may only be executed in + a cross-replica context, in a replica context you should use the + `ReplicaContext` API instead. + + Returns: + The current `ReplicaContext` object when in a replica context scope, + else `None`. + + Within a particular block, exactly one of these two things will be true: + + * `get_replica_context()` returns non-`None`, or + * `tf.distribute.is_cross_replica_context()` returns True. + """ + return _get_per_thread_mode().replica_context + + +def get_cross_replica_context(): + """Returns the current tf.distribute.Strategy if in a cross-replica context. + + DEPRECATED: Please use `in_cross_replica_context()` and + `get_distribution_strategy()` instead. + + Note that execution: + + 1. starts in the default (single-replica) replica context; + 2. switches to cross-replica context when entering a + `with tf.distribute.Strategy.scope():` block; + 3. switches to a (non-default) replica context inside + `call_for_each_replica(fn, ...)`; + 4. if `fn` calls `get_replica_context()->merge_call(merge_fn, ...)`, then + inside `merge_fn` you are back in the cross-replica context. + + Note that you can also go directly from step 1 to 4 to switch to a + cross-replica context for the default `tf.distribute.Strategy`. You may + also switch from the cross-replica context of 4 to a replica context by + calling `call_for_each_replica()`, jumping back to step 3. + + Most `tf.distribute.Strategy` methods may only be executed in + a cross-replica context. + + Returns: + Returns the current `tf.distribute.Strategy` object in a cross-replica + context, or `None`. + + Exactly one of `get_replica_context()` and `get_cross_replica_context()` + will return `None` in a particular block. + """ + return _get_per_thread_mode().cross_replica_context + + +@tf_export("distribute.in_cross_replica_context") +def in_cross_replica_context(): + """Returns True if in a cross-replica context. + + See `tf.distribute.get_replica_context` for details. + + Returns: + True if in a cross-replica context (`get_replica_context()` returns + `None`), or False if in a replica context (`get_replica_context()` returns + non-`None`). + """ + return _get_per_thread_mode().cross_replica_context is not None + + +@tf_export("distribute.get_strategy") +def get_distribution_strategy(): + """Returns the current `tf.distribute.Strategy` object. + + Typically only used in a cross-replica context: + + ``` + if tf.distribute.in_cross_replica_context(): + strategy = tf.distribute.get_strategy() + ... + ``` + + Returns: + A `tf.distribute.Strategy` object. Inside a + `with distribution_strategy.scope()` block, it returns + `distribution_strategy`, otherwise it returns the default + (single-replica) `tf.distribute.Strategy` object. + """ + return _get_per_thread_mode().distribution_strategy + + +@tf_export("distribute.has_strategy") +def has_distribution_strategy(): + """Return if there is a current non-default `tf.distribute.Strategy`. + + Returns: + True if inside a `with strategy.scope():`. + """ + return get_distribution_strategy() is not _get_default_distribution_strategy() + + +# ------------------------------------------------------------------------------ +# Defaults that are used when no distribution strategy is explicitly created. +# We create them lazily in a function so that we can workaround the circular +# dependency on distribute_lib. See lazy loader at the top of this file. + +_defaults = { + "distribution_strategy": None, + "replica_context": None, + "replica_mode": None +} + + +def _get_default_distribution_strategy(): + if _defaults["distribution_strategy"] is None: + _defaults["distribution_strategy"] = ( + distribute_lib._DefaultDistributionStrategy()) # pylint: disable=protected-access + return _defaults["distribution_strategy"] + + +def _get_default_replica_context(): + if _defaults["replica_context"] is None: + _defaults["replica_context"] = distribute_lib.ReplicaContext( + _get_default_distribution_strategy(), replica_id_in_sync_group=0) + return _defaults["replica_context"] + + +def _get_default_replica_mode(): + if _defaults["replica_mode"] is None: + _defaults["replica_mode"] = _DefaultReplicaThreadMode() + return _defaults["replica_mode"] diff --git a/tensorflow/python/distribute/mirrored_strategy.py b/tensorflow/python/distribute/mirrored_strategy.py index 7094ed6628..402a94c2b7 100644 --- a/tensorflow/python/distribute/mirrored_strategy.py +++ b/tensorflow/python/distribute/mirrored_strategy.py @@ -25,6 +25,8 @@ import threading from tensorflow.python import pywrap_tensorflow from tensorflow.python.distribute import cross_device_ops as cross_device_ops_lib +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import multi_worker_util from tensorflow.python.distribute import reduce_util from tensorflow.python.distribute import shared_variable_creator @@ -40,8 +42,6 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import variable_scope from tensorflow.python.training import coordinator -from tensorflow.python.training import device_util -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.util import nest diff --git a/tensorflow/python/distribute/values.py b/tensorflow/python/distribute/values.py index 727e491a2f..7dd1062e38 100644 --- a/tensorflow/python/distribute/values.py +++ b/tensorflow/python/distribute/values.py @@ -30,6 +30,9 @@ import six from tensorflow.python.data.experimental.ops import batching from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import multi_device_iterator_ops +from tensorflow.python.distribute import device_util +from tensorflow.python.distribute import distribute_lib +from tensorflow.python.distribute import distribution_strategy_context from tensorflow.python.distribute import input_ops from tensorflow.python.distribute import reduce_util from tensorflow.python.eager import context @@ -42,9 +45,6 @@ from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_resource_variable_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import variable_scope as vs -from tensorflow.python.training import device_util -from tensorflow.python.training import distribute as distribute_lib -from tensorflow.python.training import distribution_strategy_context from tensorflow.python.training import saver from tensorflow.python.training.checkpointable import base as checkpointable from tensorflow.python.util import nest diff --git a/tensorflow/python/tools/api/generator/doc_srcs.py b/tensorflow/python/tools/api/generator/doc_srcs.py index 9e211d172e..abb5886deb 100644 --- a/tensorflow/python/tools/api/generator/doc_srcs.py +++ b/tensorflow/python/tools/api/generator/doc_srcs.py @@ -37,7 +37,7 @@ _TENSORFLOW_DOC_SOURCES = { 'app': DocSource(docstring_module_name='platform.app'), 'bitwise': DocSource(docstring_module_name='ops.bitwise_ops'), 'compat': DocSource(docstring_module_name='util.compat'), - 'distribute': DocSource(docstring_module_name='training.distribute'), + 'distribute': DocSource(docstring_module_name='distribute.distribute_lib'), 'distributions': DocSource( docstring_module_name='ops.distributions.distributions'), 'errors': DocSource(docstring_module_name='framework.errors'), diff --git a/tensorflow/python/training/device_util.py b/tensorflow/python/training/device_util.py index 70e1ca4b5d..bf8e98052d 100644 --- a/tensorflow/python/training/device_util.py +++ b/tensorflow/python/training/device_util.py @@ -12,86 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Device-related support functions.""" +"""Deprecated, please use ../distribute/device_util.py.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.python.eager import context -from tensorflow.python.framework import device as tf_device -from tensorflow.python.framework import ops - - -def canonicalize(d, default=None): - """Canonicalize device string. - - If d has missing components, the rest would be deduced from the `default` - argument or from '/replica:0/task:0/device:CPU:0'. For example: - If d = '/cpu:0', default='/job:worker/task:1', it returns - '/job:worker/replica:0/task:1/device:CPU:0'. - If d = '/cpu:0', default='/job:worker', it returns - '/job:worker/replica:0/task:0/device:CPU:0'. - If d = '/gpu:0', default=None, it returns - '/replica:0/task:0/device:GPU:0'. - - Note: This uses "job:localhost" as the default if executing eagerly. - - Args: - d: a device string. - default: a string for default device if d doesn't have all components. - - Returns: - a canonicalized device string. - """ - d = tf_device.DeviceSpec.from_string(d) - assert d.device_type is None or d.device_type == d.device_type.upper(), ( - "Device type '%s' must be all-caps." % (d.device_type,)) - # Fill in missing device fields using defaults. - result = tf_device.DeviceSpec( - replica=0, task=0, device_type="CPU", device_index=0) - if context.executing_eagerly(): - result.job = "localhost" - if default: - result.merge_from(tf_device.DeviceSpec.from_string(default)) - result.merge_from(d) - return result.to_string() - - -def resolve(d): - """Canonicalize `d` with current device as default.""" - return canonicalize(d, default=current()) - - -class _FakeNodeDef(object): - """A fake NodeDef for _FakeOperation.""" - - def __init__(self): - self.op = "" - self.name = "" - - -class _FakeOperation(object): - """A fake Operation object to pass to device functions.""" - - def __init__(self): - self.device = "" - self.type = "" - self.name = "" - self.node_def = _FakeNodeDef() - - def _set_device(self, device): - self.device = ops._device_string(device) # pylint: disable=protected-access - - -def current(): - """Return a string (not canonicalized) for the current device.""" - # TODO(josh11b): Work out how this function interacts with ops.colocate_with. - ctx = context.context() - if ctx.executing_eagerly(): - d = ctx.device_name - else: - op = _FakeOperation() - ops.get_default_graph()._apply_device_functions(op) # pylint: disable=protected-access - d = op.device - return d +# pylint: disable=wildcard-import +from tensorflow.python.distribute.device_util import * diff --git a/tensorflow/python/training/distribute.py b/tensorflow/python/training/distribute.py index a976062249..ad27bc8a70 100644 --- a/tensorflow/python/training/distribute.py +++ b/tensorflow/python/training/distribute.py @@ -12,1654 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Library for running a computation across multiple devices.""" +"""Deprecated, please use ../distribute/distribute_lib.py.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import copy -import threading -import weakref -import enum - -from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.distribute import reduce_util -from tensorflow.python.eager import context as eager_context -from tensorflow.python.framework import constant_op -from tensorflow.python.framework import dtypes -from tensorflow.python.framework import ops -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import control_flow_ops -from tensorflow.python.ops import resource_variable_ops -from tensorflow.python.ops import variable_scope -from tensorflow.python.ops.losses import losses_impl -from tensorflow.python.platform import tf_logging -from tensorflow.python.training import device_util -from tensorflow.python.training import distribution_strategy_context -from tensorflow.python.util import nest -from tensorflow.python.util.tf_export import tf_export -from tensorflow.tools.docs import doc_controls - - -# ------------------------------------------------------------------------------ -# Context tracking whether in a strategy.update() or .update_non_slot() call. - - -_update_device = threading.local() - - -def get_update_device(): - """Get the current device if in a `tf.distribute.Strategy.update()` call.""" - try: - return _update_device.current - except AttributeError: - return None - - -class UpdateContext(object): - """Context manager when you are in `update()` or `update_non_slot()`.""" - - def __init__(self, device): - self._device = device - self._old_device = None - - def __enter__(self): - self._old_device = get_update_device() - _update_device.current = self._device - - def __exit__(self, exception_type, exception_value, traceback): - del exception_type, exception_value, traceback - _update_device.current = self._old_device - - -# ------------------------------------------------------------------------------ -# Public utility functions. - - -@tf_export("distribute.get_loss_reduction") -def get_loss_reduction(): - """`tf.distribute.ReduceOp` corresponding to the last loss reduction.""" - loss_reduction = ops.get_default_graph()._last_loss_reduction # pylint: disable=protected-access - if loss_reduction == losses_impl.Reduction.SUM: - return reduce_util.ReduceOp.SUM - return reduce_util.ReduceOp.MEAN - - -# ------------------------------------------------------------------------------ -# Internal API for validating the current thread mode - - -def _require_cross_replica_context_extended(extended): - """Verify in cross-replica context.""" - context = _get_per_thread_mode() - cross_replica = context.cross_replica_context - if cross_replica is not None and cross_replica.extended is extended: - return - strategy = extended._container_strategy() # pylint: disable=protected-access - # We have an error to report, figure out the right message. - if context.distribution_strategy is not strategy: - _wrong_strategy_scope(strategy, context) - assert cross_replica is None - raise RuntimeError("Method requires being in cross-replica context, use " - "get_replica_context().merge_call()") - - -def _wrong_strategy_scope(strategy, context): - # Figure out the right error message. - if not distribution_strategy_context.has_distribution_strategy(): - raise RuntimeError( - 'Need to be inside "with strategy.scope()" for %s' % - (strategy,)) - else: - raise RuntimeError( - "Mixing different tf.distribute.Strategy objects: %s is not %s" % - (context.distribution_strategy, strategy)) - - -def require_replica_context(replica_ctx): - """Verify in `replica_ctx` replica context.""" - context = _get_per_thread_mode() - if context.replica_context is replica_ctx: return - # We have an error to report, figure out the right message. - if context.replica_context is None: - raise RuntimeError("Need to be inside `call_for_each_replica()`") - if context.distribution_strategy is replica_ctx.distribution_strategy: - # Two different ReplicaContexts with the same tf.distribute.Strategy. - raise RuntimeError("Mismatching ReplicaContext.") - raise RuntimeError( - "Mismatching tf.distribute.Strategy objects: %s is not %s." % - (context.distribution_strategy, replica_ctx.distribution_strategy)) - - -def _require_distribution_strategy_scope_strategy(strategy): - """Verify in a `strategy.scope()` in this thread.""" - context = _get_per_thread_mode() - if context.distribution_strategy is strategy: return - _wrong_strategy_scope(strategy, context) - - -def _require_distribution_strategy_scope_extended(extended): - """Verify in a `distribution_strategy.scope()` in this thread.""" - context = _get_per_thread_mode() - if context.distribution_strategy.extended is extended: return - # Report error. - strategy = extended._container_strategy() # pylint: disable=protected-access - _wrong_strategy_scope(strategy, context) - - -# ------------------------------------------------------------------------------ -# Internal context managers used to implement the DistributionStrategy -# base class - - -class _CurrentDistributionContext(object): - """Context manager setting the current `tf.distribute.Strategy`. - - Also: overrides the variable creator and optionally the current device. - """ - - def __init__(self, - strategy, - var_creator_scope, - var_scope=None, - default_device=None): - self._context = distribution_strategy_context._CrossReplicaThreadMode( # pylint: disable=protected-access - strategy) - self._var_creator_scope = var_creator_scope - self._var_scope = var_scope - if default_device: - self._device_scope = ops.device(default_device) - else: - self._device_scope = None - - def __enter__(self): - _push_per_thread_mode(self._context) - if self._var_scope: - self._var_scope.__enter__() - self._var_creator_scope.__enter__() - if self._device_scope: - self._device_scope.__enter__() - return self._context.distribution_strategy - - def __exit__(self, exception_type, exception_value, traceback): - if self._device_scope: - self._device_scope.__exit__(exception_type, exception_value, traceback) - self._var_creator_scope.__exit__(exception_type, exception_value, traceback) - if self._var_scope: - self._var_scope.__exit__(exception_type, exception_value, traceback) - _pop_per_thread_mode() - - -class _SameScopeAgainContext(object): - """Trivial context manager when you are already in `scope()`.""" - - def __init__(self, strategy): - self._distribution_strategy = strategy - - def __enter__(self): - return self._distribution_strategy - - def __exit__(self, exception_type, exception_value, traceback): - del exception_type, exception_value, traceback - - -# TODO(yuefengz): add more replication modes. -@tf_export("distribute.InputReplicationMode") -class InputReplicationMode(enum.Enum): - """Replication mode for input function.""" - - # The input function will be called on each worker independently, creating as - # many input pipelines as number of workers. Replicas will dequeue from the - # local Dataset on their worker. Distribution Strategy doesn't manage any - # state sharing between such separate input pipelines. - PER_WORKER = "PER_WORKER" - - -@tf_export("distribute.InputContext") -class InputContext(object): - """A class wrapping information needed by an input function. - - This is a context class that is passed to the user's input fn and contains - information about the compute replicas and input pipelines. The number of - compute replicas (in sync training) helps compute per input pipeline batch - size from the desired global batch size. Input pipeline information can be - used to return a different subset of the input in each input pipeline (for - e.g. shard the input pipeline, use a different input source etc). - """ - - def __init__(self, - num_input_pipelines=1, - input_pipeline_id=0, - num_replicas_in_sync=1): - """Initializes an InputContext object. - - Args: - num_input_pipelines: the number of input pipelines in a cluster. - input_pipeline_id: the current input pipeline id, should be an int in - [0,`num_input_pipelines`). - num_replicas_in_sync: the number of replicas that are in sync. - """ - self._num_input_pipelines = num_input_pipelines - self._input_pipeline_id = input_pipeline_id - self._num_replicas_in_sync = num_replicas_in_sync - - @property - def num_replicas_in_sync(self): - """Returns the number of compute replicas in sync.""" - return self._num_replicas_in_sync - - @property - def input_pipeline_id(self): - """Returns the input pipeline ID.""" - return self._input_pipeline_id - - @property - def num_input_pipelines(self): - """Returns the number of input pipelines.""" - return self._num_input_pipelines - - def get_per_replica_batch_size(self, global_batch_size): - """Returns the per-replica batch size. - - Args: - global_batch_size: the global batch size which should be divisible by - `num_replicas_in_sync`. - - Returns: - the per-replica batch size. - - Raises: - ValueError: if `global_batch_size` not divisible by - `num_replicas_in_sync`. - """ - if global_batch_size % self._num_replicas_in_sync != 0: - raise ValueError("The `global_batch_size` %r is not divisible by " - "`num_replicas_in_sync` %r " % - (global_batch_size, self._num_replicas_in_sync)) - return global_batch_size // self._num_replicas_in_sync - - -# ------------------------------------------------------------------------------ -# Base classes for all distribution strategies. - - -@tf_export("distribute.Strategy") -class DistributionStrategy(object): - """A list of devices with a state & compute distribution policy. - - See [tensorflow/contrib/distribute/README.md]( - https://www.tensorflow.org/code/tensorflow/contrib/distribute/README.md) - for overview and examples. - """ - - # TODO(josh11b): Raise an exception if variable partitioning requested before - # we add support. - # TODO(josh11b): Also `parameter_device_index` property? - # TODO(josh11b): `map()` - # TODO(josh11b): ClusterSpec/ClusterResolver - # TODO(josh11b): Partitioned computations, state; sharding - # TODO(josh11b): Model parallelism: "replicas" with multiple devices; shuffling - # TODO(josh11b): List of replicas with their worker and parameter devices - # (where the parameter devices may overlap in the ps case). - - def __init__(self, extended): - self._extended = extended - - @property - def extended(self): - """`tf.distribute.StrategyExtended` with additional methods.""" - return self._extended - - def scope(self): - """Returns a context manager selecting this Strategy as current. - - Inside a `with strategy.scope():` code block, this thread - will use a variable creator set by `strategy`, and will - enter its "cross-replica context". - - Returns: - A context manager. - """ - return self._extended._scope(self) # pylint: disable=protected-access - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def read_var(self, v): - """DEPRECATED: use extended.read_var() instead.""" - return self._extended.read_var(v) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def colocate_vars_with(self, colocate_with_variable): - """DEPRECATED: use extended.colocate_vars_with() instead.""" - return self._extended.colocate_vars_with(colocate_with_variable) - - @doc_controls.do_not_generate_docs # DEPRECATED - def distribute_dataset(self, dataset_fn): - """Return a `dataset` split across all replicas. DEPRECATED. - - DEPRECATED: Please use `make_dataset_iterator` or - `make_input_fn_iterator` instead. - - Suitable for providing input to `extended.call_for_each_replica()` by - creating an iterator: - - ``` - def dataset_fn(): - return tf.data.Dataset.from_tensors([[1.]]).repeat() - - with strategy.scope(): - distributed_dataset = strategy.distribute_dataset(dataset_fn) - iterator = distributed_dataset.make_initializable_iterator() - replica_results = strategy.extended.call_for_each_replica( - replica_fn, args=(iterator.get_next(),)) - ``` - - Args: - dataset_fn: A function that returns a `tf.data.Dataset`. - - Returns: - A `PerReplicaDataset` that will produce data for each replica. - """ - return self._extended._distribute_dataset(dataset_fn) # pylint: disable=protected-access - - def make_dataset_iterator(self, dataset): - """Makes an iterator for input provided via input_dataset. - - Data from the given dataset will be distributed evenly across all the - compute replicas. We will assume that the input dataset is batched by the - global batch size. With this assumption, we will make a best effort to - divide each batch across all the replicas (one or more workers). - If this effort fails, an error will be thrown, and the user should instead - use `make_input_fn_iterator` which provides more control to the user, and - does not try to divide a batch across replicas. - - The user could also use `make_input_fn_iterator` if they want to - customize which input is fed to which replica/worker etc. - - Args: - dataset: `tf.data.Dataset` that will be distributed evenly across all - replicas. - - Returns: - An `tf.distribute.InputIterator` which returns inputs for each step of the - computation. User should call `initialize` on the returned iterator. - """ - return self._extended._make_dataset_iterator(dataset) # pylint: disable=protected-access - - def make_input_fn_iterator(self, - input_fn, - replication_mode=InputReplicationMode.PER_WORKER): - """Returns an iterator split across replicas created from an input function. - - The `input_fn` should take an `tf.distribute.InputContext` object where - information about input sharding can be accessed: - - ``` - def input_fn(input_context): - d = tf.data.Dataset.from_tensors([[1.]]).repeat() - return d.shard(input_context.num_input_pipelines, - input_context.input_pipeline_id) - with strategy.scope(): - iterator = strategy.make_input_fn_iterator( - input_fn) - replica_results = strategy.extended.call_for_each_replica( - replica_fn, iterator.get_next()) - ``` - - Args: - input_fn: A function that returns a `tf.data.Dataset`. This function is - expected to take an `tf.distribute.InputContext` object. - replication_mode: an enum value of `tf.distribute.InputReplicationMode`. - Only `PER_WORKER` is supported currently. - - Returns: - An iterator object that can be initialized and fetched next element. - """ - if replication_mode != InputReplicationMode.PER_WORKER: - raise ValueError( - "Input replication mode not supported: %r" % replication_mode) - return self.extended._make_input_fn_iterator( # pylint: disable=protected-access - input_fn, replication_mode=replication_mode) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def broadcast(self, tensor, destinations=None): - """DEPRECATED: use extended.broadcast_to() instead.""" - return self._extended.broadcast_to(tensor, destinations) - - @doc_controls.do_not_generate_docs # Use experimental_initialize() instead. - def initialize(self): - """DEPRECATED: Use `experimental_initialize()` instead.""" - return self._extended._initialize() # pylint: disable=protected-access - - def experimental_initialize(self): - """Any initialization to be done before running any computations. - - In eager mode, it executes any initialization as a side effect. - In graph mode, it creates the initialization ops and returns them. - - For example, TPU initialize_system ops. - - Returns: - A list of ops to execute. - """ - return self._extended._initialize() # pylint: disable=protected-access - - @doc_controls.do_not_generate_docs # Use experimental_finalize() instead. - def finalize(self): - """DEPRECATED: Use `experimental_finalize()` instead.""" - return self._extended._finalize() # pylint: disable=protected-access - - def experimental_finalize(self): - """Any final actions to be done at the end of all computations. - - In eager mode, it executes any finalize actions as a side effect. - In graph mode, it creates the finalize ops and returns them. - - For example, TPU shutdown ops. - - Returns: - A list of ops to execute. - """ - return self._extended._finalize() # pylint: disable=protected-access - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def run_steps_on_dataset(self, fn, iterator, iterations=1, - initial_loop_values=None): - """DEPRECATED: use extended.experimental_run_steps_on_iterator() instead.""" - return self._extended.experimental_run_steps_on_iterator( - fn, iterator, iterations, initial_loop_values) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def call_for_each_replica(self, fn, *args, **kwargs): - """DEPRECATED: use extended.call_for_each_replica() instead.""" - # Handle old *args, **kwargs, and new args=(...), kwargs={...}, to - # allow transition. - a = kwargs.pop("args", None) - if a is not None: - if args: - raise ValueError( - "Can't pass *args and args=... to call_for_each_replica") - args = a - k = kwargs.pop("kwargs", None) - if k is not None: - if kwargs: - raise ValueError( - "Can't pass **kwargs and kwargs=... to call_for_each_replica") - kwargs = k - kwargs.pop("run_concurrently", None) # Ignore old option. - return self._extended.call_for_each_replica(fn, args, kwargs) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def reduce(self, aggregation, value, destinations): - """DEPRECATED: use extended.reduce_to() instead.""" - return self._extended.reduce_to(aggregation, value, destinations) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def batch_reduce(self, aggregation, value_destination_pairs): - """DEPRECATED: use extended.batch_reduce_to() instead.""" - return self._extended.batch_reduce_to(aggregation, value_destination_pairs) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def update(self, var, fn, *args, **kwargs): - """DEPRECATED: use extended.update() instead.""" - group = kwargs.pop("group", True) - # We temporarily support "grouped" in addition to "group" for backward- - # compatibility. - group = kwargs.pop("grouped", True) and group - # Handle old *args, **kwargs, and new args=(...), kwargs={...}, to - # allow transition. - a = kwargs.pop("args", None) - if a is not None: - if args: - raise ValueError( - "Can't pass *args and args=... to update") - args = a - k = kwargs.pop("kwargs", None) - if k is not None: - if kwargs: - raise ValueError( - "Can't pass **kwargs and kwargs=... to update") - kwargs = k - return self._extended.update(var, fn, args, kwargs, group) - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def update_non_slot(self, colocate_with, fn, *args, **kwargs): - """DEPRECATED: use extended.update_non_slot() instead.""" - group = kwargs.pop("group", True) - # We temporarily support "grouped" in addition to "group" for backward- - # compatibility. - group = kwargs.pop("grouped", True) and group - # Handle old *args, **kwargs, and new args=(...), kwargs={...}, to - # allow transition. - a = kwargs.pop("args", None) - if a is not None: - if args: - raise ValueError( - "Can't pass *args and args=... to update_non_slot") - args = a - k = kwargs.pop("kwargs", None) - if k is not None: - if kwargs: - raise ValueError( - "Can't pass **kwargs and kwargs=... to update_non_slot") - kwargs = k - return self._extended.update_non_slot( - colocate_with, fn, args, kwargs, group) - - @doc_controls.do_not_generate_docs # DEPRECATED, -> `DistributedValues` - def unwrap(self, value): - """Returns the list of all per-replica values contained in `value`. - - Args: - value: A value returned by `extended.call_for_each_replica()` or a - variable created in `scope`. - - Returns: - A list of values contained in `value`. If `value` represents a single - value, this returns `[value].` - """ - return self._extended._unwrap(value) # pylint: disable=protected-access - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def value_container(self, value): - """DEPRECATED: use extended.value_container() instead.""" - return self._extended.value_container(value) - - @doc_controls.do_not_generate_docs # DEPRECATED, -> `DistributedValues` - def group(self, value, name=None): - """Shortcut for `tf.group(self.unwrap(value))`.""" - return self._extended._group(value, name) # pylint: disable=protected-access - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def require_static_shapes(self): - """DEPRECATED: use extended.require_static_shapes instead.""" - return self._extended.experimental_require_static_shapes - - @property - def num_replicas_in_sync(self): - """Returns number of replicas over which gradients are aggregated.""" - return self._extended._num_replicas_in_sync # pylint: disable=protected-access - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def worker_devices(self): - """DEPRECATED: use extended.worker_devices instead.""" - return self._extended.worker_devices - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def parameter_devices(self): - """DEPRECATED: use extended.parameter_devices instead.""" - return self._extended.parameter_devices - - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def non_slot_devices(self, var_list): - """DEPRECATED: use extended.non_slot_devices instead.""" - return self._extended.non_slot_devices(var_list) - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def between_graph(self): - """DEPRECATED: use extended.experimental_between_graph instead.""" - return self._extended.experimental_between_graph - - @doc_controls.do_not_generate_docs # DEPRECATED, being replaced by a new API. - def configure(self, - session_config=None, - cluster_spec=None, - task_type=None, - task_id=None): - # pylint: disable=g-doc-return-or-yield,g-doc-args - """DEPRECATED: use `update_config_proto` instead. - - Configures the strategy class. - - DEPRECATED: This method's functionality has been split into the strategy - constructor and `update_config_proto`. In the future, we will allow passing - cluster and config_proto to the constructor to configure the strategy. And - `update_config_proto` can be used to update the config_proto based on the - specific strategy. - """ - return self._extended._configure( # pylint: disable=protected-access - session_config, cluster_spec, task_type, task_id) - - def update_config_proto(self, config_proto): - """Returns a copy of `config_proto` modified for use with this strategy. - - The updated config has something needed to run a strategy, e.g. - configuration to run collective ops, or device filters to improve - distributed training performance. - - Args: - config_proto: a `tf.ConfigProto` object. - - Returns: - The updated copy of the `config_proto`. - """ - return self._extended._update_config_proto(config_proto) # pylint: disable=protected-access - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def should_init(self): - """DEPRECATED: use extended.should_init instead.""" - return self._extended.experimental_should_init - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def should_checkpoint(self): - """DEPRECATED: use extended.should_checkpoint instead.""" - return self._extended.should_checkpoint - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def should_save_summary(self): - """DEPRECATED: use extended.should_save_summary instead.""" - return self._extended.should_save_summary - - def __deepcopy__(self, memo): - # First do a regular deepcopy of `self`. - cls = self.__class__ - result = cls.__new__(cls) - memo[id(self)] = result - for k, v in self.__dict__.items(): - setattr(result, k, copy.deepcopy(v, memo)) - # One little fix-up: we want `result._extended` to reference `result` - # instead of `self`. - result._extended._container_strategy_weakref = weakref.ref(result) # pylint: disable=protected-access - return result - - def __copy__(self): - raise RuntimeError("Must only deepcopy DistributionStrategy.") - - -@tf_export("distribute.StrategyExtended") -class DistributionStrategyExtended(object): - """Additional APIs for algorithms that need to be distribution-aware. - - The intent is that you can write an algorithm in a stylized way and - it will be usable with a variety of different - `tf.distribute.Strategy` - implementations. Each descendant will implement a different strategy - for distributing the algorithm across multiple devices/machines. - Furthermore, these changes can be hidden inside the specific layers - and other library classes that need special treatment to run in a - distributed setting, so that most users' model definition code can - run unchanged. The `tf.distribute.Strategy` API works the same way - with eager and graph execution. - - First let's introduce a few high-level concepts: - - * _Data parallelism_ is where we run multiple copies of the model - on different slices of the input data. This is in contrast to - _model parallelism_ where we divide up a single copy of a model - across multiple devices. - Note: we only support data parallelism for now, but - hope to add support for model parallelism in the future. - * A _replica_ is one copy of the model, running on one slice of the - input data. - * _Synchronous_, or more commonly _sync_, training is where the - updates from each replica are aggregated together before updating - the model variables. This is in contrast to _asynchronous_, or - _async_ training, where each replica updates the model variables - independently. - * Furthermore you might run your computation on multiple devices - on one machine (or "host"), or on multiple machines/hosts. - If you are running on multiple machines, you might have a - single master host that drives computation across all of them, - or you might have multiple clients driving the computation - asynchronously. - - To distribute an algorithm, we might use some of these ingredients: - - * Parameter servers: These are hosts that hold a single copy of - parameters/variables. All replicas that want to operate on a variable - retrieve it at the beginning of a step and send an update to be - applied at the end of the step. Can support either sync or async - training. - * Mirrored variables: These are variables that are copied to multiple - devices, where we keep the copies in sync by applying the same - updates to every copy. Normally would only be used with sync training. - * Reductions and Allreduce: A _reduction_ is some method of - aggregating multiple values into one value, like "sum" or - "mean". If doing sync training, we will perform a reduction on the - gradients to a parameter from all replicas before applying the - update. Allreduce is an algorithm for performing a reduction on - values from multiple devices and making the result available on - all of those devices. - * In the future we will have support for TensorFlow's partitioned - variables, where a single variable is split across multiple - devices. - - We have then a few approaches we want to support: - - * Code written (as if) with no knowledge of class `tf.distribute.Strategy`. - This code should work as before, even if some of the layers, etc. - used by that code are written to be distribution-aware. This is done - by having a default `tf.distribute.Strategy` that gives ordinary behavior, - and by default being in a single replica context. - * Ordinary model code that you want to run using a specific - `tf.distribute.Strategy`. This can be as simple as: - - ``` - with my_strategy.scope(): - iterator = my_strategy.make_dataset_iterator(dataset) - session.run(iterator.initialize()) - replica_train_ops = my_strategy.extended.call_for_each_replica( - replica_fn, args=(iterator.get_next(),)) - train_op = my_strategy.group(replica_train_ops) - ``` - - This takes an ordinary `dataset` and `replica_fn` and runs it - distributed using a particular `tf.distribute.Strategy` in - `my_strategy`. Any variables created in `replica_fn` are created - using `my_strategy`'s policy, and library functions called by - `replica_fn` can use the `get_replica_context()` API to get enhanced - behavior in this case. - - * If you want to write a distributed algorithm, you may use any of - the `tf.distribute.Strategy` APIs inside a - `with my_strategy.scope():` block of code. - - Lower-level concepts: - - * Wrapped values: In order to represent values parallel across devices - (either replicas or the devices associated with a particular value), we - wrap them in a "PerReplica" or "Mirrored" object that contains a map - from device to values. "PerReplica" is used when the value may be - different across replicas, and "Mirrored" when the value are the same. - * Unwrapping and merging: Consider calling a function `fn` on multiple - replicas, like `extended.call_for_each_replica(fn, args=[w])` with an - argument `w` that is a wrapped value. This means `w` will have a map taking - replica device `d0` to `w0`, replica device `d1` to `w1`, - etc. `extended.call_for_each_replica()` unwraps `w` before calling `fn`, so - it calls `fn(w0)` on `d0`, `fn(w1)` on `d1`, etc. It then merges the return - values from `fn()`, which can possibly result in wrapped values. For - example, let's say `fn()` returns a tuple with three components: `(x, a, - v0)` from replica 0, `(x, b, v1)` on replica 1, etc. If the first component - is the same object `x` from every replica, then the first component of the - merged result will also be `x`. If the second component is different (`a`, - `b`, ...) from each replica, then the merged value will have a wrapped map - from replica device to the different values. If the third component is the - members of a mirrored variable (`v` maps `d0` to `v0`, `d1` to `v1`, etc.), - then the merged result will be that mirrored variable (`v`). - * Replica context vs. Cross-replica context: _replica context_ is when we - are in some function that is being called once for each replica. - Otherwise we are in cross-replica context, which is useful for - calling `tf.distribute.Strategy` methods which operate across the - replicas (like `reduce_to()`). By default you start in a replica context - (the default "single replica context") and then some methods can - switch you back and forth, as described below. - * Worker devices vs. parameter devices: Most replica computations will - happen on worker devices. Since we don't yet support model - parallelism, there will be one worker device per replica. When using - parameter servers (see above), the set of devices holding - variables may be different, otherwise the parameter devices might - match the worker devices. - * Non-slot devices are some subset of the parameter devices where we - put all the non-slot variables. We need to ensure that all - non-slot variables are allocated on the same device, or mirrored - across the same set of devices. If you have some variable you want - to colocate all the non-slot variables with, you can use - `colocate_vars_with()` to get the remaining non-slot variables on - the same device. Otherwise you can use `non_slot_devices()` to - pick a consistent set of devices to pass to both - `colocate_vars_with()` and `update_non_slot()`. - - When using a `tf.distribute.Strategy`, we have a new type dimension - called _locality_ that says what values are compatible with which - APIs: - - * T: different value for each replica (e.g. a PerReplica-wrapped value). - * M: value is "mirrored" across replicas, i.e. there are copies with the - same value on each replica (e.g. a Mirrored-wrapped value). - * V(`v`): value is "mirrored" across all the devices which have a - copy of variable `v` (also a Mirrored-wrapped value, but over - parameter devices instead of worker devices). - * N: value is "mirrored" across all the "non-slot" devices - - Rules for methods with respect to locality and single-replica vs. - cross-replica context: - - * `with d.scope()`: default single-replica context -> cross-replica context - for `d` - * `with d.extended.colocate_vars_with(v)`: in replica/cross-replica context, - variables will be created with locality V(`v`). That is, if we write - `with d.extended.colocate_vars_with(v1): v2 = tf.get_variable(...)`, - then `v2` will have locality V(`v1`), i.e. locality V(`v2`) will equal - V(`v1`). - * `with d.extended.colocate_vars_with(d.extended.non_slot_devices(...))`: in - replica/cross-replica context, variables will be created with locality N - * `v = tf.get_variable(...)`: in replica/cross-replica context, creates - a variable (which by definition will have locality V(`v`), though - will match another locality if inside a `colocate_vars_with` - scope). - * `d.make_dataset_iterator(dataset)` (or the deprecated - `d.distribute_dataset(dataset).make_one_shot_iterator()`): in cross-replica - context, produces an iterator with locality T - * `d.extended.broadcast_to(t)`: in cross-replica context, produces a value - with locality M - * `d.extended.broadcast_to(t, v)`: in cross-replica context, produces a value - with locality V(`v`) - * `d.extended.call_for_each_replica(fn, ...)`: in cross-replica context, runs - `fn()` in a replica context (and so may call `get_replica_context()` and - use its API, including `merge_call()` to get back to cross-replica - context), once for each replica. May use values with locality T or - M, and any variable. - * `d.extended.reduce_to(m, t, t)`: in cross-replica context, accepts t with - locality T and produces a value with locality M. - * `d.extended.reduce_to(m, t, v)`: in cross-replica context, accepts t with - locality T and produces a value with locality V(`v`). - * `d.extended.batch_reduce_to(m, [(t, v)]): see `d.extended.reduce_to()` - * `d.extended.update(v, fn, ...)`: in cross-replica context, runs `fn()` once - for each device `v` is copied to, all inputs should have locality - V(`v`), output will have locality V(`v`) as well. - * `d.extended.update_non_slot(d.extended.non_slot_devices(), fn)`: in - cross-replica context, like `d.extended.update()` except with locality N. - * `d.extended.read_var(v)`: Gets the (read-only) value of the variable `v` (on - the device determined by the current device scope), aggregating - across replicas for replica-local variables. Frequently, this will be - done automatically when using `v` in an expression or fetching it in - a cross-replica context, but this function can be used to force that - conversion happens at a particular point in time (for example, to - add the result of the conversion to a graph collection). - - The standard pattern for updating variables is to: - - 1. Create an input iterator with `d.make_dataset_iterator()`. - 2. Define each replica `d.extended.call_for_each_replica()` up to the point of - getting a list of gradient, variable pairs. - 3. Call `d.extended.reduce_to(VariableAggregation.SUM, t, v)` or - `d.extended.batch_reduce_to()` to sum the gradients (with locality T) - into values with locality V(`v`). - 4. Call `d.extended.update(v)` for each variable to update its value. - - Steps 3 and 4 are done automatically by class `Optimizer` if you call - its `apply_gradients` method in a replica context. Otherwise you can - manually call its `_distributed_apply` method in a cross-replica context. - - Another thing you might want to do in the middle of your replica function is - an all-reduce of some intermediate value, using `d.extended.reduce_to()` or - `d.extended.batch_reduce_to()`. You simply provide the same tensor as the - input and destination. - - Layers should expect to be called in a replica context, and can use - the `tf.distribute.get_replica_context` function to get a - `tf.distribute.ReplicaContext` object. The - `ReplicaContext` object has a `merge_call()` method for entering - cross-replica context where you can use `reduce_to()` (or - `batch_reduce_to()`) and then optionally `update()` to update state. - - You may use this API whether or not a `tf.distribute.Strategy` is - being used, since there is a default implementation of - `ReplicaContext` and `tf.distribute.Strategy`. - - NOTE for new `tf.distribute.Strategy` implementations: Please put all logic - in a subclass of `tf.distribute.StrategyExtended`. The only code needed for - the `tf.distribute.Strategy` subclass is for instantiating your subclass of - `tf.distribute.StrategyExtended` in the `__init__` method. - """ - - def __init__(self, container_strategy): - self._container_strategy_weakref = weakref.ref(container_strategy) - self._default_device = None - # This property is used to determine if we should set drop_remainder=True - # when creating Datasets from numpy array inputs. - self._require_static_shapes = False - - def _container_strategy(self): - """Get the containing `DistributionStrategy`. - - This should not generally be needed except when creating a new - `ReplicaContext` and to validate that the caller is in the correct - `scope()`. - - Returns: - The `DistributionStrategy` such that `strategy.extended` is `self`. - """ - container_strategy = self._container_strategy_weakref() - assert container_strategy is not None - return container_strategy - - def _scope(self, strategy): - """Implementation of DistributionStrategy.scope().""" - if distribution_strategy_context.has_distribution_strategy(): - _require_cross_replica_context_extended(self) - return _SameScopeAgainContext(strategy) - - def creator_with_resource_vars(*args, **kwargs): - _require_distribution_strategy_scope_extended(self) - kwargs["use_resource"] = True - return self._create_variable(*args, **kwargs) - - def distributed_getter(getter, *args, **kwargs): - if not self._allow_variable_partition(): - if kwargs.pop("partitioner", None) is not None: - tf_logging.log_first_n( - tf_logging.WARN, "Partitioned variables are disabled when using " - "current tf.distribute.Strategy.", 1) - return getter(*args, **kwargs) - - return _CurrentDistributionContext( - strategy, - variable_scope.variable_creator_scope(creator_with_resource_vars), - variable_scope.variable_scope( - variable_scope.get_variable_scope(), - custom_getter=distributed_getter), self._default_device) - - def _allow_variable_partition(self): - return False - - def _create_variable(self, next_creator, *args, **kwargs): - # Note: should support "colocate_with" argument. - raise NotImplementedError("must be implemented in descendants") - - def read_var(self, v): - """Reads the value of a variable. - - Returns the aggregate value of a replica-local variable, or the - (read-only) value of any other variable. - - Args: - v: A variable allocated within the scope of this `tf.distribute.Strategy`. - - Returns: - A tensor representing the value of `v`, aggregated across replicas if - necessary. - """ - raise NotImplementedError("must be implemented in descendants") - - def colocate_vars_with(self, colocate_with_variable): - """Scope that controls which devices variables will be created on. - - No operations should be added to the graph inside this scope, it - should only be used when creating variables (some implementations - work by changing variable creation, others work by using a - tf.colocate_with() scope). - - This may only be used inside `self.scope()`. - - Example usage: - - ``` - with strategy.scope(): - var1 = tf.get_variable(...) - with strategy.extended.colocate_vars_with(v1): - # var2 and var3 will be created on the same device(s) as var1 - var2 = tf.get_variable(...) - var3 = tf.get_variable(...) - - def fn(v1, v2, v3): - # operates on v1 from var1, v2 from var2, and v3 from var3 - - # `fn` runs on every device `v1` is on, `v2` and `v3` will be there too. - strategy.extended.update(v1, fn, args=(v2, v3)) - ``` - - Args: - colocate_with_variable: A created in `self.scope()`. Variables created - while in the returned context manager will be on the same set of - devices as `colocate_with_variable`. - - Returns: - A context manager. - """ - def create_colocated_variable(next_creator, *args, **kwargs): - _require_distribution_strategy_scope_extended(self) - kwargs["use_resource"] = True - kwargs["colocate_with"] = colocate_with_variable - return next_creator(*args, **kwargs) - - _require_distribution_strategy_scope_extended(self) - return variable_scope.variable_creator_scope(create_colocated_variable) - - def _call_dataset_fn(self, dataset_fn): - """Call the `dataset_fn` with `input_context` as argument.""" - result = dataset_fn() - if not isinstance(result, dataset_ops.DatasetV2): - raise ValueError( - "dataset_fn() must return a tf.data.Dataset when using a " - "tf.distribute.Strategy.") - return result - - # TODO(josh11b): `PerReplicaDataset` currently only implements a few methods of - # Dataset API such as make_one_shot_iterator and make_initializable_iterator. - # Extend to implement more functionality of datasets. - def _distribute_dataset(self, dataset_fn): - raise NotImplementedError("must be implemented in descendants") - - def _make_dataset_iterator(self, dataset): - raise NotImplementedError("must be implemented in descendants") - - def _make_input_fn_iterator(self, input_fn, replication_mode): - raise NotImplementedError("must be implemented in descendants") - - def broadcast_to(self, tensor, destinations): - """Mirror a tensor on one device to all worker devices. - - Args: - tensor: A Tensor value to broadcast. - destinations: A mirrored variable, device string, or list of device - strings, specifying the destination devices to copy `tensor` to. - - Returns: - A value mirrored to `destinations` devices. - """ - # TODO(josh11b): More docstring - _require_cross_replica_context_extended(self) - return self._broadcast_to(tensor, destinations) - - def _broadcast_to(self, tensor, destinations): - raise NotImplementedError("must be implemented in descendants") - - def _initialize(self): - return [] - - def _finalize(self): - return [] - - def experimental_run_steps_on_iterator(self, fn, iterator, iterations=1, - initial_loop_values=None): - """Run `fn` with input from `iterator` for `iterations` times. - - This method can be used to run a step function for training a number of - times using input from a dataset. - - Args: - fn: function to run using this distribution strategy. The function must - have the following signature: `def fn(context, inputs)`. - `context` is an instance of `MultiStepContext` that will be passed when - `fn` is run. `context` can be used to specify the outputs to be returned - from `fn` by calling `context.set_last_step_output`. It can also be used - to capture non tensor outputs by `context.set_non_tensor_output`. - See `MultiStepContext` documentation for more information. - `inputs` will have same type/structure as `iterator.get_next()`. - Typically, `fn` will use `call_for_each_replica` method of the strategy - to distribute the computation over multiple replicas. - iterator: Iterator of a dataset that represents the input for `fn`. The - caller is responsible for initializing the iterator as needed. - iterations: (Optional) Number of iterations that `fn` should be run. - Defaults to 1. - initial_loop_values: (Optional) Initial values to be passed into the - loop that runs `fn`. Defaults to `None`. # TODO(priyag): Remove - initial_loop_values argument when we have a mechanism to infer the - outputs of `fn`. - - Returns: - Returns the `MultiStepContext` object which has the following properties, - among other things: - - run_op: An op that runs `fn` `iterations` times. - - last_step_outputs: A dictionary containing tensors set using - `context.set_last_step_output`. Evaluating this returns the value of - the tensors after the last iteration. - - non_tensor_outputs: A dictionatry containing anything that was set by - `fn` by calling `context.set_non_tensor_output`. - """ - _require_cross_replica_context_extended(self) - return self._experimental_run_steps_on_iterator( - fn, iterator, iterations, initial_loop_values) - - def _experimental_run_steps_on_iterator(self, fn, iterator, iterations, - initial_loop_values): - raise NotImplementedError("must be implemented in descendants") - - def call_for_each_replica(self, fn, args=(), kwargs=None): - """Run `fn` once per replica. - - `fn` may call `tf.get_replica_context()` to access methods such as - `replica_id_in_sync_group` and `merge_call()`. - - `merge_call()` is used to communicate between the replicas and - re-enter the cross-replica context. All replicas pause their execution - having encountered a `merge_call()` call. After that the - `merge_fn`-function is executed. Its results are then unwrapped and - given back to each replica call. After that execution resumes until - `fn` is complete or encounters another `merge_call()`. Example: - - ```python - # Called once in "cross-replica" context. - def merge_fn(distribution, three_plus_replica_id): - # sum the values across replicas - return sum(distribution.unwrap(three_plus_replica_id)) - - # Called once per replica in `distribution`, in a "replica" context. - def fn(three): - replica_ctx = tf.get_replica_context() - v = three + replica_ctx.replica_id_in_sync_group - # Computes the sum of the `v` values across all replicas. - s = replica_ctx.merge_call(merge_fn, args=(v,)) - return s + v - - with distribution.scope(): - # in "cross-replica" context - ... - merged_results = distribution.call_for_each_replica(fn, args=[3]) - # merged_results has the values from every replica execution of `fn`. - print(distribution.unwrap(merged_results)) # Prints a list - ``` - - Args: - fn: function to run (will be run once per replica). - args: Tuple or list with positional arguments for `fn`. - kwargs: Dict with keyword arguments for `fn`. - - Returns: - Merged return value of `fn` across all replicas. - """ - _require_cross_replica_context_extended(self) - if kwargs is None: - kwargs = {} - return self._call_for_each_replica(fn, args, kwargs) - - def _call_for_each_replica(self, fn, args, kwargs): - raise NotImplementedError("must be implemented in descendants") - - def reduce_to(self, reduce_op, value, destinations): - """Combine (via e.g. sum or mean) values across replicas. - - Args: - reduce_op: Reduction type, an instance of `tf.distribute.ReduceOp` enum. - DEPRECATED but still accepted values: - `tf.VariableAggregation.SUM`, - `tf.VariableAggregation.MEAN`, - value: A per-replica value with one value per replica. - destinations: A mirrored variable, a per-replica tensor, a device string, - or list of device strings. The return value will be copied to all - destination devices (or all the devices where the `destinations` value - resides). To perform an all-reduction, pass `value` to `destinations`. - - Returns: - A value mirrored to `destinations`. - """ - # TODO(josh11b): More docstring - # TODO(josh11b): Return an unwrapped value if colocate_with is a - # single device. - _require_cross_replica_context_extended(self) - - # TODO(priyag): Remove this when all callers have been updated. - if isinstance(reduce_op, variable_scope.VariableAggregation): - assert reduce_op in [ - variable_scope.VariableAggregation.SUM, - variable_scope.VariableAggregation.MEAN, - ] - reduce_op = reduce_util.ReduceOp.from_variable_aggregation(reduce_op) - return self._reduce_to(reduce_op, value, destinations) - - def _reduce_to(self, reduce_op, value, destinations): - raise NotImplementedError("must be implemented in descendants") - - def batch_reduce_to(self, reduce_op, value_destination_pairs): - """Combine multiple `reduce_to` calls into one for faster execution. - - Args: - reduce_op: Reduction type, an instance of `tf.distribute.ReduceOp` enum. - DEPRECATED but still accepted values: - `tf.VariableAggregation.SUM`, - `tf.VariableAggregation.MEAN`, - value_destination_pairs: A sequence of (value, destinations) - pairs. See `reduce_to()` for a description. - - Returns: - A list of mirrored values, one per pair in `value_destination_pairs`. - """ - # TODO(josh11b): More docstring - _require_cross_replica_context_extended(self) - - # TODO(priyag): Remove this when all callers have been updated. - if isinstance(reduce_op, variable_scope.VariableAggregation): - assert reduce_op in [ - variable_scope.VariableAggregation.SUM, - variable_scope.VariableAggregation.MEAN, - ] - reduce_op = reduce_util.ReduceOp.from_variable_aggregation(reduce_op) - return self._batch_reduce_to(reduce_op, value_destination_pairs) - - def _batch_reduce_to(self, reduce_op, value_destination_pairs): - return [ - self.reduce_to(reduce_op, t, destinations=v) - for t, v in value_destination_pairs - ] - - def update(self, var, fn, args=(), kwargs=None, group=True): - """Run `fn` to update `var` using inputs mirrored to the same devices. - - If `var` is mirrored across multiple devices, then this implements - logic like: - - ``` - results = {} - for device, v in var: - with tf.device(device): - # args and kwargs will be unwrapped if they are mirrored. - results[device] = fn(v, *args, **kwargs) - return merged(results) - ``` - - Otherwise this returns `fn(var, *args, **kwargs)` colocated with `var`. - - Neither `args` nor `kwargs` may contain per-replica values. - If they contain mirrored values, they will be unwrapped before - calling `fn`. - - Args: - var: Variable, possibly mirrored to multiple devices, to operate on. - fn: Function to call. Should take the variable as the first argument. - args: Tuple or list. Additional positional arguments to pass to `fn()`. - kwargs: Dict with keyword arguments to pass to `fn()`. - group: Boolean. Defaults to True. If False, the return value will be - unwrapped. - - Returns: - By default, the merged return value of `fn` across all replicas. The - merged result has dependencies to make sure that if it is evaluated at - all, the side effects (updates) will happen on every replica. If instead - "group=False" is specified, this function will return a nest of lists - where each list has an element per replica, and the caller is responsible - for ensuring all elements are executed. - """ - _require_cross_replica_context_extended(self) - if kwargs is None: - kwargs = {} - return self._update(var, fn, args, kwargs, group) - - def _update(self, var, fn, args, kwargs, group): - raise NotImplementedError("must be implemented in descendants") - - def update_non_slot( - self, colocate_with, fn, args=(), kwargs=None, group=True): - """Runs `fn(*args, **kwargs)` on `colocate_with` devices. - - Args: - colocate_with: The return value of `non_slot_devices()`. - fn: Function to execute. - args: Tuple or list. Positional arguments to pass to `fn()`. - kwargs: Dict with keyword arguments to pass to `fn()`. - group: Boolean. Defaults to True. If False, the return value will be - unwrapped. - - Returns: - Return value of `fn`, possibly merged across devices. - """ - _require_cross_replica_context_extended(self) - if kwargs is None: - kwargs = {} - return self._update_non_slot(colocate_with, fn, args, kwargs, group) - - def _update_non_slot(self, colocate_with, fn, args, kwargs, group): - raise NotImplementedError("must be implemented in descendants") - - def _unwrap(self, distributed_value): - raise NotImplementedError("must be implemented in descendants") - - def value_container(self, value): - """Returns the container that this per-replica `value` belongs to. - - Args: - value: A value returned by `call_for_each_replica()` or a variable - created in `scope()`. - - Returns: - A container that `value` belongs to. - If value does not belong to any container (including the case of - container having been destroyed), returns the value itself. - `value in unwrap(value_container(value))` will always be true. - """ - raise NotImplementedError("must be implemented in descendants") - - def _group(self, value, name=None): - """Shortcut for `tf.group(distribution.unwrap(value))`.""" - value = nest.flatten(self._unwrap(value)) - - if len(value) != 1 or name is not None: - return control_flow_ops.group(value, name=name) - # Special handling for the common case of one op. - v, = value - if hasattr(v, "op"): - v = v.op - return v - - @property - def experimental_require_static_shapes(self): - return self._require_static_shapes - - @property - def _num_replicas_in_sync(self): - """Returns number of replicas over which gradients are aggregated.""" - raise NotImplementedError("must be implemented in descendants") - - @property - def worker_devices(self): - """Returns the list of devices used to run `call_for_each_replica()` calls. - """ - # TODO(josh11b): More docstring - raise NotImplementedError("must be implemented in descendants") - - @property - def parameter_devices(self): - """Returns the list of devices used for variable and `update` placement.""" - # TODO(josh11b): More docstring - raise NotImplementedError("must be implemented in descendants") - - def non_slot_devices(self, var_list): - """Device(s) for non-slot variables. - - Create variables on these devices in a - `with colocate_vars_with(non_slot_devices(...)):` block. - Update those using `update_non_slot()`. - - Args: - var_list: The list of variables being optimized, needed with the - default `tf.distribute.Strategy`. - """ - raise NotImplementedError("must be implemented in descendants") - - @property - def experimental_between_graph(self): - """Whether the strategy uses between-graph replication or not. - - This is expected to return a constant value that will not be changed - throughout its life cycle. - """ - raise NotImplementedError("must be implemented in descendants") - - def _configure(self, - session_config=None, - cluster_spec=None, - task_type=None, - task_id=None): - """Configures the strategy class.""" - del session_config, cluster_spec, task_type, task_id - - def _update_config_proto(self, config_proto): - return copy.deepcopy(config_proto) - - @property - def experimental_should_init(self): - """Whether initialization is needed.""" - raise NotImplementedError("must be implemented in descendants") - - @property - def should_checkpoint(self): - """Whether checkpointing is needed.""" - raise NotImplementedError("must be implemented in descendants") - - @property - def should_save_summary(self): - """Whether saving summaries is needed.""" - raise NotImplementedError("must be implemented in descendants") - - -# A note about the difference between the context managers -# `ReplicaContext` (defined here) and `_CurrentDistributionContext` -# (defined above) used by `DistributionStrategy.scope()`: -# -# * a ReplicaContext is only present during a `call_for_each_replica()` -# call (except during a `merge_run` call) and in such a scope it -# will be returned by calls to `get_replica_context()`. Implementers of new -# DistributionStrategy descendants will frequently also need to -# define a descendant of ReplicaContext, and are responsible for -# entering and exiting this context. -# -# * DistributionStrategy.scope() sets up a variable_creator scope that -# changes variable creation calls (e.g. to make mirrored -# variables). This is intended as an outer scope that users enter once -# around their model creation and graph definition. There is no -# anticipated need to define descendants of _CurrentDistributionContext. -# It sets the current DistributionStrategy for purposes of -# `get_strategy()` and `has_strategy()` -# and switches the thread mode to a "cross-replica context". -@tf_export("distribute.ReplicaContext") -class ReplicaContext(object): - """`tf.distribute.Strategy` API when in a replica context. - - To be used inside your replicated step function, such as in a - `tf.distribute.StrategyExtended.call_for_each_replica` call. - """ - - def __init__(self, strategy, replica_id_in_sync_group): - self._distribution_strategy = strategy - self._thread_context = distribution_strategy_context._InReplicaThreadMode( # pylint: disable=protected-access - self) - self._replica_id_in_sync_group = replica_id_in_sync_group - - def __enter__(self): - _push_per_thread_mode(self._thread_context) - - def __exit__(self, exception_type, exception_value, traceback): - _pop_per_thread_mode() - - def merge_call(self, merge_fn, args=(), kwargs=None): - """Merge args across replicas and run `merge_fn` in a cross-replica context. - - This allows communication and coordination when there are multiple calls - to a model function triggered by a call to - `strategy.extended.call_for_each_replica(model_fn, ...)`. - - See `tf.distribute.StrategyExtended.call_for_each_replica` for an - explanation. - - If not inside a distributed scope, this is equivalent to: - - ``` - strategy = tf.distribute.get_strategy() - with cross-replica-context(strategy): - return merge_fn(strategy, *args, **kwargs) - ``` - - Args: - merge_fn: function that joins arguments from threads that are given as - PerReplica. It accepts `tf.distribute.Strategy` object as - the first argument. - args: List or tuple with positional per-thread arguments for `merge_fn`. - kwargs: Dict with keyword per-thread arguments for `merge_fn`. - - Returns: - The return value of `merge_fn`, except for `PerReplica` values which are - unpacked. - """ - require_replica_context(self) - if kwargs is None: - kwargs = {} - return self._merge_call(merge_fn, args, kwargs) - - def _merge_call(self, merge_fn, args, kwargs): - """Default implementation for single replica.""" - _push_per_thread_mode( # thread-local, so not needed with multiple threads - distribution_strategy_context._CrossReplicaThreadMode( # pylint: disable=protected-access - self._distribution_strategy)) - try: - return merge_fn(self._distribution_strategy, *args, **kwargs) - finally: - _pop_per_thread_mode() - - @property - def num_replicas_in_sync(self): - """Returns number of replicas over which gradients are aggregated.""" - return self._distribution_strategy.num_replicas_in_sync - - @property - def replica_id_in_sync_group(self): - """Which replica is being defined, from 0 to `num_replicas_in_sync - 1`.""" - require_replica_context(self) - return self._replica_id_in_sync_group - - @property - @doc_controls.do_not_generate_docs # DEPRECATED, use `strategy` - def distribution_strategy(self): - """DEPRECATED: use `self.stratgey` instead.""" - return self._distribution_strategy - - @property - def strategy(self): - """The current `tf.distribute.Strategy` object.""" - return self._distribution_strategy - - @property - def devices(self): - """The devices this replica is to be executed on, as a list of strings.""" - require_replica_context(self) - return [device_util.current()] - - # TODO(josh11b): Implement `start_all_reduce(method, t)` for efficient - # all-reduce. It would return a function returning the result of reducing `t` - # across all replicas. The caller would wait to call this function until they - # needed the reduce result, allowing an efficient implementation: - # * With eager execution, the reduction could be performed asynchronously - # in the background, not blocking until the result was needed. - # * When constructing a graph, it could batch up all reduction requests up - # to that point that the first result is needed. Most likely this can be - # implemented in terms of `merge_call()` and `batch_reduce_to()`. - -# ------------------------------------------------------------------------------ - - -class _DefaultDistributionStrategy(DistributionStrategy): - """Default `tf.distribute.Strategy` if none is explicitly selected.""" - - def __init__(self): - super(_DefaultDistributionStrategy, self).__init__( - _DefaultDistributionExtended(self)) - - -class _DefaultDistributionExtended(DistributionStrategyExtended): - """Implementation of _DefaultDistributionStrategy.""" - - def _scope(self, strategy): - """Context manager setting a variable creator and `self` as current.""" - if distribution_strategy_context.has_distribution_strategy(): - raise RuntimeError("Must not nest tf.distribute.Strategy scopes.") - - def creator(next_creator, *args, **kwargs): - _require_distribution_strategy_scope_strategy(strategy) - return next_creator(*args, **kwargs) - - return _CurrentDistributionContext( - strategy, variable_scope.variable_creator_scope(creator)) - - def colocate_vars_with(self, colocate_with_variable): - """Does not require `self.scope`.""" - _require_distribution_strategy_scope_extended(self) - return ops.colocate_with(colocate_with_variable) - - def _distribute_dataset(self, dataset_fn): - return self._call_dataset_fn(dataset_fn) - - def _make_dataset_iterator(self, dataset): - return _DefaultDistributionExtended.DefaultInputIterator(dataset) - - def _make_input_fn_iterator(self, - input_fn, - replication_mode=InputReplicationMode.PER_WORKER): - return input_fn(InputContext()).make_initializable_iterator() - - def _broadcast_to(self, tensor, destinations): - if destinations is None: - return tensor - else: - raise NotImplementedError("TODO") - - def _call_for_each_replica(self, fn, args, kwargs): - with ReplicaContext( - self._container_strategy(), - replica_id_in_sync_group=constant_op.constant(0, dtypes.int32)): - return fn(*args, **kwargs) - - def _reduce_to(self, reduce_op, value, destinations): - # TODO(josh11b): Use destinations? - del reduce_op, destinations - return value - - def _update(self, var, fn, args, kwargs, group): - # The implementations of _update() and _update_non_slot() are identical - # except _update() passes `var` as the first argument to `fn()`. - return self._update_non_slot(var, fn, (var,) + tuple(args), kwargs, group) - - def _update_non_slot(self, colocate_with, fn, args, kwargs, should_group): - # TODO(josh11b): Figure out what we should be passing to UpdateContext() - # once that value is used for something. - with ops.colocate_with(colocate_with), UpdateContext(colocate_with): - result = fn(*args, **kwargs) - if should_group: - return result - else: - return nest.map_structure(self._unwrap, result) - - def read_var(self, replica_local_var): - return array_ops.identity(replica_local_var) - - def _unwrap(self, distributed_value): - return [distributed_value] - - def value_container(self, value): - return value - - @property - def _num_replicas_in_sync(self): - return 1 - - @property - def worker_devices(self): - raise RuntimeError("worker_devices() method unsupported by default " - "tf.distribute.Strategy.") - - @property - def parameter_devices(self): - raise RuntimeError("parameter_devices() method unsupported by default " - "tf.distribute.Strategy.") - - def non_slot_devices(self, var_list): - return min(var_list, key=lambda x: x.name) - - # TODO(priyag): This should inherit from `InputIterator`, once dependency - # issues have been resolved. - class DefaultInputIterator(object): - """Default implementation of `InputIterator` for default strategy.""" - - def __init__(self, dataset): - self._dataset = dataset - if eager_context.executing_eagerly(): - self._iterator = dataset.make_one_shot_iterator() - else: - self._iterator = dataset.make_initializable_iterator() - - def get_next(self): - return self._iterator.get_next() - - def initialize(self): - if eager_context.executing_eagerly(): - self._iterator = self._dataset.make_one_shot_iterator() - return [] - else: - return [self._iterator.initializer] - - # TODO(priyag): Delete this once all strategies use global batch size. - @property - def _global_batch_size(self): - return True - - -# ------------------------------------------------------------------------------ -# We haven't yet implemented deserialization for DistributedVariables. -# So here we catch any attempts to deserialize variables -# when using distribution strategies. -# pylint: disable=protected-access -_original_from_proto = resource_variable_ops._from_proto_fn - - -def _from_proto_fn(v, import_scope=None): - if distribution_strategy_context.has_distribution_strategy(): - raise NotImplementedError( - "Deserialization of variables is not yet supported when using a " - "tf.distribute.Strategy.") - else: - return _original_from_proto(v, import_scope=import_scope) - -resource_variable_ops._from_proto_fn = _from_proto_fn -# pylint: enable=protected-access - - -#------------------------------------------------------------------------------- -# Shorthand for some methods from distribution_strategy_context. -_push_per_thread_mode = distribution_strategy_context._push_per_thread_mode # pylint: disable=protected-access -_get_per_thread_mode = distribution_strategy_context._get_per_thread_mode # pylint: disable=protected-access -_pop_per_thread_mode = distribution_strategy_context._pop_per_thread_mode # pylint: disable=protected-access +# pylint: disable=wildcard-import +from tensorflow.python.distribute.distribute_lib import * diff --git a/tensorflow/python/training/distribution_strategy_context.py b/tensorflow/python/training/distribution_strategy_context.py index 0b3878de18..7391bf3b22 100644 --- a/tensorflow/python/training/distribution_strategy_context.py +++ b/tensorflow/python/training/distribution_strategy_context.py @@ -12,225 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Utility to get distribution strategy related contexts.""" +"""Deprecated, please use ../distribute/distribution_strategy_context.py.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.python.framework import ops -from tensorflow.python.util.lazy_loader import LazyLoader -from tensorflow.python.util.tf_export import tf_export - - -# There is a circular dependency between this and `distribute` module. So we -# load it lazily to workaround this. -distribute_lib = LazyLoader( - "distribute_lib", globals(), - "tensorflow.python.training.distribute") - -# ------------------------------------------------------------------------------ -# Internal API for setting the current thread mode as being either in a -# replica or cross-replica context for a particular distribution strategy. - - -class _ThreadMode(object): - - def __init__(self, dist, cross, replica): - self.distribution_strategy = dist - self.cross_replica_context = cross - self.replica_context = replica - - -class _CrossReplicaThreadMode(_ThreadMode): - - def __init__(self, distribution_strategy): - _ThreadMode.__init__( - self, distribution_strategy, distribution_strategy, None) - - -class _InReplicaThreadMode(_ThreadMode): - - def __init__(self, replica_ctx): - _ThreadMode.__init__( - self, replica_ctx.distribution_strategy, None, replica_ctx) - - -def _push_per_thread_mode(context): - ops.get_default_graph()._distribution_strategy_stack.append(context) # pylint: disable=protected-access - - -def _pop_per_thread_mode(): - ops.get_default_graph()._distribution_strategy_stack.pop(-1) # pylint: disable=protected-access - - -class _DefaultReplicaThreadMode(_ThreadMode): - """Type of default value returned by `_get_per_thread_mode()`. - - Used when the thread-local stack is empty. - """ - - def __init__(self): - _ThreadMode.__init__(self, _get_default_distribution_strategy(), None, - _get_default_replica_context()) - - -def _get_per_thread_mode(): - try: - return ops.get_default_graph()._distribution_strategy_stack[-1] # pylint: disable=protected-access - except (AttributeError, IndexError): - return _get_default_replica_mode() - - -# ------------------------------------------------------------------------------ -# Public API for accessing the current thread mode - - -@tf_export("distribute.get_replica_context") -def get_replica_context(): - """Returns the current `tf.distribute.ReplicaContext` or `None`. - - Returns `None` if in a cross-replica context. - - Note that execution: - - 1. starts in the default (single-replica) replica context (this function - will return the default `ReplicaContext` object); - 2. switches to cross-replica context (in which case this will return - `None`) when entering a `with tf.distribute.Strategy.scope():` block; - 3. switches to a (non-default) replica context inside - `extended.call_for_each_replica(fn, ...)`; - 4. if `fn` calls `get_replica_context().merge_call(merge_fn, ...)`, then - inside `merge_fn` you are back in the cross-replica context (and again - this function will return `None`). - - Note that you can also go directly from step 1 to 4 to switch to a - cross-replica context for the default `tf.distribute.Strategy`. You may - also switch from the cross-replica context of 4 to a replica context by - calling `extended.call_for_each_replica()`, jumping back to step 3. - - Most `tf.distribute.Strategy` methods may only be executed in - a cross-replica context, in a replica context you should use the - `ReplicaContext` API instead. - - Returns: - The current `ReplicaContext` object when in a replica context scope, - else `None`. - - Within a particular block, exactly one of these two things will be true: - - * `get_replica_context()` returns non-`None`, or - * `tf.distribute.is_cross_replica_context()` returns True. - """ - return _get_per_thread_mode().replica_context - - -def get_cross_replica_context(): - """Returns the current tf.distribute.Strategy if in a cross-replica context. - - DEPRECATED: Please use `in_cross_replica_context()` and - `get_distribution_strategy()` instead. - - Note that execution: - - 1. starts in the default (single-replica) replica context; - 2. switches to cross-replica context when entering a - `with tf.distribute.Strategy.scope():` block; - 3. switches to a (non-default) replica context inside - `call_for_each_replica(fn, ...)`; - 4. if `fn` calls `get_replica_context()->merge_call(merge_fn, ...)`, then - inside `merge_fn` you are back in the cross-replica context. - - Note that you can also go directly from step 1 to 4 to switch to a - cross-replica context for the default `tf.distribute.Strategy`. You may - also switch from the cross-replica context of 4 to a replica context by - calling `call_for_each_replica()`, jumping back to step 3. - - Most `tf.distribute.Strategy` methods may only be executed in - a cross-replica context. - - Returns: - Returns the current `tf.distribute.Strategy` object in a cross-replica - context, or `None`. - - Exactly one of `get_replica_context()` and `get_cross_replica_context()` - will return `None` in a particular block. - """ - return _get_per_thread_mode().cross_replica_context - - -@tf_export("distribute.in_cross_replica_context") -def in_cross_replica_context(): - """Returns True if in a cross-replica context. - - See `tf.distribute.get_replica_context` for details. - - Returns: - True if in a cross-replica context (`get_replica_context()` returns - `None`), or False if in a replica context (`get_replica_context()` returns - non-`None`). - """ - return _get_per_thread_mode().cross_replica_context is not None - - -@tf_export("distribute.get_strategy") -def get_distribution_strategy(): - """Returns the current `tf.distribute.Strategy` object. - - Typically only used in a cross-replica context: - - ``` - if tf.distribute.in_cross_replica_context(): - strategy = tf.distribute.get_strategy() - ... - ``` - - Returns: - A `tf.distribute.Strategy` object. Inside a - `with distribution_strategy.scope()` block, it returns - `distribution_strategy`, otherwise it returns the default - (single-replica) `tf.distribute.Strategy` object. - """ - return _get_per_thread_mode().distribution_strategy - - -@tf_export("distribute.has_strategy") -def has_distribution_strategy(): - """Return if there is a current non-default `tf.distribute.Strategy`. - - Returns: - True if inside a `with strategy.scope():`. - """ - return get_distribution_strategy() is not _get_default_distribution_strategy() - - -# ------------------------------------------------------------------------------ -# Defaults that are used when no distribution strategy is explicitly created. -# We create them lazily in a function so that we can workaround the circular -# dependency on distribute_lib. See lazy loader at the top of this file. - -_defaults = { - "distribution_strategy": None, - "replica_context": None, - "replica_mode": None -} - - -def _get_default_distribution_strategy(): - if _defaults["distribution_strategy"] is None: - _defaults["distribution_strategy"] = ( - distribute_lib._DefaultDistributionStrategy()) # pylint: disable=protected-access - return _defaults["distribution_strategy"] - - -def _get_default_replica_context(): - if _defaults["replica_context"] is None: - _defaults["replica_context"] = distribute_lib.ReplicaContext( - _get_default_distribution_strategy(), replica_id_in_sync_group=0) - return _defaults["replica_context"] - - -def _get_default_replica_mode(): - if _defaults["replica_mode"] is None: - _defaults["replica_mode"] = _DefaultReplicaThreadMode() - return _defaults["replica_mode"] +# pylint: disable=wildcard-import +from tensorflow.python.distribute.distribution_strategy_context import * diff --git a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-input-context.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-input-context.pbtxt index c39ac5a20d..583cbc6654 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-input-context.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-input-context.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.InputContext" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "input_pipeline_id" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-replica-context.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-replica-context.pbtxt index 3eda6c6036..df707e8920 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-replica-context.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-replica-context.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.ReplicaContext" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "devices" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy-extended.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy-extended.pbtxt index 3b502b534b..77706e5713 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy-extended.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy-extended.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.StrategyExtended" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "experimental_between_graph" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt index f0b0cd0d38..0fd9a3b42d 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.Strategy" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "between_graph" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-input-context.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-input-context.pbtxt index c39ac5a20d..583cbc6654 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-input-context.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-input-context.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.InputContext" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "input_pipeline_id" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-replica-context.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-replica-context.pbtxt index 3eda6c6036..df707e8920 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-replica-context.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-replica-context.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.ReplicaContext" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "devices" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy-extended.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy-extended.pbtxt index 3b502b534b..77706e5713 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy-extended.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy-extended.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.StrategyExtended" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "experimental_between_graph" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt index f0b0cd0d38..0fd9a3b42d 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.distribute.Strategy" tf_class { - is_instance: "" + is_instance: "" is_instance: "" member { name: "between_graph" -- GitLab From 335a643d687026335c84fb83b2c0f8dd91fd2b19 Mon Sep 17 00:00:00 2001 From: Roy Frostig Date: Sun, 25 Nov 2018 18:53:48 -0800 Subject: [PATCH 287/672] [XLA] Expose the shape of XRT allocations in the Python XLA library. Also, pass in UTF-8 strings in XRT methods for py3 compatibility. PiperOrigin-RevId: 222763810 --- .../xla/python/local_computation_builder.i | 1 + tensorflow/compiler/xla/python/xla_client.py | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/tensorflow/compiler/xla/python/local_computation_builder.i b/tensorflow/compiler/xla/python/local_computation_builder.i index feabfdb889..03698d9ce8 100644 --- a/tensorflow/compiler/xla/python/local_computation_builder.i +++ b/tensorflow/compiler/xla/python/local_computation_builder.i @@ -992,6 +992,7 @@ tensorflow::ImportNumpy(); %unignore xla::swig::XrtAllocation; %unignore xla::swig::XrtAllocation::FromLiteral; %unignore xla::swig::XrtAllocation::ToLiteral; +%unignore xla::swig::XrtAllocation::shape; %unignore xla::swig::XrtAllocationTuple; %unignore xla::swig::XrtAllocationTuple::Release; %unignore xla::swig::XrtAllocationTuple::size; diff --git a/tensorflow/compiler/xla/python/xla_client.py b/tensorflow/compiler/xla/python/xla_client.py index 995d2b64dc..5994e55387 100644 --- a/tensorflow/compiler/xla/python/xla_client.py +++ b/tensorflow/compiler/xla/python/xla_client.py @@ -78,6 +78,13 @@ def CurrentSourceInfoMetadata(op_type=None, op_name=None, skip_frames=1): source_line=lineno) +def _maybe_encode_string(s): + if six.PY3: + return s.encode('utf-8') + else: + return s + + class PaddingType(enum.Enum): VALID = 1 SAME = 2 @@ -228,7 +235,8 @@ class LocalBuffer(object): """Allocate and copy to XLA the given python value.""" pyval = require_numpy_array_layout(pyval) if backend.backend_type == BackendType.XRT: - cbuf = c_api.XrtAllocation.FromLiteral(pyval, backend.target) + cbuf = c_api.XrtAllocation.FromLiteral( + pyval, _maybe_encode_string(backend.target)) else: cbuf = c_api.LocalShapedBuffer.FromLiteral(pyval, None) return LocalBuffer(cbuf, backend) @@ -248,8 +256,8 @@ class LocalBuffer(object): """Assuming a tuple buffer, unpack it into constituent tuple elements.""" assert self.c_buffer is not None if self._backend.backend_type == BackendType.XRT: - result = c_api.DestructureXrtAllocationTuple(self.c_buffer, - self._backend.target) + result = c_api.DestructureXrtAllocationTuple( + self.c_buffer, _maybe_encode_string(self._backend.target)) else: result = c_api.DestructureLocalShapedBufferTuple(self.c_buffer) self.delete() @@ -552,7 +560,8 @@ class LocalComputation(object): compile_options = compile_options or CompileOptions() compile_options.result_shape = result_shape if self._backend.backend_type == BackendType.XRT: - c = self.computation.CompileForXrt(argument_shapes, self._backend.target) + c = self.computation.CompileForXrt( + argument_shapes, _maybe_encode_string(self._backend.target)) else: c = self.computation.Compile(argument_shapes, compile_options) return LocalComputation(c, is_compiled=True, backend=self._backend) @@ -1388,8 +1397,7 @@ def initialize_platform_name(platform_name): Raises: A runtime exception if the XLA service has already been initialized. """ - if six.PY3: - platform_name = platform_name.encode('utf-8') + platform_name = _maybe_encode_string(platform_name) c_api.InitializePlatformName(platform_name) -- GitLab From 6f9082773ea05e2be8f86ee97ada70889777b44a Mon Sep 17 00:00:00 2001 From: Yuefeng Zhou Date: Sun, 25 Nov 2018 19:08:36 -0800 Subject: [PATCH 288/672] Fix parameter server strategy return None config. PiperOrigin-RevId: 222764694 --- .../contrib/distribute/python/collective_all_reduce_strategy.py | 2 +- .../contrib/distribute/python/parameter_server_strategy.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py index 74a0550e81..617a95f3c4 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy.py @@ -283,7 +283,7 @@ class CollectiveAllReduceExtended(mirrored_strategy.MirroredExtended): rewrite_options.scoped_allocator_opts.enable_op.append("CollectiveReduce") if not self._cluster_spec: - return + return updated_config assert self._task_type assert self._task_id is not None diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy.py b/tensorflow/contrib/distribute/python/parameter_server_strategy.py index 5615abb751..8c33d3a143 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy.py @@ -480,7 +480,7 @@ class ParameterServerExtended(distribute_lib.DistributionStrategyExtended): # The device filters prevent communication between workers. if self._task_type not in ["chief", "worker"]: - return + return updated_config del updated_config.device_filters[:] updated_config.device_filters.extend( ["/job:%s/task:%d" % (self._task_type, self._task_id), "/job:ps"]) -- GitLab From f6b80d5cd39d5764174a8e05f3b4f73d1ea70827 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 01:02:23 -0800 Subject: [PATCH 289/672] compat: Update forward compatibility horizon to 2018-11-26 PiperOrigin-RevId: 222785233 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 216ab2c0ac..4e84b5ee48 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 25) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 26) @tf_export("compat.forward_compatible") -- GitLab From 38e94b3ee00738a2ad75663f6ad162e97abcdfcf Mon Sep 17 00:00:00 2001 From: manhyuk Date: Mon, 26 Nov 2018 18:45:15 +0900 Subject: [PATCH 290/672] fix typo --- tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc index 566701ec2a..e676323bf4 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc @@ -2409,7 +2409,7 @@ class ConvertPowStage : public ArithmeticOptimizerStage { ctx().graph_properties->GetInputProperties(node->name())[1]; for (int i = 0; i < pow_props.shape().dim_size(); ++i) { if (pow_props.shape().dim(i).size() < 0) { - // skip if p is is not fully defined. + // skip if p is not fully defined. return Status::OK(); } } @@ -2461,7 +2461,7 @@ class ConvertPowStage : public ArithmeticOptimizerStage { ShapesSymbolicallyEqual(value_props.shape(), output_shape)) { for (int i = 0; i < value_props.shape().dim_size(); ++i) { if (value_props.shape().dim(i).size() < 0) { - // skip if b is is not fully defined. + // skip if b is not fully defined. return Status::OK(); } } -- GitLab From a055605ec5ac5cafdbae66aae5c96d0cedd0e55c Mon Sep 17 00:00:00 2001 From: manhyuk Date: Mon, 26 Nov 2018 18:46:01 +0900 Subject: [PATCH 291/672] fix typo --- tensorflow/compiler/xla/service/gpu/instruction_fusion.cc | 2 +- tensorflow/core/grappler/graph_analyzer/sig_node.h | 2 +- tensorflow/lite/python/op_hint.py | 2 +- tensorflow/lite/toco/import_tensorflow.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc b/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc index 43f43b50e4..985c0d411e 100644 --- a/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc +++ b/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc @@ -80,7 +80,7 @@ bool IsIEEEFloatingPointScalarConstant(const HloInstruction* constant) { // This function limits the maximum number of operands to a fusion. // // There's a cap on how many parameters we can pass to a CUDA kernel, but -// exactly what that limit is is hazy, as it depends on (among other things) how +// exactly what that limit is hazy, as it depends on (among other things) how // much GPU constant memory is in use for other purposes. // // Moreover, we don't even know at the point that we're running fusion how many diff --git a/tensorflow/core/grappler/graph_analyzer/sig_node.h b/tensorflow/core/grappler/graph_analyzer/sig_node.h index 45c0ed3162..66d290d88e 100644 --- a/tensorflow/core/grappler/graph_analyzer/sig_node.h +++ b/tensorflow/core/grappler/graph_analyzer/sig_node.h @@ -178,7 +178,7 @@ class SigNode { // computed. size_t GetTopoHash(int distance) const; - // The the hash value for the highest computed distance. It must be previously + // The hash value for the highest computed distance. It must be previously // computed. size_t GetHighTopoHash() const { CHECK(!topo_hash_.empty()); diff --git a/tensorflow/lite/python/op_hint.py b/tensorflow/lite/python/op_hint.py index 3afce1baf2..718b23075d 100644 --- a/tensorflow/lite/python/op_hint.py +++ b/tensorflow/lite/python/op_hint.py @@ -403,7 +403,7 @@ class _LiteOperand(object): out_graphdef: A graphdef that is ready to have this input added. Returns: - The the output that the stub should use as an input for this operand. + The output that the stub should use as an input for this operand. Raises: RuntimeError: if the method is not implemented. diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index 4c3a0717e7..c8d1e1bdc5 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -1221,7 +1221,7 @@ void GetOutputNamesFromNodeDef(const NodeDef& node, void GetOutputTypesFromNodeDef(const NodeDef& node, const tensorflow::OpDef& op_def, TensorFlowUnsupportedOperator* op) { - // The the given type to the op, or clear the types if invalid. + // The given type to the op, or clear the types if invalid. auto add_type = [&node, op](tensorflow::DataType type) { if (type == tensorflow::DT_INVALID) { LOG(WARNING) << "Op node missing output type attribute: " << node.name(); -- GitLab From a382d3e89188d9d8dc18ceccf842d1492bed0d1a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 06:51:35 -0800 Subject: [PATCH 292/672] Add cuda 10 config and update to latest cuda 10 docker image. PiperOrigin-RevId: 222817562 --- .../preconfig/generate/containers.bzl | 2 +- .../ubuntu14.04/cuda10.0-cudnn7/WORKSPACE | 2 + .../ubuntu14.04/cuda10.0-cudnn7/cuda/BUILD | 1275 +++++++++++++++ .../cuda10.0-cudnn7/cuda/build_defs.bzl | 31 + .../cuda10.0-cudnn7/cuda/cuda/cuda_config.h | 26 + .../ubuntu14.04/gcc-nvcc-cuda10.0/BUILD | 87 + .../ubuntu14.04/gcc-nvcc-cuda10.0/CROSSTOOL | 1431 +++++++++++++++++ .../bin/crosstool_wrapper_driver_is_not_gcc | 264 +++ .../windows/msvc_wrapper_for_nvcc.bat | 20 + .../windows/msvc_wrapper_for_nvcc.py | 192 +++ 10 files changed, 3329 insertions(+), 1 deletion(-) create mode 100644 third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/WORKSPACE create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/BUILD create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/build_defs.bzl create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/cuda/cuda_config.h create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/BUILD create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/CROSSTOOL create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/clang/bin/crosstool_wrapper_driver_is_not_gcc create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.bat create mode 100755 third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.py diff --git a/third_party/toolchains/preconfig/generate/containers.bzl b/third_party/toolchains/preconfig/generate/containers.bzl index 1f9e29d440..0309b8ffca 100644 --- a/third_party/toolchains/preconfig/generate/containers.bzl +++ b/third_party/toolchains/preconfig/generate/containers.bzl @@ -1,4 +1,4 @@ container_digests = { "cuda9.0-cudnn7-ubuntu14.04": "sha256:c26138f4c38c754da2bad44a8a068523abf7fbd71d58a57ce92e5342c5431bf5", - "cuda10.0-cudnn7-ubuntu14.04": "sha256:34c4a55e2376b300cdc2b903775fc32e62352f6e33f927df5653743324378bfc", + "cuda10.0-cudnn7-ubuntu14.04": "sha256:7737d770599de8435115bfdf56977002319316a6735ab081f82506cb51443f9d", } diff --git a/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/WORKSPACE b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/WORKSPACE new file mode 100644 index 0000000000..b61f572d6d --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/WORKSPACE @@ -0,0 +1,2 @@ +# DO NOT EDIT: automatically generated WORKSPACE file for cuda_configure rule +workspace(name = "local_config_cuda") diff --git a/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/BUILD b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/BUILD new file mode 100755 index 0000000000..c813efccf9 --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/BUILD @@ -0,0 +1,1275 @@ +licenses(["restricted"]) # MPL2, portions GPL v3, LGPL v3, BSD-like + +package(default_visibility = ["//visibility:public"]) + +config_setting( + name = "using_nvcc", + values = { + "define": "using_cuda_nvcc=true", + }, +) + +config_setting( + name = "using_clang", + values = { + "define": "using_cuda_clang=true", + }, +) + +# Equivalent to using_clang && -c opt. +config_setting( + name = "using_clang_opt", + values = { + "define": "using_cuda_clang=true", + "compilation_mode": "opt", + }, +) + +config_setting( + name = "darwin", + values = {"cpu": "darwin"}, + visibility = ["//visibility:public"], +) + +config_setting( + name = "freebsd", + values = {"cpu": "freebsd"}, + visibility = ["//visibility:public"], +) + +cc_library( + name = "cuda_headers", + hdrs = [ + "cuda/cuda_config.h", + ":cuda-include", + ":cudnn-include", + ], + includes = [ + ".", + "cuda/include", + "cuda/include/crt", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "cudart_static", + srcs = ["cuda/lib/libcudart_static.a"], + includes = [ + ".", + "cuda/include", + ], + linkopts = select({ + ":freebsd": [], + "//conditions:default": ["-ldl"], + }) + [ + "-lpthread", + "-lrt", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "cuda_driver", + srcs = ["cuda/lib/libcuda.so"], + includes = [ + ".", + "cuda/include", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "cudart", + srcs = ["cuda/lib/libcudart.so.10.0"], + data = ["cuda/lib/libcudart.so.10.0"], + includes = [ + ".", + "cuda/include", + ], + linkstatic = 1, + visibility = ["//visibility:public"], +) + +cc_library( + name = "cublas", + srcs = ["cuda/lib/libcublas.so.10.0"], + data = ["cuda/lib/libcublas.so.10.0"], + includes = [ + ".", + "cuda/include", + ], + linkstatic = 1, + visibility = ["//visibility:public"], +) + +cc_library( + name = "cusolver", + srcs = ["cuda/lib/libcusolver.so.10.0"], + data = ["cuda/lib/libcusolver.so.10.0"], + includes = [ + ".", + "cuda/include", + ], + linkopts = ["-lgomp"], + linkstatic = 1, + visibility = ["//visibility:public"], +) + +cc_library( + name = "cudnn", + srcs = ["cuda/lib/libcudnn.so.7"], + data = ["cuda/lib/libcudnn.so.7"], + includes = [ + ".", + "cuda/include", + ], + linkstatic = 1, + visibility = ["//visibility:public"], +) + +cc_library( + name = "cudnn_header", + includes = [ + ".", + "cuda/include", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "cufft", + srcs = ["cuda/lib/libcufft.so.10.0"], + data = ["cuda/lib/libcufft.so.10.0"], + includes = [ + ".", + "cuda/include", + ], + linkstatic = 1, + visibility = ["//visibility:public"], +) + +cc_library( + name = "curand", + srcs = ["cuda/lib/libcurand.so.10.0"], + data = ["cuda/lib/libcurand.so.10.0"], + includes = [ + ".", + "cuda/include", + ], + linkstatic = 1, + visibility = ["//visibility:public"], +) + +cc_library( + name = "cuda", + visibility = ["//visibility:public"], + deps = [ + ":cublas", + ":cuda_headers", + ":cudart", + ":cudnn", + ":cufft", + ":curand", + ], +) + +cc_library( + name = "cupti_headers", + hdrs = [ + "cuda/cuda_config.h", + ":cuda-extras", + ], + includes = [ + ".", + "cuda/extras/CUPTI/include/", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "cupti_dsos", + data = ["cuda/lib/libcupti.so.10.0"], + includes = [ + ".", + "cuda/include", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "libdevice_root", + data = [":cuda-nvvm"], + visibility = ["//visibility:public"], +) + +genrule( + name = "cuda-include", + outs = [ + "cuda/include/CL/cl.h", + "cuda/include/CL/cl.hpp", + "cuda/include/CL/cl_egl.h", + "cuda/include/CL/cl_ext.h", + "cuda/include/CL/cl_gl.h", + "cuda/include/CL/cl_gl_ext.h", + "cuda/include/CL/cl_platform.h", + "cuda/include/CL/opencl.h", + "cuda/include/builtin_types.h", + "cuda/include/channel_descriptor.h", + "cuda/include/common_functions.h", + "cuda/include/cooperative_groups.h", + "cuda/include/cooperative_groups_helpers.h", + "cuda/include/crt/common_functions.h", + "cuda/include/crt/device_double_functions.h", + "cuda/include/crt/device_double_functions.hpp", + "cuda/include/crt/device_functions.h", + "cuda/include/crt/device_functions.hpp", + "cuda/include/crt/func_macro.h", + "cuda/include/crt/host_config.h", + "cuda/include/crt/host_defines.h", + "cuda/include/crt/host_runtime.h", + "cuda/include/crt/math_functions.h", + "cuda/include/crt/math_functions.hpp", + "cuda/include/crt/mma.h", + "cuda/include/crt/mma.hpp", + "cuda/include/crt/nvfunctional", + "cuda/include/crt/sm_70_rt.h", + "cuda/include/crt/sm_70_rt.hpp", + "cuda/include/crt/storage_class.h", + "cuda/include/cuComplex.h", + "cuda/include/cublas.h", + "cuda/include/cublasXt.h", + "cuda/include/cublas_api.h", + "cuda/include/cublas_v2.h", + "cuda/include/cuda.h", + "cuda/include/cudaEGL.h", + "cuda/include/cudaGL.h", + "cuda/include/cudaProfiler.h", + "cuda/include/cudaVDPAU.h", + "cuda/include/cuda_device_runtime_api.h", + "cuda/include/cuda_egl_interop.h", + "cuda/include/cuda_fp16.h", + "cuda/include/cuda_fp16.hpp", + "cuda/include/cuda_gl_interop.h", + "cuda/include/cuda_occupancy.h", + "cuda/include/cuda_profiler_api.h", + "cuda/include/cuda_runtime.h", + "cuda/include/cuda_runtime_api.h", + "cuda/include/cuda_surface_types.h", + "cuda/include/cuda_texture_types.h", + "cuda/include/cuda_vdpau_interop.h", + "cuda/include/cudalibxt.h", + "cuda/include/cudart_platform.h", + "cuda/include/cufft.h", + "cuda/include/cufftXt.h", + "cuda/include/cufftw.h", + "cuda/include/curand.h", + "cuda/include/curand_discrete.h", + "cuda/include/curand_discrete2.h", + "cuda/include/curand_globals.h", + "cuda/include/curand_kernel.h", + "cuda/include/curand_lognormal.h", + "cuda/include/curand_mrg32k3a.h", + "cuda/include/curand_mtgp32.h", + "cuda/include/curand_mtgp32_host.h", + "cuda/include/curand_mtgp32_kernel.h", + "cuda/include/curand_mtgp32dc_p_11213.h", + "cuda/include/curand_normal.h", + "cuda/include/curand_normal_static.h", + "cuda/include/curand_philox4x32_x.h", + "cuda/include/curand_poisson.h", + "cuda/include/curand_precalc.h", + "cuda/include/curand_uniform.h", + "cuda/include/cusolverDn.h", + "cuda/include/cusolverRf.h", + "cuda/include/cusolverSp.h", + "cuda/include/cusolverSp_LOWLEVEL_PREVIEW.h", + "cuda/include/cusolver_common.h", + "cuda/include/cusparse.h", + "cuda/include/cusparse_v2.h", + "cuda/include/device_atomic_functions.h", + "cuda/include/device_atomic_functions.hpp", + "cuda/include/device_double_functions.h", + "cuda/include/device_functions.h", + "cuda/include/device_launch_parameters.h", + "cuda/include/device_types.h", + "cuda/include/driver_functions.h", + "cuda/include/driver_types.h", + "cuda/include/fatBinaryCtl.h", + "cuda/include/fatbinary.h", + "cuda/include/host_config.h", + "cuda/include/host_defines.h", + "cuda/include/library_types.h", + "cuda/include/math_constants.h", + "cuda/include/math_functions.h", + "cuda/include/mma.h", + "cuda/include/npp.h", + "cuda/include/nppcore.h", + "cuda/include/nppdefs.h", + "cuda/include/nppi.h", + "cuda/include/nppi_arithmetic_and_logical_operations.h", + "cuda/include/nppi_color_conversion.h", + "cuda/include/nppi_compression_functions.h", + "cuda/include/nppi_computer_vision.h", + "cuda/include/nppi_data_exchange_and_initialization.h", + "cuda/include/nppi_filtering_functions.h", + "cuda/include/nppi_geometry_transforms.h", + "cuda/include/nppi_linear_transforms.h", + "cuda/include/nppi_morphological_operations.h", + "cuda/include/nppi_statistics_functions.h", + "cuda/include/nppi_support_functions.h", + "cuda/include/nppi_threshold_and_compare_operations.h", + "cuda/include/npps.h", + "cuda/include/npps_arithmetic_and_logical_operations.h", + "cuda/include/npps_conversion_functions.h", + "cuda/include/npps_filtering_functions.h", + "cuda/include/npps_initialization.h", + "cuda/include/npps_statistics_functions.h", + "cuda/include/npps_support_functions.h", + "cuda/include/nppversion.h", + "cuda/include/nvToolsExt.h", + "cuda/include/nvToolsExtCuda.h", + "cuda/include/nvToolsExtCudaRt.h", + "cuda/include/nvToolsExtMeta.h", + "cuda/include/nvToolsExtSync.h", + "cuda/include/nvblas.h", + "cuda/include/nvfunctional", + "cuda/include/nvgraph.h", + "cuda/include/nvjpeg.h", + "cuda/include/nvml.h", + "cuda/include/nvrtc.h", + "cuda/include/nvtx3/nvToolsExt.h", + "cuda/include/nvtx3/nvToolsExtCuda.h", + "cuda/include/nvtx3/nvToolsExtCudaRt.h", + "cuda/include/nvtx3/nvToolsExtOpenCL.h", + "cuda/include/nvtx3/nvToolsExtSync.h", + "cuda/include/nvtx3/nvtxDetail/nvtxImpl.h", + "cuda/include/nvtx3/nvtxDetail/nvtxImplCore.h", + "cuda/include/nvtx3/nvtxDetail/nvtxImplCudaRt_v3.h", + "cuda/include/nvtx3/nvtxDetail/nvtxImplCuda_v3.h", + "cuda/include/nvtx3/nvtxDetail/nvtxImplOpenCL_v3.h", + "cuda/include/nvtx3/nvtxDetail/nvtxImplSync_v3.h", + "cuda/include/nvtx3/nvtxDetail/nvtxInit.h", + "cuda/include/nvtx3/nvtxDetail/nvtxInitDecls.h", + "cuda/include/nvtx3/nvtxDetail/nvtxInitDefs.h", + "cuda/include/nvtx3/nvtxDetail/nvtxLinkOnce.h", + "cuda/include/nvtx3/nvtxDetail/nvtxTypes.h", + "cuda/include/sm_20_atomic_functions.h", + "cuda/include/sm_20_atomic_functions.hpp", + "cuda/include/sm_20_intrinsics.h", + "cuda/include/sm_20_intrinsics.hpp", + "cuda/include/sm_30_intrinsics.h", + "cuda/include/sm_30_intrinsics.hpp", + "cuda/include/sm_32_atomic_functions.h", + "cuda/include/sm_32_atomic_functions.hpp", + "cuda/include/sm_32_intrinsics.h", + "cuda/include/sm_32_intrinsics.hpp", + "cuda/include/sm_35_atomic_functions.h", + "cuda/include/sm_35_intrinsics.h", + "cuda/include/sm_60_atomic_functions.h", + "cuda/include/sm_60_atomic_functions.hpp", + "cuda/include/sm_61_intrinsics.h", + "cuda/include/sm_61_intrinsics.hpp", + "cuda/include/sobol_direction_vectors.h", + "cuda/include/surface_functions.h", + "cuda/include/surface_functions.hpp", + "cuda/include/surface_indirect_functions.h", + "cuda/include/surface_indirect_functions.hpp", + "cuda/include/surface_types.h", + "cuda/include/texture_fetch_functions.h", + "cuda/include/texture_fetch_functions.hpp", + "cuda/include/texture_indirect_functions.h", + "cuda/include/texture_indirect_functions.hpp", + "cuda/include/texture_types.h", + "cuda/include/thrust/adjacent_difference.h", + "cuda/include/thrust/advance.h", + "cuda/include/thrust/binary_search.h", + "cuda/include/thrust/complex.h", + "cuda/include/thrust/copy.h", + "cuda/include/thrust/count.h", + "cuda/include/thrust/detail/adjacent_difference.inl", + "cuda/include/thrust/detail/advance.inl", + "cuda/include/thrust/detail/alignment.h", + "cuda/include/thrust/detail/allocator/allocator_traits.h", + "cuda/include/thrust/detail/allocator/allocator_traits.inl", + "cuda/include/thrust/detail/allocator/copy_construct_range.h", + "cuda/include/thrust/detail/allocator/copy_construct_range.inl", + "cuda/include/thrust/detail/allocator/default_construct_range.h", + "cuda/include/thrust/detail/allocator/default_construct_range.inl", + "cuda/include/thrust/detail/allocator/destroy_range.h", + "cuda/include/thrust/detail/allocator/destroy_range.inl", + "cuda/include/thrust/detail/allocator/fill_construct_range.h", + "cuda/include/thrust/detail/allocator/fill_construct_range.inl", + "cuda/include/thrust/detail/allocator/malloc_allocator.h", + "cuda/include/thrust/detail/allocator/malloc_allocator.inl", + "cuda/include/thrust/detail/allocator/no_throw_allocator.h", + "cuda/include/thrust/detail/allocator/tagged_allocator.h", + "cuda/include/thrust/detail/allocator/tagged_allocator.inl", + "cuda/include/thrust/detail/allocator/temporary_allocator.h", + "cuda/include/thrust/detail/allocator/temporary_allocator.inl", + "cuda/include/thrust/detail/binary_search.inl", + "cuda/include/thrust/detail/complex/arithmetic.h", + "cuda/include/thrust/detail/complex/c99math.h", + "cuda/include/thrust/detail/complex/catrig.h", + "cuda/include/thrust/detail/complex/catrigf.h", + "cuda/include/thrust/detail/complex/ccosh.h", + "cuda/include/thrust/detail/complex/ccoshf.h", + "cuda/include/thrust/detail/complex/cexp.h", + "cuda/include/thrust/detail/complex/cexpf.h", + "cuda/include/thrust/detail/complex/clog.h", + "cuda/include/thrust/detail/complex/clogf.h", + "cuda/include/thrust/detail/complex/complex.inl", + "cuda/include/thrust/detail/complex/cpow.h", + "cuda/include/thrust/detail/complex/cproj.h", + "cuda/include/thrust/detail/complex/csinh.h", + "cuda/include/thrust/detail/complex/csinhf.h", + "cuda/include/thrust/detail/complex/csqrt.h", + "cuda/include/thrust/detail/complex/csqrtf.h", + "cuda/include/thrust/detail/complex/ctanh.h", + "cuda/include/thrust/detail/complex/ctanhf.h", + "cuda/include/thrust/detail/complex/math_private.h", + "cuda/include/thrust/detail/complex/stream.h", + "cuda/include/thrust/detail/config.h", + "cuda/include/thrust/detail/config/compiler.h", + "cuda/include/thrust/detail/config/compiler_fence.h", + "cuda/include/thrust/detail/config/config.h", + "cuda/include/thrust/detail/config/debug.h", + "cuda/include/thrust/detail/config/device_system.h", + "cuda/include/thrust/detail/config/exec_check_disable.h", + "cuda/include/thrust/detail/config/forceinline.h", + "cuda/include/thrust/detail/config/global_workarounds.h", + "cuda/include/thrust/detail/config/host_device.h", + "cuda/include/thrust/detail/config/host_system.h", + "cuda/include/thrust/detail/config/simple_defines.h", + "cuda/include/thrust/detail/contiguous_storage.h", + "cuda/include/thrust/detail/contiguous_storage.inl", + "cuda/include/thrust/detail/copy.h", + "cuda/include/thrust/detail/copy.inl", + "cuda/include/thrust/detail/copy_if.h", + "cuda/include/thrust/detail/copy_if.inl", + "cuda/include/thrust/detail/count.inl", + "cuda/include/thrust/detail/cstdint.h", + "cuda/include/thrust/detail/device_delete.inl", + "cuda/include/thrust/detail/device_free.inl", + "cuda/include/thrust/detail/device_malloc.inl", + "cuda/include/thrust/detail/device_new.inl", + "cuda/include/thrust/detail/device_ptr.inl", + "cuda/include/thrust/detail/device_reference.inl", + "cuda/include/thrust/detail/device_vector.inl", + "cuda/include/thrust/detail/dispatch/is_trivial_copy.h", + "cuda/include/thrust/detail/distance.inl", + "cuda/include/thrust/detail/equal.inl", + "cuda/include/thrust/detail/execute_with_allocator.h", + "cuda/include/thrust/detail/execution_policy.h", + "cuda/include/thrust/detail/extrema.inl", + "cuda/include/thrust/detail/fill.inl", + "cuda/include/thrust/detail/find.inl", + "cuda/include/thrust/detail/for_each.inl", + "cuda/include/thrust/detail/function.h", + "cuda/include/thrust/detail/functional.inl", + "cuda/include/thrust/detail/functional/actor.h", + "cuda/include/thrust/detail/functional/actor.inl", + "cuda/include/thrust/detail/functional/argument.h", + "cuda/include/thrust/detail/functional/composite.h", + "cuda/include/thrust/detail/functional/operators.h", + "cuda/include/thrust/detail/functional/operators/arithmetic_operators.h", + "cuda/include/thrust/detail/functional/operators/assignment_operator.h", + "cuda/include/thrust/detail/functional/operators/bitwise_operators.h", + "cuda/include/thrust/detail/functional/operators/compound_assignment_operators.h", + "cuda/include/thrust/detail/functional/operators/logical_operators.h", + "cuda/include/thrust/detail/functional/operators/operator_adaptors.h", + "cuda/include/thrust/detail/functional/operators/relational_operators.h", + "cuda/include/thrust/detail/functional/placeholder.h", + "cuda/include/thrust/detail/functional/value.h", + "cuda/include/thrust/detail/gather.inl", + "cuda/include/thrust/detail/generate.inl", + "cuda/include/thrust/detail/get_iterator_value.h", + "cuda/include/thrust/detail/host_vector.inl", + "cuda/include/thrust/detail/inner_product.inl", + "cuda/include/thrust/detail/integer_math.h", + "cuda/include/thrust/detail/integer_traits.h", + "cuda/include/thrust/detail/internal_functional.h", + "cuda/include/thrust/detail/logical.inl", + "cuda/include/thrust/detail/malloc_and_free.h", + "cuda/include/thrust/detail/merge.inl", + "cuda/include/thrust/detail/minmax.h", + "cuda/include/thrust/detail/mismatch.inl", + "cuda/include/thrust/detail/mpl/math.h", + "cuda/include/thrust/detail/numeric_traits.h", + "cuda/include/thrust/detail/overlapped_copy.h", + "cuda/include/thrust/detail/pair.inl", + "cuda/include/thrust/detail/partition.inl", + "cuda/include/thrust/detail/pointer.h", + "cuda/include/thrust/detail/pointer.inl", + "cuda/include/thrust/detail/preprocessor.h", + "cuda/include/thrust/detail/range/head_flags.h", + "cuda/include/thrust/detail/range/tail_flags.h", + "cuda/include/thrust/detail/raw_pointer_cast.h", + "cuda/include/thrust/detail/raw_reference_cast.h", + "cuda/include/thrust/detail/reduce.inl", + "cuda/include/thrust/detail/reference.h", + "cuda/include/thrust/detail/reference.inl", + "cuda/include/thrust/detail/reference_forward_declaration.h", + "cuda/include/thrust/detail/remove.inl", + "cuda/include/thrust/detail/replace.inl", + "cuda/include/thrust/detail/reverse.inl", + "cuda/include/thrust/detail/scan.inl", + "cuda/include/thrust/detail/scatter.inl", + "cuda/include/thrust/detail/seq.h", + "cuda/include/thrust/detail/sequence.inl", + "cuda/include/thrust/detail/set_operations.inl", + "cuda/include/thrust/detail/sort.inl", + "cuda/include/thrust/detail/static_assert.h", + "cuda/include/thrust/detail/static_map.h", + "cuda/include/thrust/detail/swap.h", + "cuda/include/thrust/detail/swap.inl", + "cuda/include/thrust/detail/swap_ranges.inl", + "cuda/include/thrust/detail/tabulate.inl", + "cuda/include/thrust/detail/temporary_array.h", + "cuda/include/thrust/detail/temporary_array.inl", + "cuda/include/thrust/detail/temporary_buffer.h", + "cuda/include/thrust/detail/transform.inl", + "cuda/include/thrust/detail/transform_reduce.inl", + "cuda/include/thrust/detail/transform_scan.inl", + "cuda/include/thrust/detail/trivial_sequence.h", + "cuda/include/thrust/detail/tuple.inl", + "cuda/include/thrust/detail/tuple_meta_transform.h", + "cuda/include/thrust/detail/tuple_transform.h", + "cuda/include/thrust/detail/type_traits.h", + "cuda/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h", + "cuda/include/thrust/detail/type_traits/function_traits.h", + "cuda/include/thrust/detail/type_traits/has_member_function.h", + "cuda/include/thrust/detail/type_traits/has_nested_type.h", + "cuda/include/thrust/detail/type_traits/has_trivial_assign.h", + "cuda/include/thrust/detail/type_traits/is_call_possible.h", + "cuda/include/thrust/detail/type_traits/is_metafunction_defined.h", + "cuda/include/thrust/detail/type_traits/iterator/is_discard_iterator.h", + "cuda/include/thrust/detail/type_traits/iterator/is_output_iterator.h", + "cuda/include/thrust/detail/type_traits/minimum_type.h", + "cuda/include/thrust/detail/type_traits/pointer_traits.h", + "cuda/include/thrust/detail/type_traits/result_of_adaptable_function.h", + "cuda/include/thrust/detail/uninitialized_copy.inl", + "cuda/include/thrust/detail/uninitialized_fill.inl", + "cuda/include/thrust/detail/unique.inl", + "cuda/include/thrust/detail/use_default.h", + "cuda/include/thrust/detail/util/align.h", + "cuda/include/thrust/detail/util/blocking.h", + "cuda/include/thrust/detail/vector_base.h", + "cuda/include/thrust/detail/vector_base.inl", + "cuda/include/thrust/device_allocator.h", + "cuda/include/thrust/device_delete.h", + "cuda/include/thrust/device_free.h", + "cuda/include/thrust/device_malloc.h", + "cuda/include/thrust/device_malloc_allocator.h", + "cuda/include/thrust/device_new.h", + "cuda/include/thrust/device_new_allocator.h", + "cuda/include/thrust/device_ptr.h", + "cuda/include/thrust/device_reference.h", + "cuda/include/thrust/device_vector.h", + "cuda/include/thrust/distance.h", + "cuda/include/thrust/equal.h", + "cuda/include/thrust/execution_policy.h", + "cuda/include/thrust/extrema.h", + "cuda/include/thrust/fill.h", + "cuda/include/thrust/find.h", + "cuda/include/thrust/for_each.h", + "cuda/include/thrust/functional.h", + "cuda/include/thrust/gather.h", + "cuda/include/thrust/generate.h", + "cuda/include/thrust/host_vector.h", + "cuda/include/thrust/inner_product.h", + "cuda/include/thrust/iterator/constant_iterator.h", + "cuda/include/thrust/iterator/counting_iterator.h", + "cuda/include/thrust/iterator/detail/any_assign.h", + "cuda/include/thrust/iterator/detail/any_system_tag.h", + "cuda/include/thrust/iterator/detail/constant_iterator_base.h", + "cuda/include/thrust/iterator/detail/counting_iterator.inl", + "cuda/include/thrust/iterator/detail/device_system_tag.h", + "cuda/include/thrust/iterator/detail/discard_iterator_base.h", + "cuda/include/thrust/iterator/detail/distance_from_result.h", + "cuda/include/thrust/iterator/detail/host_system_tag.h", + "cuda/include/thrust/iterator/detail/is_iterator_category.h", + "cuda/include/thrust/iterator/detail/is_trivial_iterator.h", + "cuda/include/thrust/iterator/detail/iterator_adaptor_base.h", + "cuda/include/thrust/iterator/detail/iterator_category_to_system.h", + "cuda/include/thrust/iterator/detail/iterator_category_to_traversal.h", + "cuda/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h", + "cuda/include/thrust/iterator/detail/iterator_facade_category.h", + "cuda/include/thrust/iterator/detail/iterator_traits.inl", + "cuda/include/thrust/iterator/detail/iterator_traversal_tags.h", + "cuda/include/thrust/iterator/detail/join_iterator.h", + "cuda/include/thrust/iterator/detail/minimum_category.h", + "cuda/include/thrust/iterator/detail/minimum_system.h", + "cuda/include/thrust/iterator/detail/normal_iterator.h", + "cuda/include/thrust/iterator/detail/permutation_iterator_base.h", + "cuda/include/thrust/iterator/detail/retag.h", + "cuda/include/thrust/iterator/detail/reverse_iterator.inl", + "cuda/include/thrust/iterator/detail/reverse_iterator_base.h", + "cuda/include/thrust/iterator/detail/tagged_iterator.h", + "cuda/include/thrust/iterator/detail/transform_iterator.inl", + "cuda/include/thrust/iterator/detail/transform_output_iterator.inl", + "cuda/include/thrust/iterator/detail/tuple_of_iterator_references.h", + "cuda/include/thrust/iterator/detail/universal_categories.h", + "cuda/include/thrust/iterator/detail/zip_iterator.inl", + "cuda/include/thrust/iterator/detail/zip_iterator_base.h", + "cuda/include/thrust/iterator/discard_iterator.h", + "cuda/include/thrust/iterator/iterator_adaptor.h", + "cuda/include/thrust/iterator/iterator_categories.h", + "cuda/include/thrust/iterator/iterator_facade.h", + "cuda/include/thrust/iterator/iterator_traits.h", + "cuda/include/thrust/iterator/permutation_iterator.h", + "cuda/include/thrust/iterator/retag.h", + "cuda/include/thrust/iterator/reverse_iterator.h", + "cuda/include/thrust/iterator/transform_iterator.h", + "cuda/include/thrust/iterator/transform_output_iterator.h", + "cuda/include/thrust/iterator/zip_iterator.h", + "cuda/include/thrust/logical.h", + "cuda/include/thrust/memory.h", + "cuda/include/thrust/merge.h", + "cuda/include/thrust/mismatch.h", + "cuda/include/thrust/pair.h", + "cuda/include/thrust/partition.h", + "cuda/include/thrust/random.h", + "cuda/include/thrust/random/detail/discard_block_engine.inl", + "cuda/include/thrust/random/detail/linear_congruential_engine.inl", + "cuda/include/thrust/random/detail/linear_congruential_engine_discard.h", + "cuda/include/thrust/random/detail/linear_feedback_shift_engine.inl", + "cuda/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h", + "cuda/include/thrust/random/detail/mod.h", + "cuda/include/thrust/random/detail/normal_distribution.inl", + "cuda/include/thrust/random/detail/normal_distribution_base.h", + "cuda/include/thrust/random/detail/random_core_access.h", + "cuda/include/thrust/random/detail/subtract_with_carry_engine.inl", + "cuda/include/thrust/random/detail/uniform_int_distribution.inl", + "cuda/include/thrust/random/detail/uniform_real_distribution.inl", + "cuda/include/thrust/random/detail/xor_combine_engine.inl", + "cuda/include/thrust/random/detail/xor_combine_engine_max.h", + "cuda/include/thrust/random/discard_block_engine.h", + "cuda/include/thrust/random/linear_congruential_engine.h", + "cuda/include/thrust/random/linear_feedback_shift_engine.h", + "cuda/include/thrust/random/normal_distribution.h", + "cuda/include/thrust/random/subtract_with_carry_engine.h", + "cuda/include/thrust/random/uniform_int_distribution.h", + "cuda/include/thrust/random/uniform_real_distribution.h", + "cuda/include/thrust/random/xor_combine_engine.h", + "cuda/include/thrust/reduce.h", + "cuda/include/thrust/remove.h", + "cuda/include/thrust/replace.h", + "cuda/include/thrust/reverse.h", + "cuda/include/thrust/scan.h", + "cuda/include/thrust/scatter.h", + "cuda/include/thrust/sequence.h", + "cuda/include/thrust/set_operations.h", + "cuda/include/thrust/sort.h", + "cuda/include/thrust/swap.h", + "cuda/include/thrust/system/cpp/detail/adjacent_difference.h", + "cuda/include/thrust/system/cpp/detail/assign_value.h", + "cuda/include/thrust/system/cpp/detail/binary_search.h", + "cuda/include/thrust/system/cpp/detail/copy.h", + "cuda/include/thrust/system/cpp/detail/copy_if.h", + "cuda/include/thrust/system/cpp/detail/count.h", + "cuda/include/thrust/system/cpp/detail/equal.h", + "cuda/include/thrust/system/cpp/detail/execution_policy.h", + "cuda/include/thrust/system/cpp/detail/extrema.h", + "cuda/include/thrust/system/cpp/detail/fill.h", + "cuda/include/thrust/system/cpp/detail/find.h", + "cuda/include/thrust/system/cpp/detail/for_each.h", + "cuda/include/thrust/system/cpp/detail/gather.h", + "cuda/include/thrust/system/cpp/detail/generate.h", + "cuda/include/thrust/system/cpp/detail/get_value.h", + "cuda/include/thrust/system/cpp/detail/inner_product.h", + "cuda/include/thrust/system/cpp/detail/iter_swap.h", + "cuda/include/thrust/system/cpp/detail/logical.h", + "cuda/include/thrust/system/cpp/detail/malloc_and_free.h", + "cuda/include/thrust/system/cpp/detail/memory.inl", + "cuda/include/thrust/system/cpp/detail/merge.h", + "cuda/include/thrust/system/cpp/detail/mismatch.h", + "cuda/include/thrust/system/cpp/detail/par.h", + "cuda/include/thrust/system/cpp/detail/partition.h", + "cuda/include/thrust/system/cpp/detail/reduce.h", + "cuda/include/thrust/system/cpp/detail/reduce_by_key.h", + "cuda/include/thrust/system/cpp/detail/remove.h", + "cuda/include/thrust/system/cpp/detail/replace.h", + "cuda/include/thrust/system/cpp/detail/reverse.h", + "cuda/include/thrust/system/cpp/detail/scan.h", + "cuda/include/thrust/system/cpp/detail/scan_by_key.h", + "cuda/include/thrust/system/cpp/detail/scatter.h", + "cuda/include/thrust/system/cpp/detail/sequence.h", + "cuda/include/thrust/system/cpp/detail/set_operations.h", + "cuda/include/thrust/system/cpp/detail/sort.h", + "cuda/include/thrust/system/cpp/detail/swap_ranges.h", + "cuda/include/thrust/system/cpp/detail/tabulate.h", + "cuda/include/thrust/system/cpp/detail/temporary_buffer.h", + "cuda/include/thrust/system/cpp/detail/transform.h", + "cuda/include/thrust/system/cpp/detail/transform_reduce.h", + "cuda/include/thrust/system/cpp/detail/transform_scan.h", + "cuda/include/thrust/system/cpp/detail/uninitialized_copy.h", + "cuda/include/thrust/system/cpp/detail/uninitialized_fill.h", + "cuda/include/thrust/system/cpp/detail/unique.h", + "cuda/include/thrust/system/cpp/detail/unique_by_key.h", + "cuda/include/thrust/system/cpp/detail/vector.inl", + "cuda/include/thrust/system/cpp/execution_policy.h", + "cuda/include/thrust/system/cpp/memory.h", + "cuda/include/thrust/system/cpp/vector.h", + "cuda/include/thrust/system/cuda/config.h", + "cuda/include/thrust/system/cuda/detail/adjacent_difference.h", + "cuda/include/thrust/system/cuda/detail/assign_value.h", + "cuda/include/thrust/system/cuda/detail/binary_search.h", + "cuda/include/thrust/system/cuda/detail/copy.h", + "cuda/include/thrust/system/cuda/detail/copy_if.h", + "cuda/include/thrust/system/cuda/detail/core/agent_launcher.h", + "cuda/include/thrust/system/cuda/detail/core/alignment.h", + "cuda/include/thrust/system/cuda/detail/core/triple_chevron_launch.h", + "cuda/include/thrust/system/cuda/detail/core/util.h", + "cuda/include/thrust/system/cuda/detail/count.h", + "cuda/include/thrust/system/cuda/detail/cross_system.h", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh", + "cuda/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_load.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_scan.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/block_store.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh", + "cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh", + "cuda/include/thrust/system/cuda/detail/cub/cub.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_partition.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_scan.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_select.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh", + "cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh", + "cuda/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh", + "cuda/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh", + "cuda/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh", + "cuda/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh", + "cuda/include/thrust/system/cuda/detail/cub/host/mutex.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh", + "cuda/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh", + "cuda/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh", + "cuda/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh", + "cuda/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_allocator.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_arch.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_debug.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_device.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_macro.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_namespace.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_ptx.cuh", + "cuda/include/thrust/system/cuda/detail/cub/util_type.cuh", + "cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh", + "cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh", + "cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh", + "cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh", + "cuda/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh", + "cuda/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh", + "cuda/include/thrust/system/cuda/detail/equal.h", + "cuda/include/thrust/system/cuda/detail/error.inl", + "cuda/include/thrust/system/cuda/detail/execution_policy.h", + "cuda/include/thrust/system/cuda/detail/extrema.h", + "cuda/include/thrust/system/cuda/detail/fill.h", + "cuda/include/thrust/system/cuda/detail/find.h", + "cuda/include/thrust/system/cuda/detail/for_each.h", + "cuda/include/thrust/system/cuda/detail/gather.h", + "cuda/include/thrust/system/cuda/detail/generate.h", + "cuda/include/thrust/system/cuda/detail/get_value.h", + "cuda/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h", + "cuda/include/thrust/system/cuda/detail/guarded_driver_types.h", + "cuda/include/thrust/system/cuda/detail/inner_product.h", + "cuda/include/thrust/system/cuda/detail/internal/copy_cross_system.h", + "cuda/include/thrust/system/cuda/detail/internal/copy_device_to_device.h", + "cuda/include/thrust/system/cuda/detail/iter_swap.h", + "cuda/include/thrust/system/cuda/detail/logical.h", + "cuda/include/thrust/system/cuda/detail/malloc_and_free.h", + "cuda/include/thrust/system/cuda/detail/memory.inl", + "cuda/include/thrust/system/cuda/detail/merge.h", + "cuda/include/thrust/system/cuda/detail/mismatch.h", + "cuda/include/thrust/system/cuda/detail/par.h", + "cuda/include/thrust/system/cuda/detail/par_to_seq.h", + "cuda/include/thrust/system/cuda/detail/parallel_for.h", + "cuda/include/thrust/system/cuda/detail/partition.h", + "cuda/include/thrust/system/cuda/detail/reduce.h", + "cuda/include/thrust/system/cuda/detail/reduce_by_key.h", + "cuda/include/thrust/system/cuda/detail/remove.h", + "cuda/include/thrust/system/cuda/detail/replace.h", + "cuda/include/thrust/system/cuda/detail/reverse.h", + "cuda/include/thrust/system/cuda/detail/scan.h", + "cuda/include/thrust/system/cuda/detail/scan_by_key.h", + "cuda/include/thrust/system/cuda/detail/scatter.h", + "cuda/include/thrust/system/cuda/detail/sequence.h", + "cuda/include/thrust/system/cuda/detail/set_operations.h", + "cuda/include/thrust/system/cuda/detail/sort.h", + "cuda/include/thrust/system/cuda/detail/swap_ranges.h", + "cuda/include/thrust/system/cuda/detail/tabulate.h", + "cuda/include/thrust/system/cuda/detail/temporary_buffer.h", + "cuda/include/thrust/system/cuda/detail/terminate.h", + "cuda/include/thrust/system/cuda/detail/transform.h", + "cuda/include/thrust/system/cuda/detail/transform_reduce.h", + "cuda/include/thrust/system/cuda/detail/transform_scan.h", + "cuda/include/thrust/system/cuda/detail/uninitialized_copy.h", + "cuda/include/thrust/system/cuda/detail/uninitialized_fill.h", + "cuda/include/thrust/system/cuda/detail/unique.h", + "cuda/include/thrust/system/cuda/detail/unique_by_key.h", + "cuda/include/thrust/system/cuda/detail/util.h", + "cuda/include/thrust/system/cuda/detail/vector.inl", + "cuda/include/thrust/system/cuda/error.h", + "cuda/include/thrust/system/cuda/execution_policy.h", + "cuda/include/thrust/system/cuda/experimental/pinned_allocator.h", + "cuda/include/thrust/system/cuda/memory.h", + "cuda/include/thrust/system/cuda/vector.h", + "cuda/include/thrust/system/detail/adl/adjacent_difference.h", + "cuda/include/thrust/system/detail/adl/assign_value.h", + "cuda/include/thrust/system/detail/adl/binary_search.h", + "cuda/include/thrust/system/detail/adl/copy.h", + "cuda/include/thrust/system/detail/adl/copy_if.h", + "cuda/include/thrust/system/detail/adl/count.h", + "cuda/include/thrust/system/detail/adl/equal.h", + "cuda/include/thrust/system/detail/adl/extrema.h", + "cuda/include/thrust/system/detail/adl/fill.h", + "cuda/include/thrust/system/detail/adl/find.h", + "cuda/include/thrust/system/detail/adl/for_each.h", + "cuda/include/thrust/system/detail/adl/gather.h", + "cuda/include/thrust/system/detail/adl/generate.h", + "cuda/include/thrust/system/detail/adl/get_value.h", + "cuda/include/thrust/system/detail/adl/inner_product.h", + "cuda/include/thrust/system/detail/adl/iter_swap.h", + "cuda/include/thrust/system/detail/adl/logical.h", + "cuda/include/thrust/system/detail/adl/malloc_and_free.h", + "cuda/include/thrust/system/detail/adl/merge.h", + "cuda/include/thrust/system/detail/adl/mismatch.h", + "cuda/include/thrust/system/detail/adl/partition.h", + "cuda/include/thrust/system/detail/adl/reduce.h", + "cuda/include/thrust/system/detail/adl/reduce_by_key.h", + "cuda/include/thrust/system/detail/adl/remove.h", + "cuda/include/thrust/system/detail/adl/replace.h", + "cuda/include/thrust/system/detail/adl/reverse.h", + "cuda/include/thrust/system/detail/adl/scan.h", + "cuda/include/thrust/system/detail/adl/scan_by_key.h", + "cuda/include/thrust/system/detail/adl/scatter.h", + "cuda/include/thrust/system/detail/adl/sequence.h", + "cuda/include/thrust/system/detail/adl/set_operations.h", + "cuda/include/thrust/system/detail/adl/sort.h", + "cuda/include/thrust/system/detail/adl/swap_ranges.h", + "cuda/include/thrust/system/detail/adl/tabulate.h", + "cuda/include/thrust/system/detail/adl/temporary_buffer.h", + "cuda/include/thrust/system/detail/adl/transform.h", + "cuda/include/thrust/system/detail/adl/transform_reduce.h", + "cuda/include/thrust/system/detail/adl/transform_scan.h", + "cuda/include/thrust/system/detail/adl/uninitialized_copy.h", + "cuda/include/thrust/system/detail/adl/uninitialized_fill.h", + "cuda/include/thrust/system/detail/adl/unique.h", + "cuda/include/thrust/system/detail/adl/unique_by_key.h", + "cuda/include/thrust/system/detail/bad_alloc.h", + "cuda/include/thrust/system/detail/errno.h", + "cuda/include/thrust/system/detail/error_category.inl", + "cuda/include/thrust/system/detail/error_code.inl", + "cuda/include/thrust/system/detail/error_condition.inl", + "cuda/include/thrust/system/detail/generic/adjacent_difference.h", + "cuda/include/thrust/system/detail/generic/adjacent_difference.inl", + "cuda/include/thrust/system/detail/generic/advance.h", + "cuda/include/thrust/system/detail/generic/advance.inl", + "cuda/include/thrust/system/detail/generic/binary_search.h", + "cuda/include/thrust/system/detail/generic/binary_search.inl", + "cuda/include/thrust/system/detail/generic/copy.h", + "cuda/include/thrust/system/detail/generic/copy.inl", + "cuda/include/thrust/system/detail/generic/copy_if.h", + "cuda/include/thrust/system/detail/generic/copy_if.inl", + "cuda/include/thrust/system/detail/generic/count.h", + "cuda/include/thrust/system/detail/generic/count.inl", + "cuda/include/thrust/system/detail/generic/distance.h", + "cuda/include/thrust/system/detail/generic/distance.inl", + "cuda/include/thrust/system/detail/generic/equal.h", + "cuda/include/thrust/system/detail/generic/equal.inl", + "cuda/include/thrust/system/detail/generic/extrema.h", + "cuda/include/thrust/system/detail/generic/extrema.inl", + "cuda/include/thrust/system/detail/generic/fill.h", + "cuda/include/thrust/system/detail/generic/find.h", + "cuda/include/thrust/system/detail/generic/find.inl", + "cuda/include/thrust/system/detail/generic/for_each.h", + "cuda/include/thrust/system/detail/generic/gather.h", + "cuda/include/thrust/system/detail/generic/gather.inl", + "cuda/include/thrust/system/detail/generic/generate.h", + "cuda/include/thrust/system/detail/generic/generate.inl", + "cuda/include/thrust/system/detail/generic/inner_product.h", + "cuda/include/thrust/system/detail/generic/inner_product.inl", + "cuda/include/thrust/system/detail/generic/logical.h", + "cuda/include/thrust/system/detail/generic/memory.h", + "cuda/include/thrust/system/detail/generic/memory.inl", + "cuda/include/thrust/system/detail/generic/merge.h", + "cuda/include/thrust/system/detail/generic/merge.inl", + "cuda/include/thrust/system/detail/generic/mismatch.h", + "cuda/include/thrust/system/detail/generic/mismatch.inl", + "cuda/include/thrust/system/detail/generic/partition.h", + "cuda/include/thrust/system/detail/generic/partition.inl", + "cuda/include/thrust/system/detail/generic/reduce.h", + "cuda/include/thrust/system/detail/generic/reduce.inl", + "cuda/include/thrust/system/detail/generic/reduce_by_key.h", + "cuda/include/thrust/system/detail/generic/reduce_by_key.inl", + "cuda/include/thrust/system/detail/generic/remove.h", + "cuda/include/thrust/system/detail/generic/remove.inl", + "cuda/include/thrust/system/detail/generic/replace.h", + "cuda/include/thrust/system/detail/generic/replace.inl", + "cuda/include/thrust/system/detail/generic/reverse.h", + "cuda/include/thrust/system/detail/generic/reverse.inl", + "cuda/include/thrust/system/detail/generic/scalar/binary_search.h", + "cuda/include/thrust/system/detail/generic/scalar/binary_search.inl", + "cuda/include/thrust/system/detail/generic/scan.h", + "cuda/include/thrust/system/detail/generic/scan.inl", + "cuda/include/thrust/system/detail/generic/scan_by_key.h", + "cuda/include/thrust/system/detail/generic/scan_by_key.inl", + "cuda/include/thrust/system/detail/generic/scatter.h", + "cuda/include/thrust/system/detail/generic/scatter.inl", + "cuda/include/thrust/system/detail/generic/select_system.h", + "cuda/include/thrust/system/detail/generic/sequence.h", + "cuda/include/thrust/system/detail/generic/sequence.inl", + "cuda/include/thrust/system/detail/generic/set_operations.h", + "cuda/include/thrust/system/detail/generic/set_operations.inl", + "cuda/include/thrust/system/detail/generic/sort.h", + "cuda/include/thrust/system/detail/generic/sort.inl", + "cuda/include/thrust/system/detail/generic/swap_ranges.h", + "cuda/include/thrust/system/detail/generic/swap_ranges.inl", + "cuda/include/thrust/system/detail/generic/tabulate.h", + "cuda/include/thrust/system/detail/generic/tabulate.inl", + "cuda/include/thrust/system/detail/generic/tag.h", + "cuda/include/thrust/system/detail/generic/temporary_buffer.h", + "cuda/include/thrust/system/detail/generic/temporary_buffer.inl", + "cuda/include/thrust/system/detail/generic/transform.h", + "cuda/include/thrust/system/detail/generic/transform.inl", + "cuda/include/thrust/system/detail/generic/transform_reduce.h", + "cuda/include/thrust/system/detail/generic/transform_reduce.inl", + "cuda/include/thrust/system/detail/generic/transform_scan.h", + "cuda/include/thrust/system/detail/generic/transform_scan.inl", + "cuda/include/thrust/system/detail/generic/type_traits.h", + "cuda/include/thrust/system/detail/generic/uninitialized_copy.h", + "cuda/include/thrust/system/detail/generic/uninitialized_copy.inl", + "cuda/include/thrust/system/detail/generic/uninitialized_fill.h", + "cuda/include/thrust/system/detail/generic/uninitialized_fill.inl", + "cuda/include/thrust/system/detail/generic/unique.h", + "cuda/include/thrust/system/detail/generic/unique.inl", + "cuda/include/thrust/system/detail/generic/unique_by_key.h", + "cuda/include/thrust/system/detail/generic/unique_by_key.inl", + "cuda/include/thrust/system/detail/internal/decompose.h", + "cuda/include/thrust/system/detail/sequential/adjacent_difference.h", + "cuda/include/thrust/system/detail/sequential/assign_value.h", + "cuda/include/thrust/system/detail/sequential/binary_search.h", + "cuda/include/thrust/system/detail/sequential/copy.h", + "cuda/include/thrust/system/detail/sequential/copy.inl", + "cuda/include/thrust/system/detail/sequential/copy_backward.h", + "cuda/include/thrust/system/detail/sequential/copy_if.h", + "cuda/include/thrust/system/detail/sequential/count.h", + "cuda/include/thrust/system/detail/sequential/equal.h", + "cuda/include/thrust/system/detail/sequential/execution_policy.h", + "cuda/include/thrust/system/detail/sequential/extrema.h", + "cuda/include/thrust/system/detail/sequential/fill.h", + "cuda/include/thrust/system/detail/sequential/find.h", + "cuda/include/thrust/system/detail/sequential/for_each.h", + "cuda/include/thrust/system/detail/sequential/gather.h", + "cuda/include/thrust/system/detail/sequential/general_copy.h", + "cuda/include/thrust/system/detail/sequential/generate.h", + "cuda/include/thrust/system/detail/sequential/get_value.h", + "cuda/include/thrust/system/detail/sequential/inner_product.h", + "cuda/include/thrust/system/detail/sequential/insertion_sort.h", + "cuda/include/thrust/system/detail/sequential/iter_swap.h", + "cuda/include/thrust/system/detail/sequential/logical.h", + "cuda/include/thrust/system/detail/sequential/malloc_and_free.h", + "cuda/include/thrust/system/detail/sequential/merge.h", + "cuda/include/thrust/system/detail/sequential/merge.inl", + "cuda/include/thrust/system/detail/sequential/mismatch.h", + "cuda/include/thrust/system/detail/sequential/partition.h", + "cuda/include/thrust/system/detail/sequential/reduce.h", + "cuda/include/thrust/system/detail/sequential/reduce_by_key.h", + "cuda/include/thrust/system/detail/sequential/remove.h", + "cuda/include/thrust/system/detail/sequential/replace.h", + "cuda/include/thrust/system/detail/sequential/reverse.h", + "cuda/include/thrust/system/detail/sequential/scan.h", + "cuda/include/thrust/system/detail/sequential/scan_by_key.h", + "cuda/include/thrust/system/detail/sequential/scatter.h", + "cuda/include/thrust/system/detail/sequential/sequence.h", + "cuda/include/thrust/system/detail/sequential/set_operations.h", + "cuda/include/thrust/system/detail/sequential/sort.h", + "cuda/include/thrust/system/detail/sequential/sort.inl", + "cuda/include/thrust/system/detail/sequential/stable_merge_sort.h", + "cuda/include/thrust/system/detail/sequential/stable_merge_sort.inl", + "cuda/include/thrust/system/detail/sequential/stable_primitive_sort.h", + "cuda/include/thrust/system/detail/sequential/stable_primitive_sort.inl", + "cuda/include/thrust/system/detail/sequential/stable_radix_sort.h", + "cuda/include/thrust/system/detail/sequential/stable_radix_sort.inl", + "cuda/include/thrust/system/detail/sequential/swap_ranges.h", + "cuda/include/thrust/system/detail/sequential/tabulate.h", + "cuda/include/thrust/system/detail/sequential/temporary_buffer.h", + "cuda/include/thrust/system/detail/sequential/transform.h", + "cuda/include/thrust/system/detail/sequential/transform_reduce.h", + "cuda/include/thrust/system/detail/sequential/transform_scan.h", + "cuda/include/thrust/system/detail/sequential/trivial_copy.h", + "cuda/include/thrust/system/detail/sequential/uninitialized_copy.h", + "cuda/include/thrust/system/detail/sequential/uninitialized_fill.h", + "cuda/include/thrust/system/detail/sequential/unique.h", + "cuda/include/thrust/system/detail/sequential/unique_by_key.h", + "cuda/include/thrust/system/detail/system_error.inl", + "cuda/include/thrust/system/error_code.h", + "cuda/include/thrust/system/omp/detail/adjacent_difference.h", + "cuda/include/thrust/system/omp/detail/assign_value.h", + "cuda/include/thrust/system/omp/detail/binary_search.h", + "cuda/include/thrust/system/omp/detail/copy.h", + "cuda/include/thrust/system/omp/detail/copy.inl", + "cuda/include/thrust/system/omp/detail/copy_if.h", + "cuda/include/thrust/system/omp/detail/copy_if.inl", + "cuda/include/thrust/system/omp/detail/count.h", + "cuda/include/thrust/system/omp/detail/default_decomposition.h", + "cuda/include/thrust/system/omp/detail/default_decomposition.inl", + "cuda/include/thrust/system/omp/detail/equal.h", + "cuda/include/thrust/system/omp/detail/execution_policy.h", + "cuda/include/thrust/system/omp/detail/extrema.h", + "cuda/include/thrust/system/omp/detail/fill.h", + "cuda/include/thrust/system/omp/detail/find.h", + "cuda/include/thrust/system/omp/detail/for_each.h", + "cuda/include/thrust/system/omp/detail/for_each.inl", + "cuda/include/thrust/system/omp/detail/gather.h", + "cuda/include/thrust/system/omp/detail/generate.h", + "cuda/include/thrust/system/omp/detail/get_value.h", + "cuda/include/thrust/system/omp/detail/inner_product.h", + "cuda/include/thrust/system/omp/detail/iter_swap.h", + "cuda/include/thrust/system/omp/detail/logical.h", + "cuda/include/thrust/system/omp/detail/malloc_and_free.h", + "cuda/include/thrust/system/omp/detail/memory.inl", + "cuda/include/thrust/system/omp/detail/merge.h", + "cuda/include/thrust/system/omp/detail/mismatch.h", + "cuda/include/thrust/system/omp/detail/par.h", + "cuda/include/thrust/system/omp/detail/partition.h", + "cuda/include/thrust/system/omp/detail/partition.inl", + "cuda/include/thrust/system/omp/detail/reduce.h", + "cuda/include/thrust/system/omp/detail/reduce.inl", + "cuda/include/thrust/system/omp/detail/reduce_by_key.h", + "cuda/include/thrust/system/omp/detail/reduce_by_key.inl", + "cuda/include/thrust/system/omp/detail/reduce_intervals.h", + "cuda/include/thrust/system/omp/detail/reduce_intervals.inl", + "cuda/include/thrust/system/omp/detail/remove.h", + "cuda/include/thrust/system/omp/detail/remove.inl", + "cuda/include/thrust/system/omp/detail/replace.h", + "cuda/include/thrust/system/omp/detail/reverse.h", + "cuda/include/thrust/system/omp/detail/scan.h", + "cuda/include/thrust/system/omp/detail/scan_by_key.h", + "cuda/include/thrust/system/omp/detail/scatter.h", + "cuda/include/thrust/system/omp/detail/sequence.h", + "cuda/include/thrust/system/omp/detail/set_operations.h", + "cuda/include/thrust/system/omp/detail/sort.h", + "cuda/include/thrust/system/omp/detail/sort.inl", + "cuda/include/thrust/system/omp/detail/swap_ranges.h", + "cuda/include/thrust/system/omp/detail/tabulate.h", + "cuda/include/thrust/system/omp/detail/temporary_buffer.h", + "cuda/include/thrust/system/omp/detail/transform.h", + "cuda/include/thrust/system/omp/detail/transform_reduce.h", + "cuda/include/thrust/system/omp/detail/transform_scan.h", + "cuda/include/thrust/system/omp/detail/uninitialized_copy.h", + "cuda/include/thrust/system/omp/detail/uninitialized_fill.h", + "cuda/include/thrust/system/omp/detail/unique.h", + "cuda/include/thrust/system/omp/detail/unique.inl", + "cuda/include/thrust/system/omp/detail/unique_by_key.h", + "cuda/include/thrust/system/omp/detail/unique_by_key.inl", + "cuda/include/thrust/system/omp/detail/vector.inl", + "cuda/include/thrust/system/omp/execution_policy.h", + "cuda/include/thrust/system/omp/memory.h", + "cuda/include/thrust/system/omp/vector.h", + "cuda/include/thrust/system/system_error.h", + "cuda/include/thrust/system/tbb/detail/adjacent_difference.h", + "cuda/include/thrust/system/tbb/detail/assign_value.h", + "cuda/include/thrust/system/tbb/detail/binary_search.h", + "cuda/include/thrust/system/tbb/detail/copy.h", + "cuda/include/thrust/system/tbb/detail/copy.inl", + "cuda/include/thrust/system/tbb/detail/copy_if.h", + "cuda/include/thrust/system/tbb/detail/copy_if.inl", + "cuda/include/thrust/system/tbb/detail/count.h", + "cuda/include/thrust/system/tbb/detail/equal.h", + "cuda/include/thrust/system/tbb/detail/execution_policy.h", + "cuda/include/thrust/system/tbb/detail/extrema.h", + "cuda/include/thrust/system/tbb/detail/fill.h", + "cuda/include/thrust/system/tbb/detail/find.h", + "cuda/include/thrust/system/tbb/detail/for_each.h", + "cuda/include/thrust/system/tbb/detail/for_each.inl", + "cuda/include/thrust/system/tbb/detail/gather.h", + "cuda/include/thrust/system/tbb/detail/generate.h", + "cuda/include/thrust/system/tbb/detail/get_value.h", + "cuda/include/thrust/system/tbb/detail/inner_product.h", + "cuda/include/thrust/system/tbb/detail/iter_swap.h", + "cuda/include/thrust/system/tbb/detail/logical.h", + "cuda/include/thrust/system/tbb/detail/malloc_and_free.h", + "cuda/include/thrust/system/tbb/detail/memory.inl", + "cuda/include/thrust/system/tbb/detail/merge.h", + "cuda/include/thrust/system/tbb/detail/merge.inl", + "cuda/include/thrust/system/tbb/detail/mismatch.h", + "cuda/include/thrust/system/tbb/detail/par.h", + "cuda/include/thrust/system/tbb/detail/partition.h", + "cuda/include/thrust/system/tbb/detail/partition.inl", + "cuda/include/thrust/system/tbb/detail/reduce.h", + "cuda/include/thrust/system/tbb/detail/reduce.inl", + "cuda/include/thrust/system/tbb/detail/reduce_by_key.h", + "cuda/include/thrust/system/tbb/detail/reduce_by_key.inl", + "cuda/include/thrust/system/tbb/detail/reduce_intervals.h", + "cuda/include/thrust/system/tbb/detail/remove.h", + "cuda/include/thrust/system/tbb/detail/remove.inl", + "cuda/include/thrust/system/tbb/detail/replace.h", + "cuda/include/thrust/system/tbb/detail/reverse.h", + "cuda/include/thrust/system/tbb/detail/scan.h", + "cuda/include/thrust/system/tbb/detail/scan.inl", + "cuda/include/thrust/system/tbb/detail/scan_by_key.h", + "cuda/include/thrust/system/tbb/detail/scatter.h", + "cuda/include/thrust/system/tbb/detail/sequence.h", + "cuda/include/thrust/system/tbb/detail/set_operations.h", + "cuda/include/thrust/system/tbb/detail/sort.h", + "cuda/include/thrust/system/tbb/detail/sort.inl", + "cuda/include/thrust/system/tbb/detail/swap_ranges.h", + "cuda/include/thrust/system/tbb/detail/tabulate.h", + "cuda/include/thrust/system/tbb/detail/temporary_buffer.h", + "cuda/include/thrust/system/tbb/detail/transform.h", + "cuda/include/thrust/system/tbb/detail/transform_reduce.h", + "cuda/include/thrust/system/tbb/detail/transform_scan.h", + "cuda/include/thrust/system/tbb/detail/uninitialized_copy.h", + "cuda/include/thrust/system/tbb/detail/uninitialized_fill.h", + "cuda/include/thrust/system/tbb/detail/unique.h", + "cuda/include/thrust/system/tbb/detail/unique.inl", + "cuda/include/thrust/system/tbb/detail/unique_by_key.h", + "cuda/include/thrust/system/tbb/detail/unique_by_key.inl", + "cuda/include/thrust/system/tbb/detail/vector.inl", + "cuda/include/thrust/system/tbb/execution_policy.h", + "cuda/include/thrust/system/tbb/memory.h", + "cuda/include/thrust/system/tbb/vector.h", + "cuda/include/thrust/system_error.h", + "cuda/include/thrust/tabulate.h", + "cuda/include/thrust/transform.h", + "cuda/include/thrust/transform_reduce.h", + "cuda/include/thrust/transform_scan.h", + "cuda/include/thrust/tuple.h", + "cuda/include/thrust/uninitialized_copy.h", + "cuda/include/thrust/uninitialized_fill.h", + "cuda/include/thrust/unique.h", + "cuda/include/thrust/version.h", + "cuda/include/vector_functions.h", + "cuda/include/vector_functions.hpp", + "cuda/include/vector_types.h", + ], + cmd = """ +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-10.0/include/CL/cl.h" "$(@D)/cuda/include/CL/cl.h" && cp -f "/usr/local/cuda-10.0/include/CL/cl.hpp" "$(@D)/cuda/include/CL/cl.hpp" && cp -f "/usr/local/cuda-10.0/include/CL/cl_egl.h" "$(@D)/cuda/include/CL/cl_egl.h" && cp -f "/usr/local/cuda-10.0/include/CL/cl_ext.h" "$(@D)/cuda/include/CL/cl_ext.h" && cp -f "/usr/local/cuda-10.0/include/CL/cl_gl.h" "$(@D)/cuda/include/CL/cl_gl.h" && cp -f "/usr/local/cuda-10.0/include/CL/cl_gl_ext.h" "$(@D)/cuda/include/CL/cl_gl_ext.h" && cp -f "/usr/local/cuda-10.0/include/CL/cl_platform.h" "$(@D)/cuda/include/CL/cl_platform.h" && cp -f "/usr/local/cuda-10.0/include/CL/opencl.h" "$(@D)/cuda/include/CL/opencl.h" && cp -f "/usr/local/cuda-10.0/include/builtin_types.h" "$(@D)/cuda/include/builtin_types.h" && cp -f "/usr/local/cuda-10.0/include/channel_descriptor.h" "$(@D)/cuda/include/channel_descriptor.h" && cp -f "/usr/local/cuda-10.0/include/common_functions.h" "$(@D)/cuda/include/common_functions.h" && cp -f "/usr/local/cuda-10.0/include/cooperative_groups.h" "$(@D)/cuda/include/cooperative_groups.h" && cp -f "/usr/local/cuda-10.0/include/cooperative_groups_helpers.h" "$(@D)/cuda/include/cooperative_groups_helpers.h" && cp -f "/usr/local/cuda-10.0/include/crt/common_functions.h" "$(@D)/cuda/include/crt/common_functions.h" && cp -f "/usr/local/cuda-10.0/include/crt/device_double_functions.h" "$(@D)/cuda/include/crt/device_double_functions.h" && cp -f "/usr/local/cuda-10.0/include/crt/device_double_functions.hpp" "$(@D)/cuda/include/crt/device_double_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/crt/device_functions.h" "$(@D)/cuda/include/crt/device_functions.h" && cp -f "/usr/local/cuda-10.0/include/crt/device_functions.hpp" "$(@D)/cuda/include/crt/device_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/crt/func_macro.h" "$(@D)/cuda/include/crt/func_macro.h" && cp -f "/usr/local/cuda-10.0/include/crt/host_config.h" "$(@D)/cuda/include/crt/host_config.h" && cp -f "/usr/local/cuda-10.0/include/crt/host_defines.h" "$(@D)/cuda/include/crt/host_defines.h" && cp -f "/usr/local/cuda-10.0/include/crt/host_runtime.h" "$(@D)/cuda/include/crt/host_runtime.h" && cp -f "/usr/local/cuda-10.0/include/crt/math_functions.h" "$(@D)/cuda/include/crt/math_functions.h" && cp -f "/usr/local/cuda-10.0/include/crt/math_functions.hpp" "$(@D)/cuda/include/crt/math_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/crt/mma.h" "$(@D)/cuda/include/crt/mma.h" && cp -f "/usr/local/cuda-10.0/include/crt/mma.hpp" "$(@D)/cuda/include/crt/mma.hpp" && cp -f "/usr/local/cuda-10.0/include/crt/nvfunctional" "$(@D)/cuda/include/crt/nvfunctional" && cp -f "/usr/local/cuda-10.0/include/crt/sm_70_rt.h" "$(@D)/cuda/include/crt/sm_70_rt.h" && cp -f "/usr/local/cuda-10.0/include/crt/sm_70_rt.hpp" "$(@D)/cuda/include/crt/sm_70_rt.hpp" && cp -f "/usr/local/cuda-10.0/include/crt/storage_class.h" "$(@D)/cuda/include/crt/storage_class.h" && cp -f "/usr/local/cuda-10.0/include/cuComplex.h" "$(@D)/cuda/include/cuComplex.h" && cp -f "/usr/local/cuda-10.0/include/cublas.h" "$(@D)/cuda/include/cublas.h" && cp -f "/usr/local/cuda-10.0/include/cublasXt.h" "$(@D)/cuda/include/cublasXt.h" && cp -f "/usr/local/cuda-10.0/include/cublas_api.h" "$(@D)/cuda/include/cublas_api.h" && cp -f "/usr/local/cuda-10.0/include/cublas_v2.h" "$(@D)/cuda/include/cublas_v2.h" && cp -f "/usr/local/cuda-10.0/include/cuda.h" "$(@D)/cuda/include/cuda.h" && cp -f "/usr/local/cuda-10.0/include/cudaEGL.h" "$(@D)/cuda/include/cudaEGL.h" && cp -f "/usr/local/cuda-10.0/include/cudaGL.h" "$(@D)/cuda/include/cudaGL.h" && cp -f "/usr/local/cuda-10.0/include/cudaProfiler.h" "$(@D)/cuda/include/cudaProfiler.h" && cp -f "/usr/local/cuda-10.0/include/cudaVDPAU.h" "$(@D)/cuda/include/cudaVDPAU.h" && cp -f "/usr/local/cuda-10.0/include/cuda_device_runtime_api.h" "$(@D)/cuda/include/cuda_device_runtime_api.h" && cp -f "/usr/local/cuda-10.0/include/cuda_egl_interop.h" "$(@D)/cuda/include/cuda_egl_interop.h" && cp -f "/usr/local/cuda-10.0/include/cuda_fp16.h" "$(@D)/cuda/include/cuda_fp16.h" && cp -f "/usr/local/cuda-10.0/include/cuda_fp16.hpp" "$(@D)/cuda/include/cuda_fp16.hpp" && cp -f "/usr/local/cuda-10.0/include/cuda_gl_interop.h" "$(@D)/cuda/include/cuda_gl_interop.h" && cp -f "/usr/local/cuda-10.0/include/cuda_occupancy.h" "$(@D)/cuda/include/cuda_occupancy.h" && cp -f "/usr/local/cuda-10.0/include/cuda_profiler_api.h" "$(@D)/cuda/include/cuda_profiler_api.h" && cp -f "/usr/local/cuda-10.0/include/cuda_runtime.h" "$(@D)/cuda/include/cuda_runtime.h" && cp -f "/usr/local/cuda-10.0/include/cuda_runtime_api.h" "$(@D)/cuda/include/cuda_runtime_api.h" && cp -f "/usr/local/cuda-10.0/include/cuda_surface_types.h" "$(@D)/cuda/include/cuda_surface_types.h" && cp -f "/usr/local/cuda-10.0/include/cuda_texture_types.h" "$(@D)/cuda/include/cuda_texture_types.h" && cp -f "/usr/local/cuda-10.0/include/cuda_vdpau_interop.h" "$(@D)/cuda/include/cuda_vdpau_interop.h" && cp -f "/usr/local/cuda-10.0/include/cudalibxt.h" "$(@D)/cuda/include/cudalibxt.h" && cp -f "/usr/local/cuda-10.0/include/cudart_platform.h" "$(@D)/cuda/include/cudart_platform.h" && cp -f "/usr/local/cuda-10.0/include/cufft.h" "$(@D)/cuda/include/cufft.h" && cp -f "/usr/local/cuda-10.0/include/cufftXt.h" "$(@D)/cuda/include/cufftXt.h" && cp -f "/usr/local/cuda-10.0/include/cufftw.h" "$(@D)/cuda/include/cufftw.h" && cp -f "/usr/local/cuda-10.0/include/curand.h" "$(@D)/cuda/include/curand.h" && cp -f "/usr/local/cuda-10.0/include/curand_discrete.h" "$(@D)/cuda/include/curand_discrete.h" && cp -f "/usr/local/cuda-10.0/include/curand_discrete2.h" "$(@D)/cuda/include/curand_discrete2.h" && cp -f "/usr/local/cuda-10.0/include/curand_globals.h" "$(@D)/cuda/include/curand_globals.h" && cp -f "/usr/local/cuda-10.0/include/curand_kernel.h" "$(@D)/cuda/include/curand_kernel.h" && cp -f "/usr/local/cuda-10.0/include/curand_lognormal.h" "$(@D)/cuda/include/curand_lognormal.h" && cp -f "/usr/local/cuda-10.0/include/curand_mrg32k3a.h" "$(@D)/cuda/include/curand_mrg32k3a.h" && cp -f "/usr/local/cuda-10.0/include/curand_mtgp32.h" "$(@D)/cuda/include/curand_mtgp32.h" && cp -f "/usr/local/cuda-10.0/include/curand_mtgp32_host.h" "$(@D)/cuda/include/curand_mtgp32_host.h" && cp -f "/usr/local/cuda-10.0/include/curand_mtgp32_kernel.h" "$(@D)/cuda/include/curand_mtgp32_kernel.h" && cp -f "/usr/local/cuda-10.0/include/curand_mtgp32dc_p_11213.h" "$(@D)/cuda/include/curand_mtgp32dc_p_11213.h" && cp -f "/usr/local/cuda-10.0/include/curand_normal.h" "$(@D)/cuda/include/curand_normal.h" && cp -f "/usr/local/cuda-10.0/include/curand_normal_static.h" "$(@D)/cuda/include/curand_normal_static.h" && cp -f "/usr/local/cuda-10.0/include/curand_philox4x32_x.h" "$(@D)/cuda/include/curand_philox4x32_x.h" && cp -f "/usr/local/cuda-10.0/include/curand_poisson.h" "$(@D)/cuda/include/curand_poisson.h" && cp -f "/usr/local/cuda-10.0/include/curand_precalc.h" "$(@D)/cuda/include/curand_precalc.h" && cp -f "/usr/local/cuda-10.0/include/curand_uniform.h" "$(@D)/cuda/include/curand_uniform.h" && cp -f "/usr/local/cuda-10.0/include/cusolverDn.h" "$(@D)/cuda/include/cusolverDn.h" && cp -f "/usr/local/cuda-10.0/include/cusolverRf.h" "$(@D)/cuda/include/cusolverRf.h" && cp -f "/usr/local/cuda-10.0/include/cusolverSp.h" "$(@D)/cuda/include/cusolverSp.h" && cp -f "/usr/local/cuda-10.0/include/cusolverSp_LOWLEVEL_PREVIEW.h" "$(@D)/cuda/include/cusolverSp_LOWLEVEL_PREVIEW.h" && cp -f "/usr/local/cuda-10.0/include/cusolver_common.h" "$(@D)/cuda/include/cusolver_common.h" && cp -f "/usr/local/cuda-10.0/include/cusparse.h" "$(@D)/cuda/include/cusparse.h" && cp -f "/usr/local/cuda-10.0/include/cusparse_v2.h" "$(@D)/cuda/include/cusparse_v2.h" && cp -f "/usr/local/cuda-10.0/include/device_atomic_functions.h" "$(@D)/cuda/include/device_atomic_functions.h" && cp -f "/usr/local/cuda-10.0/include/device_atomic_functions.hpp" "$(@D)/cuda/include/device_atomic_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/device_double_functions.h" "$(@D)/cuda/include/device_double_functions.h" && cp -f "/usr/local/cuda-10.0/include/device_functions.h" "$(@D)/cuda/include/device_functions.h" && cp -f "/usr/local/cuda-10.0/include/device_launch_parameters.h" "$(@D)/cuda/include/device_launch_parameters.h" && cp -f "/usr/local/cuda-10.0/include/device_types.h" "$(@D)/cuda/include/device_types.h" && cp -f "/usr/local/cuda-10.0/include/driver_functions.h" "$(@D)/cuda/include/driver_functions.h" && cp -f "/usr/local/cuda-10.0/include/driver_types.h" "$(@D)/cuda/include/driver_types.h" && cp -f "/usr/local/cuda-10.0/include/fatBinaryCtl.h" "$(@D)/cuda/include/fatBinaryCtl.h" && cp -f "/usr/local/cuda-10.0/include/fatbinary.h" "$(@D)/cuda/include/fatbinary.h" && cp -f "/usr/local/cuda-10.0/include/host_config.h" "$(@D)/cuda/include/host_config.h" && cp -f "/usr/local/cuda-10.0/include/host_defines.h" "$(@D)/cuda/include/host_defines.h" && cp -f "/usr/local/cuda-10.0/include/library_types.h" "$(@D)/cuda/include/library_types.h" && cp -f "/usr/local/cuda-10.0/include/math_constants.h" "$(@D)/cuda/include/math_constants.h" && cp -f "/usr/local/cuda-10.0/include/math_functions.h" "$(@D)/cuda/include/math_functions.h" && cp -f "/usr/local/cuda-10.0/include/mma.h" "$(@D)/cuda/include/mma.h" && cp -f "/usr/local/cuda-10.0/include/npp.h" "$(@D)/cuda/include/npp.h" && cp -f "/usr/local/cuda-10.0/include/nppcore.h" "$(@D)/cuda/include/nppcore.h" && cp -f "/usr/local/cuda-10.0/include/nppdefs.h" "$(@D)/cuda/include/nppdefs.h" && cp -f "/usr/local/cuda-10.0/include/nppi.h" "$(@D)/cuda/include/nppi.h" && cp -f "/usr/local/cuda-10.0/include/nppi_arithmetic_and_logical_operations.h" "$(@D)/cuda/include/nppi_arithmetic_and_logical_operations.h" && cp -f "/usr/local/cuda-10.0/include/nppi_color_conversion.h" "$(@D)/cuda/include/nppi_color_conversion.h" && cp -f "/usr/local/cuda-10.0/include/nppi_compression_functions.h" "$(@D)/cuda/include/nppi_compression_functions.h" && cp -f "/usr/local/cuda-10.0/include/nppi_computer_vision.h" "$(@D)/cuda/include/nppi_computer_vision.h" && cp -f "/usr/local/cuda-10.0/include/nppi_data_exchange_and_initialization.h" "$(@D)/cuda/include/nppi_data_exchange_and_initialization.h" && cp -f "/usr/local/cuda-10.0/include/nppi_filtering_functions.h" "$(@D)/cuda/include/nppi_filtering_functions.h" && cp -f "/usr/local/cuda-10.0/include/nppi_geometry_transforms.h" "$(@D)/cuda/include/nppi_geometry_transforms.h" && cp -f "/usr/local/cuda-10.0/include/nppi_linear_transforms.h" "$(@D)/cuda/include/nppi_linear_transforms.h" && cp -f "/usr/local/cuda-10.0/include/nppi_morphological_operations.h" "$(@D)/cuda/include/nppi_morphological_operations.h" && cp -f "/usr/local/cuda-10.0/include/nppi_statistics_functions.h" "$(@D)/cuda/include/nppi_statistics_functions.h" && cp -f "/usr/local/cuda-10.0/include/nppi_support_functions.h" "$(@D)/cuda/include/nppi_support_functions.h" && cp -f "/usr/local/cuda-10.0/include/nppi_threshold_and_compare_operations.h" "$(@D)/cuda/include/nppi_threshold_and_compare_operations.h" && cp -f "/usr/local/cuda-10.0/include/npps.h" "$(@D)/cuda/include/npps.h" && cp -f "/usr/local/cuda-10.0/include/npps_arithmetic_and_logical_operations.h" "$(@D)/cuda/include/npps_arithmetic_and_logical_operations.h" && cp -f "/usr/local/cuda-10.0/include/npps_conversion_functions.h" "$(@D)/cuda/include/npps_conversion_functions.h" && cp -f "/usr/local/cuda-10.0/include/npps_filtering_functions.h" "$(@D)/cuda/include/npps_filtering_functions.h" && cp -f "/usr/local/cuda-10.0/include/npps_initialization.h" "$(@D)/cuda/include/npps_initialization.h" && cp -f "/usr/local/cuda-10.0/include/npps_statistics_functions.h" "$(@D)/cuda/include/npps_statistics_functions.h" && cp -f "/usr/local/cuda-10.0/include/npps_support_functions.h" "$(@D)/cuda/include/npps_support_functions.h" && cp -f "/usr/local/cuda-10.0/include/nppversion.h" "$(@D)/cuda/include/nppversion.h" && cp -f "/usr/local/cuda-10.0/include/nvToolsExt.h" "$(@D)/cuda/include/nvToolsExt.h" && cp -f "/usr/local/cuda-10.0/include/nvToolsExtCuda.h" "$(@D)/cuda/include/nvToolsExtCuda.h" && cp -f "/usr/local/cuda-10.0/include/nvToolsExtCudaRt.h" "$(@D)/cuda/include/nvToolsExtCudaRt.h" && cp -f "/usr/local/cuda-10.0/include/nvToolsExtMeta.h" "$(@D)/cuda/include/nvToolsExtMeta.h" && cp -f "/usr/local/cuda-10.0/include/nvToolsExtSync.h" "$(@D)/cuda/include/nvToolsExtSync.h" && cp -f "/usr/local/cuda-10.0/include/nvblas.h" "$(@D)/cuda/include/nvblas.h" && cp -f "/usr/local/cuda-10.0/include/nvfunctional" "$(@D)/cuda/include/nvfunctional" && cp -f "/usr/local/cuda-10.0/include/nvgraph.h" "$(@D)/cuda/include/nvgraph.h" && cp -f "/usr/local/cuda-10.0/include/nvjpeg.h" "$(@D)/cuda/include/nvjpeg.h" && cp -f "/usr/local/cuda-10.0/include/nvml.h" "$(@D)/cuda/include/nvml.h" && cp -f "/usr/local/cuda-10.0/include/nvrtc.h" "$(@D)/cuda/include/nvrtc.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvToolsExt.h" "$(@D)/cuda/include/nvtx3/nvToolsExt.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvToolsExtCuda.h" "$(@D)/cuda/include/nvtx3/nvToolsExtCuda.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvToolsExtCudaRt.h" "$(@D)/cuda/include/nvtx3/nvToolsExtCudaRt.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvToolsExtOpenCL.h" "$(@D)/cuda/include/nvtx3/nvToolsExtOpenCL.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvToolsExtSync.h" "$(@D)/cuda/include/nvtx3/nvToolsExtSync.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxImpl.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxImpl.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxImplCore.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxImplCore.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxImplCudaRt_v3.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxImplCudaRt_v3.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxImplCuda_v3.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxImplCuda_v3.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxImplOpenCL_v3.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxImplOpenCL_v3.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxImplSync_v3.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxImplSync_v3.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxInit.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxInit.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxInitDecls.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxInitDecls.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxInitDefs.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxInitDefs.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxLinkOnce.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxLinkOnce.h" && cp -f "/usr/local/cuda-10.0/include/nvtx3/nvtxDetail/nvtxTypes.h" "$(@D)/cuda/include/nvtx3/nvtxDetail/nvtxTypes.h" && cp -f "/usr/local/cuda-10.0/include/sm_20_atomic_functions.h" "$(@D)/cuda/include/sm_20_atomic_functions.h" && cp -f "/usr/local/cuda-10.0/include/sm_20_atomic_functions.hpp" "$(@D)/cuda/include/sm_20_atomic_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/sm_20_intrinsics.h" "$(@D)/cuda/include/sm_20_intrinsics.h" && cp -f "/usr/local/cuda-10.0/include/sm_20_intrinsics.hpp" "$(@D)/cuda/include/sm_20_intrinsics.hpp" && cp -f "/usr/local/cuda-10.0/include/sm_30_intrinsics.h" "$(@D)/cuda/include/sm_30_intrinsics.h" && cp -f "/usr/local/cuda-10.0/include/sm_30_intrinsics.hpp" "$(@D)/cuda/include/sm_30_intrinsics.hpp" && cp -f "/usr/local/cuda-10.0/include/sm_32_atomic_functions.h" "$(@D)/cuda/include/sm_32_atomic_functions.h" && cp -f "/usr/local/cuda-10.0/include/sm_32_atomic_functions.hpp" "$(@D)/cuda/include/sm_32_atomic_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/sm_32_intrinsics.h" "$(@D)/cuda/include/sm_32_intrinsics.h" && cp -f "/usr/local/cuda-10.0/include/sm_32_intrinsics.hpp" "$(@D)/cuda/include/sm_32_intrinsics.hpp" && cp -f "/usr/local/cuda-10.0/include/sm_35_atomic_functions.h" "$(@D)/cuda/include/sm_35_atomic_functions.h" && cp -f "/usr/local/cuda-10.0/include/sm_35_intrinsics.h" "$(@D)/cuda/include/sm_35_intrinsics.h" && cp -f "/usr/local/cuda-10.0/include/sm_60_atomic_functions.h" "$(@D)/cuda/include/sm_60_atomic_functions.h" && cp -f "/usr/local/cuda-10.0/include/sm_60_atomic_functions.hpp" "$(@D)/cuda/include/sm_60_atomic_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/sm_61_intrinsics.h" "$(@D)/cuda/include/sm_61_intrinsics.h" && cp -f "/usr/local/cuda-10.0/include/sm_61_intrinsics.hpp" "$(@D)/cuda/include/sm_61_intrinsics.hpp" && cp -f "/usr/local/cuda-10.0/include/sobol_direction_vectors.h" "$(@D)/cuda/include/sobol_direction_vectors.h" && cp -f "/usr/local/cuda-10.0/include/surface_functions.h" "$(@D)/cuda/include/surface_functions.h" && cp -f "/usr/local/cuda-10.0/include/surface_functions.hpp" "$(@D)/cuda/include/surface_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/surface_indirect_functions.h" "$(@D)/cuda/include/surface_indirect_functions.h" && cp -f "/usr/local/cuda-10.0/include/surface_indirect_functions.hpp" "$(@D)/cuda/include/surface_indirect_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/surface_types.h" "$(@D)/cuda/include/surface_types.h" && cp -f "/usr/local/cuda-10.0/include/texture_fetch_functions.h" "$(@D)/cuda/include/texture_fetch_functions.h" && cp -f "/usr/local/cuda-10.0/include/texture_fetch_functions.hpp" "$(@D)/cuda/include/texture_fetch_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/texture_indirect_functions.h" "$(@D)/cuda/include/texture_indirect_functions.h" && cp -f "/usr/local/cuda-10.0/include/texture_indirect_functions.hpp" "$(@D)/cuda/include/texture_indirect_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/texture_types.h" "$(@D)/cuda/include/texture_types.h" && cp -f "/usr/local/cuda-10.0/include/thrust/adjacent_difference.h" "$(@D)/cuda/include/thrust/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/advance.h" "$(@D)/cuda/include/thrust/advance.h" && cp -f "/usr/local/cuda-10.0/include/thrust/binary_search.h" "$(@D)/cuda/include/thrust/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/complex.h" "$(@D)/cuda/include/thrust/complex.h" && cp -f "/usr/local/cuda-10.0/include/thrust/copy.h" "$(@D)/cuda/include/thrust/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/count.h" "$(@D)/cuda/include/thrust/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/adjacent_difference.inl" "$(@D)/cuda/include/thrust/detail/adjacent_difference.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/advance.inl" "$(@D)/cuda/include/thrust/detail/advance.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/alignment.h" "$(@D)/cuda/include/thrust/detail/alignment.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/allocator_traits.h" "$(@D)/cuda/include/thrust/detail/allocator/allocator_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/allocator_traits.inl" "$(@D)/cuda/include/thrust/detail/allocator/allocator_traits.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/copy_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/copy_construct_range.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/copy_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/copy_construct_range.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/default_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/default_construct_range.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/default_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/default_construct_range.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/destroy_range.h" "$(@D)/cuda/include/thrust/detail/allocator/destroy_range.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/destroy_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/destroy_range.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/fill_construct_range.h" "$(@D)/cuda/include/thrust/detail/allocator/fill_construct_range.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/fill_construct_range.inl" "$(@D)/cuda/include/thrust/detail/allocator/fill_construct_range.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/malloc_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/malloc_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/malloc_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/malloc_allocator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/no_throw_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/no_throw_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/tagged_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/tagged_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/tagged_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/tagged_allocator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/temporary_allocator.h" "$(@D)/cuda/include/thrust/detail/allocator/temporary_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/allocator/temporary_allocator.inl" "$(@D)/cuda/include/thrust/detail/allocator/temporary_allocator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/binary_search.inl" "$(@D)/cuda/include/thrust/detail/binary_search.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/arithmetic.h" "$(@D)/cuda/include/thrust/detail/complex/arithmetic.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/c99math.h" "$(@D)/cuda/include/thrust/detail/complex/c99math.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/catrig.h" "$(@D)/cuda/include/thrust/detail/complex/catrig.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/catrigf.h" "$(@D)/cuda/include/thrust/detail/complex/catrigf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/ccosh.h" "$(@D)/cuda/include/thrust/detail/complex/ccosh.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/ccoshf.h" "$(@D)/cuda/include/thrust/detail/complex/ccoshf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/cexp.h" "$(@D)/cuda/include/thrust/detail/complex/cexp.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/cexpf.h" "$(@D)/cuda/include/thrust/detail/complex/cexpf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/clog.h" "$(@D)/cuda/include/thrust/detail/complex/clog.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/clogf.h" "$(@D)/cuda/include/thrust/detail/complex/clogf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/complex.inl" "$(@D)/cuda/include/thrust/detail/complex/complex.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/cpow.h" "$(@D)/cuda/include/thrust/detail/complex/cpow.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/cproj.h" "$(@D)/cuda/include/thrust/detail/complex/cproj.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/csinh.h" "$(@D)/cuda/include/thrust/detail/complex/csinh.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/csinhf.h" "$(@D)/cuda/include/thrust/detail/complex/csinhf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/csqrt.h" "$(@D)/cuda/include/thrust/detail/complex/csqrt.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/csqrtf.h" "$(@D)/cuda/include/thrust/detail/complex/csqrtf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/ctanh.h" "$(@D)/cuda/include/thrust/detail/complex/ctanh.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/ctanhf.h" "$(@D)/cuda/include/thrust/detail/complex/ctanhf.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/math_private.h" "$(@D)/cuda/include/thrust/detail/complex/math_private.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/complex/stream.h" "$(@D)/cuda/include/thrust/detail/complex/stream.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config.h" "$(@D)/cuda/include/thrust/detail/config.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/compiler.h" "$(@D)/cuda/include/thrust/detail/config/compiler.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/compiler_fence.h" "$(@D)/cuda/include/thrust/detail/config/compiler_fence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/config.h" "$(@D)/cuda/include/thrust/detail/config/config.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/debug.h" "$(@D)/cuda/include/thrust/detail/config/debug.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/device_system.h" "$(@D)/cuda/include/thrust/detail/config/device_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/exec_check_disable.h" "$(@D)/cuda/include/thrust/detail/config/exec_check_disable.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/forceinline.h" "$(@D)/cuda/include/thrust/detail/config/forceinline.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/global_workarounds.h" "$(@D)/cuda/include/thrust/detail/config/global_workarounds.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/host_device.h" "$(@D)/cuda/include/thrust/detail/config/host_device.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/host_system.h" "$(@D)/cuda/include/thrust/detail/config/host_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/config/simple_defines.h" "$(@D)/cuda/include/thrust/detail/config/simple_defines.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/contiguous_storage.h" "$(@D)/cuda/include/thrust/detail/contiguous_storage.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/contiguous_storage.inl" "$(@D)/cuda/include/thrust/detail/contiguous_storage.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/copy.h" "$(@D)/cuda/include/thrust/detail/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/copy.inl" "$(@D)/cuda/include/thrust/detail/copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/copy_if.h" "$(@D)/cuda/include/thrust/detail/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/copy_if.inl" "$(@D)/cuda/include/thrust/detail/copy_if.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/count.inl" "$(@D)/cuda/include/thrust/detail/count.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/cstdint.h" "$(@D)/cuda/include/thrust/detail/cstdint.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_delete.inl" "$(@D)/cuda/include/thrust/detail/device_delete.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_free.inl" "$(@D)/cuda/include/thrust/detail/device_free.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_malloc.inl" "$(@D)/cuda/include/thrust/detail/device_malloc.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_new.inl" "$(@D)/cuda/include/thrust/detail/device_new.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_ptr.inl" "$(@D)/cuda/include/thrust/detail/device_ptr.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_reference.inl" "$(@D)/cuda/include/thrust/detail/device_reference.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/device_vector.inl" "$(@D)/cuda/include/thrust/detail/device_vector.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/dispatch/is_trivial_copy.h" "$(@D)/cuda/include/thrust/detail/dispatch/is_trivial_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/distance.inl" "$(@D)/cuda/include/thrust/detail/distance.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/equal.inl" "$(@D)/cuda/include/thrust/detail/equal.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/execute_with_allocator.h" "$(@D)/cuda/include/thrust/detail/execute_with_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/execution_policy.h" "$(@D)/cuda/include/thrust/detail/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/extrema.inl" "$(@D)/cuda/include/thrust/detail/extrema.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/fill.inl" "$(@D)/cuda/include/thrust/detail/fill.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/find.inl" "$(@D)/cuda/include/thrust/detail/find.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/for_each.inl" "$(@D)/cuda/include/thrust/detail/for_each.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/function.h" "$(@D)/cuda/include/thrust/detail/function.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional.inl" "$(@D)/cuda/include/thrust/detail/functional.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/actor.h" "$(@D)/cuda/include/thrust/detail/functional/actor.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/actor.inl" "$(@D)/cuda/include/thrust/detail/functional/actor.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/argument.h" "$(@D)/cuda/include/thrust/detail/functional/argument.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/composite.h" "$(@D)/cuda/include/thrust/detail/functional/composite.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/arithmetic_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/arithmetic_operators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/assignment_operator.h" "$(@D)/cuda/include/thrust/detail/functional/operators/assignment_operator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/bitwise_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/bitwise_operators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/compound_assignment_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/compound_assignment_operators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/logical_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/logical_operators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/operator_adaptors.h" "$(@D)/cuda/include/thrust/detail/functional/operators/operator_adaptors.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/operators/relational_operators.h" "$(@D)/cuda/include/thrust/detail/functional/operators/relational_operators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/placeholder.h" "$(@D)/cuda/include/thrust/detail/functional/placeholder.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/functional/value.h" "$(@D)/cuda/include/thrust/detail/functional/value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/gather.inl" "$(@D)/cuda/include/thrust/detail/gather.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/generate.inl" "$(@D)/cuda/include/thrust/detail/generate.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/get_iterator_value.h" "$(@D)/cuda/include/thrust/detail/get_iterator_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/host_vector.inl" "$(@D)/cuda/include/thrust/detail/host_vector.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/inner_product.inl" "$(@D)/cuda/include/thrust/detail/inner_product.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/integer_math.h" "$(@D)/cuda/include/thrust/detail/integer_math.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/integer_traits.h" "$(@D)/cuda/include/thrust/detail/integer_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/internal_functional.h" "$(@D)/cuda/include/thrust/detail/internal_functional.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/logical.inl" "$(@D)/cuda/include/thrust/detail/logical.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/merge.inl" "$(@D)/cuda/include/thrust/detail/merge.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/minmax.h" "$(@D)/cuda/include/thrust/detail/minmax.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/mismatch.inl" "$(@D)/cuda/include/thrust/detail/mismatch.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/mpl/math.h" "$(@D)/cuda/include/thrust/detail/mpl/math.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/numeric_traits.h" "$(@D)/cuda/include/thrust/detail/numeric_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/overlapped_copy.h" "$(@D)/cuda/include/thrust/detail/overlapped_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/pair.inl" "$(@D)/cuda/include/thrust/detail/pair.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/partition.inl" "$(@D)/cuda/include/thrust/detail/partition.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/pointer.h" "$(@D)/cuda/include/thrust/detail/pointer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/pointer.inl" "$(@D)/cuda/include/thrust/detail/pointer.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/preprocessor.h" "$(@D)/cuda/include/thrust/detail/preprocessor.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/range/head_flags.h" "$(@D)/cuda/include/thrust/detail/range/head_flags.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/range/tail_flags.h" "$(@D)/cuda/include/thrust/detail/range/tail_flags.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/raw_pointer_cast.h" "$(@D)/cuda/include/thrust/detail/raw_pointer_cast.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/raw_reference_cast.h" "$(@D)/cuda/include/thrust/detail/raw_reference_cast.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/reduce.inl" "$(@D)/cuda/include/thrust/detail/reduce.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/reference.h" "$(@D)/cuda/include/thrust/detail/reference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/reference.inl" "$(@D)/cuda/include/thrust/detail/reference.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/reference_forward_declaration.h" "$(@D)/cuda/include/thrust/detail/reference_forward_declaration.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/remove.inl" "$(@D)/cuda/include/thrust/detail/remove.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/replace.inl" "$(@D)/cuda/include/thrust/detail/replace.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/reverse.inl" "$(@D)/cuda/include/thrust/detail/reverse.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/scan.inl" "$(@D)/cuda/include/thrust/detail/scan.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/scatter.inl" "$(@D)/cuda/include/thrust/detail/scatter.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/seq.h" "$(@D)/cuda/include/thrust/detail/seq.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/sequence.inl" "$(@D)/cuda/include/thrust/detail/sequence.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/set_operations.inl" "$(@D)/cuda/include/thrust/detail/set_operations.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/sort.inl" "$(@D)/cuda/include/thrust/detail/sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/static_assert.h" "$(@D)/cuda/include/thrust/detail/static_assert.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/static_map.h" "$(@D)/cuda/include/thrust/detail/static_map.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/swap.h" "$(@D)/cuda/include/thrust/detail/swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/swap.inl" "$(@D)/cuda/include/thrust/detail/swap.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/swap_ranges.inl" "$(@D)/cuda/include/thrust/detail/swap_ranges.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/tabulate.inl" "$(@D)/cuda/include/thrust/detail/tabulate.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/temporary_array.h" "$(@D)/cuda/include/thrust/detail/temporary_array.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/temporary_array.inl" "$(@D)/cuda/include/thrust/detail/temporary_array.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/transform.inl" "$(@D)/cuda/include/thrust/detail/transform.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/transform_reduce.inl" "$(@D)/cuda/include/thrust/detail/transform_reduce.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/transform_scan.inl" "$(@D)/cuda/include/thrust/detail/transform_scan.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/trivial_sequence.h" "$(@D)/cuda/include/thrust/detail/trivial_sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/tuple.inl" "$(@D)/cuda/include/thrust/detail/tuple.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/tuple_meta_transform.h" "$(@D)/cuda/include/thrust/detail/tuple_meta_transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/tuple_transform.h" "$(@D)/cuda/include/thrust/detail/tuple_transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h" "$(@D)/cuda/include/thrust/detail/type_traits/algorithm/intermediate_type_from_function_and_iterators.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/function_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits/function_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/has_member_function.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_member_function.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/has_nested_type.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_nested_type.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/has_trivial_assign.h" "$(@D)/cuda/include/thrust/detail/type_traits/has_trivial_assign.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/is_call_possible.h" "$(@D)/cuda/include/thrust/detail/type_traits/is_call_possible.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/is_metafunction_defined.h" "$(@D)/cuda/include/thrust/detail/type_traits/is_metafunction_defined.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/iterator/is_discard_iterator.h" "$(@D)/cuda/include/thrust/detail/type_traits/iterator/is_discard_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/iterator/is_output_iterator.h" "$(@D)/cuda/include/thrust/detail/type_traits/iterator/is_output_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/minimum_type.h" "$(@D)/cuda/include/thrust/detail/type_traits/minimum_type.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/pointer_traits.h" "$(@D)/cuda/include/thrust/detail/type_traits/pointer_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/type_traits/result_of_adaptable_function.h" "$(@D)/cuda/include/thrust/detail/type_traits/result_of_adaptable_function.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/uninitialized_copy.inl" "$(@D)/cuda/include/thrust/detail/uninitialized_copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/uninitialized_fill.inl" "$(@D)/cuda/include/thrust/detail/uninitialized_fill.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/unique.inl" "$(@D)/cuda/include/thrust/detail/unique.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/use_default.h" "$(@D)/cuda/include/thrust/detail/use_default.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/util/align.h" "$(@D)/cuda/include/thrust/detail/util/align.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/util/blocking.h" "$(@D)/cuda/include/thrust/detail/util/blocking.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/vector_base.h" "$(@D)/cuda/include/thrust/detail/vector_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/detail/vector_base.inl" "$(@D)/cuda/include/thrust/detail/vector_base.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/device_allocator.h" "$(@D)/cuda/include/thrust/device_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_delete.h" "$(@D)/cuda/include/thrust/device_delete.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_free.h" "$(@D)/cuda/include/thrust/device_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_malloc.h" "$(@D)/cuda/include/thrust/device_malloc.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_malloc_allocator.h" "$(@D)/cuda/include/thrust/device_malloc_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_new.h" "$(@D)/cuda/include/thrust/device_new.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_new_allocator.h" "$(@D)/cuda/include/thrust/device_new_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_ptr.h" "$(@D)/cuda/include/thrust/device_ptr.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_reference.h" "$(@D)/cuda/include/thrust/device_reference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/device_vector.h" "$(@D)/cuda/include/thrust/device_vector.h" && cp -f "/usr/local/cuda-10.0/include/thrust/distance.h" "$(@D)/cuda/include/thrust/distance.h" && cp -f "/usr/local/cuda-10.0/include/thrust/equal.h" "$(@D)/cuda/include/thrust/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/execution_policy.h" "$(@D)/cuda/include/thrust/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/extrema.h" "$(@D)/cuda/include/thrust/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/fill.h" "$(@D)/cuda/include/thrust/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/find.h" "$(@D)/cuda/include/thrust/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/for_each.h" "$(@D)/cuda/include/thrust/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/functional.h" "$(@D)/cuda/include/thrust/functional.h" && cp -f "/usr/local/cuda-10.0/include/thrust/gather.h" "$(@D)/cuda/include/thrust/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/generate.h" "$(@D)/cuda/include/thrust/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/host_vector.h" "$(@D)/cuda/include/thrust/host_vector.h" && cp -f "/usr/local/cuda-10.0/include/thrust/inner_product.h" "$(@D)/cuda/include/thrust/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/constant_iterator.h" "$(@D)/cuda/include/thrust/iterator/constant_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/counting_iterator.h" "$(@D)/cuda/include/thrust/iterator/counting_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/any_assign.h" "$(@D)/cuda/include/thrust/iterator/detail/any_assign.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/any_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/any_system_tag.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/constant_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/constant_iterator_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/counting_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/counting_iterator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/device_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/device_system_tag.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/discard_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/discard_iterator_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/distance_from_result.h" "$(@D)/cuda/include/thrust/iterator/detail/distance_from_result.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/host_system_tag.h" "$(@D)/cuda/include/thrust/iterator/detail/host_system_tag.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/is_iterator_category.h" "$(@D)/cuda/include/thrust/iterator/detail/is_iterator_category.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/is_trivial_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/is_trivial_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_adaptor_base.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_adaptor_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_category_to_system.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_to_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_category_to_traversal.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_to_traversal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_category_with_system_and_traversal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_facade_category.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_facade_category.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_traits.inl" "$(@D)/cuda/include/thrust/iterator/detail/iterator_traits.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/iterator_traversal_tags.h" "$(@D)/cuda/include/thrust/iterator/detail/iterator_traversal_tags.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/join_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/join_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/minimum_category.h" "$(@D)/cuda/include/thrust/iterator/detail/minimum_category.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/minimum_system.h" "$(@D)/cuda/include/thrust/iterator/detail/minimum_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/normal_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/normal_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/permutation_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/permutation_iterator_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/retag.h" "$(@D)/cuda/include/thrust/iterator/detail/retag.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/reverse_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/reverse_iterator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/reverse_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/reverse_iterator_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/tagged_iterator.h" "$(@D)/cuda/include/thrust/iterator/detail/tagged_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/transform_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/transform_iterator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/transform_output_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/transform_output_iterator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/tuple_of_iterator_references.h" "$(@D)/cuda/include/thrust/iterator/detail/tuple_of_iterator_references.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/universal_categories.h" "$(@D)/cuda/include/thrust/iterator/detail/universal_categories.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/zip_iterator.inl" "$(@D)/cuda/include/thrust/iterator/detail/zip_iterator.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/detail/zip_iterator_base.h" "$(@D)/cuda/include/thrust/iterator/detail/zip_iterator_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/discard_iterator.h" "$(@D)/cuda/include/thrust/iterator/discard_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/iterator_adaptor.h" "$(@D)/cuda/include/thrust/iterator/iterator_adaptor.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/iterator_categories.h" "$(@D)/cuda/include/thrust/iterator/iterator_categories.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/iterator_facade.h" "$(@D)/cuda/include/thrust/iterator/iterator_facade.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/iterator_traits.h" "$(@D)/cuda/include/thrust/iterator/iterator_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/permutation_iterator.h" "$(@D)/cuda/include/thrust/iterator/permutation_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/retag.h" "$(@D)/cuda/include/thrust/iterator/retag.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/reverse_iterator.h" "$(@D)/cuda/include/thrust/iterator/reverse_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/transform_iterator.h" "$(@D)/cuda/include/thrust/iterator/transform_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/transform_output_iterator.h" "$(@D)/cuda/include/thrust/iterator/transform_output_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/iterator/zip_iterator.h" "$(@D)/cuda/include/thrust/iterator/zip_iterator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/logical.h" "$(@D)/cuda/include/thrust/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/memory.h" "$(@D)/cuda/include/thrust/memory.h" && cp -f "/usr/local/cuda-10.0/include/thrust/merge.h" "$(@D)/cuda/include/thrust/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/mismatch.h" "$(@D)/cuda/include/thrust/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/pair.h" "$(@D)/cuda/include/thrust/pair.h" && cp -f "/usr/local/cuda-10.0/include/thrust/partition.h" "$(@D)/cuda/include/thrust/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random.h" "$(@D)/cuda/include/thrust/random.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/discard_block_engine.inl" "$(@D)/cuda/include/thrust/random/detail/discard_block_engine.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/linear_congruential_engine.inl" "$(@D)/cuda/include/thrust/random/detail/linear_congruential_engine.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/linear_congruential_engine_discard.h" "$(@D)/cuda/include/thrust/random/detail/linear_congruential_engine_discard.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/linear_feedback_shift_engine.inl" "$(@D)/cuda/include/thrust/random/detail/linear_feedback_shift_engine.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h" "$(@D)/cuda/include/thrust/random/detail/linear_feedback_shift_engine_wordmask.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/mod.h" "$(@D)/cuda/include/thrust/random/detail/mod.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/normal_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/normal_distribution.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/normal_distribution_base.h" "$(@D)/cuda/include/thrust/random/detail/normal_distribution_base.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/random_core_access.h" "$(@D)/cuda/include/thrust/random/detail/random_core_access.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/subtract_with_carry_engine.inl" "$(@D)/cuda/include/thrust/random/detail/subtract_with_carry_engine.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/uniform_int_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/uniform_int_distribution.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/uniform_real_distribution.inl" "$(@D)/cuda/include/thrust/random/detail/uniform_real_distribution.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/xor_combine_engine.inl" "$(@D)/cuda/include/thrust/random/detail/xor_combine_engine.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/random/detail/xor_combine_engine_max.h" "$(@D)/cuda/include/thrust/random/detail/xor_combine_engine_max.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/discard_block_engine.h" "$(@D)/cuda/include/thrust/random/discard_block_engine.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/linear_congruential_engine.h" "$(@D)/cuda/include/thrust/random/linear_congruential_engine.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/linear_feedback_shift_engine.h" "$(@D)/cuda/include/thrust/random/linear_feedback_shift_engine.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/normal_distribution.h" "$(@D)/cuda/include/thrust/random/normal_distribution.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/subtract_with_carry_engine.h" "$(@D)/cuda/include/thrust/random/subtract_with_carry_engine.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/uniform_int_distribution.h" "$(@D)/cuda/include/thrust/random/uniform_int_distribution.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/uniform_real_distribution.h" "$(@D)/cuda/include/thrust/random/uniform_real_distribution.h" && cp -f "/usr/local/cuda-10.0/include/thrust/random/xor_combine_engine.h" "$(@D)/cuda/include/thrust/random/xor_combine_engine.h" && cp -f "/usr/local/cuda-10.0/include/thrust/reduce.h" "$(@D)/cuda/include/thrust/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/remove.h" "$(@D)/cuda/include/thrust/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/replace.h" "$(@D)/cuda/include/thrust/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/reverse.h" "$(@D)/cuda/include/thrust/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/scan.h" "$(@D)/cuda/include/thrust/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/scatter.h" "$(@D)/cuda/include/thrust/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/sequence.h" "$(@D)/cuda/include/thrust/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/set_operations.h" "$(@D)/cuda/include/thrust/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/sort.h" "$(@D)/cuda/include/thrust/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/swap.h" "$(@D)/cuda/include/thrust/swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/cpp/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/cpp/detail/assign_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/cpp/detail/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/copy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/cpp/detail/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/count.h" "$(@D)/cuda/include/thrust/system/cpp/detail/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/equal.h" "$(@D)/cuda/include/thrust/system/cpp/detail/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/extrema.h" "$(@D)/cuda/include/thrust/system/cpp/detail/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/fill.h" "$(@D)/cuda/include/thrust/system/cpp/detail/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/find.h" "$(@D)/cuda/include/thrust/system/cpp/detail/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/for_each.h" "$(@D)/cuda/include/thrust/system/cpp/detail/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/gather.h" "$(@D)/cuda/include/thrust/system/cpp/detail/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/generate.h" "$(@D)/cuda/include/thrust/system/cpp/detail/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/get_value.h" "$(@D)/cuda/include/thrust/system/cpp/detail/get_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/cpp/detail/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/cpp/detail/iter_swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/logical.h" "$(@D)/cuda/include/thrust/system/cpp/detail/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/cpp/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/memory.inl" "$(@D)/cuda/include/thrust/system/cpp/detail/memory.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/merge.h" "$(@D)/cuda/include/thrust/system/cpp/detail/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/cpp/detail/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/par.h" "$(@D)/cuda/include/thrust/system/cpp/detail/par.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/partition.h" "$(@D)/cuda/include/thrust/system/cpp/detail/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/reduce.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/remove.h" "$(@D)/cuda/include/thrust/system/cpp/detail/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/replace.h" "$(@D)/cuda/include/thrust/system/cpp/detail/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/reverse.h" "$(@D)/cuda/include/thrust/system/cpp/detail/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/scan.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/scatter.h" "$(@D)/cuda/include/thrust/system/cpp/detail/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/sequence.h" "$(@D)/cuda/include/thrust/system/cpp/detail/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/cpp/detail/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/sort.h" "$(@D)/cuda/include/thrust/system/cpp/detail/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/cpp/detail/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/cpp/detail/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/cpp/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/transform.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/cpp/detail/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/cpp/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/cpp/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/unique.h" "$(@D)/cuda/include/thrust/system/cpp/detail/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/cpp/detail/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/detail/vector.inl" "$(@D)/cuda/include/thrust/system/cpp/detail/vector.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/execution_policy.h" "$(@D)/cuda/include/thrust/system/cpp/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/memory.h" "$(@D)/cuda/include/thrust/system/cpp/memory.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cpp/vector.h" "$(@D)/cuda/include/thrust/system/cpp/vector.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/config.h" "$(@D)/cuda/include/thrust/system/cuda/config.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/cuda/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/cuda/detail/assign_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/cuda/detail/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/copy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/cuda/detail/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/core/agent_launcher.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/agent_launcher.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/core/alignment.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/alignment.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/core/triple_chevron_launch.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/triple_chevron_launch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/core/util.h" "$(@D)/cuda/include/thrust/system/cuda/detail/core/util.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/count.h" "$(@D)/cuda/include/thrust/system/cuda/detail/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cross_system.h" "$(@D)/cuda/include/thrust/system/cuda/detail/cross_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_histogram.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_downsweep.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_radix_sort_upsweep.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_reduce_by_key.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_rle.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_scan.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_segment_fixup.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_select_if.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/agent_spmv_orig.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/agent/single_pass_scan_operators.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_adjacent_difference.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_discontinuity.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_exchange.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_histogram.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_load.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_load.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_radix_rank.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_radix_sort.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_raking_layout.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_scan.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_shuffle.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/block_store.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/block_store.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_atomic.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_histogram_sort.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_raking_commutative_only.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_reduce_warp_reductions.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_raking.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans2.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/block/specializations/block_scan_warp_scans3.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/cub.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/cub.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_histogram.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_partition.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_partition.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_radix_sort.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_run_length_encode.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_scan.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_radix_sort.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_segmented_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_select.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_select.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/device_spmv.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_histogram.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_radix_sort.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_reduce_by_key.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_rle.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_scan.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_select_if.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/device/dispatch/dispatch_spmv_orig.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_barrier.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_even_share.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_mapping.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/grid/grid_queue.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/host/mutex.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/host/mutex.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/arg_index_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/cache_modified_output_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/constant_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/counting_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/discard_output_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/tex_obj_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/tex_ref_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/iterator/transform_input_iterator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_load.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_operators.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_scan.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_search.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/thread/thread_store.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_allocator.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_allocator.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_arch.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_arch.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_debug.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_debug.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_device.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_device.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_macro.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_macro.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_namespace.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_namespace.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_ptx.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_ptx.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/util_type.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/util_type.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_shfl.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_reduce_smem.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_shfl.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/specializations/warp_scan_smem.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/warp_reduce.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh" "$(@D)/cuda/include/thrust/system/cuda/detail/cub/warp/warp_scan.cuh" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/equal.h" "$(@D)/cuda/include/thrust/system/cuda/detail/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/error.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/error.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/extrema.h" "$(@D)/cuda/include/thrust/system/cuda/detail/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/fill.h" "$(@D)/cuda/include/thrust/system/cuda/detail/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/find.h" "$(@D)/cuda/include/thrust/system/cuda/detail/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/for_each.h" "$(@D)/cuda/include/thrust/system/cuda/detail/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/gather.h" "$(@D)/cuda/include/thrust/system/cuda/detail/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/generate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/get_value.h" "$(@D)/cuda/include/thrust/system/cuda/detail/get_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h" "$(@D)/cuda/include/thrust/system/cuda/detail/guarded_cuda_runtime_api.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/guarded_driver_types.h" "$(@D)/cuda/include/thrust/system/cuda/detail/guarded_driver_types.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/cuda/detail/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/internal/copy_cross_system.h" "$(@D)/cuda/include/thrust/system/cuda/detail/internal/copy_cross_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/internal/copy_device_to_device.h" "$(@D)/cuda/include/thrust/system/cuda/detail/internal/copy_device_to_device.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/cuda/detail/iter_swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/logical.h" "$(@D)/cuda/include/thrust/system/cuda/detail/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/cuda/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/memory.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/memory.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/merge.h" "$(@D)/cuda/include/thrust/system/cuda/detail/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/cuda/detail/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/par.h" "$(@D)/cuda/include/thrust/system/cuda/detail/par.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/par_to_seq.h" "$(@D)/cuda/include/thrust/system/cuda/detail/par_to_seq.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/parallel_for.h" "$(@D)/cuda/include/thrust/system/cuda/detail/parallel_for.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/partition.h" "$(@D)/cuda/include/thrust/system/cuda/detail/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/reduce.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/remove.h" "$(@D)/cuda/include/thrust/system/cuda/detail/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/replace.h" "$(@D)/cuda/include/thrust/system/cuda/detail/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/reverse.h" "$(@D)/cuda/include/thrust/system/cuda/detail/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/scan.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/scatter.h" "$(@D)/cuda/include/thrust/system/cuda/detail/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/sequence.h" "$(@D)/cuda/include/thrust/system/cuda/detail/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/cuda/detail/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/sort.h" "$(@D)/cuda/include/thrust/system/cuda/detail/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/cuda/detail/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/cuda/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/terminate.h" "$(@D)/cuda/include/thrust/system/cuda/detail/terminate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/transform.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/cuda/detail/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/cuda/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/cuda/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/unique.h" "$(@D)/cuda/include/thrust/system/cuda/detail/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/cuda/detail/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/util.h" "$(@D)/cuda/include/thrust/system/cuda/detail/util.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/detail/vector.inl" "$(@D)/cuda/include/thrust/system/cuda/detail/vector.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/error.h" "$(@D)/cuda/include/thrust/system/cuda/error.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/execution_policy.h" "$(@D)/cuda/include/thrust/system/cuda/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/experimental/pinned_allocator.h" "$(@D)/cuda/include/thrust/system/cuda/experimental/pinned_allocator.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/memory.h" "$(@D)/cuda/include/thrust/system/cuda/memory.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/cuda/vector.h" "$(@D)/cuda/include/thrust/system/cuda/vector.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/adl/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/assign_value.h" "$(@D)/cuda/include/thrust/system/detail/adl/assign_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/adl/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/copy.h" "$(@D)/cuda/include/thrust/system/detail/adl/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/adl/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/count.h" "$(@D)/cuda/include/thrust/system/detail/adl/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/equal.h" "$(@D)/cuda/include/thrust/system/detail/adl/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/extrema.h" "$(@D)/cuda/include/thrust/system/detail/adl/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/fill.h" "$(@D)/cuda/include/thrust/system/detail/adl/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/find.h" "$(@D)/cuda/include/thrust/system/detail/adl/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/for_each.h" "$(@D)/cuda/include/thrust/system/detail/adl/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/gather.h" "$(@D)/cuda/include/thrust/system/detail/adl/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/generate.h" "$(@D)/cuda/include/thrust/system/detail/adl/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/get_value.h" "$(@D)/cuda/include/thrust/system/detail/adl/get_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/adl/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/iter_swap.h" "$(@D)/cuda/include/thrust/system/detail/adl/iter_swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/logical.h" "$(@D)/cuda/include/thrust/system/detail/adl/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/detail/adl/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/merge.h" "$(@D)/cuda/include/thrust/system/detail/adl/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/adl/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/partition.h" "$(@D)/cuda/include/thrust/system/detail/adl/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/reduce.h" "$(@D)/cuda/include/thrust/system/detail/adl/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/remove.h" "$(@D)/cuda/include/thrust/system/detail/adl/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/replace.h" "$(@D)/cuda/include/thrust/system/detail/adl/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/reverse.h" "$(@D)/cuda/include/thrust/system/detail/adl/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/scan.h" "$(@D)/cuda/include/thrust/system/detail/adl/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/scatter.h" "$(@D)/cuda/include/thrust/system/detail/adl/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/sequence.h" "$(@D)/cuda/include/thrust/system/detail/adl/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/adl/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/sort.h" "$(@D)/cuda/include/thrust/system/detail/adl/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/adl/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/adl/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/adl/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/transform.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/adl/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/adl/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/adl/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/unique.h" "$(@D)/cuda/include/thrust/system/detail/adl/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/adl/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/adl/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/bad_alloc.h" "$(@D)/cuda/include/thrust/system/detail/bad_alloc.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/errno.h" "$(@D)/cuda/include/thrust/system/detail/errno.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/error_category.inl" "$(@D)/cuda/include/thrust/system/detail/error_category.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/error_code.inl" "$(@D)/cuda/include/thrust/system/detail/error_code.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/error_condition.inl" "$(@D)/cuda/include/thrust/system/detail/error_condition.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/generic/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/adjacent_difference.inl" "$(@D)/cuda/include/thrust/system/detail/generic/adjacent_difference.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/advance.h" "$(@D)/cuda/include/thrust/system/detail/generic/advance.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/advance.inl" "$(@D)/cuda/include/thrust/system/detail/generic/advance.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/generic/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/binary_search.inl" "$(@D)/cuda/include/thrust/system/detail/generic/binary_search.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/copy.h" "$(@D)/cuda/include/thrust/system/detail/generic/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/copy.inl" "$(@D)/cuda/include/thrust/system/detail/generic/copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/generic/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/copy_if.inl" "$(@D)/cuda/include/thrust/system/detail/generic/copy_if.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/count.h" "$(@D)/cuda/include/thrust/system/detail/generic/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/count.inl" "$(@D)/cuda/include/thrust/system/detail/generic/count.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/distance.h" "$(@D)/cuda/include/thrust/system/detail/generic/distance.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/distance.inl" "$(@D)/cuda/include/thrust/system/detail/generic/distance.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/equal.h" "$(@D)/cuda/include/thrust/system/detail/generic/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/equal.inl" "$(@D)/cuda/include/thrust/system/detail/generic/equal.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/extrema.h" "$(@D)/cuda/include/thrust/system/detail/generic/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/extrema.inl" "$(@D)/cuda/include/thrust/system/detail/generic/extrema.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/fill.h" "$(@D)/cuda/include/thrust/system/detail/generic/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/find.h" "$(@D)/cuda/include/thrust/system/detail/generic/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/find.inl" "$(@D)/cuda/include/thrust/system/detail/generic/find.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/for_each.h" "$(@D)/cuda/include/thrust/system/detail/generic/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/gather.h" "$(@D)/cuda/include/thrust/system/detail/generic/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/gather.inl" "$(@D)/cuda/include/thrust/system/detail/generic/gather.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/generate.h" "$(@D)/cuda/include/thrust/system/detail/generic/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/generate.inl" "$(@D)/cuda/include/thrust/system/detail/generic/generate.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/generic/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/inner_product.inl" "$(@D)/cuda/include/thrust/system/detail/generic/inner_product.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/logical.h" "$(@D)/cuda/include/thrust/system/detail/generic/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/memory.h" "$(@D)/cuda/include/thrust/system/detail/generic/memory.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/memory.inl" "$(@D)/cuda/include/thrust/system/detail/generic/memory.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/merge.h" "$(@D)/cuda/include/thrust/system/detail/generic/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/merge.inl" "$(@D)/cuda/include/thrust/system/detail/generic/merge.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/generic/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/mismatch.inl" "$(@D)/cuda/include/thrust/system/detail/generic/mismatch.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/partition.h" "$(@D)/cuda/include/thrust/system/detail/generic/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/partition.inl" "$(@D)/cuda/include/thrust/system/detail/generic/partition.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/reduce.h" "$(@D)/cuda/include/thrust/system/detail/generic/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/reduce.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reduce.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reduce_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/remove.h" "$(@D)/cuda/include/thrust/system/detail/generic/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/remove.inl" "$(@D)/cuda/include/thrust/system/detail/generic/remove.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/replace.h" "$(@D)/cuda/include/thrust/system/detail/generic/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/replace.inl" "$(@D)/cuda/include/thrust/system/detail/generic/replace.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/reverse.h" "$(@D)/cuda/include/thrust/system/detail/generic/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/reverse.inl" "$(@D)/cuda/include/thrust/system/detail/generic/reverse.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scalar/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/generic/scalar/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scalar/binary_search.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scalar/binary_search.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scan.h" "$(@D)/cuda/include/thrust/system/detail/generic/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scan.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scan.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scan_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scan_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scatter.h" "$(@D)/cuda/include/thrust/system/detail/generic/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/scatter.inl" "$(@D)/cuda/include/thrust/system/detail/generic/scatter.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/select_system.h" "$(@D)/cuda/include/thrust/system/detail/generic/select_system.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/sequence.h" "$(@D)/cuda/include/thrust/system/detail/generic/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/sequence.inl" "$(@D)/cuda/include/thrust/system/detail/generic/sequence.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/generic/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/set_operations.inl" "$(@D)/cuda/include/thrust/system/detail/generic/set_operations.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/sort.h" "$(@D)/cuda/include/thrust/system/detail/generic/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/sort.inl" "$(@D)/cuda/include/thrust/system/detail/generic/sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/generic/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/swap_ranges.inl" "$(@D)/cuda/include/thrust/system/detail/generic/swap_ranges.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/generic/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/tabulate.inl" "$(@D)/cuda/include/thrust/system/detail/generic/tabulate.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/tag.h" "$(@D)/cuda/include/thrust/system/detail/generic/tag.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/generic/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/temporary_buffer.inl" "$(@D)/cuda/include/thrust/system/detail/generic/temporary_buffer.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/transform.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/transform.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/transform_reduce.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform_reduce.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/generic/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/transform_scan.inl" "$(@D)/cuda/include/thrust/system/detail/generic/transform_scan.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/type_traits.h" "$(@D)/cuda/include/thrust/system/detail/generic/type_traits.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/uninitialized_copy.inl" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/uninitialized_fill.inl" "$(@D)/cuda/include/thrust/system/detail/generic/uninitialized_fill.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/unique.h" "$(@D)/cuda/include/thrust/system/detail/generic/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/unique.inl" "$(@D)/cuda/include/thrust/system/detail/generic/unique.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/generic/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/generic/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/detail/generic/unique_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/internal/decompose.h" "$(@D)/cuda/include/thrust/system/detail/internal/decompose.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/detail/sequential/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/assign_value.h" "$(@D)/cuda/include/thrust/system/detail/sequential/assign_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/binary_search.h" "$(@D)/cuda/include/thrust/system/detail/sequential/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/copy.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/copy_backward.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy_backward.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/copy_if.h" "$(@D)/cuda/include/thrust/system/detail/sequential/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/count.h" "$(@D)/cuda/include/thrust/system/detail/sequential/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/equal.h" "$(@D)/cuda/include/thrust/system/detail/sequential/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/execution_policy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/extrema.h" "$(@D)/cuda/include/thrust/system/detail/sequential/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/fill.h" "$(@D)/cuda/include/thrust/system/detail/sequential/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/find.h" "$(@D)/cuda/include/thrust/system/detail/sequential/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/for_each.h" "$(@D)/cuda/include/thrust/system/detail/sequential/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/gather.h" "$(@D)/cuda/include/thrust/system/detail/sequential/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/general_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/general_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/generate.h" "$(@D)/cuda/include/thrust/system/detail/sequential/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/get_value.h" "$(@D)/cuda/include/thrust/system/detail/sequential/get_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/inner_product.h" "$(@D)/cuda/include/thrust/system/detail/sequential/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/insertion_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/insertion_sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/iter_swap.h" "$(@D)/cuda/include/thrust/system/detail/sequential/iter_swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/logical.h" "$(@D)/cuda/include/thrust/system/detail/sequential/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/detail/sequential/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/merge.h" "$(@D)/cuda/include/thrust/system/detail/sequential/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/merge.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/merge.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/mismatch.h" "$(@D)/cuda/include/thrust/system/detail/sequential/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/partition.h" "$(@D)/cuda/include/thrust/system/detail/sequential/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/reduce.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/remove.h" "$(@D)/cuda/include/thrust/system/detail/sequential/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/replace.h" "$(@D)/cuda/include/thrust/system/detail/sequential/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/reverse.h" "$(@D)/cuda/include/thrust/system/detail/sequential/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/scan.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/scan_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/scatter.h" "$(@D)/cuda/include/thrust/system/detail/sequential/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/sequence.h" "$(@D)/cuda/include/thrust/system/detail/sequential/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/set_operations.h" "$(@D)/cuda/include/thrust/system/detail/sequential/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/stable_merge_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_merge_sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/stable_merge_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_merge_sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/stable_primitive_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_primitive_sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/stable_primitive_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_primitive_sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/stable_radix_sort.h" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_radix_sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/stable_radix_sort.inl" "$(@D)/cuda/include/thrust/system/detail/sequential/stable_radix_sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/swap_ranges.h" "$(@D)/cuda/include/thrust/system/detail/sequential/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/tabulate.h" "$(@D)/cuda/include/thrust/system/detail/sequential/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/detail/sequential/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/transform.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/transform_reduce.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/transform_scan.h" "$(@D)/cuda/include/thrust/system/detail/sequential/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/trivial_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/trivial_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/detail/sequential/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/detail/sequential/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/unique.h" "$(@D)/cuda/include/thrust/system/detail/sequential/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/sequential/unique_by_key.h" "$(@D)/cuda/include/thrust/system/detail/sequential/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/detail/system_error.inl" "$(@D)/cuda/include/thrust/system/detail/system_error.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/error_code.h" "$(@D)/cuda/include/thrust/system/error_code.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/omp/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/omp/detail/assign_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/omp/detail/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/copy.h" "$(@D)/cuda/include/thrust/system/omp/detail/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/copy.inl" "$(@D)/cuda/include/thrust/system/omp/detail/copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/omp/detail/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/copy_if.inl" "$(@D)/cuda/include/thrust/system/omp/detail/copy_if.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/count.h" "$(@D)/cuda/include/thrust/system/omp/detail/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/default_decomposition.h" "$(@D)/cuda/include/thrust/system/omp/detail/default_decomposition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/default_decomposition.inl" "$(@D)/cuda/include/thrust/system/omp/detail/default_decomposition.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/equal.h" "$(@D)/cuda/include/thrust/system/omp/detail/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/omp/detail/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/extrema.h" "$(@D)/cuda/include/thrust/system/omp/detail/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/fill.h" "$(@D)/cuda/include/thrust/system/omp/detail/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/find.h" "$(@D)/cuda/include/thrust/system/omp/detail/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/for_each.h" "$(@D)/cuda/include/thrust/system/omp/detail/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/for_each.inl" "$(@D)/cuda/include/thrust/system/omp/detail/for_each.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/gather.h" "$(@D)/cuda/include/thrust/system/omp/detail/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/generate.h" "$(@D)/cuda/include/thrust/system/omp/detail/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/get_value.h" "$(@D)/cuda/include/thrust/system/omp/detail/get_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/omp/detail/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/omp/detail/iter_swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/logical.h" "$(@D)/cuda/include/thrust/system/omp/detail/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/omp/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/memory.inl" "$(@D)/cuda/include/thrust/system/omp/detail/memory.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/merge.h" "$(@D)/cuda/include/thrust/system/omp/detail/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/omp/detail/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/par.h" "$(@D)/cuda/include/thrust/system/omp/detail/par.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/partition.h" "$(@D)/cuda/include/thrust/system/omp/detail/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/partition.inl" "$(@D)/cuda/include/thrust/system/omp/detail/partition.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reduce.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reduce.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reduce_intervals.h" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_intervals.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reduce_intervals.inl" "$(@D)/cuda/include/thrust/system/omp/detail/reduce_intervals.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/remove.h" "$(@D)/cuda/include/thrust/system/omp/detail/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/remove.inl" "$(@D)/cuda/include/thrust/system/omp/detail/remove.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/replace.h" "$(@D)/cuda/include/thrust/system/omp/detail/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/reverse.h" "$(@D)/cuda/include/thrust/system/omp/detail/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/scan.h" "$(@D)/cuda/include/thrust/system/omp/detail/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/scatter.h" "$(@D)/cuda/include/thrust/system/omp/detail/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/sequence.h" "$(@D)/cuda/include/thrust/system/omp/detail/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/omp/detail/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/sort.h" "$(@D)/cuda/include/thrust/system/omp/detail/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/sort.inl" "$(@D)/cuda/include/thrust/system/omp/detail/sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/omp/detail/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/omp/detail/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/omp/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/transform.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/omp/detail/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/omp/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/omp/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/unique.h" "$(@D)/cuda/include/thrust/system/omp/detail/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/unique.inl" "$(@D)/cuda/include/thrust/system/omp/detail/unique.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/omp/detail/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/omp/detail/unique_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/detail/vector.inl" "$(@D)/cuda/include/thrust/system/omp/detail/vector.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/execution_policy.h" "$(@D)/cuda/include/thrust/system/omp/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/memory.h" "$(@D)/cuda/include/thrust/system/omp/memory.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/omp/vector.h" "$(@D)/cuda/include/thrust/system/omp/vector.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/system_error.h" "$(@D)/cuda/include/thrust/system/system_error.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/adjacent_difference.h" "$(@D)/cuda/include/thrust/system/tbb/detail/adjacent_difference.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/assign_value.h" "$(@D)/cuda/include/thrust/system/tbb/detail/assign_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/binary_search.h" "$(@D)/cuda/include/thrust/system/tbb/detail/binary_search.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/copy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/copy.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/copy.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/copy_if.h" "$(@D)/cuda/include/thrust/system/tbb/detail/copy_if.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/copy_if.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/copy_if.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/count.h" "$(@D)/cuda/include/thrust/system/tbb/detail/count.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/equal.h" "$(@D)/cuda/include/thrust/system/tbb/detail/equal.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/execution_policy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/extrema.h" "$(@D)/cuda/include/thrust/system/tbb/detail/extrema.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/fill.h" "$(@D)/cuda/include/thrust/system/tbb/detail/fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/find.h" "$(@D)/cuda/include/thrust/system/tbb/detail/find.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/for_each.h" "$(@D)/cuda/include/thrust/system/tbb/detail/for_each.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/for_each.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/for_each.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/gather.h" "$(@D)/cuda/include/thrust/system/tbb/detail/gather.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/generate.h" "$(@D)/cuda/include/thrust/system/tbb/detail/generate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/get_value.h" "$(@D)/cuda/include/thrust/system/tbb/detail/get_value.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/inner_product.h" "$(@D)/cuda/include/thrust/system/tbb/detail/inner_product.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/iter_swap.h" "$(@D)/cuda/include/thrust/system/tbb/detail/iter_swap.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/logical.h" "$(@D)/cuda/include/thrust/system/tbb/detail/logical.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/malloc_and_free.h" "$(@D)/cuda/include/thrust/system/tbb/detail/malloc_and_free.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/memory.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/memory.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/merge.h" "$(@D)/cuda/include/thrust/system/tbb/detail/merge.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/merge.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/merge.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/mismatch.h" "$(@D)/cuda/include/thrust/system/tbb/detail/mismatch.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/par.h" "$(@D)/cuda/include/thrust/system/tbb/detail/par.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/partition.h" "$(@D)/cuda/include/thrust/system/tbb/detail/partition.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/partition.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/partition.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/reduce.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/reduce.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/reduce_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/reduce_by_key.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/reduce_intervals.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reduce_intervals.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/remove.h" "$(@D)/cuda/include/thrust/system/tbb/detail/remove.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/remove.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/remove.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/replace.h" "$(@D)/cuda/include/thrust/system/tbb/detail/replace.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/reverse.h" "$(@D)/cuda/include/thrust/system/tbb/detail/reverse.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/scan.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/scan.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/scan.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/scan_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scan_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/scatter.h" "$(@D)/cuda/include/thrust/system/tbb/detail/scatter.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/sequence.h" "$(@D)/cuda/include/thrust/system/tbb/detail/sequence.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/set_operations.h" "$(@D)/cuda/include/thrust/system/tbb/detail/set_operations.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/sort.h" "$(@D)/cuda/include/thrust/system/tbb/detail/sort.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/sort.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/sort.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/swap_ranges.h" "$(@D)/cuda/include/thrust/system/tbb/detail/swap_ranges.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/tabulate.h" "$(@D)/cuda/include/thrust/system/tbb/detail/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/temporary_buffer.h" "$(@D)/cuda/include/thrust/system/tbb/detail/temporary_buffer.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/transform.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/transform_reduce.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/transform_scan.h" "$(@D)/cuda/include/thrust/system/tbb/detail/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/uninitialized_copy.h" "$(@D)/cuda/include/thrust/system/tbb/detail/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/uninitialized_fill.h" "$(@D)/cuda/include/thrust/system/tbb/detail/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/unique.h" "$(@D)/cuda/include/thrust/system/tbb/detail/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/unique.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/unique.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/unique_by_key.h" "$(@D)/cuda/include/thrust/system/tbb/detail/unique_by_key.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/unique_by_key.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/unique_by_key.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/detail/vector.inl" "$(@D)/cuda/include/thrust/system/tbb/detail/vector.inl" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/execution_policy.h" "$(@D)/cuda/include/thrust/system/tbb/execution_policy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/memory.h" "$(@D)/cuda/include/thrust/system/tbb/memory.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system/tbb/vector.h" "$(@D)/cuda/include/thrust/system/tbb/vector.h" && cp -f "/usr/local/cuda-10.0/include/thrust/system_error.h" "$(@D)/cuda/include/thrust/system_error.h" && cp -f "/usr/local/cuda-10.0/include/thrust/tabulate.h" "$(@D)/cuda/include/thrust/tabulate.h" && cp -f "/usr/local/cuda-10.0/include/thrust/transform.h" "$(@D)/cuda/include/thrust/transform.h" && cp -f "/usr/local/cuda-10.0/include/thrust/transform_reduce.h" "$(@D)/cuda/include/thrust/transform_reduce.h" && cp -f "/usr/local/cuda-10.0/include/thrust/transform_scan.h" "$(@D)/cuda/include/thrust/transform_scan.h" && cp -f "/usr/local/cuda-10.0/include/thrust/tuple.h" "$(@D)/cuda/include/thrust/tuple.h" && cp -f "/usr/local/cuda-10.0/include/thrust/uninitialized_copy.h" "$(@D)/cuda/include/thrust/uninitialized_copy.h" && cp -f "/usr/local/cuda-10.0/include/thrust/uninitialized_fill.h" "$(@D)/cuda/include/thrust/uninitialized_fill.h" && cp -f "/usr/local/cuda-10.0/include/thrust/unique.h" "$(@D)/cuda/include/thrust/unique.h" && cp -f "/usr/local/cuda-10.0/include/thrust/version.h" "$(@D)/cuda/include/thrust/version.h" && cp -f "/usr/local/cuda-10.0/include/vector_functions.h" "$(@D)/cuda/include/vector_functions.h" && cp -f "/usr/local/cuda-10.0/include/vector_functions.hpp" "$(@D)/cuda/include/vector_functions.hpp" && cp -f "/usr/local/cuda-10.0/include/vector_types.h" "$(@D)/cuda/include/vector_types.h" + """, +) + +genrule( + name = "cuda-nvvm", + outs = [ + "cuda/nvvm/libdevice/libdevice.10.bc", + ], + cmd = """ +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-10.0/nvvm/libdevice/libdevice.10.bc" "$(@D)//libdevice.10.bc" + """, +) + +genrule( + name = "cuda-extras", + outs = [ + "cuda/extras/CUPTI/include/GL/gl.h", + "cuda/extras/CUPTI/include/GL/glew.h", + "cuda/extras/CUPTI/include/GL/glext.h", + "cuda/extras/CUPTI/include/GL/glu.h", + "cuda/extras/CUPTI/include/GL/glut.h", + "cuda/extras/CUPTI/include/GL/glx.h", + "cuda/extras/CUPTI/include/GL/glxext.h", + "cuda/extras/CUPTI/include/GL/wglew.h", + "cuda/extras/CUPTI/include/GL/wglext.h", + "cuda/extras/CUPTI/include/cuda_stdint.h", + "cuda/extras/CUPTI/include/cupti.h", + "cuda/extras/CUPTI/include/cupti_activity.h", + "cuda/extras/CUPTI/include/cupti_callbacks.h", + "cuda/extras/CUPTI/include/cupti_driver_cbid.h", + "cuda/extras/CUPTI/include/cupti_events.h", + "cuda/extras/CUPTI/include/cupti_metrics.h", + "cuda/extras/CUPTI/include/cupti_nvtx_cbid.h", + "cuda/extras/CUPTI/include/cupti_result.h", + "cuda/extras/CUPTI/include/cupti_runtime_cbid.h", + "cuda/extras/CUPTI/include/cupti_version.h", + "cuda/extras/CUPTI/include/generated_cudaGL_meta.h", + "cuda/extras/CUPTI/include/generated_cudaVDPAU_meta.h", + "cuda/extras/CUPTI/include/generated_cuda_gl_interop_meta.h", + "cuda/extras/CUPTI/include/generated_cuda_meta.h", + "cuda/extras/CUPTI/include/generated_cuda_runtime_api_meta.h", + "cuda/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h", + "cuda/extras/CUPTI/include/generated_nvtx_meta.h", + "cuda/extras/CUPTI/include/openacc/cupti_openacc.h", + "cuda/extras/CUPTI/include/openmp/cupti_openmp.h", + "cuda/extras/CUPTI/include/openmp/ompt.h", + ], + cmd = """ +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/gl.h" "$(@D)/cuda/extras/CUPTI/include/GL/gl.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/glew.h" "$(@D)/cuda/extras/CUPTI/include/GL/glew.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/glext.h" "$(@D)/cuda/extras/CUPTI/include/GL/glext.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/glu.h" "$(@D)/cuda/extras/CUPTI/include/GL/glu.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/glut.h" "$(@D)/cuda/extras/CUPTI/include/GL/glut.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/glx.h" "$(@D)/cuda/extras/CUPTI/include/GL/glx.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/glxext.h" "$(@D)/cuda/extras/CUPTI/include/GL/glxext.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/wglew.h" "$(@D)/cuda/extras/CUPTI/include/GL/wglew.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/GL/wglext.h" "$(@D)/cuda/extras/CUPTI/include/GL/wglext.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cuda_stdint.h" "$(@D)/cuda/extras/CUPTI/include/cuda_stdint.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti.h" "$(@D)/cuda/extras/CUPTI/include/cupti.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_activity.h" "$(@D)/cuda/extras/CUPTI/include/cupti_activity.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_callbacks.h" "$(@D)/cuda/extras/CUPTI/include/cupti_callbacks.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_driver_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_driver_cbid.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_events.h" "$(@D)/cuda/extras/CUPTI/include/cupti_events.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_metrics.h" "$(@D)/cuda/extras/CUPTI/include/cupti_metrics.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_nvtx_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_nvtx_cbid.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_result.h" "$(@D)/cuda/extras/CUPTI/include/cupti_result.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_runtime_cbid.h" "$(@D)/cuda/extras/CUPTI/include/cupti_runtime_cbid.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/cupti_version.h" "$(@D)/cuda/extras/CUPTI/include/cupti_version.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_cudaGL_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cudaGL_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_cudaVDPAU_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cudaVDPAU_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_cuda_gl_interop_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_gl_interop_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_cuda_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_cuda_runtime_api_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_runtime_api_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_cuda_vdpau_interop_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/generated_nvtx_meta.h" "$(@D)/cuda/extras/CUPTI/include/generated_nvtx_meta.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/openacc/cupti_openacc.h" "$(@D)/cuda/extras/CUPTI/include/openacc/cupti_openacc.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/openmp/cupti_openmp.h" "$(@D)/cuda/extras/CUPTI/include/openmp/cupti_openmp.h" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/include/openmp/ompt.h" "$(@D)/cuda/extras/CUPTI/include/openmp/ompt.h" + """, +) + +genrule( + name = "cuda-lib", + outs = [ + "cuda/lib/libcuda.so", + "cuda/lib/libcudart.so.10.0", + "cuda/lib/libcudart_static.a", + "cuda/lib/libcublas.so.10.0", + "cuda/lib/libcusolver.so.10.0", + "cuda/lib/libcurand.so.10.0", + "cuda/lib/libcufft.so.10.0", + "cuda/lib/libcudnn.so.7", + "cuda/lib/libcupti.so.10.0", + ], + cmd = """ +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/stubs/libcuda.so" "$(@D)/cuda/lib/libcuda.so" && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/libcudart.so.10.0.130" "$(@D)/cuda/lib/libcudart.so.10.0" && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/libcudart_static.a" "$(@D)/cuda/lib/libcudart_static.a" && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/libcublas.so.10.0.130" "$(@D)/cuda/lib/libcublas.so.10.0" && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/libcusolver.so.10.0.130" "$(@D)/cuda/lib/libcusolver.so.10.0" && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/libcurand.so.10.0.130" "$(@D)/cuda/lib/libcurand.so.10.0" && cp -f "/usr/local/cuda-10.0/targets/x86_64-linux/lib/libcufft.so.10.0.145" "$(@D)/cuda/lib/libcufft.so.10.0" && cp -f "/usr/lib/x86_64-linux-gnu/libcudnn.so.7.3.1" "$(@D)/cuda/lib/libcudnn.so.7" && cp -f "/usr/local/cuda-10.0/extras/CUPTI/lib64/libcupti.so.10.0.130" "$(@D)/cuda/lib/libcupti.so.10.0" + """, +) + +genrule( + name = "cudnn-include", + outs = [ + "cuda/include/cudnn.h", + ], + cmd = """ +if [ -d "$(@D)/extras" ]; then rm $(@D)/extras -drf; fi && if [ -d "$(@D)/include" ]; then rm $(@D)/include -drf; fi && if [ -d "$(@D)/lib" ]; then rm $(@D)/lib -drf; fi && if [ -d "$(@D)/nvvm" ]; then rm $(@D)/nvvm -drf; fi && cp -f "/usr/include/cudnn.h" "$(@D)/cudnn.h" + """, +) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/build_defs.bzl b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/build_defs.bzl new file mode 100755 index 0000000000..a53c891d8b --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/build_defs.bzl @@ -0,0 +1,31 @@ +# Macros for building CUDA code. +def if_cuda(if_true, if_false = []): + """Shorthand for select()'ing on whether we're building with CUDA. + + Returns a select statement which evaluates to if_true if we're building + with CUDA enabled. Otherwise, the select statement evaluates to if_false. + + """ + return select({ + "@local_config_cuda//cuda:using_nvcc": if_true, + "@local_config_cuda//cuda:using_clang": if_true, + "//conditions:default": if_false, + }) + +def cuda_default_copts(): + """Default options for all CUDA compilations.""" + return if_cuda(["-x", "cuda", "-DGOOGLE_CUDA=1"] + []) + +def cuda_is_configured(): + """Returns true if CUDA was enabled during the configure process.""" + return True + +def if_cuda_is_configured(x): + """Tests if the CUDA was enabled during the configure process. + + Unlike if_cuda(), this does not require that we are building with + --config=cuda. Used to allow non-CUDA code to depend on CUDA libraries. + """ + if cuda_is_configured(): + return x + return [] diff --git a/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/cuda/cuda_config.h b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/cuda/cuda_config.h new file mode 100755 index 0000000000..0934618e0b --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/cuda10.0-cudnn7/cuda/cuda/cuda_config.h @@ -0,0 +1,26 @@ +/* Copyright 2015 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef CUDA_CUDA_CONFIG_H_ +#define CUDA_CUDA_CONFIG_H_ + +#define TF_CUDA_CAPABILITIES CudaVersion("3.0") + +#define TF_CUDA_VERSION "10.0" +#define TF_CUDNN_VERSION "7" + +#define TF_CUDA_TOOLKIT_PATH "/usr/local/cuda-10.0" + +#endif // CUDA_CUDA_CONFIG_H_ diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/BUILD b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/BUILD new file mode 100755 index 0000000000..6442e7628a --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/BUILD @@ -0,0 +1,87 @@ +licenses(["restricted"]) + +package(default_visibility = ["//visibility:public"]) + +toolchain( + name = "toolchain-linux-x86_64", + exec_compatible_with = [ + "@bazel_tools//platforms:linux", + "@bazel_tools//platforms:x86_64", + ], + target_compatible_with = [ + "@bazel_tools//platforms:linux", + "@bazel_tools//platforms:x86_64", + ], + toolchain = ":cc-compiler-local", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain_suite( + name = "toolchain", + toolchains = { + "local|compiler": ":cc-compiler-local", + "darwin|compiler": ":cc-compiler-darwin", + "x64_windows|msvc-cl": ":cc-compiler-windows", + }, +) + +cc_toolchain( + name = "cc-compiler-local", + all_files = ":crosstool_wrapper_driver_is_not_gcc", + compiler_files = ":empty", + cpu = "local", + dwp_files = ":empty", + dynamic_runtime_libs = [":empty"], + linker_files = ":crosstool_wrapper_driver_is_not_gcc", + objcopy_files = ":empty", + static_runtime_libs = [":empty"], + strip_files = ":empty", + # To support linker flags that need to go to the start of command line + # we need the toolchain to support parameter files. Parameter files are + # last on the command line and contain all shared libraries to link, so all + # regular options will be left of them. + supports_param_files = 1, +) + +cc_toolchain( + name = "cc-compiler-darwin", + all_files = ":crosstool_wrapper_driver_is_not_gcc", + compiler_files = ":empty", + cpu = "darwin", + dwp_files = ":empty", + dynamic_runtime_libs = [":empty"], + linker_files = ":crosstool_wrapper_driver_is_not_gcc", + objcopy_files = ":empty", + static_runtime_libs = [":empty"], + strip_files = ":empty", + supports_param_files = 0, +) + +cc_toolchain( + name = "cc-compiler-windows", + all_files = ":windows_msvc_wrapper_files", + compiler_files = ":empty", + cpu = "x64_windows", + dwp_files = ":empty", + dynamic_runtime_libs = [":empty"], + linker_files = ":windows_msvc_wrapper_files", + objcopy_files = ":empty", + static_runtime_libs = [":empty"], + strip_files = ":empty", + supports_param_files = 1, +) + +filegroup( + name = "empty", + srcs = [], +) + +filegroup( + name = "crosstool_wrapper_driver_is_not_gcc", + srcs = ["clang/bin/crosstool_wrapper_driver_is_not_gcc"], +) + +filegroup( + name = "windows_msvc_wrapper_files", + srcs = glob(["windows/msvc_*"]), +) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/CROSSTOOL b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/CROSSTOOL new file mode 100755 index 0000000000..1c2e8bcae6 --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/CROSSTOOL @@ -0,0 +1,1431 @@ +major_version: "local" +minor_version: "" +default_target_cpu: "same_as_host" + +default_toolchain { + cpu: "k8" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "piii" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "arm" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "darwin" + toolchain_identifier: "local_darwin" +} +default_toolchain { + cpu: "ppc" + toolchain_identifier: "local_linux" +} +default_toolchain { + cpu: "x64_windows" + toolchain_identifier: "local_windows" +} + +toolchain { + abi_version: "local" + abi_libc_version: "local" + compiler: "compiler" + host_system_name: "local" + needsPic: true + target_libc: "local" + target_cpu: "local" + target_system_name: "local" + toolchain_identifier: "local_linux" + + feature { + name: "c++11" + flag_set { + action: "c++-compile" + flag_group { + flag: "-std=c++11" + } + } + } + + feature { + name: "stdlib" + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-lstdc++" + } + } + } + + feature { + name: "determinism" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + flag: "-Wno-builtin-macro-redefined" + flag: "-D__DATE__=\"redacted\"" + flag: "-D__TIMESTAMP__=\"redacted\"" + flag: "-D__TIME__=\"redacted\"" + } + } + } + + feature { + name: "alwayslink" + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-Wl,-no-as-needed" + } + } + } + + # This feature will be enabled for builds that support pic by bazel. + feature { + name: "pic" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + expand_if_all_available: "pic" + flag: "-fPIC" + } + flag_group { + expand_if_none_available: "pic" + flag: "-fPIE" + } + } + } + + # Security hardening on by default. + feature { + name: "hardening" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now + # have it enabled by default. + flag: "-U_FORTIFY_SOURCE" + flag: "-D_FORTIFY_SOURCE=1" + flag: "-fstack-protector" + } + } + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-Wl,-z,relro,-z,now" + } + } + flag_set { + action: "c++-link-executable" + flag_group { + flag: "-pie" + flag: "-Wl,-z,relro,-z,now" + } + } + } + + feature { + name: "warnings" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # All warnings are enabled. Maybe enable -Werror as well? + flag: "-Wall" + + } + } + } + + # Keep stack frames for debugging, even in opt mode. + feature { + name: "frame-pointer" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-fno-omit-frame-pointer" + } + } + } + + feature { + name: "build-id" + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + # Stamp the binary with a unique identifier. + flag: "-Wl,--build-id=md5" + flag: "-Wl,--hash-style=gnu" + } + } + } + + feature { + name: "no-canonical-prefixes" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-no-canonical-prefixes" + flag: "-fno-canonical-system-headers" + } + } + } + + feature { + name: "disable-assertions" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-DNDEBUG" + } + } + } + + feature { + name: "linker-bin-path" + + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-B/usr/bin" + } + } + } + + feature { + name: "common" + implies: "stdlib" + implies: "c++11" + implies: "determinism" + implies: "alwayslink" + implies: "hardening" + implies: "warnings" + implies: "frame-pointer" + implies: "build-id" + implies: "no-canonical-prefixes" + implies: "linker-bin-path" + } + + feature { + name: "opt" + implies: "common" + implies: "disable-assertions" + + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # No debug symbols. + # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt + # or even generally? However, that can't happen here, as it requires + # special handling in Bazel. + flag: "-g0" + + # Conservative choice for -O + # -O3 can increase binary size and even slow down the resulting binaries. + # Profile first and / or use FDO if you need better performance than this. + flag: "-O2" + + # Removal of unused code and data at link time (can this increase binary size in some cases?). + flag: "-ffunction-sections" + flag: "-fdata-sections" + } + } + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-Wl,--gc-sections" + } + } + } + + feature { + name: "fastbuild" + implies: "common" + } + + feature { + name: "dbg" + implies: "common" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-g" + } + } + } + + # Set clang as a C/C++ compiler. + tool_path { name: "gcc" path: "clang/bin/crosstool_wrapper_driver_is_not_gcc" } + + # Use the default system toolchain for everything else. + tool_path { name: "ar" path: "/usr/bin/ar" } + tool_path { name: "compat-ld" path: "/usr/bin/ld" } + tool_path { name: "cpp" path: "/usr/bin/cpp" } + tool_path { name: "dwp" path: "/usr/bin/dwp" } + tool_path { name: "gcov" path: "/usr/bin/gcov" } + tool_path { name: "ld" path: "/usr/bin/ld" } + tool_path { name: "nm" path: "/usr/bin/nm" } + tool_path { name: "objcopy" path: "/usr/bin/objcopy" } + tool_path { name: "objdump" path: "/usr/bin/objdump" } + tool_path { name: "strip" path: "/usr/bin/strip" } + + # Enabled dynamic linking. + linking_mode_flags { mode: DYNAMIC } + + cxx_builtin_include_directory: "/usr/include/c++/4.8" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu/c++/4.8" + cxx_builtin_include_directory: "/usr/include/c++/4.8/backward" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include" + cxx_builtin_include_directory: "/usr/local/include" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu" + cxx_builtin_include_directory: "/usr/include" + cxx_builtin_include_directory: "/usr/local/cuda-10.0/targets/x86_64-linux/include" + cxx_builtin_include_directory: "/usr/local/cuda-10.0/include" + cxx_builtin_include_directory: "/usr/local/cuda-10.0/extras/CUPTI/include" + cxx_builtin_include_directory: "/usr/include" +} + +toolchain { + abi_version: "local" + abi_libc_version: "local" + compiler: "compiler" + host_system_name: "local" + needsPic: true + target_libc: "macosx" + target_cpu: "darwin" + target_system_name: "local" + toolchain_identifier: "local_darwin" + feature { + name: "c++11" + flag_set { + action: "c++-compile" + flag_group { + flag: "-std=c++11" + } + } + } + + feature { + name: "stdlib" + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-lc++" + } + } + } + + feature { + name: "determinism" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + flag: "-Wno-builtin-macro-redefined" + flag: "-D__DATE__=\"redacted\"" + flag: "-D__TIMESTAMP__=\"redacted\"" + flag: "-D__TIME__=\"redacted\"" + } + } + } + + # This feature will be enabled for builds that support pic by bazel. + feature { + name: "pic" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + expand_if_all_available: "pic" + flag: "-fPIC" + } + flag_group { + expand_if_none_available: "pic" + flag: "-fPIE" + } + } + } + + # Security hardening on by default. + feature { + name: "hardening" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now + # have it enabled by default. + flag: "-U_FORTIFY_SOURCE" + flag: "-D_FORTIFY_SOURCE=1" + flag: "-fstack-protector" + } + } + flag_set { + action: "c++-link-executable" + flag_group { + flag: "-pie" + } + } + } + + feature { + name: "warnings" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # All warnings are enabled. Maybe enable -Werror as well? + flag: "-Wall" + + } + } + } + + # Keep stack frames for debugging, even in opt mode. + feature { + name: "frame-pointer" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-fno-omit-frame-pointer" + } + } + } + + feature { + name: "no-canonical-prefixes" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag:"-no-canonical-prefixes" + } + } + } + + feature { + name: "disable-assertions" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-DNDEBUG" + } + } + } + + feature { + name: "linker-bin-path" + + flag_set { + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "-B/usr/bin" + } + } + } + + feature { + name: "undefined-dynamic" + flag_set { + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-executable" + flag_group { + flag: "-undefined" + flag: "dynamic_lookup" + } + } + } + + feature { + name: "common" + implies: "stdlib" + implies: "c++11" + implies: "determinism" + implies: "hardening" + implies: "warnings" + implies: "frame-pointer" + implies: "no-canonical-prefixes" + implies: "linker-bin-path" + implies: "undefined-dynamic" + } + + feature { + name: "opt" + implies: "common" + implies: "disable-assertions" + + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + # No debug symbols. + # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt + # or even generally? However, that can't happen here, as it requires + # special handling in Bazel. + flag: "-g0" + + # Conservative choice for -O + # -O3 can increase binary size and even slow down the resulting binaries. + # Profile first and / or use FDO if you need better performance than this. + flag: "-O2" + + # Removal of unused code and data at link time (can this increase binary size in some cases?). + flag: "-ffunction-sections" + flag: "-fdata-sections" + } + } + } + + feature { + name: "fastbuild" + implies: "common" + } + + feature { + name: "dbg" + implies: "common" + flag_set { + action: "c-compile" + action: "c++-compile" + flag_group { + flag: "-g" + } + } + } + + # Set clang as a C/C++ compiler. + tool_path { name: "gcc" path: "clang/bin/crosstool_wrapper_driver_is_not_gcc" } + + # Use the default system toolchain for everything else. + tool_path { name: "ar" path: "/usr/bin/libtool" } + tool_path { name: "compat-ld" path: "/usr/bin/ld" } + tool_path { name: "cpp" path: "/usr/bin/cpp" } + tool_path { name: "dwp" path: "/usr/bin/dwp" } + tool_path { name: "gcov" path: "/usr/bin/gcov" } + tool_path { name: "ld" path: "/usr/bin/ld" } + tool_path { name: "nm" path: "/usr/bin/nm" } + tool_path { name: "objcopy" path: "/usr/bin/objcopy" } + tool_path { name: "objdump" path: "/usr/bin/objdump" } + tool_path { name: "strip" path: "/usr/bin/strip" } + + # Enabled dynamic linking. + linking_mode_flags { mode: DYNAMIC } + + cxx_builtin_include_directory: "/usr/include/c++/4.8" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu/c++/4.8" + cxx_builtin_include_directory: "/usr/include/c++/4.8/backward" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include" + cxx_builtin_include_directory: "/usr/local/include" + cxx_builtin_include_directory: "/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed" + cxx_builtin_include_directory: "/usr/include/x86_64-linux-gnu" + cxx_builtin_include_directory: "/usr/include" + cxx_builtin_include_directory: "/usr/local/cuda-10.0/targets/x86_64-linux/include" + cxx_builtin_include_directory: "/usr/local/cuda-10.0/include" + cxx_builtin_include_directory: "/usr/local/cuda-10.0/extras/CUPTI/include" + cxx_builtin_include_directory: "/usr/include" +} + +toolchain { + toolchain_identifier: "local_windows" + host_system_name: "local" + target_system_name: "local" + + abi_version: "local" + abi_libc_version: "local" + target_cpu: "x64_windows" + compiler: "msvc-cl" + target_libc: "msvcrt" + + + + tool_path { + name: "ar" + path: "" + } + tool_path { + name: "ml" + path: "" + } + tool_path { + name: "cpp" + path: "" + } + tool_path { + name: "gcc" + path: "" + } + tool_path { + name: "gcov" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "ld" + path: "" + } + tool_path { + name: "nm" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "objcopy" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "objdump" + path: "wrapper/bin/msvc_nop.bat" + } + tool_path { + name: "strip" + path: "wrapper/bin/msvc_nop.bat" + } + supports_interface_shared_objects: true + + # TODO(pcloudy): Review those flags below, they should be defined by cl.exe + compiler_flag: "/DCOMPILER_MSVC" + + # Don't define min/max macros in windows.h. + compiler_flag: "/DNOMINMAX" + + # Platform defines. + compiler_flag: "/D_WIN32_WINNT=0x0600" + # Turn off warning messages. + compiler_flag: "/D_CRT_SECURE_NO_DEPRECATE" + compiler_flag: "/D_CRT_SECURE_NO_WARNINGS" + compiler_flag: "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS" + + # Useful options to have on for compilation. + # Increase the capacity of object files to 2^32 sections. + compiler_flag: "/bigobj" + # Allocate 500MB for precomputed headers. + compiler_flag: "/Zm500" + # Use unsigned char by default. + compiler_flag: "/J" + # Use function level linking. + compiler_flag: "/Gy" + # Use string pooling. + compiler_flag: "/GF" + # Catch C++ exceptions only and tell the compiler to assume that functions declared + # as extern "C" never throw a C++ exception. + compiler_flag: "/EHsc" + + # Globally disabled warnings. + # Don't warn about elements of array being be default initialized. + compiler_flag: "/wd4351" + # Don't warn about no matching delete found. + compiler_flag: "/wd4291" + # Don't warn about diamond inheritance patterns. + compiler_flag: "/wd4250" + # Don't warn about insecure functions (e.g. non _s functions). + compiler_flag: "/wd4996" + + linker_flag: "/MACHINE:X64" + + feature { + name: "no_legacy_features" + } + + # Suppress startup banner. + feature { + name: "nologo" + flag_set { + action: "c-compile" + action: "c++-compile" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "c++-header-parsing" + action: "assemble" + action: "preprocess-assemble" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-static-library" + flag_group { + flag: "/nologo" + } + } + } + + feature { + name: 'has_configured_linker_path' + } + + # This feature indicates strip is not supported, building stripped binary will just result a copy of orignial binary + feature { + name: 'no_stripping' + } + + # This feature indicates this is a toolchain targeting Windows. + feature { + name: 'targets_windows' + implies: 'copy_dynamic_libraries_to_binary' + enabled: true + } + + feature { + name: 'copy_dynamic_libraries_to_binary' + } + + action_config { + config_name: 'assemble' + action_name: 'assemble' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'sysroot' + } + + action_config { + config_name: 'preprocess-assemble' + action_name: 'preprocess-assemble' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'sysroot' + } + + action_config { + config_name: 'c-compile' + action_name: 'c-compile' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'legacy_compile_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'parse_showincludes' + implies: 'user_compile_flags' + implies: 'sysroot' + implies: 'unfiltered_compile_flags' + } + + action_config { + config_name: 'c++-compile' + action_name: 'c++-compile' + tool { + tool_path: '' + } + implies: 'compiler_input_flags' + implies: 'compiler_output_flags' + implies: 'legacy_compile_flags' + implies: 'nologo' + implies: 'msvc_env' + implies: 'parse_showincludes' + implies: 'user_compile_flags' + implies: 'sysroot' + implies: 'unfiltered_compile_flags' + } + + action_config { + config_name: 'c++-link-executable' + action_name: 'c++-link-executable' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'user_link_flags' + implies: 'legacy_link_flags' + implies: 'linker_subsystem_flag' + implies: 'linker_param_file' + implies: 'msvc_env' + implies: 'no_stripping' + } + + action_config { + config_name: 'c++-link-dynamic-library' + action_name: 'c++-link-dynamic-library' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'shared_flag' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'user_link_flags' + implies: 'legacy_link_flags' + implies: 'linker_subsystem_flag' + implies: 'linker_param_file' + implies: 'msvc_env' + implies: 'no_stripping' + implies: 'has_configured_linker_path' + implies: 'def_file' + } + + action_config { + config_name: 'c++-link-nodeps-dynamic-library' + action_name: 'c++-link-nodeps-dynamic-library' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'shared_flag' + implies: 'linkstamps' + implies: 'output_execpath_flags' + implies: 'input_param_flags' + implies: 'user_link_flags' + implies: 'legacy_link_flags' + implies: 'linker_subsystem_flag' + implies: 'linker_param_file' + implies: 'msvc_env' + implies: 'no_stripping' + implies: 'has_configured_linker_path' + implies: 'def_file' + } + + action_config { + config_name: 'c++-link-static-library' + action_name: 'c++-link-static-library' + tool { + tool_path: '' + } + implies: 'nologo' + implies: 'archiver_flags' + implies: 'input_param_flags' + implies: 'linker_param_file' + implies: 'msvc_env' + } + + # TODO(b/65151735): Remove legacy_compile_flags feature when legacy fields are + # not used in this crosstool + feature { + name: 'legacy_compile_flags' + flag_set { + expand_if_all_available: 'legacy_compile_flags' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + iterate_over: 'legacy_compile_flags' + flag: '%{legacy_compile_flags}' + } + } + } + + feature { + name: "msvc_env" + env_set { + action: "c-compile" + action: "c++-compile" + action: "c++-module-compile" + action: "c++-module-codegen" + action: "c++-header-parsing" + action: "assemble" + action: "preprocess-assemble" + action: "c++-link-executable" + action: "c++-link-dynamic-library" + action: "c++-link-nodeps-dynamic-library" + action: "c++-link-static-library" + env_entry { + key: "PATH" + value: "" + } + env_entry { + key: "INCLUDE" + value: "" + } + env_entry { + key: "LIB" + value: "" + } + env_entry { + key: "TMP" + value: "" + } + env_entry { + key: "TEMP" + value: "" + } + } + } + + feature { + name: 'include_paths' + flag_set { + action: "assemble" + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + flag_group { + iterate_over: 'quote_include_paths' + flag: '/I%{quote_include_paths}' + } + flag_group { + iterate_over: 'include_paths' + flag: '/I%{include_paths}' + } + flag_group { + iterate_over: 'system_include_paths' + flag: '/I%{system_include_paths}' + } + } + } + + feature { + name: "preprocessor_defines" + flag_set { + action: "assemble" + action: "preprocess-assemble" + action: "c-compile" + action: "c++-compile" + action: "c++-header-parsing" + action: "c++-module-compile" + flag_group { + flag: "/D%{preprocessor_defines}" + iterate_over: "preprocessor_defines" + } + } + } + + # Tell Bazel to parse the output of /showIncludes + feature { + name: 'parse_showincludes' + flag_set { + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-module-compile' + action: 'c++-header-parsing' + flag_group { + flag: "/showIncludes" + } + } + } + + + feature { + name: 'generate_pdb_file' + requires: { + feature: 'dbg' + } + requires: { + feature: 'fastbuild' + } + } + + feature { + name: 'shared_flag' + flag_set { + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: '/DLL' + } + } + } + + feature { + name: 'linkstamps' + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + expand_if_all_available: 'linkstamp_paths' + flag_group { + iterate_over: 'linkstamp_paths' + flag: '%{linkstamp_paths}' + } + } + } + + feature { + name: 'output_execpath_flags' + flag_set { + expand_if_all_available: 'output_execpath' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: '/OUT:%{output_execpath}' + } + } + } + + feature { + name: 'archiver_flags' + flag_set { + expand_if_all_available: 'output_execpath' + action: 'c++-link-static-library' + flag_group { + flag: '/OUT:%{output_execpath}' + } + } + } + + feature { + name: 'input_param_flags' + flag_set { + expand_if_all_available: 'interface_library_output_path' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/IMPLIB:%{interface_library_output_path}" + } + } + flag_set { + expand_if_all_available: 'libopts' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'libopts' + flag: '%{libopts}' + } + } + flag_set { + expand_if_all_available: 'libraries_to_link' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + action: 'c++-link-static-library' + flag_group { + iterate_over: 'libraries_to_link' + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'object_file_group' + } + iterate_over: 'libraries_to_link.object_files' + flag_group { + flag: '%{libraries_to_link.object_files}' + } + } + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'object_file' + } + flag_group { + flag: '%{libraries_to_link.name}' + } + } + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'interface_library' + } + flag_group { + flag: '%{libraries_to_link.name}' + } + } + flag_group { + expand_if_equal: { + variable: 'libraries_to_link.type' + value: 'static_library' + } + flag_group { + expand_if_false: 'libraries_to_link.is_whole_archive' + flag: '%{libraries_to_link.name}' + } + flag_group { + expand_if_true: 'libraries_to_link.is_whole_archive' + flag: '/WHOLEARCHIVE:%{libraries_to_link.name}' + } + } + } + } + } + + # Since this feature is declared earlier in the CROSSTOOL than + # "user_link_flags", this feature will be applied prior to it anwyhere they + # are both implied. And since "user_link_flags" contains the linkopts from + # the build rule, this allows the user to override the /SUBSYSTEM in the BUILD + # file. + feature { + name: 'linker_subsystem_flag' + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: '/SUBSYSTEM:CONSOLE' + } + } + } + + # The "user_link_flags" contains user-defined linkopts (from build rules) + # so it should be defined after features that declare user-overridable flags. + # For example the "linker_subsystem_flag" defines a default "/SUBSYSTEM" flag + # but we want to let the user override it, therefore "link_flag_subsystem" is + # defined earlier in the CROSSTOOL file than "user_link_flags". + feature { + name: 'user_link_flags' + flag_set { + expand_if_all_available: 'user_link_flags' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'user_link_flags' + flag: '%{user_link_flags}' + } + } + } + feature { + name: 'legacy_link_flags' + flag_set { + expand_if_all_available: 'legacy_link_flags' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'legacy_link_flags' + flag: '%{legacy_link_flags}' + } + } + } + + feature { + name: 'linker_param_file' + flag_set { + expand_if_all_available: 'linker_param_file' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + action: 'c++-link-static-library' + flag_group { + flag: '@%{linker_param_file}' + } + } + } + + feature { + name: 'static_link_msvcrt' + } + + feature { + name: 'static_link_msvcrt_no_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MT" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:libcmt.lib" + } + } + requires: { feature: 'fastbuild'} + requires: { feature: 'opt'} + } + + feature { + name: 'dynamic_link_msvcrt_no_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MD" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:msvcrt.lib" + } + } + requires: { feature: 'fastbuild'} + requires: { feature: 'opt'} + } + + feature { + name: 'static_link_msvcrt_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MTd" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:libcmtd.lib" + } + } + requires: { feature: 'dbg'} + } + + feature { + name: 'dynamic_link_msvcrt_debug' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/MDd" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEFAULTLIB:msvcrtd.lib" + } + } + requires: { feature: 'dbg'} + } + + feature { + name: 'dbg' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/Od" + flag: "/Z7" + flag: "/DDEBUG" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEBUG:FULL" + flag: "/INCREMENTAL:NO" + } + } + implies: 'generate_pdb_file' + } + + feature { + name: 'fastbuild' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/Od" + flag: "/Z7" + flag: "/DDEBUG" + } + } + flag_set { + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEBUG:FASTLINK" + flag: "/INCREMENTAL:NO" + } + } + implies: 'generate_pdb_file' + } + + feature { + name: 'opt' + flag_set { + action: 'c-compile' + action: 'c++-compile' + flag_group { + flag: "/O2" + flag: "/DNDEBUG" + } + } + } + + feature { + name: 'user_compile_flags' + flag_set { + expand_if_all_available: 'user_compile_flags' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + iterate_over: 'user_compile_flags' + flag: '%{user_compile_flags}' + } + } + } + + feature { + name: 'sysroot' + flag_set { + expand_if_all_available: 'sysroot' + action: 'assemble' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + iterate_over: 'sysroot' + flag: '--sysroot=%{sysroot}' + } + } + } + + feature { + name: 'unfiltered_compile_flags' + flag_set { + expand_if_all_available: 'unfiltered_compile_flags' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + iterate_over: 'unfiltered_compile_flags' + flag: '%{unfiltered_compile_flags}' + } + } + } + + feature { + name: 'compiler_output_flags' + flag_set { + action: 'assemble' + flag_group { + expand_if_all_available: 'output_file' + expand_if_none_available: 'output_assembly_file' + expand_if_none_available: 'output_preprocess_file' + flag: '/Fo%{output_file}' + flag: '/Zi' + } + } + flag_set { + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + expand_if_all_available: 'output_file' + expand_if_none_available: 'output_assembly_file' + expand_if_none_available: 'output_preprocess_file' + flag: '/Fo%{output_file}' + } + flag_group { + expand_if_all_available: 'output_file' + expand_if_all_available: 'output_assembly_file' + flag: '/Fa%{output_file}' + } + flag_group { + expand_if_all_available: 'output_file' + expand_if_all_available: 'output_preprocess_file' + flag: '/P' + flag: '/Fi%{output_file}' + } + } + } + + feature { + name: 'compiler_input_flags' + flag_set { + action: 'assemble' + action: 'preprocess-assemble' + action: 'c-compile' + action: 'c++-compile' + action: 'c++-header-parsing' + action: 'c++-module-compile' + action: 'c++-module-codegen' + flag_group { + expand_if_all_available: 'source_file' + flag: '/c' + flag: '%{source_file}' + } + } + } + + feature { + name : 'def_file', + flag_set { + expand_if_all_available: 'def_file_path' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: "c++-link-nodeps-dynamic-library" + flag_group { + flag: "/DEF:%{def_file_path}" + # We can specify a different DLL name in DEF file, /ignore:4070 suppresses + # the warning message about DLL name doesn't match the default one. + # See https://msdn.microsoft.com/en-us/library/sfkk2fz7.aspx + flag: "/ignore:4070" + } + } + } + + feature { + name: 'windows_export_all_symbols' + } + + feature { + name: 'no_windows_export_all_symbols' + } + + linking_mode_flags { mode: DYNAMIC } +} diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/clang/bin/crosstool_wrapper_driver_is_not_gcc b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/clang/bin/crosstool_wrapper_driver_is_not_gcc new file mode 100755 index 0000000000..7ae59e9967 --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/clang/bin/crosstool_wrapper_driver_is_not_gcc @@ -0,0 +1,264 @@ +#!/usr/bin/env python +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Crosstool wrapper for compiling CUDA programs. + +SYNOPSIS: + crosstool_wrapper_is_not_gcc [options passed in by cc_library() + or cc_binary() rule] + +DESCRIPTION: + This script is expected to be called by the cc_library() or cc_binary() bazel + rules. When the option "-x cuda" is present in the list of arguments passed + to this script, it invokes the nvcc CUDA compiler. Most arguments are passed + as is as a string to --compiler-options of nvcc. When "-x cuda" is not + present, this wrapper invokes hybrid_driver_is_not_gcc with the input + arguments as is. + +NOTES: + Changes to the contents of this file must be propagated from + //third_party/gpus/crosstool/crosstool_wrapper_is_not_gcc to + //third_party/gpus/crosstool/v*/*/clang/bin/crosstool_wrapper_is_not_gcc +""" + +from __future__ import print_function + +__author__ = 'keveman@google.com (Manjunath Kudlur)' + +from argparse import ArgumentParser +import os +import subprocess +import re +import sys +import pipes + +# Template values set by cuda_autoconf. +CPU_COMPILER = ('/usr/bin/gcc') +GCC_HOST_COMPILER_PATH = ('/usr/bin/gcc') + +NVCC_PATH = '/usr/local/cuda-10.0/bin/nvcc' +PREFIX_DIR = os.path.dirname(GCC_HOST_COMPILER_PATH) +NVCC_VERSION = '10.0' + +def Log(s): + print('gpus/crosstool: {0}'.format(s)) + + +def GetOptionValue(argv, option): + """Extract the list of values for option from the argv list. + + Args: + argv: A list of strings, possibly the argv passed to main(). + option: The option whose value to extract, without the leading '-'. + + Returns: + A list of values, either directly following the option, + (eg., -opt val1 val2) or values collected from multiple occurrences of + the option (eg., -opt val1 -opt val2). + """ + + parser = ArgumentParser() + parser.add_argument('-' + option, nargs='*', action='append') + args, _ = parser.parse_known_args(argv) + if not args or not vars(args)[option]: + return [] + else: + return sum(vars(args)[option], []) + + +def GetHostCompilerOptions(argv): + """Collect the -isystem, -iquote, and --sysroot option values from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + + Returns: + The string that can be used as the --compiler-options to nvcc. + """ + + parser = ArgumentParser() + parser.add_argument('-isystem', nargs='*', action='append') + parser.add_argument('-iquote', nargs='*', action='append') + parser.add_argument('--sysroot', nargs=1) + parser.add_argument('-g', nargs='*', action='append') + parser.add_argument('-fno-canonical-system-headers', action='store_true') + + args, _ = parser.parse_known_args(argv) + + opts = '' + + if args.isystem: + opts += ' -isystem ' + ' -isystem '.join(sum(args.isystem, [])) + if args.iquote: + opts += ' -iquote ' + ' -iquote '.join(sum(args.iquote, [])) + if args.g: + opts += ' -g' + ' -g'.join(sum(args.g, [])) + if args.fno_canonical_system_headers: + opts += ' -fno-canonical-system-headers' + if args.sysroot: + opts += ' --sysroot ' + args.sysroot[0] + + return opts + +def _update_options(nvcc_options): + if NVCC_VERSION in ("7.0",): + return nvcc_options + + update_options = { "relaxed-constexpr" : "expt-relaxed-constexpr" } + return [ update_options[opt] if opt in update_options else opt + for opt in nvcc_options ] + +def GetNvccOptions(argv): + """Collect the -nvcc_options values from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + + Returns: + The string that can be passed directly to nvcc. + """ + + parser = ArgumentParser() + parser.add_argument('-nvcc_options', nargs='*', action='append') + + args, _ = parser.parse_known_args(argv) + + if args.nvcc_options: + options = _update_options(sum(args.nvcc_options, [])) + return ' '.join(['--'+a for a in options]) + return '' + + +def InvokeNvcc(argv, log=False): + """Call nvcc with arguments assembled from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + log: True if logging is requested. + + Returns: + The return value of calling os.system('nvcc ' + args) + """ + + host_compiler_options = GetHostCompilerOptions(argv) + nvcc_compiler_options = GetNvccOptions(argv) + opt_option = GetOptionValue(argv, 'O') + m_options = GetOptionValue(argv, 'm') + m_options = ''.join([' -m' + m for m in m_options if m in ['32', '64']]) + include_options = GetOptionValue(argv, 'I') + out_file = GetOptionValue(argv, 'o') + depfiles = GetOptionValue(argv, 'MF') + defines = GetOptionValue(argv, 'D') + defines = ''.join([' -D' + define for define in defines]) + undefines = GetOptionValue(argv, 'U') + undefines = ''.join([' -U' + define for define in undefines]) + std_options = GetOptionValue(argv, 'std') + # currently only c++11 is supported by Cuda 7.0 std argument + nvcc_allowed_std_options = ["c++11"] + std_options = ''.join([' -std=' + define + for define in std_options if define in nvcc_allowed_std_options]) + + # The list of source files get passed after the -c option. I don't know of + # any other reliable way to just get the list of source files to be compiled. + src_files = GetOptionValue(argv, 'c') + + # Pass -w through from host to nvcc, but don't do anything fancier with + # warnings-related flags, since they're not necessarily the same across + # compilers. + warning_options = ' -w' if '-w' in argv else '' + + if len(src_files) == 0: + return 1 + if len(out_file) != 1: + return 1 + + opt = (' -O2' if (len(opt_option) > 0 and int(opt_option[0]) > 0) + else ' -g -G') + + includes = (' -I ' + ' -I '.join(include_options) + if len(include_options) > 0 + else '') + + # Unfortunately, there are other options that have -c prefix too. + # So allowing only those look like C/C++ files. + src_files = [f for f in src_files if + re.search('\.cpp$|\.cc$|\.c$|\.cxx$|\.C$', f)] + srcs = ' '.join(src_files) + out = ' -o ' + out_file[0] + + supported_cuda_compute_capabilities = [ "3.0" ] + nvccopts = '-D_FORCE_INLINES ' + for capability in supported_cuda_compute_capabilities: + capability = capability.replace('.', '') + nvccopts += r'-gencode=arch=compute_%s,\"code=sm_%s,compute_%s\" ' % ( + capability, capability, capability) + nvccopts += ' ' + nvcc_compiler_options + nvccopts += undefines + nvccopts += defines + nvccopts += std_options + nvccopts += m_options + nvccopts += warning_options + + if depfiles: + # Generate the dependency file + depfile = depfiles[0] + cmd = (NVCC_PATH + ' ' + nvccopts + + ' --compiler-options "' + host_compiler_options + '"' + + ' --compiler-bindir=' + GCC_HOST_COMPILER_PATH + + ' -I .' + + ' -x cu ' + opt + includes + ' ' + srcs + ' -M -o ' + depfile) + if log: Log(cmd) + exit_status = os.system(cmd) + if exit_status != 0: + return exit_status + + cmd = (NVCC_PATH + ' ' + nvccopts + + ' --compiler-options "' + host_compiler_options + ' -fPIC"' + + ' --compiler-bindir=' + GCC_HOST_COMPILER_PATH + + ' -I .' + + ' -x cu ' + opt + includes + ' -c ' + srcs + out) + + # TODO(zhengxq): for some reason, 'gcc' needs this help to find 'as'. + # Need to investigate and fix. + cmd = 'PATH=' + PREFIX_DIR + ':$PATH ' + cmd + if log: Log(cmd) + return os.system(cmd) + + +def main(): + parser = ArgumentParser() + parser.add_argument('-x', nargs=1) + parser.add_argument('--cuda_log', action='store_true') + args, leftover = parser.parse_known_args(sys.argv[1:]) + + if args.x and args.x[0] == 'cuda': + if args.cuda_log: Log('-x cuda') + leftover = [pipes.quote(s) for s in leftover] + if args.cuda_log: Log('using nvcc') + return InvokeNvcc(leftover, log=args.cuda_log) + + # Strip our flags before passing through to the CPU compiler for files which + # are not -x cuda. We can't just pass 'leftover' because it also strips -x. + # We not only want to pass -x to the CPU compiler, but also keep it in its + # relative location in the argv list (the compiler is actually sensitive to + # this). + cpu_compiler_flags = [flag for flag in sys.argv[1:] + if not flag.startswith(('--cuda_log'))] + + return subprocess.call([CPU_COMPILER] + cpu_compiler_flags) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.bat b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.bat new file mode 100755 index 0000000000..e896e654fd --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.bat @@ -0,0 +1,20 @@ +:: Copyright 2015 The TensorFlow Authors. 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. +:: ============================================================================= + +:: Invoke msvc_wrapper_for_nvcc.py, which is located in the same directory. +@echo OFF +set arg0=%~0 +for %%F in ("%arg0%") do set DRIVER_BIN=%%~dpF +"/usr/bin/python3" -B "%DRIVER_BIN%\msvc_wrapper_for_nvcc.py" %* diff --git a/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.py b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.py new file mode 100755 index 0000000000..00483951af --- /dev/null +++ b/third_party/toolchains/preconfig/ubuntu14.04/gcc-nvcc-cuda10.0/windows/msvc_wrapper_for_nvcc.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# Copyright 2015 The TensorFlow Authors. 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. +# ============================================================================== + +"""Crosstool wrapper for compiling CUDA programs with nvcc on Windows. + +DESCRIPTION: + This script is the Windows version of //third_party/gpus/crosstool/crosstool_wrapper_is_not_gcc +""" + +from __future__ import print_function + +from argparse import ArgumentParser +import os +import subprocess +import re +import sys +import pipes + +# Template values set by cuda_autoconf. +CPU_COMPILER = ('/usr/bin/gcc') +GCC_HOST_COMPILER_PATH = ('/usr/bin/gcc') + +NVCC_PATH = '/usr/local/cuda-10.0/bin/nvcc' +NVCC_VERSION = '10.0' +NVCC_TEMP_DIR = "C:\\Windows\\Temp\\nvcc_inter_files_tmp_dir" +supported_cuda_compute_capabilities = [ "3.0" ] + +def Log(s): + print('gpus/crosstool: {0}'.format(s)) + + +def GetOptionValue(argv, option): + """Extract the list of values for option from options. + + Args: + option: The option whose value to extract, without the leading '/'. + + Returns: + 1. A list of values, either directly following the option, + (eg., /opt val1 val2) or values collected from multiple occurrences of + the option (eg., /opt val1 /opt val2). + 2. The leftover options. + """ + + parser = ArgumentParser(prefix_chars='/') + parser.add_argument('/' + option, nargs='*', action='append') + args, leftover = parser.parse_known_args(argv) + if args and vars(args)[option]: + return (sum(vars(args)[option], []), leftover) + return ([], leftover) + +def _update_options(nvcc_options): + if NVCC_VERSION in ("7.0",): + return nvcc_options + + update_options = { "relaxed-constexpr" : "expt-relaxed-constexpr" } + return [ update_options[opt] if opt in update_options else opt + for opt in nvcc_options ] + +def GetNvccOptions(argv): + """Collect the -nvcc_options values from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + + Returns: + 1. The string that can be passed directly to nvcc. + 2. The leftover options. + """ + + parser = ArgumentParser() + parser.add_argument('-nvcc_options', nargs='*', action='append') + + args, leftover = parser.parse_known_args(argv) + + if args.nvcc_options: + options = _update_options(sum(args.nvcc_options, [])) + return (['--' + a for a in options], leftover) + return ([], leftover) + + +def InvokeNvcc(argv, log=False): + """Call nvcc with arguments assembled from argv. + + Args: + argv: A list of strings, possibly the argv passed to main(). + log: True if logging is requested. + + Returns: + The return value of calling os.system('nvcc ' + args) + """ + + src_files = [f for f in argv if + re.search('\.cpp$|\.cc$|\.c$|\.cxx$|\.C$', f)] + if len(src_files) == 0: + raise Error('No source files found for cuda compilation.') + + out_file = [ f for f in argv if f.startswith('/Fo') ] + if len(out_file) != 1: + raise Error('Please sepecify exactly one output file for cuda compilation.') + out = ['-o', out_file[0][len('/Fo'):]] + + nvcc_compiler_options, argv = GetNvccOptions(argv) + + opt_option, argv = GetOptionValue(argv, 'O') + opt = ['-g', '-G'] + if (len(opt_option) > 0 and opt_option[0] != 'd'): + opt = ['-O2'] + + include_options, argv = GetOptionValue(argv, 'I') + includes = ["-I " + include for include in include_options] + + defines, argv = GetOptionValue(argv, 'D') + defines = ['-D' + define for define in defines] + + undefines, argv = GetOptionValue(argv, 'U') + undefines = ['-U' + define for define in undefines] + + # The rest of the unrecongized options should be passed to host compiler + host_compiler_options = [option for option in argv if option not in (src_files + out_file)] + + m_options = ["-m64"] + + nvccopts = ['-D_FORCE_INLINES'] + for capability in supported_cuda_compute_capabilities: + capability = capability.replace('.', '') + nvccopts += [r'-gencode=arch=compute_%s,"code=sm_%s,compute_%s"' % ( + capability, capability, capability)] + nvccopts += nvcc_compiler_options + nvccopts += undefines + nvccopts += defines + nvccopts += m_options + nvccopts += ['--compiler-options="' + " ".join(host_compiler_options) + '"'] + nvccopts += ['-x', 'cu'] + opt + includes + out + ['-c'] + src_files + # If we don't specify --keep-dir, nvcc will generate intermediate files under TEMP + # Put them under NVCC_TEMP_DIR instead, then Bazel can ignore files under NVCC_TEMP_DIR during dependency check + # http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#options-for-guiding-compiler-driver + # Different actions are sharing NVCC_TEMP_DIR, so we cannot remove it if the directory already exists. + if os.path.isfile(NVCC_TEMP_DIR): + os.remove(NVCC_TEMP_DIR) + if not os.path.exists(NVCC_TEMP_DIR): + os.makedirs(NVCC_TEMP_DIR) + nvccopts += ['--keep', '--keep-dir', NVCC_TEMP_DIR] + cmd = [NVCC_PATH] + nvccopts + if log: + Log(cmd) + proc = subprocess.Popen(cmd, + stdout=sys.stdout, + stderr=sys.stderr, + env=os.environ.copy(), + shell=True) + proc.wait() + return proc.returncode + +def main(): + parser = ArgumentParser() + parser.add_argument('-x', nargs=1) + parser.add_argument('--cuda_log', action='store_true') + args, leftover = parser.parse_known_args(sys.argv[1:]) + + if args.x and args.x[0] == 'cuda': + if args.cuda_log: Log('-x cuda') + leftover = [pipes.quote(s) for s in leftover] + if args.cuda_log: Log('using nvcc') + return InvokeNvcc(leftover, log=args.cuda_log) + + # Strip our flags before passing through to the CPU compiler for files which + # are not -x cuda. We can't just pass 'leftover' because it also strips -x. + # We not only want to pass -x to the CPU compiler, but also keep it in its + # relative location in the argv list (the compiler is actually sensitive to + # this). + cpu_compiler_flags = [flag for flag in sys.argv[1:] + if not flag.startswith(('--cuda_log')) + and not flag.startswith(('-nvcc_options'))] + + return subprocess.call([CPU_COMPILER] + cpu_compiler_flags) + +if __name__ == '__main__': + sys.exit(main()) -- GitLab From 92112c2ff39da4ebf37b518aabcbd48e3137cc9c Mon Sep 17 00:00:00 2001 From: Feiyang Chen Date: Mon, 26 Nov 2018 23:08:28 +0800 Subject: [PATCH 293/672] add tensorFlow visualization toolkit links --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8af5370bef..0d1e1ea2ea 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ Build Type * [TensorFlow Roadmap](https://www.tensorflow.org/community/roadmap) * [TensorFlow White Papers](https://www.tensorflow.org/about/bib) * [TensorFlow YouTube Channel](https://www.youtube.com/channel/UC0rqucBdTuFTjJiefW5t-IQ) +* [TensorFlow Visualization Toolkit](https://github.com/tensorflow/tensorboard) Learn more about the TensorFlow community at the [community page of tensorflow.org](https://www.tensorflow.org/community) for a few ways to participate. -- GitLab From 64e084b8cb27e8c53b15468c21f1b3471b4b9659 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Mon, 26 Nov 2018 07:35:53 -0800 Subject: [PATCH 294/672] Add cond_v2 and while_v2 as a dependency for tests PiperOrigin-RevId: 222822446 --- tensorflow/python/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 5c9e7f5e89..3fe381183a 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -1081,10 +1081,12 @@ py_library( srcs_version = "PY2AND3", deps = [ ":client", + ":cond_v2", ":framework_test_lib", ":gradient_checker", ":platform_test", ":util", + ":while_v2", ], ) -- GitLab From 8be3b4631892e10b18d0a4cc8cad6099c1f6803b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 08:24:04 -0800 Subject: [PATCH 295/672] Migrate ::StringPiece to absl::string_view. PiperOrigin-RevId: 222828687 --- tensorflow/core/platform/regexp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/platform/regexp.h b/tensorflow/core/platform/regexp.h index a4eedf3045..ca9ca1e244 100644 --- a/tensorflow/core/platform/regexp.h +++ b/tensorflow/core/platform/regexp.h @@ -16,6 +16,7 @@ limitations under the License. #ifndef TENSORFLOW_PLATFORM_REGEXP_H_ #define TENSORFLOW_PLATFORM_REGEXP_H_ +#include "absl/strings/string_view.h" #include "tensorflow/core/platform/platform.h" #include "tensorflow/core/platform/types.h" @@ -23,7 +24,7 @@ limitations under the License. defined(GOOGLE_RE2) #include "tensorflow/core/platform/google/build_config/re2.h" namespace tensorflow { -typedef ::StringPiece RegexpStringPiece; +typedef absl::string_view RegexpStringPiece; } // namespace tensorflow #else -- GitLab From b53a109aa242d8ef493f18d97f872494efa17082 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Mon, 26 Nov 2018 08:34:23 -0800 Subject: [PATCH 296/672] Change API for io.decode_csv for TF 2.0. PiperOrigin-RevId: 222829999 --- tensorflow/python/ops/parsing_ops.py | 50 ++++++++++++++++++- .../tools/api/golden/v2/tensorflow.io.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 5 ++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/parsing_ops.py b/tensorflow/python/ops/parsing_ops.py index 7a11096d4f..a84af6c5cf 100644 --- a/tensorflow/python/ops/parsing_ops.py +++ b/tensorflow/python/ops/parsing_ops.py @@ -1828,7 +1828,7 @@ def _parse_single_sequence_example_raw(serialized, # Swap `name` and `na_value` for backward compatibility. -@tf_export("io.decode_csv", v1=["io.decode_csv", "decode_csv"]) +@tf_export(v1=["io.decode_csv", "decode_csv"]) @deprecation.deprecated_endpoints("decode_csv") def decode_csv(records, record_defaults, @@ -1867,6 +1867,54 @@ def decode_csv(records, A list of `Tensor` objects. Has the same type as `record_defaults`. Each tensor will have the same shape as records. + Raises: + ValueError: If any of the arguments is malformed. + """ + return decode_csv_v2( + records, record_defaults, + field_delim, use_quote_delim, + na_value, select_cols, name + ) + + +@tf_export("io.decode_csv", v1=[]) +def decode_csv_v2(records, + record_defaults, + field_delim=",", + use_quote_delim=True, + na_value="", + select_cols=None, + name=None): + """Convert CSV records to tensors. Each column maps to one tensor. + + RFC 4180 format is expected for the CSV records. + (https://tools.ietf.org/html/rfc4180) + Note that we allow leading and trailing spaces with int or float field. + + Args: + records: A `Tensor` of type `string`. + Each string is a record/row in the csv and all records should have + the same format. + record_defaults: A list of `Tensor` objects with specific types. + Acceptable types are `float32`, `float64`, `int32`, `int64`, `string`. + One tensor per column of the input record, with either a + scalar default value for that column or an empty vector if the column is + required. + field_delim: An optional `string`. Defaults to `","`. + char delimiter to separate fields in a record. + use_quote_delim: An optional `bool`. Defaults to `True`. + If false, treats double quotation marks as regular + characters inside of the string fields (ignoring RFC 4180, Section 2, + Bullet 5). + na_value: Additional string to recognize as NA/NaN. + select_cols: Optional sorted list of column indices to select. If specified, + only this subset of columns will be parsed and returned. + name: A name for the operation (optional). + + Returns: + A list of `Tensor` objects. Has the same type as `record_defaults`. + Each tensor will have the same shape as records. + Raises: ValueError: If any of the arguments is malformed. """ diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt index 98250df803..8906329742 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.pbtxt @@ -66,7 +66,7 @@ tf_module { } member_method { name: "decode_csv" - argspec: "args=[\'records\', \'record_defaults\', \'field_delim\', \'use_quote_delim\', \'name\', \'na_value\', \'select_cols\'], varargs=None, keywords=None, defaults=[\',\', \'True\', \'None\', \'\', \'None\'], " + argspec: "args=[\'records\', \'record_defaults\', \'field_delim\', \'use_quote_delim\', \'na_value\', \'select_cols\', \'name\'], varargs=None, keywords=None, defaults=[\',\', \'True\', \'\', \'None\', \'None\'], " } member_method { name: "decode_gif" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 33e4f0f442..ed29a7cb62 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -379,6 +379,11 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.sparse.segment_sum": [ "data", "indices", "segment_ids", "name", "num_segments" ], + "tf.io.decode_csv": [ + "records", "record_defaults", + "field_delim", "use_quote_delim", + "name", "na_value", "select_cols", + ], "tf.strings.substr": ["input", "pos", "len", "name", "unit"], "tf.strings.reduce_join": [ "input", "axis", "keep_dims", "separator", "name", -- GitLab From 47c8db116582633cfd898d2fab19fc57922e6a67 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Mon, 26 Nov 2018 08:38:45 -0800 Subject: [PATCH 297/672] Fix top TensorBoard link. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d1e1ea2ea..eaee8c274b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ data flow graphs. The graph nodes represent mathematical operations, while the graph edges represent the multidimensional data arrays (tensors) that flow between them. This flexible architecture enables you to deploy computation to one or more CPUs or GPUs in a desktop, server, or mobile device without rewriting -code. TensorFlow also includes [TensorBoard](https://www.tensorflow.org/guide/summaries_and_tensorboard), a data visualization toolkit. +code. TensorFlow also includes [TensorBoard](https://github.com/tensorflow/tensorboard), +a data visualization toolkit. TensorFlow was originally developed by researchers and engineers working on the Google Brain team within Google's Machine Intelligence Research -- GitLab From 0d2e879a162a6c92d5602a7a88ea4e92fd104ee2 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Mon, 26 Nov 2018 08:55:52 -0800 Subject: [PATCH 298/672] Refactor shared cond_v2 and _IfGrad logic into _build_cond helper method. PiperOrigin-RevId: 222832725 --- tensorflow/python/ops/cond_v2.py | 148 +++++++++++++++---------------- 1 file changed, 73 insertions(+), 75 deletions(-) diff --git a/tensorflow/python/ops/cond_v2.py b/tensorflow/python/ops/cond_v2.py index 0f08c611bc..4db59871d3 100644 --- a/tensorflow/python/ops/cond_v2.py +++ b/tensorflow/python/ops/cond_v2.py @@ -74,55 +74,14 @@ def cond_v2(pred, true_fn, false_fn, name="cond"): false_name, read_only_collections=False), add_control_dependencies=add_control_dependencies, op_return_value=pred) - _check_same_outputs(true_graph, false_graph) - - # Add inputs to true_graph and false_graph to make them match. Note that - # this modifies true_graph and false_graph. - cond_inputs = _make_inputs_match(true_graph, false_graph, - true_graph.external_captures, - false_graph.external_captures) - - # Add all intermediate tensors as function outputs so they're available for - # the gradient computation. - - true_intermediates = _get_intermediates(true_graph) - false_intermediates = _get_intermediates(false_graph) - - # Save the original number of outputs to return to the caller. - num_cond_outputs = len(true_graph.outputs) - - # Make the number/type of new intermediate outputs match. - extra_true_outputs, extra_false_outputs = _pad_params( - true_graph, false_graph, true_intermediates, false_intermediates) - - true_graph.outputs.extend(extra_true_outputs) - false_graph.outputs.extend(extra_false_outputs) - - # Create the If op. - tensors = gen_functional_ops._if( # pylint: disable=protected-access - pred, - cond_inputs, [t.dtype for t in true_graph.outputs], - util.create_new_tf_function(true_graph), - util.create_new_tf_function(false_graph), - output_shapes=_get_output_shapes(true_graph.outputs, - false_graph.outputs), - name=scope) - - # TODO(b/110167197) this approach requires cond_v2 to have at least 1 output - util.maybe_set_lowering_attr(tensors[0].op) - - # Return identities for each output of the If op, rather than the output of - # the If op directly. This makes pruning work if the output of cond() is - # fetched: the lowering pass converts the If outputs into IdentityN outputs, - # which if fetched will cause all ops in the taken branch to be run (since - # it takes all merge ops as input). After lowering, each output identity op - # will end up with only the appropriate merge op as input. - # TODO(b/79984175): this doesn't have to be a tuple once we covert to the - # correct output structure - tensors = tuple(array_ops.identity(t) for t in tensors) + + outputs = _build_cond(pred, true_graph, false_graph, + true_graph.external_captures, + false_graph.external_captures, + name=scope) return func_graph_module.pack_sequence_as(true_graph.structured_outputs, - tensors[:num_cond_outputs]) + outputs) @ops.RegisterGradient("If") @@ -150,44 +109,83 @@ def _IfGrad(op, *grads): # pylint: disable=invalid-name true_grad_inputs = _resolve_grad_inputs(true_graph, true_grad_graph) false_grad_inputs = _resolve_grad_inputs(false_graph, false_grad_graph) - # Make the inputs to true_grad_graph and false_grad_graph match. Note that - # this modifies true_grad_graph and false_grad_graph. - grad_inputs = _make_inputs_match(true_grad_graph, false_grad_graph, - true_grad_inputs, false_grad_inputs) + outputs = _build_cond(op.inputs[0], true_grad_graph, false_grad_graph, + true_grad_inputs, false_grad_inputs) + + # The predicate has no gradient. + return [None] + outputs + + +def _build_cond(pred, true_graph, false_graph, true_inputs, false_inputs, + name=None): + """Creates an If op from the specified predicate, branch functions and inputs. + + Note that this modifies true_graph and false_graph to make the inputs match, + and to output all intermediates values so they're available for the gradient + computation. + + true_graph and false_graph need not have the same input types, but they must + have the same outpute types. + + Args: + pred: boolean Tensor + true_graph: FuncGraph + false_graph: FuncGraph + true_inputs: a list of Tensors to be passed to true_graph as input. + false_inputs: a list of Tensors to be passed to false_graph as input. + name: the name for the If op. + + Returns: + A list of Tensors which are the outputs of the If op. Does not include added + intermediate outputs. + """ + _check_same_outputs(true_graph, false_graph) + + # Add inputs to true_graph and false_graph to make them match. Note that + # this modifies true_graph and false_graph. + cond_inputs = _make_inputs_match(true_graph, false_graph, + true_inputs, false_inputs) # Add all intermediate tensors as function outputs so they're available for - # higher-order gradient computations. + # the gradient computation. - true_grad_intermediates = _get_intermediates(true_grad_graph) - false_grad_intermediates = _get_intermediates(false_grad_graph) + true_intermediates = _get_intermediates(true_graph) + false_intermediates = _get_intermediates(false_graph) - # Save the original number of gradient outputs to return. - num_grad_outputs = len(true_grad_graph.outputs) + # Save the original number of outputs to return to the caller. + num_cond_outputs = len(true_graph.outputs) # Make the number/type of new intermediate outputs match. - extra_true_grad_outputs, extra_false_grad_outputs = _pad_params( - true_grad_graph, false_grad_graph, - true_grad_intermediates, false_grad_intermediates) - - true_grad_graph.outputs.extend(extra_true_grad_outputs) - false_grad_graph.outputs.extend(extra_false_grad_outputs) - - # Create the gradient If op. - tensors = gen_functional_ops._if( - op.inputs[0], - grad_inputs, [t.dtype for t in true_grad_graph.outputs], - util.create_new_tf_function(true_grad_graph), - util.create_new_tf_function(false_grad_graph), - output_shapes=_get_output_shapes(true_grad_graph.outputs, - false_grad_graph.outputs)) - + extra_true_outputs, extra_false_outputs = _pad_params( + true_graph, false_graph, true_intermediates, false_intermediates) + + true_graph.outputs.extend(extra_true_outputs) + false_graph.outputs.extend(extra_false_outputs) + + # Create the If op. + tensors = gen_functional_ops._if( # pylint: disable=protected-access + pred, + cond_inputs, [t.dtype for t in true_graph.outputs], + util.create_new_tf_function(true_graph), + util.create_new_tf_function(false_graph), + output_shapes=_get_output_shapes(true_graph.outputs, + false_graph.outputs), + name=name) + + # TODO(b/110167197) this approach requires cond_v2 to have at least 1 output util.maybe_set_lowering_attr(tensors[0].op) - # See comment in cond_v2. + # Return identities for each output of the If op, rather than the output of + # the If op directly. This makes pruning work if the output of cond() is + # fetched: the lowering pass converts the If outputs into IdentityN outputs, + # which if fetched will cause all ops in the taken branch to be run (since + # it takes all merge ops as input). After lowering, each output identity op + # will end up with only the appropriate merge op as input. + # TODO(b/79984175): this doesn't have to be a tuple once we covert to the + # correct output structure tensors = [array_ops.identity(t) for t in tensors] - # The predicate has no gradient. - return [None] + tensors[:num_grad_outputs] + return tensors[:num_cond_outputs] def _get_func_graphs(if_op): -- GitLab From f0c122b979c6a0047eed25a22d2e7120a2ae258d Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 09:00:23 -0800 Subject: [PATCH 299/672] Exposing CUDA 10 toolchain for image submitted in CL/222817562. PiperOrigin-RevId: 222833255 --- third_party/toolchains/BUILD | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/third_party/toolchains/BUILD b/third_party/toolchains/BUILD index a7b4687c02..9da417fd5f 100644 --- a/third_party/toolchains/BUILD +++ b/third_party/toolchains/BUILD @@ -35,3 +35,16 @@ platform( value:"docker://gcr.io/asci-toolchain/nosla-cuda9.0-cudnn7-ubuntu14.04@%s" }""" % container_digests["cuda9.0-cudnn7-ubuntu14.04"], ) + +platform( + name = "rbe_cuda10.0-cudnn7-ubuntu14.04", + constraint_values = [ + "@bazel_tools//platforms:x86_64", + "@bazel_tools//platforms:linux", + ], + remote_execution_properties = """ + properties: { + name: "container-image" + value:"docker://gcr.io/asci-toolchain/nosla-cuda10.0-cudnn7-ubuntu14.04@%s" + }""" % container_digests["cuda10.0-cudnn7-ubuntu14.04"], +) -- GitLab From 284b2783c4676c9d00199a585db9d6d07d9e68be Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 09:10:04 -0800 Subject: [PATCH 300/672] Prevent executor accessing a deleted TraceCollector by making the latter a global singleton object. Currently, a device tracer can stop tracing at any point, while data pipiline is still running and uses a cached stale TraceCollector pointer. PiperOrigin-RevId: 222834820 --- tensorflow/core/common_runtime/executor.cc | 16 +++--- .../core/platform/default/device_tracer.cc | 55 ++++++++++++++----- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/tensorflow/core/common_runtime/executor.cc b/tensorflow/core/common_runtime/executor.cc index 77b249c2b4..6b3284b84a 100644 --- a/tensorflow/core/common_runtime/executor.cc +++ b/tensorflow/core/common_runtime/executor.cc @@ -1239,7 +1239,6 @@ class ExecutorState { // Step-local container. ScopedStepContainer* step_container_; StepStatsCollectorInterface* const stats_collector_; - const tracing::TraceCollector* const trace_collector_; const tracing::EventCollector* const event_collector_; Context context_; @@ -1366,7 +1365,6 @@ ExecutorState::ExecutorState(const Executor::Args& args, ExecutorImpl* impl) tensor_store_(args.tensor_store), step_container_(args.step_container), stats_collector_(args.stats_collector), - trace_collector_(tracing::GetTraceCollector()), event_collector_( tracing::GetEventCollector(tracing::EventCategory::kCompute)), context_(ContextKind::kThread), @@ -1565,7 +1563,6 @@ struct ExecutorState::AsyncState { // Returns true if `item` might be traced by the given trace and event // collectors. Returns false only if `item` definitely will not be traced. bool MightTrace(const NodeItem& item, - const tracing::TraceCollector* trace_collector, const tracing::EventCollector* event_collector, bool using_annotations) { // Tracing will only be enabled if either `event_collector` is non null, @@ -1578,6 +1575,7 @@ bool MightTrace(const NodeItem& item, if (event_collector != nullptr) { return true; } + auto* trace_collector = tracing::GetTraceCollector(); if (trace_collector) { if (using_annotations) { return trace_collector->IsEnabledForAnnotations(); @@ -1762,9 +1760,8 @@ void ExecutorState::Process(TaggedNode tagged_node, int64 scheduled_nsec) { OpKernelContext ctx(¶ms, item.num_outputs); nodestats::SetOpStart(stats); - if (TF_PREDICT_FALSE(MightTrace(item, trace_collector_, - event_collector_, - trace_using_annotations_))) { + if (TF_PREDICT_FALSE( + MightTrace(item, event_collector_, trace_using_annotations_))) { const string& op_name = op_kernel->name(); tracing::ScopedRegion region(tracing::EventCategory::kCompute, op_name); @@ -2048,13 +2045,14 @@ void ExecutorState::PropagateOutputs(const TaggedNode& tagged_node, TaggedNodeSeq* ready) { auto activity_handle = [&]() -> std::unique_ptr { - if (TF_PREDICT_FALSE(trace_collector_ != nullptr && - trace_collector_->IsEnabledForActivities( + auto* trace_collector = tracing::GetTraceCollector(); + if (TF_PREDICT_FALSE(trace_collector != nullptr && + trace_collector->IsEnabledForActivities( false /* is_expensive */))) { const string& op_name = item->kernel->name(); // Intentionally using ExecutorPropagateOutputs as the first key so that // users are aware that it's not the op invocation. - return trace_collector_->CreateActivityHandle( + return trace_collector->CreateActivityHandle( "ExecutorPropagateOutputs", strings::StrCat(op_name, "#id=", step_id_, "#"), false /* is_expensive */); diff --git a/tensorflow/core/platform/default/device_tracer.cc b/tensorflow/core/platform/default/device_tracer.cc index cf8b477b83..8351362e05 100644 --- a/tensorflow/core/platform/default/device_tracer.cc +++ b/tensorflow/core/platform/default/device_tracer.cc @@ -297,19 +297,16 @@ CUPTIManager *GetCUPTIManager() { // for the duration of the CUPTI API callback. TF_STATIC_THREAD_LOCAL_POD(const char *, tls_current_annotation); -class DeviceTracerImpl : public DeviceTracer, - public CUPTIClient, - public tracing::TraceCollector { +class TraceCollectorImpl : public tracing::TraceCollector { public: - DeviceTracerImpl(CUPTIManager *cupti_manager); - ~DeviceTracerImpl() override; + TraceCollectorImpl() { tracing::SetTraceCollector(this); } - // DeviceTracer interface: - Status Start() override; - Status Stop() override; - Status Collect(StepStatsCollector *collector) override; + ~TraceCollectorImpl() override { + DCHECK(!active_trace_session_) + << "Unexpected active trace session detected. "; + } - // tracing::TraceCollector interface: + // Note the method can be called after a call to Stop(). virtual std::unique_ptr CreateAnnotationHandle( StringPiece name_part1, StringPiece name_part2) const { struct Impl : public tracing::TraceCollector::Handle { @@ -332,8 +329,7 @@ class DeviceTracerImpl : public DeviceTracer, } bool IsEnabledForAnnotations() const override { - // We are always enabled for 'Annotations'. - return true; + return active_trace_session_.load(std::memory_order_relaxed); } bool IsEnabledForActivities(bool is_expensive) const override { @@ -341,6 +337,36 @@ class DeviceTracerImpl : public DeviceTracer, return false; } + void Start() { + DCHECK(!active_trace_session_) + << "Unexpected active trace session detected. "; + active_trace_session_ = true; + } + + void Stop() { + DCHECK(active_trace_session_) << "No active trace session detected. "; + active_trace_session_ = false; + } + + private: + std::atomic active_trace_session_; +}; + +TraceCollectorImpl *GlobalDefaultTraceCollector() { + static auto *instance = new TraceCollectorImpl(); + return instance; +} + +class DeviceTracerImpl : public DeviceTracer, public CUPTIClient { + public: + DeviceTracerImpl(CUPTIManager *cupti_manager); + ~DeviceTracerImpl() override; + + // DeviceTracer interface: + Status Start() override; + Status Stop() override; + Status Collect(StepStatsCollector *collector) override; + protected: // This callback is used exclusively by CUPTIManager. friend class CUPTIManager; @@ -430,7 +456,7 @@ Status DeviceTracerImpl::Start() { } // Register as a TraceEngine to receive ScopedAnnotations. - tracing::SetTraceCollector(this); + GlobalDefaultTraceCollector()->Start(); // Intercept launch and memcpy calls to capture the Op name annotation. // TODO(pbar) Add callbacks for memcpy variants. @@ -478,7 +504,8 @@ Status DeviceTracerImpl::Stop() { return Status::OK(); } CUPTI_CALL(Unsubscribe(subscriber_)); - tracing::SetTraceCollector(nullptr); + GlobalDefaultTraceCollector()->Stop(); + TF_RETURN_IF_ERROR(cupti_manager_->DisableTrace()); end_walltime_us_ = NowInUsec(); CUPTI_CALL(GetTimestamp(&end_timestamp_)); -- GitLab From d9ba1a9e6d867a2e9b48558c566e96d062761c84 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Mon, 26 Nov 2018 09:42:25 -0800 Subject: [PATCH 301/672] Fix requested changes --- .../tensorrt/convert/convert_nodes_test.cc | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 92697e2f87..45e901bf5b 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -1986,7 +1986,7 @@ TEST_F(OpConverterTest, ConvertActivation) { } // Get nodedef for activation layer. - auto get_act_nodedef = [](std::string op_name) -> NodeDef { + auto get_act_nodedef = [](string op_name) -> NodeDef { Scope s = Scope::NewRootScope(); auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); if (op_name == "Relu") { @@ -1999,11 +1999,11 @@ TEST_F(OpConverterTest, ConvertActivation) { auto act = ops::Tanh(s.WithOpName("my_act"), input); return act.operation.node()->def(); } - EXPECT_TRUE(false); - return MakeNodeDef("my_act", "Relu", {}); + ASSERT_TRUE(false); + return NodeDef(); }; // Get expected output for activation layer. - auto get_act_output = [](std::string op_name, float input) -> float { + auto get_act_output = [](string op_name, float input) -> float { if (op_name == "Relu") { return (input > 0.0f) ? input : 0.0f; } else if (op_name == "Sigmoid") { @@ -2011,32 +2011,27 @@ TEST_F(OpConverterTest, ConvertActivation) { } else if (op_name == "Tanh") { return std::tanh(input); } - EXPECT_TRUE(false); - return input; + ASSERT_TRUE(false); + return 0; }; - { - // Ok. - for (std::string op_name : {"Relu", "Sigmoid", "Tanh"}) { - Reset(); - NodeDef node_def = get_act_nodedef(op_name); - AddTestTensor("input", {1, 2, 3}); - RunValidationAndConversion(node_def); - TRT_TensorOrWeights output; - TF_EXPECT_OK(GetTensorOrWeights("my_act", &output)); - EXPECT_TRUE(output.is_tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({1, 2, 3}, output.tensor()->getDimensions())) - << output.DebugString(); - - const std::vector input_data = {-100, -2, -1, 0, 1, 100}; - std::vector output_data(6); - BuildAndRun("input", input_data, "my_act", &output_data); - for (int i = 0; i < input_data.size(); i++) { - const float expected_output = get_act_output(op_name, input_data[i]); - EXPECT_FLOAT_EQ(output_data[i], expected_output) - << op_name << "(" << input_data[i] << ") should be equal to " - << expected_output; - } + // Ok. + for (string op_name : {"Relu", "Sigmoid", "Tanh"}) { + Reset(); + NodeDef node_def = get_act_nodedef(op_name); + AddTestTensor("input", {1, 2, 3}); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_act", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray({1, 2, 3}, output.tensor()->getDimensions()); + + const std::vector input_data = {-100, -2, -1, 0, 1, 100}; + std::vector output_data(6); + BuildAndRun("input", input_data, "my_act", &output_data); + for (int i = 0; i < input_data.size(); i++) { + const float expected_output = get_act_output(op_name, input_data[i]); + EXPECT_FLOAT_EQ(output_data[i], expected_output); } } } -- GitLab From 8e8f2a2a95d15021276cc6123e12066e42ef7f26 Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Mon, 26 Nov 2018 10:02:59 -0800 Subject: [PATCH 302/672] Filter layers from checkpointable data structures on demand to avoid sync issues Previously if a wrapper (e.g. an auto-generated _ListWrapper) got out of sync with the thing it was wrapping, it would return the wrapper's collection of layers instead of layers from the thing it was wrapping. PiperOrigin-RevId: 222842576 --- .../contrib/checkpoint/python/containers.py | 4 ++ .../checkpointable/data_structures.py | 47 ++++++++++++------- .../checkpointable/data_structures_test.py | 17 +++++++ 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/tensorflow/contrib/checkpoint/python/containers.py b/tensorflow/contrib/checkpoint/python/containers.py index 242c1e8ba4..5418e2605b 100644 --- a/tensorflow/contrib/checkpoint/python/containers.py +++ b/tensorflow/contrib/checkpoint/python/containers.py @@ -46,6 +46,10 @@ class UniqueNameTracker(data_structures.CheckpointableDataStructure): self._maybe_initialize_checkpointable() self._name_counts = {} + @property + def _values(self): + return [dep.ref for dep in self._checkpoint_dependencies] + def track(self, checkpointable, base_name): """Add a dependency on `checkpointable`. diff --git a/tensorflow/python/training/checkpointable/data_structures.py b/tensorflow/python/training/checkpointable/data_structures.py index c29e5db075..a46a4a1910 100644 --- a/tensorflow/python/training/checkpointable/data_structures.py +++ b/tensorflow/python/training/checkpointable/data_structures.py @@ -111,9 +111,6 @@ class CheckpointableDataStructure(base.CheckpointableBase): """Base class for data structures which contain checkpointable objects.""" def __init__(self): - # An append-only ordered set - self._layers = [] - self.trainable = True self._extra_variables = [] @@ -128,21 +125,30 @@ class CheckpointableDataStructure(base.CheckpointableBase): ("Only checkpointable objects (such as Layers or Optimizers) may be " "stored in a List object. Got %s, which does not inherit from " "CheckpointableBase.") % (value,)) - if (isinstance(value, CheckpointableDataStructure) - or layer_utils.is_layer(value) - or layer_utils.has_weights(value)): - # Check for object-identity rather than with __eq__ to avoid - # de-duplicating empty container types. Automatically generated list - # wrappers keep things like "[] == []" true, which means "[] in [[]]" is - # also true. This becomes not true once one of the lists is mutated. - if not any((layer is value for layer in self._layers)): - self._layers.append(value) - if hasattr(value, "_use_resource_variables"): - # In subclassed models, legacy layers (tf.layers) must always use - # resource variables. - value._use_resource_variables = True # pylint: disable=protected-access + if hasattr(value, "_use_resource_variables"): + # In subclassed models, legacy layers (tf.layers) must always use + # resource variables. + value._use_resource_variables = True # pylint: disable=protected-access return value + @property + def _values(self): + """An iterable/sequence which may contain checkpointable objects.""" + raise NotImplementedError("Abstract method") + + @property + def _layers(self): + """All Layers and Layer containers, including empty containers.""" + # Filter objects on demand so that wrapper objects use values from the thing + # they're wrapping if out of sync. + collected = [] + for obj in self._values: + if (isinstance(obj, CheckpointableDataStructure) + or layer_utils.is_layer(obj) + or layer_utils.has_weights(obj)): + collected.append(obj) + return collected + @property def layers(self): return layer_utils.filter_empty_layer_containers(self._layers) @@ -265,6 +271,10 @@ class List(CheckpointableDataStructure, collections.Sequence): def _name_element(self, index): return "%d" % (index,) + @property + def _values(self): + return self + def append(self, value): """Add a new checkpointable value.""" value = self._track_value(value, self._name_element(len(self._storage))) @@ -479,6 +489,11 @@ class Mapping(CheckpointableDataStructure, collections.Mapping): def _make_storage(self, *args, **kwargs): return dict(*args, **kwargs) + @property + def _values(self): + # Sort items deterministically by key + return list(zip(*sorted(self.items(), key=lambda it: it[0])))[1] + def _name_element(self, key): if not isinstance(key, six.string_types): raise TypeError( diff --git a/tensorflow/python/training/checkpointable/data_structures_test.py b/tensorflow/python/training/checkpointable/data_structures_test.py index ff7d1f1d2d..17cbe3192d 100644 --- a/tensorflow/python/training/checkpointable/data_structures_test.py +++ b/tensorflow/python/training/checkpointable/data_structures_test.py @@ -253,6 +253,13 @@ class ListTests(test.TestCase): l.append(1) self.assertEqual([1], l_wrapper) + def testLayerCollectionWithExternalMutation(self): + l = [] + l_wrapper = data_structures._ListWrapper(l) + layer = core.Dense(1) + l.append(layer) + self.assertEqual([layer], l_wrapper.layers) + def testHashing(self): has_sequences = set([data_structures.List(), data_structures.List()]) @@ -324,6 +331,16 @@ class MappingTests(test.TestCase): with self.assertRaises(TypeError): mapping[1] = data_structures.List() + def testLayerCollectionWithExternalMutation(self): + d = {} + root = tracking.Checkpointable() + root.wrapper = d + layer1 = core.Dense(1) + layer2 = core.Dense(1) + d["a"] = layer1 + d["b"] = layer2 + self.assertEqual([layer1, layer2], root.wrapper.layers) + def testHashing(self): has_mappings = set([data_structures.Mapping(), data_structures.Mapping()]) -- GitLab From ddb47e779808a3bd5cbd1948705c267548acc209 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 10:09:44 -0800 Subject: [PATCH 303/672] Publish cumulative graph run time and count to Streamz. We record the time at the beginning and end of running DirectSession::RunInternal / GraphMgr::ExecuteAsync(for distributed learning) and calculate the difference. This way of publishing graph run time intends to work around the GPU/TPU OOM issue when calculate step time from Xprof StepStats. PiperOrigin-RevId: 222843844 --- tensorflow/core/BUILD | 10 +++++ .../core/common_runtime/direct_session.cc | 3 ++ tensorflow/core/common_runtime/metrics.cc | 40 +++++++++++++++++++ tensorflow/core/common_runtime/metrics.h | 27 +++++++++++++ tensorflow/core/distributed_runtime/BUILD | 1 + .../core/distributed_runtime/graph_mgr.cc | 21 ++++++---- 6 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 tensorflow/core/common_runtime/metrics.cc create mode 100644 tensorflow/core/common_runtime/metrics.h diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 2a8c2718ed..5e1d93cfa2 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -3022,6 +3022,15 @@ cc_library( deps = [":lib_internal"], ) +tf_cuda_library( + name = "metrics", + srcs = ["common_runtime/metrics.cc"], + hdrs = ["common_runtime/metrics.h"], + deps = [ + ":lib", + ], +) + tf_cuda_library( name = "direct_session_internal", srcs = ["common_runtime/direct_session.cc"], @@ -3038,6 +3047,7 @@ tf_cuda_library( ":graph", ":lib", ":lib_internal", + ":metrics", ":proto_text", ":protos_all_cc", "//tensorflow/core/debug:debug_graph_utils", diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index 40b7071f40..178469db51 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -30,6 +30,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/graph_optimizer.h" #include "tensorflow/core/common_runtime/memory_types.h" +#include "tensorflow/core/common_runtime/metrics.h" #include "tensorflow/core/common_runtime/optimization_registry.h" #include "tensorflow/core/common_runtime/process_util.h" #include "tensorflow/core/common_runtime/scoped_allocator_mgr.h" @@ -462,6 +463,7 @@ Status DirectSession::RunInternal(int64 step_id, const RunOptions& run_options, CallFrameInterface* call_frame, ExecutorsAndKeys* executors_and_keys, RunMetadata* run_metadata) { + const uint64 start_time_usecs = Env::Default()->NowMicros(); string session_id_meta = strings::StrCat("SessionRun #id=", step_id, "#"); tracing::ScopedActivity activity(session_id_meta); @@ -716,6 +718,7 @@ Status DirectSession::RunInternal(int64 step_id, const RunOptions& run_options, exec_and_lib.graph->ToGraphDef(partition_graph_def); } } + UpdateGraphExecTime(Env::Default()->NowMicros() - start_time_usecs); return Status::OK(); } diff --git a/tensorflow/core/common_runtime/metrics.cc b/tensorflow/core/common_runtime/metrics.cc new file mode 100644 index 0000000000..f4c94ed7ec --- /dev/null +++ b/tensorflow/core/common_runtime/metrics.cc @@ -0,0 +1,40 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/core/common_runtime/metrics.h" +#include "tensorflow/core/lib/monitoring/counter.h" + +namespace tensorflow { + +namespace { + +auto* graph_runs = monitoring::Counter<0>::New( + "/tensorflow/core/graph_runs", + "The number of graph executions used to collect " + "/tensorflow/core/graph_run_time_usecs"); + +auto* graph_run_time_usecs = monitoring::Counter<0>::New( + "/tensorflow/core/graph_run_time_usecs", + "The total time spent on executing graphs in microseconds."); +} // namespace + +void UpdateGraphExecTime(const uint64 running_time_usecs) { + if (running_time_usecs > 0) { + graph_runs->GetCell()->IncrementBy(1); + graph_run_time_usecs->GetCell()->IncrementBy(running_time_usecs); + } +} + +} // namespace tensorflow diff --git a/tensorflow/core/common_runtime/metrics.h b/tensorflow/core/common_runtime/metrics.h new file mode 100644 index 0000000000..d3430c9f03 --- /dev/null +++ b/tensorflow/core/common_runtime/metrics.h @@ -0,0 +1,27 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_CORE_COMMON_RUNTIME_METRICS_H_ +#define TENSORFLOW_CORE_COMMON_RUNTIME_METRICS_H_ + +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { + +void UpdateGraphExecTime(const uint64 running_time_usecs); + +} // namespace tensorflow + +#endif // TENSORFLOW_CORE_COMMON_RUNTIME_METRICS_H_ diff --git a/tensorflow/core/distributed_runtime/BUILD b/tensorflow/core/distributed_runtime/BUILD index 818324746f..cd9e58ac39 100644 --- a/tensorflow/core/distributed_runtime/BUILD +++ b/tensorflow/core/distributed_runtime/BUILD @@ -425,6 +425,7 @@ cc_library( "//tensorflow/core:graph", "//tensorflow/core:lib", "//tensorflow/core:lib_internal", + "//tensorflow/core:metrics", "//tensorflow/core:protos_all_cc", "//tensorflow/core:worker_proto_cc", "//tensorflow/core/debug", diff --git a/tensorflow/core/distributed_runtime/graph_mgr.cc b/tensorflow/core/distributed_runtime/graph_mgr.cc index 3944668028..ee5823e314 100644 --- a/tensorflow/core/distributed_runtime/graph_mgr.cc +++ b/tensorflow/core/distributed_runtime/graph_mgr.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/distributed_runtime/graph_mgr.h" +#include // NOLINT(build/c++11) #include #include "tensorflow/core/common_runtime/build_graph_options.h" @@ -25,6 +26,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/graph_optimizer.h" #include "tensorflow/core/common_runtime/memory_types.h" +#include "tensorflow/core/common_runtime/metrics.h" #include "tensorflow/core/common_runtime/optimization_registry.h" #include "tensorflow/core/common_runtime/process_util.h" #include "tensorflow/core/common_runtime/rendezvous_util.h" @@ -386,6 +388,7 @@ void GraphMgr::ExecuteAsync(const string& handle, const int64 step_id, MutableRunGraphResponseWrapper* response, CancellationManager* cancellation_manager, const NamedTensors& in, StatusCallback done) { + const uint64 start_time_usecs = Env::Default()->NowMicros(); // Lookup an item. Holds one ref while executing. Item* item = nullptr; { @@ -443,14 +446,16 @@ void GraphMgr::ExecuteAsync(const string& handle, const int64 step_id, return; } - StartParallelExecutors(handle, step_id, item, rendezvous, ce_handle, - collector, cost_graph, cancellation_manager, - [item, rendezvous, ce_handle, done](const Status& s) { - done(s); - rendezvous->Unref(); - item->Unref(); - delete ce_handle; - }); + StartParallelExecutors( + handle, step_id, item, rendezvous, ce_handle, collector, cost_graph, + cancellation_manager, + [item, rendezvous, ce_handle, done, start_time_usecs](const Status& s) { + done(s); + UpdateGraphExecTime(Env::Default()->NowMicros() - start_time_usecs); + rendezvous->Unref(); + item->Unref(); + delete ce_handle; + }); } void GraphMgr::StartParallelExecutors(const string& handle, int64 step_id, -- GitLab From 7f2309d633a3ab43c4b78e7569fa987ba94f4192 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 10:29:22 -0800 Subject: [PATCH 304/672] Added training hooks to train ops. PiperOrigin-RevId: 222846882 --- .../estimator/python/gan_estimator_impl.py | 15 ++-- .../estimator/python/gan_estimator_test.py | 35 ++++++++- tensorflow/contrib/gan/python/namedtuples.py | 12 ++- tensorflow/contrib/gan/python/train.py | 15 +++- tensorflow/contrib/gan/python/train_test.py | 75 +++++++++++++++++++ 5 files changed, 140 insertions(+), 12 deletions(-) diff --git a/tensorflow/contrib/gan/python/estimator/python/gan_estimator_impl.py b/tensorflow/contrib/gan/python/estimator/python/gan_estimator_impl.py index 219cc199d7..3593b501bb 100644 --- a/tensorflow/contrib/gan/python/estimator/python/gan_estimator_impl.py +++ b/tensorflow/contrib/gan/python/estimator/python/gan_estimator_impl.py @@ -113,7 +113,8 @@ class GANEstimator(estimator.Estimator): add_summaries=None, use_loss_summaries=True, config=None, - warm_start_from=None): + warm_start_from=None, + is_chief=True): """Initializes a GANEstimator instance. Args: @@ -154,6 +155,8 @@ class GANEstimator(estimator.Estimator): config: `RunConfig` object to configure the runtime settings. warm_start_from: A filepath to a checkpoint or saved model, or a WarmStartSettings object to configure initialization. + is_chief: Whether or not this Estimator is running on a chief or worker. + Needs to be set appropriately if using SyncReplicasOptimizers. Raises: ValueError: If loss functions aren't callable. @@ -187,7 +190,7 @@ class GANEstimator(estimator.Estimator): return _get_estimator_spec( mode, gan_model, generator_loss_fn, discriminator_loss_fn, get_eval_metric_ops_fn, generator_optimizer, discriminator_optimizer, - get_hooks_fn, use_loss_summaries) + get_hooks_fn, use_loss_summaries, is_chief) super(GANEstimator, self).__init__( model_fn=_model_fn, model_dir=model_dir, config=config, @@ -215,7 +218,7 @@ def _get_gan_model( def _get_estimator_spec( mode, gan_model, generator_loss_fn, discriminator_loss_fn, get_eval_metric_ops_fn, generator_optimizer, discriminator_optimizer, - get_hooks_fn=None, use_loss_summaries=True): + get_hooks_fn=None, use_loss_summaries=True, is_chief=True): """Get the EstimatorSpec for the current mode.""" if mode == model_fn_lib.ModeKeys.PREDICT: estimator_spec = model_fn_lib.EstimatorSpec( @@ -236,7 +239,7 @@ def _get_estimator_spec( else discriminator_optimizer) get_hooks_fn = get_hooks_fn or tfgan_train.get_sequential_train_hooks() estimator_spec = _get_train_estimator_spec( - gan_model, gan_loss, gopt, dopt, get_hooks_fn) + gan_model, gan_loss, gopt, dopt, get_hooks_fn, is_chief=is_chief) return estimator_spec @@ -321,11 +324,11 @@ def _get_eval_estimator_spec(gan_model, gan_loss, get_eval_metric_ops_fn=None, def _get_train_estimator_spec( gan_model, gan_loss, generator_optimizer, discriminator_optimizer, - get_hooks_fn, train_op_fn=tfgan_train.gan_train_ops): + get_hooks_fn, train_op_fn=tfgan_train.gan_train_ops, is_chief=True): """Return an EstimatorSpec for the train case.""" scalar_loss = gan_loss.generator_loss + gan_loss.discriminator_loss train_ops = train_op_fn(gan_model, gan_loss, generator_optimizer, - discriminator_optimizer) + discriminator_optimizer, is_chief=is_chief) training_hooks = get_hooks_fn(train_ops) return model_fn_lib.EstimatorSpec( loss=scalar_loss, diff --git a/tensorflow/contrib/gan/python/estimator/python/gan_estimator_test.py b/tensorflow/contrib/gan/python/estimator/python/gan_estimator_test.py index 3d6bdab0ad..bc9021050b 100644 --- a/tensorflow/contrib/gan/python/estimator/python/gan_estimator_test.py +++ b/tensorflow/contrib/gan/python/estimator/python/gan_estimator_test.py @@ -48,6 +48,7 @@ from tensorflow.python.platform import test from tensorflow.python.summary.writer import writer_cache from tensorflow.python.training import input as input_lib from tensorflow.python.training import learning_rate_decay +from tensorflow.python.training import sync_replicas_optimizer from tensorflow.python.training import training from tensorflow.python.training import training_util @@ -82,7 +83,7 @@ class GetGANModelTest(test.TestCase, parameterized.TestCase): self.assertEqual(generator_inputs, gan_model.generator_inputs) self.assertIsNotNone(gan_model.generated_data) - self.assertEqual(2, len(gan_model.generator_variables)) # 1 FC layer + self.assertLen(gan_model.generator_variables, 2) # 1 FC layer self.assertIsNotNone(gan_model.generator_fn) if mode == model_fn_lib.ModeKeys.PREDICT: self.assertIsNone(gan_model.real_data) @@ -95,7 +96,7 @@ class GetGANModelTest(test.TestCase, parameterized.TestCase): self.assertIsNotNone(gan_model.real_data) self.assertIsNotNone(gan_model.discriminator_real_outputs) self.assertIsNotNone(gan_model.discriminator_gen_outputs) - self.assertEqual(2, len(gan_model.discriminator_variables)) # 1 FC layer + self.assertLen(gan_model.discriminator_variables, 2) # 1 FC layer self.assertIsNotNone(gan_model.discriminator_scope) self.assertIsNotNone(gan_model.discriminator_fn) @@ -121,6 +122,7 @@ def get_dummy_gan_model(): def dummy_loss_fn(gan_model, add_summaries=True): + del add_summaries return math_ops.reduce_sum(gan_model.discriminator_real_outputs - gan_model.discriminator_gen_outputs) @@ -168,6 +170,35 @@ class GetEstimatorSpecTest(test.TestCase, parameterized.TestCase): self.assertShapeEqual(np.array(0), spec.loss) # must be a scalar self.assertIsNotNone(spec.eval_metric_ops) + def test_get_sync_estimator_spec(self): + """Make sure spec is loaded with sync hooks for sync opts.""" + + def get_sync_optimizer(): + return sync_replicas_optimizer.SyncReplicasOptimizer( + training.GradientDescentOptimizer(learning_rate=1.0), + replicas_to_aggregate=1) + + with ops.Graph().as_default(): + self._gan_model = get_dummy_gan_model() + g_opt = get_sync_optimizer() + d_opt = get_sync_optimizer() + + spec = estimator._get_estimator_spec( + model_fn_lib.ModeKeys.TRAIN, + self._gan_model, + generator_loss_fn=dummy_loss_fn, + discriminator_loss_fn=dummy_loss_fn, + get_eval_metric_ops_fn=get_metrics, + generator_optimizer=g_opt, + discriminator_optimizer=d_opt) + + self.assertLen(spec.training_hooks, 4) + sync_opts = [ + hook._sync_optimizer for hook in spec.training_hooks if + isinstance(hook, sync_replicas_optimizer._SyncReplicasOptimizerHook)] + self.assertLen(sync_opts, 2) + self.assertSetEqual(frozenset(sync_opts), frozenset((g_opt, d_opt))) + # TODO(joelshor): Add pandas test. class GANEstimatorIntegrationTest(test.TestCase): diff --git a/tensorflow/contrib/gan/python/namedtuples.py b/tensorflow/contrib/gan/python/namedtuples.py index b9ac1bf151..969b68449d 100644 --- a/tensorflow/contrib/gan/python/namedtuples.py +++ b/tensorflow/contrib/gan/python/namedtuples.py @@ -213,7 +213,8 @@ class GANTrainOps( collections.namedtuple('GANTrainOps', ( 'generator_train_op', 'discriminator_train_op', - 'global_step_inc_op' + 'global_step_inc_op', + 'train_hooks' ))): """GANTrainOps contains the training ops. @@ -221,8 +222,17 @@ class GANTrainOps( generator_train_op: Op that performs a generator update step. discriminator_train_op: Op that performs a discriminator update step. global_step_inc_op: Op that increments the shared global step. + train_hooks: a list or tuple containing hooks related to training that need + to be populated when training ops are instantiated. Used primarily for + sync hooks. """ + def __new__(cls, generator_train_op, discriminator_train_op, + global_step_inc_op, train_hooks=()): + return super(GANTrainOps, cls).__new__(cls, generator_train_op, + discriminator_train_op, + global_step_inc_op, train_hooks) + class GANTrainSteps( collections.namedtuple('GANTrainSteps', ( diff --git a/tensorflow/contrib/gan/python/train.py b/tensorflow/contrib/gan/python/train.py index cf5b9d9476..4c7bee41b3 100644 --- a/tensorflow/contrib/gan/python/train.py +++ b/tensorflow/contrib/gan/python/train.py @@ -924,6 +924,7 @@ def gan_train_ops( generator_optimizer, discriminator_optimizer, check_for_unused_update_ops=True, + is_chief=True, # Optional args to pass directly to the `create_train_op`. **kwargs): """Returns GAN train ops. @@ -939,6 +940,8 @@ def gan_train_ops( discriminator_optimizer: The optimizer for the discriminator updates. check_for_unused_update_ops: If `True`, throws an exception if there are update ops outside of the generator or discriminator scopes. + is_chief: Specifies whether or not the training is being run by the primary + replica during replica training. **kwargs: Keyword args to pass directly to `training.create_train_op` for both the generator and discriminator train op. @@ -980,6 +983,9 @@ def gan_train_ops( kwargs, model.generator_scope.name, model.discriminator_scope.name, check_for_unused_update_ops) + # Get the sync hooks if these are needed. + sync_hooks = [] + generator_global_step = None if isinstance(generator_optimizer, sync_replicas_optimizer.SyncReplicasOptimizer): @@ -995,6 +1001,7 @@ def gan_train_ops( trainable=False, collections=[ops.GraphKeys.GLOBAL_VARIABLES]) gen_update_ops += [generator_global_step.assign(global_step)] + sync_hooks.append(generator_optimizer.make_session_run_hook(is_chief)) with ops.name_scope('generator_train'): gen_train_op = training.create_train_op( total_loss=loss.generator_loss, @@ -1016,6 +1023,7 @@ def gan_train_ops( trainable=False, collections=[ops.GraphKeys.GLOBAL_VARIABLES]) dis_update_ops += [discriminator_global_step.assign(global_step)] + sync_hooks.append(discriminator_optimizer.make_session_run_hook(is_chief)) with ops.name_scope('discriminator_train'): disc_train_op = training.create_train_op( total_loss=loss.discriminator_loss, @@ -1025,7 +1033,8 @@ def gan_train_ops( update_ops=dis_update_ops, **kwargs) - return namedtuples.GANTrainOps(gen_train_op, disc_train_op, global_step_inc) + return namedtuples.GANTrainOps(gen_train_op, disc_train_op, global_step_inc, + sync_hooks) # TODO(joelshor): Implement a dynamic GAN train loop, as in `Real-Time Adaptive @@ -1066,7 +1075,7 @@ def get_sequential_train_hooks(train_steps=namedtuples.GANTrainSteps(1, 1)): train_steps.generator_train_steps) discriminator_hook = RunTrainOpsHook(train_ops.discriminator_train_op, train_steps.discriminator_train_steps) - return [generator_hook, discriminator_hook] + return [generator_hook, discriminator_hook] + list(train_ops.train_hooks) return get_hooks @@ -1126,7 +1135,7 @@ def get_joint_train_hooks(train_steps=namedtuples.GANTrainSteps(1, 1)): g_hook = RunTrainOpsHook(g_op, num_g_steps) d_hook = RunTrainOpsHook(d_op, num_d_steps) - return [joint_hook, g_hook, d_hook] + return [joint_hook, g_hook, d_hook] + list(train_ops.train_hooks) return get_hooks diff --git a/tensorflow/contrib/gan/python/train_test.py b/tensorflow/contrib/gan/python/train_test.py index e8c24eea3d..841f25cd7f 100644 --- a/tensorflow/contrib/gan/python/train_test.py +++ b/tensorflow/contrib/gan/python/train_test.py @@ -836,6 +836,9 @@ class GANTrainOpsTest(test.TestCase, parameterized.TestCase): self.assertIsInstance(train_ops, namedtuples.GANTrainOps) + # Make sure there are no training hooks populated accidentally. + self.assertEmpty(train_ops.train_hooks) + # TODO(joelshor): Add a test to check that custom update op is run. @parameterized.named_parameters( ('gan', create_gan_model, False), @@ -925,6 +928,14 @@ class GANTrainOpsTest(test.TestCase, parameterized.TestCase): # No new trainable variables should have been added. self.assertLen(variables_lib.get_trainable_variables(), num_trainable_vars) + # Sync hooks should be populated in the GANTrainOps. + self.assertLen(train_ops.train_hooks, 2) + for hook in train_ops.train_hooks: + self.assertIsInstance( + hook, sync_replicas_optimizer._SyncReplicasOptimizerHook) + sync_opts = [hook._sync_optimizer for hook in train_ops.train_hooks] + self.assertSetEqual(frozenset(sync_opts), frozenset((g_opt, d_opt))) + g_sync_init_op = g_opt.get_init_tokens_op(num_tokens=1) d_sync_init_op = d_opt.get_init_tokens_op(num_tokens=1) @@ -958,6 +969,32 @@ class GANTrainOpsTest(test.TestCase, parameterized.TestCase): coord.request_stop() coord.join(g_threads + d_threads) + @parameterized.named_parameters( + ('is_chief', True), + ('is_not_chief', False), + ) + def test_is_chief_in_train_hooks(self, is_chief): + """Make sure is_chief is propagated correctly to sync hooks.""" + model = create_gan_model() + loss = train.gan_loss(model) + g_opt = get_sync_optimizer() + d_opt = get_sync_optimizer() + train_ops = train.gan_train_ops( + model, + loss, + g_opt, + d_opt, + is_chief=is_chief, + summarize_gradients=True, + colocate_gradients_with_ops=True) + + self.assertLen(train_ops.train_hooks, 2) + for hook in train_ops.train_hooks: + self.assertIsInstance( + hook, sync_replicas_optimizer._SyncReplicasOptimizerHook) + is_chief_list = [hook._is_chief for hook in train_ops.train_hooks] + self.assertListEqual(is_chief_list, [is_chief, is_chief]) + class GANTrainTest(test.TestCase, parameterized.TestCase): """Tests for `gan_train`.""" @@ -1035,6 +1072,44 @@ class GANTrainTest(test.TestCase, parameterized.TestCase): self.assertTrue(np.isscalar(final_loss)) self.assertEqual(17.0, final_loss) + @parameterized.named_parameters( + ('gan', create_gan_model), + ('callable_gan', create_callable_gan_model), + ('infogan', create_infogan_model), + ('callable_infogan', create_callable_infogan_model), + ('acgan', create_acgan_model), + ('callable_acgan', create_callable_acgan_model), + ) + def test_train_hooks_exist_in_get_hooks_fn(self, create_gan_model_fn): + model = create_gan_model_fn() + loss = train.gan_loss(model) + + g_opt = get_sync_optimizer() + d_opt = get_sync_optimizer() + train_ops = train.gan_train_ops( + model, + loss, + g_opt, + d_opt, + summarize_gradients=True, + colocate_gradients_with_ops=True) + + sequential_train_hooks = train.get_sequential_train_hooks()(train_ops) + self.assertLen(sequential_train_hooks, 4) + sync_opts = [ + hook._sync_optimizer for hook in sequential_train_hooks if + isinstance(hook, sync_replicas_optimizer._SyncReplicasOptimizerHook)] + self.assertLen(sync_opts, 2) + self.assertSetEqual(frozenset(sync_opts), frozenset((g_opt, d_opt))) + + joint_train_hooks = train.get_joint_train_hooks()(train_ops) + self.assertLen(joint_train_hooks, 5) + sync_opts = [ + hook._sync_optimizer for hook in joint_train_hooks if + isinstance(hook, sync_replicas_optimizer._SyncReplicasOptimizerHook)] + self.assertLen(sync_opts, 2) + self.assertSetEqual(frozenset(sync_opts), frozenset((g_opt, d_opt))) + class PatchGANTest(test.TestCase, parameterized.TestCase): """Tests that functions work on PatchGAN style output.""" -- GitLab From 9fca5f0778c2a0b86f6ecd925256e8917c6030b3 Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Mon, 26 Nov 2018 10:35:48 -0800 Subject: [PATCH 305/672] [tf.data] Adding eager coverage to dataset tests. PiperOrigin-RevId: 222847973 --- .../kernel_tests/batch_dataset_op_test.py | 357 +++++++----------- .../kernel_tests/cache_dataset_op_test.py | 357 +++++++----------- .../concatenate_dataset_op_test.py | 62 ++- .../dataset_constructor_op_test.py | 324 +++++++--------- .../data/kernel_tests/dataset_ops_test.py | 13 +- .../kernel_tests/filter_dataset_op_test.py | 149 +++----- .../python/data/kernel_tests/inputs_test.py | 2 + .../list_files_dataset_op_test.py | 281 +++++--------- .../data/kernel_tests/optional_ops_test.py | 12 +- .../kernel_tests/prefetch_dataset_op_test.py | 29 +- .../kernel_tests/sequence_dataset_op_test.py | 217 ++++------- .../kernel_tests/shard_dataset_op_test.py | 53 +-- .../kernel_tests/shuffle_dataset_op_test.py | 240 ++++++------ .../python/data/kernel_tests/test_base.py | 26 +- .../data/kernel_tests/zip_dataset_op_test.py | 134 +++---- 15 files changed, 886 insertions(+), 1370 deletions(-) diff --git a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py index e8decb9ad0..94c37a0f2c 100644 --- a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py @@ -26,11 +26,13 @@ import numpy as np from tensorflow.python.client import session from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.util import nest from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import string_ops @@ -38,6 +40,7 @@ from tensorflow.python.platform import test from tensorflow.python.util import compat +@test_util.run_all_in_graph_and_eager_modes class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( @@ -62,59 +65,42 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], np.array(37.0) * np.arange(7)) - count_t = array_ops.placeholder(dtypes.int64, shape=[]) - batch_size_t = array_ops.placeholder(dtypes.int64, shape=[]) - drop_remainder_t = array_ops.placeholder(dtypes.bool, shape=[]) - def _map_fn(x, y, z): return math_ops.square(x), math_ops.square(y), math_ops.square(z) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components).map(_map_fn) - .repeat(count).batch(batch_size, - drop_remainder).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.from_tensor_slices(components).map( + _map_fn).repeat(count).batch(batch_size, drop_remainder) + get_next = self.getNext(dataset) if drop_remainder: dim0 = batch_size else: dim0 = None - self.assertEqual([[dim0] + list(c.shape[1:]) for c in components], - [t.shape.as_list() for t in get_next]) - - with self.cached_session() as sess: - sess.run( - init_op, - feed_dict={ - count_t: count, - batch_size_t: batch_size, - drop_remainder_t: drop_remainder - }) - num_full_batches = (count * 7) // batch_size - for i in range(num_full_batches): - result = sess.run(get_next) - for component, result_component in zip(components, result): - for j in range(batch_size): - self.assertAllEqual(component[(i * batch_size + j) % 7]**2, - result_component[j]) - if not drop_remainder and (count * 7) % batch_size > 0: - result = sess.run(get_next) - for component, result_component in zip(components, result): - for j in range((count * 7) % batch_size): - self.assertAllEqual( - component[(num_full_batches * batch_size + j) % 7]**2, - result_component[j]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertEqual( + [ts.as_list() for ts in nest.flatten(dataset.output_shapes)], + [[dim0] + list(c.shape[1:]) for c in components]) + + num_full_batches = (count * 7) // batch_size + for i in range(num_full_batches): + result = self.evaluate(get_next()) + for component, result_component in zip(components, result): + for j in range(batch_size): + self.assertAllEqual(component[(i * batch_size + j) % 7]**2, + result_component[j]) + if not drop_remainder and (count * 7) % batch_size > 0: + result = self.evaluate(get_next()) + for component, result_component in zip(components, result): + for j in range((count * 7) % batch_size): + self.assertAllEqual( + component[(num_full_batches * batch_size + j) % 7]**2, + result_component[j]) + with self.assertRaises(errors.OutOfRangeError): + result = self.evaluate(get_next()) def testBatchDatasetInvalidBatchSize(self): - iterator = (dataset_ops.Dataset.range(10).batch(0).make_one_shot_iterator()) - get_next = iterator.get_next() - - with self.cached_session() as sess: - with self.assertRaises(errors.InvalidArgumentError): - sess.run(get_next) + dataset = (dataset_ops.Dataset.range(10).batch(0)) + self.assertDatasetProduces( + dataset, expected_error=(errors.InvalidArgumentError, '')) def testBatchSparse(self): @@ -122,23 +108,14 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): return sparse_tensor.SparseTensorValue( indices=[[0]], values=(i * [1]), dense_shape=[1]) - iterator = dataset_ops.Dataset.range(10).map(_sparse).batch( - 5).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(2): - actual = sess.run(get_next) - expected = sparse_tensor.SparseTensorValue( + dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5) + expected_output = [ + sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], - dense_shape=[5, 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dense_shape=[5, 1]) for i in range(2) + ] + self.assertDatasetProduces(dataset, expected_output=expected_output) def testBatchSparseWithDifferentDenseShapes(self): @@ -149,29 +126,21 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): values=array_ops.fill([math_ops.to_int32(i)], i), dense_shape=[i]) - iterator = dataset_ops.Dataset.range(10).map(_sparse).batch( - 5).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(2): - actual = sess.run(get_next) - expected_indices = [] - expected_values = [] - for j in range(5): - for k in range(i * 5 + j): - expected_indices.append([j, k]) - expected_values.append(i * 5 + j) - expected = sparse_tensor.SparseTensorValue( - indices=expected_indices, - values=expected_values, - dense_shape=[5, (i + 1) * 5 - 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5) + expected_output = [] + for i in range(2): + expected_indices = [] + expected_outputs = [] + for j in range(5): + for k in range(i * 5 + j): + expected_indices.append([j, k]) + expected_outputs.append(i * 5 + j) + expected_output.append( + sparse_tensor.SparseTensorValue( + indices=expected_indices, + values=expected_outputs, + dense_shape=[5, (i + 1) * 5 - 1])) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testNestedBatchSparse(self): @@ -179,23 +148,15 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): return sparse_tensor.SparseTensorValue( indices=[[0]], values=(i * [1]), dense_shape=[1]) - iterator = dataset_ops.Dataset.range(10).map(_sparse).batch(5).batch( - 2).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - actual = sess.run(get_next) - expected = sparse_tensor.SparseTensorValue( - indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], - [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0]], - values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - dense_shape=[2, 5, 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5).batch(2) + expected_output = [ + sparse_tensor.SparseTensorValue( + indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], + [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0]], + values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + dense_shape=[2, 5, 1]) + ] + self.assertDatasetProduces(dataset, expected_output=expected_output) def testBatchShapeError(self): @@ -204,25 +165,22 @@ class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): yield [4.0, 5.0, 6.0] yield [7.0, 8.0, 9.0, 10.0] - iterator = ( + dataset = ( dataset_ops.Dataset.from_generator( - generator, dtypes.float32, output_shapes=[None]).batch(3) - .make_initializable_iterator()) - next_element = iterator.get_next() - - with self.cached_session() as sess: - sess.run(iterator.initializer) - with self.assertRaisesRegexp( - errors.InvalidArgumentError, - r'Cannot batch tensors with different shapes in component 0. ' - r'First element had shape \[3\] and element 2 had shape \[4\].'): - sess.run(next_element) + generator, dtypes.float32, output_shapes=[None]).batch(3)) + self.assertDatasetProduces( + dataset, + expected_error=( + errors.InvalidArgumentError, + r'Cannot batch tensors with different shapes in component 0. First ' + r'element had shape \[3\] and element 2 had shape \[4\].')) def _random_seq_lens(count): return np.random.randint(20, size=(count,)).astype(np.int32) +@test_util.run_all_in_graph_and_eager_modes class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( @@ -243,125 +201,83 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): size does not divide number of inputs evenly """ - seq_lens_t = array_ops.placeholder(dtypes.int32, shape=[None]) - batch_size_t = array_ops.placeholder(dtypes.int64, shape=[]) - padded_shapes_t = array_ops.placeholder(dtypes.int64, shape=[1]) - drop_remainder_t = array_ops.placeholder(dtypes.bool, shape=[]) - - iterator = ( - dataset_ops.Dataset.from_tensor_slices(seq_lens_t) - .map(lambda x: array_ops.fill([x], x)).padded_batch( - batch_size=batch_size_t, - drop_remainder=drop_remainder_t, - padded_shapes=padded_shapes_t).make_initializable_iterator()) - - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run( - init_op, - feed_dict={ - seq_lens_t: seq_lens, - batch_size_t: batch_size, - padded_shapes_t: padded_shapes, - drop_remainder_t: drop_remainder, - }) - - num_full_batches = len(seq_lens) // batch_size - - for i in range(num_full_batches): - result = sess.run(get_next) - padded_len = padded_shapes[0] - if padded_len is None or padded_len == -1: - padded_len = np.max(result) if result.size > 0 else 0 - self.assertEqual((batch_size, padded_len), result.shape) - for j in range(batch_size): - seq_len = seq_lens[(i * batch_size) + j] - self.assertAllEqual(result[j, :seq_len], [seq_len] * seq_len) - self.assertAllEqual(result[j, seq_len:], - [0] * (padded_len - seq_len)) - - if not drop_remainder and len(seq_lens) % batch_size > 0: - result = sess.run(get_next) + dataset = dataset_ops.Dataset.from_tensor_slices(seq_lens).map( + lambda x: array_ops.fill([x], x)).padded_batch( + batch_size=batch_size, + drop_remainder=drop_remainder, + padded_shapes=padded_shapes) + + num_full_batches = len(seq_lens) // batch_size + get_next = self.getNext(dataset) + for i in range(num_full_batches): + result = self.evaluate(get_next()) + padded_len = padded_shapes[0] + if padded_len is None or padded_len == -1: padded_len = np.max(result) if result.size > 0 else 0 - self.assertEqual((len(seq_lens) % batch_size, padded_len), - result.shape) - for j in range(len(seq_lens) % batch_size): - seq_len = seq_lens[num_full_batches * batch_size + j] - self.assertAllEqual(result[j, :seq_len], [seq_len] * seq_len) - self.assertAllEqual(result[j, seq_len:], - [0] * (padded_len - seq_len)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertEqual((batch_size, padded_len), result.shape) + for j in range(batch_size): + seq_len = seq_lens[(i * batch_size) + j] + self.assertAllEqual(result[j, :seq_len], [seq_len] * seq_len) + self.assertAllEqual(result[j, seq_len:], [0] * (padded_len - seq_len)) + + if not drop_remainder and len(seq_lens) % batch_size > 0: + result = self.evaluate(get_next()) + padded_len = np.max(result) if result.size > 0 else 0 + self.assertEqual((len(seq_lens) % batch_size, padded_len), result.shape) + for j in range(len(seq_lens) % batch_size): + seq_len = seq_lens[num_full_batches * batch_size + j] + self.assertAllEqual(result[j, :seq_len], [seq_len] * seq_len) + self.assertAllEqual(result[j, seq_len:], [0] * (padded_len - seq_len)) + + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testPaddedBatchShortPadding(self): - iterator = ( - dataset_ops.Dataset.from_tensor_slices([6, 5, 5, 5, 5]) - .map(lambda x: array_ops.fill([x], x)).padded_batch( - batch_size=4, padded_shapes=[5]).make_one_shot_iterator()) - get_next = iterator.get_next() - - with self.cached_session() as sess: - with self.assertRaises(errors.DataLossError): - sess.run(get_next) + dataset = ( + dataset_ops.Dataset.from_tensor_slices( + [6, 5, 5, 5, 5]).map(lambda x: array_ops.fill([x], x)).padded_batch( + batch_size=4, padded_shapes=[5])) + self.assertDatasetProduces( + dataset, expected_error=(errors.DataLossError, '')) def testPaddedBatchEmptyTensors(self): - iterator = ( - dataset_ops.Dataset.from_tensor_slices([0, 0, 0, 0]) - .map(lambda x: array_ops.fill([x], x)).padded_batch( - batch_size=4, padded_shapes=[-1]).make_one_shot_iterator()) - get_next = iterator.get_next() - - with self.cached_session() as sess: - result = sess.run(get_next) - self.assertAllEqual([[], [], [], []], result) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = ( + dataset_ops.Dataset.from_tensor_slices( + [0, 0, 0, 0]).map(lambda x: array_ops.fill([x], x)).padded_batch( + batch_size=4, padded_shapes=[-1])) + self.assertDatasetProduces(dataset, expected_output=[[[], [], [], []]]) def testPaddedBatchDatasetNonDefaultPadding(self): - seq_lens = array_ops.placeholder(dtypes.int32, shape=[None]) - padded_shape = array_ops.placeholder(dtypes.int64, shape=[1]) def fill_tuple(x): filled = array_ops.fill([x], x) return (filled, string_ops.as_string(filled)) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(seq_lens).map(fill_tuple) + random_seq_lens = np.random.randint(20, size=(32,)).astype(np.int32) + dataset = ( + dataset_ops.Dataset.from_tensor_slices(random_seq_lens).map(fill_tuple) .padded_batch( - 4, - padded_shapes=(padded_shape, padded_shape), - padding_values=(-1, '')).make_initializable_iterator()) - - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - # Test with random sequence lengths, and max padding. - random_seq_lens = np.random.randint(20, size=(32,)).astype(np.int32) - sess.run( - init_op, feed_dict={ - padded_shape: [-1], - seq_lens: random_seq_lens - }) - for i in range(8): - result = sess.run(get_next) - padded_len = np.max(result[0]) - self.assertEqual((4, padded_len), result[0].shape) - self.assertEqual((4, padded_len), result[1].shape) - for j in range(4): - seq_len = random_seq_lens[(i * 4) + j] - self.assertAllEqual(result[0][j, :seq_len], [seq_len] * seq_len) - self.assertAllEqual(result[0][j, seq_len:], - [-1] * (padded_len - seq_len)) - self.assertAllEqual(result[1][j, :seq_len], - [compat.as_bytes(str(seq_len))] * seq_len) - self.assertAllEqual(result[1][j, seq_len:], - [b''] * (padded_len - seq_len)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + 4, padded_shapes=([-1], [-1]), padding_values=(-1, ''))) + + get_next = self.getNext(dataset) + for i in range(8): + result = self.evaluate(get_next()) + padded_len = np.max(result[0]) + self.assertEqual((4, padded_len), result[0].shape) + self.assertEqual((4, padded_len), result[1].shape) + for j in range(4): + seq_len = random_seq_lens[(i * 4) + j] + self.assertAllEqual(result[0][j, :seq_len], [seq_len] * seq_len) + self.assertAllEqual(result[0][j, seq_len:], + [-1] * (padded_len - seq_len)) + self.assertAllEqual(result[1][j, :seq_len], + [compat.as_bytes(str(seq_len))] * seq_len) + self.assertAllEqual(result[1][j, seq_len:], + [b''] * (padded_len - seq_len)) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testPaddedBatchDatasetUnicode(self): # See GitHub issue 16149 @@ -377,11 +293,10 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): (tensor_shape.TensorShape([None]), tensor_shape.TensorShape([None]))) padded_dataset = dataset.padded_batch( 2, padded_shapes=([None], [None]), padding_values=('', 0)) - with self.cached_session() as sess: - next_element = padded_dataset.make_one_shot_iterator().get_next() - sess.run(next_element) + next_element = self.getNext(padded_dataset) + self.evaluate(next_element()) - def testPaddedBatchDatasetShapeSpecifications(self): + def testSkipEagerPaddedBatchDatasetShapeSpecifications(self): int_placeholder = array_ops.placeholder(dtypes.int32) float_placeholder = array_ops.placeholder(dtypes.float32) string_placeholder = array_ops.placeholder(dtypes.string) @@ -452,6 +367,7 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): _ = dataset_ops.Dataset.range(10).padded_batch( 5, padded_shapes=shape_as_tensor) + def testSkipEagerPaddedBatchShapeError(self): with self.assertRaisesRegexp( ValueError, r'The padded shape \((\?|None), (\?|None)\) is not compatible with the ' @@ -461,6 +377,7 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): 5, padded_shapes=shape_as_tensor) +# TODO(b/119837791): Add eager benchmarks too. class BatchDatasetBenchmark(test.Benchmark): def benchmarkBatchSparse(self): diff --git a/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py b/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py index 63625fac03..06ce18a9b4 100644 --- a/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py @@ -25,16 +25,16 @@ import numpy as np from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import iterator_ops from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops -from tensorflow.python.ops import array_ops +from tensorflow.python.framework import test_util from tensorflow.python.ops import variables from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class FileCacheDatasetTest(test_base.DatasetTestBase): def setUp(self): @@ -48,159 +48,124 @@ class FileCacheDatasetTest(test_base.DatasetTestBase): def testCacheDatasetPassthrough(self): components = (np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8]), np.array([9.0, 10.0, 11.0, 12.0])) - count_placeholder = array_ops.placeholder_with_default( - constant_op.constant(5, dtypes.int64), shape=[]) - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - repeat_dataset = (dataset_ops.Dataset.from_tensor_slices(components) - .repeat(count_placeholder)) - - cache_dataset = repeat_dataset.cache(filename_placeholder) + def dataset_fn(count=5, filename=None): + repeat_dataset = ( + dataset_ops.Dataset.from_tensor_slices(components).repeat(count)) + if filename: + return repeat_dataset.cache(filename) + else: + return repeat_dataset self.assertEqual( - tuple([c.shape[1:] for c in components]), cache_dataset.output_shapes) - - # Create initialization ops for iterators without and with - # caching, respectively. - iterator = iterator_ops.Iterator.from_structure(cache_dataset.output_types, - cache_dataset.output_shapes) - init_fifo_op = iterator.make_initializer(repeat_dataset) - init_cache_op = iterator.make_initializer(cache_dataset) - - get_next = iterator.get_next() - - with self.cached_session() as sess: - # First run without caching to collect the "ground truth". - sess.run(init_fifo_op) - elements = [] - for _ in range(20): - elements.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Assert that the cached dataset has the same elements as the - # "ground truth". - sess.run( - init_cache_op, feed_dict={filename_placeholder: self.cache_prefix}) - cached_elements = [] - for _ in range(20): - cached_elements.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - self.assertAllEqual(elements, cached_elements) - - # Re-initialize with an empty upstream (to throw errors.OutOfRangeError - # if we didn't use the cache). - sess.run( - init_cache_op, - feed_dict={ - count_placeholder: 0, - filename_placeholder: self.cache_prefix - }) - replayed_elements = [] - for _ in range(20): - replayed_elements.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - self.assertEqual(cached_elements, replayed_elements) - - # Re-initialize with an empty upstream and a missing cache file (should - # throw errors.OutOfRangeError immediately). - sess.run( - init_cache_op, - feed_dict={ - count_placeholder: 0, - filename_placeholder: self.cache_prefix + "nonsense" - }) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + tuple([c.shape[1:] for c in components]), + dataset_fn().output_shapes) + + get_next = self.getNext(dataset_fn()) + + # First run without caching to collect the "ground truth". + elements = [] + for _ in range(20): + elements.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + # Assert that the cached dataset has the same elements as the + # "ground truth". + get_next = self.getNext(dataset_fn(filename=self.cache_prefix)) + cached_elements = [] + for _ in range(20): + cached_elements.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + self.assertAllEqual(elements, cached_elements) + + # Re-initialize with an empty upstream (to throw errors.OutOfRangeError + # if we didn't use the cache). + get_next = self.getNext(dataset_fn(count=0, filename=self.cache_prefix)) + replayed_elements = [] + for _ in range(20): + replayed_elements.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + self.assertEqual(cached_elements, replayed_elements) + + # Re-initialize with an empty upstream and a missing cache file (should + # throw errors.OutOfRangeError immediately). + get_next = self.getNext( + dataset_fn(count=0, filename=self.cache_prefix + "nonsense")) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testConcurrentWriters(self): components = (np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8]), np.array([9.0, 10.0, 11.0, 12.0])) - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - cache_dataset1 = (dataset_ops.Dataset.from_tensor_slices(components) - .cache(filename_placeholder)) - cache_dataset2 = (dataset_ops.Dataset.from_tensor_slices(components) - .cache(filename_placeholder)) + cache_dataset1 = ( + dataset_ops.Dataset.from_tensor_slices(components).cache( + self.cache_prefix)) + cache_dataset2 = ( + dataset_ops.Dataset.from_tensor_slices(components).cache( + self.cache_prefix)) - iterator1 = cache_dataset1.make_initializable_iterator() - iterator2 = cache_dataset2.make_initializable_iterator() - init_cache_op1 = iterator1.initializer - init_cache_op2 = iterator2.initializer + get_next1 = self.getNext(cache_dataset1) + get_next2 = self.getNext(cache_dataset2) - get_next1 = iterator1.get_next() - get_next2 = iterator2.get_next() + self.evaluate(get_next1()) # this should succeed - with self.cached_session() as sess: - sess.run( - init_cache_op1, feed_dict={filename_placeholder: self.cache_prefix}) - sess.run(get_next1) # this should succeed + with self.assertRaises(errors.AlreadyExistsError): + self.evaluate(get_next2()) - sess.run( - init_cache_op2, feed_dict={filename_placeholder: self.cache_prefix}) - with self.assertRaises(errors.AlreadyExistsError): - sess.run(get_next2) - - sess.run(get_next1) # this should continue to succeed + self.evaluate(get_next1()) # this should continue to succeed def testConcurrentReaders(self): components = (np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8]), np.array([9.0, 10.0, 11.0, 12.0])) - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - - cache_dataset1 = (dataset_ops.Dataset.from_tensor_slices(components) - .cache(filename_placeholder)) - cache_dataset2 = (dataset_ops.Dataset.from_tensor_slices(components) - .cache(filename_placeholder)) - - iterator1 = cache_dataset1.make_initializable_iterator() - iterator2 = cache_dataset2.make_initializable_iterator() - init_cache_op1 = iterator1.initializer - init_cache_op2 = iterator2.initializer - - get_next1 = iterator1.get_next() - get_next2 = iterator2.get_next() - - with self.cached_session() as sess: - sess.run( - init_cache_op1, feed_dict={filename_placeholder: self.cache_prefix}) - elements = [] - for _ in range(4): - elements.append(sess.run(get_next1)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next1) - - # Re-initialize - sess.run( - init_cache_op1, feed_dict={filename_placeholder: self.cache_prefix}) - sess.run( - init_cache_op2, feed_dict={filename_placeholder: self.cache_prefix}) - - # Reading concurrently should succeed. - elements_itr1 = [] - elements_itr2 = [] - elements_itr2.append(sess.run(get_next2)) - elements_itr1.append(sess.run(get_next1)) - elements_itr2.append(sess.run(get_next2)) - elements_itr1.append(sess.run(get_next1)) - # Intentionally reversing the order - elements_itr1.append(sess.run(get_next1)) - elements_itr2.append(sess.run(get_next2)) - elements_itr1.append(sess.run(get_next1)) - elements_itr2.append(sess.run(get_next2)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next2) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next1) - - self.assertAllEqual(elements, elements_itr1) - self.assertAllEqual(elements, elements_itr2) - + cache_dataset1 = ( + dataset_ops.Dataset.from_tensor_slices(components).cache( + self.cache_prefix)) + cache_dataset2 = ( + dataset_ops.Dataset.from_tensor_slices(components).cache( + self.cache_prefix)) + + get_next1 = self.getNext(cache_dataset1) + get_next2 = self.getNext(cache_dataset2) + + elements = [] + for _ in range(4): + elements.append(self.evaluate(get_next1())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next1()) + + # Re-initialize + get_next1 = self.getNext(cache_dataset1) + get_next2 = self.getNext(cache_dataset2) + + # Reading concurrently should succeed. + elements_itr1 = [] + elements_itr2 = [] + elements_itr2.append(self.evaluate(get_next2())) + elements_itr1.append(self.evaluate(get_next1())) + elements_itr2.append(self.evaluate(get_next2())) + elements_itr1.append(self.evaluate(get_next1())) + # Intentionally reversing the order + elements_itr1.append(self.evaluate(get_next1())) + elements_itr2.append(self.evaluate(get_next2())) + elements_itr1.append(self.evaluate(get_next1())) + elements_itr2.append(self.evaluate(get_next2())) + + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next2()) + + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next1()) + + self.assertAllEqual(elements, elements_itr1) + self.assertAllEqual(elements, elements_itr2) + + +@test_util.run_all_in_graph_and_eager_modes class MemoryCacheDatasetTest(test_base.DatasetTestBase): def testCacheDatasetPassthrough(self): @@ -212,106 +177,76 @@ class MemoryCacheDatasetTest(test_base.DatasetTestBase): cached_dataset = dataset.cache().repeat(2) uncached_dataset = dataset.repeat(2) + self.evaluate(repeat_count.initializer) # Needs to be initializable to capture the variable. - cached_iterator = cached_dataset.make_initializable_iterator() - cached_next = cached_iterator.get_next() - uncached_iterator = uncached_dataset.make_initializable_iterator() - uncached_next = uncached_iterator.get_next() + cached_next = self.getNext(cached_dataset, requires_initialization=True) + uncached_next = self.getNext( + uncached_dataset, requires_initialization=True) + for i in range(3): + for _ in range(10): + self.assertEqual(self.evaluate(cached_next()), i) + self.assertEqual(self.evaluate(uncached_next()), i) - with self.cached_session() as sess: + self.evaluate(repeat_count.assign(0)) - sess.run(repeat_count.initializer) - sess.run(cached_iterator.initializer) - sess.run(uncached_iterator.initializer) - - for i in range(3): - for _ in range(10): - self.assertEqual(sess.run(cached_next), i) - self.assertEqual(sess.run(uncached_next), i) - - sess.run(repeat_count.assign(0)) - - # The uncached iterator should now be empty. - with self.assertRaises(errors.OutOfRangeError): - sess.run(uncached_next) + # The uncached iterator should now be empty. + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(uncached_next()) - # The cached iterator replays from cache. - for i in range(3): - for _ in range(10): - self.assertEqual(sess.run(cached_next), i) + # The cached iterator replays from cache. + for i in range(3): + for _ in range(10): + self.assertEqual(self.evaluate(cached_next()), i) - # The cached iterator should now be empty. - with self.assertRaises(errors.OutOfRangeError): - sess.run(cached_next) + # The cached iterator should now be empty. + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(cached_next()) def testEmptyCacheReading(self): components = (np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8]), np.array([9.0, 10.0, 11.0, 12.0])) - count_placeholder = array_ops.placeholder_with_default( - constant_op.constant(5, dtypes.int64), shape=[]) - - repeat_dataset = (dataset_ops.Dataset.from_tensor_slices(components) - .repeat(count_placeholder)) + repeat_dataset = ( + dataset_ops.Dataset.from_tensor_slices(components).repeat(0)) cache_dataset = repeat_dataset.cache() # Create initialization ops for iterators without and with # caching, respectively. - iterator = cache_dataset.make_initializable_iterator() - init_cache_op = iterator.initializer - - get_next = iterator.get_next() - - with self.cached_session() as sess: - # Initialize with an empty upstream and a missing cache file (should - # throw errors.OutOfRangeError immediately). - sess.run(init_cache_op, feed_dict={count_placeholder: 0}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertDatasetProduces(cache_dataset, expected_output=[]) def testConcurrentReaders(self): - count_placeholder = array_ops.placeholder_with_default( - constant_op.constant(5, dtypes.int64), shape=[]) - dataset = dataset_ops.Dataset.range(count_placeholder).cache() + + dataset = dataset_ops.Dataset.range(5).cache() d1 = dataset.map(lambda x: x + 1) d2 = dataset.map(lambda x: x + 6) - i1 = d1.make_initializable_iterator() - i2 = d2.make_initializable_iterator() + get_next1 = self.getNext(d1) - with self.cached_session() as sess: - sess.run(i1.initializer) + self.assertEqual(1, self.evaluate(get_next1())) + self.assertEqual(2, self.evaluate(get_next1())) + self.assertEqual(3, self.evaluate(get_next1())) - self.assertEqual(1, sess.run(i1.get_next())) - self.assertEqual(2, sess.run(i1.get_next())) - self.assertEqual(3, sess.run(i1.get_next())) + get_next2 = self.getNext(d2) - sess.run(i2.initializer, feed_dict={count_placeholder: 3}) + self.assertEqual(6, self.evaluate(get_next2())) + self.assertEqual(7, self.evaluate(get_next2())) + self.assertEqual(4, self.evaluate(get_next1())) # interleave execution + self.assertEqual([8, 5], + [self.evaluate(get_next2()), + self.evaluate(get_next1())]) + self.assertEqual(9, self.evaluate(get_next2())) + self.assertEqual(10, self.evaluate(get_next2())) - self.assertEqual(6, sess.run(i2.get_next())) - self.assertEqual(7, sess.run(i2.get_next())) - self.assertEqual(4, sess.run(i1.get_next())) # interleave execution - self.assertEqual([8, 5], sess.run([i2.get_next(), i1.get_next()])) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(i1.get_next()) - with self.assertRaises(errors.OutOfRangeError): - sess.run(i2.get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next2()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next1()) def testCacheTakeRepeat(self): dataset = dataset_ops.Dataset.range(10).cache().take(5).repeat(2) - itr = dataset.make_one_shot_iterator() - n = itr.get_next() - - expected_values = [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] - with self.cached_session() as sess: - for i, expected in enumerate(expected_values): - self.assertEqual(expected, sess.run(n), - "Unexpected value at index %s" % i) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + expected_output = [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] + self.assertDatasetProduces(dataset, expected_output=expected_output) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py b/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py index 83af31f380..3123e32d8e 100644 --- a/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py @@ -24,9 +24,11 @@ from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest from tensorflow.python.framework import errors from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class ConcatenateDatasetTest(test_base.DatasetTestBase): def testConcatenateDataset(self): @@ -46,23 +48,19 @@ class ConcatenateDatasetTest(test_base.DatasetTestBase): self.assertEqual(concatenated.output_shapes, (tensor_shape.TensorShape( [20]), tensor_shape.TensorShape([15]), tensor_shape.TensorShape([]))) - iterator = concatenated.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(9): - result = sess.run(get_next) - if i < 4: - for component, result_component in zip(input_components, result): - self.assertAllEqual(component[i], result_component) - else: - for component, result_component in zip(to_concatenate_components, - result): - self.assertAllEqual(component[i - 4], result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + get_next = self.getNext(concatenated) + + for i in range(9): + result = self.evaluate(get_next()) + if i < 4: + for component, result_component in zip(input_components, result): + self.assertAllEqual(component[i], result_component) + else: + for component, result_component in zip(to_concatenate_components, + result): + self.assertAllEqual(component[i - 4], result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testConcatenateDatasetDifferentShape(self): input_components = ( @@ -79,24 +77,18 @@ class ConcatenateDatasetTest(test_base.DatasetTestBase): self.assertEqual( [ts.as_list() for ts in nest.flatten(concatenated.output_shapes)], [[20], [None]]) - - iterator = concatenated.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(9): - result = sess.run(get_next) - if i < 4: - for component, result_component in zip(input_components, result): - self.assertAllEqual(component[i], result_component) - else: - for component, result_component in zip(to_concatenate_components, - result): - self.assertAllEqual(component[i - 4], result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + get_next = self.getNext(concatenated) + for i in range(9): + result = self.evaluate(get_next()) + if i < 4: + for component, result_component in zip(input_components, result): + self.assertAllEqual(component[i], result_component) + else: + for component, result_component in zip(to_concatenate_components, + result): + self.assertAllEqual(component[i - 4], result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testConcatenateDatasetDifferentStructure(self): input_components = ( diff --git a/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py b/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py index bc6b36285a..4a7a946576 100644 --- a/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py @@ -31,33 +31,26 @@ from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class DatasetConstructorTest(test_base.DatasetTestBase): def testFromTensors(self): """Test a dataset that represents a single tuple of tensors.""" components = (np.array(1), np.array([1, 2, 3]), np.array(37.0)) - iterator = (dataset_ops.Dataset.from_tensors(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.from_tensors(components) self.assertEqual([c.shape for c in components], - [t.shape for t in get_next]) + nest.flatten(dataset.output_shapes)) - with self.cached_session() as sess: - sess.run(init_op) - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertAllEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertDatasetProduces(dataset, expected_output=[components]) def testFromTensorsSparse(self): """Test a dataset that represents a single tuple of tensors.""" @@ -70,23 +63,12 @@ class DatasetConstructorTest(test_base.DatasetTestBase): values=np.array([-1, 1]), dense_shape=np.array([2, 2]))) - iterator = ( - dataset_ops.Dataset.from_tensors(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.from_tensors(components) self.assertEqual( [tensor_shape.TensorShape(c.dense_shape) for c in components], - [shape for shape in iterator.output_shapes]) - - with self.cached_session() as sess: - sess.run(init_op) - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertSparseValuesEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + [shape for shape in dataset.output_shapes]) + self.assertDatasetProduces(dataset, expected_output=[components]) def testFromTensorsMixed(self): """Test an dataset that represents a single tuple of tensors.""" @@ -100,27 +82,13 @@ class DatasetConstructorTest(test_base.DatasetTestBase): values=np.array([-1, 1]), dense_shape=np.array([2, 2]))) - iterator = ( - dataset_ops.Dataset.from_tensors(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - + dataset = dataset_ops.Dataset.from_tensors(components) self.assertEqual([ tensor_shape.TensorShape(c.dense_shape) if sparse_tensor.is_sparse(c) else c.shape for c in components - ], [shape for shape in iterator.output_shapes]) + ], [shape for shape in dataset.output_shapes]) - with self.cached_session() as sess: - sess.run(init_op) - results = sess.run(get_next) - for component, result_component in zip(components, results): - if sparse_tensor.is_sparse(component): - self.assertSparseValuesEqual(component, result_component) - else: - self.assertAllEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertDatasetProduces(dataset, expected_output=[components]) def testFromTensorSlices(self): """Test a dataset that represents the slices from a tuple of tensors.""" @@ -130,22 +98,18 @@ class DatasetConstructorTest(test_base.DatasetTestBase): np.array([37.0, 38.0, 39.0, 40.0]) ) - iterator = (dataset_ops.Dataset.from_tensor_slices(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.from_tensor_slices(components) + get_next = self.getNext(dataset) self.assertEqual([c.shape[1:] for c in components], - [t.shape for t in get_next]) + [shape for shape in dataset.output_shapes]) - with self.cached_session() as sess: - sess.run(init_op) - for i in range(4): - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertAllEqual(component[i], result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + for i in range(4): + results = self.evaluate(get_next()) + for component, result_component in zip(components, results): + self.assertAllEqual(component[i], result_component) + with self.assertRaises(errors.OutOfRangeError): + results = self.evaluate(get_next()) def testFromTensorSlicesSparse(self): """Test a dataset that represents the slices from a tuple of tensors.""" @@ -158,50 +122,39 @@ class DatasetConstructorTest(test_base.DatasetTestBase): values=np.array([1, 2, 3]), dense_shape=np.array([3, 3]))) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.from_tensor_slices(components) self.assertEqual( [tensor_shape.TensorShape(c.dense_shape[1:]) for c in components], - [shape for shape in iterator.output_shapes]) - - with self.cached_session() as sess: - sess.run(init_op) - expected = [ - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([1]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[1]]), - values=np.array([2]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[2]]), - values=np.array([3]), - dense_shape=np.array([3]))), - ] - for i in range(3): - results = sess.run(get_next) - for component, result_component in zip(expected[i], results): - self.assertSparseValuesEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + [shape for shape in dataset.output_shapes]) + + expected = [ + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([1]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[1]]), + values=np.array([2]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[2]]), + values=np.array([3]), + dense_shape=np.array([3]))), + ] + self.assertDatasetProduces(dataset, expected_output=expected) def testFromTensorSlicesMixed(self): """Test a dataset that represents the slices from a tuple of tensors.""" @@ -217,78 +170,68 @@ class DatasetConstructorTest(test_base.DatasetTestBase): values=np.array([1, 2, 3]), dense_shape=np.array([3, 3]))) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - + dataset = dataset_ops.Dataset.from_tensor_slices(components) + get_next = self.getNext(dataset) self.assertEqual([ tensor_shape.TensorShape(c.dense_shape[1:]) if sparse_tensor.is_sparse(c) else c.shape[1:] for c in components - ], [shape for shape in iterator.output_shapes]) - - with self.cached_session() as sess: - sess.run(init_op) - expected = [ - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([1]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[1]]), - values=np.array([2]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[2]]), - values=np.array([3]), - dense_shape=np.array([3]))), - ] - for i in range(3): - results = sess.run(get_next) - for component, result_component in zip( - (list(zip(*components[:3]))[i] + expected[i]), results): - if sparse_tensor.is_sparse(component): - self.assertSparseValuesEqual(component, result_component) - else: - self.assertAllEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + ], [shape for shape in dataset.output_shapes]) + + expected = [ + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([1]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[1]]), + values=np.array([2]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[2]]), + values=np.array([3]), + dense_shape=np.array([3]))), + ] + for i in range(3): + results = self.evaluate(get_next()) + for component, result_component in zip( + (list(zip(*components[:3]))[i] + expected[i]), results): + if sparse_tensor.is_sparse(component): + self.assertSparseValuesEqual(component, result_component) + else: + self.assertAllEqual(component, result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testFromTensorSlicesWithDict(self): components = {"foo": [1, 2, 3], "bar": [[4.0], [5.0], [6.0]]} - iterator = (dataset_ops.Dataset.from_tensor_slices(components) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - self.assertEqual(dtypes.int32, iterator.output_types["foo"]) - self.assertEqual(dtypes.float32, iterator.output_types["bar"]) - self.assertEqual((), iterator.output_shapes["foo"]) - self.assertEqual((1,), iterator.output_shapes["bar"]) - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(3): - results = sess.run(get_next) - self.assertEqual(components["foo"][i], results["foo"]) - self.assertEqual(components["bar"][i], results["bar"]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testFromSparseTensorSlices(self): + dataset = dataset_ops.Dataset.from_tensor_slices(components) + get_next = self.getNext(dataset) + + self.assertEqual(dtypes.int32, dataset.output_types["foo"]) + self.assertEqual(dtypes.float32, dataset.output_types["bar"]) + self.assertEqual((), dataset.output_shapes["foo"]) + self.assertEqual((1,), dataset.output_shapes["bar"]) + + for i in range(3): + results = self.evaluate(get_next()) + self.assertEqual(components["foo"][i], results["foo"]) + self.assertEqual(components["bar"][i], results["bar"]) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + def testSkipEagerFromSparseTensorSlices(self): """Test a dataset based on slices of a `tf.SparseTensor`.""" st = array_ops.sparse_placeholder(dtypes.float64) iterator = (dataset_ops.Dataset.from_sparse_tensor_slices(st) @@ -389,8 +332,33 @@ class DatasetConstructorTest(test_base.DatasetTestBase): for s in nest.flatten(dataset.output_shapes) ])) - iterator = dataset.make_one_shot_iterator() - (w, x), (y, z) = iterator.get_next() + # Define a separate set of components with matching leading + # dimension for the from-slices constructor. + components_for_slices = (np.array([1, 2, 3], dtype=np.int64), + (np.array([4., 5., 6.]), np.array([7., 8., 9.])), + np.array([10, 11, 12], dtype=np.int64)) + + dataset = dataset_ops.Dataset.from_tensor_slices(components_for_slices) + self.assertEquals((dtypes.int64, + (dtypes.float64, dtypes.float64), dtypes.int64), + dataset.output_types) + self.assertEquals(([], ([], []), []), dataset.output_shapes) + + # TODO(b/117581999): more specific shapes in eager mode. + def testSkipEagerNestedStructure(self): + components = (np.array([1, 2, 3], dtype=np.int64), (np.array([4., 5.]), + np.array([6., 7.])), + np.array([8, 9, 10], dtype=np.int64)) + + dataset = dataset_ops.Dataset.from_tensors(components) + dataset = dataset.map(lambda x, y, z: ((x, z), (y[0], y[1]))) + + dataset = dataset.flat_map( + lambda x, y: dataset_ops.Dataset.from_tensors( + ((x[0], x[1]), (y[0], y[1])))).batch(32) + + get_next = self.getNext(dataset) + (w, x), (y, z) = get_next() self.assertEquals(dtypes.int64, w.dtype) self.assertEquals(dtypes.int64, x.dtype) self.assertEquals(dtypes.float64, y.dtype) @@ -400,8 +368,8 @@ class DatasetConstructorTest(test_base.DatasetTestBase): self.assertEquals([None, 2], y.shape.as_list()) self.assertEquals([None, 2], z.shape.as_list()) - iterator = dataset.make_initializable_iterator() - (w, x), (y, z) = iterator.get_next() + get_next = self.getNext(dataset) + (w, x), (y, z) = get_next() self.assertEquals(dtypes.int64, w.dtype) self.assertEquals(dtypes.int64, x.dtype) self.assertEquals(dtypes.float64, y.dtype) @@ -411,18 +379,6 @@ class DatasetConstructorTest(test_base.DatasetTestBase): self.assertEquals([None, 2], y.shape.as_list()) self.assertEquals([None, 2], z.shape.as_list()) - # Define a separate set of components with matching leading - # dimension for the from-slices constructor. - components_for_slices = (np.array([1, 2, 3], dtype=np.int64), - (np.array([4., 5., 6.]), - np.array([7., 8., 9.])), - np.array([10, 11, 12], dtype=np.int64)) - - dataset = dataset_ops.Dataset.from_tensor_slices(components_for_slices) - self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), - dtypes.int64), dataset.output_types) - self.assertEquals(([], ([], []), []), dataset.output_shapes) - def testNestedDict(self): components = {"a": {"aa": 1, "ab": [2.0, 2.0]}, "b": [3, 3, 3]} dataset = dataset_ops.Dataset.from_tensors(components) @@ -454,12 +410,11 @@ class DatasetConstructorTest(test_base.DatasetTestBase): self.assertEquals(dtypes.int64, dataset.output_types) self.assertEquals([3], dataset.output_shapes) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - self.assertEquals(dtypes.int64, get_next.dtype) - self.assertEquals([3], get_next.shape) + get_next = self.getNext(dataset) + self.assertEquals(dtypes.int64, get_next().dtype) + self.assertEquals([3], get_next().shape) - def testSplitPipelineFailsWithPlacementError(self): + def testSkipEagerSplitPipelineFailsWithPlacementError(self): with session.Session( target="", config=config_pb2.ConfigProto(device_count={"CPU": 2})) as sess: @@ -490,6 +445,7 @@ class DatasetConstructorTest(test_base.DatasetTestBase): sess.run(iterator.get_next()) +# TODO(b/119837791): Add eager benchmarks as well. class DatasetConstructorBenchmark(test.Benchmark): def benchmarkSliceRepeatBatch(self): diff --git a/tensorflow/python/data/kernel_tests/dataset_ops_test.py b/tensorflow/python/data/kernel_tests/dataset_ops_test.py index 67d3b41d3e..373cdc0a77 100644 --- a/tensorflow/python/data/kernel_tests/dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_ops_test.py @@ -32,17 +32,18 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): def testAsSerializedGraph(self): dataset = dataset_ops.Dataset.range(10) - with self.cached_session() as sess: - graph = graph_pb2.GraphDef().FromString( - sess.run(dataset._as_serialized_graph())) - self.assertTrue(any(node.op != "RangeDataset" for node in graph.node)) + graph = graph_pb2.GraphDef().FromString( + self.evaluate(dataset._as_serialized_graph())) + self.assertTrue(any([node.op != "RangeDataset" for node in graph.node])) @staticmethod def make_apply_fn(dataset): @@ -253,6 +254,7 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertTrue(ds.options().experimental_autotune) self.assertTrue(ds.options().experimental_filter_fusion) + # TODO(b/119882922): use-after-free bug in eager mode. # pylint: disable=g-long-lambda @parameterized.named_parameters( ("Tensor", lambda: constant_op.constant(37.0), @@ -276,7 +278,8 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): optional_ops.OptionalStructure( structure.TensorStructure(dtypes.float32, []))), ) - def testDatasetStructure(self, tf_value_fn, expected_element_structure): + def testSkipEagerDatasetStructure(self, tf_value_fn, + expected_element_structure): dataset = dataset_ops.Dataset.from_tensors(0).map(lambda _: tf_value_fn()) dataset_structure = structure.Structure.from_value(dataset) self.assertIsInstance(dataset_structure, dataset_ops.DatasetStructure) diff --git a/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py b/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py index a0c6b37a6d..fba474b97b 100644 --- a/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py @@ -24,16 +24,17 @@ import numpy as np from tensorflow.python.client import session from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import functional_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class FilterDatasetTest(test_base.DatasetTestBase): def testFilterDataset(self): @@ -43,69 +44,43 @@ class FilterDatasetTest(test_base.DatasetTestBase): 7, dtype=np.int64)[:, np.newaxis], np.array(37.0, dtype=np.float64) * np.arange(7) ) - count = array_ops.placeholder(dtypes.int64, shape=[]) - modulus = array_ops.placeholder(dtypes.int64) - def _map_fn(x, y, z): return math_ops.square(x), math_ops.square(y), math_ops.square(z) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components).map(_map_fn) - .repeat(count) - .filter(lambda x, _y, _z: math_ops.equal(math_ops.mod(x, modulus), 0)) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - self.assertEqual([c.shape[1:] for c in components], - [t.shape for t in get_next]) - - with self.cached_session() as sess: - # Test that we can dynamically feed a different modulus value for each - # iterator. - def do_test(count_val, modulus_val): - sess.run(init_op, feed_dict={count: count_val, modulus: modulus_val}) - for _ in range(count_val): - for i in [x for x in range(7) if x**2 % modulus_val == 0]: - result = sess.run(get_next) - for component, result_component in zip(components, result): - self.assertAllEqual(component[i]**2, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - do_test(14, 2) - do_test(4, 18) - - # Test an empty dataset. - do_test(0, 1) + def do_test(count, modulus): + dataset = dataset_ops.Dataset.from_tensor_slices(components).map( + _map_fn).repeat(count).filter( + lambda x, _y, _z: math_ops.equal(math_ops.mod(x, modulus), 0)) + self.assertEqual([c.shape[1:] for c in components], + [shape for shape in dataset.output_shapes]) + get_next = self.getNext(dataset) + for _ in range(count): + for i in [x for x in range(7) if x**2 % modulus == 0]: + result = self.evaluate(get_next()) + for component, result_component in zip(components, result): + self.assertAllEqual(component[i]**2, result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + do_test(14, 2) + do_test(4, 18) + + # Test an empty dataset. + do_test(0, 1) def testFilterRange(self): - dataset = dataset_ops.Dataset.range(100).filter( + dataset = dataset_ops.Dataset.range(4).filter( lambda x: math_ops.not_equal(math_ops.mod(x, 3), 2)) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - with self.cached_session() as sess: - self.assertEqual(0, sess.run(get_next)) - self.assertEqual(1, sess.run(get_next)) - self.assertEqual(3, sess.run(get_next)) + self.assertDatasetProduces(dataset, expected_output=[0, 1, 3]) def testFilterDict(self): - iterator = (dataset_ops.Dataset.range(10) - .map(lambda x: {"foo": x * 2, "bar": x ** 2}) - .filter(lambda d: math_ops.equal(d["bar"] % 2, 0)) - .map(lambda d: d["foo"] + d["bar"]) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(10): - if (i ** 2) % 2 == 0: - self.assertEqual(i * 2 + i ** 2, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).map( + lambda x: {"foo": x * 2, "bar": x ** 2}).filter( + lambda d: math_ops.equal(d["bar"] % 2, 0)).map( + lambda d: d["foo"] + d["bar"]) + self.assertDatasetProduces( + dataset, + expected_output=[(i * 2 + i**2) for i in range(10) if not (i**2) % 2]) def testUseStepContainerInFilter(self): input_data = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int64) @@ -117,18 +92,9 @@ class FilterDatasetTest(test_base.DatasetTestBase): summed = math_ops.reduce_sum(squared_xs) return math_ops.equal(summed, 1 + 4 + 9) - iterator = ( - dataset_ops.Dataset.from_tensor_slices([[1, 2, 3], [4, 5, 6]]) - .filter(_predicate) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - self.assertAllEqual(input_data[0], sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.from_tensor_slices( + [[1, 2, 3], [4, 5, 6]]).filter(_predicate) + self.assertDatasetProduces(dataset, expected_output=[input_data[0]]) def testSparse(self): @@ -141,46 +107,29 @@ class FilterDatasetTest(test_base.DatasetTestBase): def _filter_fn(_, i): return math_ops.equal(i % 2, 0) - iterator = ( - dataset_ops.Dataset.range(10).map(_map_fn).filter(_filter_fn).map( - lambda x, i: x).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(5): - actual = sess.run(get_next) - self.assertTrue(isinstance(actual, sparse_tensor.SparseTensorValue)) - self.assertSparseValuesEqual(actual, _map_fn(i * 2)[0]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).map(_map_fn).filter(_filter_fn).map( + lambda x, i: x) + self.assertDatasetProduces( + dataset, expected_output=[_map_fn(i * 2)[0] for i in range(5)]) def testShortCircuit(self): - iterator = ( - dataset_ops.Dataset.zip( - (dataset_ops.Dataset.range(10), - dataset_ops.Dataset.from_tensors(True).repeat(None))) - .filter(lambda x, y: y).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(10): - self.assertEqual((i, True), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.zip( + (dataset_ops.Dataset.range(10), + dataset_ops.Dataset.from_tensors(True).repeat(None) + )).filter(lambda x, y: y) + self.assertDatasetProduces( + dataset, expected_output=[(i, True) for i in range(10)]) def testParallelFilters(self): dataset = dataset_ops.Dataset.range(10).filter( lambda x: math_ops.equal(x % 2, 0)) - iterators = [dataset.make_one_shot_iterator() for _ in range(10)] - next_elements = [iterator.get_next() for iterator in iterators] - with self.cached_session() as sess: - self.assertEqual([0 for _ in range(10)], sess.run(next_elements)) + next_elements = [self.getNext(dataset) for _ in range(10)] + self.assertEqual([0 for _ in range(10)], + self.evaluate( + [next_element() for next_element in next_elements])) +# TODO(b/119837791): Add eager benchmarks too. class FilterDatasetBenchmark(test.Benchmark): def _benchmark(self, predicate, name): diff --git a/tensorflow/python/data/kernel_tests/inputs_test.py b/tensorflow/python/data/kernel_tests/inputs_test.py index d089b49bcc..03df502d14 100644 --- a/tensorflow/python/data/kernel_tests/inputs_test.py +++ b/tensorflow/python/data/kernel_tests/inputs_test.py @@ -25,9 +25,11 @@ from tensorflow.python.data.ops import readers from tensorflow.python.data.util import nest from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class InputsTest(test_base.DatasetTestBase, parameterized.TestCase): @staticmethod diff --git a/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py b/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py index b58c1444da..7efe3c692a 100644 --- a/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py @@ -24,13 +24,13 @@ import tempfile from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors -from tensorflow.python.ops import array_ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test from tensorflow.python.util import compat +@test_util.run_all_in_graph_and_eager_modes class ListFilesDatasetOpTest(test_base.DatasetTestBase): def setUp(self): @@ -43,32 +43,23 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): for filename in filenames: open(path.join(self.tmp_dir, filename), 'a').close() - def testEmptyDirectory(self): + # Note: eager mode fails in assertion error same as initializer in graph mode. + def testSkipEagerEmptyDirectory(self): dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*')) - with self.cached_session() as sess: - itr = dataset.make_one_shot_iterator() - next_element = itr.get_next() - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.assertDatasetProduces(dataset, expected_output=[]) def testSimpleDirectory(self): filenames = ['a', 'b', 'c'] self._touchTempFiles(filenames) dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*')) - with self.cached_session() as sess: - itr = dataset.make_one_shot_iterator() - next_element = itr.get_next() - - full_filenames = [] - produced_filenames = [] - for filename in filenames: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) - self.assertItemsEqual(full_filenames, produced_filenames) - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames + ], + assert_items_equal=True) def testSimpleDirectoryNotShuffled(self): filenames = ['b', 'c', 'a'] @@ -76,15 +67,12 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): dataset = dataset_ops.Dataset.list_files( path.join(self.tmp_dir, '*'), shuffle=False) - with self.cached_session() as sess: - itr = dataset.make_one_shot_iterator() - next_element = itr.get_next() - - for filename in sorted(filenames): - self.assertEqual(compat.as_bytes(path.join(self.tmp_dir, filename)), - sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in sorted(filenames) + ]) def testFixedSeedResultsInRepeatableOrder(self): filenames = ['a', 'b', 'c'] @@ -92,120 +80,76 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): dataset = dataset_ops.Dataset.list_files( path.join(self.tmp_dir, '*'), shuffle=True, seed=37) - with self.cached_session() as sess: - itr = dataset.make_initializable_iterator() - next_element = itr.get_next() - - full_filenames = [compat.as_bytes(path.join(self.tmp_dir, filename)) - for filename in filenames] - - all_produced_filenames = [] - for _ in range(3): - produced_filenames = [] - sess.run(itr.initializer) - try: - while True: - produced_filenames.append(sess.run(next_element)) - except errors.OutOfRangeError: - pass - all_produced_filenames.append(produced_filenames) - - # Each run should produce the same set of filenames, which may be - # different from the order of `full_filenames`. - self.assertItemsEqual(full_filenames, all_produced_filenames[0]) - # However, the different runs should produce filenames in the same order - # as each other. - self.assertEqual(all_produced_filenames[0], all_produced_filenames[1]) - self.assertEqual(all_produced_filenames[0], all_produced_filenames[2]) - - def testEmptyDirectoryInitializer(self): - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - dataset = dataset_ops.Dataset.list_files(filename_placeholder) - - with self.cached_session() as sess: - itr = dataset.make_initializable_iterator() - with self.assertRaisesRegexp( - errors.InvalidArgumentError, 'No files matched pattern: '): - sess.run( - itr.initializer, - feed_dict={filename_placeholder: path.join(self.tmp_dir, '*')}) - - def testSimpleDirectoryInitializer(self): - filenames = ['a', 'b', 'c'] - self._touchTempFiles(filenames) - - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - dataset = dataset_ops.Dataset.list_files(filename_placeholder) - with self.cached_session() as sess: - itr = dataset.make_initializable_iterator() - next_element = itr.get_next() - sess.run( - itr.initializer, - feed_dict={filename_placeholder: path.join(self.tmp_dir, '*')}) + full_filenames = [compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames] - full_filenames = [] + all_produced_filenames = [] + for _ in range(3): produced_filenames = [] - for filename in filenames: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) + next_element = self.getNext(dataset, requires_initialization=True) + try: + while True: + produced_filenames.append(self.evaluate(next_element())) + except errors.OutOfRangeError: + pass + all_produced_filenames.append(produced_filenames) + + # Each run should produce the same set of filenames, which may be + # different from the order of `full_filenames`. + self.assertItemsEqual(full_filenames, all_produced_filenames[0]) + # However, the different runs should produce filenames in the same order + # as each other. + self.assertEqual(all_produced_filenames[0], all_produced_filenames[1]) + self.assertEqual(all_produced_filenames[0], all_produced_filenames[2]) + + # TODO(b/117581999): eager mode assertion fail wrapped, debug. + def tesSkipEagerEmptyDirectoryInitializer(self): + dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*')) + self.assertDatasetProduces( + dataset, + expected_error=(errors.InvalidArgumentError, + 'No files matched pattern'), + requires_initialization=True) - self.assertItemsEqual(full_filenames, produced_filenames) + def testSimpleDirectoryInitializer(self): + filenames = ['a', 'b', 'c'] + self._touchTempFiles(filenames) - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*')) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames + ], + assert_items_equal=True) def testFileSuffixes(self): filenames = ['a.txt', 'b.py', 'c.py', 'd.pyc'] self._touchTempFiles(filenames) - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - dataset = dataset_ops.Dataset.list_files(filename_placeholder) - - with self.cached_session() as sess: - itr = dataset.make_initializable_iterator() - next_element = itr.get_next() - sess.run( - itr.initializer, - feed_dict={filename_placeholder: path.join(self.tmp_dir, '*.py')}) - - full_filenames = [] - produced_filenames = [] - for filename in filenames[1:-1]: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) - self.assertItemsEqual(full_filenames, produced_filenames) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*.py')) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames[1:-1] + ], + assert_items_equal=True) def testFileMiddles(self): filenames = ['a.txt', 'b.py', 'c.pyc'] self._touchTempFiles(filenames) - filename_placeholder = array_ops.placeholder(dtypes.string, shape=[]) - dataset = dataset_ops.Dataset.list_files(filename_placeholder) - - with self.cached_session() as sess: - itr = dataset.make_initializable_iterator() - next_element = itr.get_next() - sess.run( - itr.initializer, - feed_dict={filename_placeholder: path.join(self.tmp_dir, '*.py*')}) - - full_filenames = [] - produced_filenames = [] - for filename in filenames[1:]: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) - - self.assertItemsEqual(full_filenames, produced_filenames) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + dataset = dataset_ops.Dataset.list_files(path.join(self.tmp_dir, '*.py*')) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames[1:] + ], + assert_items_equal=True) def testNoShuffle(self): filenames = ['a', 'b', 'c'] @@ -222,21 +166,18 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): # more meaningful. dataset = dataset_ops.Dataset.list_files( path.join(self.tmp_dir, '*'), shuffle=False).repeat(2) - with self.cached_session() as sess: - itr = dataset.make_one_shot_iterator() - next_element = itr.get_next() - - full_filenames = [] - produced_filenames = [] - for filename in filenames * 2: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) - self.assertItemsEqual(full_filenames, produced_filenames) - self.assertEqual(produced_filenames[:len(filenames)], - produced_filenames[len(filenames):]) + next_element = self.getNext(dataset) + + full_filenames = [] + produced_filenames = [] + for filename in filenames * 2: + full_filenames.append(compat.as_bytes(path.join(self.tmp_dir, filename))) + produced_filenames.append(compat.as_bytes(self.evaluate(next_element()))) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(next_element()) + self.assertItemsEqual(full_filenames, produced_filenames) + self.assertEqual(produced_filenames[:len(filenames)], + produced_filenames[len(filenames):]) def testMultiplePatternsAsList(self): filenames = ['a.txt', 'b.py', 'c.py', 'd.pyc'] @@ -244,47 +185,27 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): patterns = [path.join(self.tmp_dir, pat) for pat in ['*.py', '*.txt']] dataset = dataset_ops.Dataset.list_files(patterns) - with self.cached_session() as sess: - itr = dataset.make_one_shot_iterator() - next_element = itr.get_next() - - full_filenames = [] - produced_filenames = [] - for filename in filenames[:-1]: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) - self.assertItemsEqual(full_filenames, produced_filenames) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames[:-1] + ], + assert_items_equal=True) def testMultiplePatternsAsTensor(self): filenames = ['a.txt', 'b.py', 'c.py', 'd.pyc'] self._touchTempFiles(filenames) - filename_placeholder = array_ops.placeholder( - dtypes.string, shape=[ - 2, - ]) - dataset = dataset_ops.Dataset.list_files(filename_placeholder) - - with self.cached_session() as sess: - itr = dataset.make_initializable_iterator() - next_element = itr.get_next() - patterns = [path.join(self.tmp_dir, pat) for pat in ['*.py', '*.txt']] - sess.run(itr.initializer, feed_dict={filename_placeholder: patterns}) - - full_filenames = [] - produced_filenames = [] - for filename in filenames[:-1]: - full_filenames.append( - compat.as_bytes(path.join(self.tmp_dir, filename))) - produced_filenames.append(compat.as_bytes(sess.run(next_element))) - self.assertItemsEqual(full_filenames, produced_filenames) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(itr.get_next()) + dataset = dataset_ops.Dataset.list_files( + [path.join(self.tmp_dir, pat) for pat in ['*.py', '*.txt']]) + self.assertDatasetProduces( + dataset, + expected_output=[ + compat.as_bytes(path.join(self.tmp_dir, filename)) + for filename in filenames[:-1] + ], + assert_items_equal=True) if __name__ == '__main__': diff --git a/tensorflow/python/data/kernel_tests/optional_ops_test.py b/tensorflow/python/data/kernel_tests/optional_ops_test.py index 604e3ad88e..5406a202a3 100644 --- a/tensorflow/python/data/kernel_tests/optional_ops_test.py +++ b/tensorflow/python/data/kernel_tests/optional_ops_test.py @@ -36,15 +36,14 @@ from tensorflow.python.ops import array_ops from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): - @test_util.run_in_graph_and_eager_modes def testFromValue(self): opt = optional_ops.Optional.from_value(constant_op.constant(37.0)) self.assertTrue(self.evaluate(opt.has_value())) self.assertEqual(37.0, self.evaluate(opt.get_value())) - @test_util.run_in_graph_and_eager_modes def testFromStructuredValue(self): opt = optional_ops.Optional.from_value({ "a": constant_op.constant(37.0), @@ -56,7 +55,6 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): "b": ([b"Foo"], b"Bar") }, self.evaluate(opt.get_value())) - @test_util.run_in_graph_and_eager_modes def testFromSparseTensor(self): st_0 = sparse_tensor.SparseTensorValue( indices=np.array([[0]]), @@ -75,7 +73,6 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertAllEqual(expected.dense_shape, self.evaluate(actual.dense_shape)) - @test_util.run_in_graph_and_eager_modes def testFromNone(self): value_structure = structure.TensorStructure(dtypes.float32, []) opt = optional_ops.Optional.none_from_structure(value_structure) @@ -90,7 +87,6 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.InvalidArgumentError): self.evaluate(opt.get_value()) - @test_util.run_in_graph_and_eager_modes def testCopyToGPU(self): if not test_util.is_gpu_available(): self.skipTest("No GPU available") @@ -151,7 +147,8 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): optional_ops.OptionalStructure( structure.TensorStructure(dtypes.float32, []))), ) - def testOptionalStructure(self, tf_value_fn, expected_value_structure): + def testSkipEagerOptionalStructure(self, tf_value_fn, + expected_value_structure): tf_value = tf_value_fn() opt = optional_ops.Optional.from_value(tf_value) @@ -205,7 +202,8 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): indices=[[0, 1], [1, 0]], values=[37.0, 42.0], dense_shape=[2, 2])}, False), ) - def testIteratorGetNextAsOptional(self, np_value, tf_value_fn, works_on_gpu): + def testSkipEagerIteratorGetNextAsOptional(self, np_value, tf_value_fn, + works_on_gpu): if not works_on_gpu and test.is_gpu_available(): self.skipTest("Test case not yet supported on GPU.") ds = dataset_ops.Dataset.from_tensors(np_value).repeat(3) diff --git a/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py index 76e2697b29..41b0689947 100644 --- a/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py @@ -21,39 +21,24 @@ from absl.testing import parameterized from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors -from tensorflow.python.ops import array_ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class PrefetchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.parameters((-1), (0), (5)) def testBufferSize(self, buffer_size): - buffer_size_t = array_ops.placeholder(dtypes.int64, shape=[]) - iterator = dataset_ops.Dataset.range(10).prefetch( - buffer_size=buffer_size_t).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op, feed_dict={buffer_size_t: buffer_size}) - for m in range(10): - self.assertEqual(m, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).prefetch(buffer_size=buffer_size) + self.assertDatasetProduces(dataset, expected_output=range(10)) @parameterized.parameters((-2), (-42)) def testInvalidBufferSize(self, buffer_size): - buffer_size_t = array_ops.placeholder(dtypes.int64, shape=[]) - iterator = dataset_ops.Dataset.range(10).prefetch( - buffer_size=buffer_size_t).make_initializable_iterator() - init_op = iterator.initializer - - with self.assertRaisesRegexp(errors.InvalidArgumentError, "buffer_size"): - with self.cached_session() as sess: - sess.run(init_op, feed_dict={buffer_size_t: buffer_size}) + dataset = dataset_ops.Dataset.range(10).prefetch(buffer_size=buffer_size) + self.assertDatasetProduces( + dataset, expected_error=(errors.InvalidArgumentError, "buffer_size")) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py b/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py index e86356dee7..6da4e0dfca 100644 --- a/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py @@ -21,12 +21,11 @@ import numpy as np from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import dtypes -from tensorflow.python.framework import errors -from tensorflow.python.ops import array_ops +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class SequenceDatasetTest(test_base.DatasetTestBase): def testRepeatTensorDataset(self): @@ -35,175 +34,101 @@ class SequenceDatasetTest(test_base.DatasetTestBase): # This placeholder can be fed when dataset-definition subgraph # runs (i.e. `init_op` below) to configure the number of # repetitions used in a particular iterator. - count_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - iterator = (dataset_ops.Dataset.from_tensors(components) - .repeat(count_placeholder).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + def do_test(count): + dataset = dataset_ops.Dataset.from_tensors(components).repeat(count) + self.assertEqual([c.shape for c in components], + [shape for shape in dataset.output_shapes]) + self.assertDatasetProduces(dataset, [components] * count) + # Test a finite repetition. + do_test(3) + + # test a different finite repetition. + do_test(7) + + # Test an empty repetition. + do_test(0) + + # Test an infinite repetition. + # NOTE(mrry): There's not a good way to test that the sequence + # actually is infinite. + dataset = dataset_ops.Dataset.from_tensors(components).repeat(-1) self.assertEqual([c.shape for c in components], - [t.shape for t in get_next]) - - with self.cached_session() as sess: - # Test a finite repetition. - sess.run(init_op, feed_dict={count_placeholder: 3}) - for _ in range(3): - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertAllEqual(component, result_component) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test a different finite repetition. - sess.run(init_op, feed_dict={count_placeholder: 7}) - for _ in range(7): - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertAllEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test an empty repetition. - sess.run(init_op, feed_dict={count_placeholder: 0}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test an infinite repetition. - # NOTE(mrry): There's not a good way to test that the sequence - # actually is infinite. - sess.run(init_op, feed_dict={count_placeholder: -1}) - for _ in range(17): - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertAllEqual(component, result_component) + [shape for shape in dataset.output_shapes]) + get_next = self.getNext(dataset) + for _ in range(17): + results = self.evaluate(get_next()) + for component, result_component in zip(components, results): + self.assertAllEqual(component, result_component) def testTakeTensorDataset(self): components = (np.arange(10),) - count_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - iterator = (dataset_ops.Dataset.from_tensor_slices(components) - .take(count_placeholder).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + def do_test(count): + dataset = dataset_ops.Dataset.from_tensor_slices(components).take(count) + self.assertEqual([c.shape[1:] for c in components], + [shape for shape in dataset.output_shapes]) + num_output = min(count, 10) if count != -1 else 10 + self.assertDatasetProduces( + dataset, [tuple(components[0][i:i + 1]) for i in range(num_output)]) - self.assertEqual([c.shape[1:] for c in components], - [t.shape for t in get_next]) + # Take fewer than input size + do_test(4) - with self.cached_session() as sess: - # Take fewer than input size - sess.run(init_op, feed_dict={count_placeholder: 4}) - for i in range(4): - results = sess.run(get_next) - self.assertAllEqual(results, components[0][i:i+1]) + # Take more than input size + do_test(25) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + # Take all of input + do_test(-1) - # Take more than input size - sess.run(init_op, feed_dict={count_placeholder: 25}) - for i in range(10): - results = sess.run(get_next) - self.assertAllEqual(results, components[0][i:i+1]) + # Take nothing + do_test(0) + + def testSkipTensorDataset(self): + components = (np.arange(10),) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + def do_test(count): + dataset = dataset_ops.Dataset.from_tensor_slices(components).skip(count) + self.assertEqual([c.shape[1:] for c in components], + [shape for shape in dataset.output_shapes]) + start_range = min(count, 10) if count != -1 else 10 + self.assertDatasetProduces( + dataset, + [tuple(components[0][i:i + 1]) for i in range(start_range, 10)]) - # Take all of input - sess.run(init_op, feed_dict={count_placeholder: -1}) - for i in range(10): - results = sess.run(get_next) - self.assertAllEqual(results, components[0][i:i+1]) + # Skip fewer than input size, we should skip + # the first 4 elements and then read the rest. + do_test(4) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + # Skip more than input size: get nothing. + do_test(25) - # Take nothing - sess.run(init_op, feed_dict={count_placeholder: 0}) + # Skip exactly input size. + do_test(10) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + # Set -1 for 'count': skip the entire dataset. + do_test(-1) - def testSkipTensorDataset(self): - components = (np.arange(10),) - count_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - - iterator = (dataset_ops.Dataset.from_tensor_slices(components) - .skip(count_placeholder).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - self.assertEqual([c.shape[1:] for c in components], - [t.shape for t in get_next]) - - with self.cached_session() as sess: - # Skip fewer than input size, we should skip - # the first 4 elements and then read the rest. - sess.run(init_op, feed_dict={count_placeholder: 4}) - for i in range(4, 10): - results = sess.run(get_next) - self.assertAllEqual(results, components[0][i:i+1]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Skip more than input size: get nothing. - sess.run(init_op, feed_dict={count_placeholder: 25}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Skip exactly input size. - sess.run(init_op, feed_dict={count_placeholder: 10}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Set -1 for 'count': skip the entire dataset. - sess.run(init_op, feed_dict={count_placeholder: -1}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Skip nothing - sess.run(init_op, feed_dict={count_placeholder: 0}) - for i in range(0, 10): - results = sess.run(get_next) - self.assertAllEqual(results, components[0][i:i+1]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + # Skip nothing + do_test(0) def testRepeatRepeatTensorDataset(self): """Test the composition of repeat datasets.""" components = (np.array(1), np.array([1, 2, 3]), np.array(37.0)) - inner_count = array_ops.placeholder(dtypes.int64, shape=[]) - outer_count = array_ops.placeholder(dtypes.int64, shape=[]) - - iterator = (dataset_ops.Dataset.from_tensors(components).repeat(inner_count) - .repeat(outer_count).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() + inner_count, outer_count = 7, 14 + dataset = dataset_ops.Dataset.from_tensors(components).repeat( + inner_count).repeat(outer_count) self.assertEqual([c.shape for c in components], - [t.shape for t in get_next]) - - with self.cached_session() as sess: - sess.run(init_op, feed_dict={inner_count: 7, outer_count: 14}) - for _ in range(7 * 14): - results = sess.run(get_next) - for component, result_component in zip(components, results): - self.assertAllEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + [shape for shape in dataset.output_shapes]) + self.assertDatasetProduces(dataset, + [components] * (inner_count * outer_count)) def testRepeatEmptyDataset(self): """Test that repeating an empty dataset does not hang.""" - iterator = (dataset_ops.Dataset.from_tensors(0).repeat(10).skip(10) - .repeat(-1).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.from_tensors(0).repeat(10).skip(10).repeat(-1) + self.assertDatasetProduces(dataset, []) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/shard_dataset_op_test.py b/tensorflow/python/data/kernel_tests/shard_dataset_op_test.py index b9f3c79da5..7dd932d015 100644 --- a/tensorflow/python/data/kernel_tests/shard_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/shard_dataset_op_test.py @@ -19,43 +19,26 @@ from __future__ import print_function from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class ShardDatasetOpTest(test_base.DatasetTestBase): def testSimpleCase(self): dataset = dataset_ops.Dataset.range(10).shard(5, 2) - iterator = dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - self.assertEqual(2, sess.run(iterator.get_next())) - self.assertEqual(7, sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[2, 7]) def testNestedData(self): dataset_a = dataset_ops.Dataset.range(10) dataset_b = dataset_ops.Dataset.range(10, 0, -1) dataset = dataset_ops.Dataset.zip((dataset_a, dataset_b)).shard(5, 2) - iterator = dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - self.assertEqual((2, 8), sess.run(iterator.get_next())) - self.assertEqual((7, 3), sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[(2, 8), (7, 3)]) def testOffsetZero(self): dataset = dataset_ops.Dataset.range(10).shard(5, 0) - iterator = dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - self.assertEqual(0, sess.run(iterator.get_next())) - self.assertEqual(5, sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[0, 5]) def testOffsetGreaterNumShards(self): with self.assertRaises(ValueError): @@ -75,37 +58,19 @@ class ShardDatasetOpTest(test_base.DatasetTestBase): def testIteratorEndsBeforeFirstElem(self): dataset = dataset_ops.Dataset.range(1).shard(5, 2) - iterator = dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[]) def testLargerWorkerPool(self): dataset = dataset_ops.Dataset.range(10).shard(7, 5) - iterator = dataset.make_one_shot_iterator() - with self.cached_session() as sess: - self.assertEqual(5, sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[5]) def testIndexEqualsNumShards(self): dataset = dataset_ops.Dataset.range(10).shard(5, 4) - iterator = dataset.make_one_shot_iterator() - with self.cached_session() as sess: - self.assertEqual(4, sess.run(iterator.get_next())) - self.assertEqual(9, sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[4, 9]) def testIndexEqualsNumShards2(self): dataset = dataset_ops.Dataset.range(10).shard(4, 3) - iterator = dataset.make_one_shot_iterator() - with self.cached_session() as sess: - self.assertEqual(3, sess.run(iterator.get_next())) - self.assertEqual(7, sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + self.assertDatasetProduces(dataset, expected_output=[3, 7]) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py b/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py index cad28f860e..bf8303ca6e 100644 --- a/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py @@ -24,16 +24,17 @@ import numpy as np from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import iterator_ops -from tensorflow.python.framework import constant_op + from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): def testShuffleDataset(self): @@ -41,102 +42,80 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8]), np.array([9.0, 10.0, 11.0, 12.0]) ) - count_placeholder = array_ops.placeholder_with_default( - constant_op.constant(5, dtypes.int64), shape=[]) - buffer_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - seed_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - - repeat_dataset = (dataset_ops.Dataset.from_tensor_slices(components) - .repeat(count_placeholder)) - - shuffle_dataset = repeat_dataset.shuffle(buffer_size_placeholder, - seed_placeholder) - - self.assertEqual(tuple([c.shape[1:] for c in components]), - shuffle_dataset.output_shapes) - - # Create initialization ops for iterators without and with - # shuffling, respectively. - iterator = iterator_ops.Iterator.from_structure( - shuffle_dataset.output_types, shuffle_dataset.output_shapes) - init_fifo_op = iterator.make_initializer(repeat_dataset) - init_shuffle_op = iterator.make_initializer(shuffle_dataset) - - get_next = iterator.get_next() - - with self.cached_session() as sess: - # First run without shuffling to collect the "ground truth". - sess.run(init_fifo_op) - unshuffled_elements = [] - for _ in range(20): - unshuffled_elements.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Assert that the shuffled dataset has the same elements as the - # "ground truth". - sess.run( - init_shuffle_op, - feed_dict={buffer_size_placeholder: 100, - seed_placeholder: 37}) - shuffled_elements = [] - for _ in range(20): - shuffled_elements.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - self.assertAllEqual( - sorted(unshuffled_elements), sorted(shuffled_elements)) - - # Assert that shuffling twice with the same seeds gives the same sequence. - sess.run( - init_shuffle_op, - feed_dict={buffer_size_placeholder: 100, - seed_placeholder: 37}) - reshuffled_elements_same_seed = [] - for _ in range(20): - reshuffled_elements_same_seed.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - self.assertEqual(shuffled_elements, reshuffled_elements_same_seed) - - # Assert that shuffling twice with a different seed gives a different - # permutation of the same elements. - sess.run( - init_shuffle_op, - feed_dict={buffer_size_placeholder: 100, - seed_placeholder: 1037}) - reshuffled_elements_different_seed = [] - for _ in range(20): - reshuffled_elements_different_seed.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - self.assertNotEqual(shuffled_elements, reshuffled_elements_different_seed) - self.assertAllEqual( - sorted(shuffled_elements), sorted(reshuffled_elements_different_seed)) - - # Assert that the shuffled dataset has the same elements as the - # "ground truth" when the buffer size is smaller than the input - # dataset. - sess.run( - init_shuffle_op, - feed_dict={buffer_size_placeholder: 2, - seed_placeholder: 37}) - reshuffled_elements_small_buffer = [] - for _ in range(20): - reshuffled_elements_small_buffer.append(sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - self.assertAllEqual( - sorted(unshuffled_elements), sorted(reshuffled_elements_small_buffer)) - # Test the case of shuffling an empty dataset. - sess.run(init_shuffle_op, feed_dict={buffer_size_placeholder: 2, - seed_placeholder: 37, - count_placeholder: 0}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + def dataset_fn(count=5, buffer_size=None, seed=0): + repeat_dataset = ( + dataset_ops.Dataset.from_tensor_slices(components).repeat(count)) + if buffer_size: + shuffle_dataset = repeat_dataset.shuffle(buffer_size, seed) - def testSeedZero(self): + self.assertEqual( + tuple([c.shape[1:] for c in components]), + shuffle_dataset.output_shapes) + return shuffle_dataset + else: + return repeat_dataset + + # First run without shuffling to collect the "ground truth". + get_next = self.getNext(dataset_fn()) + unshuffled_elements = [] + for _ in range(20): + unshuffled_elements.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + # Assert that the shuffled dataset has the same elements as the + # "ground truth". + get_next = self.getNext(dataset_fn(buffer_size=100, seed=37)) + shuffled_elements = [] + for _ in range(20): + shuffled_elements.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + self.assertAllEqual(sorted(unshuffled_elements), sorted(shuffled_elements)) + + # Assert that shuffling twice with the same seeds gives the same sequence. + get_next = self.getNext(dataset_fn(buffer_size=100, seed=37)) + reshuffled_elements_same_seed = [] + for _ in range(20): + reshuffled_elements_same_seed.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + self.assertEqual(shuffled_elements, reshuffled_elements_same_seed) + + # Assert that shuffling twice with a different seed gives a different + # permutation of the same elements. + get_next = self.getNext(dataset_fn(buffer_size=100, seed=137)) + reshuffled_elements_different_seed = [] + for _ in range(20): + reshuffled_elements_different_seed.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + self.assertNotEqual(shuffled_elements, reshuffled_elements_different_seed) + self.assertAllEqual( + sorted(shuffled_elements), sorted(reshuffled_elements_different_seed)) + + # Assert that the shuffled dataset has the same elements as the + # "ground truth" when the buffer size is smaller than the input + # dataset. + get_next = self.getNext(dataset_fn(buffer_size=2, seed=37)) + reshuffled_elements_small_buffer = [] + for _ in range(20): + reshuffled_elements_small_buffer.append(self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + self.assertAllEqual( + sorted(unshuffled_elements), sorted(reshuffled_elements_small_buffer)) + + # Test the case of shuffling an empty dataset. + get_next = self.getNext(dataset_fn(count=0, buffer_size=100, seed=37)) + + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + def testSkipEagerSeedZero(self): """Test for same behavior when the seed is a Python or Tensor zero.""" iterator = ( dataset_ops.Dataset.range(10).shuffle(10, seed=0) @@ -165,52 +144,40 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): def testDefaultArguments(self): components = [0, 1, 2, 3, 4] - iterator = (dataset_ops.Dataset.from_tensor_slices(components).shuffle(5) - .repeat().make_one_shot_iterator()) - - get_next = iterator.get_next() - - with self.cached_session() as sess: - counts = collections.defaultdict(lambda: 0) - for _ in range(10): - for _ in range(5): - counts[sess.run(get_next)] += 1 + dataset = dataset_ops.Dataset.from_tensor_slices(components).shuffle( + 5).repeat() + get_next = self.getNext(dataset) + counts = collections.defaultdict(lambda: 0) + for _ in range(10): + for _ in range(5): + counts[self.evaluate(get_next())] += 1 for i in range(5): self.assertEqual(10, counts[i]) def testShuffleNoReshuffleEachIteration(self): - iterator = (dataset_ops.Dataset.range(10) - .shuffle(10, reshuffle_each_iteration=False) - .batch(10) - .repeat(3) - .make_one_shot_iterator()) - next_element = iterator.get_next() + dataset = dataset_ops.Dataset.range(10).shuffle( + 10, reshuffle_each_iteration=False).batch(10).repeat(3) + next_element = self.getNext(dataset) - with self.cached_session() as sess: - initial_permutation = sess.run(next_element) - self.assertAllEqual(initial_permutation, sess.run(next_element)) - self.assertAllEqual(initial_permutation, sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + initial_permutation = self.evaluate(next_element()) + self.assertAllEqual(initial_permutation, self.evaluate(next_element())) + self.assertAllEqual(initial_permutation, self.evaluate(next_element())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(next_element()) def testShuffleReshuffleEachIteration(self): - iterator = (dataset_ops.Dataset.range(10) - .shuffle(10, seed=3, reshuffle_each_iteration=True) - .batch(10) - .repeat(3) - .make_one_shot_iterator()) - next_element = iterator.get_next() + dataset = dataset_ops.Dataset.range(10).shuffle( + 10, seed=3, reshuffle_each_iteration=True).batch(10).repeat(3) + next_element = self.getNext(dataset) - with self.cached_session() as sess: - initial_permutation = list(sess.run(next_element)) - for _ in range(2): - next_permutation = list(sess.run(next_element)) - self.assertNotEqual(initial_permutation, next_permutation) - self.assertAllEqual( - sorted(initial_permutation), sorted(next_permutation)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + initial_permutation = list(self.evaluate(next_element())) + for _ in range(2): + next_permutation = list(self.evaluate(next_element())) + self.assertNotEqual(initial_permutation, next_permutation) + self.assertAllEqual(sorted(initial_permutation), sorted(next_permutation)) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(next_element()) @parameterized.named_parameters( ("ReshuffleGraphLevelSeed", True, 38, None), @@ -220,7 +187,8 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ("NoReshuffleOpLevelSeed", False, None, 42), ("NoReshuffleGraphAndOpLevelSeed", False, 38, 42), ) - def testShuffleSeed(self, reshuffle, graph_level_seed, op_level_seed): + def testSkipEagerShuffleSeed(self, reshuffle, graph_level_seed, + op_level_seed): results = [] for _ in range(2): with ops.Graph().as_default() as g: @@ -241,13 +209,15 @@ class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertAllEqual(results[0], results[1]) + # TODO(b/117581999): fails for eager mode with result[0] equal to result[1], + # debug. @parameterized.named_parameters( ("ReshuffleOneShot", True, False), ("ReshuffleInitializable", True, True), ("NoReshuffleOneShot", False, False), ("NoReshuffleInitializable", False, True), ) - def testMultipleIterators(self, reshuffle, initializable): + def testSkipEagerMultipleIterators(self, reshuffle, initializable): with ops.Graph().as_default() as g: dataset = dataset_ops.Dataset.range(100).shuffle( 10, reshuffle_each_iteration=reshuffle).repeat(3) diff --git a/tensorflow/python/data/kernel_tests/test_base.py b/tensorflow/python/data/kernel_tests/test_base.py index ca853da3f6..af8e5e8a27 100644 --- a/tensorflow/python/data/kernel_tests/test_base.py +++ b/tensorflow/python/data/kernel_tests/test_base.py @@ -68,19 +68,29 @@ class DatasetTestBase(test.TestCase): iterator = dataset.make_one_shot_iterator() return iterator.get_next - def _compareOutputToExpected(self, result_values, expected_values): + def _compareOutputToExpected(self, result_values, expected_values, + assert_items_equal): + if assert_items_equal: + # TODO(shivaniagrawal): add support for nested elements containing sparse + # tensors when needed. + self.assertItemsEqual(result_values, expected_values) + return for i in range(len(result_values)): - if sparse_tensor.is_sparse(result_values[i]): - self.assertSparseValuesEqual(result_values[i], expected_values[i]) - else: - self.assertAllEqual(result_values[i], expected_values[i]) + nest.assert_same_structure(result_values[i], expected_values[i]) + for result_value, expected_value in zip( + nest.flatten(result_values[i]), nest.flatten(expected_values[i])): + if sparse_tensor.is_sparse(result_value): + self.assertSparseValuesEqual(result_value, expected_value) + else: + self.assertAllEqual(result_value, expected_value) def assertDatasetProduces(self, dataset, expected_output=None, expected_error=None, requires_initialization=False, - num_test_iterations=2): + num_test_iterations=1, + assert_items_equal=False): """Asserts that a dataset produces the expected output / error. Args: @@ -98,6 +108,8 @@ class DatasetTestBase(test.TestCase): dataset (e.g. when it contains stateful nodes). Defaults to False. num_test_iterations: Number of times `dataset` will be iterated. Defaults to 2. + assert_items_equal: Tests expected_output has (only) the same elements + regardless of order. """ self.assertTrue( expected_error is not None or expected_output is not None, @@ -120,7 +132,7 @@ class DatasetTestBase(test.TestCase): result = [] for _ in range(len(expected_output)): result.append(self.evaluate(get_next())) - self._compareOutputToExpected(result, expected_output) + self._compareOutputToExpected(result, expected_output, assert_items_equal) with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next()) with self.assertRaises(errors.OutOfRangeError): diff --git a/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py b/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py index 9d76387a34..c86765addc 100644 --- a/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py @@ -21,94 +21,80 @@ import numpy as np from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors -from tensorflow.python.ops import array_ops +from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class ZipDatasetTest(test_base.DatasetTestBase): def testZipDataset(self): - component_placeholders = [ - array_ops.placeholder(dtypes.int64), - array_ops.placeholder(dtypes.int64), - array_ops.placeholder(dtypes.float64) - ] - - datasets = tuple([ - dataset_ops.Dataset.from_tensor_slices(component_placeholder) - for component_placeholder in component_placeholders - ]) - zipped = dataset_ops.Dataset.zip(datasets) - - iterator = zipped.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - with self.cached_session() as sess: - equal_length_components = [ - np.tile(np.array([[1], [2], [3], [4]]), 20), - np.tile(np.array([[12], [13], [14], [15]]), 22), - np.array([37.0, 38.0, 39.0, 40.0]) - ] - sess.run(init_op, feed_dict={ph: value for ph, value in zip( - component_placeholders, equal_length_components)}) - for i in range(4): - results = sess.run(get_next) - for component, result_component in zip( - equal_length_components, results): - self.assertAllEqual(component[i], result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + def dataset_fn(components): + datasets = tuple([ + dataset_ops.Dataset.from_tensor_slices(component) + for component in components + ]) + return dataset_ops.Dataset.zip(datasets) + + equal_length_components = [ + np.tile(np.array([[1], [2], [3], [4]]), 20), + np.tile(np.array([[12], [13], [14], [15]]), 22), + np.array([37.0, 38.0, 39.0, 40.0]) + ] - variable_length_components = [[1, 2, 3, 4], [1, 2, 3, 4, 5], [1.0, 2.0]] - sess.run(init_op, feed_dict={ph: value for ph, value in zip( - component_placeholders, variable_length_components)}) - for i in range(2): - results = sess.run(get_next) - for component, result_component in zip( - variable_length_components, results): - self.assertAllEqual(component[i], result_component) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + get_next = self.getNext(dataset_fn(equal_length_components)) + for i in range(4): + results = self.evaluate(get_next()) + for component, result_component in zip(equal_length_components, results): + self.assertAllEqual(component[i], result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + variable_length_components = [[1, 2, 3, 4], [1, 2, 3, 4, 5], [1.0, 2.0]] + get_next = self.getNext(dataset_fn(variable_length_components)) + for i in range(2): + results = self.evaluate(get_next()) + for component, result_component in zip(variable_length_components, + results): + self.assertAllEqual(component[i], result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testNestedZipDataset(self): - component_placeholders = [ - array_ops.placeholder(dtypes.int64, shape=[4, 20]), - array_ops.placeholder(dtypes.int64, shape=[4, 22]), - array_ops.placeholder(dtypes.float64, shape=[4]) - ] + equal_length_components = [ + np.tile(np.array([[1], [2], [3], [4]]), 20), + np.tile(np.array([[12], [13], [14], [15]]), 22), + np.array([37.0, 38.0, 39.0, 40.0]) + ] datasets = [ - dataset_ops.Dataset.from_tensor_slices(component_placeholder) - for component_placeholder in component_placeholders + dataset_ops.Dataset.from_tensor_slices(component) + for component in equal_length_components ] - zipped = dataset_ops.Dataset.zip((datasets[0], (datasets[1], datasets[2]))) - - iterator = zipped.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - self.assertEqual([20], get_next[0].shape) - self.assertEqual([22], get_next[1][0].shape) - self.assertEqual([], get_next[1][1].shape) - - with self.cached_session() as sess: - equal_length_components = [ - np.tile(np.array([[1], [2], [3], [4]]), 20), - np.tile(np.array([[12], [13], [14], [15]]), 22), - np.array([37.0, 38.0, 39.0, 40.0]) - ] - sess.run(init_op, feed_dict={ph: value for ph, value in zip( - component_placeholders, equal_length_components)}) - for i in range(4): - result1, (result2, result3) = sess.run(get_next) - self.assertAllEqual(equal_length_components[0][i], result1) - self.assertAllEqual(equal_length_components[1][i], result2) - self.assertAllEqual(equal_length_components[2][i], result3) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.zip((datasets[0], (datasets[1], datasets[2]))) + + self.assertEqual( + dataset.output_shapes, + (tensor_shape.TensorShape([20]), + (tensor_shape.TensorShape([22]), tensor_shape.TensorShape([])))) + + get_next = self.getNext(dataset) + for i in range(4): + result1, (result2, result3) = self.evaluate(get_next()) + self.assertAllEqual(equal_length_components[0][i], result1) + self.assertAllEqual(equal_length_components[1][i], result2) + self.assertAllEqual(equal_length_components[2][i], result3) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) if __name__ == "__main__": -- GitLab From 1d8c26069ce359be3d36f0a323993e919c0f6d73 Mon Sep 17 00:00:00 2001 From: Tamara Norman Date: Mon, 26 Nov 2018 10:43:45 -0800 Subject: [PATCH 306/672] Fix error message and the checks for tf.get_variable applying the initializer to get the default value PiperOrigin-RevId: 222849262 --- tensorflow/python/ops/variable_scope.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 1b122ceffd..cf33c61b82 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -909,18 +909,20 @@ class _VariableStore(object): # Instantiate initializer if provided initializer is a type object. if isinstance(initializer, type(init_ops.Initializer)): initializer = initializer(dtype=dtype) - if shape and shape.is_fully_defined(): + spec = tf_inspect.getargspec(initializer) + if shape is not None and shape.is_fully_defined(): init_val = lambda: initializer( # pylint: disable=g-long-lambda shape.as_list(), dtype=dtype, partition_info=partition_info) - elif not tf_inspect.getargspec(initializer).args: + variable_dtype = dtype.base_dtype + elif len(spec.args) == len(spec.defaults or []): init_val = initializer + variable_dtype = None else: - raise ValueError("You can only pass an initializer function that " - "expects no arguments to its callable when the " - "shape is not fully defined. The given initializer " - "function expects the following args %s" % - tf_inspect.getargspec(initializer).args) - variable_dtype = dtype.base_dtype + raise ValueError("The initializer passed is not valid. It should " + "be a callable with no arguments and the " + "shape should not be provided or an instance of " + "`tf.keras.initializers.*' and `shape` should be " + "fully defined.") # Create the variable. if use_resource is None: -- GitLab From a52d67777b0ac6f8f56ba17386ff7bafe1c2e4e4 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 10:46:58 -0800 Subject: [PATCH 307/672] update/remove symbols PiperOrigin-RevId: 222849751 --- tensorflow/python/framework/ops.py | 2 +- tensorflow/python/ops/partitioned_variables.py | 2 +- tensorflow/python/ops/random_ops.py | 4 +++- tensorflow/python/ops/sparse_ops.py | 2 +- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 16 ---------------- tensorflow/tools/compatibility/renames_v2.py | 4 ++++ 6 files changed, 10 insertions(+), 20 deletions(-) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index c465d2bc10..b8187ab20c 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -5557,7 +5557,7 @@ def eager_run(main=None, argv=None): app.run(main, argv) -@tf_export("reset_default_graph") +@tf_export(v1=["reset_default_graph"]) def reset_default_graph(): """Clears the default graph stack and resets the global default graph. diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 816317da10..66153e33f2 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -68,7 +68,7 @@ __all__ = [ ] -@tf_export("variable_axis_size_partitioner") +@tf_export(v1=["variable_axis_size_partitioner"]) def variable_axis_size_partitioner( max_shard_bytes, axis=0, bytes_per_string_element=16, max_shards=None): """Get a partitioner for VariableScope to keep shards below `max_shard_bytes`. diff --git a/tensorflow/python/ops/random_ops.py b/tensorflow/python/ops/random_ops.py index c893ef011b..f2df87cf2d 100644 --- a/tensorflow/python/ops/random_ops.py +++ b/tensorflow/python/ops/random_ops.py @@ -138,7 +138,9 @@ def parameterized_truncated_normal(shape, return rnd -@tf_export("random.truncated_normal", "truncated_normal") +@tf_export("random.truncated_normal", + v1=["random.truncated_normal", "truncated_normal"]) +@deprecation.deprecated_endpoints("truncated_normal") def truncated_normal(shape, mean=0.0, stddev=1.0, diff --git a/tensorflow/python/ops/sparse_ops.py b/tensorflow/python/ops/sparse_ops.py index e8a0f31d9d..91baa6f7b8 100644 --- a/tensorflow/python/ops/sparse_ops.py +++ b/tensorflow/python/ops/sparse_ops.py @@ -939,7 +939,7 @@ def sparse_slice(sp_input, start, size, name=None): output_shape) -@tf_export("sparse_to_dense") +@tf_export(v1=["sparse_to_dense"]) @deprecation.deprecated( None, "Create a `tf.sparse.SparseTensor` and use `tf.sparse.to_dense` instead.") diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 99751504ae..6afe44a03f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -928,10 +928,6 @@ tf_module { name: "required_space_to_batch_paddings" argspec: "args=[\'input_shape\', \'block_shape\', \'base_paddings\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } - member_method { - name: "reset_default_graph" - argspec: "args=[], varargs=None, keywords=None, defaults=None" - } member_method { name: "reshape" argspec: "args=[\'tensor\', \'shape\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " @@ -1036,10 +1032,6 @@ tf_module { name: "sparse_concat" argspec: "args=[\'axis\', \'sp_inputs\', \'expand_nonconcat_dim\', \'concat_dim\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\', \'None\'], " } - member_method { - name: "sparse_to_dense" - argspec: "args=[\'sparse_indices\', \'output_shape\', \'sparse_values\', \'default_value\', \'validate_indices\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'True\', \'None\'], " - } member_method { name: "split" argspec: "args=[\'value\', \'num_or_size_splits\', \'axis\', \'num\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'None\', \'split\'], " @@ -1108,10 +1100,6 @@ tf_module { name: "truediv" argspec: "args=[\'x\', \'y\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "truncated_normal" - argspec: "args=[\'shape\', \'mean\', \'stddev\', \'dtype\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\'0.0\', \'1.0\', \"\", \'None\', \'None\'], " - } member_method { name: "truncatediv" argspec: "args=[\'x\', \'y\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " @@ -1140,10 +1128,6 @@ tf_module { name: "unstack" argspec: "args=[\'value\', \'num\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'0\', \'unstack\'], " } - member_method { - name: "variable_axis_size_partitioner" - argspec: "args=[\'max_shard_bytes\', \'axis\', \'bytes_per_string_element\', \'max_shards\'], varargs=None, keywords=None, defaults=[\'0\', \'16\', \'None\'], " - } member_method { name: "variable_creator_scope" argspec: "args=[\'variable_creator\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index dc47796a7c..c22b09df48 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -392,6 +392,7 @@ renames = { 'tf.reduce_join': 'tf.strings.reduce_join', 'tf.regex_replace': 'tf.strings.regex_replace', 'tf.report_uninitialized_variables': 'tf.compat.v1.report_uninitialized_variables', + 'tf.reset_default_graph': 'tf.compat.v1.reset_default_graph', 'tf.resource_loader.get_data_files_path': 'tf.compat.v1.resource_loader.get_data_files_path', 'tf.resource_loader.get_path_to_datafile': 'tf.compat.v1.resource_loader.get_path_to_datafile', 'tf.resource_loader.get_root_dir_with_all_resources': 'tf.compat.v1.resource_loader.get_root_dir_with_all_resources', @@ -499,6 +500,7 @@ renames = { 'tf.sparse_split': 'tf.compat.v1.sparse_split', 'tf.sparse_tensor_dense_matmul': 'tf.sparse.sparse_dense_matmul', 'tf.sparse_tensor_to_dense': 'tf.sparse.to_dense', + 'tf.sparse_to_dense': 'tf.compat.v1.sparse_to_dense', 'tf.sparse_to_indicator': 'tf.sparse.to_indicator', 'tf.sparse_transpose': 'tf.sparse.transpose', 'tf.spectral.dct': 'tf.signal.dct', @@ -594,6 +596,7 @@ renames = { 'tf.train.update_checkpoint_state': 'tf.compat.v1.train.update_checkpoint_state', 'tf.train.write_graph': 'tf.io.write_graph', 'tf.trainable_variables': 'tf.compat.v1.trainable_variables', + 'tf.truncated_normal': 'tf.random.truncated_normal', 'tf.uniform_unit_scaling_initializer': 'tf.initializers.uniform_unit_scaling', 'tf.unsorted_segment_max': 'tf.math.unsorted_segment_max', 'tf.unsorted_segment_mean': 'tf.math.unsorted_segment_mean', @@ -601,6 +604,7 @@ renames = { 'tf.unsorted_segment_prod': 'tf.math.unsorted_segment_prod', 'tf.unsorted_segment_sqrt_n': 'tf.math.unsorted_segment_sqrt_n', 'tf.unsorted_segment_sum': 'tf.math.unsorted_segment_sum', + 'tf.variable_axis_size_partitioner': 'tf.compat.v1.variable_axis_size_partitioner', 'tf.variable_op_scope': 'tf.compat.v1.variable_op_scope', 'tf.variable_scope': 'tf.compat.v1.variable_scope', 'tf.variables_initializer': 'tf.compat.v1.variables_initializer', -- GitLab From a70c22df20ffa56602d01be09187df76cb377f12 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Mon, 26 Nov 2018 10:48:30 -0800 Subject: [PATCH 308/672] [tf.data] Fix threadpool names. The `ThreadPool` class adds the `tf_` prefix to the threadpool name in its constructor. PiperOrigin-RevId: 222850033 --- .../core/kernels/data/experimental/threadpool_dataset_op.cc | 3 +-- tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc b/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc index 139642d4a3..341ce08a57 100644 --- a/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc +++ b/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc @@ -359,8 +359,7 @@ class PrivateThreadPoolDatasetOp : public UnaryDatasetOpKernel { input_(input), num_threads_(num_threads) { thread_pool_ = MakeUnique( - ctx->env(), ThreadOptions{}, "tf_data_private_threadpool", - num_threads, + ctx->env(), ThreadOptions{}, "data_private_threadpool", num_threads, /*low_latency_hint=*/false); input_->Ref(); } diff --git a/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc b/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc index 985e197a99..23e6adc57a 100644 --- a/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc +++ b/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc @@ -1241,7 +1241,7 @@ class ParallelInterleaveDatasetV2Op : public UnaryDatasetOpKernel { element_in_use_(params.dataset->cycle_length_, false), thread_pool_(new thread::ThreadPool( Env::Default(), ThreadOptions(), - "tf_data_parallel_interleave_worker_pool", + "data_parallel_interleave_worker_pool", dataset()->cycle_length_ /* num_threads */, false /* low_latency_hint */)) { std::vector components = -- GitLab From 556b91e88fce84df4aca3302dc28c309a930546c Mon Sep 17 00:00:00 2001 From: James Keeling Date: Mon, 26 Nov 2018 10:50:59 -0800 Subject: [PATCH 309/672] Split conv GPU code into multiple files This file was a bottleneck during compilation, often taking many minutes to compile. PiperOrigin-RevId: 222850419 --- tensorflow/core/kernels/BUILD | 10 ++- tensorflow/core/kernels/conv_2d.h | 2 +- .../{conv_2d_gpu.cu.cc => conv_2d_gpu.h} | 86 ++----------------- .../core/kernels/conv_2d_gpu_double.cu.cc | 50 +++++++++++ .../core/kernels/conv_2d_gpu_float.cu.cc | 63 ++++++++++++++ .../core/kernels/conv_2d_gpu_half.cu.cc | 57 ++++++++++++ tensorflow/core/kernels/conv_2d_gpu_int.cu.cc | 38 ++++++++ .../core/kernels/conv_2d_gpu_uint16.cu.cc | 38 ++++++++ .../core/kernels/conv_2d_gpu_uint32.cu.cc | 38 ++++++++ .../core/kernels/conv_2d_gpu_uint64.cu.cc | 38 ++++++++ .../core/kernels/conv_2d_gpu_uint8.cu.cc | 38 ++++++++ 11 files changed, 377 insertions(+), 81 deletions(-) rename tensorflow/core/kernels/{conv_2d_gpu.cu.cc => conv_2d_gpu.h} (91%) create mode 100644 tensorflow/core/kernels/conv_2d_gpu_double.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_float.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_half.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_int.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_uint16.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_uint32.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_uint64.cu.cc create mode 100644 tensorflow/core/kernels/conv_2d_gpu_uint8.cu.cc diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index ae76034b0b..1efce939a3 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -199,8 +199,16 @@ tf_kernel_library( name = "conv_2d", hdrs = ["conv_2d.h"], gpu_srcs = [ - "conv_2d_gpu.cu.cc", "conv_2d.h", + "conv_2d_gpu.h", + "conv_2d_gpu_double.cu.cc", + "conv_2d_gpu_float.cu.cc", + "conv_2d_gpu_half.cu.cc", + "conv_2d_gpu_int.cu.cc", + "conv_2d_gpu_uint16.cu.cc", + "conv_2d_gpu_uint32.cu.cc", + "conv_2d_gpu_uint64.cu.cc", + "conv_2d_gpu_uint8.cu.cc", ], deps = [ ":eigen_helpers", diff --git a/tensorflow/core/kernels/conv_2d.h b/tensorflow/core/kernels/conv_2d.h index a6964b1aac..1bac2a18c3 100644 --- a/tensorflow/core/kernels/conv_2d.h +++ b/tensorflow/core/kernels/conv_2d.h @@ -162,7 +162,7 @@ struct TransformFilter { merged_dims[1] = in.dimension(NDIMS - 2); // input filters merged_dims[2] = in.dimension(NDIMS - 1); // output filters - CHECK(dst_filter_format == FORMAT_OIHW) + DCHECK(dst_filter_format == FORMAT_OIHW) << "Unsupported destination filter format: " << ToString(dst_filter_format); // Source filter format is FORMAT_HWIO and spatial dimensions HW are merged diff --git a/tensorflow/core/kernels/conv_2d_gpu.cu.cc b/tensorflow/core/kernels/conv_2d_gpu.h similarity index 91% rename from tensorflow/core/kernels/conv_2d_gpu.cu.cc rename to tensorflow/core/kernels/conv_2d_gpu.h index c6adf9ebff..8d11757428 100644 --- a/tensorflow/core/kernels/conv_2d_gpu.cu.cc +++ b/tensorflow/core/kernels/conv_2d_gpu.h @@ -13,6 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +#ifndef TENSORFLOW_CORE_KERNELS_CONV_2D_GPU_H_ +#define TENSORFLOW_CORE_KERNELS_CONV_2D_GPU_H_ + #if GOOGLE_CUDA #define EIGEN_USE_GPU @@ -34,7 +37,7 @@ namespace tensorflow { typedef Eigen::GpuDevice GPUDevice; namespace functor { -namespace { + template struct maybe_conj { __device__ static __inline__ T run(T x) { @@ -75,8 +78,6 @@ struct maybe_conj { } }; -} // namespace - // TODO(mjanusz): Move this to a shared util file. // A simple array that contains data that can be passed between CPU and GPU. template @@ -433,7 +434,7 @@ struct TransformFilter { combined_dims[2] = in.dimension(NDIMS - 1); // output filters CudaLaunchConfig config = GetCudaLaunchConfig(out.size(), d); - DCHECK(dst_filter_format == FORMAT_OIHW) + CHECK(dst_filter_format == FORMAT_OIHW) << "Unsupported output layout: " << ToString(dst_filter_format); ShuffleInTensor3Simple @@ -998,82 +999,9 @@ struct NCHWToNHWC { } }; -template struct ShuffleAndReverse; -template struct ShuffleAndReverse; - -template struct ShuffleAndReverse; -template struct ShuffleAndReverse; - -template struct TransformDepth; -template struct TransformDepth; - -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; -template struct SwapDimension1And2InTensor3; - -template struct SwapDimension0And2InTensor3; -template struct SwapDimension0And2InTensor3; -template struct SwapDimension0And2InTensor3; -template struct SwapDimension0And2InTensor3; -template struct SwapDimension0And2InTensor3; -template struct SwapDimension0And2InTensor3; -template struct SwapDimension0And2InTensor3; - -// For 2d ops. -template struct TransformFilter; -template struct TransformFilter; -template struct TransformFilter; - -template struct ReverseTransformFilter; -template struct ReverseTransformFilter; -template struct ReverseTransformFilter; - -template struct NHWCToNCHW; -template struct NHWCToNCHW; -template struct NHWCToNCHW; - -template struct NCHWToNHWC; -template struct NCHWToNHWC; -template struct NCHWToNHWC; - -template struct PadInput; -template struct PadInput; -template struct PadInput; -template struct PadInput; - -// For 3d ops. -template struct TransformFilter; -template struct TransformFilter; -template struct TransformFilter; - -template struct ReverseTransformFilter; -template struct ReverseTransformFilter; -template struct ReverseTransformFilter; - -template struct NHWCToNCHW; -template struct NHWCToNCHW; -template struct NHWCToNCHW; - -template struct NCHWToNHWC; -template struct NCHWToNHWC; -template struct NCHWToNHWC; - -template struct PadInput; -template struct PadInput; -template struct PadInput; - } // namespace functor } // namespace tensorflow #endif // GOOGLE_CUDA + +#endif // TENSORFLOW_CORE_KERNELS_CONV_2D_GPU_H_ diff --git a/tensorflow/core/kernels/conv_2d_gpu_double.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_double.cu.cc new file mode 100644 index 0000000000..353d6d1130 --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_double.cu.cc @@ -0,0 +1,50 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct SwapDimension1And2InTensor3; + +template struct SwapDimension0And2InTensor3; + +// For 2d ops. +template struct TransformFilter; +template struct ReverseTransformFilter; +template struct NHWCToNCHW; +template struct NCHWToNHWC; +template struct PadInput; + +// For 3d ops. +template struct TransformFilter; +template struct ReverseTransformFilter; +template struct NHWCToNCHW; +template struct NCHWToNHWC; +template struct PadInput; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_float.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_float.cu.cc new file mode 100644 index 0000000000..21030dd12b --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_float.cu.cc @@ -0,0 +1,63 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct ShuffleAndReverse; +template struct ShuffleAndReverse; + +template struct TransformDepth; + +template struct SwapDimension1And2InTensor3; +template struct SwapDimension1And2InTensor3; + +template struct SwapDimension0And2InTensor3; +template struct SwapDimension0And2InTensor3; + +// For 2d ops. +template struct TransformFilter; +template struct ReverseTransformFilter; +template struct NHWCToNCHW; +template struct NCHWToNHWC; +template struct PadInput; + +// For 3d ops. +template struct TransformFilter; +template struct ReverseTransformFilter; +template struct NHWCToNCHW; +template struct NCHWToNHWC; +template struct PadInput; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_half.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_half.cu.cc new file mode 100644 index 0000000000..948308651f --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_half.cu.cc @@ -0,0 +1,57 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct ShuffleAndReverse; +template struct ShuffleAndReverse; + +template struct TransformDepth; + +template struct SwapDimension1And2InTensor3; + +// For 2d ops. +template struct TransformFilter; +template struct ReverseTransformFilter; +template struct NHWCToNCHW; +template struct NCHWToNHWC; +template struct PadInput; + +// For 3d ops. +template struct TransformFilter; +template struct ReverseTransformFilter; +template struct NHWCToNCHW; +template struct NCHWToNHWC; +template struct PadInput; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_int.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_int.cu.cc new file mode 100644 index 0000000000..901ce3e55d --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_int.cu.cc @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +// For 2d ops. +template struct PadInput; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_uint16.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_uint16.cu.cc new file mode 100644 index 0000000000..e47532a983 --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_uint16.cu.cc @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct SwapDimension1And2InTensor3; +template struct SwapDimension0And2InTensor3; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_uint32.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_uint32.cu.cc new file mode 100644 index 0000000000..56cd5dd218 --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_uint32.cu.cc @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct SwapDimension1And2InTensor3; +template struct SwapDimension0And2InTensor3; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_uint64.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_uint64.cu.cc new file mode 100644 index 0000000000..045a664e96 --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_uint64.cu.cc @@ -0,0 +1,38 @@ +/* Copyright 2015 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct SwapDimension1And2InTensor3; +template struct SwapDimension0And2InTensor3; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/conv_2d_gpu_uint8.cu.cc b/tensorflow/core/kernels/conv_2d_gpu_uint8.cu.cc new file mode 100644 index 0000000000..215417860a --- /dev/null +++ b/tensorflow/core/kernels/conv_2d_gpu_uint8.cu.cc @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include +#include +#include +#include + +#include "tensorflow/core/kernels/conv_2d.h" +#include "tensorflow/core/kernels/conv_2d_gpu.h" + +namespace tensorflow { + +namespace functor { + +template struct SwapDimension1And2InTensor3; +template struct SwapDimension0And2InTensor3; + +} // namespace functor +} // namespace tensorflow + +#endif // GOOGLE_CUDA -- GitLab From bb425754adacc784c2ad50ed94307eaa03626b41 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Mon, 26 Nov 2018 10:57:38 -0800 Subject: [PATCH 310/672] [tf.data] Fix memory leak in `tf.data.experimental.unbatch()`. Remember to `Unref()` the input dataset when the `UnbatchDatasetOp::Dataset` is destroyed. Fixes #23924. PiperOrigin-RevId: 222851427 --- tensorflow/core/kernels/data/unbatch_dataset_op.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/core/kernels/data/unbatch_dataset_op.cc b/tensorflow/core/kernels/data/unbatch_dataset_op.cc index b32ab8ba4f..af7f676370 100644 --- a/tensorflow/core/kernels/data/unbatch_dataset_op.cc +++ b/tensorflow/core/kernels/data/unbatch_dataset_op.cc @@ -54,6 +54,8 @@ class UnbatchDatasetOp : public UnaryDatasetOpKernel { } } + ~Dataset() override { input_->Unref(); } + std::unique_ptr MakeIteratorInternal( const string& prefix) const override { return std::unique_ptr( -- GitLab From 59d14c5d418849d7d6a8659c00677be27fd7f3cb Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Mon, 26 Nov 2018 11:13:09 -0800 Subject: [PATCH 311/672] Don't run done callback till all handles are scheduled, and the code breaks out of the loop. PiperOrigin-RevId: 222854381 --- tensorflow/core/kernels/partitioned_function_ops.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/kernels/partitioned_function_ops.cc b/tensorflow/core/kernels/partitioned_function_ops.cc index 89b74495c7..6c90ffd75e 100644 --- a/tensorflow/core/kernels/partitioned_function_ops.cc +++ b/tensorflow/core/kernels/partitioned_function_ops.cc @@ -453,7 +453,7 @@ class PartitionedCallOp : public AsyncOpKernel { }, rendez, std::move(done), std::placeholders::_1); auto* refcounted_done = new ReffedStatusCallback(std::move(callback)); - for (int i = 1; i < handles->size(); ++i) { + for (int i = 0; i < handles->size(); ++i) { refcounted_done->Ref(); } @@ -507,6 +507,7 @@ class PartitionedCallOp : public AsyncOpKernel { }); } } + refcounted_done->Unref(); } string UniquifyFunctionName(const FunctionLibraryDefinition* function_library, -- GitLab From 32fb5465740ee99d6989c603643788b08a8a0461 Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Mon, 26 Nov 2018 11:16:46 -0800 Subject: [PATCH 312/672] Enable generators in `model.predict` to yield tuples of size 1 (just the input data). PiperOrigin-RevId: 222855043 --- tensorflow/python/keras/BUILD | 1 + .../python/keras/engine/training_generator.py | 4 +- .../keras/engine/training_generator_test.py | 388 ++++++++++-------- 3 files changed, 211 insertions(+), 182 deletions(-) diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index fa1cad2359..bac961bb9d 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -746,6 +746,7 @@ py_test( ":keras", "//tensorflow/python:client_testlib", "//third_party/py/numpy", + "@absl_py//absl/testing:parameterized", ], ) diff --git a/tensorflow/python/keras/engine/training_generator.py b/tensorflow/python/keras/engine/training_generator.py index 988bed5170..e7310a7bb9 100644 --- a/tensorflow/python/keras/engine/training_generator.py +++ b/tensorflow/python/keras/engine/training_generator.py @@ -388,7 +388,9 @@ def predict_generator(model, if isinstance(generator_output, tuple): # Compatibility with the generators # used for training. - if len(generator_output) == 2: + if len(generator_output) == 1: + x = generator_output[0] + elif len(generator_output) == 2: x, _ = generator_output elif len(generator_output) == 3: x, _, _ = generator_output diff --git a/tensorflow/python/keras/engine/training_generator_test.py b/tensorflow/python/keras/engine/training_generator_test.py index 88e8943424..42cfa3bc70 100644 --- a/tensorflow/python/keras/engine/training_generator_test.py +++ b/tensorflow/python/keras/engine/training_generator_test.py @@ -21,220 +21,269 @@ from __future__ import print_function import os import unittest +from absl.testing import parameterized import numpy as np from tensorflow.python import keras from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.keras import metrics as metrics_module +from tensorflow.python.keras import testing_utils from tensorflow.python.platform import test from tensorflow.python.training.rmsprop import RMSPropOptimizer -class TestGeneratorMethods(test.TestCase): +def custom_generator(mode=2): + batch_size = 10 + num_samples = 50 + arr_data = np.random.random((num_samples, 2)) + arr_labels = np.random.random((num_samples, 4)) + arr_weights = np.random.random((num_samples,)) + i = 0 + while True: + batch_index = i * batch_size % num_samples + i += 1 + start = batch_index + end = start + batch_size + x = arr_data[start: end] + y = arr_labels[start: end] + w = arr_weights[start: end] + if mode == 1: + yield x + elif mode == 2: + yield x, y + else: + yield x, y, w + + +@tf_test_util.run_all_in_graph_and_eager_modes +class TestGeneratorMethods(test.TestCase, parameterized.TestCase): @unittest.skipIf( os.name == 'nt', 'use_multiprocessing=True does not work on windows properly.') - def test_generator_methods(self): - arr_data = np.random.random((50, 2)) - arr_labels = np.random.random((50,)) + @parameterized.parameters('sequential', 'functional') + def test_fit_generator_method(self, model_type): + if model_type == 'sequential': + model = testing_utils.get_small_sequential_mlp( + num_hidden=3, num_classes=4, input_dim=2) + else: + model = testing_utils.get_small_functional_mlp( + num_hidden=3, num_classes=4, input_dim=2) + model.compile( + loss='mse', + optimizer='sgd', + metrics=['mae', metrics_module.CategoricalAccuracy()]) + + model.fit_generator(custom_generator(), + steps_per_epoch=5, + epochs=1, + verbose=1, + max_queue_size=10, + workers=4, + use_multiprocessing=True) + model.fit_generator(custom_generator(), + steps_per_epoch=5, + epochs=1, + verbose=1, + max_queue_size=10, + use_multiprocessing=False) + model.fit_generator(custom_generator(), + steps_per_epoch=5, + epochs=1, + verbose=1, + max_queue_size=10, + use_multiprocessing=False, + validation_data=custom_generator(), + validation_steps=10) + model.fit_generator(custom_generator(), + steps_per_epoch=5, + validation_data=custom_generator(), + validation_steps=1, + workers=0) - def custom_generator(): - batch_size = 10 - num_samples = 50 - while True: - batch_index = np.random.randint(0, num_samples - batch_size) - start = batch_index - end = start + batch_size - x = arr_data[start: end] - y = arr_labels[start: end] - yield x, y - - with self.cached_session(): - x = keras.Input((2,)) - y = keras.layers.Dense(1)(x) - fn_model = keras.models.Model(x, y) - fn_model.compile( - loss='mse', - optimizer='sgd', - metrics=['mae', metrics_module.CategoricalAccuracy()]) - - seq_model = keras.models.Sequential() - seq_model.add(keras.layers.Dense(1, input_shape=(2,))) - seq_model.compile(loss='mse', optimizer='sgd') - - for model in [fn_model, seq_model]: - model.fit_generator(custom_generator(), - steps_per_epoch=5, - epochs=1, - verbose=1, + @unittest.skipIf( + os.name == 'nt', + 'use_multiprocessing=True does not work on windows properly.') + @parameterized.parameters('sequential', 'functional') + def test_evaluate_generator_method(self, model_type): + if model_type == 'sequential': + model = testing_utils.get_small_sequential_mlp( + num_hidden=3, num_classes=4, input_dim=2) + else: + model = testing_utils.get_small_functional_mlp( + num_hidden=3, num_classes=4, input_dim=2) + model.compile( + loss='mse', + optimizer='sgd', + metrics=['mae', metrics_module.CategoricalAccuracy()]) + model.summary() + + model.evaluate_generator(custom_generator(), + steps=5, + max_queue_size=10, + workers=2, + verbose=1, + use_multiprocessing=True) + model.evaluate_generator(custom_generator(), + steps=5, + max_queue_size=10, + use_multiprocessing=False) + model.evaluate_generator(custom_generator(), + steps=5, + max_queue_size=10, + use_multiprocessing=False, + workers=0) + + @unittest.skipIf( + os.name == 'nt', + 'use_multiprocessing=True does not work on windows properly.') + @parameterized.parameters('sequential', 'functional') + def test_predict_generator_method(self, model_type): + if model_type == 'sequential': + model = testing_utils.get_small_sequential_mlp( + num_hidden=3, num_classes=4, input_dim=2) + else: + model = testing_utils.get_small_functional_mlp( + num_hidden=3, num_classes=4, input_dim=2) + model.compile( + loss='mse', + optimizer='sgd', + metrics=['mae', metrics_module.CategoricalAccuracy()]) + + model.predict_generator(custom_generator(), + steps=5, max_queue_size=10, - workers=4, + workers=2, use_multiprocessing=True) - model.fit_generator(custom_generator(), - steps_per_epoch=5, - epochs=1, - verbose=1, + model.predict_generator(custom_generator(), + steps=5, max_queue_size=10, use_multiprocessing=False) - model.fit_generator(custom_generator(), - steps_per_epoch=5, - epochs=1, - verbose=1, + model.predict_generator(custom_generator(), + steps=5, + max_queue_size=10, + workers=0) + # Test generator with just inputs (no targets) + model.predict_generator(custom_generator(mode=1), + steps=5, + max_queue_size=10, + workers=2, + use_multiprocessing=True) + model.predict_generator(custom_generator(mode=1), + steps=5, + max_queue_size=10, + use_multiprocessing=False) + model.predict_generator(custom_generator(mode=1), + steps=5, max_queue_size=10, - use_multiprocessing=False, - validation_data=custom_generator(), - validation_steps=10) - model.fit_generator(custom_generator(), - steps_per_epoch=5, - validation_data=custom_generator(), - validation_steps=1, workers=0) - model.predict_generator(custom_generator(), - steps=5, - max_queue_size=10, - workers=2, - use_multiprocessing=True) - model.predict_generator(custom_generator(), - steps=5, - max_queue_size=10, - use_multiprocessing=False) - model.predict_generator(custom_generator(), - steps=5, - max_queue_size=10, - workers=0) - model.evaluate_generator(custom_generator(), - steps=5, - max_queue_size=10, - workers=2, - verbose=1, - use_multiprocessing=True) - model.evaluate_generator(custom_generator(), - steps=5, - max_queue_size=10, - use_multiprocessing=False) - model.evaluate_generator(custom_generator(), - steps=5, - max_queue_size=10, - use_multiprocessing=False, - workers=0) def test_generator_methods_with_sample_weights(self): - arr_data = np.random.random((50, 2)) - arr_labels = np.random.random((50,)) - arr_sample_weights = np.random.random((50,)) + model = keras.models.Sequential() + model.add(keras.layers.Dense(4, input_shape=(2,))) + model.compile( + loss='mse', + optimizer='sgd', + metrics=['mae', metrics_module.CategoricalAccuracy()]) + + model.fit_generator(custom_generator(mode=3), + steps_per_epoch=5, + epochs=1, + verbose=1, + max_queue_size=10, + use_multiprocessing=False) + model.fit_generator(custom_generator(mode=3), + steps_per_epoch=5, + epochs=1, + verbose=1, + max_queue_size=10, + use_multiprocessing=False, + validation_data=custom_generator(mode=3), + validation_steps=10) + model.predict_generator(custom_generator(mode=3), + steps=5, + max_queue_size=10, + use_multiprocessing=False) + model.evaluate_generator(custom_generator(mode=3), + steps=5, + max_queue_size=10, + use_multiprocessing=False) - def custom_generator(): - batch_size = 10 - num_samples = 50 - while True: - batch_index = np.random.randint(0, num_samples - batch_size) - start = batch_index - end = start + batch_size - x = arr_data[start: end] - y = arr_labels[start: end] - w = arr_sample_weights[start: end] - yield x, y, w - - with self.cached_session(): - model = keras.models.Sequential() - model.add(keras.layers.Dense(1, input_shape=(2,))) - model.compile( - loss='mse', - optimizer='sgd', - metrics=['mae', metrics_module.CategoricalAccuracy()]) + def test_generator_methods_invalid_use_case(self): - model.fit_generator(custom_generator(), + def invalid_generator(): + while 1: + yield 0 + + model = keras.models.Sequential() + model.add(keras.layers.Dense(4, input_shape=(2,))) + model.compile(loss='mse', optimizer='sgd') + + with self.assertRaises(ValueError): + model.fit_generator(invalid_generator(), steps_per_epoch=5, epochs=1, verbose=1, max_queue_size=10, use_multiprocessing=False) + with self.assertRaises(ValueError): model.fit_generator(custom_generator(), steps_per_epoch=5, epochs=1, verbose=1, max_queue_size=10, use_multiprocessing=False, - validation_data=custom_generator(), + validation_data=invalid_generator(), validation_steps=10) - model.predict_generator(custom_generator(), + with self.assertRaises(AttributeError): + model.predict_generator(invalid_generator(), steps=5, max_queue_size=10, use_multiprocessing=False) - model.evaluate_generator(custom_generator(), + with self.assertRaises(ValueError): + model.evaluate_generator(invalid_generator(), steps=5, max_queue_size=10, use_multiprocessing=False) - def test_generator_methods_invalid_use_case(self): + def test_generator_input_to_fit_eval_predict(self): + val_data = np.ones([10, 10], np.float32), np.ones([10, 1], np.float32) - def custom_generator(): - while 1: - yield 0 + def ones_generator(): + while True: + yield np.ones([10, 10], np.float32), np.ones([10, 1], np.float32) - with self.cached_session(): - model = keras.models.Sequential() - model.add(keras.layers.Dense(1, input_shape=(2,))) - model.compile(loss='mse', optimizer='sgd') + inputs = keras.layers.Input(shape=(10,)) + x = keras.layers.Dense(10, activation='relu')(inputs) + outputs = keras.layers.Dense(1, activation='sigmoid')(x) + model = keras.Model(inputs, outputs) + + model.compile(RMSPropOptimizer(0.001), 'binary_crossentropy') + model.fit( + ones_generator(), + steps_per_epoch=2, + validation_data=val_data, + epochs=2) + model.evaluate(ones_generator(), steps=2) + model.predict(ones_generator(), steps=2) - with self.assertRaises(ValueError): - model.fit_generator(custom_generator(), - steps_per_epoch=5, - epochs=1, - verbose=1, - max_queue_size=10, - use_multiprocessing=False) - with self.assertRaises(ValueError): - model.fit_generator(custom_generator(), - steps_per_epoch=5, - epochs=1, - verbose=1, - max_queue_size=10, - use_multiprocessing=False, - validation_data=custom_generator(), - validation_steps=10) - with self.assertRaises(AttributeError): - model.predict_generator(custom_generator(), - steps=5, - max_queue_size=10, - use_multiprocessing=False) - with self.assertRaises(ValueError): - model.evaluate_generator(custom_generator(), - steps=5, - max_queue_size=10, - use_multiprocessing=False) + +@tf_test_util.run_all_in_graph_and_eager_modes +class TestGeneratorMethodsWithSequences(test.TestCase): def test_training_with_sequences(self): class DummySequence(keras.utils.Sequence): def __getitem__(self, idx): - return np.zeros([10, 2]), np.ones([10]) + return np.zeros([10, 2]), np.ones([10, 4]) def __len__(self): return 10 - arr_data = np.random.random((50, 2)) - arr_labels = np.random.random((50,)) - arr_sample_weights = np.random.random((50,)) - - def custom_generator(): - batch_size = 10 - num_samples = 50 - while True: - batch_index = np.random.randint(0, num_samples - batch_size) - start = batch_index - end = start + batch_size - x = arr_data[start: end] - y = arr_labels[start: end] - w = arr_sample_weights[start: end] - yield x, y, w - - with self.cached_session(): - model = keras.models.Sequential() - model.add(keras.layers.Dense(1, input_shape=(2,))) - model.compile(loss='mse', optimizer='sgd') + model = keras.models.Sequential() + model.add(keras.layers.Dense(4, input_shape=(2,))) + model.compile(loss='mse', optimizer='sgd') model.fit_generator(DummySequence(), steps_per_epoch=10, @@ -251,29 +300,6 @@ class TestGeneratorMethods(test.TestCase): workers=0, use_multiprocessing=False) - @tf_test_util.run_in_graph_and_eager_modes - def test_generator_input_to_fit_eval_predict(self): - val_data = np.ones([10, 10], np.float32), np.ones([10, 1], np.float32) - - def custom_generator(): - while True: - yield np.ones([10, 10], np.float32), np.ones([10, 1], np.float32) - - inputs = keras.layers.Input(shape=(10,)) - x = keras.layers.Dense(10, activation='relu')(inputs) - outputs = keras.layers.Dense(1, activation='sigmoid')(x) - model = keras.Model(inputs, outputs) - - model.compile(RMSPropOptimizer(0.001), 'binary_crossentropy') - model.fit( - custom_generator(), - steps_per_epoch=2, - validation_data=val_data, - epochs=2) - model.evaluate(custom_generator(), steps=2) - model.predict(custom_generator(), steps=2) - - @tf_test_util.run_in_graph_and_eager_modes def test_sequence_input_to_fit_eval_predict(self): val_data = np.ones([10, 10], np.float32), np.ones([10, 1], np.float32) -- GitLab From 17630415893203929f2b65a5df2b019bd4d3d040 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Mon, 26 Nov 2018 11:17:29 -0800 Subject: [PATCH 313/672] Make testConcurrentExecutesWithoutError resilient to non-deterministic autotuning c1 and c2 may not be exactly equal if we pick different GEMM algorithms for computing matrix1 and matrix2. For some reason I don't understand this happens fairly frequently with XLA enabled (via auto-clustering) but not without XLA. PiperOrigin-RevId: 222855174 --- tensorflow/python/kernel_tests/cholesky_op_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/kernel_tests/cholesky_op_test.py b/tensorflow/python/kernel_tests/cholesky_op_test.py index e96b277266..fa41a03b54 100644 --- a/tensorflow/python/kernel_tests/cholesky_op_test.py +++ b/tensorflow/python/kernel_tests/cholesky_op_test.py @@ -184,7 +184,7 @@ class CholeskyOpTest(test.TestCase): c1 = linalg_ops.cholesky(matrix1) c2 = linalg_ops.cholesky(matrix2) c1_val, c2_val = sess.run([c1, c2]) - self.assertAllEqual(c1_val, c2_val) + self.assertAllClose(c1_val, c2_val) class CholeskyGradTest(test.TestCase): -- GitLab From 243f9a78916be6f1f2edf27db5dd981ad33e1d44 Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Mon, 26 Nov 2018 11:18:36 -0800 Subject: [PATCH 314/672] BEGIN_PUBLIC Rollback change of https://github.com/tensorflow/tensorflow/pull/23441 since its no longer needed. END_PUBLIC Automated rollback of commit 8e048e840e4a0127b8f5bffab4ea5e649db4a0ab. Revert #23441. PiperOrigin-RevId: 222855383 --- tensorflow/python/keras/layers/wrappers.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/keras/layers/wrappers.py b/tensorflow/python/keras/layers/wrappers.py index f6ae77a21f..67b154141e 100644 --- a/tensorflow/python/keras/layers/wrappers.py +++ b/tensorflow/python/keras/layers/wrappers.py @@ -435,15 +435,10 @@ class Bidirectional(Wrapper): @tf_utils.shape_type_conversion def compute_output_shape(self, input_shape): - forward_layer_output_shape = self.forward_layer.compute_output_shape( - input_shape) - if getattr(forward_layer_output_shape, 'as_list', None) is None: - output_shape = tuple(forward_layer_output_shape) - else: - output_shape = tuple(forward_layer_output_shape.as_list()) - + output_shape = tuple(self.forward_layer.compute_output_shape( + input_shape).as_list()) if self.return_state: - state_shape = list(output_shape[1:]) + state_shape = output_shape[1:] output_shape = output_shape[0] if self.merge_mode == 'concat': -- GitLab From e468989d1735d16850a34335aaff13b117660fed Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Mon, 26 Nov 2018 11:26:03 -0800 Subject: [PATCH 315/672] [tf.data] Fix serialization bug in PrivateThreadPoolDatasetOp. PiperOrigin-RevId: 222856707 --- .../core/kernels/data/experimental/threadpool_dataset_op.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc b/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc index 341ce08a57..335f2b7a4b 100644 --- a/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc +++ b/tensorflow/core/kernels/data/experimental/threadpool_dataset_op.cc @@ -391,7 +391,8 @@ class PrivateThreadPoolDatasetOp : public UnaryDatasetOpKernel { TF_RETURN_IF_ERROR(b->AddInputDataset(ctx, input_, &input_graph_node)); Node* num_threads_node = nullptr; TF_RETURN_IF_ERROR(b->AddScalar(num_threads_, &num_threads_node)); - TF_RETURN_IF_ERROR(b->AddDataset(this, {input_graph_node}, output)); + TF_RETURN_IF_ERROR( + b->AddDataset(this, {input_graph_node, num_threads_node}, output)); return Status::OK(); } -- GitLab From e802b5a236407ae916268979e35e1634c14355e2 Mon Sep 17 00:00:00 2001 From: Katherine Wu Date: Mon, 26 Nov 2018 11:29:12 -0800 Subject: [PATCH 316/672] Symbol changes for Tf 2.0 API Changes: - Deprecate: create_partioned_variables - Change args: gather, hessians PiperOrigin-RevId: 222857296 --- tensorflow/python/ops/array_ops.py | 11 +++++++++-- tensorflow/python/ops/gradients_impl.py | 15 ++++++++++++++- tensorflow/python/ops/partitioned_variables.py | 2 +- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 8 ++------ tensorflow/tools/compatibility/renames_v2.py | 1 + 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 8e9b8950bc..496d3855b5 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -3216,7 +3216,7 @@ reverse_sequence_v2.__doc__ = deprecation.rewrite_argument_docstring( # pylint: enable=redefined-builtin -@tf_export("gather") +@tf_export(v1=["gather"]) def gather(params, indices, validate_indices=None, name=None, axis=0): del validate_indices if axis != 0: @@ -3232,7 +3232,14 @@ def gather(params, indices, validate_indices=None, name=None, axis=0): return gen_array_ops.gather_v2(params, indices, axis, name=name) -gather.__doc__ = gen_array_ops.gather_v2.__doc__ +@tf_export("gather", v1=[]) +def gather_v2(params, indices, validate_indices=None, axis=0, name=None): + return gather(params, indices, validate_indices=validate_indices, name=name, + axis=axis) + + +gather.__doc__ = gather_v2.__doc__ = gen_array_ops.gather_v2.__doc__ + @tf_export("batch_gather") diff --git a/tensorflow/python/ops/gradients_impl.py b/tensorflow/python/ops/gradients_impl.py index 278008526c..27cee9113d 100644 --- a/tensorflow/python/ops/gradients_impl.py +++ b/tensorflow/python/ops/gradients_impl.py @@ -1239,7 +1239,7 @@ def _hessian_vector_product(ys, xs, v): return gradients(elemwise_products, xs) -@tf_export("hessians") +@tf_export(v1=["hessians"]) def hessians(ys, xs, name="hessians", @@ -1304,3 +1304,16 @@ def hessians(ys, array_ops.concat((_shape, _shape), 0)) hessians.append(_reshaped_hessian) return hessians + + +@tf_export("hessians", v1=[]) +def HessiansV2(ys, + xs, + gate_gradients=False, + aggregation_method=None, + name="hessians"): + return hessians(ys, xs, name=name, gate_gradients=gate_gradients, + aggregation_method=aggregation_method) + + +HessiansV2.__doc__ = hessians.__doc__ diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 66153e33f2..c1084c2559 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -237,7 +237,7 @@ def fixed_size_partitioner(num_shards, axis=0): return _partitioner -@tf_export("create_partitioned_variables") +@tf_export(v1=["create_partitioned_variables"]) @deprecation.deprecated( date=None, instructions="Use tf.get_variable with a partitioner set.") diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 6afe44a03f..92ebdb91c5 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -580,10 +580,6 @@ tf_module { name: "cosh" argspec: "args=[\'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "create_partitioned_variables" - argspec: "args=[\'shape\', \'slicing\', \'initializer\', \'dtype\', \'trainable\', \'collections\', \'name\', \'reuse\'], varargs=None, keywords=None, defaults=[\"\", \'True\', \'None\', \'None\', \'None\'], " - } member_method { name: "cumsum" argspec: "args=[\'x\', \'axis\', \'exclusive\', \'reverse\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'False\', \'False\', \'None\'], " @@ -682,7 +678,7 @@ tf_module { } member_method { name: "gather" - argspec: "args=[\'params\', \'indices\', \'validate_indices\', \'name\', \'axis\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'0\'], " + argspec: "args=[\'params\', \'indices\', \'validate_indices\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'0\', \'None\'], " } member_method { name: "gather_nd" @@ -714,7 +710,7 @@ tf_module { } member_method { name: "hessians" - argspec: "args=[\'ys\', \'xs\', \'name\', \'colocate_gradients_with_ops\', \'gate_gradients\', \'aggregation_method\'], varargs=None, keywords=None, defaults=[\'hessians\', \'False\', \'False\', \'None\'], " + argspec: "args=[\'ys\', \'xs\', \'gate_gradients\', \'aggregation_method\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\', \'hessians\'], " } member_method { name: "histogram_fixed_width" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index c22b09df48..b02326278e 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -107,6 +107,7 @@ renames = { 'tf.convert_to_tensor_or_sparse_tensor': 'tf.compat.v1.convert_to_tensor_or_sparse_tensor', 'tf.count_nonzero': 'tf.compat.v1.count_nonzero', 'tf.count_up_to': 'tf.compat.v1.count_up_to', + 'tf.create_partitioned_variables': 'tf.compat.v1.create_partitioned_variables', 'tf.cross': 'tf.linalg.cross', 'tf.cumprod': 'tf.math.cumprod', 'tf.debugging.is_finite': 'tf.math.is_finite', -- GitLab From acafc054e1e080cf2a46d47ee6954816a01e4acc Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Mon, 26 Nov 2018 11:34:27 -0800 Subject: [PATCH 317/672] Fix diagram link. PiperOrigin-RevId: 222858360 --- tensorflow/lite/toco/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/toco/README.md b/tensorflow/lite/toco/README.md index bd8f8282f0..fe98a90b38 100644 --- a/tensorflow/lite/toco/README.md +++ b/tensorflow/lite/toco/README.md @@ -26,4 +26,4 @@ to client devices, generally mobile devices, where the TensorFlow Lite interpreter handles them on-device. This flow is represented in the diagram below. -![drawing](g3doc/toco_landscape.svg) +![drawing](../g3doc/images/convert/workflow.svg) -- GitLab From 3951cc626a924b3ebddfce7cfbb08c5d513c08d6 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Mon, 26 Nov 2018 11:37:16 -0800 Subject: [PATCH 318/672] [tf.data] Fixes leak of `OptimizeDatasetOp::Dataset` if optimization fails. Previously, we were not calling `dataset->Unref()` when optimization failed, and the `Dataset` object would leak. If we *had* called `Unref()` we would have attempted to call `optimized_input_->Unref()`, but `optimized_input_` was uninitialized in the case that optimization fails. PiperOrigin-RevId: 222858890 --- .../core/kernels/data/optimize_dataset_op.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/kernels/data/optimize_dataset_op.cc b/tensorflow/core/kernels/data/optimize_dataset_op.cc index f90dcb95e3..f5bb35d360 100644 --- a/tensorflow/core/kernels/data/optimize_dataset_op.cc +++ b/tensorflow/core/kernels/data/optimize_dataset_op.cc @@ -29,6 +29,7 @@ limitations under the License. #include "tensorflow/core/grappler/grappler_item_builder.h" #include "tensorflow/core/grappler/optimizers/data/graph_utils.h" #include "tensorflow/core/grappler/optimizers/meta_optimizer.h" +#include "tensorflow/core/lib/core/refcount.h" #include "tensorflow/core/lib/random/random.h" #include "tensorflow/core/protobuf/meta_graph.pb.h" #include "tensorflow/core/protobuf/rewriter_config.pb.h" @@ -56,8 +57,13 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { ctx, ParseVectorArgument(ctx, "optimizations", &optimizations)); Dataset* dataset = new Dataset(ctx, input, optimizations, output_types_, output_shapes_); - OP_REQUIRES_OK(ctx, dataset->Optimize(ctx)); - *output = dataset; + Status s = dataset->Optimize(ctx); + if (s.ok()) { + *output = dataset; + } else { + dataset->Unref(); + OP_REQUIRES_OK(ctx, s); + } } private: @@ -68,6 +74,7 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { const DataTypeVector& output_types, const std::vector& output_shapes) : DatasetBase(DatasetContext(ctx)), + optimized_input_(nullptr), input_(input), optimizations_(optimizations), output_types_(output_types), @@ -77,7 +84,9 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { ~Dataset() override { input_->Unref(); - optimized_input_->Unref(); + if (optimized_input_) { + optimized_input_->Unref(); + } } std::unique_ptr MakeIteratorInternal( -- GitLab From c4553ea15d6489f3d2dba3e3b17e8cad5e3a9331 Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Mon, 26 Nov 2018 11:52:44 -0800 Subject: [PATCH 319/672] [tf.data] Adding eager coverage to remaining core dataset tests. PiperOrigin-RevId: 222861664 --- tensorflow/python/data/kernel_tests/BUILD | 34 +- .../kernel_tests/flat_map_dataset_op_test.py | 99 +-- .../interleave_dataset_op_test.py | 192 +++-- .../data/kernel_tests/iterator_ops_test.py | 39 +- .../multi_device_iterator_test.py | 1 + .../kernel_tests/range_dataset_op_test.py | 333 -------- .../kernel_tests/reader_dataset_ops_test.py | 770 +++++------------- .../kernel_tests/reduce_dataset_op_test.py | 40 +- .../save_restore_experimental_test.py | 686 ++++++++++++++++ .../kernel_tests/window_dataset_op_test.py | 268 +++--- 10 files changed, 1196 insertions(+), 1266 deletions(-) create mode 100644 tensorflow/python/data/kernel_tests/save_restore_experimental_test.py diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index dc89474f49..0cdb44a3b4 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -158,7 +158,7 @@ tf_py_test( tf_py_test( name = "flat_map_dataset_op_test", - size = "small", + size = "medium", srcs = ["flat_map_dataset_op_test.py"], additional_deps = [ ":test_base", @@ -208,7 +208,7 @@ tf_py_test( tf_py_test( name = "interleave_dataset_op_test", - size = "small", + size = "medium", srcs = ["interleave_dataset_op_test.py"], additional_deps = [ ":test_base", @@ -233,6 +233,7 @@ cuda_py_test( size = "small", srcs = ["iterator_ops_test.py"], additional_deps = [ + ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/python/data/ops:readers", @@ -300,7 +301,7 @@ tf_py_test( tf_py_test( name = "map_dataset_op_test", - size = "small", + size = "medium", srcs = ["map_dataset_op_test.py"], additional_deps = [ ":test_base", @@ -415,7 +416,7 @@ tf_py_test( tf_py_test( name = "reader_dataset_ops_test", - size = "small", + size = "medium", srcs = ["reader_dataset_ops_test.py"], additional_deps = [ ":test_base", @@ -456,6 +457,29 @@ tf_py_test( ], ) +tf_py_test( + name = "save_restore_experimental_test", + size = "small", + srcs = ["save_restore_experimental_test.py"], + additional_deps = [ + ":reader_dataset_ops_test", + ":test_base", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:iterator_ops", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python:client_testlib", + "//tensorflow/python:dataset_ops_gen", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:framework_ops", + "//tensorflow/python:io_ops", + "//tensorflow/python:parsing_ops", + "//tensorflow/python:platform", + "//tensorflow/python:tensor_shape", + "//tensorflow/python:variables", + ], +) + tf_py_test( name = "sequence_dataset_op_test", size = "small", @@ -520,7 +544,7 @@ py_library( tf_py_test( name = "window_dataset_op_test", - size = "small", + size = "medium", srcs = ["window_dataset_op_test.py"], additional_deps = [ ":test_base", diff --git a/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py b/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py index 68038f9cfc..9292f20637 100644 --- a/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py @@ -26,54 +26,41 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import sparse_ops from tensorflow.python.platform import test from tensorflow.python.training import server_lib +@test_util.run_all_in_graph_and_eager_modes class FlatMapDatasetTest(test_base.DatasetTestBase): # pylint: disable=g-long-lambda def testFlatMapDataset(self): repeats = [1, 2, 3, 4, 5, 0, 1] components = np.array(repeats, dtype=np.int64) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components) - .flat_map(lambda x: dataset_ops.Dataset.from_tensors([x]).repeat(x)) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in repeats: - for _ in range(i): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.from_tensor_slices(components).flat_map( + lambda x: dataset_ops.Dataset.from_tensors([x]).repeat(x)) + expected_output = [] + for i in repeats: + expected_output.extend([[i]] * i) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testNestedFlatMapDataset(self): repeats = [[1, 2], [3, 4], [5, 0], [1, 7]] components = np.array(repeats, dtype=np.int64) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components) - .flat_map(lambda x: dataset_ops.Dataset.from_tensor_slices(x) - .flat_map(lambda y: dataset_ops.Dataset.from_tensors(y) - .repeat(y))).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for row in repeats: - for i in row: - for _ in range(i): - self.assertEqual(i, sess.run(get_next)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testSharedResourceNestedFlatMapDataset(self): + dataset = dataset_ops.Dataset.from_tensor_slices(components).flat_map( + lambda x: dataset_ops.Dataset.from_tensor_slices(x).flat_map( + lambda y: dataset_ops.Dataset.from_tensors(y).repeat(y)) + ) + expected_output = [] + for row in repeats: + for i in row: + expected_output.extend([i] * i) + self.assertDatasetProduces(dataset, expected_output=expected_output) + + # Note: no eager mode coverage, session specific test. + def testSkipEagerSharedResourceNestedFlatMapDataset(self): repeats = [[1, 2], [3, 4], [5, 0], [1, 7]] components = np.array(repeats, dtype=np.int64) iterator = ( @@ -106,22 +93,16 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): sess.run(get_next) def testMapDict(self): - iterator = (dataset_ops.Dataset.range(10) - .map(lambda x: {"foo": x * 2, "bar": x ** 2}) - .flat_map(lambda d: dataset_ops.Dataset.from_tensors(d["foo"]) - .repeat(d["bar"])) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(10): - for _ in range(i ** 2): - self.assertEqual(i * 2, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - # pylint: enable=g-long-lambda + dataset = dataset_ops.Dataset.range(10).map( + lambda x: {"foo": x * 2, "bar": x ** 2}).flat_map( + lambda d: dataset_ops.Dataset.from_tensors( + d["foo"]).repeat(d["bar"])) + get_next = self.getNext(dataset) + for i in range(10): + for _ in range(i**2): + self.assertEqual(i * 2, self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testSparse(self): def _map_fn(i): @@ -132,20 +113,12 @@ class FlatMapDatasetTest(test_base.DatasetTestBase): return dataset_ops.Dataset.from_tensor_slices( sparse_ops.sparse_to_dense(x.indices, x.dense_shape, x.values)) - iterator = ( - dataset_ops.Dataset.range(10).map(_map_fn).flat_map(_flat_map_fn) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(10): - for j in range(2): - expected = [i, 0] if j % 2 == 0 else [0, -i] - self.assertAllEqual(expected, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).map(_map_fn).flat_map(_flat_map_fn) + expected_output = [] + for i in range(10): + for j in range(2): + expected_output.append([i, 0] if j % 2 == 0 else [0, -i]) + self.assertDatasetProduces(dataset, expected_output=expected_output) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py b/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py index b911c249ce..f0b16591f7 100644 --- a/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py @@ -27,6 +27,7 @@ from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import script_ops from tensorflow.python.ops import sparse_ops @@ -115,9 +116,7 @@ def _make_coordinated_sloppy_dataset(input_values, cycle_length, block_length, dataset = dataset_ops.Dataset.from_tensor_slices(input_values).repeat( 2).interleave(interleave_fn, cycle_length, block_length, num_parallel_calls).with_options(options) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - return get_next, coordination_events + return dataset, coordination_events def _repeat(values, count): @@ -133,6 +132,7 @@ def _repeat(values, count): return [[value] * value for value in np.tile(values, count)] +@test_util.run_all_in_graph_and_eager_modes class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( @@ -191,16 +191,9 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): count).interleave( lambda x: dataset_ops.Dataset.from_tensors(x).repeat(x), cycle_length, block_length, num_parallel_calls) - get_next = dataset.make_one_shot_iterator().get_next() - - with self.cached_session() as sess: - for expected_element in _interleave( - _repeat(input_values, count), cycle_length, block_length): - self.assertEqual(expected_element, sess.run(get_next)) - - for _ in range(2): - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + expected_output = [element for element in _interleave( + _repeat(input_values, count), cycle_length, block_length)] + self.assertDatasetProduces(dataset, expected_output) @parameterized.named_parameters( ("1", np.float32([1., np.nan, 2., np.nan, 3.]), 1, 3, None), @@ -223,17 +216,16 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): lambda x: array_ops.check_numerics(x, "message")).interleave( dataset_ops.Dataset.from_tensors, cycle_length, block_length, num_parallel_calls) - get_next = dataset.make_one_shot_iterator().get_next() + get_next = self.getNext(dataset) - with self.cached_session() as sess: - for value in input_values: - if np.isnan(value): - with self.assertRaises(errors.InvalidArgumentError): - sess.run(get_next) - else: - self.assertEqual(value, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + for value in input_values: + if np.isnan(value): + with self.assertRaises(errors.InvalidArgumentError): + self.evaluate(get_next()) + else: + self.assertEqual(value, self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testInterleaveSparse(self): @@ -245,72 +237,112 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): return dataset_ops.Dataset.from_tensor_slices( sparse_ops.sparse_to_dense(x.indices, x.dense_shape, x.values)) - iterator = ( - dataset_ops.Dataset.range(10).map(_map_fn).interleave( - _interleave_fn, cycle_length=1).make_one_shot_iterator()) - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.range(10).map(_map_fn).interleave( + _interleave_fn, cycle_length=1) + get_next = self.getNext(dataset) + for i in range(10): + for j in range(2): + expected = [i, 0] if j % 2 == 0 else [0, -i] + self.assertAllEqual(expected, self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + - with self.cached_session() as sess: - for i in range(10): - for j in range(2): - expected = [i, 0] if j % 2 == 0 else [0, -i] - self.assertAllEqual(expected, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) +class InterleaveDatasetTestWithConfig(test_base.DatasetTestBase, + parameterized.TestCase): @parameterized.named_parameters( - ("1", np.int64([4, 5, 6]), 2, 1, 1), - ("2", np.int64([4, 5, 6]), 2, 1, 2), - ("3", np.int64([4, 5, 6]), 2, 3, 1), - ("4", np.int64([4, 5, 6]), 2, 3, 2), - ("5", np.int64([4, 5, 6]), 3, 2, 1), - ("6", np.int64([4, 5, 6]), 3, 2, 2), - ("7", np.int64([4, 5, 6]), 3, 2, 3), - ("8", np.int64([4, 0, 6]), 2, 3, 1), - ("9", np.int64([4, 0, 6]), 2, 3, 2), + ("1", np.int64([4, 5, 6]), 2, 1), + ("2", np.int64([4, 5, 6]), 2, 3), + ("3", np.int64([4, 5, 6]), 3, 2), + ("4", np.int64([4, 0, 6]), 2, 3), ) + @test_util.run_in_graph_and_eager_modes( + config=config_pb2.ConfigProto( + inter_op_parallelism_threads=2, use_per_session_threads=True)) def testSloppyInterleaveInOrder(self, input_values, cycle_length, - block_length, num_parallel_calls): - get_next, coordination_events = _make_coordinated_sloppy_dataset( - input_values, cycle_length, block_length, num_parallel_calls) - config = config_pb2.ConfigProto( - inter_op_parallelism_threads=num_parallel_calls + 1, - use_per_session_threads=True) - with self.cached_session(config=config) as sess: - for expected_element in _interleave( - _repeat(input_values, 2), cycle_length, block_length): - coordination_events[expected_element].set() - self.assertEqual(expected_element * expected_element, - sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + block_length): + dataset, coordination_events = _make_coordinated_sloppy_dataset( + input_values, cycle_length, block_length, num_parallel_calls=1) + get_next = self.getNext(dataset) + for expected_element in _interleave( + _repeat(input_values, 2), cycle_length, block_length): + coordination_events[expected_element].set() + self.assertEqual(expected_element * expected_element, + self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + @parameterized.named_parameters( + ("1", np.int64([4, 5, 6]), 2, 1), + ("2", np.int64([4, 5, 6]), 2, 3), + ("3", np.int64([4, 5, 6]), 3, 2), + ("4", np.int64([4, 0, 6]), 2, 3), + ) + @test_util.run_in_graph_and_eager_modes( + config=config_pb2.ConfigProto( + inter_op_parallelism_threads=3, use_per_session_threads=True)) + def testSloppyInterleaveInOrder_2(self, input_values, cycle_length, + block_length): + dataset, coordination_events = _make_coordinated_sloppy_dataset( + input_values, cycle_length, block_length, num_parallel_calls=2) + get_next = self.getNext(dataset) + for expected_element in _interleave( + _repeat(input_values, 2), cycle_length, block_length): + coordination_events[expected_element].set() + self.assertEqual(expected_element * expected_element, + self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) @parameterized.named_parameters( - ("1", np.int64([4, 5, 6]), 2, 1, 2), - ("2", np.int64([4, 5, 6]), 2, 3, 2), - ("3", np.int64([4, 5, 6]), 3, 2, 3), - ("4", np.int64([4, 0, 6]), 2, 3, 2), + ("1", np.int64([4, 5, 6]), 2, 1), + ("2", np.int64([4, 5, 6]), 2, 3), + ("3", np.int64([4, 0, 6]), 2, 3), ) + @test_util.run_in_graph_and_eager_modes( + config=config_pb2.ConfigProto( + inter_op_parallelism_threads=3, use_per_session_threads=True)) def testSloppyInterleaveOutOfOrder(self, input_values, cycle_length, - block_length, num_parallel_calls): - get_next, coordination_events = _make_coordinated_sloppy_dataset( - input_values, cycle_length, block_length, num_parallel_calls) - config = config_pb2.ConfigProto( - inter_op_parallelism_threads=num_parallel_calls + 1, - use_per_session_threads=True) - with self.cached_session(config=config) as sess: - elements = [ - x for x in _interleave( - _repeat(input_values, 2), cycle_length, block_length) - ] - for i in [1, 4, 7]: - elements[i], elements[i + 1] = elements[i + 1], elements[i] - - for element in elements: - coordination_events[element].set() - self.assertEqual(element * element, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + block_length): + dataset, coordination_events = _make_coordinated_sloppy_dataset( + input_values, cycle_length, block_length, num_parallel_calls=2) + get_next = self.getNext(dataset) + elements = [ + x for x in _interleave( + _repeat(input_values, 2), cycle_length, block_length) + ] + for i in [1, 4, 7]: + elements[i], elements[i + 1] = elements[i + 1], elements[i] + + for element in elements: + coordination_events[element].set() + self.assertEqual(element * element, self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + @test_util.run_in_graph_and_eager_modes( + config=config_pb2.ConfigProto( + inter_op_parallelism_threads=4, use_per_session_threads=True)) + def testSloppyInterleaveOutOfOrder_2(self): + input_values, cycle_length, block_length = np.int64([4, 5, 6]), 3, 2 + dataset, coordination_events = _make_coordinated_sloppy_dataset( + input_values, cycle_length, block_length, num_parallel_calls=3) + get_next = self.getNext(dataset) + elements = [ + x for x in _interleave( + _repeat(input_values, 2), cycle_length, block_length) + ] + for i in [1, 4, 7]: + elements[i], elements[i + 1] = elements[i + 1], elements[i] + + for element in elements: + coordination_events[element].set() + self.assertEqual(element * element, self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/iterator_ops_test.py b/tensorflow/python/data/kernel_tests/iterator_ops_test.py index 490ca813dc..3d4db80883 100644 --- a/tensorflow/python/data/kernel_tests/iterator_ops_test.py +++ b/tensorflow/python/data/kernel_tests/iterator_ops_test.py @@ -28,6 +28,7 @@ from tensorflow.core.protobuf import cluster_pb2 from tensorflow.core.protobuf import config_pb2 from tensorflow.python.client import session from tensorflow.python.compat import compat as forward_compat +from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.ops import readers @@ -863,15 +864,16 @@ class IteratorTest(test.TestCase, parameterized.TestCase): self.assertEqual("overridden_name", next_element.op.name) -class IteratorCheckpointingTest(test.TestCase): +@test_util.run_all_in_graph_and_eager_modes +class IteratorCheckpointingTest(test_base.DatasetTestBase): - @test_util.run_in_graph_and_eager_modes def testSaveRestoreOneShotIterator(self): checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") dataset = dataset_ops.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6]).map( math_ops.square).batch(2) - iterator = dataset.make_one_shot_iterator() + iterator = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() get_next = iterator.get_next if context.executing_eagerly( ) else functools.partial(self.evaluate, iterator.get_next()) checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) @@ -885,21 +887,23 @@ class IteratorCheckpointingTest(test.TestCase): with self.assertRaises(errors.OutOfRangeError): get_next() - @test_util.run_in_graph_and_eager_modes def testSaveRestoreMultipleIterator(self): checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") dataset = dataset_ops.Dataset.from_tensor_slices( [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) dataset = dataset.map(math_ops.square).batch(2) - iterator_1 = dataset.make_one_shot_iterator() + iterator_1 = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() get_next_1 = iterator_1.get_next if context.executing_eagerly( ) else functools.partial(self.evaluate, iterator_1.get_next()) - iterator_2 = dataset.make_one_shot_iterator() + iterator_2 = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() get_next_2 = iterator_2.get_next if context.executing_eagerly( ) else functools.partial(self.evaluate, iterator_2.get_next()) dataset_2 = dataset_ops.Dataset.range(10) - iterator_3 = dataset_2.make_one_shot_iterator() + iterator_3 = iter(dataset_2) if context.executing_eagerly( + ) else dataset_2.make_one_shot_iterator() get_next_3 = iterator_3.get_next if context.executing_eagerly( ) else functools.partial(self.evaluate, iterator_3.get_next()) checkpoint = checkpointable_utils.Checkpoint( @@ -917,12 +921,12 @@ class IteratorCheckpointingTest(test.TestCase): self.assertAllEqual([1, 4], get_next_2()) self.assertAllEqual(3, get_next_3()) - @test_util.run_in_graph_and_eager_modes def testRestoreExhaustedIterator(self): checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") dataset = dataset_ops.Dataset.range(3) - iterator = dataset.make_one_shot_iterator() + iterator = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() get_next = iterator.get_next if context.executing_eagerly( ) else functools.partial(self.evaluate, iterator.get_next()) checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) @@ -941,16 +945,17 @@ class IteratorCheckpointingTest(test.TestCase): checkpoint_directory = self.get_temp_dir() checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") dataset = dataset_ops.Dataset.range(10) - iterator = dataset.make_initializable_iterator() - get_next = iterator.get_next() + iterator = iter(dataset) if context.executing_eagerly( + ) else dataset.make_initializable_iterator() + get_next = iterator.get_next checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) for i in range(5): - with self.cached_session() as sess: - checkpoint.restore(checkpoint_management.latest_checkpoint( - checkpoint_directory)).initialize_or_restore(sess) - for j in range(2): - self.assertEqual(i * 2 + j, sess.run(get_next)) - checkpoint.save(file_prefix=checkpoint_prefix) + checkpoint.restore( + checkpoint_management.latest_checkpoint( + checkpoint_directory)).initialize_or_restore() + for j in range(2): + self.assertEqual(i * 2 + j, self.evaluate(get_next())) + checkpoint.save(file_prefix=checkpoint_prefix) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py index 42ee1e2186..afb0939397 100644 --- a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py +++ b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py @@ -31,6 +31,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.platform import test +# TODO(b/117581999): Add eager coverage for the following tests. class MultiDeviceIteratorTest(test_base.DatasetTestBase): def testNoGetNext(self): diff --git a/tensorflow/python/data/kernel_tests/range_dataset_op_test.py b/tensorflow/python/data/kernel_tests/range_dataset_op_test.py index 9fc79707d0..907cb59096 100644 --- a/tensorflow/python/data/kernel_tests/range_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/range_dataset_op_test.py @@ -17,21 +17,11 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import os from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import iterator_ops -from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors -from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import test_util -from tensorflow.python.ops import gen_dataset_ops -from tensorflow.python.ops import io_ops -from tensorflow.python.ops import parsing_ops -from tensorflow.python.ops import variables -from tensorflow.python.platform import gfile from tensorflow.python.platform import test @@ -79,328 +69,5 @@ class RangeDatasetTest(test_base.DatasetTestBase): self.assertDatasetProduces(dataset, expected_output=range(10, 2, -1)) -class ExperimentalCheckpointDatasetTest(test_base.DatasetTestBase): - - def tearDown(self): - # Remove all checkpoint files. - prefix = self._iterator_checkpoint_prefix() - pattern = prefix + "*" - files = gfile.Glob(pattern) - map(gfile.Remove, files) - - def _iterator_checkpoint_prefix(self): - return os.path.join(self.get_temp_dir(), "iterator") - - def _save_op(self, iterator_resource): - iterator_state_variant = gen_dataset_ops.serialize_iterator( - iterator_resource) - save_op = io_ops.write_file( - self._iterator_checkpoint_prefix(), - parsing_ops.serialize_tensor(iterator_state_variant)) - return save_op - - def _restore_op(self, iterator_resource): - iterator_state_variant = parsing_ops.parse_tensor( - io_ops.read_file(self._iterator_checkpoint_prefix()), dtypes.variant) - restore_op = gen_dataset_ops.deserialize_iterator(iterator_resource, - iterator_state_variant) - return restore_op - - def testSaveRestore(self): - - def _build_graph(start, stop): - iterator = dataset_ops.Dataset.range(start, - stop).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - break_point = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(init_op) - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Saving and restoring in same session. - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testRestoreWithoutBuildingDatasetGraph(self): - - def _build_graph(start, stop, num_epochs): - dataset = dataset_ops.Dataset.range(start, stop).repeat(num_epochs) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - num_epochs = 5 - break_point = 5 - break_epoch = 3 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for _ in range(break_epoch): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - # Create an empty IteratorResource and restore the Iterator into it. - output_types = dtypes.int64 - output_shapes = tensor_shape.scalar() - iterator = iterator_ops.Iterator.from_structure(output_types, - output_shapes) - restore_op = self._restore_op(iterator._iterator_resource) - get_next = iterator.get_next() - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - for _ in range(break_epoch + 1, num_epochs): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testRestoreInModifiedGraph(self): - - def _build_graph(start, stop): - dataset = dataset_ops.Dataset.range(start, stop) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - stop_1 = 8 - break_point = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - # Intentionally build a graph with a different value for stop to make sure - # the original dataset graph is actually getting loaded. - init_op, get_next, _, restore_op = _build_graph(start, stop_1) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testInitThenRestore(self): - # Note: Calling init_op before restore_op is redundant. This test just makes - # sure we do not fail if restore is called on an already initialized - # iterator resource. - - def _build_graph(start, stop): - dataset = dataset_ops.Dataset.range(start, stop) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - break_point = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(init_op) - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testMultipleSaves(self): - - def _build_graph(start, stop): - iterator = dataset_ops.Dataset.range(start, - stop).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - start = 2 - stop = 10 - break_point1 = 5 - break_point2 = 7 - - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point1): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point1, break_point2): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - break_point2 = 7 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point2, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testSaveRestoreWithRepeat(self): - - def _build_graph(start, stop, num_epochs): - iterator = dataset_ops.Dataset.range( - start, stop).repeat(num_epochs).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - start = 2 - stop = 10 - num_epochs = 5 - break_range = 5 - break_epoch = 3 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph( - start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for _ in range(break_epoch - 1): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - for i in range(start, break_range): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_range, stop): - self.assertEqual(i, sess.run(get_next)) - for _ in range(break_epoch, num_epochs): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testSaveRestoreExhaustedIterator(self): - - def _build_graph(start, stop, num_epochs): - iterator = dataset_ops.Dataset.range( - start, stop).repeat(num_epochs).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - start = 2 - stop = 10 - num_epochs = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph( - start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for _ in range(num_epochs): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py b/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py index 4fef4f30bf..483a79513a 100644 --- a/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py @@ -23,19 +23,11 @@ import zlib from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.ops import readers from tensorflow.python.eager import context -from tensorflow.python.framework import constant_op -from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors -from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.lib.io import python_io -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import gen_dataset_ops -from tensorflow.python.ops import io_ops -from tensorflow.python.ops import parsing_ops from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -47,6 +39,7 @@ except ImportError: psutil_import_succeeded = False +@test_util.run_all_in_graph_and_eager_modes class TextLineDatasetTest(test_base.DatasetTestBase): def _lineText(self, f, l): @@ -88,66 +81,41 @@ class TextLineDatasetTest(test_base.DatasetTestBase): def _testTextLineDataset(self, compression_type=None): test_filenames = self._createFiles( 2, 5, crlf=True, compression_type=compression_type) - filenames = array_ops.placeholder(dtypes.string, shape=[None]) - num_epochs = array_ops.placeholder(dtypes.int64, shape=[]) - batch_size = array_ops.placeholder(dtypes.int64, shape=[]) - - repeat_dataset = readers.TextLineDataset( - filenames, compression_type=compression_type).repeat(num_epochs) - batch_dataset = repeat_dataset.batch(batch_size) - - iterator = iterator_ops.Iterator.from_structure(batch_dataset.output_types) - init_op = iterator.make_initializer(repeat_dataset) - init_batch_op = iterator.make_initializer(batch_dataset) - get_next = iterator.get_next() - - with self.cached_session() as sess: - # Basic test: read from file 0. - sess.run( - init_op, feed_dict={filenames: [test_filenames[0]], - num_epochs: 1}) - for i in range(5): - self.assertEqual(self._lineText(0, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Basic test: read from file 1. - sess.run( - init_op, feed_dict={filenames: [test_filenames[1]], - num_epochs: 1}) - for i in range(5): - self.assertEqual(self._lineText(1, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Basic test: read from both files. - sess.run(init_op, feed_dict={filenames: test_filenames, num_epochs: 1}) - for j in range(2): - for i in range(5): - self.assertEqual(self._lineText(j, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test repeated iteration through both files. - sess.run(init_op, feed_dict={filenames: test_filenames, num_epochs: 10}) - for _ in range(10): - for j in range(2): - for i in range(5): - self.assertEqual(self._lineText(j, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test batched and repeated iteration through both files. - sess.run( - init_batch_op, - feed_dict={filenames: test_filenames, - num_epochs: 10, - batch_size: 5}) - for _ in range(10): - self.assertAllEqual([self._lineText(0, i) for i in range(5)], - sess.run(get_next)) - self.assertAllEqual([self._lineText(1, i) for i in range(5)], - sess.run(get_next)) + + def dataset_fn(filenames, num_epochs, batch_size=None): + repeat_dataset = readers.TextLineDataset( + filenames, compression_type=compression_type).repeat(num_epochs) + if batch_size: + return repeat_dataset.batch(batch_size) + return repeat_dataset + + # Basic test: read from file 0. + expected_output = [self._lineText(0, i) for i in range(5)] + self.assertDatasetProduces( + dataset_fn([test_filenames[0]], 1), expected_output=expected_output) + + # Basic test: read from file 1. + self.assertDatasetProduces( + dataset_fn([test_filenames[1]], 1), + expected_output=[self._lineText(1, i) for i in range(5)]) + + # Basic test: read from both files. + expected_output = [self._lineText(0, i) for i in range(5)] + expected_output.extend([self._lineText(1, i) for i in range(5)]) + self.assertDatasetProduces( + dataset_fn(test_filenames, 1), expected_output=expected_output) + + # Test repeated iteration through both files. + expected_output = [self._lineText(0, i) for i in range(5)] + expected_output.extend([self._lineText(1, i) for i in range(5)]) + self.assertDatasetProduces( + dataset_fn(test_filenames, 10), expected_output=expected_output * 10) + + # Test batched and repeated iteration through both files. + self.assertDatasetProduces( + dataset_fn(test_filenames, 10, 5), + expected_output=[[self._lineText(0, i) for i in range(5)], + [self._lineText(1, i) for i in range(5)]] * 10) def testTextLineDatasetNoCompression(self): self._testTextLineDataset() @@ -162,14 +130,10 @@ class TextLineDatasetTest(test_base.DatasetTestBase): test_filenames = self._createFiles(2, 5, crlf=True) repeat_dataset = readers.TextLineDataset(test_filenames, buffer_size=10) - iterator = repeat_dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - for j in range(2): - for i in range(5): - self.assertEqual(self._lineText(j, i), sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + expected_output = [] + for j in range(2): + expected_output.extend([self._lineText(j, i) for i in range(5)]) + self.assertDatasetProduces(repeat_dataset, expected_output=expected_output) def testIteratorResourceCleanup(self): filename = os.path.join(self.get_temp_dir(), "text.txt") @@ -200,10 +164,10 @@ class TextLineDatasetTest(test_base.DatasetTestBase): self.assertNotIn(filename, [open_file.path for open_file in open_files]) -class FixedLengthRecordReaderTest(test_base.DatasetTestBase): +class FixedLengthRecordReaderTestBase(test_base.DatasetTestBase): def setUp(self): - super(FixedLengthRecordReaderTest, self).setUp() + super(FixedLengthRecordReaderTestBase, self).setUp() self._num_files = 2 self._num_records = 7 self._header_bytes = 5 @@ -241,77 +205,64 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): return filenames + +@test_util.run_all_in_graph_and_eager_modes +class FixedLengthRecordReaderTest(FixedLengthRecordReaderTestBase): + def _testFixedLengthRecordDataset(self, compression_type=None): test_filenames = self._createFiles(compression_type=compression_type) - filenames = array_ops.placeholder(dtypes.string, shape=[None]) - num_epochs = array_ops.placeholder(dtypes.int64, shape=[]) - batch_size = array_ops.placeholder(dtypes.int64, shape=[]) - - repeat_dataset = ( - readers.FixedLengthRecordDataset( - filenames, - self._record_bytes, - self._header_bytes, - self._footer_bytes, - compression_type=compression_type).repeat(num_epochs)) - batch_dataset = repeat_dataset.batch(batch_size) - - iterator = iterator_ops.Iterator.from_structure(batch_dataset.output_types) - init_op = iterator.make_initializer(repeat_dataset) - init_batch_op = iterator.make_initializer(batch_dataset) - get_next = iterator.get_next() - - with self.cached_session() as sess: - # Basic test: read from file 0. - sess.run( - init_op, feed_dict={filenames: [test_filenames[0]], - num_epochs: 1}) - for i in range(self._num_records): - self.assertEqual(self._record(0, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Basic test: read from file 1. - sess.run( - init_op, feed_dict={filenames: [test_filenames[1]], - num_epochs: 1}) - for i in range(self._num_records): - self.assertEqual(self._record(1, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Basic test: read from both files. - sess.run(init_op, feed_dict={filenames: test_filenames, num_epochs: 1}) + + def dataset_fn(filenames, num_epochs, batch_size=None): + repeat_dataset = readers.FixedLengthRecordDataset( + filenames, + self._record_bytes, + self._header_bytes, + self._footer_bytes, + compression_type=compression_type).repeat(num_epochs) + if batch_size: + return repeat_dataset.batch(batch_size) + return repeat_dataset + + # Basic test: read from file 0. + self.assertDatasetProduces( + dataset_fn([test_filenames[0]], 1), + expected_output=[ + self._record(0, i) for i in range(self._num_records) + ]) + + # Basic test: read from file 1. + self.assertDatasetProduces( + dataset_fn([test_filenames[1]], 1), + expected_output=[ + self._record(1, i) for i in range(self._num_records) + ]) + + # Basic test: read from both files. + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces( + dataset_fn(test_filenames, 1), expected_output=expected_output) + + # Test repeated iteration through both files. + get_next = self.getNext(dataset_fn(test_filenames, 10)) + for _ in range(10): for j in range(self._num_files): for i in range(self._num_records): - self.assertEqual(self._record(j, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test repeated iteration through both files. - sess.run(init_op, feed_dict={filenames: test_filenames, num_epochs: 10}) - for _ in range(10): - for j in range(self._num_files): - for i in range(self._num_records): - self.assertEqual(self._record(j, i), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test batched and repeated iteration through both files. - sess.run( - init_batch_op, - feed_dict={ - filenames: test_filenames, - num_epochs: 10, - batch_size: self._num_records - }) - for _ in range(10): - for j in range(self._num_files): - self.assertAllEqual( - [self._record(j, i) for i in range(self._num_records)], - sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertEqual(self._record(j, i), self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + # Test batched and repeated iteration through both files. + get_next = self.getNext(dataset_fn(test_filenames, 10, self._num_records)) + for _ in range(10): + for j in range(self._num_files): + self.assertAllEqual( + [self._record(j, i) for i in range(self._num_records)], + self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) def testFixedLengthRecordDatasetNoCompression(self): self._testFixedLengthRecordDataset() @@ -330,14 +281,11 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): self._header_bytes, self._footer_bytes, buffer_size=10) - iterator = dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - for j in range(self._num_files): - for i in range(self._num_records): - self.assertEqual(self._record(j, i), sess.run(iterator.get_next())) - with self.assertRaises(errors.OutOfRangeError): - sess.run(iterator.get_next()) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testFixedLengthRecordDatasetWrongSize(self): test_filenames = self._createFiles() @@ -347,310 +295,17 @@ class FixedLengthRecordReaderTest(test_base.DatasetTestBase): self._header_bytes, self._footer_bytes, buffer_size=10) - iterator = dataset.make_one_shot_iterator() - - with self.cached_session() as sess: - with self.assertRaisesRegexp( - errors.InvalidArgumentError, - r"Excluding the header \(5 bytes\) and footer \(2 bytes\), input " - r"file \".*fixed_length_record.0.txt\" has body length 21 bytes, " - r"which is not an exact multiple of the record length \(4 bytes\)."): - sess.run(iterator.get_next()) - - def _iterator_checkpoint_path(self): - return os.path.join(self.get_temp_dir(), "iterator") - - def _save_op(self, iterator_resource): - iterator_state_variant = gen_dataset_ops.serialize_iterator( - iterator_resource) - save_op = io_ops.write_file( - self._iterator_checkpoint_path(), - parsing_ops.serialize_tensor(iterator_state_variant)) - return save_op - - def _restore_op(self, iterator_resource): - iterator_state_variant = parsing_ops.parse_tensor( - io_ops.read_file(self._iterator_checkpoint_path()), dtypes.variant) - restore_op = gen_dataset_ops.deserialize_iterator(iterator_resource, - iterator_state_variant) - return restore_op - - def _build_iterator_graph(self, num_epochs): - filenames = self._createFiles() - dataset = (readers.FixedLengthRecordDataset( - filenames, self._record_bytes, self._header_bytes, self._footer_bytes) - .repeat(num_epochs)) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next_op = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next_op, save_op, restore_op - - def _restore_iterator(self): - output_types = dtypes.string - output_shapes = tensor_shape.scalar() - iterator = iterator_ops.Iterator.from_structure(output_types, output_shapes) - get_next = iterator.get_next() - restore_op = self._restore_op(iterator._iterator_resource) - return restore_op, get_next - - def testSaveRestore(self): - num_epochs = 10 - epoch_break = 5 - file_break = self._num_files // 2 - record_break = self._num_records // 2 - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch == epoch_break and f == file_break and - r == record_break): - sess.run(save_op) - break - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - else: - continue - break - else: - continue - break - else: - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch < epoch_break or - (epoch == epoch_break and f < file_break) or - (epoch == epoch_break and f == file_break and - r < record_break)): - continue - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - def testInitThenRestore(self): - # Note: Calling init_op before restore_op is redundant. This test just makes - # sure we do not fail if restore is called on an already initialized - # iterator resource. - num_epochs = 10 - epoch_break = 5 - file_break = self._num_files // 2 - record_break = self._num_records // 2 - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch == epoch_break and f == file_break and - r == record_break): - sess.run(save_op) - break - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - else: - continue - break - else: - continue - break - else: - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch < epoch_break or - (epoch == epoch_break and f < file_break) or - (epoch == epoch_break and f == file_break and - r < record_break)): - continue - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - def testRestoreInModifiedGraph(self): - num_epochs = 10 - num_epochs_1 = 20 - epoch_break = 5 - file_break = self._num_files // 2 - record_break = self._num_records // 2 - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch == epoch_break and f == file_break and - r == record_break): - sess.run(save_op) - break - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - else: - continue - break - else: - continue - break - else: - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs_1) - with self.session(graph=g) as sess: - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch < epoch_break or - (epoch == epoch_break and f < file_break) or - (epoch == epoch_break and f == file_break and - r < record_break)): - continue - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - def testRestoreWithoutBuildingDatasetGraph(self): - num_epochs = 10 - epoch_break = 5 - file_break = self._num_files // 2 - record_break = self._num_records // 2 - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch == epoch_break and f == file_break and - r == record_break): - sess.run(save_op) - break - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - else: - continue - break - else: - continue - break - else: - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - with ops.Graph().as_default() as g: - restore_op, get_next_op = self._restore_iterator() - with self.session(graph=g) as sess: - sess.run(restore_op) - for epoch in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - if (epoch < epoch_break or - (epoch == epoch_break and f < file_break) or - (epoch == epoch_break and f == file_break and - r < record_break)): - continue - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - def testRestoreUnusedIterator(self): - num_epochs = 10 - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - # Save unused iterator. - sess.run(save_op) - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - for _ in range(num_epochs * self._num_files * self._num_records): - sess.run(get_next_op) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - - def testRestoreExhaustedIterator(self): - num_epochs = 10 - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for _ in range(num_epochs): - for f in range(self._num_files): - for r in range(self._num_records): - self.assertEqual(self._record(f, r), sess.run(get_next_op)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next_op, save_op, restore_op = self._build_iterator_graph( - num_epochs=num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next_op) + self.assertDatasetProduces( + dataset, + expected_error=( + errors.InvalidArgumentError, + r"Excluding the header \(5 bytes\) and footer \(2 bytes\), input " + r"file \".*fixed_length_record.0.txt\" has body length 21 bytes, " + r"which is not an exact multiple of the record length \(4 bytes\).") + ) +@test_util.run_all_in_graph_and_eager_modes class TFRecordDatasetTest(test_base.DatasetTestBase): def setUp(self): @@ -660,21 +315,17 @@ class TFRecordDatasetTest(test_base.DatasetTestBase): self.test_filenames = self._createFiles() - self.filenames = array_ops.placeholder(dtypes.string, shape=[None]) - self.num_epochs = array_ops.placeholder_with_default( - constant_op.constant(1, dtypes.int64), shape=[]) - self.compression_type = array_ops.placeholder_with_default("", shape=[]) - self.batch_size = array_ops.placeholder(dtypes.int64, shape=[]) - - repeat_dataset = readers.TFRecordDataset(self.filenames, - self.compression_type).repeat( - self.num_epochs) - batch_dataset = repeat_dataset.batch(self.batch_size) + def dataset_fn(self, + filenames, + compression_type="", + num_epochs=1, + batch_size=None): - iterator = iterator_ops.Iterator.from_structure(batch_dataset.output_types) - self.init_op = iterator.make_initializer(repeat_dataset) - self.init_batch_op = iterator.make_initializer(batch_dataset) - self.get_next = iterator.get_next() + repeat_dataset = readers.TFRecordDataset( + filenames, compression_type).repeat(num_epochs) + if batch_size: + return repeat_dataset.batch(batch_size) + return repeat_dataset def _record(self, f, r): return compat.as_bytes("Record %d of file %d" % (r, f)) @@ -691,71 +342,42 @@ class TFRecordDatasetTest(test_base.DatasetTestBase): return filenames def testReadOneEpoch(self): - with self.cached_session() as sess: - # Basic test: read from file 0. - sess.run( - self.init_op, - feed_dict={ - self.filenames: [self.test_filenames[0]], - self.num_epochs: 1 - }) - for i in range(self._num_records): - self.assertAllEqual(self._record(0, i), sess.run(self.get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) - - # Basic test: read from file 1. - sess.run( - self.init_op, - feed_dict={ - self.filenames: [self.test_filenames[1]], - self.num_epochs: 1 - }) - for i in range(self._num_records): - self.assertAllEqual(self._record(1, i), sess.run(self.get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) - - # Basic test: read from both files. - sess.run( - self.init_op, - feed_dict={self.filenames: self.test_filenames, - self.num_epochs: 1}) - for j in range(self._num_files): - for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), sess.run(self.get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) + # Basic test: read from file 0. + dataset = self.dataset_fn(self.test_filenames[0]) + self.assertDatasetProduces( + dataset, + expected_output=[self._record(0, i) for i in range(self._num_records)]) + + # Basic test: read from file 1. + dataset = self.dataset_fn(self.test_filenames[1]) + self.assertDatasetProduces( + dataset, + expected_output=[self._record(1, i) for i in range(self._num_records)]) + + # Basic test: read from both files. + dataset = self.dataset_fn(self.test_filenames) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testReadTenEpochs(self): - with self.cached_session() as sess: - sess.run( - self.init_op, - feed_dict={self.filenames: self.test_filenames, - self.num_epochs: 10}) - for _ in range(10): - for j in range(self._num_files): - for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), sess.run(self.get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) + dataset = self.dataset_fn(self.test_filenames, num_epochs=10) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output * 10) def testReadTenEpochsOfBatches(self): - with self.cached_session() as sess: - sess.run( - self.init_batch_op, - feed_dict={ - self.filenames: self.test_filenames, - self.num_epochs: 10, - self.batch_size: self._num_records - }) - for _ in range(10): - for j in range(self._num_files): - values = sess.run(self.get_next) - self.assertAllEqual( - [self._record(j, i) for i in range(self._num_records)], values) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) + dataset = self.dataset_fn( + self.test_filenames, num_epochs=10, batch_size=self._num_records) + expected_output = [] + for j in range(self._num_files): + expected_output.append( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output * 10) def testReadZlibFiles(self): zlib_files = [] @@ -767,17 +389,12 @@ class TFRecordDatasetTest(test_base.DatasetTestBase): with open(zfn, "wb") as f: f.write(cdata) zlib_files.append(zfn) - - with self.cached_session() as sess: - sess.run( - self.init_op, - feed_dict={self.filenames: zlib_files, - self.compression_type: "ZLIB"}) - for j in range(self._num_files): - for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), sess.run(self.get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = self.dataset_fn(zlib_files, compression_type="ZLIB") + self.assertDatasetProduces(dataset, expected_output=expected_output) def testReadGzipFiles(self): gzip_files = [] @@ -787,59 +404,42 @@ class TFRecordDatasetTest(test_base.DatasetTestBase): with gzip.GzipFile(gzfn, "wb") as gzf: gzf.write(f.read()) gzip_files.append(gzfn) - - with self.cached_session() as sess: - sess.run( - self.init_op, - feed_dict={self.filenames: gzip_files, - self.compression_type: "GZIP"}) - for j in range(self._num_files): - for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), sess.run(self.get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(self.get_next) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = self.dataset_fn(gzip_files, compression_type="GZIP") + self.assertDatasetProduces(dataset, expected_output=expected_output) def testReadWithBuffer(self): one_mebibyte = 2**20 - d = readers.TFRecordDataset(self.test_filenames, buffer_size=one_mebibyte) - iterator = d.make_one_shot_iterator() - next_element = iterator.get_next() - with self.cached_session() as sess: - for j in range(self._num_files): - for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + dataset = readers.TFRecordDataset( + self.test_filenames, buffer_size=one_mebibyte) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testReadFromDatasetOfFiles(self): files = dataset_ops.Dataset.from_tensor_slices(self.test_filenames) - d = readers.TFRecordDataset(files) - iterator = d.make_one_shot_iterator() - next_element = iterator.get_next() - with self.cached_session() as sess: - for j in range(self._num_files): - for i in range(self._num_records): - self.assertAllEqual(self._record(j, i), sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = readers.TFRecordDataset(files) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testReadTenEpochsFromDatasetOfFilesInParallel(self): files = dataset_ops.Dataset.from_tensor_slices( self.test_filenames).repeat(10) - d = readers.TFRecordDataset(files, num_parallel_reads=4) - iterator = d.make_one_shot_iterator() - next_element = iterator.get_next() - expected = [] - actual = [] - with self.cached_session() as sess: - for _ in range(10): - for j in range(self._num_files): - for i in range(self._num_records): - expected.append(self._record(j, i)) - actual.append(sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - self.assertEqual(sorted(expected), sorted(actual)) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = readers.TFRecordDataset(files, num_parallel_reads=4) + self.assertDatasetProduces( + dataset, expected_output=expected_output * 10, assert_items_equal=True) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py b/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py index 11e07300b9..061f0d1343 100644 --- a/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py @@ -22,21 +22,24 @@ import numpy as np from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): def testSum(self): for i in range(10): ds = dataset_ops.Dataset.range(1, i + 1) - result = ds.reduce(np.int64(0), lambda x, y: x + y) - with self.cached_session() as sess: - self.assertEqual(((i + 1) * i) // 2, sess.run(result)) + result = ds.reduce( + constant_op.constant(0, dtype=dtypes.int64), lambda x, y: x + y) + self.assertEqual(((i + 1) * i) // 2, self.evaluate(result)) def testSumTuple(self): @@ -47,9 +50,8 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for i in range(10): ds = dataset_ops.Dataset.range(1, i + 1) ds = dataset_ops.Dataset.zip((ds, ds)) - result = ds.reduce(np.int64(0), reduce_fn) - with self.cached_session() as sess: - self.assertEqual(((i + 1) * i), sess.run(result)) + result = ds.reduce(constant_op.constant(0, dtype=dtypes.int64), reduce_fn) + self.assertEqual(((i + 1) * i), self.evaluate(result)) def testSumAndCount(self): @@ -59,13 +61,14 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for i in range(10): ds = dataset_ops.Dataset.range(1, i + 1) - result = ds.reduce((np.int64(0), np.int64(0)), reduce_fn) - with self.cached_session() as sess: - s, c = sess.run(result) - self.assertEqual(((i + 1) * i) // 2, s) - self.assertEqual(i, c) - - def testSquareUsingPlaceholder(self): + result = ds.reduce((constant_op.constant(0, dtype=dtypes.int64), + constant_op.constant(0, dtype=dtypes.int64)), + reduce_fn) + s, c = self.evaluate(result) + self.assertEqual(((i + 1) * i) // 2, s) + self.assertEqual(i, c) + + def testSkipEagerSquareUsingPlaceholder(self): delta = array_ops.placeholder(dtype=dtypes.int64) def reduce_fn(state, _): @@ -92,8 +95,7 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for i in range(10): ds = dataset_ops.Dataset.from_tensors(make_sparse_fn(i+1)) result = ds.reduce(make_sparse_fn(0), reduce_fn) - with self.cached_session() as sess: - self.assertSparseValuesEqual(make_sparse_fn(i+1), sess.run(result)) + self.assertSparseValuesEqual(make_sparse_fn(i + 1), self.evaluate(result)) def testNested(self): @@ -115,10 +117,10 @@ class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): for i in range(10): ds = dataset_ops.Dataset.range(1, i + 1).map(map_fn) result = ds.reduce(map_fn(0), reduce_fn) - with self.cached_session() as sess: - result = sess.run(result) - self.assertEqual(((i + 1) * i) // 2, result["dense"]) - self.assertSparseValuesEqual(make_sparse_fn(i), result["sparse"]) + result = self.evaluate(result) + self.assertEqual(((i + 1) * i) // 2, result["dense"]) + self.assertSparseValuesEqual(make_sparse_fn(i), result["sparse"]) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/save_restore_experimental_test.py b/tensorflow/python/data/kernel_tests/save_restore_experimental_test.py new file mode 100644 index 0000000000..c07d24ef6e --- /dev/null +++ b/tensorflow/python/data/kernel_tests/save_restore_experimental_test.py @@ -0,0 +1,686 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for the experimental saving and restoring input pipeline.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os + +from tensorflow.python.data.kernel_tests import reader_dataset_ops_test +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.ops import iterator_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_shape +from tensorflow.python.ops import gen_dataset_ops +from tensorflow.python.ops import io_ops +from tensorflow.python.ops import parsing_ops +from tensorflow.python.ops import variables +from tensorflow.python.platform import gfile +from tensorflow.python.platform import test + + +class ExperimentalCheckpointFixedLengthRecordReaderTest( + reader_dataset_ops_test.FixedLengthRecordReaderTestBase): + + def tearDown(self): + # Remove all checkpoint files. + prefix = self._iterator_checkpoint_prefix() + pattern = prefix + "*" + files = gfile.Glob(pattern) + map(gfile.Remove, files) + + def _iterator_checkpoint_prefix(self): + return os.path.join(self.get_temp_dir(), "iterator") + + def _save_op(self, iterator_resource): + iterator_state_variant = gen_dataset_ops.serialize_iterator( + iterator_resource) + save_op = io_ops.write_file( + self._iterator_checkpoint_prefix(), + parsing_ops.serialize_tensor(iterator_state_variant)) + return save_op + + def _restore_op(self, iterator_resource): + iterator_state_variant = parsing_ops.parse_tensor( + io_ops.read_file(self._iterator_checkpoint_prefix()), dtypes.variant) + restore_op = gen_dataset_ops.deserialize_iterator(iterator_resource, + iterator_state_variant) + return restore_op + + def testSaveRestore(self): + + def _build_graph(start, stop): + iterator = dataset_ops.Dataset.range(start, + stop).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + break_point = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(init_op) + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + # Saving and restoring in same session. + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testRestoreWithoutBuildingDatasetGraph(self): + + def _build_graph(start, stop, num_epochs): + dataset = dataset_ops.Dataset.range(start, stop).repeat(num_epochs) + iterator = dataset.make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + num_epochs = 5 + break_point = 5 + break_epoch = 3 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for _ in range(break_epoch): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + # Create an empty IteratorResource and restore the Iterator into it. + output_types = dtypes.int64 + output_shapes = tensor_shape.scalar() + iterator = iterator_ops.Iterator.from_structure(output_types, + output_shapes) + restore_op = self._restore_op(iterator._iterator_resource) + get_next = iterator.get_next() + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + for _ in range(break_epoch + 1, num_epochs): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testRestoreInModifiedGraph(self): + + def _build_graph(start, stop): + dataset = dataset_ops.Dataset.range(start, stop) + iterator = dataset.make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + stop_1 = 8 + break_point = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + # Intentionally build a graph with a different value for stop to make sure + # the original dataset graph is actually getting loaded. + init_op, get_next, _, restore_op = _build_graph(start, stop_1) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testInitThenRestore(self): + # Note: Calling init_op before restore_op is redundant. This test just makes + # sure we do not fail if restore is called on an already initialized + # iterator resource. + + def _build_graph(start, stop): + dataset = dataset_ops.Dataset.range(start, stop) + iterator = dataset.make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + break_point = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(init_op) + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testMultipleSaves(self): + + def _build_graph(start, stop): + iterator = dataset_ops.Dataset.range(start, + stop).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + start = 2 + stop = 10 + break_point1 = 5 + break_point2 = 7 + + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point1): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point1, break_point2): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + break_point2 = 7 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point2, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testSaveRestoreWithRepeat(self): + + def _build_graph(start, stop, num_epochs): + iterator = dataset_ops.Dataset.range( + start, stop).repeat(num_epochs).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + start = 2 + stop = 10 + num_epochs = 5 + break_range = 5 + break_epoch = 3 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph( + start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + # Note: There is no checkpoint saved currently so a NotFoundError is + # raised. + with self.assertRaises(errors.NotFoundError): + sess.run(restore_op) + for _ in range(break_epoch - 1): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + for i in range(start, break_range): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_range, stop): + self.assertEqual(i, sess.run(get_next)) + for _ in range(break_epoch, num_epochs): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testSaveRestoreExhaustedIterator(self): + + def _build_graph(start, stop, num_epochs): + iterator = dataset_ops.Dataset.range( + start, stop).repeat(num_epochs).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + start = 2 + stop = 10 + num_epochs = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph( + start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + # Note: There is no checkpoint saved currently so a NotFoundError is + # raised. + with self.assertRaises(errors.NotFoundError): + sess.run(restore_op) + for _ in range(num_epochs): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(restore_op) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + +class ExperimentalCheckpointRangeTest(test_base.DatasetTestBase): + + def tearDown(self): + # Remove all checkpoint files. + prefix = self._iterator_checkpoint_prefix() + pattern = prefix + "*" + files = gfile.Glob(pattern) + map(gfile.Remove, files) + + def _iterator_checkpoint_prefix(self): + return os.path.join(self.get_temp_dir(), "iterator") + + def _save_op(self, iterator_resource): + iterator_state_variant = gen_dataset_ops.serialize_iterator( + iterator_resource) + save_op = io_ops.write_file( + self._iterator_checkpoint_prefix(), + parsing_ops.serialize_tensor(iterator_state_variant)) + return save_op + + def _restore_op(self, iterator_resource): + iterator_state_variant = parsing_ops.parse_tensor( + io_ops.read_file(self._iterator_checkpoint_prefix()), dtypes.variant) + restore_op = gen_dataset_ops.deserialize_iterator(iterator_resource, + iterator_state_variant) + return restore_op + + def testSaveRestore(self): + + def _build_graph(start, stop): + iterator = dataset_ops.Dataset.range(start, + stop).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + break_point = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(init_op) + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + # Saving and restoring in same session. + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testRestoreWithoutBuildingDatasetGraph(self): + + def _build_graph(start, stop, num_epochs): + dataset = dataset_ops.Dataset.range(start, stop).repeat(num_epochs) + iterator = dataset.make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + num_epochs = 5 + break_point = 5 + break_epoch = 3 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for _ in range(break_epoch): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + # Create an empty IteratorResource and restore the Iterator into it. + output_types = dtypes.int64 + output_shapes = tensor_shape.scalar() + iterator = iterator_ops.Iterator.from_structure(output_types, + output_shapes) + restore_op = self._restore_op(iterator._iterator_resource) + get_next = iterator.get_next() + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + for _ in range(break_epoch + 1, num_epochs): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testRestoreInModifiedGraph(self): + + def _build_graph(start, stop): + dataset = dataset_ops.Dataset.range(start, stop) + iterator = dataset.make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + stop_1 = 8 + break_point = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + # Intentionally build a graph with a different value for stop to make sure + # the original dataset graph is actually getting loaded. + init_op, get_next, _, restore_op = _build_graph(start, stop_1) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testInitThenRestore(self): + # Note: Calling init_op before restore_op is redundant. This test just makes + # sure we do not fail if restore is called on an already initialized + # iterator resource. + + def _build_graph(start, stop): + dataset = dataset_ops.Dataset.range(start, stop) + iterator = dataset.make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + # Saving and restoring in different sessions. + start = 2 + stop = 10 + break_point = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(init_op) + sess.run(restore_op) + for i in range(break_point, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testMultipleSaves(self): + + def _build_graph(start, stop): + iterator = dataset_ops.Dataset.range(start, + stop).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + start = 2 + stop = 10 + break_point1 = 5 + break_point2 = 7 + + with ops.Graph().as_default() as g: + init_op, get_next, save_op, _ = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + for i in range(start, break_point1): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point1, break_point2): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + break_point2 = 7 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph(start, stop) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_point2, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testSaveRestoreWithRepeat(self): + + def _build_graph(start, stop, num_epochs): + iterator = dataset_ops.Dataset.range( + start, stop).repeat(num_epochs).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + start = 2 + stop = 10 + num_epochs = 5 + break_range = 5 + break_epoch = 3 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph( + start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + # Note: There is no checkpoint saved currently so a NotFoundError is + # raised. + with self.assertRaises(errors.NotFoundError): + sess.run(restore_op) + for _ in range(break_epoch - 1): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + for i in range(start, break_range): + self.assertEqual(i, sess.run(get_next)) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(restore_op) + for i in range(break_range, stop): + self.assertEqual(i, sess.run(get_next)) + for _ in range(break_epoch, num_epochs): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + def testSaveRestoreExhaustedIterator(self): + + def _build_graph(start, stop, num_epochs): + iterator = dataset_ops.Dataset.range( + start, stop).repeat(num_epochs).make_initializable_iterator() + init_op = iterator.initializer + get_next = iterator.get_next() + save_op = self._save_op(iterator._iterator_resource) + restore_op = self._restore_op(iterator._iterator_resource) + return init_op, get_next, save_op, restore_op + + start = 2 + stop = 10 + num_epochs = 5 + with ops.Graph().as_default() as g: + init_op, get_next, save_op, restore_op = _build_graph( + start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(variables.global_variables_initializer()) + sess.run(init_op) + # Note: There is no checkpoint saved currently so a NotFoundError is + # raised. + with self.assertRaises(errors.NotFoundError): + sess.run(restore_op) + for _ in range(num_epochs): + for i in range(start, stop): + self.assertEqual(i, sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + sess.run(save_op) + + with ops.Graph().as_default() as g: + init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) + with self.session(graph=g) as sess: + sess.run(restore_op) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/window_dataset_op_test.py b/tensorflow/python/data/kernel_tests/window_dataset_op_test.py index 9d06781094..7124cc75f1 100644 --- a/tensorflow/python/data/kernel_tests/window_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/window_dataset_op_test.py @@ -22,14 +22,17 @@ import numpy as np from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.util import nest from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test +@test_util.run_all_in_graph_and_eager_modes class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( @@ -62,65 +65,50 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], np.array(37.0) * np.arange(7)) - count_t = array_ops.placeholder(dtypes.int64, shape=[]) - size_t = array_ops.placeholder(dtypes.int64, shape=[]) - shift_t = array_ops.placeholder(dtypes.int64, shape=[]) - stride_t = array_ops.placeholder(dtypes.int64, shape=[]) - drop_remainder_t = array_ops.placeholder(dtypes.bool, shape=[]) - def _map_fn(x, y, z): return math_ops.square(x), math_ops.square(y), math_ops.square(z) def _flat_map_fn(x, y, z): - return dataset_ops.Dataset.zip((x.batch(batch_size=size_t), - y.batch(batch_size=size_t), - z.batch(batch_size=size_t))) + return dataset_ops.Dataset.zip((x.batch(batch_size=size), + y.batch(batch_size=size), + z.batch(batch_size=size))) - iterator = dataset_ops.Dataset.from_tensor_slices(components).map( + dataset = dataset_ops.Dataset.from_tensor_slices(components).map( _map_fn).repeat(count).window( - size=size_t, - shift=shift_t, - stride=stride_t, - drop_remainder=drop_remainder_t).flat_map( - _flat_map_fn).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - self.assertEqual([[None] + list(c.shape[1:]) for c in components], - [t.shape.as_list() for t in get_next]) - - with self.cached_session() as sess: - sess.run( - init_op, - feed_dict={ - count_t: count, - size_t: size, - shift_t: shift, - stride_t: stride, - drop_remainder_t: drop_remainder - }) - num_full_batches = max( - 0, (count * 7 - ((size - 1) * stride + 1)) // shift + 1) - for i in range(num_full_batches): - result = sess.run(get_next) + size=size, + shift=shift, + stride=stride, + drop_remainder=drop_remainder).flat_map(_flat_map_fn) + get_next = self.getNext(dataset) + + self.assertEqual( + [[None] + list(c.shape[1:]) for c in components], + [ts.as_list() for ts in nest.flatten(dataset.output_shapes)]) + + num_full_batches = max(0, + (count * 7 - ((size - 1) * stride + 1)) // shift + 1) + for i in range(num_full_batches): + result = self.evaluate(get_next()) + for component, result_component in zip(components, result): + for j in range(size): + self.assertAllEqual(component[(i * shift + j * stride) % 7]**2, + result_component[j]) + if not drop_remainder: + num_partial_batches = (count * 7) // shift + ( + (count * 7) % shift > 0) - num_full_batches + for i in range(num_partial_batches): + result = self.evaluate(get_next()) for component, result_component in zip(components, result): - for j in range(size): - self.assertAllEqual(component[(i * shift + j * stride) % 7]**2, - result_component[j]) - if not drop_remainder: - num_partial_batches = (count * 7) // shift + ( - (count * 7) % shift > 0) - num_full_batches - for i in range(num_partial_batches): - result = sess.run(get_next) - for component, result_component in zip(components, result): - remaining = (count * 7) - ((num_full_batches + i) * shift) - num_elements = remaining // stride + ((remaining % stride) > 0) - for j in range(num_elements): - self.assertAllEqual( - component[((num_full_batches + i) * shift + j * stride) % 7] - **2, result_component[j]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + remaining = (count * 7) - ((num_full_batches + i) * shift) + num_elements = remaining // stride + ((remaining % stride) > 0) + for j in range(num_elements): + self.assertAllEqual( + component[((num_full_batches + i) * shift + j * stride) % 7]**2, + result_component[j]) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) @parameterized.named_parameters( ("1", 14, 0, 3, 1), @@ -128,28 +116,12 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): ("3", 14, 3, 3, 0), ) def testWindowDatasetInvalid(self, count, size, shift, stride): - count_t = array_ops.placeholder(dtypes.int64, shape=[]) - size_t = array_ops.placeholder(dtypes.int64, shape=[]) - shift_t = array_ops.placeholder(dtypes.int64, shape=[]) - stride_t = array_ops.placeholder(dtypes.int64, shape=[]) - - iterator = dataset_ops.Dataset.range(10).map(lambda x: x).repeat( - count_t).window( - size=size_t, shift=shift_t, - stride=stride_t).flat_map(lambda x: x.batch(batch_size=size_t) - ).make_initializable_iterator() - init_op = iterator.initializer - - with self.cached_session() as sess: - with self.assertRaises(errors.InvalidArgumentError): - sess.run( - init_op, - feed_dict={ - count_t: count, - size_t: size, - shift_t: shift, - stride_t: stride - }) + dataset = dataset_ops.Dataset.range(10).map(lambda x: x).repeat( + count).window( + size=size, shift=shift, + stride=stride).flat_map(lambda x: x.batch(batch_size=size)) + self.assertDatasetProduces( + dataset, expected_error=(errors.InvalidArgumentError, "")) def testWindowSparse(self): @@ -157,25 +129,18 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): return sparse_tensor.SparseTensorValue( indices=[[0]], values=(i * [1]), dense_shape=[1]) - iterator = dataset_ops.Dataset.range(10).map(_sparse).window( - size=5, shift=3, drop_remainder=True).flat_map( - lambda x: x.batch(batch_size=5)).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() + dataset = dataset_ops.Dataset.range(10).map(_sparse).window( + size=5, shift=3, + drop_remainder=True).flat_map(lambda x: x.batch(batch_size=5)) - with self.cached_session() as sess: - sess.run(init_op) - num_batches = (10 - 5) // 3 + 1 - for i in range(num_batches): - actual = sess.run(get_next) - expected = sparse_tensor.SparseTensorValue( + num_batches = (10 - 5) // 3 + 1 + expected_output = [ + sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 3, i * 3 + 1, i * 3 + 2, i * 3 + 3, i * 3 + 4], - dense_shape=[5, 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dense_shape=[5, 1]) for i in range(num_batches) + ] + self.assertDatasetProduces(dataset, expected_output=expected_output) def testWindowSparseWithDifferentDenseShapes(self): @@ -186,31 +151,25 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): values=array_ops.fill([math_ops.to_int32(i)], i), dense_shape=[i]) - iterator = dataset_ops.Dataset.range(10).map(_sparse).window( - size=5, shift=3, drop_remainder=True).flat_map( - lambda x: x.batch(batch_size=5)).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - num_batches = (10 - 5) // 3 + 1 - for i in range(num_batches): - actual = sess.run(get_next) - expected_indices = [] - expected_values = [] - for j in range(5): - for k in range(i * 3 + j): - expected_indices.append([j, k]) - expected_values.append(i * 3 + j) - expected = sparse_tensor.SparseTensorValue( - indices=expected_indices, - values=expected_values, - dense_shape=[5, i * 3 + 5 - 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + dataset = dataset_ops.Dataset.range(10).map(_sparse).window( + size=5, shift=3, + drop_remainder=True).flat_map(lambda x: x.batch(batch_size=5)) + + expected_output = [] + num_batches = (10 - 5) // 3 + 1 + for i in range(num_batches): + expected_indices = [] + expected_values = [] + for j in range(5): + for k in range(i * 3 + j): + expected_indices.append([j, k]) + expected_values.append(i * 3 + j) + expected_output.append( + sparse_tensor.SparseTensorValue( + indices=expected_indices, + values=expected_values, + dense_shape=[5, i * 3 + 5 - 1])) + self.assertDatasetProduces(dataset, expected_output=expected_output) def testNestedWindowSparse(self): @@ -218,38 +177,27 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): return sparse_tensor.SparseTensorValue( indices=[[0]], values=(i * [1]), dense_shape=[1]) - iterator = dataset_ops.Dataset.range(10).map(_sparse).window( + dataset = dataset_ops.Dataset.range(10).map(_sparse).window( size=4, shift=2, drop_remainder=True).flat_map(lambda x: x.batch(batch_size=4)).window( - size=3, shift=1, drop_remainder=True).flat_map( - lambda x: x.batch(batch_size=3)).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - # Slide: 1st batch. - actual = sess.run(get_next) - expected = sparse_tensor.SparseTensorValue( - indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 0], - [1, 1, 0], [1, 2, 0], [1, 3, 0], [2, 0, 0], [2, 1, 0], - [2, 2, 0], [2, 3, 0]], - values=[0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7], - dense_shape=[3, 4, 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - # Slide: 2nd batch. - actual = sess.run(get_next) - expected = sparse_tensor.SparseTensorValue( - indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 0], - [1, 1, 0], [1, 2, 0], [1, 3, 0], [2, 0, 0], [2, 1, 0], - [2, 2, 0], [2, 3, 0]], - values=[2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9], - dense_shape=[3, 4, 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + size=3, shift=1, + drop_remainder=True).flat_map(lambda x: x.batch(batch_size=3)) + + expected_output = [ + sparse_tensor.SparseTensorValue( + indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 0], + [1, 1, 0], [1, 2, 0], [1, 3, 0], [2, 0, 0], [2, 1, 0], + [2, 2, 0], [2, 3, 0]], + values=[0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7], + dense_shape=[3, 4, 1]), + sparse_tensor.SparseTensorValue( + indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [1, 0, 0], + [1, 1, 0], [1, 2, 0], [1, 3, 0], [2, 0, 0], [2, 1, 0], + [2, 2, 0], [2, 3, 0]], + values=[2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9], + dense_shape=[3, 4, 1]) + ] + self.assertDatasetProduces(dataset, expected_output=expected_output) def testWindowShapeError(self): @@ -258,19 +206,15 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): yield [4.0, 5.0, 6.0] yield [7.0, 8.0, 9.0, 10.0] - iterator = dataset_ops.Dataset.from_generator( + dataset = dataset_ops.Dataset.from_generator( generator, dtypes.float32, output_shapes=[None]).window( - size=3, shift=1).flat_map( - lambda x: x.batch(batch_size=3)).make_initializable_iterator() - next_element = iterator.get_next() - - with self.cached_session() as sess: - sess.run(iterator.initializer) - with self.assertRaisesRegexp( - errors.InvalidArgumentError, - r"Cannot batch tensors with different shapes in component 0. " - r"First element had shape \[3\] and element 2 had shape \[4\]."): - sess.run(next_element) + size=3, shift=1).flat_map(lambda x: x.batch(batch_size=3)) + self.assertDatasetProduces( + dataset, + expected_error=( + errors.InvalidArgumentError, + r"Cannot batch tensors with different shapes in component 0. " + r"First element had shape \[3\] and element 2 had shape \[4\].")) def testWindowIgnoreErrors(self): input_values = np.float32([1., np.nan, 2., np.nan, 3.]) @@ -278,13 +222,9 @@ class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): lambda x: array_ops.check_numerics(x, "message")).window( size=2, shift=2, stride=2, drop_remainder=True).flat_map(lambda x: x.batch(batch_size=2)) - get_next = dataset.make_one_shot_iterator().get_next() - - with self.cached_session() as sess: - self.assertAllEqual(np.float32([1., 2.]), sess.run(get_next)) - self.assertAllEqual(np.float32([2., 3.]), sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.assertDatasetProduces( + dataset, expected_output=[np.float32([1., 2.]), + np.float32([2., 3.])]) if __name__ == "__main__": -- GitLab From 34b20ffd2a0f370a4992c3dab915dbc832e374b5 Mon Sep 17 00:00:00 2001 From: Dan Moldovan Date: Mon, 26 Nov 2018 12:01:33 -0800 Subject: [PATCH 320/672] Re-enable previously disabled tests. PiperOrigin-RevId: 222863222 --- tensorflow/examples/autograph/integration_tests/BUILD | 2 -- tensorflow/python/autograph/converters/BUILD | 2 -- tensorflow/python/autograph/impl/BUILD | 2 -- tensorflow/python/autograph/pyct/BUILD | 2 -- tensorflow/python/autograph/pyct/static_analysis/BUILD | 2 -- tensorflow/python/eager/BUILD | 6 ------ 6 files changed, 16 deletions(-) diff --git a/tensorflow/examples/autograph/integration_tests/BUILD b/tensorflow/examples/autograph/integration_tests/BUILD index d20c17b63b..2a4a0f75e7 100644 --- a/tensorflow/examples/autograph/integration_tests/BUILD +++ b/tensorflow/examples/autograph/integration_tests/BUILD @@ -22,7 +22,6 @@ py_test( "keras_test.py", ], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ "//tensorflow:tensorflow_py", ], @@ -34,7 +33,6 @@ py_test( "list_literals_test.py", ], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ "//tensorflow:tensorflow_py", ], diff --git a/tensorflow/python/autograph/converters/BUILD b/tensorflow/python/autograph/converters/BUILD index ced2e4796b..3ac446db02 100644 --- a/tensorflow/python/autograph/converters/BUILD +++ b/tensorflow/python/autograph/converters/BUILD @@ -63,7 +63,6 @@ py_test( name = "asserts_test", srcs = ["asserts_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":converters", "//tensorflow/python:client_testlib", @@ -239,7 +238,6 @@ py_test( name = "error_handlers_test", srcs = ["error_handlers_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":converters", "//tensorflow/python:client_testlib", diff --git a/tensorflow/python/autograph/impl/BUILD b/tensorflow/python/autograph/impl/BUILD index 2f9037c43b..201a888754 100644 --- a/tensorflow/python/autograph/impl/BUILD +++ b/tensorflow/python/autograph/impl/BUILD @@ -41,7 +41,6 @@ py_test( name = "api_test", srcs = ["api_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":impl", "//tensorflow/python:client_testlib", @@ -54,7 +53,6 @@ py_test( name = "conversion_test", srcs = ["conversion_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":impl", "//tensorflow/python:client_testlib", diff --git a/tensorflow/python/autograph/pyct/BUILD b/tensorflow/python/autograph/pyct/BUILD index ddadc6b96e..ba8ec27139 100644 --- a/tensorflow/python/autograph/pyct/BUILD +++ b/tensorflow/python/autograph/pyct/BUILD @@ -80,7 +80,6 @@ py_test( name = "compiler_test", srcs = ["compiler_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":pyct", "//tensorflow/python:client_testlib", @@ -154,7 +153,6 @@ py_test( name = "transformer_test", srcs = ["transformer_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":pyct", "//tensorflow/python:client_testlib", diff --git a/tensorflow/python/autograph/pyct/static_analysis/BUILD b/tensorflow/python/autograph/pyct/static_analysis/BUILD index 4a4ccdcbd1..5e260c5730 100644 --- a/tensorflow/python/autograph/pyct/static_analysis/BUILD +++ b/tensorflow/python/autograph/pyct/static_analysis/BUILD @@ -38,7 +38,6 @@ py_test( name = "activity_test", srcs = ["activity_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":static_analysis", "//tensorflow/python:client_testlib", @@ -51,7 +50,6 @@ py_test( name = "live_values_test", srcs = ["live_values_test.py"], srcs_version = "PY2AND3", - tags = ["no_windows"], deps = [ ":static_analysis", "//tensorflow/python:client_testlib", diff --git a/tensorflow/python/eager/BUILD b/tensorflow/python/eager/BUILD index d3457ed241..5a18afa0fc 100644 --- a/tensorflow/python/eager/BUILD +++ b/tensorflow/python/eager/BUILD @@ -189,9 +189,6 @@ cuda_py_test( "//tensorflow/python:resource_variable_ops", ], shard_count = 5, - tags = [ - "no_windows", - ], ) cuda_py_test( @@ -214,9 +211,6 @@ cuda_py_test( "//tensorflow/python:resource_variable_ops", ], shard_count = 15, - tags = [ - "no_windows", - ], ) py_library( -- GitLab From 968bb07ccc1871368addc2fbe07f61f1a91183a3 Mon Sep 17 00:00:00 2001 From: Martin Wicke Date: Mon, 26 Nov 2018 12:04:09 -0800 Subject: [PATCH 321/672] Remove flags module from v2 API. Use argparse or absl if you need flag parsing. PiperOrigin-RevId: 222863846 --- tensorflow/api_template.__init__.py | 2 -- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 4 ---- 2 files changed, 6 deletions(-) diff --git a/tensorflow/api_template.__init__.py b/tensorflow/api_template.__init__.py index 59b07e15b8..f13623b0d5 100644 --- a/tensorflow/api_template.__init__.py +++ b/tensorflow/api_template.__init__.py @@ -28,8 +28,6 @@ _component_api_helper.package_hook( # API IMPORTS PLACEHOLDER -from tensorflow.python.platform import flags # pylint: disable=g-import-not-at-top - # Make sure directory containing top level submodules is in # the __path__ so that "from tensorflow.foo import bar" works. # We're using bitwise, but there's nothing special about that. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 92ebdb91c5..a1e2e7be6f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -204,10 +204,6 @@ tf_module { name: "feature_column" mtype: "" } - member { - name: "flags" - mtype: "" - } member { name: "float16" mtype: "" -- GitLab From 107ae2e68de97434193070747e0fef8b597325e5 Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Mon, 26 Nov 2018 12:12:51 -0800 Subject: [PATCH 322/672] Optimize mkldnn pack. PiperOrigin-RevId: 222865206 --- .../core/kernels/eigen_spatial_convolutions.h | 182 ++++++++++-------- .../eigen_spatial_convolutions_test.cc | 103 +++++++--- 2 files changed, 179 insertions(+), 106 deletions(-) diff --git a/tensorflow/core/kernels/eigen_spatial_convolutions.h b/tensorflow/core/kernels/eigen_spatial_convolutions.h index 1f211b19b4..e8dea4763e 100644 --- a/tensorflow/core/kernels/eigen_spatial_convolutions.h +++ b/tensorflow/core/kernels/eigen_spatial_convolutions.h @@ -56,6 +56,7 @@ namespace internal { // // TODO(ezhulenev): Consolidate this part of the code with the image patch // extraction code since they are both very similar. + template { public: typedef Scalar_ Scalar; + typedef TensorContractionInputMapper< Scalar, Index, Side, TensorEvaluator< @@ -79,6 +81,7 @@ class TensorContractionInputMapper< nocontract_t, contract_t, packet_size, inner_dim_contiguous, inner_dim_reordered, Alignment> Self; + typedef TensorContractionSubMapper< Scalar, Index, Side, TensorEvaluator< @@ -88,6 +91,7 @@ class TensorContractionInputMapper< nocontract_t, contract_t, packet_size, inner_dim_contiguous, inner_dim_reordered, Alignment> SubMapper; + typedef SubMapper VectorMapper; typedef SubMapper LinearMapper; typedef typename packet_traits::type Packet; @@ -533,6 +537,7 @@ class TensorContractionSubMapper< nocontract_t, contract_t, packet_size, inner_dim_contiguous, inner_dim_reordered, Alignment> ParentMapper; + typedef TensorContractionSubMapper< Scalar, Index, Side, TensorEvaluator< @@ -542,6 +547,7 @@ class TensorContractionSubMapper< nocontract_t, contract_t, packet_size, inner_dim_contiguous, inner_dim_reordered, Alignment> Self; + typedef Self LinearMapper; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorContractionSubMapper( @@ -578,7 +584,6 @@ class TensorContractionSubMapper< return m_base_mapper.template loadPacket(i + m_depth_offset, j + m_col_offset); } - EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar loadCoeffStandard(Index i) const { return m_base_mapper.loadCoeffStandard(i + m_depth_offset, m_rowIndex, @@ -611,18 +616,29 @@ class TensorContractionSubMapper< EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index maxCol(const Index peeled_k) const { const Index max_col = - fastPatchColStride().divide(m_depth_offset + peeled_k); + (m_depth_offset + (peeled_k == 0 ? 0 : peeled_k - 1)) / + fastPatchColStride(); return std::min(1 + max_col, patchCols()); } EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index maxRow(const Index peeled_k, const Index col) const { - const Index max_row = fastPatchRowStride().divide( - m_depth_offset + peeled_k - col * patchColStride()); + const Index max_row = (m_depth_offset + (peeled_k == 0 ? 0 : peeled_k - 1) - + col * patchColStride()) / + fastPatchRowStride(); return std::min(1 + max_row, patchRows()); } + EIGEN_DEVICE_FUNC + EIGEN_ALWAYS_INLINE Index maxDepth(const Index peeled_k, const Index col, + Index row) const { + const Index max_depth = m_depth_offset + peeled_k - // + col * patchColStride() - // + row * patchRowStride(); + return std::min(max_depth, patchDepth()); + } + // MaxDepth uses only the remaining number of elements in the peeled_k. EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index maxDepth(const Index num_elements, @@ -692,6 +708,12 @@ class TensorContractionSubMapper< return r < 0 || r >= m_base_mapper.m_inputRows; } EIGEN_DEVICE_FUNC + EIGEN_ALWAYS_INLINE bool padAnyRow(const Index first_row, + const Index last_row) const { + return m_rowIndex + first_row < 0 || + m_rowIndex + last_row >= m_base_mapper.m_inputRows; + } + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool padCol(const Index col) const { const Index c = m_colIndex + col; return c < 0 || c >= m_base_mapper.m_inputCols; @@ -738,9 +760,6 @@ class TensorContractionSubMapper< } private: - const ParentMapper m_base_mapper; // Keeping a copy instead of a reference - // performs better in benchmarks. - Index m_depth_offset; // First row in the input matrix Index m_col_offset; // First col in the input matrix @@ -750,6 +769,9 @@ class TensorContractionSubMapper< Index m_rowIndex; Index m_colIndex; Index m_otherIndex; + + const ParentMapper m_base_mapper; // Keeping a copy instead of a reference + // performs better in benchmarks. }; // Arrange a block of the right input matrix (in our case it's always a "virtual @@ -1319,23 +1341,19 @@ struct mkldnn_gemm_pack< typedef typename packet_traits::type Packet; EIGEN_DONT_INLINE - void operator()(Scalar* block, const DataMapper& rhs, StorageIndex rows, + void operator()(Scalar* block, const DataMapper rhs, StorageIndex rows, StorageIndex cols) { const bool standard_patches = !rhs.nonStandardPatches(); if (standard_patches && (rhs.patchDepth() % packet_size == 0)) { - if (rhs.rowStride() == 1) { - packStandardPatches(block, rhs, rows, cols); - } else { - packStandardPatches(block, rhs, rows, cols); - } + // Single packet always belong to single patch (row, col). + packStandardPatches( + block, rhs, rows, cols); } else if (standard_patches) { - if (rhs.rowStride() == 1) { - packStandardPatches(block, rhs, rows, cols); - } else { - packStandardPatches(block, rhs, rows, cols); - } + // Single packet can span across multiple patch rows or columns. + packStandardPatches( + block, rhs, rows, cols); } else { // With non-standard patches we don't do any vectorized loads. @@ -1357,72 +1375,64 @@ struct mkldnn_gemm_pack< // - patch_depth_is_multiple_of_packet_size=true: We are guaranteed to have // depth dimension size to be a multiple of packet size, so we can skip all // non vectorized loads and checks. - // - // - squeeze_reads=true: If stride along the `row` dimension is `1`, we can - // squeeze reads along the `row` and `depth` dimensions, because they are - // guaranteed to be contiguous in memory (two innermost dimensions). - // - template + template EIGEN_ALWAYS_INLINE void packStandardPatches(Scalar* block, - const DataMapper& rhs, + const DataMapper rhs, StorageIndex rows, StorageIndex cols) { eigen_assert(!rhs.nonStandardPatches()); // Give vectorized_rows the name used in all other gemm_pack_rhs above. - const Index peeled_k = (rows / packet_size) * packet_size; + const StorageIndex peeled_k = (rows / packet_size) * packet_size; - const Index start_col = rhs.colOffset(); - const Index max_col = rhs.maxCol(peeled_k); + const StorageIndex start_col = rhs.colOffset(); + const StorageIndex max_col = rhs.maxCol(peeled_k); for (StorageIndex col = 0; col < cols; ++col) { SubMapper lm = rhs.getLinearMapper(0, col); - Index k = 0; + StorageIndex k = 0; for (Index c = start_col; c < max_col; ++c) { eigen_assert(k <= peeled_k); - const Index start_row = (c == start_col) ? rhs.rowOffset() : 0; - const Index max_row = rhs.maxRow(peeled_k, c); + const StorageIndex start_row = (c == start_col) ? rhs.rowOffset() : 0; + const StorageIndex max_row = rhs.maxRow(peeled_k, c); const bool pad_col = lm.padCol(c); // We can squeeze reads for all rows in [start_row, max_row) range. - if (squeeze_reads && !pad_col && !lm.padRow(start_row) && - !lm.padRow(max_row - 1)) { - const Index start_depth = (c == start_col) ? rhs.depthOffset() : 0; - - // Upper bound on the number of elements in the depth dimension that - // we can squeeze read. - const Index squeeze_length = - (max_row - start_row) * rhs.patchDepth() - start_depth; + if (!pad_col && !lm.padAnyRow(start_row, max_row - 1)) { + const StorageIndex start_depth = + (c == start_col) ? rhs.depthOffset() : 0; - // Do not overshoot beyond the block size. - const Index max_depth = - start_depth + std::min(peeled_k - k, squeeze_length); + const StorageIndex max_depth = + std::min(start_depth + (peeled_k - k), + (max_row - start_row) * rhs.patchDepth()); - const Index base_idx = lm.baseIndex(start_row, c); + const StorageIndex base_idx = lm.baseIndex(start_row, c); - if (patch_depth_is_multiple_of_packet_size) + if (patch_depth_is_multiple_of_packet_size) { + // If patch depth is a multiple of packet size, it's guaranteed that + // we can process all values in depth dimension with packets. eigen_assert((max_depth - start_depth) % packet_size == 0); + StorageIndex d = start_depth; - // If patch depth is a multiple of packet size, it's guaranteed that - // we can process all values in depth dimension with packets. - const Index max_vectorized_depth = - patch_depth_is_multiple_of_packet_size ? max_depth - : max_depth - packet_size; - - Index d = start_depth; + for (; d < max_depth; d += packet_size) { + eigen_assert(k < peeled_k); + internal::pstoreu(block, rhs.packetNoPadding(d, base_idx)); + block += packet_size; + k += packet_size; + } - // 1. Process depth dimension with vectorized instructions. - for (; d < max_vectorized_depth; d += packet_size) { - eigen_assert(k < peeled_k); - internal::pstoreu(block, rhs.packetNoPadding(d, base_idx)); - block += packet_size; - k += packet_size; - } + } else { + StorageIndex d = start_depth; + const StorageIndex vectorized_depth = max_depth - packet_size; - // 2. Finish with coefficients. - if (!patch_depth_is_multiple_of_packet_size) { + for (; d <= vectorized_depth; d += packet_size) { + eigen_assert(k < peeled_k); + internal::pstoreu(block, rhs.packetNoPadding(d, base_idx)); + block += packet_size; + k += packet_size; + } for (; d < max_depth; d++) { eigen_assert(k < peeled_k); *block = rhs.coeffNoPadding(d, base_idx); @@ -1437,39 +1447,43 @@ struct mkldnn_gemm_pack< // If we are not allowed to squeeze reads along the `row` and `depth` // dimensions, we must process rows one by one. - for (Index r = start_row; r < max_row; ++r) { + for (StorageIndex r = start_row; r < max_row; ++r) { eigen_assert(k <= peeled_k); - const Index start_depth = + const StorageIndex start_depth = ((c == start_col) && (r == start_row)) ? rhs.depthOffset() : 0; - const Index max_depth = rhs.maxDepth(peeled_k - k, start_depth); + const StorageIndex max_depth = + rhs.maxDepth(peeled_k - k, start_depth); const bool pad = pad_col || lm.padRow(r); - const Index base_idx = lm.baseIndex(r, c); + const StorageIndex base_idx = lm.baseIndex(r, c); - if (patch_depth_is_multiple_of_packet_size) + if (patch_depth_is_multiple_of_packet_size) { + // If patch depth is a multiple of packet size, it's guaranteed that + // we can process all values in depth dimension with packets. eigen_assert((max_depth - start_depth) % packet_size == 0); + StorageIndex d = start_depth; - // If patch depth is a multiple of packet size, it's guaranteed that - // we can process all values in depth dimension with packets. - const Index max_vectorized_depth = - patch_depth_is_multiple_of_packet_size ? max_depth - : max_depth - packet_size; - - Index d = start_depth; - - // 1. Process depth dimension with vectorized instructions. - for (; d < max_vectorized_depth; d += packet_size) { - eigen_assert(k < peeled_k); - const Packet p = pad ? pset1(Scalar(0)) - : rhs.packetNoPadding(d, base_idx); - internal::pstoreu(block, p); - block += packet_size; - k += packet_size; - } + for (; d < max_depth; d += packet_size) { + eigen_assert(k < peeled_k); + const Packet p = pad ? pset1(Scalar(0)) + : rhs.packetNoPadding(d, base_idx); + internal::pstoreu(block, p); + block += packet_size; + k += packet_size; + } - // 2. Finish with coefficients. - if (!patch_depth_is_multiple_of_packet_size) { + } else { + const StorageIndex max_vectorized_depth = max_depth - packet_size; + StorageIndex d = start_depth; + for (; d < max_vectorized_depth; d += packet_size) { + eigen_assert(k < peeled_k); + const Packet p = pad ? pset1(Scalar(0)) + : rhs.packetNoPadding(d, base_idx); + internal::pstoreu(block, p); + block += packet_size; + k += packet_size; + } for (; d < max_depth; d++) { eigen_assert(k < peeled_k); *block = pad ? Scalar(0) : rhs.coeffNoPadding(d, base_idx); diff --git a/tensorflow/core/kernels/eigen_spatial_convolutions_test.cc b/tensorflow/core/kernels/eigen_spatial_convolutions_test.cc index 8219fc9025..22f71d6260 100644 --- a/tensorflow/core/kernels/eigen_spatial_convolutions_test.cc +++ b/tensorflow/core/kernels/eigen_spatial_convolutions_test.cc @@ -1380,7 +1380,12 @@ static void PackRhsHelper(int iters, /* Filter (kernel) dimensions: */ int filter_count, int filter_cols, int filter_rows, /* Input strides: */ - int col_strides, int row_strides) { + int col_strides, int row_strides, + /* Block dimensions: */ + Index block_rows, Index block_cols) { + // Set random seed for benchmark repeatability. + srand(12345); + tensorflow::testing::UseRealTime(); tensorflow::testing::StopTiming(); @@ -1508,10 +1513,6 @@ static void PackRhsHelper(int iters, PackRhsImpl pack_rhs; - // This is the typical size of the rhs block used in Tensor contractions. - const Index default_depth = 320; // must be multiple of 8 - const Index default_cols = 280; - const Index packed_total_size = input_dims.TotalSize(); tensorflow::testing::StartTiming(); @@ -1520,11 +1521,14 @@ static void PackRhsHelper(int iters, num_inputs == 1 ? 1 : internal::random(0, num_inputs - 1); // Depth offset must be a multiple of 8 (float packet size with AVX2). - Index depth_offset = (internal::random(0, patch_size - 10) / 8) * 8; + Index depth_offset = + (patch_size > block_rows) + ? (internal::random(0, patch_size - 10) / 8) * 8 + : 0; Index col_offset = internal::random(0, num_patches - 10); - Index depth = std::min(default_depth, patch_size - depth_offset); - Index cols = std::min(default_cols, num_patches - col_offset); + Index depth = std::min(block_rows, patch_size - depth_offset); + Index cols = std::min(block_cols, num_patches - col_offset); // Write packed data to random memory location to emulate cold caches. Index packed_size = depth * cols; @@ -1538,20 +1542,37 @@ static void PackRhsHelper(int iters, tensorflow::testing::StopTiming(); std::ostringstream stringStream; - stringStream << "patch: depth=" << patch_depth << " rows=" << patch_rows - << " cols=" << patch_cols << " num_patches=" << num_patches + stringStream << "patch: " << patch_rows << "x" << patch_cols << " D" + << patch_depth << "; num_patches=" << num_patches << " patch_size=" << patch_size << " num_inputs=" << num_inputs; tensorflow::testing::SetLabel(stringStream.str()); } -#define BM_NAME(prefix, N, H, W, C, FC, FH, FW, SH, SW) \ - BM_##prefix##_##N##_##H##x##W##_IC##C##_FC##FC##_##FH##x##FW##_s##SH##x##SW - -#define BM_PackRhs(N, H, W, C, FC, FH, FW, SH, SW) \ - static void BM_NAME(PackRhs, N, H, W, C, FC, FH, FW, SH, SW)(int iters) { \ - PackRhsHelper(iters, N, H, W, C, FC, FH, FW, SH, SW); \ - } \ - BENCHMARK(BM_NAME(PackRhs, N, H, W, C, FC, FH, FW, SH, SW)) +// -------------------------------------------------------------------------- // +// Macro argumentnames: +// N: batch size +// H: height +// W: width +// C: input channels +// FC: filter channles +// FH: filter height +// SH: stride in height dimensions +// SW: stride in width dimensions +// BR: block rows +// BC: block cols + +#define BM_CONCAT(a, b) a##b + +#define BM_NAME(prefix, N, H, W, C, FC, FH, FW, SH, SW, BR, BC) \ + BM_CONCAT(BM_##prefix##_##N##_##H##x##W##_IC##C##_FC##FC##_##FH##x##FW, \ + _s##SH##x##SW##_B##BR##x##BC) + +#define BM_PackRhs(N, H, W, C, FC, FH, FW, SH, SW, BR, BC) \ + static void BM_NAME(PackRhs, N, H, W, C, FC, FH, FW, SH, SW, BR, \ + BC)(int iters) { \ + PackRhsHelper(iters, N, H, W, C, FC, FH, FW, SH, SW, BR, BC); \ + } \ + BENCHMARK(BM_NAME(PackRhs, N, H, W, C, FC, FH, FW, SH, SW, BR, BC)) // Number of input channel (input depth) it equal to the number of patch // channels (patch depth). @@ -1563,14 +1584,16 @@ BM_PackRhs(/*batch*/ 32, // /*channels*/ 32, // /*num_filters*/ 64, // /*filter*/ 5, 5, // - /*stride*/ 1, 1); + /*stride*/ 1, 1, // + /*block*/ 256, 56); BM_PackRhs(/*batch*/ 32, // /*image*/ 64, 64, // /*channels*/ 32, // /*num_filters*/ 64, // /*filter*/ 5, 5, // - /*stride*/ 2, 2); + /*stride*/ 2, 2, // + /*block*/ 256, 56); // Slow path: input channel dimension is not the multiple of the packet size. BM_PackRhs(/*batch*/ 32, // @@ -1578,12 +1601,48 @@ BM_PackRhs(/*batch*/ 32, // /*channels*/ 30, // /*num_filters*/ 64, // /*filter*/ 5, 5, // - /*stride*/ 1, 1); + /*stride*/ 1, 1, // + /*block*/ 256, 56); BM_PackRhs(/*batch*/ 32, // /*image*/ 64, 64, // /*channels*/ 30, // /*num_filters*/ 64, // /*filter*/ 5, 5, // - /*stride*/ 2, 2); + /*stride*/ 2, 2, // + /*block*/ 256, 56); + +// Slow path with input channel dimension smaller than the packet size. +BM_PackRhs(/*batch*/ 32, // + /*image*/ 256, 256, // + /*channels*/ 4, // + /*num_filters*/ 16, // + /*filter*/ 8, 8, // + /*stride*/ 1, 1, // + /*block*/ 256, 56); + +BM_PackRhs(/*batch*/ 32, // + /*image*/ 256, 256, // + /*channels*/ 4, // + /*num_filters*/ 16, // + /*filter*/ 8, 8, // + /*stride*/ 2, 4, // + /*block*/ 256, 56); + +// Short and wide block with small input channel dimension. +BM_PackRhs(/*batch*/ 32, // + /*image*/ 64, 64, // + /*channels*/ 4, // + /*num_filters*/ 16, // + /*filter*/ 3, 3, // + /*stride*/ 1, 1, // + /*block*/ 36, 432); + +BM_PackRhs(/*batch*/ 32, // + /*image*/ 64, 64, // + /*channels*/ 4, // + /*num_filters*/ 16, // + /*filter*/ 3, 3, // + /*stride*/ 2, 2, // + /*block*/ 36, 432); } // namespace Eigen -- GitLab From f4b03c1c82906566852a117c2e452b0f7798874f Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Mon, 26 Nov 2018 12:44:55 -0800 Subject: [PATCH 323/672] Add negative offset to filter to properly test Relu activation. PiperOrigin-RevId: 222869970 --- tensorflow/core/kernels/conv_ops_test.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tensorflow/core/kernels/conv_ops_test.cc b/tensorflow/core/kernels/conv_ops_test.cc index 252467f27c..ef27dfec54 100644 --- a/tensorflow/core/kernels/conv_ops_test.cc +++ b/tensorflow/core/kernels/conv_ops_test.cc @@ -707,8 +707,10 @@ class FusedConv2DOpTest : public OpsTestBase { Tensor image(dtype, {image_batch_count, image_height, image_width, depth}); image.flat() = image.flat().setRandom(); + // Add some negative values to filter to properly test Relu. Tensor filter(dtype, {filter_size, filter_size, depth, filter_count}); filter.flat() = filter.flat().setRandom(); + filter.flat() -= filter.flat().constant(static_cast(0.5f)); const int bias_size = filter_count; Tensor bias(dtype, {bias_size}); @@ -744,8 +746,10 @@ class FusedConv2DOpTest : public OpsTestBase { Tensor image(dtype, {image_batch_count, image_height, image_width, depth}); image.flat() = image.flat().setRandom(); + // Add some negative values to filter to properly test Relu. Tensor filter(dtype, {filter_size, filter_size, depth, filter_count}); filter.flat() = filter.flat().setRandom(); + filter.flat() -= filter.flat().constant(static_cast(0.5f)); const int scale_size = filter_count; -- GitLab From e67c4e41c8d787240813a5533cb9a31465fb9ac6 Mon Sep 17 00:00:00 2001 From: Yanan Cao Date: Mon, 26 Nov 2018 13:10:27 -0800 Subject: [PATCH 324/672] ArgMax custom call kernel should support negative dim argument PiperOrigin-RevId: 222874198 --- .../compiler/tf2xla/kernels/index_ops_cpu.cc | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc index 42bf4b06e5..dce9641f63 100644 --- a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc +++ b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc @@ -50,21 +50,24 @@ class ArgMaxCustomCallOp : public XlaOpKernel { // overhead, when compiling ahead-of-time. int64 dim; OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntScalar(1, &dim)); - OP_REQUIRES(ctx, dim >= 0, errors::InvalidArgument("dim must be >= 0")); - OP_REQUIRES( - ctx, dim < input_shape.dims(), - errors::InvalidArgument("dim must be < input rank (", - input_shape.dims(), "), but got: ", dim)); - const int64 dim_size = input_shape.dim_size(dim); - OP_REQUIRES(ctx, dim_size > 0, + + const int input_dims = input_shape.dims(); + const int axis = dim < 0 ? dim + input_dims : dim; + OP_REQUIRES(ctx, axis >= 0 && axis < input_dims, + errors::InvalidArgument("Expected dimension in the range [", + -input_dims, ", ", input_dims, + "), but got ", dim)); + + const int64 axis_size = input_shape.dim_size(axis); + OP_REQUIRES(ctx, axis_size > 0, errors::InvalidArgument( "Reduction axis ", dim, " is empty in shape: ", input_shape.DebugString())); - // The output shape is the input shape contracted along dim. + // The output shape is the input shape contracted along axis. TensorShape output_shape; for (int d = 0; d < input_shape.dims() - 1; ++d) { - output_shape.AddDim(input_shape.dim_size((d < dim) ? d : d + 1)); + output_shape.AddDim(input_shape.dim_size((d < axis) ? d : d + 1)); } // For now we use a custom-call, only for the 1d and 2d cases. @@ -84,7 +87,7 @@ class ArgMaxCustomCallOp : public XlaOpKernel { args.push_back(xla::ConstantLiteral( &b, xla::LiteralUtil::CreateR1(output_shape.dim_sizes()))); args.push_back( - xla::ConstantLiteral(&b, xla::LiteralUtil::CreateR0(dim))); + xla::ConstantLiteral(&b, xla::LiteralUtil::CreateR0(axis))); } // The argmax function expects row-major layout. -- GitLab From 9e98765f10503ca9f4a60373966705345db39d39 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 13:14:14 -0800 Subject: [PATCH 325/672] Mock out calls to time.time() and time.sleep() in basic_session_run_hooks_test.py This fixes race conditions in the unit tests that seems to be causing some flakiness. PiperOrigin-RevId: 222874796 --- .../training/basic_session_run_hooks_test.py | 166 +++++++++++------- 1 file changed, 98 insertions(+), 68 deletions(-) diff --git a/tensorflow/python/training/basic_session_run_hooks_test.py b/tensorflow/python/training/basic_session_run_hooks_test.py index 2d469634e0..3fabb3e086 100644 --- a/tensorflow/python/training/basic_session_run_hooks_test.py +++ b/tensorflow/python/training/basic_session_run_hooks_test.py @@ -22,7 +22,6 @@ from __future__ import print_function import os.path import shutil import tempfile -import threading import time from tensorflow.contrib.framework.python.framework import checkpoint_utils @@ -52,6 +51,11 @@ from tensorflow.python.training import session_run_hook from tensorflow.python.training import training_util +# Provide a realistic start time for unit tests where we need to mock out +# calls to time.time(). +MOCK_START_TIME = 1484695987.209386 + + class MockCheckpointSaverListener( basic_session_run_hooks.CheckpointSaverListener): @@ -95,7 +99,9 @@ class SecondOrStepTimerTest(test.TestCase): with self.assertRaises(ValueError): basic_session_run_hooks.SecondOrStepTimer() - def test_every_secs(self): + @test.mock.patch.object(time, 'time') + def test_every_secs(self, mock_time): + mock_time.return_value = MOCK_START_TIME timer = basic_session_run_hooks.SecondOrStepTimer(every_secs=1.0) self.assertTrue(timer.should_trigger_for_step(1)) @@ -103,7 +109,7 @@ class SecondOrStepTimerTest(test.TestCase): self.assertFalse(timer.should_trigger_for_step(1)) self.assertFalse(timer.should_trigger_for_step(2)) - time.sleep(1.0) + mock_time.return_value += 1.0 self.assertFalse(timer.should_trigger_for_step(1)) self.assertTrue(timer.should_trigger_for_step(2)) @@ -314,7 +320,7 @@ class LoggingTensorHookTest(test.TestCase): # in first run, elapsed time is None. self.assertEqual(str(self.logged_message).find('sec'), -1) - def _validate_print_every_n_secs(self, sess, at_end): + def _validate_print_every_n_secs(self, sess, at_end, mock_time): t = constant_op.constant(42.0, name='foo') train_op = constant_op.constant(3) @@ -331,7 +337,7 @@ class LoggingTensorHookTest(test.TestCase): self.logged_message = '' mon_sess.run(train_op) self.assertEqual(str(self.logged_message).find(t.name), -1) - time.sleep(1.0) + mock_time.return_value += 1.0 self.logged_message = '' mon_sess.run(train_op) @@ -345,17 +351,21 @@ class LoggingTensorHookTest(test.TestCase): # assertNotRegexpMatches is not supported by python 3.1 and later self.assertEqual(str(self.logged_message).find(t.name), -1) - def test_print_every_n_secs(self): + @test.mock.patch.object(time, 'time') + def test_print_every_n_secs(self, mock_time): with ops.Graph().as_default(), session_lib.Session() as sess: - self._validate_print_every_n_secs(sess, at_end=False) + mock_time.return_value = MOCK_START_TIME + self._validate_print_every_n_secs(sess, at_end=False, mock_time=mock_time) # Verify proper reset. - self._validate_print_every_n_secs(sess, at_end=False) + self._validate_print_every_n_secs(sess, at_end=False, mock_time=mock_time) - def test_print_every_n_secs_and_end(self): + @test.mock.patch.object(time, 'time') + def test_print_every_n_secs_and_end(self, mock_time): with ops.Graph().as_default(), session_lib.Session() as sess: - self._validate_print_every_n_secs(sess, at_end=True) + mock_time.return_value = MOCK_START_TIME + self._validate_print_every_n_secs(sess, at_end=True, mock_time=mock_time) # Verify proper reset. - self._validate_print_every_n_secs(sess, at_end=True) + self._validate_print_every_n_secs(sess, at_end=True, mock_time=mock_time) def test_print_formatter(self): with ops.Graph().as_default(), session_lib.Session() as sess: @@ -562,11 +572,8 @@ class CheckpointSaverHookTest(test.TestCase): @test.mock.patch.object(time, 'time') def test_save_secs_saves_periodically(self, mock_time): - # Let's have a realistic start time - current_time = 1484695987.209386 - with self.graph.as_default(): - mock_time.return_value = current_time + mock_time.return_value = MOCK_START_TIME hook = basic_session_run_hooks.CheckpointSaverHook( self.model_dir, save_secs=2, scaffold=self.scaffold) hook.begin() @@ -576,10 +583,10 @@ class CheckpointSaverHookTest(test.TestCase): sess.run(self.scaffold.init_op) mon_sess = monitored_session._HookedSession(sess, [hook]) - mock_time.return_value = current_time + mock_time.return_value = MOCK_START_TIME mon_sess.run(self.train_op) # Saved. - mock_time.return_value = current_time + 0.5 + mock_time.return_value = MOCK_START_TIME + 0.5 mon_sess.run(self.train_op) # Not saved. self.assertEqual(1, @@ -587,13 +594,13 @@ class CheckpointSaverHookTest(test.TestCase): self.global_step.name)) # Simulate 2.5 seconds of sleep. - mock_time.return_value = current_time + 2.5 + mock_time.return_value = MOCK_START_TIME + 2.5 mon_sess.run(self.train_op) # Saved. - mock_time.return_value = current_time + 2.6 + mock_time.return_value = MOCK_START_TIME + 2.6 mon_sess.run(self.train_op) # Not saved. - mock_time.return_value = current_time + 2.7 + mock_time.return_value = MOCK_START_TIME + 2.7 mon_sess.run(self.train_op) # Not saved. self.assertEqual(3, @@ -601,7 +608,7 @@ class CheckpointSaverHookTest(test.TestCase): self.global_step.name)) # Simulate 7.5 more seconds of sleep (10 seconds from start. - mock_time.return_value = current_time + 10 + mock_time.return_value = MOCK_START_TIME + 10 mon_sess.run(self.train_op) # Saved. self.assertEqual(6, checkpoint_utils.load_variable(self.model_dir, @@ -609,11 +616,8 @@ class CheckpointSaverHookTest(test.TestCase): @test.mock.patch.object(time, 'time') def test_save_secs_calls_listeners_periodically(self, mock_time): - # Let's have a realistic start time - current_time = 1484695987.209386 - with self.graph.as_default(): - mock_time.return_value = current_time + mock_time.return_value = MOCK_START_TIME listener = MockCheckpointSaverListener() hook = basic_session_run_hooks.CheckpointSaverHook( self.model_dir, @@ -626,28 +630,28 @@ class CheckpointSaverHookTest(test.TestCase): sess.run(self.scaffold.init_op) mon_sess = monitored_session._HookedSession(sess, [hook]) - mock_time.return_value = current_time + 0.5 + mock_time.return_value = MOCK_START_TIME + 0.5 mon_sess.run(self.train_op) # hook runs here - mock_time.return_value = current_time + 0.5 + mock_time.return_value = MOCK_START_TIME + 0.5 mon_sess.run(self.train_op) - mock_time.return_value = current_time + 3.0 + mock_time.return_value = MOCK_START_TIME + 3.0 mon_sess.run(self.train_op) # hook runs here - mock_time.return_value = current_time + 3.5 + mock_time.return_value = MOCK_START_TIME + 3.5 mon_sess.run(self.train_op) - mock_time.return_value = current_time + 4.0 + mock_time.return_value = MOCK_START_TIME + 4.0 mon_sess.run(self.train_op) - mock_time.return_value = current_time + 6.5 + mock_time.return_value = MOCK_START_TIME + 6.5 mon_sess.run(self.train_op) # hook runs here - mock_time.return_value = current_time + 7.0 + mock_time.return_value = MOCK_START_TIME + 7.0 mon_sess.run(self.train_op) # hook won't run here, so it does at end - mock_time.return_value = current_time + 7.5 + mock_time.return_value = MOCK_START_TIME + 7.5 hook.end(sess) # hook runs here self.assertEqual({ 'begin': 1, @@ -913,7 +917,9 @@ class StepCounterHookTest(test.TestCase): def tearDown(self): shutil.rmtree(self.log_dir, ignore_errors=True) - def test_step_counter_every_n_steps(self): + @test.mock.patch.object(time, 'time') + def test_step_counter_every_n_steps(self, mock_time): + mock_time.return_value = MOCK_START_TIME with ops.Graph().as_default() as g, session_lib.Session() as sess: variables.get_or_create_global_step() train_op = training_util._increment_global_step(1) @@ -925,7 +931,7 @@ class StepCounterHookTest(test.TestCase): mon_sess = monitored_session._HookedSession(sess, [hook]) with test.mock.patch.object(tf_logging, 'warning') as mock_log: for _ in range(30): - time.sleep(0.01) + mock_time.return_value += 0.01 mon_sess.run(train_op) # logging.warning should not be called. self.assertIsNone(mock_log.call_args) @@ -941,7 +947,9 @@ class StepCounterHookTest(test.TestCase): self.assertEqual('global_step/sec', summary_value.tag) self.assertGreater(summary_value.simple_value, 0) - def test_step_counter_every_n_secs(self): + @test.mock.patch.object(time, 'time') + def test_step_counter_every_n_secs(self, mock_time): + mock_time.return_value = MOCK_START_TIME with ops.Graph().as_default() as g, session_lib.Session() as sess: variables.get_or_create_global_step() train_op = training_util._increment_global_step(1) @@ -953,9 +961,9 @@ class StepCounterHookTest(test.TestCase): sess.run(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) mon_sess.run(train_op) - time.sleep(0.2) + mock_time.return_value += 0.2 mon_sess.run(train_op) - time.sleep(0.2) + mock_time.return_value += 0.2 mon_sess.run(train_op) hook.end(sess) @@ -1037,13 +1045,15 @@ class StepCounterHookTest(test.TestCase): sess.run(variables_lib.global_variables_initializer()) self.mon_sess = monitored_session._HookedSession(sess, [self.hook]) - def test_steps_per_run_less_than_every_n_steps(self): + @test.mock.patch.object(time, 'time') + def test_steps_per_run_less_than_every_n_steps(self, mock_time): + mock_time.return_value = MOCK_START_TIME with ops.Graph().as_default() as g, session_lib.Session() as sess: self._setup_steps_per_run_test(10, 5, g, sess) # Logs at 15, 25 for _ in range(5): - time.sleep(0.01) + mock_time.return_value += 0.01 self.mon_sess.run(self.train_op) self.hook.end(sess) @@ -1058,13 +1068,15 @@ class StepCounterHookTest(test.TestCase): self.assertEqual('global_step/sec', summary_value.tag) self.assertGreater(summary_value.simple_value, 0) - def test_steps_per_run_equal_every_n_steps(self): + @test.mock.patch.object(time, 'time') + def test_steps_per_run_equal_every_n_steps(self, mock_time): + mock_time.return_value = MOCK_START_TIME with ops.Graph().as_default() as g, session_lib.Session() as sess: self._setup_steps_per_run_test(5, 5, g, sess) # Logs at 10, 15, 20, 25 for _ in range(5): - time.sleep(0.01) + mock_time.return_value += 0.01 self.mon_sess.run(self.train_op) self.hook.end(sess) @@ -1080,13 +1092,15 @@ class StepCounterHookTest(test.TestCase): self.assertEqual('global_step/sec', summary_value.tag) self.assertGreater(summary_value.simple_value, 0) - def test_steps_per_run_greater_than_every_n_steps(self): + @test.mock.patch.object(time, 'time') + def test_steps_per_run_greater_than_every_n_steps(self, mock_time): + mock_time.return_value = MOCK_START_TIME with ops.Graph().as_default() as g, session_lib.Session() as sess: self._setup_steps_per_run_test(5, 10, g, sess) # Logs at 20, 30, 40, 50 for _ in range(5): - time.sleep(0.01) + mock_time.return_value += 0.01 self.mon_sess.run(self.train_op) self.hook.end(sess) @@ -1199,7 +1213,9 @@ class SummarySaverHookTest(test.TestCase): }, }) - def test_save_secs_saving_once_every_step(self): + @test.mock.patch.object(time, 'time') + def test_save_secs_saving_once_every_step(self, mock_time): + mock_time.return_value = MOCK_START_TIME hook = basic_session_run_hooks.SummarySaverHook( save_secs=0.5, summary_writer=self.summary_writer, @@ -1211,7 +1227,7 @@ class SummarySaverHookTest(test.TestCase): mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(4): mon_sess.run(self.train_op) - time.sleep(0.5) + mock_time.return_value += 0.5 hook.end(sess) self.summary_writer.assert_summaries( @@ -1279,27 +1295,43 @@ class GlobalStepWaiterHookTest(test.TestCase): session_run_hook.SessionRunContext( original_args=None, session=sess)) - def test_wait_for_step(self): + @test.mock.patch.object(time, 'sleep') + def test_wait_for_step(self, mock_sleep): with ops.Graph().as_default(): gstep = variables.get_or_create_global_step() hook = basic_session_run_hooks.GlobalStepWaiterHook(wait_until_step=1000) hook.begin() + with session_lib.Session() as sess: + # Mock out calls to time.sleep() to update the global step. + + class Context(object): + counter = 0 + + def mock_sleep_side_effect(seconds): + del seconds # argument is ignored + Context.counter += 1 + if Context.counter == 1: + # The first time sleep() is called, we update the global_step from + # 0 to 500. + sess.run(state_ops.assign(gstep, 500)) + elif Context.counter == 2: + # The second time sleep() is called, we update the global_step from + # 500 to 1100. + sess.run(state_ops.assign(gstep, 1100)) + else: + raise AssertionError( + 'Expected before_run() to terminate after the second call to ' + 'time.sleep()') + + mock_sleep.side_effect = mock_sleep_side_effect + + # Run the mocked-out interaction with the hook. sess.run(variables_lib.global_variables_initializer()) - waiter = threading.Thread( - target=hook.before_run, - args=(session_run_hook.SessionRunContext( - original_args=None, session=sess),)) - waiter.daemon = True - waiter.start() - time.sleep(1.0) - self.assertTrue(waiter.is_alive()) - sess.run(state_ops.assign(gstep, 500)) - time.sleep(1.0) - self.assertTrue(waiter.is_alive()) - sess.run(state_ops.assign(gstep, 1100)) - time.sleep(1.2) - self.assertFalse(waiter.is_alive()) + run_context = session_run_hook.SessionRunContext( + original_args=None, session=sess) + hook.before_run(run_context) + self.assertEqual(Context.counter, 2) class FinalOpsHookTest(test.TestCase): @@ -1465,29 +1497,27 @@ class ProfilerHookTest(test.TestCase): @test.mock.patch.object(time, 'time') def test_save_secs_saves_periodically(self, mock_time): # Pick a fixed start time. - current_time = 1484863632. - with self.graph.as_default(): - mock_time.return_value = current_time + mock_time.return_value = MOCK_START_TIME hook = basic_session_run_hooks.ProfilerHook( save_secs=2, output_dir=self.output_dir) with monitored_session.SingularMonitoredSession(hooks=[hook]) as sess: sess.run(self.train_op) # Not saved. self.assertEqual(0, self._count_timeline_files()) # Simulate 2.5 seconds of sleep. - mock_time.return_value = current_time + 2.5 + mock_time.return_value = MOCK_START_TIME + 2.5 sess.run(self.train_op) # Saved. self.assertEqual(1, self._count_timeline_files()) # Pretend some small amount of time has passed. - mock_time.return_value = current_time + 2.6 + mock_time.return_value = MOCK_START_TIME + 2.6 sess.run(self.train_op) # Not saved. # Edge test just before we should save the timeline. - mock_time.return_value = current_time + 4.4 + mock_time.return_value = MOCK_START_TIME + 4.4 sess.run(self.train_op) # Not saved. self.assertEqual(1, self._count_timeline_files()) - mock_time.return_value = current_time + 4.5 + mock_time.return_value = MOCK_START_TIME + 4.5 sess.run(self.train_op) # Saved. self.assertEqual(2, self._count_timeline_files()) -- GitLab From 7d1710c55c552abe19ebbc5e999521678355b3aa Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Mon, 26 Nov 2018 13:23:56 -0800 Subject: [PATCH 326/672] Update TensorFlow Lite Converter documentation. PiperOrigin-RevId: 222876388 --- tensorflow/lite/g3doc/convert/index.md | 14 +- tensorflow/lite/g3doc/convert/python_api.md | 29 ++-- tensorflow/lite/g3doc/devguide.md | 179 +++++++++----------- 3 files changed, 105 insertions(+), 117 deletions(-) diff --git a/tensorflow/lite/g3doc/convert/index.md b/tensorflow/lite/g3doc/convert/index.md index bc92a1c1a1..60fa265c29 100644 --- a/tensorflow/lite/g3doc/convert/index.md +++ b/tensorflow/lite/g3doc/convert/index.md @@ -6,14 +6,20 @@ file used by the TensorFlow Lite interpreter. ## From model training to device deployment After a TensorFlow model is trained, the TensorFlow Lite converter uses that -model to generate a TensorFlow Lite [FlatBuffer](https://google.github.io/flatbuffers/) -file (`.tflite`). The converter supports as input: +model to generate a TensorFlow Lite +[FlatBuffer](https://google.github.io/flatbuffers/) file (`.tflite`). The +converter supports as input: [SavedModels](https://www.tensorflow.org/guide/saved_model#using_savedmodel_with_estimators), frozen graphs (models generated by [freeze_graph.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/tools/freeze_graph.py)), -and `tf.keras` models. The TensorFlow Lite `FlatBuffer` file is deployed to a -client device (generally a mobile or embedded device), and the TensorFlow Lite +and `tf.keras` HDF5 models. The TensorFlow Lite `FlatBuffer` file is deployed to +a client device (generally a mobile or embedded device), and the TensorFlow Lite interpreter uses the compressed model for on-device inference. This conversion process is shown in the diagram below: ![TFLite converter workflow](../images/convert/workflow.svg) + +The TensorFlow Lite Converter can be used either from [Python](python_api.md) or +from the [command line](cmdline_examples.md). This allows you to integrate the +conversion step into the model design workflow, ensuring the model is easy to +convert to a mobile inference graph. diff --git a/tensorflow/lite/g3doc/convert/python_api.md b/tensorflow/lite/g3doc/convert/python_api.md index 4bdf0d8cbe..b914a34fa8 100644 --- a/tensorflow/lite/g3doc/convert/python_api.md +++ b/tensorflow/lite/g3doc/convert/python_api.md @@ -3,10 +3,9 @@ This page provides examples on how to use the TensorFlow Lite Converter and the TensorFlow Lite interpreter using the Python API. -Note: TFLite recently moved from `tf.contrib.lite` to `tf.lite`. If you are -using tensorflow `r1.12` or earlier you will need to add `.contrib` to the -commands below. `tf.lite` works with newer builds, like the nightly build, -which can be installed with: `pip install tf-nightly` +Note: These docs describe the converter in the TensorFlow nightly release, +installed using `pip install tf-nightly`. For docs describing older versions +reference ["Converting models from TensorFlow 1.12"](#pre_tensorflow_1.12). [TOC] @@ -24,11 +23,6 @@ The API for converting TensorFlow models to TensorFlow Lite as of TensorFlow 1.9 is `tf.lite.TFLiteConverter`. The API for calling the Python intepreter is `tf.lite.Interpreter`. -Note: Reference "Additional Instructions" sections for converting TensorFlow -models to TensorFlow Lite -[in TensorFlow 1.9 to TensorFlow 1.11](#pre_tensorflow_1.11) and -[prior to TensorFlow 1.9](#pre_tensorflow_1.9) - `TFLiteConverter` provides class methods based on the original format of the model. `TFLiteConverter.from_session()` is available for GraphDefs. `TFLiteConverter.from_saved_model()` is available for SavedModels. @@ -250,14 +244,13 @@ either install the nightly build with [Docker](https://www.tensorflow.org/install/docker), or [build the pip package from source](https://www.tensorflow.org/install/source). -### Converting models in TensorFlow 1.9 to TensorFlow 1.11 - -To convert TensorFlow models to TensorFlow Lite in TensorFlow 1.9 through -TensorFlow 1.11, use `TocoConverter`. `TocoConverter` is semantically -identically to `TFLiteConverter`. +### Converting models from TensorFlow 1.12 -### Converting models prior to TensorFlow 1.9 +Reference the following table to convert TensorFlow models to TensorFlow Lite in +and before TensorFlow 1.12. Run `help()` to get details of each API. -To convert TensorFlow models to TensorFlow Lite in TensorFlow 1.7 and TensorFlow -1.8, use the `toco_convert` function. Run `help(tf.lite.toco_convert)` -to get details about accepted parameters. +TensorFlow Version | Python API +------------------ | --------------------------------- +1.12 | `tf.contrib.lite.TFLiteConverter` +1.9-1.11 | `tf.contrib.lite.TocoConverter` +1.7-1.8 | `tf.contrib.lite.toco_convert` diff --git a/tensorflow/lite/g3doc/devguide.md b/tensorflow/lite/g3doc/devguide.md index 270cb8ce37..798bf4996a 100644 --- a/tensorflow/lite/g3doc/devguide.md +++ b/tensorflow/lite/g3doc/devguide.md @@ -35,7 +35,7 @@ by suggesting contextually relevant messages. The model is built specifically fo memory constrained devices, such as watches and phones, and has been successfully used in Smart Replies on Android Wear. Currently, this model is Android-specific. -These pre-trained models are [available for download](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/models.md) +These pre-trained models are [available for download](models.md). ### Re-train Inception-V3 or MobileNet for a custom data set @@ -57,51 +57,58 @@ A developer may choose to train a custom model using Tensorflow (see the [TensorFlow tutorials](../tutorials/) for examples of building and training models). If you have already written a model, the first step is to export this to a `tf.GraphDef` file. This is required because some formats do not store the -model structure outside the code, and we must communicate with other parts of the -framework. See -[Exporting the Inference Graph](https://github.com/tensorflow/models/blob/master/research/slim/README.md) -to create .pb file for the custom model. +model structure outside the code, and we must communicate with other parts of +the framework. See +[Exporting the Inference Graph](https://www.tensorflow.org/tutorials/keras/save_and_restore_models#save_the_entire_model) +to create file for the custom model. -TensorFlow Lite currently supports a subset of TensorFlow operators. Refer to the -[TensorFlow Lite & TensorFlow Compatibility Guide](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/g3doc/tf_ops_compatibility.md) +TensorFlow Lite currently supports a subset of TensorFlow operators. Refer to +the [TensorFlow Lite & TensorFlow Compatibility Guide](tf_ops_compatibility.md) for supported operators and their usage. This set of operators will continue to grow in future Tensorflow Lite releases. - ## 2. Convert the model format -The model generated (or downloaded) in the previous step is a *standard* -Tensorflow model and you should now have a .pb or .pbtxt `tf.GraphDef` file. -Models generated with transfer learning (re-training) or custom models must be -converted—but, we must first freeze the graph to convert the model to the -Tensorflow Lite format. This process uses several model formats: - -* `tf.GraphDef` (.pb) —A protobuf that represents the TensorFlow training or - computation graph. It contains operators, tensors, and variables definitions. -* *CheckPoint* (.ckpt) —Serialized variables from a TensorFlow graph. Since this - does not contain a graph structure, it cannot be interpreted by itself. -* `FrozenGraphDef` —A subclass of `GraphDef` that does not contain - variables. A `GraphDef` can be converted to a `FrozenGraphDef` by taking a - CheckPoint and a `GraphDef`, and converting each variable into a constant - using the value retrieved from the CheckPoint. -* `SavedModel` —A `GraphDef` and CheckPoint with a signature that labels - input and output arguments to a model. A `GraphDef` and CheckPoint can be - extracted from a `SavedModel`. -* *TensorFlow Lite model* (.tflite) —A serialized - [FlatBuffer](https://google.github.io/flatbuffers/) that contains TensorFlow - Lite operators and tensors for the TensorFlow Lite interpreter, similar to a - `FrozenGraphDef`. - -### Freeze Graph - -To use the `GraphDef` .pb file with TensorFlow Lite, you must have checkpoints -that contain trained weight parameters. The .pb file only contains the structure -of the graph. The process of merging the checkpoint values with the graph -structure is called *freezing the graph*. - -You should have a checkpoints folder or download them for a pre-trained model -(for example, -[MobileNets](https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md)). +The [TensorFlow Lite Converter](convert) accepts the following file formats: + +* `SavedModel` — A `GraphDef` and checkpoint with a signature that labels + input and output arguments to a model. See the documentation for converting + SavedModels using [Python](convert/python_api#basic_savedmodel) or using the + [command line](convert/cmdline_examples#savedmodel). +* `tf.keras` - A HDF5 file containing a model with weights and input and + output arguments generated by `tf.Keras`. See [here] for converting HDF5 + models. See the documentation for converting HDF5 models using + [Python](convert/python_api#basic_keras_file) or using the + [command line](convert/cmdline_examples#keras). +* `frozen tf.GraphDef` — A subclass of `tf.GraphDef` that does not contain + variables. A `GraphDef` can be converted to a `frozen GraphDef` by taking a + checkpoint and a `GraphDef`, and converting each variable into a constant + using the value retrieved from the checkpoint. Instructions on converting a + `tf.GraphDef` to a TensorFlow Lite model are described in the next + subsection. + +### Converting a tf.GraphDef + +TensorFlow models may be saved as a .pb or .pbtxt `tf.GraphDef` file. In order +to convert the `tf.GraphDef` file to TensorFlow Lite, the model must first be +frozen. This process invovles several file formats including the `frozen +GraphDef`: + +* `tf.GraphDef` (.pb or .pbtxt) — A protobuf that represents the TensorFlow + training or computation graph. It contains operators, tensors, and variables + definitions. +* *checkpoint* (.ckpt) — Serialized variables from a TensorFlow graph. Since + this does not contain a graph structure, it cannot be interpreted by itself. +* *TensorFlow Lite model* (.tflite) — A serialized + [FlatBuffer](https://google.github.io/flatbuffers/) that contains TensorFlow + Lite operators and tensors for the TensorFlow Lite interpreter. + +You must have checkpoints that contain trained weights. The `tf.GraphDef` file +only contains the structure of the graph. The process of merging the checkpoint +values with the graph structure is called *freezing the graph*. + +`tf.GraphDef` and checkpoint files for MobileNet models are available +[here](https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md). To freeze the graph, use the following command (changing the arguments): @@ -113,69 +120,52 @@ freeze_graph --input_graph=/tmp/mobilenet_v1_224.pb \ --output_node_names=MobileNetV1/Predictions/Reshape_1 ``` -The `input_binary` flag must be enabled so the protobuf is read and written in -a binary format. Set the `input_graph` and `input_checkpoint` files. +Set the `input_binary` flag to `True` when reading a binary protobuf, a `.pb` +file. Set to `False` for a `.pbtxt` file. -The `output_node_names` may not be obvious outside of the code that built the -model. The easiest way to find them is to visualize the graph, either with -[TensorBoard](https://codelabs.developers.google.com/codelabs/tensorflow-for-poets-2/#3) -or `graphviz`. +Set `input_graph` and `input_checkpoint` to the respective filenames. The +`output_node_names` may not be obvious outside of the code that built the model. +The easiest way to find them is to visualize the graph, either with +[TensorBoard](https://www.tensorflow.org/guide/summaries_and_tensorboard) or +`graphviz`. The frozen `GraphDef` is now ready for conversion to the `FlatBuffer` format -(.tflite) for use on Android or iOS devices. For Android, the Tensorflow -Optimizing Converter tool supports both float and quantized models. To convert -the frozen `GraphDef` to the .tflite format: +(.tflite) for use on Android or iOS devices. For Android, the TensorFlow Lite +Converter tool supports both float and quantized models. To convert the frozen +`GraphDef` to the .tflite format use a command similar to the following: ``` -toco --input_file=$(pwd)/mobilenet_v1_1.0_224/frozen_graph.pb \ - --input_format=TENSORFLOW_GRAPHDEF \ - --output_format=TFLITE \ +tflite_convert \ --output_file=/tmp/mobilenet_v1_1.0_224.tflite \ - --inference_type=FLOAT \ - --input_type=FLOAT \ + --graph_def_file=/tmp/mobilenet_v1_0.50_128/frozen_graph.pb \ --input_arrays=input \ - --output_arrays=MobilenetV1/Predictions/Reshape_1 \ - --input_shapes=1,224,224,3 + --output_arrays=MobilenetV1/Predictions/Reshape_1 ``` -The `input_file` argument should reference the frozen `GraphDef` file -containing the model architecture. The [frozen_graph.pb](https://storage.googleapis.com/download.tensorflow.org/models/mobilenet_v1_1.0_224_frozen.tgz) -file used here is available for download. `output_file` is where the TensorFlow -Lite model will get generated. The `input_type` and `inference_type` -arguments should be set to `FLOAT`, unless converting a -quantized model. -Setting the `input_array`, `output_array`, and `input_shape` arguments are not as -straightforward. The easiest way to find these values is to explore the graph -using Tensorboard. Reuse the arguments for specifying the output nodes for -inference in the `freeze_graph` step. - -It is also possible to use the Tensorflow Optimizing Converter with protobufs -from either Python or from the command line (see the -[toco_from_protos.py](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/toco/python/toco_from_protos.py) -example). This allows you to integrate the conversion step into the model design -workflow, ensuring the model is easily convertible to a mobile inference graph. -For example: - -```python -import tensorflow as tf - -img = tf.placeholder(name="img", dtype=tf.float32, shape=(1, 64, 64, 3)) -val = img + tf.constant([1., 2., 3.]) + tf.constant([1., 4., 4.]) -out = tf.identity(val, name="out") - -with tf.Session() as sess: - tflite_model = tf.lite.toco_convert(sess.graph_def, [img], [out]) - open("converteds_model.tflite", "wb").write(tflite_model) -``` +The +[frozen_graph.pb](https://storage.googleapis.com/download.tensorflow.org/models/mobilenet_v1_1.0_224_frozen.tgz) +file used here is available for download. Setting the `input_array` and +`output_array` arguments is not straightforward. The easiest way to find these +values is to explore the graph using +[TensorBoard](https://www.tensorflow.org/guide/summaries_and_tensorboard). Reuse +the arguments for specifying the output nodes for inference in the +`freeze_graph` step. + +### Full converter reference -For usage, see the Tensorflow Optimizing Converter -[command-line examples](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/toco/g3doc/cmdline_examples.md). +The [TensorFlow Lite Converter](convert/) can be [Python](convert/python_api.md) +or from the [command line](convert/cmdline_examples.md). This allows you to +integrate the conversion step into the model design workflow, ensuring the model +is easy to convert to a mobile inference graph. -Refer to the -[Ops compatibility guide](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/g3doc/tf_ops_compatibility.md) -for troubleshooting help, and if that doesn't help, please +### Ops compatibility + +Refer to the [ops compatibility guide](tf_ops_compatibility.md) for +troubleshooting help, and if that doesn't help, please [file an issue](https://github.com/tensorflow/tensorflow/issues). +### Graph vizualization tool + The [development repo](https://github.com/tensorflow/tensorflow) contains a tool to visualize TensorFlow Lite models after conversion. To build the [visualize.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/visualize.py) @@ -212,8 +202,8 @@ installing TensorFlow on Android and setting up `bazel` and Android Studio. ### iOS To integrate a TensorFlow model in an iOS app, see the -[TensorFlow Lite for iOS](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/g3doc/ios.md) -guide and iOS demo guide. +[TensorFlow Lite for iOS](ios.md) guide and iOS demo +guide. #### Core ML support @@ -227,6 +217,5 @@ devices. To use the converter, refer to the ### Raspberry Pi Compile Tensorflow Lite for a Raspberry Pi by following the -[RPi build instructions](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/rpi.md) -This compiles a static library file (`.a`) used to build your app. There are -plans for Python bindings and a demo app. +[RPi build instructions](rpi.md) This compiles a static library file (`.a`) used +to build your app. There are plans for Python bindings and a demo app. -- GitLab From dbf34e95585a4c1f89bcc041e95752ae7dd0cacc Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Mon, 26 Nov 2018 13:34:22 -0800 Subject: [PATCH 327/672] Adding `MeanAbsoluteError`, `MeanAbsolutePercentageError`, `MeanSquaredLogarithmicError ` losses to the new loss module. PiperOrigin-RevId: 222878057 --- tensorflow/python/keras/losses.py | 111 +++++++++++++ tensorflow/python/keras/losses_test.py | 207 +++++++++++++++++++++++++ 2 files changed, 318 insertions(+) diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index 0e274d4d50..8afe2fadce 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -133,6 +133,117 @@ class MeanSquaredError(Loss): return mean_squared_error(y_true, y_pred) +class MeanAbsoluteError(Loss): + """Computes the mean of absolute difference between labels and predictions. + + For example, if `y_true` is [0., 0., 1., 1.] and `y_pred` is [1., 1., 1., 0.] + then the mean absolute error value is 3/4 (0.75). + + Usage: + + ```python + mae = tf.losses.MeanAbsoluteError() + loss = mae([0., 0., 1., 1.], [1., 1., 1., 0.]) + print('Loss: ', loss.numpy()) # Loss: 0.75 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss=tf.losses.MeanAbsoluteError()) + ``` + """ + + def call(self, y_true, y_pred): + """Invokes the `MeanAbsoluteError` instance. + + Args: + y_true: Ground truth values. + y_pred: The predicted values. + + Returns: + Mean absolute error losses. + """ + y_pred = ops.convert_to_tensor(y_pred) + y_true = math_ops.cast(y_true, y_pred.dtype) + return mean_absolute_error(y_true, y_pred) + + +class MeanAbsolutePercentageError(Loss): + """Computes the mean absolute percentage error between `y_true` and `y_pred`. + + For example, if `y_true` is [0., 0., 1., 1.] and `y_pred` is [1., 1., 1., 0.] + then the mean absolute percentage error value is 5e+08. + + Usage: + + ```python + mape = tf.losses.MeanAbsolutePercentageError() + loss = mape([0., 0., 1., 1.], [1., 1., 1., 0.]) + print('Loss: ', loss.numpy()) # Loss: 5e+08 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss=tf.losses.MeanAbsolutePercentageError()) + ``` + """ + + def call(self, y_true, y_pred): + """Invokes the `MeanAbsolutePercentageError` instance. + + Args: + y_true: Ground truth values. + y_pred: The predicted values. + + Returns: + Mean absolute percentage error losses. + """ + y_pred = ops.convert_to_tensor(y_pred) + y_true = math_ops.cast(y_true, y_pred.dtype) + return mean_absolute_percentage_error(y_true, y_pred) + + +class MeanSquaredLogarithmicError(Loss): + """Computes the mean squared logarithmic error between `y_true` and `y_pred`. + + For example, if `y_true` is [0., 0., 1., 1.] and `y_pred` is [1., 1., 1., 0.] + then the mean squared logarithmic error value is 0.36034. + + Usage: + + ```python + msle = tf.losses.MeanSquaredLogarithmicError() + loss = msle([0., 0., 1., 1.], [1., 1., 1., 0.]) + print('Loss: ', loss.numpy()) # Loss: 0.36034 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss=tf.losses.MeanSquaredLogarithmicError()) + ``` + """ + + def call(self, y_true, y_pred): + """Invokes the `MeanSquaredLogarithmicError` instance. + + Args: + y_true: Ground truth values. + y_pred: The predicted values. + + Returns: + Mean squared logarithmic error losses. + """ + y_pred = ops.convert_to_tensor(y_pred) + y_true = math_ops.cast(y_true, y_pred.dtype) + return mean_squared_logarithmic_error(y_true, y_pred) + + @tf_export('keras.metrics.mean_squared_error', 'keras.metrics.mse', 'keras.metrics.MSE', diff --git a/tensorflow/python/keras/losses_test.py b/tensorflow/python/keras/losses_test.py index b056f920ab..d80b272b12 100644 --- a/tensorflow/python/keras/losses_test.py +++ b/tensorflow/python/keras/losses_test.py @@ -234,5 +234,212 @@ class MeanSquaredErrorTest(test.TestCase): self.assertAlmostEqual(self.evaluate(loss), 227.69998, 3) +@test_util.run_all_in_graph_and_eager_modes +class MeanAbsoluteErrorTest(test.TestCase): + + def test_config(self): + mae_obj = keras.losses.MeanAbsoluteError( + reduction=keras.losses.ReductionV2.SUM, name='mae_1') + self.assertEqual(mae_obj.name, 'mae_1') + self.assertEqual(mae_obj.reduction, keras.losses.ReductionV2.SUM) + + def test_all_correct_unweighted(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3)) + loss = mae_obj(y_true, y_true) + self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) + + def test_unweighted(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mae_obj(y_true, y_pred) + self.assertAlmostEqual(self.evaluate(loss), 5.5, 3) + + def test_scalar_weighted(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mae_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), 12.65, 3) + + def test_sample_weighted(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + sample_weight = constant_op.constant([1.2, 3.4], shape=(2, 1)) + loss = mae_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 81.4 / 6, 3) + + def test_timestep_weighted(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3, 1), + dtype=dtypes.float32) + sample_weight = constant_op.constant([3, 6, 5, 0, 4, 2], shape=(2, 3)) + loss = mae_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 83 / 6, 3) + + def test_zero_weighted(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mae_obj(y_true, y_pred, sample_weight=0) + self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) + + def test_invalid_sample_weight(self): + mae_obj = keras.losses.MeanAbsoluteError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], shape=(2, 3, 1)) + sample_weight = constant_op.constant([3, 6, 5, 0], shape=(2, 2)) + with self.assertRaisesRegexp( + ValueError, r'Shapes \(2, 2\) and \(2, 3\) are incompatible'): + mae_obj(y_true, y_pred, sample_weight=sample_weight) + + def test_no_reduction(self): + mae_obj = keras.losses.MeanAbsoluteError( + reduction=keras.losses.ReductionV2.NONE) + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mae_obj(y_true, y_pred, sample_weight=2.3) + loss = self.evaluate(loss) + self.assertArrayNear(loss, [10.7333, 14.5666], 1e-3) + + def test_sum_reduction(self): + mae_obj = keras.losses.MeanAbsoluteError( + reduction=keras.losses.ReductionV2.SUM) + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mae_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), 25.29999, 3) + + +@test_util.run_all_in_graph_and_eager_modes +class MeanAbsolutePercentageErrorTest(test.TestCase): + + def test_config(self): + mape_obj = keras.losses.MeanAbsolutePercentageError( + reduction=keras.losses.ReductionV2.SUM, name='mape_1') + self.assertEqual(mape_obj.name, 'mape_1') + self.assertEqual(mape_obj.reduction, keras.losses.ReductionV2.SUM) + + def test_unweighted(self): + mape_obj = keras.losses.MeanAbsolutePercentageError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mape_obj(y_true, y_pred) + self.assertAlmostEqual(self.evaluate(loss), 211.8518, 3) + + def test_scalar_weighted(self): + mape_obj = keras.losses.MeanAbsolutePercentageError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mape_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), 487.259, 3) + + def test_sample_weighted(self): + mape_obj = keras.losses.MeanAbsolutePercentageError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + sample_weight = constant_op.constant([1.2, 3.4], shape=(2, 1)) + loss = mape_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 422.8888, 3) + + def test_timestep_weighted(self): + mape_obj = keras.losses.MeanAbsolutePercentageError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3, 1), + dtype=dtypes.float32) + sample_weight = constant_op.constant([3, 6, 5, 0, 4, 2], shape=(2, 3)) + loss = mape_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 694.4445, 3) + + def test_zero_weighted(self): + mape_obj = keras.losses.MeanAbsolutePercentageError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = mape_obj(y_true, y_pred, sample_weight=0) + self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) + + +@test_util.run_all_in_graph_and_eager_modes +class MeanSquaredLogarithmicErrorTest(test.TestCase): + + def test_config(self): + msle_obj = keras.losses.MeanSquaredLogarithmicError( + reduction=keras.losses.ReductionV2.SUM, name='mape_1') + self.assertEqual(msle_obj.name, 'mape_1') + self.assertEqual(msle_obj.reduction, keras.losses.ReductionV2.SUM) + + def test_unweighted(self): + msle_obj = keras.losses.MeanSquaredLogarithmicError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = msle_obj(y_true, y_pred) + self.assertAlmostEqual(self.evaluate(loss), 1.4370, 3) + + def test_scalar_weighted(self): + msle_obj = keras.losses.MeanSquaredLogarithmicError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = msle_obj(y_true, y_pred, sample_weight=2.3) + self.assertAlmostEqual(self.evaluate(loss), 3.3051, 3) + + def test_sample_weighted(self): + msle_obj = keras.losses.MeanSquaredLogarithmicError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + sample_weight = constant_op.constant([1.2, 3.4], shape=(2, 1)) + loss = msle_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 3.7856, 3) + + def test_timestep_weighted(self): + msle_obj = keras.losses.MeanSquaredLogarithmicError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3, 1)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3, 1), + dtype=dtypes.float32) + sample_weight = constant_op.constant([3, 6, 5, 0, 4, 2], shape=(2, 3)) + loss = msle_obj(y_true, y_pred, sample_weight=sample_weight) + self.assertAlmostEqual(self.evaluate(loss), 2.6473, 3) + + def test_zero_weighted(self): + msle_obj = keras.losses.MeanSquaredLogarithmicError() + y_true = constant_op.constant([1, 9, 2, -5, -2, 6], shape=(2, 3)) + y_pred = constant_op.constant([4, 8, 12, 8, 1, 3], + shape=(2, 3), + dtype=dtypes.float32) + loss = msle_obj(y_true, y_pred, sample_weight=0) + self.assertAlmostEqual(self.evaluate(loss), 0.0, 3) + + if __name__ == '__main__': test.main() -- GitLab From 8d71758444bb71ebb5bc6d851e8e1626bc512a8d Mon Sep 17 00:00:00 2001 From: Dan Moldovan Date: Mon, 26 Nov 2018 13:39:49 -0800 Subject: [PATCH 328/672] Simplify the error message for mismatched function source, since now it's an extremely rare possibility. PiperOrigin-RevId: 222879086 --- .../python/autograph/impl/conversion.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/tensorflow/python/autograph/impl/conversion.py b/tensorflow/python/autograph/impl/conversion.py index 48a9307cab..3dfc12eb76 100644 --- a/tensorflow/python/autograph/impl/conversion.py +++ b/tensorflow/python/autograph/impl/conversion.py @@ -281,11 +281,10 @@ def function_to_graph(f, node, source = parser.parse_entity(f) node = node.body[0] - # In general, the output of inspect.getsource is inexact because it uses crude - # regex matching methods to search the source file. This is particularly - # problematic for lambda functions, where the entire containing lines are - # returned. Certain distributions of CPython may also return the enclosing - # function for local functions. + # In general, the output of inspect.getsource is inexact because it uses + # regex matching to adjust the exact location around the line number that + # CPython records. This is particularly problematic for lambda functions, + # where the entire containing lines are returned. nodes = ast_util.find_matching_definitions(node, f) if len(nodes) != 1: if f.__name__ == '': @@ -295,17 +294,11 @@ def function_to_graph(f, ' matching signature. To avoid ambiguity, define each lambda' ' in a separate expression.'.format(f, source)) else: - # The inspect.getsource bug is currently known to occur in the Windows - # integration tests which run Python 3.6. - # TODO(mdan): Find out eaxctly which distribution of Python is that. raise ValueError( 'Unable to identify source code of function {}. The source code' ' reported by Python did not include exactly one matching signature:' - '\n{}\nTo avoid ambiguity, use a unique name for each' - ' function.\nNote that some distributions of Python may report source' - ' code incorrectly. It may be possible to avoid that bug by' - ' organizing the code into smaller units (smaller files, functions or' - ' classes), or by turning AutoGraph off.'.format(f, source)) + '\n{}\n. This is an extremely rare occurrence. Please report it to' + ' the TensorFlow team.'.format(f, source)) node, = nodes # TODO(znado): Place inside standard_analysis. -- GitLab From c0d3a71e476d52345477727681d3acf3ae87a2eb Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Mon, 26 Nov 2018 13:44:56 -0800 Subject: [PATCH 329/672] Fix Layer/variable aggregation from empty checkpointable data structures PiperOrigin-RevId: 222879879 --- tensorflow/python/training/checkpointable/data_structures.py | 5 ++++- .../python/training/checkpointable/data_structures_test.py | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/training/checkpointable/data_structures.py b/tensorflow/python/training/checkpointable/data_structures.py index a46a4a1910..817552f326 100644 --- a/tensorflow/python/training/checkpointable/data_structures.py +++ b/tensorflow/python/training/checkpointable/data_structures.py @@ -492,7 +492,10 @@ class Mapping(CheckpointableDataStructure, collections.Mapping): @property def _values(self): # Sort items deterministically by key - return list(zip(*sorted(self.items(), key=lambda it: it[0])))[1] + ordered = list(zip(*sorted(self.items(), key=lambda it: it[0]))) + if ordered: + return ordered[1] + return [] def _name_element(self, key): if not isinstance(key, six.string_types): diff --git a/tensorflow/python/training/checkpointable/data_structures_test.py b/tensorflow/python/training/checkpointable/data_structures_test.py index 17cbe3192d..9cefd942ac 100644 --- a/tensorflow/python/training/checkpointable/data_structures_test.py +++ b/tensorflow/python/training/checkpointable/data_structures_test.py @@ -335,11 +335,15 @@ class MappingTests(test.TestCase): d = {} root = tracking.Checkpointable() root.wrapper = d + self.assertEqual([], root.wrapper.layers) + self.assertEqual([], root.wrapper.trainable_weights) layer1 = core.Dense(1) layer2 = core.Dense(1) d["a"] = layer1 d["b"] = layer2 self.assertEqual([layer1, layer2], root.wrapper.layers) + # The layers have still not created variables + self.assertEqual([], root.wrapper.trainable_weights) def testHashing(self): has_mappings = set([data_structures.Mapping(), -- GitLab From 0d81559010c5ab605a47d81b595b9bd36b894906 Mon Sep 17 00:00:00 2001 From: Scott Zhu Date: Mon, 26 Nov 2018 13:55:29 -0800 Subject: [PATCH 330/672] Update unified_lstm in eager mode. PiperOrigin-RevId: 222881522 --- .../python/keras/layers/unified_rnn_test.py | 253 +++++++++--------- 1 file changed, 129 insertions(+), 124 deletions(-) diff --git a/tensorflow/python/keras/layers/unified_rnn_test.py b/tensorflow/python/keras/layers/unified_rnn_test.py index e28f9625b9..b08ff3cafc 100644 --- a/tensorflow/python/keras/layers/unified_rnn_test.py +++ b/tensorflow/python/keras/layers/unified_rnn_test.py @@ -24,12 +24,13 @@ import time from tensorflow.core.protobuf import config_pb2 from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python import keras -from tensorflow.python.client import session +from tensorflow.python.eager import context from tensorflow.python.eager import function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.keras import activations from tensorflow.python.keras import backend as K from tensorflow.python.keras import constraints @@ -54,14 +55,19 @@ from tensorflow.python.training import gradient_descent class RNNTest(test.TestCase): + rewrites = rewriter_config_pb2.RewriterConfig() + rewrites.function_optimization = rewriter_config_pb2.RewriterConfig.OFF + customer_optimizer = rewrites.custom_optimizers.add() + customer_optimizer.name = 'ExperimentalImplementationSelector' + rewrites.min_graph_nodes = -1 + graph_options = config_pb2.GraphOptions(rewrite_options=rewrites) + config = config_pb2.ConfigProto(graph_options=graph_options) + def setUp(self): - rewrites = rewriter_config_pb2.RewriterConfig() - rewrites.function_optimization = rewriter_config_pb2.RewriterConfig.OFF - customer_optimizer = rewrites.custom_optimizers.add() - customer_optimizer.name = 'ExperimentalImplementationSelector' - rewrites.min_graph_nodes = -1 - graph_options = config_pb2.GraphOptions(rewrite_options=rewrites) - self.config = config_pb2.ConfigProto(graph_options=graph_options) + self.config = RNNTest.config + + def tearDown(self): + ops.reset_default_graph() def test_unifiedRNN(self): input_shape = 10 @@ -71,7 +77,7 @@ class RNNTest(test.TestCase): batch = 100 epoch = 1 - with ops.Graph().as_default(), session.Session(config=self.config) as sess: + with self.cached_session(config=self.config, use_gpu=True) as sess: (x_train, y_train), _ = testing_utils.get_test_data( train_samples=batch, test_samples=0, @@ -107,32 +113,6 @@ class RNNTest(test.TestCase): self.assertNotEqual(existing_loss, loss_value) existing_loss = loss_value - def test_keras_model_with_lstm(self): - input_shape = 10 - rnn_state_size = 8 - output_shape = 8 - timestep = 4 - batch = 100 - epoch = 10 - - (x_train, y_train), _ = testing_utils.get_test_data( - train_samples=batch, - test_samples=0, - input_shape=(timestep, input_shape), - num_classes=output_shape) - y_train = keras.utils.to_categorical(y_train, output_shape) - - K.set_session(session.Session(config=self.config)) - layer = UnifiedLSTM(rnn_state_size) - - inputs = keras.layers.Input( - shape=[timestep, input_shape], dtype=dtypes.float32) - - outputs, unused_runtime = layer(inputs) - model = keras.models.Model(inputs, outputs) - model.compile('rmsprop', loss='mse') - model.fit(x_train, y_train, epochs=epoch) - def test_unifiedRNN_with_cond(self): # This test is to demonstrate the graph rewrite of grappler plugin under # the condition that the function returns different number of internal @@ -144,7 +124,7 @@ class RNNTest(test.TestCase): batch = 100 epoch = 1 - with ops.Graph().as_default(), session.Session(config=self.config) as sess: + with self.cached_session(config=self.config, use_gpu=True) as sess: (x_train, y_train), _ = testing_utils.get_test_data( train_samples=batch, test_samples=0, @@ -190,37 +170,63 @@ class RNNTest(test.TestCase): self.assertNotEqual(existing_loss, loss_value) existing_loss = loss_value + @test_util.run_in_graph_and_eager_modes(config=config) + def test_keras_model_with_lstm(self): + input_shape = 10 + rnn_state_size = 8 + output_shape = 8 + timestep = 4 + batch = 100 + epoch = 10 + + (x_train, y_train), _ = testing_utils.get_test_data( + train_samples=batch, + test_samples=0, + input_shape=(timestep, input_shape), + num_classes=output_shape) + y_train = keras.utils.to_categorical(y_train, output_shape) + + layer = UnifiedLSTM(rnn_state_size) + + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs, unused_runtime = layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('rmsprop', loss='mse') + model.fit(x_train, y_train, epochs=epoch) + + def _measure_performance(self, test_config, model, x_train, y_train): + batch = test_config['batch'] + epoch = test_config['epoch'] + warmup_epoch = test_config['warmup_epoch'] + + # warm up the model + model.fit(x_train, y_train, batch_size=batch, epochs=warmup_epoch) + start_time = time.time() + model.fit(x_train, y_train, batch_size=batch, epochs=epoch - warmup_epoch) + end_time = time.time() + return (end_time - start_time) / (epoch - warmup_epoch) + def _time_performance_run_cudnn_lstm(self, test_config, x_train, y_train): # Get the performance number for standard Cudnn LSTM input_shape = test_config['input_shape'] rnn_state_size = test_config['rnn_state_size'] timestep = test_config['timestep'] - epoch = test_config['epoch'] - warmup_epoch = test_config['warmup_epoch'] - ops.reset_default_graph() - with self.test_session(use_gpu=True): - cudnn_lstm_layer = CuDNNLSTM(rnn_state_size) - inputs = keras.layers.Input( - shape=[timestep, input_shape], dtype=dtypes.float32) - - outputs = cudnn_lstm_layer(inputs) - model = keras.models.Model(inputs, outputs) - model.compile('sgd', 'mse') - - total_duration = 0 - for i in range(epoch): - start_time = time.time() - model.fit(x_train, y_train) - end_time = time.time() - if i >= warmup_epoch: - duration_per_epoch = end_time - start_time - total_duration += duration_per_epoch - logging.vlog(2, '%s: Time consumed for epoch %d is: %s', - 'CuDNN LSTM', i, duration_per_epoch) - logging.info('Average performance for %s per epoch is: %s', - 'CuDNN LSTM', (total_duration / epoch)) - return total_duration / epoch + cudnn_lstm_layer = CuDNNLSTM(rnn_state_size) + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs = cudnn_lstm_layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('sgd', 'mse') + + sec_per_epoch = self._measure_performance( + test_config, model, x_train, y_train) + logging.info('Average performance for %s per epoch is: %s', + 'CuDNN LSTM', sec_per_epoch) + return sec_per_epoch def _time_performance_run_unifed_lstm_gpu( self, test_config, x_train, y_train): @@ -228,11 +234,7 @@ class RNNTest(test.TestCase): input_shape = test_config['input_shape'] rnn_state_size = test_config['rnn_state_size'] timestep = test_config['timestep'] - epoch = test_config['epoch'] - warmup_epoch = test_config['warmup_epoch'] - ops.reset_default_graph() - K.set_session(session.Session(config=self.config)) layer = UnifiedLSTM(rnn_state_size) inputs = keras.layers.Input( shape=[timestep, input_shape], dtype=dtypes.float32) @@ -241,19 +243,11 @@ class RNNTest(test.TestCase): model = keras.models.Model(inputs, outputs) model.compile('sgd', 'mse') - total_duration = 0 - for i in range(epoch): - start_time = time.time() - model.fit(x_train, y_train) - end_time = time.time() - if i >= warmup_epoch: - duration_per_epoch = end_time - start_time - total_duration += duration_per_epoch - logging.vlog(2, '%s: Time consumed for epoch %d is: %s', - 'Unified LSTM', i, duration_per_epoch) + sec_per_epoch = self._measure_performance( + test_config, model, x_train, y_train) logging.info('Average performance for %s per epoch is: %s', - 'Unified LSTM', (total_duration / epoch)) - return total_duration / epoch + 'Unified LSTM', sec_per_epoch) + return sec_per_epoch def _time_performance_run_normal_lstm( self, test_config, x_train, y_train): @@ -261,49 +255,40 @@ class RNNTest(test.TestCase): input_shape = test_config['input_shape'] rnn_state_size = test_config['rnn_state_size'] timestep = test_config['timestep'] - epoch = test_config['epoch'] - warmup_epoch = test_config['warmup_epoch'] - ops.reset_default_graph() - with self.test_session(use_gpu=True): - layer = keras.layers.LSTM(rnn_state_size) - inputs = keras.layers.Input( - shape=[timestep, input_shape], dtype=dtypes.float32) - - outputs = layer(inputs) - model = keras.models.Model(inputs, outputs) - model.compile('sgd', 'mse') - - total_duration = 0 - for i in range(epoch): - start_time = time.time() - model.fit(x_train, y_train) - end_time = time.time() - if i >= warmup_epoch: - duration_per_epoch = end_time - start_time - total_duration += duration_per_epoch - logging.vlog(2, '%s: Time consumed for epoch %d is: %s', - 'Normal LSTM', i, duration_per_epoch) - logging.info('Average performance for %s per epoch is: %s', - 'Normal LSTM', (total_duration / epoch)) - return total_duration / epoch - - def DISABLED_test_performance_with_standard_cudnn_impl(self): + layer = keras.layers.LSTM(rnn_state_size) + inputs = keras.layers.Input( + shape=[timestep, input_shape], dtype=dtypes.float32) + + outputs = layer(inputs) + model = keras.models.Model(inputs, outputs) + model.compile('sgd', 'mse') + + sec_per_epoch = self._measure_performance( + test_config, model, x_train, y_train) + logging.info('Average performance for %s per epoch is: %s', + 'Normal LSTM', sec_per_epoch) + return sec_per_epoch + + @test_util.run_in_graph_and_eager_modes(config=config, use_gpu=True) + def test_performance_with_standard_cudnn_impl(self): if not test.is_gpu_available(): self.skipTest('performance test will only run on GPU') + batch = 64 + num_batch = 10 test_config = { 'input_shape': 128, 'rnn_state_size': 64, 'output_shape': 64, 'timestep': 50, + 'batch': batch, 'epoch': 20, # The performance for warmup epoch is ignored. 'warmup_epoch': 1, } - batch = 64 (x_train, y_train), _ = testing_utils.get_test_data( - train_samples=batch, + train_samples=(batch * num_batch), test_samples=0, input_shape=(test_config['timestep'], test_config['input_shape']), num_classes=test_config['output_shape']) @@ -318,17 +303,25 @@ class RNNTest(test.TestCase): cudnn_vs_unified = cudnn_duration / unified_lstm_gpu_duration unified_vs_normal = normal_lstm_duration / unified_lstm_gpu_duration - # Assert the performance diff should be within 80% of the native cudnn impl. - self.assertGreaterEqual( - cudnn_vs_unified, 0.80, - 'Expect the performance of Unified LSTM is within 80% of CuDNN LSTM, ' - 'but got {}%'.format(cudnn_vs_unified * 100)) - # Assert the performance diff between CPU impl and GPU impl should be more - # than 5 times. - self.assertGreaterEqual( - unified_vs_normal, 5, - 'Expect the performance of Unified LSTM is more than 5 times of normal ' - 'LSTM, but got {}'.format(unified_vs_normal)) + + # TODO(scottzhu): reeanble the test after moving it to benchmark test suite. + # The current test has performance flakiness issue. + logging.info('Expect the performance of Unified LSTM is within 80% of ' + 'CuDNN LSTM, got {0:.2f}%'.format(cudnn_vs_unified * 100)) + logging.info('Expect the performance of Unified LSTM is more than 5 times' + ' of normal LSTM, got {0:.2f}'.format(unified_vs_normal)) + + # Assert the performance diff should be within 80% of the native cudnn. + # self.assertGreaterEqual( + # cudnn_vs_unified, 0.80, + # 'Expect the performance of Unified LSTM is within 80% of CuDNN LSTM, ' + # 'but got {0:.2f}%'.format(cudnn_vs_unified * 100)) + # # Assert the performance diff between CPU impl and GPU impl should be more + # # than 5 times. + # self.assertGreaterEqual( + # unified_vs_normal, 5, + # 'Expect the performance of Unified LSTM is more than 5 times of ' + # 'normal LSTM, but got {0:.2f}'.format(unified_vs_normal)) class UnifiedLSTM(RNN): @@ -454,13 +447,25 @@ class UnifiedLSTM(RNN): # Reverse time axis. inputs = K.reverse(inputs, 1) - outputs, [new_h, new_c], runtime = normal_lstm( - inputs, initial_state[0], initial_state[1], self.kernel, - self.recurrent_kernel, self.bias, self.units, self.activation, - self.recurrent_activation) - - function.register(cudnn_lstm, inputs, initial_state[0], initial_state[1], - self.kernel, self.recurrent_kernel, self.bias, self.units) + if ops.executing_eagerly_outside_functions(): + if context.num_gpus() > 0: + outputs, [new_h, new_c], runtime = cudnn_lstm( + inputs, initial_state[0], initial_state[1], self.kernel, + self.recurrent_kernel, self.bias, self.units) + else: + outputs, [new_h, new_c], runtime = normal_lstm( + inputs, initial_state[0], initial_state[1], self.kernel, + self.recurrent_kernel, self.bias, self.units, self.activation, + self.recurrent_activation) + else: + outputs, [new_h, new_c], runtime = normal_lstm( + inputs, initial_state[0], initial_state[1], self.kernel, + self.recurrent_kernel, self.bias, self.units, self.activation, + self.recurrent_activation) + + function.register(cudnn_lstm, inputs, initial_state[0], initial_state[1], + self.kernel, self.recurrent_kernel, self.bias, + self.units) states = [new_h, new_c] -- GitLab From 30344d07629fd350686046079fe1ff75c8d36fb5 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 14:07:23 -0800 Subject: [PATCH 331/672] In TF2.x, use thread-local stacks for device functions, control dependencies, and colocation constraints. PiperOrigin-RevId: 222883745 --- tensorflow/python/BUILD | 4 +++- tensorflow/python/framework/ops.py | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 3fe381183a..4cfb90c486 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -861,6 +861,7 @@ py_library( ":platform", ":registry", ":tensor_shape", + ":tf2", ":traceable_stack", ":util", ":versions", @@ -984,6 +985,7 @@ py_library( srcs_version = "PY2AND3", deps = [ ":dtypes", + ":tf2", ":util", "//tensorflow/core:protos_all_py", ], @@ -2085,7 +2087,6 @@ py_library( srcs = ["ops/control_flow_ops.py"], srcs_version = "PY2AND3", deps = [ - "tensor_shape", ":array_ops", ":array_ops_gen", ":constant_op", @@ -2100,6 +2101,7 @@ py_library( ":resource_variable_ops_gen", ":sparse_tensor", ":tensor_array_ops", + ":tensor_shape", ":tf2", ":tf_should_use", ":util", diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index b8187ab20c..ec00778347 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -36,6 +36,7 @@ from tensorflow.core.framework import op_def_pb2 from tensorflow.core.framework import versions_pb2 from tensorflow.core.protobuf import config_pb2 from tensorflow.python import pywrap_tensorflow as c_api +from tensorflow.python import tf2 from tensorflow.python.eager import context from tensorflow.python.eager import core from tensorflow.python.eager import tape @@ -2811,8 +2812,8 @@ class Graph(object): self._stack_state_is_thread_local = False self._thread_local = threading.local() # Functions that will be applied to choose a device if none is specified. - # After switch_to_thread_local(), self._thread_local._device_function_stack - # is used instead. + # In TF2.x or after switch_to_thread_local(), + # self._thread_local._device_function_stack is used instead. self._graph_device_function_stack = traceable_stack.TraceableStack() # Default original_op applied to new ops. self._default_original_op = None @@ -2820,7 +2821,7 @@ class Graph(object): # WhileContext defined in ops/control_flow_ops.py self._control_flow_context = None # A new node will depend of the union of all of the nodes in the stack. - # After switch_to_thread_local(), + # In TF2.x or after switch_to_thread_local(), # self._thread_local._control_dependencies_stack is used instead. self._graph_control_dependencies_stack = [] # Arbitrary collections of objects. @@ -2844,7 +2845,7 @@ class Graph(object): producer=versions.GRAPH_DEF_VERSION, min_consumer=versions.GRAPH_DEF_VERSION_MIN_CONSUMER) self._building_function = False - # Stack of colocate_with ops. After switch_to_thread_local(), + # Stack of colocate_with ops. In TF2.x or after switch_to_thread_local(), # self._thread_local._colocation_stack is used instead. self._graph_colocation_stack = traceable_stack.TraceableStack() # Set of tensors that are dangerous to feed! @@ -2877,6 +2878,8 @@ class Graph(object): # requirement (many custom ops do not have shape functions, and we don't # want to break these existing cases). c_api.SetRequireShapeInferenceFns(self._c_graph, False) + if tf2.enabled(): + self.switch_to_thread_local() # Note: this method is private because the API of tf.Graph() is public and # frozen, and this functionality is still not ready for public visibility. -- GitLab From eb334c580a5763d83f5ca5e3bab69baf4a6919da Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 14:09:15 -0800 Subject: [PATCH 332/672] V2 changes for math.bincount, math.confusion_matrix PiperOrigin-RevId: 222884085 --- tensorflow/python/ops/confusion_matrix.py | 77 ++++++- tensorflow/python/ops/math_ops.py | 82 +++++-- .../tools/api/golden/v2/tensorflow.math.pbtxt | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 217 ++++++++++++------ 4 files changed, 280 insertions(+), 100 deletions(-) diff --git a/tensorflow/python/ops/confusion_matrix.py b/tensorflow/python/ops/confusion_matrix.py index b86b174afe..ccfe3b65c2 100644 --- a/tensorflow/python/ops/confusion_matrix.py +++ b/tensorflow/python/ops/confusion_matrix.py @@ -90,12 +90,13 @@ def remove_squeezable_dimensions( return labels, predictions -@tf_export( - 'math.confusion_matrix', - v1=['math.confusion_matrix', 'confusion_matrix']) -@deprecation.deprecated_endpoints('confusion_matrix', 'train.confusion_matrix') -def confusion_matrix(labels, predictions, num_classes=None, dtype=dtypes.int32, - name=None, weights=None): +@tf_export('math.confusion_matrix', v1=[]) +def confusion_matrix(labels, + predictions, + num_classes=None, + weights=None, + dtype=dtypes.int32, + name=None): """Computes the confusion matrix from predictions and labels. The matrix columns represent the prediction labels and the rows represent the @@ -132,9 +133,9 @@ def confusion_matrix(labels, predictions, num_classes=None, dtype=dtypes.int32, num_classes: The possible number of labels the classification task can have. If this value is not provided, it will be calculated using both predictions and labels array. + weights: An optional `Tensor` whose shape matches `predictions`. dtype: Data type of the confusion matrix. name: Scope name. - weights: An optional `Tensor` whose shape matches `predictions`. Returns: A `Tensor` of type `dtype` with shape `[n, n]` representing the confusion @@ -193,3 +194,65 @@ def confusion_matrix(labels, predictions, num_classes=None, dtype=dtypes.int32, zero_matrix = array_ops.zeros(math_ops.to_int32(shape), dtype) return sparse_ops.sparse_add(zero_matrix, cm_sparse) + + +@tf_export(v1=['math.confusion_matrix', 'confusion_matrix']) +@deprecation.deprecated_endpoints('confusion_matrix', 'train.confusion_matrix') +def confusion_matrix_v1(labels, + predictions, + num_classes=None, + dtype=dtypes.int32, + name=None, + weights=None): + """Computes the confusion matrix from predictions and labels. + + The matrix columns represent the prediction labels and the rows represent the + real labels. The confusion matrix is always a 2-D array of shape `[n, n]`, + where `n` is the number of valid labels for a given classification task. Both + prediction and labels must be 1-D arrays of the same shape in order for this + function to work. + + If `num_classes` is `None`, then `num_classes` will be set to one plus the + maximum value in either predictions or labels. Class labels are expected to + start at 0. For example, if `num_classes` is 3, then the possible labels + would be `[0, 1, 2]`. + + If `weights` is not `None`, then each prediction contributes its + corresponding weight to the total value of the confusion matrix cell. + + For example: + + ```python + tf.confusion_matrix([1, 2, 4], [2, 2, 4]) ==> + [[0 0 0 0 0] + [0 0 1 0 0] + [0 0 1 0 0] + [0 0 0 0 0] + [0 0 0 0 1]] + ``` + + Note that the possible labels are assumed to be `[0, 1, 2, 3, 4]`, + resulting in a 5x5 confusion matrix. + + Args: + labels: 1-D `Tensor` of real labels for the classification task. + predictions: 1-D `Tensor` of predictions for a given classification. + num_classes: The possible number of labels the classification task can have. + If this value is not provided, it will be calculated using both + predictions and labels array. + dtype: Data type of the confusion matrix. + name: Scope name. + weights: An optional `Tensor` whose shape matches `predictions`. + + Returns: + A `Tensor` of type `dtype` with shape `[n, n]` representing the confusion + matrix, where `n` is the number of possible labels in the classification + task. + + Raises: + ValueError: If both predictions and labels are not 1-D vectors and have + mismatched shapes, or if `weights` is not `None` and its shape doesn't + match `predictions`. + """ + return confusion_matrix(labels, predictions, num_classes, weights, dtype, + name) diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index 73ca3d527a..a4e3613079 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -2927,13 +2927,64 @@ def tanh(x, name=None): return gen_math_ops.tanh(x, name=name) -@tf_export("math.bincount", v1=["math.bincount", "bincount"]) -@deprecation.deprecated_endpoints("bincount") +@tf_export("math.bincount", v1=[]) def bincount(arr, weights=None, minlength=None, maxlength=None, - dtype=dtypes.int32): + dtype=dtypes.int32, + name=None): + """Counts the number of occurrences of each value in an integer array. + + If `minlength` and `maxlength` are not given, returns a vector with length + `tf.reduce_max(arr) + 1` if `arr` is non-empty, and length 0 otherwise. + If `weights` are non-None, then index `i` of the output stores the sum of the + value in `weights` at each index where the corresponding value in `arr` is + `i`. + + Args: + arr: An int32 tensor of non-negative values. + weights: If non-None, must be the same shape as arr. For each value in + `arr`, the bin will be incremented by the corresponding weight instead of + 1. + minlength: If given, ensures the output has length at least `minlength`, + padding with zeros at the end if necessary. + maxlength: If given, skips values in `arr` that are equal or greater than + `maxlength`, ensuring that the output has length at most `maxlength`. + dtype: If `weights` is None, determines the type of the output bins. + name: A name scope for the associated operations (optional). + + Returns: + A vector with the same dtype as `weights` or the given `dtype`. The bin + values. + """ + name = "bincount" if name is None else name + with ops.name_scope(name): + arr = ops.convert_to_tensor(arr, name="arr", dtype=dtypes.int32) + array_is_nonempty = reduce_prod(array_ops.shape(arr)) > 0 + output_size = cast(array_is_nonempty, dtypes.int32) * (reduce_max(arr) + 1) + if minlength is not None: + minlength = ops.convert_to_tensor( + minlength, name="minlength", dtype=dtypes.int32) + output_size = gen_math_ops.maximum(minlength, output_size) + if maxlength is not None: + maxlength = ops.convert_to_tensor( + maxlength, name="maxlength", dtype=dtypes.int32) + output_size = gen_math_ops.minimum(maxlength, output_size) + if weights is not None: + weights = ops.convert_to_tensor(weights, name="weights") + return gen_math_ops.unsorted_segment_sum(weights, arr, output_size) + weights = constant_op.constant([], dtype) + return gen_math_ops.bincount(arr, output_size, weights) + + +@tf_export(v1=["math.bincount", "bincount"]) +@deprecation.deprecated_endpoints("bincount") +def bincount_v1(arr, + weights=None, + minlength=None, + maxlength=None, + dtype=dtypes.int32): """Counts the number of occurrences of each value in an integer array. If `minlength` and `maxlength` are not given, returns a vector with length @@ -2945,34 +2996,19 @@ def bincount(arr, Args: arr: An int32 tensor of non-negative values. weights: If non-None, must be the same shape as arr. For each value in - `arr`, the bin will be incremented by the corresponding weight instead - of 1. + `arr`, the bin will be incremented by the corresponding weight instead of + 1. minlength: If given, ensures the output has length at least `minlength`, - padding with zeros at the end if necessary. + padding with zeros at the end if necessary. maxlength: If given, skips values in `arr` that are equal or greater than - `maxlength`, ensuring that the output has length at most `maxlength`. + `maxlength`, ensuring that the output has length at most `maxlength`. dtype: If `weights` is None, determines the type of the output bins. Returns: A vector with the same dtype as `weights` or the given `dtype`. The bin values. """ - arr = ops.convert_to_tensor(arr, name="arr", dtype=dtypes.int32) - array_is_nonempty = reduce_prod(array_ops.shape(arr)) > 0 - output_size = cast(array_is_nonempty, dtypes.int32) * (reduce_max(arr) + 1) - if minlength is not None: - minlength = ops.convert_to_tensor( - minlength, name="minlength", dtype=dtypes.int32) - output_size = gen_math_ops.maximum(minlength, output_size) - if maxlength is not None: - maxlength = ops.convert_to_tensor( - maxlength, name="maxlength", dtype=dtypes.int32) - output_size = gen_math_ops.minimum(maxlength, output_size) - if weights is not None: - weights = ops.convert_to_tensor(weights, name="weights") - return gen_math_ops.unsorted_segment_sum(weights, arr, output_size) - weights = constant_op.constant([], dtype) - return gen_math_ops.bincount(arr, output_size, weights) + return bincount(arr, weights, minlength, maxlength, dtype) @tf_export("math.cumsum", "cumsum") diff --git a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt index c10361f90d..f5bbb77d32 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt @@ -78,7 +78,7 @@ tf_module { } member_method { name: "bincount" - argspec: "args=[\'arr\', \'weights\', \'minlength\', \'maxlength\', \'dtype\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \"\"], " + argspec: "args=[\'arr\', \'weights\', \'minlength\', \'maxlength\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \"\", \'None\'], " } member_method { name: "ceil" @@ -86,7 +86,7 @@ tf_module { } member_method { name: "confusion_matrix" - argspec: "args=[\'labels\', \'predictions\', \'num_classes\', \'dtype\', \'name\', \'weights\'], varargs=None, keywords=None, defaults=[\'None\', \"\", \'None\', \'None\'], " + argspec: "args=[\'labels\', \'predictions\', \'num_classes\', \'weights\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \"\", \'None\'], " } member_method { name: "conj" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index ed29a7cb62..eb4e62b895 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -246,71 +246,142 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # function_reorders or function_keyword_renames, use the OLD function name. # These renames happen after the arguments have been processed. self.symbol_renames.update({ - "tf.batch_to_space_nd": "tf.batch_to_space", - "tf.gfile.Copy": "tf.io.gfile.Copy", - "tf.gfile.DeleteRecursively": "tf.io.gfile.DeleteRecursively", - "tf.gfile.Exists": "tf.io.gfile.Exists", - "tf.gfile.Glob": "tf.io.gfile.Glob", - "tf.gfile.IsDirectory": "tf.io.gfile.IsDirectory", - "tf.gfile.ListDirectory": "tf.io.gfile.ListDirectory", - "tf.gfile.MakeDirs": "tf.io.gfile.MakeDirs", - "tf.gfile.MkDir": "tf.io.gfile.MkDir", - "tf.gfile.Remove": "tf.io.gfile.Remove", - "tf.gfile.Rename": "tf.io.gfile.Rename", - "tf.gfile.Stat": "tf.io.gfile.Stat", - "tf.gfile.Walk": "tf.io.gfile.Walk", - "tf.contrib.data.AUTOTUNE": "tf.data.experimental.AUTOTUNE", - "tf.contrib.data.Counter": "tf.data.experimental.Counter", - "tf.contrib.data.CheckpointInputPipelineHook": "tf.data.experimental.CheckpointInputPipelineHook", - "tf.contrib.data.CsvDataset": "tf.data.experimental.CsvDataset", - "tf.contrib.data.Optional": "tf.data.experimental.Optional", - "tf.contrib.data.RandomDataset": "tf.data.experimental.RandomDataset", - "tf.contrib.data.Reducer": "tf.data.experimental.Reducer", - "tf.contrib.data.SqlDataset": "tf.data.experimental.SqlDataset", - "tf.contrib.data.StatsAggregator": "tf.data.experimental.StatsAggregator", - "tf.contrib.data.TFRecordWriter": "tf.data.experimental.TFRecordWriter", - "tf.contrib.data.assert_element_shape": "tf.data.experimental.assert_element_shape", - "tf.contrib.data.batch_and_drop_remainder": "tf.compat.v1.contrib.data.batch_and_drop_remainder", - "tf.contrib.data.bucket_by_sequence_length": "tf.data.experimental.bucket_by_sequence_length", - "tf.contrib.data.choose_from_datasets": "tf.data.experimental.choose_from_datasets", - "tf.contrib.data.copy_to_device": "tf.data.experimental.copy_to_device", - "tf.contrib.data.dense_to_sparse_batch": "tf.data.experimental.dense_to_sparse_batch", - "tf.contrib.data.enumerate_dataset": "tf.data.experimental.enumerate_dataset", - "tf.contrib.data.get_next_as_optional": "tf.data.experimental.get_next_as_optional", - "tf.contrib.data.get_single_element": "tf.data.experimental.get_single_element", - "tf.contrib.data.group_by_reducer": "tf.data.experimental.group_by_reducer", - "tf.contrib.data.group_by_window": "tf.data.experimental.group_by_window", - "tf.contrib.data.ignore_errors": "tf.data.experimental.ignore_errors", - "tf.contrib.data.latency_stats": "tf.data.experimental.latency_stats", - "tf.contrib.data.make_batched_features_dataset": "tf.data.experimental.make_batched_features_dataset", - "tf.contrib.data.make_csv_dataset": "tf.data.experimental.make_csv_dataset", - "tf.contrib.data.make_saveable_from_iterator": "tf.data.experimental.make_saveable_from_iterator", - "tf.contrib.data.map_and_batch": "tf.data.experimental.map_and_batch", - "tf.contrib.data.padded_batch_and_drop_remainder": "tf.compat.v1.contrib.data.padded_batch_and_drop_remainder", - "tf.contrib.data.parallel_interleave": "tf.data.experimental.parallel_interleave", - "tf.contrib.data.parse_example_dataset": "tf.data.experimental.parse_example_dataset", - "tf.contrib.data.prefetch_to_device": "tf.data.experimental.prefetch_to_device", - "tf.contrib.data.read_batch_features": "tf.compat.v1.contrib.data.read_batch_features", - "tf.contrib.data.reduce_dataset": "tf.compat.v1.contrib.data.reduce_dataset", - "tf.contrib.data.rejection_resample": "tf.data.experimental.rejection_resample", - "tf.contrib.data.sample_from_datasets": "tf.data.experimental.sample_from_datasets", - "tf.contrib.data.scan": "tf.data.experimental.scan", - "tf.contrib.data.set_stats_aggregator": "tf.data.experimental.set_stats_aggregator", - "tf.contrib.data.shuffle_and_repeat": "tf.data.experimental.shuffle_and_repeat", - "tf.contrib.data.sliding_window_batch": "tf.compat.v1.contrib.data.sliding_window_batch", - "tf.contrib.data.sloppy_interleave": "tf.compat.v1.contrib.data.sloppy_interleave", - "tf.contrib.data.unbatch": "tf.data.experimental.unbatch", - "tf.contrib.data.unique": "tf.data.experimental.unique", - "tf.contrib.framework.sort": "tf.sort", - "tf.contrib.framework.argsort": "tf.argsort", - "tf.manip.batch_to_space_nd": "tf.batch_to_space", - "tf.quantize_v2": "tf.quantization.quantize", - "tf.sparse_concat": "tf.sparse.concat", - "tf.sparse_split": "tf.sparse.split", - "tf.multinomial": "tf.random.categorical", - "tf.random.multinomial": "tf.random.categorical", - "tf.load_file_system_library": "tf.load_library", - "tf.pywrap_tensorflow": "tf.compat.v1.pywrap_tensorflow", + "tf.batch_to_space_nd": + "tf.batch_to_space", + "tf.gfile.Copy": + "tf.io.gfile.Copy", + "tf.gfile.DeleteRecursively": + "tf.io.gfile.DeleteRecursively", + "tf.gfile.Exists": + "tf.io.gfile.Exists", + "tf.gfile.Glob": + "tf.io.gfile.Glob", + "tf.gfile.IsDirectory": + "tf.io.gfile.IsDirectory", + "tf.gfile.ListDirectory": + "tf.io.gfile.ListDirectory", + "tf.gfile.MakeDirs": + "tf.io.gfile.MakeDirs", + "tf.gfile.MkDir": + "tf.io.gfile.MkDir", + "tf.gfile.Remove": + "tf.io.gfile.Remove", + "tf.gfile.Rename": + "tf.io.gfile.Rename", + "tf.gfile.Stat": + "tf.io.gfile.Stat", + "tf.gfile.Walk": + "tf.io.gfile.Walk", + "tf.contrib.data.AUTOTUNE": + "tf.data.experimental.AUTOTUNE", + "tf.contrib.data.Counter": + "tf.data.experimental.Counter", + "tf.contrib.data.CheckpointInputPipelineHook": + "tf.data.experimental.CheckpointInputPipelineHook", + "tf.contrib.data.CsvDataset": + "tf.data.experimental.CsvDataset", + "tf.contrib.data.Optional": + "tf.data.experimental.Optional", + "tf.contrib.data.RandomDataset": + "tf.data.experimental.RandomDataset", + "tf.contrib.data.Reducer": + "tf.data.experimental.Reducer", + "tf.contrib.data.SqlDataset": + "tf.data.experimental.SqlDataset", + "tf.contrib.data.StatsAggregator": + "tf.data.experimental.StatsAggregator", + "tf.contrib.data.TFRecordWriter": + "tf.data.experimental.TFRecordWriter", + "tf.contrib.data.assert_element_shape": + "tf.data.experimental.assert_element_shape", + "tf.contrib.data.batch_and_drop_remainder": + "tf.compat.v1.contrib.data.batch_and_drop_remainder", + "tf.contrib.data.bucket_by_sequence_length": + "tf.data.experimental.bucket_by_sequence_length", + "tf.contrib.data.choose_from_datasets": + "tf.data.experimental.choose_from_datasets", + "tf.contrib.data.copy_to_device": + "tf.data.experimental.copy_to_device", + "tf.contrib.data.dense_to_sparse_batch": + "tf.data.experimental.dense_to_sparse_batch", + "tf.contrib.data.enumerate_dataset": + "tf.data.experimental.enumerate_dataset", + "tf.contrib.data.get_next_as_optional": + "tf.data.experimental.get_next_as_optional", + "tf.contrib.data.get_single_element": + "tf.data.experimental.get_single_element", + "tf.contrib.data.group_by_reducer": + "tf.data.experimental.group_by_reducer", + "tf.contrib.data.group_by_window": + "tf.data.experimental.group_by_window", + "tf.contrib.data.ignore_errors": + "tf.data.experimental.ignore_errors", + "tf.contrib.data.latency_stats": + "tf.data.experimental.latency_stats", + "tf.contrib.data.make_batched_features_dataset": + "tf.data.experimental.make_batched_features_dataset", + "tf.contrib.data.make_csv_dataset": + "tf.data.experimental.make_csv_dataset", + "tf.contrib.data.make_saveable_from_iterator": + "tf.data.experimental.make_saveable_from_iterator", + "tf.contrib.data.map_and_batch": + "tf.data.experimental.map_and_batch", + "tf.contrib.data.padded_batch_and_drop_remainder": + "tf.compat.v1.contrib.data.padded_batch_and_drop_remainder", + "tf.contrib.data.parallel_interleave": + "tf.data.experimental.parallel_interleave", + "tf.contrib.data.parse_example_dataset": + "tf.data.experimental.parse_example_dataset", + "tf.contrib.data.prefetch_to_device": + "tf.data.experimental.prefetch_to_device", + "tf.contrib.data.read_batch_features": + "tf.compat.v1.contrib.data.read_batch_features", + "tf.contrib.data.reduce_dataset": + "tf.compat.v1.contrib.data.reduce_dataset", + "tf.contrib.data.rejection_resample": + "tf.data.experimental.rejection_resample", + "tf.contrib.data.sample_from_datasets": + "tf.data.experimental.sample_from_datasets", + "tf.contrib.data.scan": + "tf.data.experimental.scan", + "tf.contrib.data.set_stats_aggregator": + "tf.data.experimental.set_stats_aggregator", + "tf.contrib.data.shuffle_and_repeat": + "tf.data.experimental.shuffle_and_repeat", + "tf.contrib.data.sliding_window_batch": + "tf.compat.v1.contrib.data.sliding_window_batch", + "tf.contrib.data.sloppy_interleave": + "tf.compat.v1.contrib.data.sloppy_interleave", + "tf.contrib.data.unbatch": + "tf.data.experimental.unbatch", + "tf.contrib.data.unique": + "tf.data.experimental.unique", + "tf.contrib.framework.sort": + "tf.sort", + "tf.contrib.framework.argsort": + "tf.argsort", + "tf.manip.batch_to_space_nd": + "tf.batch_to_space", + "tf.quantize_v2": + "tf.quantization.quantize", + "tf.sparse_concat": + "tf.sparse.concat", + "tf.sparse_split": + "tf.sparse.split", + "tf.multinomial": + "tf.random.categorical", + "tf.random.multinomial": + "tf.random.categorical", + "tf.load_file_system_library": + "tf.load_library", + "tf.pywrap_tensorflow": + "tf.compat.v1.pywrap_tensorflow", + "tf.bincount": + "tf.math.bincount", + "tf.confusion_matrix": + "tf.math.confusion_matrix", + "tf.train.confusion_matrix": + "tf.math.confusion_matrix", }) # pylint: enable=line-too-long @@ -380,9 +451,13 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "data", "indices", "segment_ids", "name", "num_segments" ], "tf.io.decode_csv": [ - "records", "record_defaults", - "field_delim", "use_quote_delim", - "name", "na_value", "select_cols", + "records", + "record_defaults", + "field_delim", + "use_quote_delim", + "name", + "na_value", + "select_cols", ], "tf.strings.substr": ["input", "pos", "len", "name", "unit"], "tf.strings.reduce_join": [ @@ -471,6 +546,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "input", "axis", "keep_dims", "separator", "name", "reduction_indices" ], + "tf.confusion_matrix": [ + "labels", "predictions", "num_classes", "dtype", "name", "weights" + ], + "tf.math.confusion_matrix": [ + "labels", "predictions", "num_classes", "dtype", "name", "weights" + ] } # Specially handled functions. -- GitLab From 44d7919d0a46305d4eeaa63b84294a2e12aa97c1 Mon Sep 17 00:00:00 2001 From: Anjali Sridhar Date: Mon, 26 Nov 2018 14:16:48 -0800 Subject: [PATCH 333/672] Add support for dynamic learning rate to MirroredStrategy. PiperOrigin-RevId: 222885339 --- .../contrib/distribute/python/keras_test.py | 34 +++++++++++++++---- .../engine/distributed_training_utils.py | 24 +++++++++---- tensorflow/python/keras/engine/training.py | 7 ++-- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/tensorflow/contrib/distribute/python/keras_test.py b/tensorflow/contrib/distribute/python/keras_test.py index 29d85fe971..07027bde8a 100644 --- a/tensorflow/contrib/distribute/python/keras_test.py +++ b/tensorflow/contrib/distribute/python/keras_test.py @@ -35,6 +35,7 @@ from tensorflow.python.framework import random_seed from tensorflow.python.framework import test_util from tensorflow.python.keras import testing_utils from tensorflow.python.keras.engine import distributed_training_utils +from tensorflow.python.keras.optimizer_v2 import gradient_descent as gradient_descent_keras from tensorflow.python.ops.parsing_ops import gen_parsing_ops from tensorflow.python.platform import gfile from tensorflow.python.platform import test @@ -42,7 +43,6 @@ from tensorflow.python.summary.writer import writer_cache from tensorflow.python.training import gradient_descent from tensorflow.python.training import rmsprop - _RANDOM_SEED = 1337 _TRAIN_SIZE = 200 _INPUT_SIZE = (10,) @@ -973,6 +973,28 @@ class TestDistributionStrategyWithDatasets(test.TestCase, ref_output = np.ones((160, 1), dtype=np.float32) self.assertArrayNear(output, ref_output, 1e-1) + @combinations.generate(strategy_minus_tpu_combinations()) + def testOptimizerWithCallbacks(self, distribution): + with self.cached_session(): + model = get_model() + + optimizer = gradient_descent_keras.SGD(0.01) + loss = 'mse' + model.compile(optimizer, loss, distribute=distribution) + + dataset = get_dataset(distribution) + + def schedule(_): + return 0.001 + + model.fit(dataset, epochs=1, steps_per_epoch=2, verbose=0, + callbacks=[keras.callbacks.LearningRateScheduler(schedule)]) + grouped_models = distribution.unwrap(model._grouped_model) + with distribution.scope(): + for m in grouped_models: + self.assertAllClose(0.001, keras.backend.get_value( + m.optimizer.lr), atol=1e-05, rtol=1e-05) + class TestDistributionStrategyErrorCases(test.TestCase, parameterized.TestCase): @@ -1090,14 +1112,14 @@ class TestDistributionStrategyErrorCases(test.TestCase, parameterized.TestCase): def schedule(_): return 0.001 with self.assertRaisesRegexp(ValueError, - 'LearningRateScheduler callback is not ' - 'supported with DistributionStrategy.'): + 'You must specify a Keras Optimizer V2 when ' + 'using'): model.fit(dataset, epochs=1, steps_per_epoch=2, verbose=0, callbacks=[keras.callbacks.LearningRateScheduler(schedule)]) with self.assertRaisesRegexp(ValueError, - 'ReduceLROnPlateau callback is not ' - 'supported with DistributionStrategy.'): + 'You must specify a Keras Optimizer V2 when ' + 'using'): model.fit(dataset, epochs=1, steps_per_epoch=2, verbose=0, callbacks=[keras.callbacks.ReduceLROnPlateau()]) with self.assertRaisesRegexp(ValueError, @@ -1247,7 +1269,7 @@ class TestDistributionStrategyCorrectness(test.TestCase, model.set_weights(initial_weights) model.compile( loss=keras.losses.mean_squared_error, - optimizer=gradient_descent.GradientDescentOptimizer(0.5), + optimizer=gradient_descent_keras.SGD(0.5), distribute=with_distribution) training_inputs, eval_inputs, predict_inputs = ( diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index fba557ff5b..bb8174e26a 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util from tensorflow.python.keras import backend as K from tensorflow.python.keras import callbacks +from tensorflow.python.keras.optimizer_v2 import optimizer_v2 from tensorflow.python.ops import array_ops from tensorflow.python.ops import variables from tensorflow.python.platform import tf_logging as logging @@ -145,11 +146,14 @@ def flatten_perdevice_values(distribution_strategy, perdevice_values): for e in distribution_strategy.unwrap(flattened)] -def validate_callbacks(input_callbacks): +def validate_callbacks(input_callbacks, optimizer, current_strategy): """Validate whether given callbacks are supported by DistributionStrategy. Args: input_callbacks: List of callbacks passed by the user to fit. + optimizer: Optimizer instance used to train the model. + current_strategy: The DistributionStrategy used to distribute training + and validation. Raises: ValueError: If `LearningRateScheduler` or `ReduceLROnPlateau` is one of the @@ -171,12 +175,18 @@ def validate_callbacks(input_callbacks): 'these attributes are not set. You can access each of ' 'the individual distributed models using the ' '`_grouped_model` attribute of your original model.') - if isinstance(callback, callbacks.LearningRateScheduler): - raise ValueError('LearningRateScheduler callback is not supported with ' - 'DistributionStrategy.') - if isinstance(callback, callbacks.ReduceLROnPlateau): - raise ValueError('ReduceLROnPlateau callback is not supported with ' - 'DistributionStrategy.') + if isinstance(callback, (callbacks.LearningRateScheduler, + callbacks.ReduceLROnPlateau)): + strategy_name = current_strategy.__class__.__name__ + # TODO(anjalisridhar): We might need to add a condition for multi + # worker strategy when we support it in Keras. + if is_tpu_strategy(current_strategy): + raise ValueError('%s callback is not supported with %s.' % + (callback, strategy_name)) + + if not isinstance(optimizer, optimizer_v2.OptimizerV2): + raise ValueError('You must specify a Keras Optimizer V2 when using ' + '%s callback with DistributionStrategy.' % callback) # If users want to use the TensorBoard callback they cannot use certain # features of the callback that involve accessing model attributes and diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index 8c564ed61b..4d3fffb25a 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -1676,7 +1676,8 @@ class Model(Network): # Validate and standardize user data. if self._distribution_strategy: - distributed_training_utils.validate_callbacks(callbacks) + distributed_training_utils.validate_callbacks(callbacks, self.optimizer, + self._distribution_strategy) distributed_training_utils.validate_inputs( x, y, self._distribution_strategy) @@ -2488,9 +2489,7 @@ class DistributedCallbackModel(Model): def __init__(self, model): super(DistributedCallbackModel, self).__init__() - # TODO(anjalisridhar): Right now the only attributes set are the layer and - # weights. We may need to set additional attributes as needed since we have - # not called compile on this model. + self.optimizer = model.optimizer def set_original_model(self, orig_model): self._original_model = orig_model -- GitLab From d530dd79e70820a6791f4f6158c225d3d2e23c46 Mon Sep 17 00:00:00 2001 From: Yanan Cao Date: Mon, 26 Nov 2018 14:22:54 -0800 Subject: [PATCH 334/672] Allow HLO version of Argmax as fallback when CustomCall is not supported PiperOrigin-RevId: 222886344 --- .../compiler/tf2xla/kernels/index_ops_cpu.cc | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc index dce9641f63..20b7176041 100644 --- a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc +++ b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc @@ -30,7 +30,9 @@ limitations under the License. namespace tensorflow { namespace { -// The logic below uses a custom-call to implement argmax. +// The logic below uses a custom-call to implement argmax when possible. When +// custom-call is not allowed or input shapes are not supported, this kernel +// falls back to using XLA HLO native ArgMax. // // Also see b/29507024 for first-class XLA support for indexing ops. class ArgMaxCustomCallOp : public XlaOpKernel { @@ -64,16 +66,26 @@ class ArgMaxCustomCallOp : public XlaOpKernel { "Reduction axis ", dim, " is empty in shape: ", input_shape.DebugString())); + const DataType dtype = output_type(0); + xla::PrimitiveType output_type; + OP_REQUIRES_OK(ctx, DataTypeToPrimitiveType(dtype, &output_type)); + + // Fall back to XLA ArgMax HLO when CustomCall is not allowed or when input + // shape isn't supported. + if (!XlaContext::Get(ctx).allow_cpu_custom_calls() || + (input_dims != 1 && input_dims != 2)) { + xla::XlaOp output = XlaHelpers::ArgMax(ctx->Input(0), output_type, axis); + ctx->SetOutput(0, output); + return; + } + + xla::XlaOp output; // The output shape is the input shape contracted along axis. TensorShape output_shape; for (int d = 0; d < input_shape.dims() - 1; ++d) { output_shape.AddDim(input_shape.dim_size((d < axis) ? d : d + 1)); } - // For now we use a custom-call, only for the 1d and 2d cases. - OP_REQUIRES(ctx, XlaContext::Get(ctx).allow_cpu_custom_calls(), - errors::InvalidArgument( - "ArgMax implementation requires a CustomCall on CPU")); xla::XlaBuilder& b = *ctx->builder(); // XLA passes to the function, so it is not included here. @@ -104,27 +116,14 @@ class ArgMaxCustomCallOp : public XlaOpKernel { } // Tell XLA to call the custom code, defined in - // index_ops_kernel_argmax_float_1d.cc. - xla::XlaOp output; - switch (input_shape.dims()) { - case 1: - output = xla::CustomCallWithLayout(&b, "argmax_float_1d_xla_impl", args, - xla_shape, arg_shapes); - break; - case 2: - output = xla::CustomCallWithLayout(&b, "argmax_float_2d_xla_impl", args, - xla_shape, arg_shapes); - break; - default: - OP_REQUIRES(ctx, false, - errors::Unimplemented( - "Argmax is only implemented for 1d and 2d tensors" - ", but got shape: ", - input_shape.DebugString())); + // index_ops_kernel_argmax_float_{1, 2}d.cc. + if (input_dims == 1) { + output = xla::CustomCallWithLayout(&b, "argmax_float_1d_xla_impl", args, + xla_shape, arg_shapes); + } else { + output = xla::CustomCallWithLayout(&b, "argmax_float_2d_xla_impl", args, + xla_shape, arg_shapes); } - const DataType dtype = output_type(0); - xla::PrimitiveType output_type; - OP_REQUIRES_OK(ctx, DataTypeToPrimitiveType(dtype, &output_type)); output = xla::ConvertElementType(output, output_type); ctx->SetOutput(0, output); } -- GitLab From 315336dafd057c494e015d7a7716573fa33a5a40 Mon Sep 17 00:00:00 2001 From: Pete Warden Date: Mon, 26 Nov 2018 14:27:47 -0800 Subject: [PATCH 335/672] Add input processing to micro speech example PiperOrigin-RevId: 222887236 --- .../micro/examples/micro_speech/BUILD | 211 ++++++++++++++++-- .../examples/micro_speech/audio_provider.cc | 33 +++ .../examples/micro_speech/audio_provider.h | 36 +++ .../micro_speech/audio_provider_test.cc | 44 ++++ .../examples/micro_speech/feature_provider.cc | 121 ++++++++++ .../examples/micro_speech/feature_provider.h | 48 ++++ .../micro_speech/feature_provider_test.cc | 38 ++++ .../micro_speech/fixed_point/preprocessor.cc | 44 ++-- .../micro/examples/micro_speech/main.cc | 112 ++++++++++ .../examples/micro_speech/model_settings.cc | 23 ++ .../examples/micro_speech/model_settings.h | 42 ++++ .../examples/micro_speech/preprocessor.cc | 36 ++- .../examples/micro_speech/preprocessor.h | 5 + .../micro/examples/micro_speech/timer.cc | 22 ++ .../micro/examples/micro_speech/timer.h | 31 +++ .../micro/examples/micro_speech/timer_test.cc | 46 ++++ .../experimental/micro/testing/micro_test.h | 18 ++ 17 files changed, 843 insertions(+), 67 deletions(-) create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/main.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer.h create mode 100644 tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD b/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD index 07fb876411..799b2e5a5d 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/BUILD @@ -10,18 +10,46 @@ load( "tflite_micro_cc_test", ) -tflite_micro_cc_test( - name = "micro_speech_test", +cc_library( + name = "model_settings", + srcs = [ + "model_settings.cc", + ], + hdrs = [ + "model_settings.h", + ], +) + +cc_library( + name = "tiny_conv_model_data", srcs = [ - "micro_speech_test.cc", - "no_features_data.cc", - "no_features_data.h", "tiny_conv_model_data.cc", + ], + hdrs = [ "tiny_conv_model_data.h", + ], +) + +cc_library( + name = "features_test_data", + srcs = [ + "no_features_data.cc", "yes_features_data.cc", + ], + hdrs = [ + "no_features_data.h", "yes_features_data.h", ], +) + +tflite_micro_cc_test( + name = "micro_speech_test", + srcs = [ + "micro_speech_test.cc", + ], deps = [ + ":features_test_data", + ":tiny_conv_model_data", "//tensorflow/lite:schema_fbs_version", "//tensorflow/lite/experimental/micro:micro_framework", "//tensorflow/lite/experimental/micro/kernels:all_ops_resolver", @@ -31,46 +59,185 @@ tflite_micro_cc_test( ], ) -tflite_micro_cc_test( - name = "preprocessor_reference_test", +cc_library( + name = "preprocessor_test_data", srcs = [ "no_30ms_sample_data.cc", - "no_30ms_sample_data.h", "no_power_spectrum_data.cc", + "yes_30ms_sample_data.cc", + "yes_power_spectrum_data.cc", + ], + hdrs = [ + "no_30ms_sample_data.h", "no_power_spectrum_data.h", + "yes_30ms_sample_data.h", + "yes_power_spectrum_data.h", + ], +) + +cc_library( + name = "preprocessor_reference", + srcs = [ "preprocessor.cc", + ], + hdrs = [ "preprocessor.h", + ], + deps = [ + ":model_settings", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + ], +) + +tflite_micro_cc_test( + name = "preprocessor_reference_test", + srcs = [ "preprocessor_test.cc", - "yes_30ms_sample_data.cc", - "yes_30ms_sample_data.h", - "yes_power_spectrum_data.cc", - "yes_power_spectrum_data.h", ], deps = [ + ":model_settings", + ":preprocessor_reference", + ":preprocessor_test_data", "//tensorflow/lite/c:c_api_internal", "//tensorflow/lite/experimental/micro:micro_framework", "//tensorflow/lite/experimental/micro/testing:micro_test", ], ) -tflite_micro_cc_test( - name = "preprocessor_fixed_test", +cc_library( + name = "preprocessor_fixed", srcs = [ "fixed_point/preprocessor.cc", - "no_30ms_sample_data.cc", - "no_30ms_sample_data.h", - "no_power_spectrum_data.cc", - "no_power_spectrum_data.h", + ], + hdrs = [ "preprocessor.h", + ], + deps = [ + ":model_settings", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + ], +) + +tflite_micro_cc_test( + name = "preprocessor_fixed_test", + srcs = [ "preprocessor_test.cc", - "yes_30ms_sample_data.cc", - "yes_30ms_sample_data.h", - "yes_power_spectrum_data.cc", - "yes_power_spectrum_data.h", ], deps = [ + ":model_settings", + ":preprocessor_fixed", + ":preprocessor_test_data", "//tensorflow/lite/c:c_api_internal", "//tensorflow/lite/experimental/micro:micro_framework", "//tensorflow/lite/experimental/micro/testing:micro_test", ], ) + +cc_library( + name = "audio_provider", + srcs = [ + "audio_provider.cc", + ], + hdrs = [ + "audio_provider.h", + ], + deps = [ + ":model_settings", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + ], +) + +tflite_micro_cc_test( + name = "audio_provider_test", + srcs = [ + "audio_provider_test.cc", + ], + deps = [ + ":audio_provider", + ":model_settings", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + +cc_library( + name = "feature_provider", + srcs = [ + "feature_provider.cc", + ], + hdrs = [ + "feature_provider.h", + ], + deps = [ + ":audio_provider", + ":model_settings", + ":preprocessor_reference", + ":timer", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + ], +) + +tflite_micro_cc_test( + name = "feature_provider_test", + srcs = [ + "feature_provider_test.cc", + ], + deps = [ + ":audio_provider", + ":feature_provider", + ":model_settings", + ":timer", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + +cc_library( + name = "timer", + srcs = [ + "timer.cc", + ], + hdrs = [ + "timer.h", + ], +) + +tflite_micro_cc_test( + name = "timer_test", + srcs = [ + "timer_test.cc", + ], + deps = [ + ":timer", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + +cc_binary( + name = "micro_speech", + srcs = [ + "main.cc", + ], + deps = [ + ":audio_provider", + ":feature_provider", + ":features_test_data", + ":model_settings", + ":preprocessor_reference", + ":timer", + ":tiny_conv_model_data", + "//tensorflow/lite:schema_fbs_version", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/kernels:all_ops_resolver", + "//tensorflow/lite/experimental/micro/kernels:micro_ops", + "//tensorflow/lite/schema:schema_fbs", + ], +) diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc new file mode 100644 index 0000000000..c0365d5690 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.cc @@ -0,0 +1,33 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" + +namespace { +int16_t g_dummy_audio_data[kMaxAudioSampleSize]; +} // namespace + +TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, + int start_ms, int duration_ms, + int* audio_samples_size, int16_t** audio_samples) { + for (int i = 0; i < kMaxAudioSampleSize; ++i) { + g_dummy_audio_data[i] = 0; + } + *audio_samples_size = kMaxAudioSampleSize; + *audio_samples = g_dummy_audio_data; + return kTfLiteOk; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h new file mode 100644 index 0000000000..7e2442a5e8 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h @@ -0,0 +1,36 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" + +// This is an abstraction around an audio source like a microphone, and is +// expected to return 16-bit PCM sample data for a given point in time. The +// sample data itself should be used as quickly as possible by the caller, since +// to allow memory optimizations there are no guarantees that the samples won't +// be overwritten by new data in the future. In practice, implementations should +// ensure that there's a reasonable time allowed for clients to access the data +// before any reuse. +// The reference implementation can have no platform-specific dependencies, so +// it just returns an array filled with zeros. For real applications, you should +// ensure there's a specialized implementation that accesses hardware APIs. +TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, + int start_ms, int duration_ms, + int* audio_samples_size, int16_t** audio_samples); + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc new file mode 100644 index 0000000000..5f7c7605f0 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider_test.cc @@ -0,0 +1,44 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(TestAudioProvider) { + tflite::MicroErrorReporter micro_error_reporter; + tflite::ErrorReporter* error_reporter = µ_error_reporter; + + int audio_samples_size = 0; + int16_t* audio_samples = nullptr; + TfLiteStatus get_status = + GetAudioSamples(error_reporter, 0, kFeatureSliceDurationMs, + &audio_samples_size, &audio_samples); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, get_status); + TF_LITE_MICRO_EXPECT_LE(audio_samples_size, kMaxAudioSampleSize); + TF_LITE_MICRO_EXPECT_NE(audio_samples, nullptr); + + // Make sure we can read all of the returned memory locations. + int total = 0; + for (int i = 0; i < audio_samples_size; ++i) { + total += audio_samples[i]; + } +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc new file mode 100644 index 0000000000..c4c52ac0ff --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.cc @@ -0,0 +1,121 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/audio_provider.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" + +namespace { +// Stores the timestamp for the previous fetch of audio data, so that we can +// avoid recalculating all the features from scratch if some earlier timeslices +// are still present. +int32_t g_last_time_in_ms = 0; +// Make sure we don't try to use cached information if this is the first call +// into the provider. +bool g_is_first_run = true; +} // namespace + +FeatureProvider::FeatureProvider(int feature_size, uint8_t* feature_data) + : feature_size_(feature_size), feature_data_(feature_data) { + // Initialize the feature data to default values. + for (int n = 0; n < feature_size_; ++n) { + feature_data_[n] = 0; + } +} + +FeatureProvider::~FeatureProvider() {} + +TfLiteStatus FeatureProvider::PopulateFeatureData( + tflite::ErrorReporter* error_reporter, int* how_many_new_slices) { + if (feature_size_ != kFeatureElementCount) { + error_reporter->Report("Requested feature_data_ size %d doesn't match %d", + feature_size_, kFeatureElementCount); + return kTfLiteError; + } + + const int32_t time_in_ms = TimeInMilliseconds(); + // Quantize the time into steps as long as each window stride, so we can + // figure out which audio data we need to fetch. + const int last_step = (g_last_time_in_ms / kFeatureSliceStrideMs); + const int current_step = (time_in_ms / kFeatureSliceStrideMs); + g_last_time_in_ms = time_in_ms; + + int slices_needed = current_step - last_step; + // If this is the first call, make sure we don't use any cached information. + if (g_is_first_run) { + g_is_first_run = false; + slices_needed = kFeatureSliceCount; + } + if (slices_needed > kFeatureSliceCount) { + slices_needed = kFeatureSliceCount; + } + *how_many_new_slices = slices_needed; + + const int slices_to_keep = kFeatureSliceCount - slices_needed; + const int slices_to_drop = kFeatureSliceCount - slices_to_keep; + // If we can avoid recalculating some slices, just move the existing data + // up in the spectrogram, to perform something like this: + // last time = 80ms current time = 120ms + // +-----------+ +-----------+ + // | data@20ms | --> | data@60ms | + // +-----------+ -- +-----------+ + // | data@40ms | -- --> | data@80ms | + // +-----------+ -- -- +-----------+ + // | data@60ms | -- -- | | + // +-----------+ -- +-----------+ + // | data@80ms | -- | | + // +-----------+ +-----------+ + if (slices_to_keep > 0) { + for (int dest_slice = 0; dest_slice < slices_to_keep; ++dest_slice) { + uint8_t* dest_slice_data = + feature_data_ + (dest_slice * kFeatureSliceSize); + const int src_slice = dest_slice + slices_to_drop; + const uint8_t* src_slice_data = + feature_data_ + (src_slice * kFeatureSliceSize); + for (int i = 0; i < kFeatureSliceSize; ++i) { + dest_slice_data[i] = src_slice_data[i]; + } + } + } + // Any slices that need to be filled in with feature data have their + // appropriate audio data pulled, and features calculated for that slice. + if (slices_needed > 0) { + for (int new_slice = slices_to_keep; new_slice < kFeatureSliceCount; + ++new_slice) { + const int new_step = (current_step - kFeatureSliceCount + 1) + new_slice; + const int32_t slice_start_ms = (new_step * kFeatureSliceStrideMs); + int16_t* audio_samples = nullptr; + int audio_samples_size = 0; + GetAudioSamples(error_reporter, slice_start_ms, kFeatureSliceDurationMs, + &audio_samples_size, &audio_samples); + if (audio_samples_size < kMaxAudioSampleSize) { + error_reporter->Report("Audio data size %d too small, want %d", + audio_samples_size, kMaxAudioSampleSize); + return kTfLiteError; + } + uint8_t* new_slice_data = feature_data_ + (new_slice * kFeatureSliceSize); + TfLiteStatus preprocess_status = + Preprocess(error_reporter, audio_samples, audio_samples_size, + kFeatureSliceSize, new_slice_data); + if (preprocess_status != kTfLiteOk) { + return preprocess_status; + } + } + } + return kTfLiteOk; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h new file mode 100644 index 0000000000..a86c56ebf0 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h @@ -0,0 +1,48 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" + +// Binds itself to an area of memory intended to hold the input features for an +// audio-recognition neural network model, and fills that data area with the +// features representing the current audio input, for example from a microphone. +// The audio features themselves are a two-dimensional array, made up of +// horizontal slices representing the frequencies at one point in time, stacked +// on top of each other to form a spectrogram showing how those frequencies +// changed over time. +class FeatureProvider { + public: + // Create the provider, and bind it to an area of memory. This memory should + // remain accessible for the lifetime of the provider object, since subsequent + // calls will fill it with feature data. The provider does no memory + // management of this data. + FeatureProvider(int feature_size, uint8_t* feature_data); + ~FeatureProvider(); + + // Fills the feature data with information from audio inputs, and returns how + // many feature slices were updated. + TfLiteStatus PopulateFeatureData(tflite::ErrorReporter* error_reporter, + int* how_many_new_slices); + + private: + int feature_size_; + uint8_t* feature_data_; +}; + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc new file mode 100644 index 0000000000..1e52aec8d2 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider_test.cc @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(TestFeatureProvider) { + tflite::MicroErrorReporter micro_error_reporter; + tflite::ErrorReporter* error_reporter = µ_error_reporter; + + uint8_t feature_data[kFeatureElementCount]; + FeatureProvider feature_provider(kFeatureElementCount, feature_data); + + int how_many_new_slices = 0; + TfLiteStatus populate_status = feature_provider.PopulateFeatureData( + error_reporter, &how_many_new_slices); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, populate_status); + TF_LITE_MICRO_EXPECT_EQ(kFeatureSliceCount, how_many_new_slices); +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc index de60c982f3..b623d8d11b 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/fixed_point/preprocessor.cc @@ -31,6 +31,8 @@ limitations under the License. #include +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" + namespace { // q format notation: qx.y => 1 sign bit, x-1 integer bits, y fraction bits. @@ -66,13 +68,6 @@ inline int32_t FloatToFixed_Q2_30(float input) { return static_cast(roundf(input * (1 << 30))); } -// These constants allow us to allocate fixed-sized arrays on the stack for our -// working memory. -constexpr int kInputSize = 512; -constexpr int kAverageWindowSize = 6; -constexpr int kOutputSize = - ((kInputSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; - // Performs a discrete Fourier transform on the real inputs. This corresponds to // rdft() in the FFT package at http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html, // and to kiss_fftr() in KISSFFT at https://github.com/mborgerding/kissfft. @@ -127,14 +122,14 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output) { // Ensure our input and output data arrays are valid. - if (input_size > kInputSize) { + if (input_size > kMaxAudioSampleSize) { error_reporter->Report("Input size %d larger than %d", input_size, - kInputSize); + kMaxAudioSampleSize); return kTfLiteError; } - if (output_size != kOutputSize) { + if (output_size != kFeatureSliceSize) { error_reporter->Report("Requested output size %d doesn't match %d", - output_size, kOutputSize); + output_size, kFeatureSliceSize); return kTfLiteError; } @@ -142,18 +137,17 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // In a real application, we'd calculate this table once in an initialization // function and store it for repeated reuse. // q1.15 format. - int16_t window_function[kInputSize]; + int16_t window_function[kMaxAudioSampleSize]; CalculatePeriodicHann(input_size, window_function); // Apply the window function to our time series input, and pad it with zeroes // to the next power of two. - int32_t fixed_input[kInputSize]; - for (int i = 0; i < kInputSize; ++i) { + int32_t fixed_input[kMaxAudioSampleSize]; + for (int i = 0; i < kMaxAudioSampleSize; ++i) { if (i < input_size) { // input is int16_t. Treat as q1.15 fixed point value in range [-1,1) // window_function is also q1.15 fixed point number - fixed_input[i] = - Q1_15_FixedMultiply_Q2_30(input[i], window_function[i]); + fixed_input[i] = Q1_15_FixedMultiply_Q2_30(input[i], window_function[i]); } else { fixed_input[i] = 0; } @@ -161,31 +155,31 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // Pull the frequency data from the time series sample. // Calculated in q10.22 format from q2.30 inputs. - int32_t fourier_values[kInputSize]; - CalculateDiscreteFourierTransform(fixed_input, kInputSize, fourier_values); + int32_t fourier_values[kMaxAudioSampleSize]; + CalculateDiscreteFourierTransform(fixed_input, kMaxAudioSampleSize, + fourier_values); // We have the complex numbers giving us information about each frequency // band, but all we want to know is how strong each frequency is, so calculate // the squared magnitude by adding together the squares of each component. - int32_t power_spectrum[kInputSize / 2]; - for (int i = 0; i < (kInputSize / 2); ++i) { + int32_t power_spectrum[kMaxAudioSampleSize / 2]; + for (int i = 0; i < (kMaxAudioSampleSize / 2); ++i) { const int32_t real = fourier_values[(i * 2) + 0]; const int32_t imaginary = fourier_values[(i * 2) + 1]; // q10.22 results - power_spectrum[i] = - Q10_22_FixedMultiply_Q10_22(real, real) + - Q10_22_FixedMultiply_Q10_22(imaginary, imaginary); + power_spectrum[i] = Q10_22_FixedMultiply_Q10_22(real, real) + + Q10_22_FixedMultiply_Q10_22(imaginary, imaginary); } // Finally, reduce the size of the output by averaging together six adjacent // frequencies into each slot, producing an array of 43 values. // Power_spectrum numbers are q10.22. Divide by kAverageWindowSize inside // loop to prevent overflow. - for (int i = 0; i < kOutputSize; ++i) { + for (int i = 0; i < kFeatureSliceSize; ++i) { int32_t average = 0; for (int j = 0; j < kAverageWindowSize; ++j) { const int index = (i * kAverageWindowSize) + j; - if (index < (kInputSize / 2)) { + if (index < (kMaxAudioSampleSize / 2)) { average += power_spectrum[index] / kAverageWindowSize; } } diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc new file mode 100644 index 0000000000..1890c25cf2 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/main.cc @@ -0,0 +1,112 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/feature_provider.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" +#include "tensorflow/lite/experimental/micro/examples/micro_speech/tiny_conv_model_data.h" +#include "tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/micro_interpreter.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include "tensorflow/lite/version.h" + +int main(int argc, char* argv[]) { + // Set up logging. + tflite::MicroErrorReporter micro_error_reporter; + tflite::ErrorReporter* error_reporter = µ_error_reporter; + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + const tflite::Model* model = ::tflite::GetModel(g_tiny_conv_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + error_reporter->Report( + "Model provided is schema version %d not equal " + "to supported version %d.\n", + model->version(), TFLITE_SCHEMA_VERSION); + return 1; + } + + // This pulls in all the operation implementations we need. + tflite::ops::micro::AllOpsResolver resolver; + + // Create an area of memory to use for input, output, and intermediate arrays. + // The size of this will depend on the model you're using, and may need to be + // determined by experimentation. + const int tensor_arena_size = 10 * 1024; + uint8_t tensor_arena[tensor_arena_size]; + tflite::SimpleTensorAllocator tensor_allocator(tensor_arena, + tensor_arena_size); + + // Build an interpreter to run the model with. + tflite::MicroInterpreter interpreter(model, resolver, &tensor_allocator, + error_reporter); + + // Get information about the memory area to use for the model's input. + TfLiteTensor* model_input = interpreter.input(0); + if ((model_input->dims->size != 4) || (model_input->dims->data[0] != 1) || + (model_input->dims->data[1] != kFeatureSliceCount) || + (model_input->dims->data[2] != kFeatureSliceSize) || + (model_input->type != kTfLiteUInt8)) { + error_reporter->Report("Bad input tensor parameters in model"); + return 1; + } + + // Prepare to access the audio spectrograms from a microphone or other source + // that will provide the inputs to the neural network. + FeatureProvider feature_provider(kFeatureElementCount, + model_input->data.uint8); + + // Keep reading and analysing audio data in an infinite loop. + while (true) { + // Fetch the spectrogram for the current time. + int how_many_new_slices = 0; + TfLiteStatus feature_status = feature_provider.PopulateFeatureData( + error_reporter, &how_many_new_slices); + if (feature_status != kTfLiteOk) { + error_reporter->Report("Feature generation failed"); + return 1; + } + // If no new audio samples have been received since last time, don't bother + // running the network model. + if (how_many_new_slices == 0) { + continue; + } + + // Run the model on the spectrogram input and make sure it succeeds. + TfLiteStatus invoke_status = interpreter.Invoke(); + if (invoke_status != kTfLiteOk) { + error_reporter->Report("Invoke failed"); + return 1; + } + + // The output from the model is a vector containing the scores for each + // kind of prediction, so figure out what the highest scoring category was. + TfLiteTensor* output = interpreter.output(0); + uint8_t top_category_score = 0; + int top_category_index = 0; + for (int category_index = 0; category_index < kCategoryCount; + ++category_index) { + const uint8_t category_score = output->data.uint8[category_index]; + if (category_score > top_category_score) { + top_category_score = category_score; + top_category_index = category_index; + } + } + + error_reporter->Report("Heard %s", kCategoryLabels[top_category_index]); + } + + return 0; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.cc new file mode 100644 index 0000000000..b9b8fb37b1 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.cc @@ -0,0 +1,23 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" + +const char* kCategoryLabels[kCategoryCount] = { + "silence", + "unknown", + "yes", + "no", +}; diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h new file mode 100644 index 0000000000..1d8f3123a5 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h @@ -0,0 +1,42 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ + +// Keeping these as constant expressions allow us to allocate fixed-sized arrays +// on the stack for our working memory. + +// The size of the input time series data we pass to the FFT to produce the +// frequency information. This has to be a power of two, and since we're dealing +// with 30ms of 16KHz inputs, which means 480 samples, this is the next value. +constexpr int kMaxAudioSampleSize = 512; + +// All of these values are derived from the values used during model training, +// if you change your model you'll need to update these constants. +constexpr int kAverageWindowSize = 6; +constexpr int kFeatureSliceSize = + ((kMaxAudioSampleSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; +constexpr int kFeatureSliceCount = 49; +constexpr int kFeatureElementCount = (kFeatureSliceSize * kFeatureSliceCount); +constexpr int kFeatureSliceStrideMs = 20; +constexpr int kFeatureSliceDurationMs = 30; + +constexpr int kCategoryCount = 4; +constexpr int kSilenceIndex = 0; +constexpr int kUnknownIndex = 1; +extern const char* kCategoryLabels[kCategoryCount]; + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_MODEL_SETTINGS_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc index 12f9e22038..f4a7f801cc 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.cc @@ -28,14 +28,9 @@ limitations under the License. #include -namespace { +#include "tensorflow/lite/experimental/micro/examples/micro_speech/model_settings.h" -// These constants allow us to allocate fixed-sized arrays on the stack for our -// working memory. -constexpr int kInputSize = 512; -constexpr int kAverageWindowSize = 6; -constexpr int kOutputSize = - ((kInputSize / 2) + (kAverageWindowSize - 1)) / kAverageWindowSize; +namespace { // Performs a discrete Fourier transform on the real inputs. This corresponds to // rdft() in the FFT package at http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html, @@ -78,27 +73,27 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output) { // Ensure our input and output data arrays are valid. - if (input_size > kInputSize) { + if (input_size > kMaxAudioSampleSize) { error_reporter->Report("Input size %d larger than %d", input_size, - kInputSize); + kMaxAudioSampleSize); return kTfLiteError; } - if (output_size != kOutputSize) { + if (output_size != kFeatureSliceSize) { error_reporter->Report("Requested output size %d doesn't match %d", - output_size, kOutputSize); + output_size, kFeatureSliceSize); return kTfLiteError; } // Pre-calculate the window function we'll be applying to the input data. // In a real application, we'd calculate this table once in an initialization // function and store it for repeated reuse. - float window_function[kInputSize]; + float window_function[kMaxAudioSampleSize]; CalculatePeriodicHann(input_size, window_function); // Apply the window function to our time series input, and pad it with zeroes // to the next power of two. - float float_input[kInputSize]; - for (int i = 0; i < kInputSize; ++i) { + float float_input[kMaxAudioSampleSize]; + for (int i = 0; i < kMaxAudioSampleSize; ++i) { if (i < input_size) { float_input[i] = (input[i] * window_function[i]) / static_cast(1 << 15); @@ -108,14 +103,15 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, } // Pull the frequency data from the time series sample. - float fourier_values[kInputSize]; - CalculateDiscreteFourierTransform(float_input, kInputSize, fourier_values); + float fourier_values[kMaxAudioSampleSize]; + CalculateDiscreteFourierTransform(float_input, kMaxAudioSampleSize, + fourier_values); // We have the complex numbers giving us information about each frequency // band, but all we want to know is how strong each frequency is, so calculate // the squared magnitude by adding together the squares of each component. - float power_spectrum[kInputSize / 2]; - for (int i = 0; i < (kInputSize / 2); ++i) { + float power_spectrum[kMaxAudioSampleSize / 2]; + for (int i = 0; i < (kMaxAudioSampleSize / 2); ++i) { const float real = fourier_values[(i * 2) + 0]; const float imaginary = fourier_values[(i * 2) + 1]; power_spectrum[i] = (real * real) + (imaginary * imaginary); @@ -123,11 +119,11 @@ TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, // Finally, reduce the size of the output by averaging together six adjacent // frequencies into each slot, producing an array of 43 values. - for (int i = 0; i < kOutputSize; ++i) { + for (int i = 0; i < kFeatureSliceSize; ++i) { float total = 0.0f; for (int j = 0; j < kAverageWindowSize; ++j) { const int index = (i * kAverageWindowSize) + j; - if (index < (kInputSize / 2)) { + if (index < (kMaxAudioSampleSize / 2)) { total += power_spectrum[index]; } } diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h index dede2a8642..adff790d6c 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/preprocessor.h @@ -19,6 +19,11 @@ limitations under the License. #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +// Converts audio sample data into a more compact form that's appropriate for +// feeding into a neural network. There are reference implementations that use +// both floating point and fixed point available, but because the calculations +// involved can be time-consuming, it's recommended that you use or write +// specialized versions for your platform. TfLiteStatus Preprocess(tflite::ErrorReporter* error_reporter, const int16_t* input, int input_size, int output_size, uint8_t* output); diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc new file mode 100644 index 0000000000..6c96a61ab5 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.cc @@ -0,0 +1,22 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" + +int32_t TimeInMilliseconds() { + static int current_time = 0; + current_time += 100; + return current_time; +} diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h new file mode 100644 index 0000000000..162952844a --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer.h @@ -0,0 +1,31 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ + +#include + +// Returns the time in milliseconds. There's no contract about what time zero +// represents, the accuracy, or the granularity of the result. Subsequent calls +// will generally not return a lower value, but even that's not guaranteed if +// there's an overflow wraparound. +// The reference implementation of this function just returns a constantly +// incrementing value for each call, since it would need a non-portable platform +// call to access time information. For real applications, you'll need to write +// your own platform-specific implementation. +int32_t TimeInMilliseconds(); + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_EXAMPLES_MICRO_SPEECH_TIMER_H_ diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc new file mode 100644 index 0000000000..83a2dfcc65 --- /dev/null +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc @@ -0,0 +1,46 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/lite/experimental/micro/examples/micro_speech/timer.h" + +#include + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/micro_error_reporter.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(TestTimer) { + // Make sure that the technically-undefined overflow behavior we rely on below + // works on this platform. It's still not guaranteed, but at least this is a + // sanity check. + int32_t overflow_value = std::numeric_limits::max(); + overflow_value += 1; + TF_LITE_MICRO_EXPECT_EQ(std::numeric_limits::min(), overflow_value); + + const int32_t first_time = TimeInMilliseconds(); + const int32_t second_time = TimeInMilliseconds(); + + // It's possible that the timer may have wrapped around from +BIG_NUM to + // -BIG_NUM between the first and second calls, since we're storing + // milliseconds in a 32-bit integer. It's not reasonable that the call itself + // would have taken more than 2^31 milliseconds though, so look at the + // difference and rely on integer overflow to ensure it's accurate. + const int32_t time_delta = (second_time - first_time); + TF_LITE_MICRO_EXPECT_LE(0, time_delta); +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/testing/micro_test.h b/tensorflow/lite/experimental/micro/testing/micro_test.h index 10bab05fae..2f20dd5ac7 100644 --- a/tensorflow/lite/experimental/micro/testing/micro_test.h +++ b/tensorflow/lite/experimental/micro/testing/micro_test.h @@ -153,4 +153,22 @@ extern tflite::ErrorReporter* reporter; } \ } while (false) +#define TF_LITE_MICRO_EXPECT_GE(x, y) \ + do { \ + if ((x) < (y)) { \ + micro_test::reporter->Report(#x " >= " #y " failed at %s:%d", __FILE__, \ + __LINE__); \ + micro_test::did_test_fail = true; \ + } \ + } while (false) + +#define TF_LITE_MICRO_EXPECT_LE(x, y) \ + do { \ + if ((x) > (y)) { \ + micro_test::reporter->Report(#x " <= " #y " failed at %s:%d", __FILE__, \ + __LINE__); \ + micro_test::did_test_fail = true; \ + } \ + } while (false) + #endif // TENSORFLOW_LITE_EXPERIMENTAL_MICRO_TESTING_MICRO_TEST_H_ -- GitLab From bc4638e250b39bd6ebfd3a9bded632ad0139d5e7 Mon Sep 17 00:00:00 2001 From: Sreeni Kesavarapu Date: Mon, 26 Nov 2018 14:32:24 -0800 Subject: [PATCH 336/672] Adds round_mode to QuantizeAndDequantizeV2 op to select rounding algorithm. PiperOrigin-RevId: 222888022 --- tensorflow/compiler/tests/unary_ops_test.py | 66 +++++++++ .../kernels/quantize_and_dequantize_op.cc | 43 +++++- .../api_def_QuantizeAndDequantizeV2.pbtxt | 15 +- tensorflow/core/kernels/cwise_ops.h | 21 +++ .../kernels/quantize_and_dequantize_op.cc | 29 +++- .../core/kernels/quantize_and_dequantize_op.h | 81 +++++++++-- .../quantize_and_dequantize_op_gpu.cu.cc | 4 +- .../quantize_and_dequantize_op_test.cc | 136 +++++++++++++++++- tensorflow/core/ops/array_ops.cc | 3 + .../golden/v1/tensorflow.quantization.pbtxt | 2 +- .../golden/v2/tensorflow.quantization.pbtxt | 2 +- 11 files changed, 374 insertions(+), 28 deletions(-) diff --git a/tensorflow/compiler/tests/unary_ops_test.py b/tensorflow/compiler/tests/unary_ops_test.py index d612d3b32d..95c9e7ffd4 100644 --- a/tensorflow/compiler/tests/unary_ops_test.py +++ b/tensorflow/compiler/tests/unary_ops_test.py @@ -481,6 +481,72 @@ class UnaryOpsTest(xla_test.XLATestCase): np.array([-1, -0.5, 0, 0.3], dtype=dtype), expected=np.array([-1., -0.5, 0., 0.296875], dtype=dtype)) + def quantize_and_dequantize_v2_round_half_up(x): + return array_ops.quantize_and_dequantize_v2( + x, + -1, + 1.0, + signed_input=True, + num_bits=8, + range_given=True, + round_mode="HALF_UP") + + self._assertOpOutputMatchesExpected( + quantize_and_dequantize_v2_round_half_up, + np.array([-0.8, -0.5, 0, 0.3, 0.8, -2, 33], dtype=dtype), + expected=np.array([ + -102.0 / 127, + -63.0 / 127, + 0, + 38.0 / 127, + 102.0 / 127, + -128.0 / 127, + 1, + ], + dtype=dtype)) + + def quantize_and_dequantize_v2_round_half_to_even(x): + return array_ops.quantize_and_dequantize_v2( + x, + -1.0, + 1.0, + signed_input=True, + num_bits=8, + range_given=True, + round_mode="HALF_TO_EVEN") + + self._assertOpOutputMatchesExpected( + quantize_and_dequantize_v2_round_half_to_even, + np.array( + [ + -0.8, + # The -0.5 should become -63.5 after scaling and with + # rounding this should become -64. But with the test + # unary_ops_test_cpu_ondemand, this fails as the result + # before scaling becomes -63.499996 and gets rounded to -63. + # TODO(sreenik): Some one more familiar with this test needs + # to take a look and resolve this. This works on all other + # variations of the platform like cpu, and gpu. + # -0.5, + 0, + 0.3, + 0.8, + -2, + 33 + ], + dtype=dtype), + expected=np.array( + [ + -102.0 / 127, + # -64.0 / 127, + 0, + 38.0 / 127, + 102.0 / 127, + -128.0 / 127, + 1, + ], + dtype=dtype)) + def quantize_and_dequantize_v3(x): return array_ops.quantize_and_dequantize_v3( x, -127, 127, num_bits=8, signed_input=True, range_given=False) diff --git a/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc b/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc index 6f4ed496a1..7fe102428d 100644 --- a/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc @@ -19,6 +19,7 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/lib/arithmetic.h" #include "tensorflow/compiler/xla/client/lib/constants.h" +#include "tensorflow/compiler/xla/client/lib/math.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/client/xla_computation.h" #include "tensorflow/core/platform/macros.h" @@ -26,12 +27,26 @@ limitations under the License. namespace tensorflow { namespace { +enum QuantizerRoundMode { + // Round half up: if the fraction of y is exactly 0.5, then + // round(y) = y + 0.5 + // E.g., -5.5 gets rounded to -5, -5.4 goes to -5, + // 5.4 goes to 5, and 5.5 goes to 6. + ROUND_HALF_UP, + // Round half to even: if the fraction of y is exactly 0.5, then round(y) is + // the nearest even integer to y. + // E.g., 23.5 gets rounded to 24, 24.5 gets rounded to 24, while -23.5 becomes + // -24, and -24.5 gets rounded to 24. + ROUND_HALF_TO_EVEN, +}; + class QuantizeAndDequantizeOp : public XlaOpKernel { public: explicit QuantizeAndDequantizeOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) { OP_REQUIRES_OK(ctx, ctx->GetAttr("signed_input", &signed_input_)); OP_REQUIRES_OK(ctx, ctx->GetAttr("range_given", &range_given_)); + round_mode_ = ROUND_HALF_TO_EVEN; } void Compile(XlaOpKernelContext* ctx) override { @@ -117,8 +132,17 @@ class QuantizeAndDequantizeOp : public XlaOpKernel { // in that case they were measured from the tensor. input = Clamp(min_range, input, max_range); } - xla::XlaOp result = - Floor((input - min_range) * scale + half) * inverse_scale + min_range; + xla::XlaOp result; + switch (round_mode_) { + case ROUND_HALF_TO_EVEN: { + result = xla::RoundToEven(input * scale) * inverse_scale; + break; + } + case ROUND_HALF_UP: { + result = Floor(input * scale + half) * inverse_scale; + break; + } + } ctx->SetOutput(0, result); } @@ -126,6 +150,7 @@ class QuantizeAndDequantizeOp : public XlaOpKernel { int64 num_bits_ = -1; bool signed_input_; bool range_given_; + QuantizerRoundMode round_mode_; }; class QuantizeAndDequantizeV2Op : public QuantizeAndDequantizeOp { @@ -136,6 +161,20 @@ class QuantizeAndDequantizeV2Op : public QuantizeAndDequantizeOp { OP_REQUIRES(ctx, num_bits_ > 0 && num_bits_ < (signed_input_ ? 62 : 63), errors::InvalidArgument("num_bits is out of range: ", num_bits_, " with signed_input_ ", signed_input_)); + string round_mode_string; + OP_REQUIRES_OK(ctx, ctx->GetAttr("round_mode", &round_mode_string)); + OP_REQUIRES( + ctx, + (round_mode_string == "HALF_UP" || round_mode_string == "HALF_TO_EVEN"), + errors::InvalidArgument("Round mode string must be " + "'HALF_UP' or " + "'HALF_TO_EVEN', is '" + + round_mode_string + "'")); + if (round_mode_string == "HALF_UP") { + round_mode_ = ROUND_HALF_UP; + } else if (round_mode_string == "HALF_TO_EVEN") { + round_mode_ = ROUND_HALF_TO_EVEN; + } } }; diff --git a/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV2.pbtxt b/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV2.pbtxt index c43142599b..dff7c8754f 100644 --- a/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV2.pbtxt +++ b/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV2.pbtxt @@ -39,6 +39,19 @@ END name: "range_given" description: <> { enum { Cost = 4 * NumTraits::AddCost, PacketAccess = false }; }; +template +struct scalar_round_up_op { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar + operator()(const Scalar& x) const { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), + NUMERIC_TYPE_MUST_BE_REAL) + + Scalar round_val = Eigen::numext::floor(x); + const Scalar fraction = x - round_val; + if (fraction >= Scalar(.5)) { + round_val += Scalar(1.0); + } + return round_val; + } +}; + +template +struct functor_traits> { + enum { Cost = 4 * NumTraits::AddCost, PacketAccess = false }; +}; + #undef ENABLE_FLOAT_EQUALITY_WARNING #undef DISABLE_FLOAT_EQUALITY_WARNING diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.cc b/tensorflow/core/kernels/quantize_and_dequantize_op.cc index dadc15b69e..f13341e0af 100644 --- a/tensorflow/core/kernels/quantize_and_dequantize_op.cc +++ b/tensorflow/core/kernels/quantize_and_dequantize_op.cc @@ -49,6 +49,21 @@ class QuantizeAndDequantizeV2Op : public OpKernel { errors::InvalidArgument("num_bits is out of range: ", num_bits_, " with signed_input_ ", signed_input_)); OP_REQUIRES_OK(ctx, ctx->GetAttr("range_given", &range_given_)); + + string round_mode_string; + OP_REQUIRES_OK(ctx, ctx->GetAttr("round_mode", &round_mode_string)); + OP_REQUIRES( + ctx, + (round_mode_string == "HALF_UP" || round_mode_string == "HALF_TO_EVEN"), + errors::InvalidArgument("Round mode string must be " + "'HALF_UP' or " + "'HALF_TO_EVEN', is '" + + round_mode_string + "'")); + if (round_mode_string == "HALF_UP") { + round_mode_ = ROUND_HALF_UP; + } else if (round_mode_string == "HALF_TO_EVEN") { + round_mode_ = ROUND_HALF_TO_EVEN; + } } void Compute(OpKernelContext* ctx) override { @@ -76,13 +91,15 @@ class QuantizeAndDequantizeV2Op : public OpKernel { functor::QuantizeAndDequantizeOneScaleFunctor f; f(ctx->eigen_device(), input.flat(), signed_input_, num_bits_, - range_given_, &input_min_tensor, &input_max_tensor, output->flat()); + range_given_, &input_min_tensor, &input_max_tensor, round_mode_, + output->flat()); } private: bool signed_input_; int num_bits_; bool range_given_; + QuantizerRoundMode round_mode_; }; // Simulate quantization precision loss in a float tensor by: @@ -135,7 +152,8 @@ class QuantizeAndDequantizeV3Op : public OpKernel { functor::QuantizeAndDequantizeOneScaleFunctor f; f(ctx->eigen_device(), input.flat(), signed_input_, num_bits_val, - range_given_, &input_min_tensor, &input_max_tensor, output->flat()); + range_given_, &input_min_tensor, &input_max_tensor, ROUND_HALF_TO_EVEN, + output->flat()); } private: @@ -180,7 +198,7 @@ class QuantizeAndDequantizeOp : public OpKernel { functor::QuantizeAndDequantizeOneScaleFunctor functor; functor(ctx->eigen_device(), input.flat(), signed_input_, num_bits_, range_given_, &input_min_tensor, &input_max_tensor, - output->flat()); + ROUND_HALF_TO_EVEN, output->flat()); } private: @@ -198,10 +216,11 @@ struct QuantizeAndDequantizeOneScaleFunctor { void operator()(const CPUDevice& d, typename TTypes::ConstVec input, const bool signed_input, const int num_bits, const bool range_given, Tensor* input_min_tensor, - Tensor* input_max_tensor, typename TTypes::Vec out) { + Tensor* input_max_tensor, QuantizerRoundMode round_mode, + typename TTypes::Vec out) { QuantizeAndDequantizeOneScaleImpl::Compute( d, input, signed_input, num_bits, range_given, input_min_tensor, - input_max_tensor, out); + input_max_tensor, round_mode, out); } }; } // namespace functor diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.h b/tensorflow/core/kernels/quantize_and_dequantize_op.h index 6b0c5e5a46..a495e8b71f 100644 --- a/tensorflow/core/kernels/quantize_and_dequantize_op.h +++ b/tensorflow/core/kernels/quantize_and_dequantize_op.h @@ -22,6 +22,20 @@ limitations under the License. #include "tensorflow/core/kernels/cwise_ops.h" namespace tensorflow { + +enum QuantizerRoundMode { + // Round half up: if the fraction of y is exactly 0.5, then + // round(y) = y + 0.5 + // E.g., -5.5 gets rounded to -5, -5.4 goes to -5, + // 5.4 goes to 5, and 5.5 goes to 6. + ROUND_HALF_UP, + // Round half to even: if the fraction of y is exactly 0.5, then round(y) is + // the nearest even integer to y. + // E.g., 23.5 gets rounded to 24, 24.5 gets rounded to 24, while -23.5 becomes + // -24, and -24.5 gets rounded to 24. + ROUND_HALF_TO_EVEN, +}; + namespace functor { // TODO(pauldonnelly): 'signed_input' should really be called 'signed_output'. @@ -31,15 +45,69 @@ struct QuantizeAndDequantizeOneScaleFunctor { void operator()(const Device& d, typename TTypes::ConstVec input, bool signed_input, int num_bits, bool range_given, Tensor* input_min_tensor, Tensor* input_max_tensor, - typename TTypes::Vec out); + QuantizerRoundMode round_mode, typename TTypes::Vec out); }; +// The implementation below runs on both CPU and GPU. +template +void ClampScaleAndRound(const Device& d, typename TTypes::ConstVec input, + T min_range, T max_range, T scale, T inverse_scale, + Func round_func, typename TTypes::Vec out) { + out.device(d) = (input.cwiseMin(max_range).cwiseMax(min_range) * scale) + .unaryExpr(round_func) * + inverse_scale; +} + +// The implementation below runs on both CPU and GPU. +template +void ClampScaleAndRound(const Device& d, typename TTypes::ConstVec input, + T min_range, T max_range, T scale, T inverse_scale, + QuantizerRoundMode round_mode, + typename TTypes::Vec out) { + switch (round_mode) { + case ROUND_HALF_TO_EVEN: + ClampScaleAndRound(d, input, min_range, max_range, scale, inverse_scale, + Eigen::internal::scalar_round_op_google(), out); + break; + case ROUND_HALF_UP: + ClampScaleAndRound(d, input, min_range, max_range, scale, inverse_scale, + Eigen::internal::scalar_round_up_op(), out); + break; + } +} + +// The implementation below runs on both CPU and GPU. +template +void ScaleAndRound(const Device& d, typename TTypes::ConstVec input, T scale, + T inverse_scale, Func round_func, + typename TTypes::Vec out) { + out.device(d) = (input * scale).unaryExpr(round_func) * inverse_scale; +} + +// The implementation below runs on both CPU and GPU. +template +void ScaleAndRound(const Device& d, typename TTypes::ConstVec input, T scale, + T inverse_scale, QuantizerRoundMode round_mode, + typename TTypes::Vec out) { + switch (round_mode) { + case ROUND_HALF_TO_EVEN: + ScaleAndRound(d, input, scale, inverse_scale, + Eigen::internal::scalar_round_op_google(), out); + break; + case ROUND_HALF_UP: + ScaleAndRound(d, input, scale, inverse_scale, + Eigen::internal::scalar_round_up_op(), out); + break; + } +} + // The implementation below runs on both CPU and GPU. template struct QuantizeAndDequantizeOneScaleImpl { static void Compute(const Device& d, typename TTypes::ConstVec input, bool signed_input, int num_bits, bool range_given, Tensor* input_min_tensor, Tensor* input_max_tensor, + QuantizerRoundMode round_mode, typename TTypes::Vec out) { T min_range; T max_range; @@ -89,15 +157,10 @@ struct QuantizeAndDequantizeOneScaleImpl { // The semantics of the op does not guarantee to clamp to the specified // min_range and max_range - because we may have changed either min_range // or max_range. - out.device(d) = - (input.cwiseMin(max_range).cwiseMax(min_range) * scale) - .unaryExpr(Eigen::internal::scalar_round_op_google()) * - inverse_scale; + ClampScaleAndRound(d, input, min_range, max_range, scale, inverse_scale, + round_mode, out); } else { - out.device(d) = - (input * scale) - .unaryExpr(Eigen::internal::scalar_round_op_google()) * - inverse_scale; + ScaleAndRound(d, input, scale, inverse_scale, round_mode, out); } } }; diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc b/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc index 61c79cf695..5745e418f3 100644 --- a/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc +++ b/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc @@ -32,10 +32,10 @@ struct QuantizeAndDequantizeOneScaleFunctor { void operator()(const GPUDevice& d, typename TTypes::ConstVec input, bool signed_input, int num_bits, bool range_given, Tensor* input_min_tensor, Tensor* input_max_tensor, - typename TTypes::Vec out) { + QuantizerRoundMode round_mode, typename TTypes::Vec out) { QuantizeAndDequantizeOneScaleImpl::Compute( d, input, signed_input, num_bits, range_given, input_min_tensor, - input_max_tensor, out); + input_max_tensor, round_mode, out); } }; } // end namespace functor diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc b/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc index cddabf8a99..b9e015c96b 100644 --- a/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc +++ b/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc @@ -101,17 +101,51 @@ TEST_F(QuantizeAndDequantizeTest, Convert_1D_tensor_with_int8) { .Attr("range_given", false) .Finalize(node_def())); TF_ASSERT_OK(InitOp()); - AddInputFromArray(TensorShape({6}), {-1, -0.5, 0, 0.3, 0.8, 0.555}); + AddInputFromArray(TensorShape({7}), + {-1, -0.5, 0, 0.3, 0.8, 0.555, 0.50390625}); AddInputFromArray(TensorShape({}), {0.0}); // Min AddInputFromArray(TensorShape({}), {0.0}); // Max - // With int8, the tensor is quantized to {-128, -64, 0, 38, 102, 71}. + // With int8, the tensor is quantized to {-128, -64, 0, 38, 102, 71, 64}. // Scale is: 1/127 - // Then it is dequantized to {-1, -0.5, 0, 38.0/128, 102.0/128, 71.0/128} + // Then it is dequantized to {-1, -0.5, 0, 38.0/128, 102.0/128, 71.0/128, 0.5} TF_ASSERT_OK(RunOpKernel()); - Tensor expected(allocator(), DT_FLOAT, TensorShape({6})); - test::FillValues(&expected, - {-1, -0.5, 0, 38.0 / 128, 102.0 / 128, 71.0 / 128}); + Tensor expected(allocator(), DT_FLOAT, TensorShape({7})); + test::FillValues( + &expected, {-1, -0.5, 0, 38.0 / 128, 102.0 / 128, 71.0 / 128, 0.5}); + test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); + + // Ensure that the inputs haven't been changed. + EXPECT_EQ(inputs_[1]->scalar()(), 0.0); + EXPECT_EQ(inputs_[2]->scalar()(), 0.0); +} + +// Convert a 1D tensor with signed 8 bits and round_mode half_up. +TEST_F(QuantizeAndDequantizeTest, Convert_1D_tensor_with_int8_round_half_up) { + TF_ASSERT_OK( + NodeDefBuilder("quantize_and_dequantize_op", "QuantizeAndDequantizeV2") + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Attr("signed_input", true) + .Attr("num_bits", 8) + .Attr("range_given", false) + .Attr("round_mode", "HALF_UP") + .Finalize(node_def())); + TF_ASSERT_OK(InitOp()); + AddInputFromArray(TensorShape({7}), + {-1, -0.5, 0, 0.3, 0.8, 0.555, 0.50390625}); + AddInputFromArray(TensorShape({}), {0.0}); // Min + AddInputFromArray(TensorShape({}), {0.0}); // Max + + // With int8, the tensor is quantized to {-128, -64, 0, 38, 102, 71, 65}. + // Scale is: 1/127 + // Then it is dequantized to {-1, -0.5, 0, 38.0/128, 102.0/128, 71.0/128, + // 65.0 /128} + TF_ASSERT_OK(RunOpKernel()); + Tensor expected(allocator(), DT_FLOAT, TensorShape({7})); + test::FillValues(&expected, {-1, -0.5, 0, 38.0 / 128, 102.0 / 128, + 71.0 / 128, 65.0 / 128}); test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); // Ensure that the inputs haven't been changed. @@ -162,7 +196,7 @@ TEST_F(QuantizeAndDequantizeTest, Convert_1D_tensor_with_int4) { .Attr("range_given", false) .Finalize(node_def())); TF_ASSERT_OK(InitOp()); - AddInputFromArray(TensorShape({6}), {-1, -0.5, 0, 0.3, 0.8, 0.555}); + AddInputFromArray(TensorShape({6}), {-1, -0.5, 0, 0.3125, 0.8, 0.555}); AddInputFromArray(TensorShape({}), {0.0}); // Min AddInputFromArray(TensorShape({}), {0.0}); // Max @@ -178,6 +212,35 @@ TEST_F(QuantizeAndDequantizeTest, Convert_1D_tensor_with_int4) { EXPECT_EQ(inputs_[2]->scalar()(), 0.0); } +// Convert a 1D tensor with signed 4 bits and round_mode hafl_up. +TEST_F(QuantizeAndDequantizeTest, Convert_1D_tensor_with_int4_round_half_up) { + TF_ASSERT_OK( + NodeDefBuilder("quantize_and_dequantize_op", "QuantizeAndDequantizeV2") + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Attr("signed_input", true) + .Attr("num_bits", 4) + .Attr("range_given", false) + .Attr("round_mode", "HALF_UP") + .Finalize(node_def())); + TF_ASSERT_OK(InitOp()); + AddInputFromArray(TensorShape({6}), {-1, -0.5, 0, 0.3125, 0.8, 0.555}); + AddInputFromArray(TensorShape({}), {0.0}); // Min + AddInputFromArray(TensorShape({}), {0.0}); // Max + + // With int4, the tensor is quantized to {-8, -4, 0, 3, 6, 4}. + // Scale is: 1/8 + TF_ASSERT_OK(RunOpKernel()); + Tensor expected(allocator(), DT_FLOAT, TensorShape({6})); + test::FillValues(&expected, {-1, -0.5, 0, 0.375, 0.75, 0.5}); + test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); + + // Ensure that the inputs haven't been changed. + EXPECT_EQ(inputs_[1]->scalar()(), 0.0); + EXPECT_EQ(inputs_[2]->scalar()(), 0.0); +} + // Convert a 1D tensor with signed 4 bits. TEST_F(QuantizeAndDequantizeTest, Convert_1D_tensor_with_int4_V3) { TF_ASSERT_OK( @@ -237,6 +300,38 @@ TEST_F(QuantizeAndDequantizeTest, Convert_2D_tensor_with_int8_range_given) { test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); } +// Convert a 2D tensor with signed 8 bits, given range and round_mode half_up. +TEST_F(QuantizeAndDequantizeTest, + Convert_2D_tensor_with_int8_range_given_round_half_up) { + TF_ASSERT_OK( + NodeDefBuilder("quantize_and_dequantize_op", "QuantizeAndDequantizeV2") + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Attr("signed_input", true) + .Attr("num_bits", 8) + .Attr("range_given", true) + .Attr("round_mode", "HALF_UP") + .Finalize(node_def())); + TF_ASSERT_OK(InitOp()); + // Note that the last two values are saturated. + AddInputFromArray(TensorShape({2, 4}), + {-0.8, -0.5, 0, 0.3, 0.8, 0.555, -2, 33}); + AddInputFromArray(TensorShape({}), {-1.0}); // Min + AddInputFromArray(TensorShape({}), {1.0}); // Max + + // Note that the range is given as [-1, 1]. + // With int8, the tensor is quantized to {-102, -63, 0, 38, 102, 70, -128, + // 127}. + // Scale is: 1/127 + TF_ASSERT_OK(RunOpKernel()); + Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 4})); + test::FillValues( + &expected, {-102.0 / 127, -63.0 / 127, 0, 38.0 / 127, 102.0 / 127, + 70.0 / 127, -128.0 / 127, 1}); + test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); +} + // Convert a 2D tensor with signed 8 bits with given range. TEST_F(QuantizeAndDequantizeTest, Convert_2D_tensor_with_int8_range_given_V3) { TF_ASSERT_OK( @@ -293,6 +388,33 @@ TEST_F(QuantizeAndDequantizeTest, Convert_4D_tensor_with_uint8_range_given) { test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); } +// Convert a 4D tensor with unsigned 8 bits, given range and round_mode half_up. +TEST_F(QuantizeAndDequantizeTest, + Convert_4D_tensor_with_uint8_range_given_round_half_up) { + TF_ASSERT_OK( + NodeDefBuilder("quantize_and_dequantize_op", "QuantizeAndDequantizeV2") + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Attr("signed_input", false) + .Attr("num_bits", 8) + .Attr("range_given", true) + .Attr("round_mode", "HALF_UP") + .Finalize(node_def())); + TF_ASSERT_OK(InitOp()); + AddInputFromArray(TensorShape({2, 2, 1, 1}), {-0.5, 0, 0.3, 0.8}); + AddInputFromArray(TensorShape({}), {0.0}); // Min + AddInputFromArray(TensorShape({}), {1.0}); // Max + + // Note that the range is given as [0, 1]. + // With int8, the tensor is quantized to {0, 0, 77, 204} + // Scale is: 1/255 + TF_ASSERT_OK(RunOpKernel()); + Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 1, 1})); + test::FillValues(&expected, {0, 0, 77.0 / 255, 204.0 / 255}); + test::ExpectTensorNear(expected, *GetOutput(0), 1e-5); +} + // Convert a 4D tensor with unsigned 8 bits with given range. TEST_F(QuantizeAndDequantizeTest, Convert_4D_tensor_with_uint8_range_given_V3) { TF_ASSERT_OK( diff --git a/tensorflow/core/ops/array_ops.cc b/tensorflow/core/ops/array_ops.cc index f55562ec99..e07a35a63d 100644 --- a/tensorflow/core/ops/array_ops.cc +++ b/tensorflow/core/ops/array_ops.cc @@ -2743,6 +2743,9 @@ REGISTER_OP("QuantizeAndDequantizeV2") .Attr("range_given: bool = false") .Output("output: T") .Attr("T: {bfloat16, half, float, double}") + .Attr( + "round_mode: {'HALF_TO_EVEN', 'HALF_UP'} = " + "'HALF_TO_EVEN'") .SetShapeFn([](InferenceContext* c) { ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); diff --git a/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt index 2948b7318e..632c2f8f83 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt @@ -34,7 +34,7 @@ tf_module { } member_method { name: "quantize_and_dequantize" - argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'None\'], " + argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'None\'], " } member_method { name: "quantized_concat" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt index 2948b7318e..632c2f8f83 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt @@ -34,7 +34,7 @@ tf_module { } member_method { name: "quantize_and_dequantize" - argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'None\'], " + argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'None\'], " } member_method { name: "quantized_concat" -- GitLab From c73e01176b69573d2495f833f939f285f0d8c0cc Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Mon, 26 Nov 2018 14:32:28 -0800 Subject: [PATCH 337/672] [tf.data] Avoid calling `Iterator.get_next()` in each iteration of graph mode. PiperOrigin-RevId: 222888047 --- tensorflow/python/data/kernel_tests/test_base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/data/kernel_tests/test_base.py b/tensorflow/python/data/kernel_tests/test_base.py index af8e5e8a27..03fc0da149 100644 --- a/tensorflow/python/data/kernel_tests/test_base.py +++ b/tensorflow/python/data/kernel_tests/test_base.py @@ -45,8 +45,8 @@ class DatasetTestBase(test.TestCase): ```python # In both graph and eager modes dataset = ... - nxt = self.getNext(dataset) - result = self.evaluate(nxt()) + get_next = self.getNext(dataset) + result = self.evaluate(get_next()) ``` Args: @@ -66,7 +66,8 @@ class DatasetTestBase(test.TestCase): self.evaluate(iterator.initializer) else: iterator = dataset.make_one_shot_iterator() - return iterator.get_next + get_next = iterator.get_next() + return lambda: get_next def _compareOutputToExpected(self, result_values, expected_values, assert_items_equal): -- GitLab From db03fe99dfc31f083356310f41b998307e7dfe30 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 14:32:54 -0800 Subject: [PATCH 338/672] Enable a GRPC ClientSession to request compression by setting the RPCOptions fields of the SessionConfig. PiperOrigin-RevId: 222888148 --- tensorflow/core/distributed_runtime/rpc/BUILD | 1 + .../distributed_runtime/rpc/grpc_channel.cc | 44 ++++++++++++++---- .../distributed_runtime/rpc/grpc_channel.h | 8 +++- .../rpc/grpc_channel_test.cc | 45 ++++++++++++++----- .../distributed_runtime/rpc/grpc_session.cc | 10 +++-- .../rpc/grpc_session_test.cc | 27 +++++++++++ tensorflow/core/protobuf/config.proto | 7 +++ 7 files changed, 116 insertions(+), 26 deletions(-) diff --git a/tensorflow/core/distributed_runtime/rpc/BUILD b/tensorflow/core/distributed_runtime/rpc/BUILD index d122016d3e..273709a01f 100644 --- a/tensorflow/core/distributed_runtime/rpc/BUILD +++ b/tensorflow/core/distributed_runtime/rpc/BUILD @@ -105,6 +105,7 @@ cc_library( "//tensorflow/core:framework", "//tensorflow/core:lib", "//tensorflow/core:lib_internal", + "//tensorflow/core:protos_all_cc", ], ) diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_channel.cc b/tensorflow/core/distributed_runtime/rpc/grpc_channel.cc index 456c30ecf4..781b7d65cd 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_channel.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_channel.cc @@ -53,30 +53,58 @@ Status ValidateHostPortPair(const string& host_port) { } return Status::OK(); } -} // namespace -Status NewHostPortGrpcChannel(const string& target, - SharedGrpcChannelPtr* channel_pointer) { - // Minimally ensure that the target is valid - TF_RETURN_IF_ERROR(ValidateHostPortPair(target)); +} // namespace +::grpc::ChannelArguments GetChannelArguments(const RPCOptions* rpc_options) { // TODO(mrry): Implement secure channels. ::grpc::ChannelArguments args; args.SetInt(GRPC_ARG_MAX_MESSAGE_LENGTH, std::numeric_limits::max()); // NOTE(mrry): Some versions of gRPC use a 20-second minimum backoff // on connection failure, which makes our tests time out. args.SetInt("grpc.testing.fixed_reconnect_backoff_ms", 1000); + if (rpc_options != nullptr) { + if (rpc_options->compression_algorithm() == "deflate") { + args.SetCompressionAlgorithm(GRPC_COMPRESS_DEFLATE); + args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL, + rpc_options->compression_level()); + VLOG(5) << "Setting GRPC compression : algo='" + << rpc_options->compression_algorithm() + << "' level=" << rpc_options->compression_level(); + } else if (rpc_options->compression_algorithm() == "gzip") { + args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); + args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL, + rpc_options->compression_level()); + VLOG(5) << "Setting GRPC compression : algo='" + << rpc_options->compression_algorithm() + << "' level=" << rpc_options->compression_level(); + } else if (!rpc_options->compression_algorithm().empty()) { + LOG(ERROR) << "Invalid compression algorithm: " + << rpc_options->compression_algorithm(); + } + } + return args; +} + +Status NewHostPortGrpcChannel(const string& target, + const RPCOptions* rpc_options, + SharedGrpcChannelPtr* channel_pointer) { + // Minimally ensure that the target is valid + TF_RETURN_IF_ERROR(ValidateHostPortPair(target)); + + ::grpc::ChannelArguments args = GetChannelArguments(rpc_options); *channel_pointer = ::grpc::CreateCustomChannel( "dns:///" + target, ::grpc::InsecureChannelCredentials(), args); return Status::OK(); } ChannelCreationFunction ConvertToChannelCreationFunction( - const std::function& - new_channel_func_ptr) { + const std::function& new_channel_func_ptr) { return [new_channel_func_ptr](const string& target) -> SharedGrpcChannelPtr { SharedGrpcChannelPtr channel_ptr; - if (new_channel_func_ptr(target, &channel_ptr).ok()) { + if (new_channel_func_ptr(target, /*rpc_options=*/nullptr, &channel_ptr) + .ok()) { return channel_ptr; } else { return nullptr; diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_channel.h b/tensorflow/core/distributed_runtime/rpc/grpc_channel.h index 6fa99d7b14..57d16218e8 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_channel.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_channel.h @@ -25,6 +25,7 @@ limitations under the License. #include "grpcpp/grpcpp.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_util.h" +#include "tensorflow/core/protobuf/config.pb.h" namespace tensorflow { @@ -86,11 +87,14 @@ GrpcChannelCache* NewGrpcChannelCache(const GrpcChannelSpec& channel_spec, // Below here are internal-only functions. +::grpc::ChannelArguments GetChannelArguments(const RPCOptions* rpc_options); + ChannelCreationFunction ConvertToChannelCreationFunction( - const std::function& - new_channel_func_ptr); + const std::function& new_channel_func_ptr); Status NewHostPortGrpcChannel(const string& target, + const RPCOptions* rpc_options, SharedGrpcChannelPtr* channel_pointer); } // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_channel_test.cc b/tensorflow/core/distributed_runtime/rpc/grpc_channel_test.cc index a814ef85e2..a6fae2286f 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_channel_test.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_channel_test.cc @@ -184,18 +184,39 @@ TEST(GrpcChannelTest, SparseHostPorts) { TEST(GrpcChannelTest, NewHostPortGrpcChannelValidation) { SharedGrpcChannelPtr mock_ptr; - EXPECT_TRUE(NewHostPortGrpcChannel("127.0.0.1:2222", &mock_ptr).ok()); - EXPECT_TRUE(NewHostPortGrpcChannel("example.com:2222", &mock_ptr).ok()); - EXPECT_TRUE(NewHostPortGrpcChannel("fqdn.example.com.:2222", &mock_ptr).ok()); - EXPECT_TRUE(NewHostPortGrpcChannel("[2002:a9c:258e::]:2222", &mock_ptr).ok()); - EXPECT_TRUE(NewHostPortGrpcChannel("[::]:2222", &mock_ptr).ok()); - - EXPECT_FALSE(NewHostPortGrpcChannel("example.com/abc:2222", &mock_ptr).ok()); - EXPECT_FALSE(NewHostPortGrpcChannel("127.0.0.1:2222/", &mock_ptr).ok()); - EXPECT_FALSE(NewHostPortGrpcChannel("example.com/abc:", &mock_ptr).ok()); - EXPECT_FALSE(NewHostPortGrpcChannel("[::]/:2222", &mock_ptr).ok()); - EXPECT_FALSE(NewHostPortGrpcChannel("[::]:2222/", &mock_ptr).ok()); - EXPECT_FALSE(NewHostPortGrpcChannel("[::]:", &mock_ptr).ok()); + EXPECT_TRUE(NewHostPortGrpcChannel("127.0.0.1:2222", /*rpc_options=*/nullptr, + &mock_ptr) + .ok()); + EXPECT_TRUE(NewHostPortGrpcChannel("example.com:2222", + /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_TRUE(NewHostPortGrpcChannel("fqdn.example.com.:2222", + /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_TRUE(NewHostPortGrpcChannel("[2002:a9c:258e::]:2222", + /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_TRUE( + NewHostPortGrpcChannel("[::]:2222", /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + + EXPECT_FALSE(NewHostPortGrpcChannel("example.com/abc:2222", + /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_FALSE(NewHostPortGrpcChannel("127.0.0.1:2222/", + /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_FALSE(NewHostPortGrpcChannel( + "example.com/abc:", /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_FALSE( + NewHostPortGrpcChannel("[::]/:2222", /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_FALSE( + NewHostPortGrpcChannel("[::]:2222/", /*rpc_options=*/nullptr, &mock_ptr) + .ok()); + EXPECT_FALSE( + NewHostPortGrpcChannel("[::]:", /*rpc_options=*/nullptr, &mock_ptr).ok()); } } // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_session.cc b/tensorflow/core/distributed_runtime/rpc/grpc_session.cc index fdce1b10e0..1ad40fe297 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_session.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_session.cc @@ -52,8 +52,9 @@ Status GrpcSession::Create(const SessionOptions& options, } if (!master) { SharedGrpcChannelPtr master_channel; - TF_RETURN_IF_ERROR(NewHostPortGrpcChannel( - options.target.substr(kSchemePrefixLength), &master_channel)); + TF_RETURN_IF_ERROR( + NewHostPortGrpcChannel(options.target.substr(kSchemePrefixLength), + &options.config.rpc_options(), &master_channel)); master.reset(NewGrpcMaster(master_channel)); } session->SetRemoteMaster(std::move(master)); @@ -384,8 +385,9 @@ void GrpcSession::SetRemoteMaster(std::unique_ptr master) { Status GrpcSession::Reset(const SessionOptions& options, const std::vector& containers) { SharedGrpcChannelPtr master_channel; - TF_RETURN_IF_ERROR(NewHostPortGrpcChannel( - options.target.substr(kSchemePrefixLength), &master_channel)); + TF_RETURN_IF_ERROR( + NewHostPortGrpcChannel(options.target.substr(kSchemePrefixLength), + /*rpc_options=*/nullptr, &master_channel)); auto master = NewGrpcMaster(master_channel); ResetRequest req; for (const auto& c : containers) req.add_container(c); diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_session_test.cc b/tensorflow/core/distributed_runtime/rpc/grpc_session_test.cc index fc601991a2..ad0f8e5e2f 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_session_test.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_session_test.cc @@ -1066,4 +1066,31 @@ TEST(SessionTest, RunTimeoutWithRunOptions) { error::INTERNAL == status.code()); } +TEST(SessionTest, TestCompression) { + std::unique_ptr cluster; + TF_CHECK_OK(test::TestCluster::MakeTestCluster(Devices(1, 0), 1, &cluster)); + SessionOptions options = Options(cluster->targets()[0], 100); + RPCOptions* rpc_options = options.config.mutable_rpc_options(); + rpc_options->set_compression_algorithm("deflate"); + rpc_options->set_compression_level(GRPC_COMPRESS_LEVEL_HIGH); + + std::unique_ptr session(NewRemote(options)); + + static const float kTestValue = 409.1934f; + Graph graph(OpRegistry::Global()); + Tensor tensor(DT_FLOAT, TensorShape({1, 1})); + tensor.flat()(0) = kTestValue; + Node* b = test::graph::Constant(&graph, tensor); + GraphDef gdef; + graph.ToGraphDef(&gdef); + RunOptions run_options; + TF_CHECK_OK(session->Create(run_options, gdef)); + + std::vector> inputs; + std::vector outputs; + TF_CHECK_OK(session->Run(inputs, {b->name()}, {}, &outputs)); + ASSERT_EQ(1, outputs.size()); + IsSingleFloatValue(outputs[0], kTestValue); +} + } // namespace tensorflow diff --git a/tensorflow/core/protobuf/config.proto b/tensorflow/core/protobuf/config.proto index 174b588661..b3dc5dccc0 100644 --- a/tensorflow/core/protobuf/config.proto +++ b/tensorflow/core/protobuf/config.proto @@ -291,6 +291,13 @@ message RPCOptions { // transport for client-master communication that avoids the RPC // stack. This option is primarily for used testing the RPC stack. bool use_rpc_for_inprocess_master = 1; + + // The compression algorithm to be used. One of "deflate", "gzip". + string compression_algorithm = 2; + + // If compression_algorithm is set, the compression level to be used. + // From 0 (no compression), up to 3. + int32 compression_level = 3; }; // Session configuration parameters. -- GitLab From 6f2c7bebc8cef4806f8cbed422df256bb7b6bad4 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Mon, 26 Nov 2018 14:37:54 -0800 Subject: [PATCH 339/672] Add KubernetesClusterResolver and TFConfigClusterResolver to base init file PiperOrigin-RevId: 222888923 --- tensorflow/contrib/cluster_resolver/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tensorflow/contrib/cluster_resolver/__init__.py b/tensorflow/contrib/cluster_resolver/__init__.py index fd1263fe81..ab0746ab83 100644 --- a/tensorflow/contrib/cluster_resolver/__init__.py +++ b/tensorflow/contrib/cluster_resolver/__init__.py @@ -24,7 +24,9 @@ from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import SimpleClusterResolver from tensorflow.contrib.cluster_resolver.python.training.cluster_resolver import UnionClusterResolver from tensorflow.contrib.cluster_resolver.python.training.gce_cluster_resolver import GceClusterResolver +from tensorflow.contrib.cluster_resolver.python.training.kubernetes_cluster_resolver import KubernetesClusterResolver from tensorflow.contrib.cluster_resolver.python.training.slurm_cluster_resolver import SlurmClusterResolver +from tensorflow.contrib.cluster_resolver.python.training.tfconfig_cluster_resolver import TFConfigClusterResolver from tensorflow.contrib.cluster_resolver.python.training.tpu_cluster_resolver import TPUClusterResolver # pylint: enable=wildcard-import,unused-import @@ -35,6 +37,8 @@ _allowed_symbols = [ 'SimpleClusterResolver', 'UnionClusterResolver', 'GceClusterResolver', + 'KubernetesClusterResolver', + 'TFConfigClusterResolver', 'TPUClusterResolver', 'SlurmClusterResolver', ] -- GitLab From 47131dbc19605e3754878d738dbfbe4e539c36da Mon Sep 17 00:00:00 2001 From: Taylor Robie Date: Mon, 26 Nov 2018 14:42:08 -0800 Subject: [PATCH 340/672] Add a `name` arg to scalar_mul() PiperOrigin-RevId: 222889631 --- tensorflow/python/ops/math_ops.py | 17 +++++++++++++---- .../tools/api/golden/v1/tensorflow.math.pbtxt | 2 +- tensorflow/tools/api/golden/v1/tensorflow.pbtxt | 2 +- .../tools/api/golden/v2/tensorflow.math.pbtxt | 2 +- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index a4e3613079..d6b2423c1b 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -440,8 +440,8 @@ def erf(x, name=None): return gen_math_ops.erf(x, name=name) -@tf_export("math.scalar_mul", "scalar_mul") -def scalar_mul(scalar, x): +@tf_export(v1=["math.scalar_mul", "scalar_mul"]) +def scalar_mul(scalar, x, name=None): """Multiplies a scalar times a `Tensor` or `IndexedSlices` object. Intended for use in gradient code which might deal with `IndexedSlices` @@ -451,6 +451,7 @@ def scalar_mul(scalar, x): Args: scalar: A 0-D scalar `Tensor`. Must have known shape. x: A `Tensor` or `IndexedSlices` to be scaled. + name: A name for the operation (optional). Returns: `scalar * x` of the same type (`Tensor` or `IndexedSlices`) as `x`. @@ -463,13 +464,21 @@ def scalar_mul(scalar, x): shape = scalar.get_shape() if shape.ndims == 0: if isinstance(x, ops.IndexedSlices): - return ops.IndexedSlices(scalar * x.values, x.indices, x.dense_shape) + return ops.IndexedSlices(gen_math_ops.mul(scalar, x.values, name), + x.indices, x.dense_shape) else: - return scalar * x + return gen_math_ops.mul(scalar, x, name) else: raise ValueError("Only scalar multiply works, got shape %s" % shape) +@tf_export("math.scalar_mul", "scalar_mul", v1=[]) +@_set_doc(scalar_mul.__doc__) +def scalar_mul_v2(scalar, x, name=None): + with ops.name_scope(name, "scalar_mul", [x]) as name: + return scalar_mul(scalar, x, name) + + @tf_export("math.pow", "pow") def pow(x, y, name=None): # pylint: disable=redefined-builtin r"""Computes the power of one value to another. diff --git a/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt index b7a99caeb7..f34e2c2aa5 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.math.pbtxt @@ -342,7 +342,7 @@ tf_module { } member_method { name: "scalar_mul" - argspec: "args=[\'scalar\', \'x\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'scalar\', \'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "segment_max" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt index 290cd2d9c5..656a52945c 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt @@ -1826,7 +1826,7 @@ tf_module { } member_method { name: "scalar_mul" - argspec: "args=[\'scalar\', \'x\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'scalar\', \'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "scan" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt index f5bbb77d32..979d77ea6b 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.math.pbtxt @@ -342,7 +342,7 @@ tf_module { } member_method { name: "scalar_mul" - argspec: "args=[\'scalar\', \'x\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'scalar\', \'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "segment_max" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index a1e2e7be6f..a380b0d99f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -946,7 +946,7 @@ tf_module { } member_method { name: "scalar_mul" - argspec: "args=[\'scalar\', \'x\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'scalar\', \'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "scan" -- GitLab From eca1437dece6ed0379193d11dd3f3a94dc16681e Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Mon, 26 Nov 2018 14:47:18 -0800 Subject: [PATCH 341/672] Add extendable logging system. PiperOrigin-RevId: 222890503 --- tensorflow/core/BUILD | 17 +++++++ .../core/platform/default/build_config.bzl | 3 ++ tensorflow/core/platform/default/logger.cc | 34 +++++++++++++ tensorflow/core/platform/logger.h | 51 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 tensorflow/core/platform/default/logger.cc create mode 100644 tensorflow/core/platform/logger.h diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 5e1d93cfa2..781ada7b46 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -112,6 +112,7 @@ load( "tf_additional_device_tracer_test_flags", "tf_additional_gdr_lib_defines", "tf_additional_human_readable_json_deps", + "tf_additional_logger_deps", "tf_additional_lib_defines", "tf_additional_lib_deps", "tf_additional_lib_hdrs", @@ -443,6 +444,18 @@ cc_library( ] + tf_additional_human_readable_json_deps(), ) +cc_library( + name = "logger", + srcs = tf_platform_srcs(["logger.cc"]), + hdrs = ["platform/logger.h"] + tf_platform_hdrs(["logger.h"]), + copts = tf_copts(), + visibility = ["//visibility:public"], + deps = [ + ":lib", + ":lib_internal", + ] + tf_additional_logger_deps(), +) + filegroup( name = "platform_env_hdrs", srcs = [ @@ -1594,6 +1607,8 @@ filegroup( "util/stats_calculator.*", "util/reporter.*", "platform/**/cuda_libdevice_path.*", + "platform/**/logger.cc", + "platform/**/logger.h", "platform/default/test_benchmark.*", "platform/cuda.h", "platform/google/**/*", @@ -2206,6 +2221,7 @@ cc_library( "platform/**/env_time.cc", "platform/**/cuda_libdevice_path.cc", "platform/**/device_tracer.cc", + "platform/**/logger.cc", "platform/**/logging.cc", "platform/**/human_readable_json.cc", "platform/abi.cc", @@ -2218,6 +2234,7 @@ cc_library( "platform/**/stream_executor.h", "platform/**/env_time.cc", "platform/**/device_tracer.cc", + "platform/**/logger.cc", "platform/**/logging.cc", "platform/**/human_readable_json.cc", "platform/abi.cc", diff --git a/tensorflow/core/platform/default/build_config.bzl b/tensorflow/core/platform/default/build_config.bzl index 3a4415f229..0428715130 100644 --- a/tensorflow/core/platform/default/build_config.bzl +++ b/tensorflow/core/platform/default/build_config.bzl @@ -543,6 +543,9 @@ def tf_additional_proto_srcs(): def tf_additional_human_readable_json_deps(): return [] +def tf_additional_logger_deps(): + return [] + def tf_additional_all_protos(): return ["//tensorflow/core:protos_all"] diff --git a/tensorflow/core/platform/default/logger.cc b/tensorflow/core/platform/default/logger.cc new file mode 100644 index 0000000000..54b1a1a67c --- /dev/null +++ b/tensorflow/core/platform/default/logger.cc @@ -0,0 +1,34 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/core/platform/logger.h" + +#include "tensorflow/core/platform/logging.h" + +namespace tensorflow { + +Logger* Logger::Singleton() { + class DefaultLogger : public Logger { + private: + void DoLogProto(google::protobuf::Any* proto) override { + VLOG(2) << proto->ShortDebugString(); + } + void DoFlush() override {} + }; + static Logger* instance = new DefaultLogger(); + return instance; +} + +} // namespace tensorflow diff --git a/tensorflow/core/platform/logger.h b/tensorflow/core/platform/logger.h new file mode 100644 index 0000000000..5d304bea63 --- /dev/null +++ b/tensorflow/core/platform/logger.h @@ -0,0 +1,51 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#ifndef TENSORFLOW_CORE_PLATFORM_LOGGER_H_ +#define TENSORFLOW_CORE_PLATFORM_LOGGER_H_ + +#include "google/protobuf/any.pb.h" +#include "tensorflow/core/platform/protobuf.h" + +namespace tensorflow { + +// Abstract logging interface. Contrary to logging.h, this class describes an +// interface, not a concrete logging mechanism. This is useful when we want to +// log anything to a non-local place, e.g. a database. +class Logger { + public: + static Logger* Singleton(); + + virtual ~Logger() = default; + + // Logs a typed proto. + template + void LogProto(const ProtoType& proto) { + google::protobuf::Any any; + any.PackFrom(proto); + DoLogProto(&any); + } + + // Flushes any pending log. Blocks until everything is flushed. + void Flush() { DoFlush(); } + + private: + virtual void DoLogProto(google::protobuf::Any* proto) = 0; + virtual void DoFlush() = 0; +}; + +} // namespace tensorflow + +#endif // TENSORFLOW_CORE_PLATFORM_LOGGER_H_ -- GitLab From f00608d7bc88aaa1cd6f1ce46fa28271860b3723 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 14:52:12 -0800 Subject: [PATCH 342/672] Go: Update generated wrapper functions for TensorFlow ops. PiperOrigin-RevId: 222891342 --- tensorflow/go/op/wrappers.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tensorflow/go/op/wrappers.go b/tensorflow/go/op/wrappers.go index ad31c335e6..02a1335149 100644 --- a/tensorflow/go/op/wrappers.go +++ b/tensorflow/go/op/wrappers.go @@ -463,6 +463,14 @@ func QuantizeAndDequantizeV2RangeGiven(value bool) QuantizeAndDequantizeV2Attr { } } +// QuantizeAndDequantizeV2RoundMode sets the optional round_mode attribute to value. +// If not specified, defaults to "HALF_TO_EVEN" +func QuantizeAndDequantizeV2RoundMode(value string) QuantizeAndDequantizeV2Attr { + return func(m optionalAttr) { + m["round_mode"] = value + } +} + // Quantizes then dequantizes a tensor. // // This op simulates the precision loss from the quantized forward pass by: -- GitLab From ac5311fcf66d0156b71ff17c0777b67dc0251448 Mon Sep 17 00:00:00 2001 From: Andy Ly Date: Mon, 26 Nov 2018 14:53:52 -0800 Subject: [PATCH 343/672] Switch to using Eigen::NumTraits instead of std::numeric_limits when checking bounds. PiperOrigin-RevId: 222891638 --- tensorflow/core/grappler/BUILD | 1 + .../optimizers/arithmetic_optimizer_test.cc | 27 +++++++++++++++++++ tensorflow/core/grappler/utils.cc | 4 +-- tensorflow/core/grappler/utils_test.cc | 23 ++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/grappler/BUILD b/tensorflow/core/grappler/BUILD index 7b03ec38bf..7982b35853 100644 --- a/tensorflow/core/grappler/BUILD +++ b/tensorflow/core/grappler/BUILD @@ -41,6 +41,7 @@ tf_cc_test( "//tensorflow/core:all_kernels", "//tensorflow/core:lib", "//tensorflow/core:protos_all_cc", + "//tensorflow/core:tensor_testutil", "//tensorflow/core:test", "//tensorflow/core:test_main", ], diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc index b6286c425e..35d22898f6 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer_test.cc @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/grappler/optimizers/arithmetic_optimizer.h" +#include "tensorflow/cc/ops/math_ops.h" #include "tensorflow/cc/ops/standard_ops.h" #include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/tensor_testutil.h" @@ -3793,5 +3794,31 @@ TEST_F(ArithmeticOptimizerTest, RemoveStackStridedSliceSameAxis) { tensors[fCSlice2ToOut]); } +TEST_F(ArithmeticOptimizerTest, SimplifyAggregationBFloat16) { + tensorflow::Scope s = tensorflow::Scope::NewRootScope(); + Output x = ops::Const(s.WithOpName("x"), {1.0f, 2.0f}, {1, 2}); + Output cast = ops::Cast(s.WithOpName("cast"), x, DT_BFLOAT16); + Output add = ops::AddN(s.WithOpName("add"), {cast, cast}); + Output id = ops::Identity(s.WithOpName("id"), add); + + GrapplerItem item; + TF_CHECK_OK(s.ToGraphDef(&item.graph)); + item.fetch = {"id"}; + auto tensors_expected = EvaluateNodes(item.graph, item.fetch); + EXPECT_EQ(1, tensors_expected.size()); + + GraphDef output; + ArithmeticOptimizer optimizer; + EnableOnlySimplifyAggregation(&optimizer); + OptimizeAndPrune(&optimizer, &item, &output); + + // Extra node created for multiplier. + EXPECT_EQ(5, output.node_size()); + + auto tensors = EvaluateNodes(output, item.fetch); + EXPECT_EQ(1, tensors.size()); + test::ExpectTensorEqual(tensors_expected[0], tensors[0]); +} + } // namespace grappler } // namespace tensorflow diff --git a/tensorflow/core/grappler/utils.cc b/tensorflow/core/grappler/utils.cc index 9336c4df8b..2977544262 100644 --- a/tensorflow/core/grappler/utils.cc +++ b/tensorflow/core/grappler/utils.cc @@ -40,8 +40,8 @@ namespace { template bool SafeSetScalarTensorValue(double value, Tensor* tensor) { using RealType = typename Eigen::NumTraits::Real; - if (value > static_cast(std::numeric_limits::max()) || - value < static_cast(std::numeric_limits::min())) { + if (value > static_cast(Eigen::NumTraits::highest()) || + value < static_cast(Eigen::NumTraits::lowest())) { return false; } tensor->flat()(0) = static_cast(value); diff --git a/tensorflow/core/grappler/utils_test.cc b/tensorflow/core/grappler/utils_test.cc index 8cbff1c397..e993391b51 100644 --- a/tensorflow/core/grappler/utils_test.cc +++ b/tensorflow/core/grappler/utils_test.cc @@ -16,10 +16,13 @@ limitations under the License. #include "tensorflow/core/grappler/utils.h" #include +#include #include #include "tensorflow/cc/ops/standard_ops.h" #include "tensorflow/core/framework/node_def.pb.h" +#include "tensorflow/core/framework/tensor_testutil.h" #include "tensorflow/core/grappler/grappler_item.h" +#include "tensorflow/core/lib/bfloat16/bfloat16.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/status_test_util.h" #include "tensorflow/core/lib/core/threadpool.h" @@ -441,6 +444,26 @@ BM_ParseNodeNameAsStringPiece("foo:123", foo123); BM_ParseNodeNameAsStringPiece("foo/bar/baz:123", foo_bar_baz_123); BM_ParseNodeNameAsStringPiece("^foo/bar/baz:123", foo_bar_baz_123_ctrl); +TEST_F(UtilsTest, SetTensorValueBFloat16) { + Tensor t(DT_BFLOAT16, TensorShape({})); + TF_ASSERT_OK(SetTensorValue(t.dtype(), 2, &t)); + test::ExpectTensorEqual(Tensor(bfloat16(2)), t); +} + +TEST_F(UtilsTest, SetTensorValueBFloat16IntMax) { + Tensor t(DT_BFLOAT16, TensorShape({})); + TF_ASSERT_OK(SetTensorValue(t.dtype(), std::numeric_limits::max(), &t)); + test::ExpectTensorEqual( + Tensor(bfloat16(std::numeric_limits::max())), t); +} + +TEST_F(UtilsTest, SetTensorValueBFloat16IntMin) { + Tensor t(DT_BFLOAT16, TensorShape({})); + TF_ASSERT_OK(SetTensorValue(t.dtype(), std::numeric_limits::min(), &t)); + test::ExpectTensorEqual( + Tensor(bfloat16(std::numeric_limits::min())), t); +} + } // namespace } // namespace grappler } // namespace tensorflow -- GitLab From 11f77c8e22dc1040867356fd3475bc9264ae9e88 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Mon, 26 Nov 2018 14:54:26 -0800 Subject: [PATCH 344/672] Add TFLite specific template for select/missing ops. PiperOrigin-RevId: 222891735 --- .../ISSUE_TEMPLATE/40-tflite-op-request.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/40-tflite-op-request.md diff --git a/.github/ISSUE_TEMPLATE/40-tflite-op-request.md b/.github/ISSUE_TEMPLATE/40-tflite-op-request.md new file mode 100644 index 0000000000..7b391279e4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/40-tflite-op-request.md @@ -0,0 +1,24 @@ +--- +name: TensorFlow Lite Op Request +about: Use this template for reporting ops you are using or missing. + +--- + + +**System information** +- OS Platform and Distribution (e.g., Linux Ubuntu 16.04): +- TensorFlow installed from (source or binary): +- TensorFlow version (or github SHA if from source): + + +**Provide the text output from tflite_convert** + +``` +# Copy and paste here +``` + +Also, please include a link to a GraphDef or the model if possible. + +**Any other info / logs** + +Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. -- GitLab From c81c9a4cf223149c5bda4f6bd9c8424272c6c83e Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Mon, 26 Nov 2018 15:05:10 -0800 Subject: [PATCH 345/672] [XLA] Don't create invalid output fusions We were incorrectly allowing Ax+B fusions where B was also the `Ax` dot operation. PiperOrigin-RevId: 222893743 --- .../xla/service/cpu/cpu_instruction_fusion.cc | 7 +++++- .../cpu/cpu_instruction_fusion_test.cc | 22 ++++++++++++++++++ .../xla/service/gpu/instruction_fusion.cc | 3 ++- .../service/gpu/instruction_fusion_test.cc | 23 +++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion.cc b/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion.cc index f9cd61bea3..6f79ad7c14 100644 --- a/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion.cc +++ b/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion.cc @@ -48,10 +48,15 @@ bool IsMatrixVectorDot(const HloInstruction* hlo) { (hlo_shape.dimensions(0) == 1 || hlo_shape.dimensions(1) == 1); } +bool HasExactlyOneUse(const HloInstruction& hlo_instr) { + return hlo_instr.user_count() == 1 && + absl::c_count(hlo_instr.users().front()->operands(), &hlo_instr) == 1; +} + bool CanBeOutputFused(const HloInstruction* producer, const HloInstruction* consumer) { return consumer->opcode() == HloOpcode::kAdd && IsMatrixVectorDot(producer) && - producer->user_count() == 1; + HasExactlyOneUse(*producer) == 1; } bool CanBeOutputFusedIntoSomeOperand(const HloInstruction* consumer) { diff --git a/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion_test.cc b/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion_test.cc index c77d5988ba..527df0bd1c 100644 --- a/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion_test.cc +++ b/tensorflow/compiler/xla/service/cpu/cpu_instruction_fusion_test.cc @@ -763,6 +763,28 @@ TEST_F(OpcodeFusionTest, DotAddOutputFusion_19x50x1_multi_use) { Not(op::Fusion())); } +TEST_F(InstructionFusionTest, + DotOperationFusion_DontOutputFuseDuplicateOperands) { + absl::string_view module_string = R"( +HloModule module + +ENTRY main { + a = f32[50,60]{1,0} parameter(0) + b = f32[60,1]{1,0} parameter(1) + c = f32[50,1]{1,0} dot(a, b), lhs_contracting_dims={1}, rhs_contracting_dims={0} + ROOT d = f32[50,1]{1,0} add(c, c) +} +)"; + + TF_ASSERT_OK_AND_ASSIGN(std::unique_ptr module, + ParseAndReturnVerifiedModule(module_string)); + TF_ASSERT_OK_AND_ASSIGN(bool fused_something, + CpuInstructionFusion().Run(module.get())); + EXPECT_FALSE(fused_something); + EXPECT_THAT(module->entry_computation()->root_instruction(), + Not(op::Fusion())); +} + struct GatherLoopFusionTestSpec { string test_name; string hlo_computation_text; diff --git a/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc b/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc index 985c0d411e..6151dd8ff4 100644 --- a/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc +++ b/tensorflow/compiler/xla/service/gpu/instruction_fusion.cc @@ -181,7 +181,8 @@ bool GpuInstructionFusion::ShouldFuse(HloInstruction* consumer, return true; } } else if (consumer->operand_count() == 2 && - consumer->opcode() == HloOpcode::kAdd) { + consumer->opcode() == HloOpcode::kAdd && + consumer->operand(other_operand_index) != producer) { // Fuse a bias add into the output of the dot. return true; } diff --git a/tensorflow/compiler/xla/service/gpu/instruction_fusion_test.cc b/tensorflow/compiler/xla/service/gpu/instruction_fusion_test.cc index 2b060b03ce..688604cd36 100644 --- a/tensorflow/compiler/xla/service/gpu/instruction_fusion_test.cc +++ b/tensorflow/compiler/xla/service/gpu/instruction_fusion_test.cc @@ -358,6 +358,29 @@ TEST_F(InstructionFusionTest, DotOutputFusionBiasAdd) { op::Parameter())); } +TEST_F(InstructionFusionTest, + DotOperationFusion_DontOutputFuseDuplicateOperands) { + absl::string_view module_string = R"( +HloModule module + +ENTRY main { + a = f32[50,60]{1,0} parameter(0) + b = f32[60,1]{1,0} parameter(1) + c = f32[50,1]{1,0} dot(a, b), lhs_contracting_dims={1}, rhs_contracting_dims={0} + ROOT d = f32[50,1]{1,0} add(c, c) +} +)"; + + TF_ASSERT_OK_AND_ASSIGN(std::unique_ptr module, + ParseAndReturnVerifiedModule(module_string)); + TF_ASSERT_OK_AND_ASSIGN( + bool fused_something, + GpuInstructionFusion(/*may_duplicate=*/false).Run(module.get())); + EXPECT_FALSE(fused_something); + EXPECT_THAT(module->entry_computation()->root_instruction(), + Not(op::Fusion())); +} + // Compute sum(1/p0), where p0 has type f32, twice. Check that the division is // duplicated and fused into both reduces. TEST_F(InstructionFusionTest, FloatingPointDivIsCheap) { -- GitLab From 6a9b639385e48672345345adfc3a79f7ff49068e Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Mon, 26 Nov 2018 15:08:11 -0800 Subject: [PATCH 346/672] Remove train.LooperThread from TF 2.0 API. PiperOrigin-RevId: 222894257 --- tensorflow/python/training/coordinator.py | 2 +- .../v2/tensorflow.train.-looper-thread.pbtxt | 73 ------------------- .../api/golden/v2/tensorflow.train.pbtxt | 4 - tensorflow/tools/compatibility/renames_v2.py | 1 + 4 files changed, 2 insertions(+), 78 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-looper-thread.pbtxt diff --git a/tensorflow/python/training/coordinator.py b/tensorflow/python/training/coordinator.py index 0ff97d85e3..b7e5c98c78 100644 --- a/tensorflow/python/training/coordinator.py +++ b/tensorflow/python/training/coordinator.py @@ -408,7 +408,7 @@ class Coordinator(object): # Threads for the standard services. -@tf_export("train.LooperThread") +@tf_export(v1=["train.LooperThread"]) class LooperThread(threading.Thread): """A thread that runs code repeatedly, optionally on a timer. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-looper-thread.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-looper-thread.pbtxt deleted file mode 100644 index c61859004e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-looper-thread.pbtxt +++ /dev/null @@ -1,73 +0,0 @@ -path: "tensorflow.train.LooperThread" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "daemon" - mtype: "" - } - member { - name: "ident" - mtype: "" - } - member { - name: "name" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'coord\', \'timer_interval_secs\', \'target\', \'args\', \'kwargs\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " - } - member_method { - name: "getName" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "isAlive" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "isDaemon" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "is_alive" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "join" - argspec: "args=[\'self\', \'timeout\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "loop" - argspec: "args=[\'coord\', \'timer_interval_secs\', \'target\', \'args\', \'kwargs\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "run" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "run_loop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "setDaemon" - argspec: "args=[\'self\', \'daemonic\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "setName" - argspec: "args=[\'self\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "start" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "start_loop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "stop_loop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt index 9c221ddea3..91e1e0582e 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt @@ -112,10 +112,6 @@ tf_module { name: "LoggingTensorHook" mtype: "" } - member { - name: "LooperThread" - mtype: "" - } member { name: "MomentumOptimizer" mtype: "" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index b02326278e..e01360a060 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -549,6 +549,7 @@ renames = { 'tf.to_int32': 'tf.compat.v1.to_int32', 'tf.to_int64': 'tf.compat.v1.to_int64', 'tf.trace': 'tf.linalg.trace', + 'tf.train.LooperThread': 'tf.compat.v1.train.LooperThread', 'tf.train.MonitoredTrainingSession': 'tf.compat.v1.train.MonitoredTrainingSession', 'tf.train.NewCheckpointReader': 'tf.compat.v1.train.NewCheckpointReader', 'tf.train.ProfilerHook': 'tf.compat.v1.train.ProfilerHook', -- GitLab From f01c4b51d715a5fa903ac2876423b74d085f51f4 Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Mon, 26 Nov 2018 15:35:38 -0800 Subject: [PATCH 347/672] Infer signatures for functional tf.keras.Models in tf.saved_model.save Allows exporting functional Models without any @tf.function decoration. PiperOrigin-RevId: 222898916 --- tensorflow/python/saved_model/save.py | 68 +++++++++++++++++----- tensorflow/python/saved_model/save_test.py | 57 ++++++++++++++++++ 2 files changed, 111 insertions(+), 14 deletions(-) diff --git a/tensorflow/python/saved_model/save.py b/tensorflow/python/saved_model/save.py index 02c8dc7c13..d52251e49f 100644 --- a/tensorflow/python/saved_model/save.py +++ b/tensorflow/python/saved_model/save.py @@ -27,6 +27,7 @@ from tensorflow.python.eager import def_function from tensorflow.python.eager import function from tensorflow.python.framework import meta_graph from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_spec from tensorflow.python.lib.io import file_io from tensorflow.python.ops import array_ops from tensorflow.python.ops import resource_variable_ops @@ -42,17 +43,50 @@ from tensorflow.python.util import nest from tensorflow.python.util.tf_export import tf_export +def _check_for_functional_keras_model(root): + """Makes an export signature for `root` if it's a functional Keras Model.""" + # If nothing is decorated yet but this is a functional Keras Model (duck + # typed), we'll try to make a signature ourselves. + try: + inputs = root.inputs + input_names = root.input_names + except AttributeError: + return None + input_signature = [] + for input_tensor, input_name in zip(inputs, input_names): + input_signature.append(tensor_spec.TensorSpec( + shape=input_tensor.shape, dtype=input_tensor.dtype, + name=input_name)) + + @def_function.function(input_signature=input_signature) + def _wrapped_model(*args): + outputs_list = nest.flatten(root(inputs=list(args))) + return {name: output for name, output + in zip(root.output_names, outputs_list)} + return _wrapped_model + + def _find_function_to_export(root): """Iterate over `root`'s attributes, finding traced functions.""" - functions = [] - function_attribute_names = [] + exported_function = None + previous_attribute_name = None for attribute_name in dir(root): attribute_value = getattr(root, attribute_name, None) if isinstance(attribute_value, def_function.PolymorphicFunction): - functions.append(attribute_value) - function_attribute_names.append(attribute_name) - # TODO(allenl): Automatically infer signatures for Keras functional models? - if not functions: + if exported_function is not None: + raise ValueError( + ("Exporting an object with no " + "tf.saved_model.save(..., signatures=...) " + "argument specified, and with more than one " + "@tf.function-decorated method attached to it: {}. The signature " + "keys for these functions are ambiguous. Specify signature " + "functions explicitly.").format( + [previous_attribute_name, attribute_name])) + exported_function = attribute_value + previous_attribute_name = attribute_name + if exported_function is None: + exported_function = _check_for_functional_keras_model(root) + if exported_function is None: raise ValueError( ("Exporting an object with no tf.saved_model.save(..., signatures=...) " "argument specified, and with no @tf.function-decorated methods " @@ -61,14 +95,7 @@ def _find_function_to_export(root): "signatures does not make sense, as the only consumers will expect " "signatures. Either decorate a method or specify a signature function " "explicitly.")) - elif len(functions) > 1: - raise ValueError( - ("Exporting an object with no tf.saved_model.save(..., signatures=...) " - "argument specified, and with more than one @tf.function-decorated " - "method attached to it: {}. The signature keys for these functions " - "are ambiguous. Specify signature functions explicitly.").format( - function_attribute_names)) - return functions[0] + return exported_function def _canonicalize_signatures(signatures): @@ -451,6 +478,19 @@ def save(obj, export_dir, signatures=None): tf.TensorSpec(shape=[None, 3], dtype=tf.float32, name="inp"))) ``` + `tf.keras.Model` instances constructed from inputs and outputs already have a + signature and so do not require a `@tf.function` decorator or a `signatures` + argument. If neither are specified, the model's forward pass is exported. + + ```python + x = input_layer.Input((4,), name="x") + y = core.Dense(5, name="out")(x) + model = training.Model(x, y) + tf.saved_model.save(model, '/tmp/saved_model/') + # The exported SavedModel takes "x" with shape [None, 4] and returns "out" + # with shape [None, 5] + ``` + Variables must be tracked by assigning them to an attribute of a tracked object or to an attribute of `obj` directly. TensorFlow objects (e.g. layers from `tf.keras.layers`, optimizers from `tf.train`) track their variables diff --git a/tensorflow/python/saved_model/save_test.py b/tensorflow/python/saved_model/save_test.py index 04cd9d0683..8fb28039a4 100644 --- a/tensorflow/python/saved_model/save_test.py +++ b/tensorflow/python/saved_model/save_test.py @@ -21,6 +21,8 @@ from __future__ import print_function import os import sys +import numpy + from tensorflow.python.eager import backprop from tensorflow.python.eager import def_function from tensorflow.python.eager import test @@ -29,8 +31,11 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_spec from tensorflow.python.framework import test_util +from tensorflow.python.keras.engine import input_layer from tensorflow.python.keras.engine import training from tensorflow.python.keras.layers import core +from tensorflow.python.keras.layers import merge +from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables from tensorflow.python.saved_model import loader @@ -214,6 +219,19 @@ class SaveTest(test.TestCase): with self.assertRaisesRegexp(ValueError, "call.*second_function"): save.save(model, save_dir) + def test_subclassed_no_signature(self): + + class Subclassed(training.Model): + + def call(self, inputs): + return inputs * 2. + + save_dir = os.path.join(self.get_temp_dir(), "saved_model") + model = Subclassed() + with self.assertRaisesRegexp( + ValueError, "no @tf.function-decorated methods"): + save.save(model, save_dir) + def test_docstring(self): class Adder(util.Checkpoint): @@ -254,6 +272,45 @@ class SaveTest(test.TestCase): self.assertNotIn("T", complex_node.attr) self.assertNotIn("Tout", complex_node.attr) + def test_export_functional_keras_model(self): + x = input_layer.Input((4,), name="x") + y = core.Dense(4, name="out")(x) + model = training.Model(x, y) + save_dir = os.path.join(self.get_temp_dir(), "saved_model") + save.save(model, save_dir) + self.assertAllClose( + {"out": model(array_ops.ones([1, 4]))}, + self._import_and_infer(save_dir, {"x": [[1., 1., 1., 1.]]})) + + def test_export_functional_keras_model_after_fit(self): + x = input_layer.Input((1,)) + y = core.Dense(1, name="y")(x) + model = training.Model(x, y) + model.compile(optimizer="sgd", loss="mse") + model.fit(x=numpy.array([[1.]]), + y=numpy.array([2.]), epochs=2) + save_dir = os.path.join(self.get_temp_dir(), "saved_model") + save.save(model, save_dir) + self.assertAllClose( + {"y": model(constant_op.constant([[1.], [2.]]))}, + self._import_and_infer(save_dir, {"input_1": [[1.], [2.]]})) + + def test_export_multi_input_functional_keras_model(self): + x1 = input_layer.Input((2,), name="x1") + x2 = input_layer.Input((2,), name="x2") + y1 = core.Dense(4)(merge.Add()([x1, x2])) + y2 = core.Dense(4)(merge.Multiply()([x1, x2])) + model = training.Model([x1, x2], [y1, y2]) + save_dir = os.path.join(self.get_temp_dir(), "saved_model") + save.save(model, save_dir) + outputs = model([array_ops.ones([1, 2]), 2. * array_ops.ones([1, 2])]) + self.assertAllClose( + {"dense": outputs[0], "dense_1": outputs[1]}, + self._import_and_infer( + save_dir, + {"x1": [[1., 1.]], + "x2": [[2., 2.]]})) + class MemoryTests(test.TestCase): -- GitLab From 04e95d6b4c67920cc7e442b89a150a88b86fea08 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Mon, 26 Nov 2018 15:36:50 -0800 Subject: [PATCH 348/672] [tf.data] Test and benchmark cleanup. PiperOrigin-RevId: 222899136 --- tensorflow/python/data/benchmarks/BUILD | 55 ++ .../python/data/benchmarks/batch_benchmark.py | 85 +++ .../data/benchmarks/filter_benchmark.py | 69 ++ .../from_tensor_slices_benchmark.py | 188 +++++ .../python/data/benchmarks/map_benchmark.py | 135 ++++ .../python/data/experimental/benchmarks/BUILD | 63 +- .../benchmarks/autotune_benchmark.py | 187 +++++ .../benchmarks/csv_dataset_benchmark.py | 129 ++++ .../benchmarks/map_and_batch_benchmark.py | 129 ++++ .../experimental/benchmarks/map_benchmark.py | 245 ------- .../benchmarks/map_vectorization_benchmark.py | 194 +++++ .../benchmarks/matching_files_benchmark.py | 2 +- .../benchmarks/optimize_benchmark.py | 120 +++ .../data/experimental/kernel_tests/BUILD | 4 - .../kernel_tests/batch_dataset_op_test.py | 688 ------------------ .../kernel_tests/csv_dataset_test.py | 99 --- .../kernel_tests/optimization/BUILD | 8 +- .../optimization/map_vectorization_test.py | 101 --- .../optimization/model_dataset_test.py | 164 ----- tensorflow/python/data/kernel_tests/BUILD | 413 +++++++---- .../python/data/kernel_tests/batch_test.py | 173 +++++ ...cache_dataset_op_test.py => cache_test.py} | 6 +- ...dataset_op_test.py => concatenate_test.py} | 4 +- ...tal_test.py => dataset_checkpoint_test.py} | 331 +-------- .../dataset_constructor_op_test.py | 606 --------------- .../{dataset_ops_test.py => dataset_test.py} | 7 +- ...lter_dataset_op_test.py => filter_test.py} | 45 +- .../fixed_length_record_dataset_test.py | 171 +++++ ...ap_dataset_op_test.py => flat_map_test.py} | 4 +- ...ator_op_test.py => from_generator_test.py} | 4 +- .../from_sparse_tensor_slices_test.py | 85 +++ .../kernel_tests/from_tensor_slices_test.py | 177 +++++ .../data/kernel_tests/from_tensors_test.py | 258 +++++++ .../python/data/kernel_tests/inputs_test.py | 151 ---- ..._dataset_op_test.py => interleave_test.py} | 151 ++-- .../kernel_tests/iterator_checkpoint_test.py | 129 ++++ ...uster_test.py => iterator_cluster_test.py} | 2 +- ...{iterator_ops_test.py => iterator_test.py} | 100 +-- ..._dataset_op_test.py => list_files_test.py} | 5 +- .../{map_dataset_op_test.py => map_test.py} | 109 +-- .../multi_device_iterator_test.py | 4 +- ...{optional_ops_test.py => optional_test.py} | 2 +- ...ataset_op_test.py => padded_batch_test.py} | 196 +---- ...ch_dataset_op_test.py => prefetch_test.py} | 5 +- ...range_dataset_op_test.py => range_test.py} | 5 +- .../kernel_tests/reader_dataset_ops_test.py | 446 ------------ ...duce_dataset_op_test.py => reduce_test.py} | 4 +- ...ence_dataset_op_test.py => repeat_test.py} | 55 +- ...shard_dataset_op_test.py => shard_test.py} | 5 +- ...fle_dataset_op_test.py => shuffle_test.py} | 4 +- .../python/data/kernel_tests/skip_test.py | 62 ++ .../python/data/kernel_tests/take_test.py | 55 ++ .../kernel_tests/text_line_dataset_test.py | 165 +++++ .../kernel_tests/tf_record_dataset_test.py | 170 +++++ ...ndow_dataset_op_test.py => window_test.py} | 4 +- .../{zip_dataset_op_test.py => zip_test.py} | 4 +- 56 files changed, 3150 insertions(+), 3632 deletions(-) create mode 100644 tensorflow/python/data/benchmarks/batch_benchmark.py create mode 100644 tensorflow/python/data/benchmarks/filter_benchmark.py create mode 100644 tensorflow/python/data/benchmarks/from_tensor_slices_benchmark.py create mode 100644 tensorflow/python/data/benchmarks/map_benchmark.py create mode 100644 tensorflow/python/data/experimental/benchmarks/autotune_benchmark.py create mode 100644 tensorflow/python/data/experimental/benchmarks/csv_dataset_benchmark.py delete mode 100644 tensorflow/python/data/experimental/benchmarks/map_benchmark.py create mode 100644 tensorflow/python/data/experimental/benchmarks/map_vectorization_benchmark.py create mode 100644 tensorflow/python/data/experimental/benchmarks/optimize_benchmark.py delete mode 100644 tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py create mode 100644 tensorflow/python/data/kernel_tests/batch_test.py rename tensorflow/python/data/kernel_tests/{cache_dataset_op_test.py => cache_test.py} (98%) rename tensorflow/python/data/kernel_tests/{concatenate_dataset_op_test.py => concatenate_test.py} (98%) rename tensorflow/python/data/kernel_tests/{save_restore_experimental_test.py => dataset_checkpoint_test.py} (51%) delete mode 100644 tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py rename tensorflow/python/data/kernel_tests/{dataset_ops_test.py => dataset_test.py} (98%) rename tensorflow/python/data/kernel_tests/{filter_dataset_op_test.py => filter_test.py} (77%) create mode 100644 tensorflow/python/data/kernel_tests/fixed_length_record_dataset_test.py rename tensorflow/python/data/kernel_tests/{flat_map_dataset_op_test.py => flat_map_test.py} (97%) rename tensorflow/python/data/kernel_tests/{dataset_from_generator_op_test.py => from_generator_test.py} (99%) create mode 100644 tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py create mode 100644 tensorflow/python/data/kernel_tests/from_tensor_slices_test.py create mode 100644 tensorflow/python/data/kernel_tests/from_tensors_test.py delete mode 100644 tensorflow/python/data/kernel_tests/inputs_test.py rename tensorflow/python/data/kernel_tests/{interleave_dataset_op_test.py => interleave_test.py} (69%) create mode 100644 tensorflow/python/data/kernel_tests/iterator_checkpoint_test.py rename tensorflow/python/data/kernel_tests/{iterator_ops_cluster_test.py => iterator_cluster_test.py} (98%) rename tensorflow/python/data/kernel_tests/{iterator_ops_test.py => iterator_test.py} (87%) rename tensorflow/python/data/kernel_tests/{list_files_dataset_op_test.py => list_files_test.py} (98%) rename tensorflow/python/data/kernel_tests/{map_dataset_op_test.py => map_test.py} (90%) rename tensorflow/python/data/kernel_tests/{optional_ops_test.py => optional_test.py} (99%) rename tensorflow/python/data/kernel_tests/{batch_dataset_op_test.py => padded_batch_test.py} (58%) rename tensorflow/python/data/kernel_tests/{prefetch_dataset_op_test.py => prefetch_test.py} (93%) rename tensorflow/python/data/kernel_tests/{range_dataset_op_test.py => range_test.py} (96%) delete mode 100644 tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py rename tensorflow/python/data/kernel_tests/{reduce_dataset_op_test.py => reduce_test.py} (97%) rename tensorflow/python/data/kernel_tests/{sequence_dataset_op_test.py => repeat_test.py} (67%) rename tensorflow/python/data/kernel_tests/{shard_dataset_op_test.py => shard_test.py} (96%) rename tensorflow/python/data/kernel_tests/{shuffle_dataset_op_test.py => shuffle_test.py} (98%) create mode 100644 tensorflow/python/data/kernel_tests/skip_test.py create mode 100644 tensorflow/python/data/kernel_tests/take_test.py create mode 100644 tensorflow/python/data/kernel_tests/text_line_dataset_test.py create mode 100644 tensorflow/python/data/kernel_tests/tf_record_dataset_test.py rename tensorflow/python/data/kernel_tests/{window_dataset_op_test.py => window_test.py} (98%) rename tensorflow/python/data/kernel_tests/{zip_dataset_op_test.py => zip_test.py} (97%) diff --git a/tensorflow/python/data/benchmarks/BUILD b/tensorflow/python/data/benchmarks/BUILD index fd723e0d71..5b0500eae1 100644 --- a/tensorflow/python/data/benchmarks/BUILD +++ b/tensorflow/python/data/benchmarks/BUILD @@ -6,6 +6,61 @@ exports_files(["LICENSE"]) load("//tensorflow:tensorflow.bzl", "py_test") +py_test( + name = "batch_benchmark", + srcs = ["batch_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", + "//tensorflow/python:session", + "//tensorflow/python:sparse_tensor", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + +py_test( + name = "filter_benchmark", + srcs = ["filter_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_ops", + "//tensorflow/python:session", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + +py_test( + name = "from_tensor_slices_benchmark", + srcs = ["from_tensor_slices_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:client_testlib", + "//tensorflow/python:errors", + "//tensorflow/python:session", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + +py_test( + name = "map_benchmark", + srcs = ["map_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_ops", + "//tensorflow/python:session", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + py_test( name = "range_benchmark", srcs = ["range_benchmark.py"], diff --git a/tensorflow/python/data/benchmarks/batch_benchmark.py b/tensorflow/python/data/benchmarks/batch_benchmark.py new file mode 100644 index 0000000000..b61ac86eb5 --- /dev/null +++ b/tensorflow/python/data/benchmarks/batch_benchmark.py @@ -0,0 +1,85 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for `tf.data.Dataset.batch()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import sparse_tensor +from tensorflow.python.ops import array_ops +from tensorflow.python.platform import test + + +# TODO(b/119837791): Add eager benchmarks. +class BatchBenchmark(test.Benchmark): + """Benchmarks for `tf.data.Dataset.batch()`.""" + + def benchmarkBatchSparse(self): + non_zeros_per_row_values = [0, 1, 5, 10, 100] + batch_size_values = [1, 32, 64, 128, 1024] + + sparse_placeholder = array_ops.sparse_placeholder(dtype=dtypes.int64) + batch_size_placeholder = array_ops.placeholder(dtype=dtypes.int64, shape=[]) + + dataset = dataset_ops.Dataset.from_tensors(sparse_placeholder).repeat( + ).batch(batch_size_placeholder) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + for non_zeros_per_row in non_zeros_per_row_values: + + sparse_value = sparse_tensor.SparseTensorValue( + indices=np.arange(non_zeros_per_row, dtype=np.int64)[:, np.newaxis], + values=np.arange(non_zeros_per_row, dtype=np.int64), + dense_shape=[1000]) + + for batch_size in batch_size_values: + + with session.Session() as sess: + sess.run(iterator.initializer, feed_dict={ + sparse_placeholder: sparse_value, + batch_size_placeholder: batch_size}) + # Run five steps to warm up the session caches before taking the + # first measurement. + for _ in range(5): + sess.run(next_element.indices.op) + deltas = [] + for _ in range(100): + start = time.time() + for _ in range(100): + sess.run(next_element.indices.op) + end = time.time() + deltas.append(end - start) + + median_wall_time = np.median(deltas) / 100.0 + + print("Batch sparse dataset non-zeros per row: %d batch_size: %d " + "wall time: %f" + % (non_zeros_per_row, batch_size, median_wall_time)) + self.report_benchmark( + iters=10000, wall_time=median_wall_time, + name="batch_sparse_dataset_nnz_%d_batch_size_%d" % ( + non_zeros_per_row, batch_size)) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/benchmarks/filter_benchmark.py b/tensorflow/python/data/benchmarks/filter_benchmark.py new file mode 100644 index 0000000000..b9acdc7227 --- /dev/null +++ b/tensorflow/python/data/benchmarks/filter_benchmark.py @@ -0,0 +1,69 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for `tf.data.Dataset.filter()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.platform import test + + +# TODO(b/119837791): Add eager benchmarks. +class FilterBenchmark(test.Benchmark): + """Benchmarks for `tf.data.Dataset.filter()`.""" + + def _benchmark(self, predicate, name): + with ops.Graph().as_default(): + dataset = ( + dataset_ops.Dataset.from_tensors(True).repeat(None).filter(predicate)) + iterator = dataset.make_one_shot_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for _ in range(5): + sess.run(next_element.op) + deltas = [] + for _ in range(100): + start = time.time() + for _ in range(100): + sess.run(next_element.op) + end = time.time() + deltas.append(end - start) + + median_wall_time = np.median(deltas) / 100 + print("Filter dataset using %s. Median wall time: %f" % + (name, median_wall_time)) + self.report_benchmark( + iters=100, + wall_time=median_wall_time, + name=name) + + def benchmarkSimpleFunction(self): + self._benchmark(array_ops.identity, "simple_function") + + def benchmarkReturnComponentOptimization(self): + self._benchmark(lambda x: x, "return_component") + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/benchmarks/from_tensor_slices_benchmark.py b/tensorflow/python/data/benchmarks/from_tensor_slices_benchmark.py new file mode 100644 index 0000000000..74a2d271ad --- /dev/null +++ b/tensorflow/python/data/benchmarks/from_tensor_slices_benchmark.py @@ -0,0 +1,188 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for `tf.data.Dataset.from_tensor_slices()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import errors +from tensorflow.python.platform import test + + +# TODO(b/119837791): Add eager benchmarks. +class FromTensorSlicesBenchmark(test.Benchmark): + """Benchmarks for `tf.data.Dataset.from_tensor_slices()`.""" + + def benchmarkSliceRepeatBatch(self): + input_size = 10000 + batch_size = 100 + num_epochs = 100 + + input_data = np.random.randn(input_size) + + dataset = ( + dataset_ops.Dataset.from_tensor_slices(input_data) + .repeat(num_epochs + 1).batch(batch_size)) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + sess.run(iterator.initializer) + # Run one whole epoch to burn in the computation. + for _ in range(input_size // batch_size): + sess.run(next_element) + deltas = [] + try: + while True: + start = time.time() + sess.run(next_element) + deltas.append(time.time() - start) + except errors.OutOfRangeError: + pass + + median_wall_time = np.median(deltas) + print("Slice/repeat/batch with sess.run() input size: %d batch size: %d " + "Median wall time per element: %f" % (input_size, batch_size, + median_wall_time)) + self.report_benchmark( + iters=len(deltas), + wall_time=median_wall_time, + name="slice_repeat_batch_input_%d_batch_%d" % (input_size, batch_size)) + + def benchmarkSliceRepeatBatchCallable(self): + input_size = 10000 + batch_size = 100 + num_epochs = 100 + + input_data = np.random.randn(input_size) + + dataset = ( + dataset_ops.Dataset.from_tensor_slices(input_data) + .repeat(num_epochs + 1).batch(batch_size)) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + sess.run(iterator.initializer) + get_next_element = sess.make_callable(next_element) + # Run one whole epoch to burn in the computation. + for _ in range(input_size // batch_size): + get_next_element() + deltas = [] + try: + while True: + start = time.time() + get_next_element() + deltas.append(time.time() - start) + except errors.OutOfRangeError: + pass + + median_wall_time = np.median(deltas) + print( + "Slice/repeat/batch with callable input size: %d batch size: %d Median" + " wall time per element: %f" % (input_size, batch_size, + median_wall_time)) + self.report_benchmark( + iters=len(deltas), + wall_time=median_wall_time, + name="slice_repeat_batch_callable_input_%d_batch_%d" % + (input_size, batch_size)) + + def benchmarkReshapeSliceRepeatCallable(self): + input_size = 10000 + batch_size = 100 + num_epochs = 100 + + input_data = np.random.randn(input_size) + + dataset = ( + dataset_ops.Dataset.from_tensor_slices(input_data.reshape(100, 100)) + .repeat(num_epochs + 1)) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + sess.run(iterator.initializer) + get_next_element = sess.make_callable(next_element) + # Run one whole epoch to burn in the computation. + for _ in range(input_size // batch_size): + get_next_element() + deltas = [] + try: + while True: + start = time.time() + get_next_element() + deltas.append(time.time() - start) + except errors.OutOfRangeError: + pass + + median_wall_time = np.median(deltas) + print("Reshape/slice/repeat with callable input size: %d batch size: %d " + "Median wall time per element: %f" % (input_size, batch_size, + median_wall_time)) + self.report_benchmark( + iters=len(deltas), + wall_time=median_wall_time, + name="reshape_slice_repeat_callable_input_%d_batch_%d" % + (input_size, batch_size)) + + def benchmarkSliceBatchCacheRepeatCallable(self): + input_size = 10000 + batch_size = 100 + num_epochs = 100 + + input_data = np.random.randn(input_size) + + dataset = ( + dataset_ops.Dataset.from_tensor_slices(input_data).batch(batch_size) + .cache().repeat(num_epochs + 1)) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + sess.run(iterator.initializer) + get_next_element = sess.make_callable(next_element) + # Run one whole epoch to burn in the computation. + for _ in range(input_size // batch_size): + get_next_element() + deltas = [] + try: + while True: + start = time.time() + get_next_element() + deltas.append(time.time() - start) + except errors.OutOfRangeError: + pass + + median_wall_time = np.median(deltas) + print( + "Slice/batch/cache/repeat with callable input size: %d batch size: %d " + "Median wall time per element: %f" + % (input_size, batch_size, median_wall_time)) + self.report_benchmark( + iters=len(deltas), + wall_time=median_wall_time, + name="slice_batch_cache_repeat_callable_input_%d_batch_%d" % + (input_size, batch_size)) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/benchmarks/map_benchmark.py b/tensorflow/python/data/benchmarks/map_benchmark.py new file mode 100644 index 0000000000..48294eeb89 --- /dev/null +++ b/tensorflow/python/data/benchmarks/map_benchmark.py @@ -0,0 +1,135 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Bechmarks for `tf.data.Dataset.map()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import ops +from tensorflow.python.platform import test + + +# TODO(b/119837791): Add eager benchmarks. +class MapBenchmark(test.Benchmark): + """Bechmarks for `tf.data.Dataset.map()`.""" + + def benchmarkChainOfMaps(self): + chain_lengths = [0, 1, 2, 5, 10, 20, 50] + for chain_length in chain_lengths: + for mode in ["general", "single-threaded", "short-circuit"]: + if mode == "general": + map_fn = lambda x: x + 1 + use_inter_op_parallelism = True + print_label = "" + benchmark_label = "" + if mode == "single-threaded": + map_fn = lambda x: x + 1 + use_inter_op_parallelism = False + print_label = " (single threaded mode)" + benchmark_label = "_single_threaded" + if mode == "short-circuit": + map_fn = lambda x: x + use_inter_op_parallelism = True # should not have any significance + print_label = " (short circuit mode)" + benchmark_label = "_short_circuit" + + with ops.Graph().as_default(): + dataset = dataset_ops.Dataset.from_tensors(0).repeat(None) + for _ in range(chain_length): + dataset = dataset_ops.MapDataset( + dataset, + map_fn, + use_inter_op_parallelism=use_inter_op_parallelism) + iterator = dataset.make_one_shot_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for _ in range(5): + sess.run(next_element.op) + deltas = [] + for _ in range(100): + start = time.time() + for _ in range(100): + sess.run(next_element.op) + end = time.time() + deltas.append(end - start) + + median_wall_time = np.median(deltas) / 100 + print("Map dataset chain length%s: %d Median wall time: %f" % + (print_label, chain_length, median_wall_time)) + self.report_benchmark( + iters=1000, + wall_time=median_wall_time, + name="map_dataset_chain_length_%d%s" % (chain_length, + benchmark_label)) + + def benchmarkMapFanOut(self): + fan_outs = [1, 2, 5, 10, 20, 50, 100] + for fan_out in fan_outs: + for mode in ["general", "single-threaded", "short-circuit"]: + if mode == "general": + map_fn = lambda *xs: [x + 1 for x in xs] + use_inter_op_parallelism = True + print_label = "" + benchmark_label = "" + if mode == "single-threaded": + map_fn = lambda *xs: [x + 1 for x in xs] + use_inter_op_parallelism = False + print_label = " (single threaded mode)" + benchmark_label = "_single_threaded" + if mode == "short-circuit": + map_fn = lambda *xs: xs + use_inter_op_parallelism = True # should not have any significance + print_label = " (short circuit mode)" + benchmark_label = "_short_circuit" + + with ops.Graph().as_default(): + dataset = dataset_ops.Dataset.from_tensors( + tuple(0 for _ in range(fan_out))).repeat(None) + dataset = dataset_ops.MapDataset( + dataset, + map_fn, + use_inter_op_parallelism=use_inter_op_parallelism) + iterator = dataset.make_one_shot_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for _ in range(5): + sess.run(next_element[0].op) + deltas = [] + for _ in range(100): + start = time.time() + for _ in range(100): + sess.run(next_element[0].op) + end = time.time() + deltas.append(end - start) + + median_wall_time = np.median(deltas) / 100 + print("Map dataset fan out%s: %d Median wall time: %f" % + (print_label, fan_out, median_wall_time)) + self.report_benchmark( + iters=1000, + wall_time=median_wall_time, + name="map_dataset_fan_out_%d%s" % (fan_out, benchmark_label)) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/experimental/benchmarks/BUILD b/tensorflow/python/data/experimental/benchmarks/BUILD index c48647a218..075863d34f 100644 --- a/tensorflow/python/data/experimental/benchmarks/BUILD +++ b/tensorflow/python/data/experimental/benchmarks/BUILD @@ -7,32 +7,67 @@ exports_files(["LICENSE"]) load("//tensorflow:tensorflow.bzl", "cuda_py_test") load("//tensorflow:tensorflow.bzl", "py_test") +py_test( + name = "csv_dataset_benchmark", + srcs = ["csv_dataset_benchmark.py"], + srcs_version = "PY2AND3", + tags = ["no_pip"], + deps = [ + "//tensorflow/python:client_testlib", + "//tensorflow/python:parsing_ops", + "//tensorflow/python:platform", + "//tensorflow/python:platform_test", + "//tensorflow/python:session", + "//tensorflow/python/data/experimental/ops:readers", + "//tensorflow/python/data/ops:readers", + "//third_party/py/numpy", + ], +) + py_test( name = "map_and_batch_benchmark", - size = "medium", srcs = ["map_and_batch_benchmark.py"], srcs_version = "PY2AND3", deps = [ + "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_ops", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:math_ops", "//tensorflow/python:random_ops", "//tensorflow/python:session", "//tensorflow/python/data/experimental/ops:batching", - "//tensorflow/python/data/experimental/ops:optimization", "//tensorflow/python/data/ops:dataset_ops", "//third_party/py/numpy", ], ) py_test( - name = "map_benchmark", - size = "medium", - srcs = ["map_benchmark.py"], + name = "map_vectorization_benchmark", + srcs = ["map_vectorization_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/core:protos_all_py", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:math_ops", + "//tensorflow/python:parsing_ops", + "//tensorflow/python:session", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/util:nest", + "//third_party/py/numpy", + ], +) + +py_test( + name = "autotune_benchmark", + srcs = ["autotune_benchmark.py"], srcs_version = "PY2AND3", deps = [ "//tensorflow/python:client_testlib", - "//tensorflow/python:framework_ops", "//tensorflow/python:math_ops", "//tensorflow/python:session", "//tensorflow/python/data/experimental/ops:batching", @@ -42,6 +77,20 @@ py_test( ], ) +py_test( + name = "optimize_benchmark", + srcs = ["optimize_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_ops", + "//tensorflow/python:math_ops", + "//tensorflow/python:session", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + py_test( name = "matching_files_benchmark", size = "small", diff --git a/tensorflow/python/data/experimental/benchmarks/autotune_benchmark.py b/tensorflow/python/data/experimental/benchmarks/autotune_benchmark.py new file mode 100644 index 0000000000..b00e918338 --- /dev/null +++ b/tensorflow/python/data/experimental/benchmarks/autotune_benchmark.py @@ -0,0 +1,187 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for autotuning performance knobs.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.experimental.ops import batching +from tensorflow.python.data.experimental.ops import optimization +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.platform import test + + +class AutotuneBenchmark(test.Benchmark): + """Benchmarks for autotuning performance knobs.""" + + def benchmarkMap(self): + k = 1024 * 1024 + dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), + np.random.rand(4 * k, + 1))).repeat() + dataset = dataset.map( + math_ops.matmul, num_parallel_calls=optimization.AUTOTUNE) + iterator = dataset.make_one_shot_iterator() + get_next = iterator.get_next() + + deltas = [] + with session.Session() as sess: + for _ in range(5): + sess.run(get_next.op) + for _ in range(1000): + start = time.time() + sess.run(get_next.op) + end = time.time() + deltas.append(end - start) + + print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % + (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), + np.max(deltas))) + self.report_benchmark( + iters=1000, wall_time=np.median(deltas), name="map_autotune") + + def benchmarkMapAndBatch(self): + self._benchmarkMapAndBatch(numa_aware=False) + self._benchmarkMapAndBatch(numa_aware=True) + + def _benchmarkMapAndBatch(self, numa_aware): + batch_size = 16 + k = 1024 * 1024 + dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), + np.random.rand(4 * k, + 1))).repeat() + dataset = dataset.apply( + batching.map_and_batch( + math_ops.matmul, + num_parallel_calls=optimization.AUTOTUNE, + batch_size=batch_size)) + options = dataset_ops.Options() + options.experimental_numa_aware = numa_aware + dataset = dataset.with_options(options) + iterator = dataset.make_one_shot_iterator() + get_next = iterator.get_next() + + deltas = [] + with session.Session() as sess: + for _ in range(5): + sess.run(get_next.op) + for _ in range(100): + start = time.time() + sess.run(get_next.op) + end = time.time() + deltas.append(end - start) + + print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % + (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), + np.max(deltas))) + + self.report_benchmark( + iters=100, + wall_time=np.median(deltas), + name=("numa_" if numa_aware else "") + "map_and_batch_autotune") + + def benchmarkInterleave(self): + k = 1024 * 1024 + dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), + np.random.rand(4 * k, + 1))).repeat() + dataset = dataset.map(math_ops.matmul) + dataset = dataset_ops.Dataset.range(1).repeat().interleave( + lambda _: dataset, + cycle_length=10, + num_parallel_calls=optimization.AUTOTUNE) + iterator = dataset.make_one_shot_iterator() + get_next = iterator.get_next() + + deltas = [] + with session.Session() as sess: + for _ in range(5): + sess.run(get_next.op) + for _ in range(1000): + start = time.time() + sess.run(get_next.op) + end = time.time() + deltas.append(end - start) + + print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % + (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), + np.max(deltas))) + self.report_benchmark( + iters=1000, + wall_time=np.median(deltas), + name="interleave_autotune") + + def benchmarkMapAndInterleave(self): + k = 1024 * 1024 + a = (np.random.rand(1, 8 * k), np.random.rand(8 * k, 1)) + b = (np.random.rand(1, 4 * k), np.random.rand(4 * k, 1)) + c = (np.random.rand(1, 2 * k), np.random.rand(2 * k, 1)) + dataset = dataset_ops.Dataset.from_tensors((a, b, c)).repeat() + + def f1(a, b, c): + x, y = a + return math_ops.matmul(x, y), b, c + + def f2(a, b, c): + x, y = b + return a, math_ops.matmul(x, y), c + + def f3(a, b, c): + x, y = c + return a, b, math_ops.matmul(x, y) + + dataset = dataset.map(f1, num_parallel_calls=optimization.AUTOTUNE) + dataset = dataset_ops.Dataset.range(1).repeat().interleave( + lambda _: dataset, + num_parallel_calls=optimization.AUTOTUNE, + cycle_length=2) + + dataset = dataset.map(f2, num_parallel_calls=optimization.AUTOTUNE) + dataset = dataset_ops.Dataset.range(1).repeat().interleave( + lambda _: dataset, + num_parallel_calls=optimization.AUTOTUNE, + cycle_length=2) + + dataset = dataset.map(f3, num_parallel_calls=optimization.AUTOTUNE) + iterator = dataset.make_one_shot_iterator() + get_next = iterator.get_next() + + deltas = [] + with session.Session() as sess: + for _ in range(5): + sess.run(get_next) + for _ in range(100): + start = time.time() + sess.run(get_next) + end = time.time() + deltas.append(end - start) + + print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % + (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), + np.max(deltas))) + self.report_benchmark( + iters=100, + wall_time=np.median(deltas), + name="map_and_interleave_autotune") + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/experimental/benchmarks/csv_dataset_benchmark.py b/tensorflow/python/data/experimental/benchmarks/csv_dataset_benchmark.py new file mode 100644 index 0000000000..7eebf49c38 --- /dev/null +++ b/tensorflow/python/data/experimental/benchmarks/csv_dataset_benchmark.py @@ -0,0 +1,129 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for `tf.data.experimental.CsvDataset`.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import string +import tempfile +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.experimental.ops import readers +from tensorflow.python.data.ops import readers as core_readers +from tensorflow.python.ops import parsing_ops +from tensorflow.python.platform import gfile +from tensorflow.python.platform import googletest +from tensorflow.python.platform import test + + +class CsvDatasetBenchmark(test.Benchmark): + """Benchmarks for `tf.data.experimental.CsvDataset`.""" + + FLOAT_VAL = '1.23456E12' + STR_VAL = string.ascii_letters * 10 + + def _setUp(self, str_val): + # Since this isn't test.TestCase, have to manually create a test dir + gfile.MakeDirs(googletest.GetTempDir()) + self._temp_dir = tempfile.mkdtemp(dir=googletest.GetTempDir()) + + self._num_cols = [4, 64, 256] + self._num_per_iter = 5000 + self._filenames = [] + for n in self._num_cols: + fn = os.path.join(self._temp_dir, 'file%d.csv' % n) + with open(fn, 'wb') as f: + # Just write 100 rows and use `repeat`... Assumes the cost + # of creating an iterator is not significant + row = ','.join([str_val for _ in range(n)]) + f.write('\n'.join([row for _ in range(100)])) + self._filenames.append(fn) + + def _tearDown(self): + gfile.DeleteRecursively(self._temp_dir) + + def _runBenchmark(self, dataset, num_cols, prefix): + dataset = dataset.skip(self._num_per_iter - 1) + deltas = [] + for _ in range(10): + next_element = dataset.make_one_shot_iterator().get_next() + with session.Session() as sess: + start = time.time() + # NOTE: This depends on the underlying implementation of skip, to have + # the net effect of calling `GetNext` num_per_iter times on the + # input dataset. We do it this way (instead of a python for loop, or + # batching N inputs in one iter) so that the overhead from session.run + # or batch doesn't dominate. If we eventually optimize skip, this has + # to change. + sess.run(next_element) + end = time.time() + deltas.append(end - start) + # Median wall time per CSV record read and decoded + median_wall_time = np.median(deltas) / self._num_per_iter + print('%s num_cols: %d Median wall time: %f' % (prefix, num_cols, + median_wall_time)) + self.report_benchmark( + iters=self._num_per_iter, + wall_time=median_wall_time, + name='%s_with_cols_%d' % (prefix, num_cols)) + + def benchmarkMapWithFloats(self): + self._setUp(self.FLOAT_VAL) + for i in range(len(self._filenames)): + num_cols = self._num_cols[i] + kwargs = {'record_defaults': [[0.0]] * num_cols} + dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() + dataset = dataset.map(lambda l: parsing_ops.decode_csv(l, **kwargs)) # pylint: disable=cell-var-from-loop + self._runBenchmark(dataset, num_cols, 'csv_float_map_decode_csv') + self._tearDown() + + def benchmarkMapWithStrings(self): + self._setUp(self.STR_VAL) + for i in range(len(self._filenames)): + num_cols = self._num_cols[i] + kwargs = {'record_defaults': [['']] * num_cols} + dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() + dataset = dataset.map(lambda l: parsing_ops.decode_csv(l, **kwargs)) # pylint: disable=cell-var-from-loop + self._runBenchmark(dataset, num_cols, 'csv_strings_map_decode_csv') + self._tearDown() + + def benchmarkCsvDatasetWithFloats(self): + self._setUp(self.FLOAT_VAL) + for i in range(len(self._filenames)): + num_cols = self._num_cols[i] + kwargs = {'record_defaults': [[0.0]] * num_cols} + dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() + dataset = readers.CsvDataset(self._filenames[i], **kwargs).repeat() # pylint: disable=cell-var-from-loop + self._runBenchmark(dataset, num_cols, 'csv_float_fused_dataset') + self._tearDown() + + def benchmarkCsvDatasetWithStrings(self): + self._setUp(self.STR_VAL) + for i in range(len(self._filenames)): + num_cols = self._num_cols[i] + kwargs = {'record_defaults': [['']] * num_cols} + dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() + dataset = readers.CsvDataset(self._filenames[i], **kwargs).repeat() # pylint: disable=cell-var-from-loop + self._runBenchmark(dataset, num_cols, 'csv_strings_fused_dataset') + self._tearDown() + +if __name__ == '__main__': + test.main() diff --git a/tensorflow/python/data/experimental/benchmarks/map_and_batch_benchmark.py b/tensorflow/python/data/experimental/benchmarks/map_and_batch_benchmark.py index a90156cd33..1e8dd0f63d 100644 --- a/tensorflow/python/data/experimental/benchmarks/map_and_batch_benchmark.py +++ b/tensorflow/python/data/experimental/benchmarks/map_and_batch_benchmark.py @@ -17,6 +17,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import hashlib +import itertools import time import numpy as np @@ -25,11 +27,15 @@ from tensorflow.core.protobuf import config_pb2 from tensorflow.python.client import session from tensorflow.python.data.experimental.ops import batching from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.platform import test +_NUMPY_RANDOM_SEED = 42 + class MapAndBatchBenchmark(test.Benchmark): """Benchmarks for `tf.data.experimental.map_and_batch()`.""" @@ -89,6 +95,129 @@ class MapAndBatchBenchmark(test.Benchmark): name="benchmark_batch_dense_dataset_nnz_%d_batch_size_%d" % ( np.prod(shape), batch_size)) + def benchmarkMapAndBatchChainingVersusFusing(self): + """Compares the performance of chaining and fusing map and batch. + + NOTE: It is recommended to build the benchmark with + `-c opt --copt=-mavx --copt=-mavx2 --copt=-mfma --copt=-gmlt` + and execute it on a machine with at least 32 CPU cores. + """ + + # Sequential pipeline configurations. + seq_elem_size_series = itertools.product([1], [1], [1, 2, 4, 8], [16]) + seq_batch_size_series = itertools.product([1], [1], [1], [8, 16, 32, 64]) + + # Parallel pipeline configuration. + par_elem_size_series = itertools.product([32], [32], [1, 2, 4, 8], [256]) + par_batch_size_series = itertools.product([32], [32], [1], + [128, 256, 512, 1024]) + par_num_calls_series = itertools.product([8, 16, 32, 64], [32], [1], [512]) + par_inter_op_series = itertools.product([32], [8, 16, 32, 64], [1], [512]) + + def name(method, label, num_calls, inter_op, element_size, batch_size): + return ("%s_id_%s_num_calls_%d_inter_op_%d_elem_size_%d_batch_size_%d" % ( + method, + hashlib.sha1(label).hexdigest()[:8], + num_calls, + inter_op, + element_size, + batch_size, + )) + + def benchmark(label, series): + """Runs benchmark the given series.""" + + print("%s:" % label) + + def make_base_dataset(element_size): + k = 1024 * 1024 + x = constant_op.constant(np.random.rand(element_size, 4 * k)) + y = constant_op.constant(np.random.rand(4 * k, 1)) + return dataset_ops.Dataset.range(1000000000000).map(lambda _: (x, y)) + + for num_calls, inter_op, element_size, batch_size in series: + + num_iters = 1024 // ( + (element_size * batch_size) // min(num_calls, inter_op)) + dataset = make_base_dataset(element_size) + chained_dataset = dataset.map( + math_ops.matmul, + num_parallel_calls=num_calls).batch(batch_size=batch_size) + chained_iterator = chained_dataset.make_one_shot_iterator() + chained_get_next = chained_iterator.get_next() + + chained_deltas = [] + with session.Session( + config=config_pb2.ConfigProto( + inter_op_parallelism_threads=inter_op, + use_per_session_threads=True)) as sess: + for _ in range(5): + sess.run(chained_get_next.op) + for _ in range(num_iters): + start = time.time() + sess.run(chained_get_next.op) + end = time.time() + chained_deltas.append(end - start) + + fused_dataset = dataset.apply( + batching.map_and_batch( + math_ops.matmul, + num_parallel_calls=num_calls, + batch_size=batch_size)) + fused_iterator = fused_dataset.make_one_shot_iterator() + fused_get_next = fused_iterator.get_next() + + fused_deltas = [] + with session.Session( + config=config_pb2.ConfigProto( + inter_op_parallelism_threads=inter_op, + use_per_session_threads=True)) as sess: + + for _ in range(5): + sess.run(fused_get_next.op) + for _ in range(num_iters): + start = time.time() + sess.run(fused_get_next.op) + end = time.time() + fused_deltas.append(end - start) + + print( + "batch size: %d, num parallel calls: %d, inter-op parallelism: %d, " + "element size: %d, num iters: %d\nchained wall time: %f (median), " + "%f (mean), %f (stddev), %f (min), %f (max)\n fused wall time: " + "%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n " + "chained/fused: %.2fx (median), %.2fx (mean)" % + (batch_size, num_calls, inter_op, element_size, num_iters, + np.median(chained_deltas), np.mean(chained_deltas), + np.std(chained_deltas), np.min(chained_deltas), + np.max(chained_deltas), np.median(fused_deltas), + np.mean(fused_deltas), np.std(fused_deltas), np.min(fused_deltas), + np.max(fused_deltas), + np.median(chained_deltas) / np.median(fused_deltas), + np.mean(chained_deltas) / np.mean(fused_deltas))) + + self.report_benchmark( + iters=num_iters, + wall_time=np.median(chained_deltas), + name=name("chained", label, num_calls, inter_op, element_size, + batch_size)) + + self.report_benchmark( + iters=num_iters, + wall_time=np.median(fused_deltas), + name=name("fused", label, num_calls, inter_op, element_size, + batch_size)) + + print() + + np.random.seed(_NUMPY_RANDOM_SEED) + benchmark("Sequential element size evaluation", seq_elem_size_series) + benchmark("Sequential batch size evaluation", seq_batch_size_series) + benchmark("Parallel element size evaluation", par_elem_size_series) + benchmark("Parallel batch size evaluation", par_batch_size_series) + benchmark("Transformation parallelism evaluation", par_num_calls_series) + benchmark("Threadpool size evaluation", par_inter_op_series) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/experimental/benchmarks/map_benchmark.py b/tensorflow/python/data/experimental/benchmarks/map_benchmark.py deleted file mode 100644 index ad253cffa5..0000000000 --- a/tensorflow/python/data/experimental/benchmarks/map_benchmark.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. 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. -# ============================================================================== -"""Tests for the experimental input pipeline ops.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import hashlib -import itertools -import time - -import numpy as np - -from tensorflow.core.protobuf import config_pb2 -from tensorflow.python.client import session -from tensorflow.python.data.experimental.ops import batching -from tensorflow.python.data.experimental.ops import optimization -from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import ops -from tensorflow.python.ops import math_ops -from tensorflow.python.platform import test - -_NUMPY_RANDOM_SEED = 42 - - -class MapDatasetBenchmark(test.Benchmark): - - # The purpose of this benchmark is to compare the performance of chaining vs - # fusing of the map and batch transformations across various configurations. - # - # NOTE: It is recommended to build the benchmark with - # `-c opt --copt=-mavx --copt=-mavx2 --copt=-mfma --copt=-gmlt` - # and execute it on a machine with at least 32 CPU cores. - def benchmarkMapAndBatch(self): - - # Sequential pipeline configurations. - seq_elem_size_series = itertools.product([1], [1], [1, 2, 4, 8], [16]) - seq_batch_size_series = itertools.product([1], [1], [1], [8, 16, 32, 64]) - - # Parallel pipeline configuration. - par_elem_size_series = itertools.product([32], [32], [1, 2, 4, 8], [256]) - par_batch_size_series = itertools.product([32], [32], [1], - [128, 256, 512, 1024]) - par_num_calls_series = itertools.product([8, 16, 32, 64], [32], [1], [512]) - par_inter_op_series = itertools.product([32], [8, 16, 32, 64], [1], [512]) - - def name(method, label, num_calls, inter_op, element_size, batch_size): - return ("%s_id_%s_num_calls_%d_inter_op_%d_elem_size_%d_batch_size_%d" % ( - method, - hashlib.sha1(label).hexdigest(), - num_calls, - inter_op, - element_size, - batch_size, - )) - - def benchmark(label, series): - - print("%s:" % label) - for num_calls, inter_op, element_size, batch_size in series: - - num_iters = 1024 // ( - (element_size * batch_size) // min(num_calls, inter_op)) - k = 1024 * 1024 - dataset = dataset_ops.Dataset.from_tensors((np.random.rand( - element_size, 4 * k), np.random.rand(4 * k, 1))).repeat() - - chained_dataset = dataset.map( - math_ops.matmul, - num_parallel_calls=num_calls).batch(batch_size=batch_size) - chained_iterator = chained_dataset.make_one_shot_iterator() - chained_get_next = chained_iterator.get_next() - - chained_deltas = [] - with session.Session( - config=config_pb2.ConfigProto( - inter_op_parallelism_threads=inter_op, - use_per_session_threads=True)) as sess: - for _ in range(5): - sess.run(chained_get_next.op) - for _ in range(num_iters): - start = time.time() - sess.run(chained_get_next.op) - end = time.time() - chained_deltas.append(end - start) - - fused_dataset = dataset.apply( - batching.map_and_batch( - math_ops.matmul, - num_parallel_calls=num_calls, - batch_size=batch_size)) - fused_iterator = fused_dataset.make_one_shot_iterator() - fused_get_next = fused_iterator.get_next() - - fused_deltas = [] - with session.Session( - config=config_pb2.ConfigProto( - inter_op_parallelism_threads=inter_op, - use_per_session_threads=True)) as sess: - - for _ in range(5): - sess.run(fused_get_next.op) - for _ in range(num_iters): - start = time.time() - sess.run(fused_get_next.op) - end = time.time() - fused_deltas.append(end - start) - - print( - "batch size: %d, num parallel calls: %d, inter-op parallelism: %d, " - "element size: %d, num iters: %d\nchained wall time: %f (median), " - "%f (mean), %f (stddev), %f (min), %f (max)\n fused wall time: " - "%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n " - "chained/fused: %.2fx (median), %.2fx (mean)" % - (batch_size, num_calls, inter_op, element_size, num_iters, - np.median(chained_deltas), np.mean(chained_deltas), - np.std(chained_deltas), np.min(chained_deltas), - np.max(chained_deltas), np.median(fused_deltas), - np.mean(fused_deltas), np.std(fused_deltas), np.min(fused_deltas), - np.max(fused_deltas), - np.median(chained_deltas) / np.median(fused_deltas), - np.mean(chained_deltas) / np.mean(fused_deltas))) - - self.report_benchmark( - iters=num_iters, - wall_time=np.median(chained_deltas), - name=name("chained", label, num_calls, inter_op, element_size, - batch_size)) - - self.report_benchmark( - iters=num_iters, - wall_time=np.median(fused_deltas), - name=name("fused", label, num_calls, inter_op, element_size, - batch_size)) - - print("") - - np.random.seed(_NUMPY_RANDOM_SEED) - benchmark("Sequential element size evaluation", seq_elem_size_series) - benchmark("Sequential batch size evaluation", seq_batch_size_series) - benchmark("Parallel element size evaluation", par_elem_size_series) - benchmark("Parallel batch size evaluation", par_batch_size_series) - benchmark("Transformation parallelism evaluation", par_num_calls_series) - benchmark("Threadpool size evaluation", par_inter_op_series) - - # This benchmark compares the performance of pipeline with multiple chained - # maps with and without map fusion. - def benchmarkChainOfMaps(self): - chain_lengths = [0, 1, 2, 5, 10, 20, 50] - for chain_length in chain_lengths: - self._benchmarkChainOfMaps(chain_length, False) - self._benchmarkChainOfMaps(chain_length, True) - - def _benchmarkChainOfMaps(self, chain_length, optimize_dataset): - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors(0).repeat(None) - for _ in range(chain_length): - dataset = dataset.map(lambda x: x) - if optimize_dataset: - dataset = dataset.apply(optimization.optimize(["map_fusion"])) - - iterator = dataset.make_one_shot_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for _ in range(5): - sess.run(next_element.op) - deltas = [] - for _ in range(100): - start = time.time() - for _ in range(100): - sess.run(next_element.op) - end = time.time() - deltas.append(end - start) - - median_wall_time = np.median(deltas) / 100 - opt_mark = "opt" if optimize_dataset else "no-opt" - print("Map dataset {} chain length: {} Median wall time: {}".format( - opt_mark, chain_length, median_wall_time)) - self.report_benchmark( - iters=1000, - wall_time=median_wall_time, - name="benchmark_map_dataset_chain_latency_{}_{}".format( - opt_mark, chain_length)) - - -class MapAndFilterBenchmark(test.Benchmark): - - # This benchmark compares the performance of pipeline with multiple chained - # map + filter with and without map fusion. - def benchmarkMapAndFilter(self): - chain_lengths = [0, 1, 2, 5, 10, 20, 50] - for chain_length in chain_lengths: - self._benchmarkMapAndFilter(chain_length, False) - self._benchmarkMapAndFilter(chain_length, True) - - def _benchmarkMapAndFilter(self, chain_length, optimize_dataset): - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors(0).repeat(None) - for _ in range(chain_length): - dataset = dataset.map(lambda x: x + 5).filter( - lambda x: math_ops.greater_equal(x - 5, 0)) - if optimize_dataset: - dataset = dataset.apply( - optimization.optimize(["map_and_filter_fusion"])) - - iterator = dataset.make_one_shot_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for _ in range(10): - sess.run(next_element.op) - deltas = [] - for _ in range(100): - start = time.time() - for _ in range(100): - sess.run(next_element.op) - end = time.time() - deltas.append(end - start) - - median_wall_time = np.median(deltas) / 100 - opt_mark = "opt" if optimize_dataset else "no-opt" - print("Map and filter dataset {} chain length: {} Median wall time: {}". - format(opt_mark, chain_length, median_wall_time)) - self.report_benchmark( - iters=1000, - wall_time=median_wall_time, - name="benchmark_map_and_filter_dataset_chain_latency_{}_{}".format( - opt_mark, chain_length)) - - -if __name__ == "__main__": - test.main() diff --git a/tensorflow/python/data/experimental/benchmarks/map_vectorization_benchmark.py b/tensorflow/python/data/experimental/benchmarks/map_vectorization_benchmark.py new file mode 100644 index 0000000000..0c3ac8b371 --- /dev/null +++ b/tensorflow/python/data/experimental/benchmarks/map_vectorization_benchmark.py @@ -0,0 +1,194 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for the `MapVectorization` optimization.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.core.example import example_pb2 +from tensorflow.core.example import feature_pb2 +from tensorflow.python.client import session +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.util import nest +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import parsing_ops +from tensorflow.python.platform import test + + +def _generate_csv_test_case(): + """Generates a `decode_csv()` test case.""" + + def csv_factory(): + return dataset_ops.Dataset.from_tensor_slices(["1.0:2:a", + "2.4:5:c"]).repeat(5) + + def decode_csv_fn(x): + return parsing_ops.decode_csv( + x, + record_defaults=[ + constant_op.constant([], dtypes.float32), + constant_op.constant([], dtypes.int32), + constant_op.constant([], dtypes.string) + ], + field_delim=":") + + return decode_csv_fn, csv_factory + + +def _generate_parse_single_example_test_case(): + """Generates a `parse_single_example()` test case.""" + + def parse_example_factory(): + """Parse example factory.""" + + def _int64_feature(*values): + return feature_pb2.Feature(int64_list=feature_pb2.Int64List(value=values)) + + def _bytes_feature(*values): + return feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[v.encode("utf-8") for v in values])) + + return dataset_ops.Dataset.from_tensor_slices( + constant_op.constant([ + example_pb2.Example( + features=feature_pb2.Features( + feature={ + "dense_int": _int64_feature(i), + "dense_str": _bytes_feature(str(i)), + "sparse_int": _int64_feature(i, i * 2, i * 4, i * 8), + "sparse_str": _bytes_feature(*["abc"] * i) + })).SerializeToString() for i in range(10) + ])) + + def parse_single_example_fn(x): + features = { + "dense_int": parsing_ops.FixedLenFeature((), dtypes.int64, 0), + "dense_str": parsing_ops.FixedLenFeature((), dtypes.string, ""), + "sparse_int": parsing_ops.VarLenFeature(dtypes.int64), + "sparse_str": parsing_ops.VarLenFeature(dtypes.string), + } + return parsing_ops.parse_single_example(x, features) + + return parse_single_example_fn, parse_example_factory + + +# TODO(rachelim): Add a benchmark for more expensive transformations, such as +# vgg_preprocessing. +class MapVectorizationBenchmark(test.Benchmark): + """Benchmarks for the `MapVectorization` optimization.""" + + def _run(self, x, num_iters=100, name=None): + deltas = [] + with session.Session() as sess: + for _ in range(5): + # Warm up session... + sess.run(x) + for _ in range(num_iters): + start = time.time() + sess.run(x) + end = time.time() + deltas.append(end - start) + median_time = np.median(deltas) + self.report_benchmark(iters=num_iters, wall_time=median_time, name=name) + return median_time + + def _compare(self, input_dataset, map_fn, batch_size, input_size, str_id): + num_elems = int(np.sum([np.prod(x) for x in input_size])) + name_template = "{}__batch_size_{}_input_element_size_{}_{}" + unoptimized = input_dataset.map(map_fn).batch(batch_size) + unoptimized_op = unoptimized.make_one_shot_iterator().get_next() + + optimized = input_dataset.map(map_fn).batch(batch_size) + options = dataset_ops.Options() + options.experimental_map_vectorization = True + optimized = optimized.with_options(options) + optimized_op = optimized.make_one_shot_iterator().get_next() + + unoptimized_time = self._run( + unoptimized_op, + name=name_template.format(str_id, batch_size, num_elems, "unoptimized")) + optimized_time = self._run( + optimized_op, + name=name_template.format(str_id, batch_size, num_elems, "optimized")) + + print("Batch size: {}\n" + "Input element size: {}\n" + "Transformation: {}\n" + "Speedup: {}\n".format(batch_size, input_size, str_id, + (unoptimized_time / optimized_time))) + + # Known cheap functions + def benchmarkIdentity(self): + self._benchmark_helper(lambda *args: [array_ops.identity(x) for x in args], + "identity") + + def benchmarkAddConst(self): + self._benchmark_helper(lambda *args: [x + 1 for x in args], "add_const") + + def benchmarkReturnConst(self): + self._benchmark_helper(lambda *args: [constant_op.constant(2)], "ret_const") + + def benchmarkSelect(self): + self._benchmark_helper(lambda *args: args[0], "select") + + def benchmarkCast(self): + self._benchmark_helper( + lambda *args: [math_ops.cast(x, dtypes.float64) for x in args], "cast") + + def benchmarkReshape(self): + self._benchmark_helper( + lambda *args: [array_ops.reshape(x, (-1, 30)) for x in args], "reshape") + + def benchmarkDecodeCSV(self): + csv_fn, csv_factory = _generate_csv_test_case() + self._benchmark_helper(csv_fn, "decode_csv", lambda: [csv_factory()]) + + def benchmarkParseSingleExample(self): + # NOTE: Since we haven't implemented a vectorizer for "SerializeSparse", + # this function is only naively vectorized. + parse_fn, parse_factory = _generate_parse_single_example_test_case() + + self._benchmark_helper(parse_fn, "parse_single_example", + lambda: [parse_factory()]) + + def _default_dataset_factory(self): + input_sizes = [(10, 10, 3), (10, 100, 300)] + for sz in input_sizes: + yield dataset_ops.Dataset.from_tensor_slices(np.random.rand(*sz)) + + def _benchmark_helper(self, map_fn, str_id, base_dataset_factory=None): + if base_dataset_factory is None: + base_dataset_factory = self._default_dataset_factory + + batch_size = 1000 + for base_dataset in base_dataset_factory(): + base_dataset = base_dataset.repeat() + input_size = [ + tuple(shape.as_list()) + for shape in nest.flatten(base_dataset.output_shapes) + ] + self._compare(base_dataset, map_fn, batch_size, input_size, str_id) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py b/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py index d0d979dbd4..2eb5561b11 100644 --- a/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py +++ b/tensorflow/python/data/experimental/benchmarks/matching_files_benchmark.py @@ -91,7 +91,7 @@ class MatchingFilesBenchmark(test.Benchmark): (len(median_deltas) - 2): np.average(median_deltas[2:]) }, - name='benchmark_matching_files_dataset_nesteddirectory(%d*%d)' % + name='dataset_nested_directory(%d*%d)' % (width, depth)) shutil.rmtree(tmp_dir, ignore_errors=True) diff --git a/tensorflow/python/data/experimental/benchmarks/optimize_benchmark.py b/tensorflow/python/data/experimental/benchmarks/optimize_benchmark.py new file mode 100644 index 0000000000..0eca97d26d --- /dev/null +++ b/tensorflow/python/data/experimental/benchmarks/optimize_benchmark.py @@ -0,0 +1,120 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Benchmarks for static optimizations.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import ops +from tensorflow.python.ops import math_ops +from tensorflow.python.platform import test + + +class OptimizationBenchmark(test.Benchmark): + """Benchmarks for static optimizations.""" + + def benchmarkMapFusion(self): + """Evaluates performance map of fusion.""" + + chain_lengths = [0, 1, 2, 5, 10, 20, 50] + for chain_length in chain_lengths: + self._benchmarkMapFusion(chain_length, False) + self._benchmarkMapFusion(chain_length, True) + + def _benchmarkMapFusion(self, chain_length, optimize_dataset): + with ops.Graph().as_default(): + dataset = dataset_ops.Dataset.from_tensors(0).repeat(None) + for _ in range(chain_length): + dataset = dataset.map(lambda x: x) + if optimize_dataset: + options = dataset_ops.Options() + options.experimental_map_fusion = True + dataset = dataset.with_options(options) + + iterator = dataset.make_one_shot_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for _ in range(5): + sess.run(next_element.op) + deltas = [] + for _ in range(100): + start = time.time() + for _ in range(100): + sess.run(next_element.op) + end = time.time() + deltas.append(end - start) + + median_wall_time = np.median(deltas) / 100 + opt_mark = "opt" if optimize_dataset else "noopt" + print("Map dataset {} chain length: {} Median wall time: {}".format( + opt_mark, chain_length, median_wall_time)) + self.report_benchmark( + iters=100, + wall_time=median_wall_time, + name="map_fusion_{}_chain_length_{}".format( + opt_mark, chain_length)) + + def benchmarkMapAndFilterFusion(self): + """Evaluates performance map of fusion.""" + + chain_lengths = [0, 1, 2, 5, 10, 20, 50] + for chain_length in chain_lengths: + self._benchmarkMapAndFilterFusion(chain_length, False) + self._benchmarkMapAndFilterFusion(chain_length, True) + + def _benchmarkMapAndFilterFusion(self, chain_length, optimize_dataset): + with ops.Graph().as_default(): + dataset = dataset_ops.Dataset.from_tensors(0).repeat(None) + for _ in range(chain_length): + dataset = dataset.map(lambda x: x + 5).filter( + lambda x: math_ops.greater_equal(x - 5, 0)) + if optimize_dataset: + options = dataset_ops.Options() + options.experimental_map_and_filter_fusion = True + dataset = dataset.with_options(options) + iterator = dataset.make_one_shot_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for _ in range(10): + sess.run(next_element.op) + deltas = [] + for _ in range(100): + start = time.time() + for _ in range(100): + sess.run(next_element.op) + end = time.time() + deltas.append(end - start) + + median_wall_time = np.median(deltas) / 100 + opt_mark = "opt" if optimize_dataset else "noopt" + print("Map and filter dataset {} chain length: {} Median wall time: {}" + .format(opt_mark, chain_length, median_wall_time)) + self.report_benchmark( + iters=100, + wall_time=median_wall_time, + name="map_and_filter_fusion_{}_chain_length_{}".format( + opt_mark, chain_length)) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/BUILD b/tensorflow/python/data/experimental/kernel_tests/BUILD index ba5c6f7b17..6b22f9b8a8 100644 --- a/tensorflow/python/data/experimental/kernel_tests/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/BUILD @@ -72,15 +72,11 @@ py_test( "//tensorflow/python:errors", "//tensorflow/python:framework_test_lib", "//tensorflow/python:parsing_ops", - "//tensorflow/python:platform", - "//tensorflow/python:platform_test", - "//tensorflow/python:session", "//tensorflow/python/data/experimental/ops:error_ops", "//tensorflow/python/data/experimental/ops:readers", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:readers", "//tensorflow/python/eager:context", - "//third_party/py/numpy", ], ) diff --git a/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py deleted file mode 100644 index e896752a26..0000000000 --- a/tensorflow/python/data/experimental/kernel_tests/batch_dataset_op_test.py +++ /dev/null @@ -1,688 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. 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. -# ============================================================================== -"""Tests for the experimental input pipeline ops.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import math -import time - -from absl.testing import parameterized -import numpy as np - -from tensorflow.python.client import session -from tensorflow.python.data.experimental.ops import batching -from tensorflow.python.data.kernel_tests import test_base -from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.framework import constant_op -from tensorflow.python.framework import dtypes -from tensorflow.python.framework import errors -from tensorflow.python.framework import ops -from tensorflow.python.framework import sparse_tensor -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import math_ops -from tensorflow.python.ops import script_ops -from tensorflow.python.ops import string_ops -from tensorflow.python.platform import test -from tensorflow.python.util import compat - - -class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): - - def testDenseToSparseBatchDataset(self): - components = np.random.randint(12, size=(100,)).astype(np.int32) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components) - .map(lambda x: array_ops.fill([x], x)).apply( - batching.dense_to_sparse_batch(4, - [12])).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - - for start in range(0, len(components), 4): - results = sess.run(get_next) - self.assertAllEqual([[i, j] - for i, c in enumerate(components[start:start + 4]) - for j in range(c)], results.indices) - self.assertAllEqual( - [c for c in components[start:start + 4] for _ in range(c)], - results.values) - self.assertAllEqual([min(4, - len(components) - start), 12], - results.dense_shape) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testDenseToSparseBatchDatasetWithUnknownShape(self): - components = np.random.randint(5, size=(40,)).astype(np.int32) - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components).map( - lambda x: array_ops.fill([x, x], x)).apply( - batching.dense_to_sparse_batch( - 4, [5, None])).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - - for start in range(0, len(components), 4): - results = sess.run(get_next) - self.assertAllEqual([[i, j, z] - for i, c in enumerate(components[start:start + 4]) - for j in range(c) - for z in range(c)], results.indices) - self.assertAllEqual([ - c for c in components[start:start + 4] for _ in range(c) - for _ in range(c) - ], results.values) - self.assertAllEqual([ - min(4, - len(components) - start), 5, - np.max(components[start:start + 4]) - ], results.dense_shape) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testDenseToSparseBatchDatasetWithInvalidShape(self): - input_tensor = array_ops.constant([[1]]) - with self.assertRaisesRegexp(ValueError, "Dimension -2 must be >= 0"): - dataset_ops.Dataset.from_tensors(input_tensor).apply( - batching.dense_to_sparse_batch(4, - [-2])).make_initializable_iterator() - - def testDenseToSparseBatchDatasetShapeErrors(self): - input_tensor = array_ops.placeholder(dtypes.int32) - iterator = ( - dataset_ops.Dataset.from_tensors(input_tensor).apply( - batching.dense_to_sparse_batch(4, - [12])).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - # Initialize with an input tensor of incompatible rank. - sess.run(init_op, feed_dict={input_tensor: [[1]]}) - with self.assertRaisesRegexp(errors.InvalidArgumentError, - "incompatible with the row shape"): - sess.run(get_next) - - # Initialize with an input tensor that is larger than `row_shape`. - sess.run(init_op, feed_dict={input_tensor: range(13)}) - with self.assertRaisesRegexp(errors.DataLossError, - "larger than the row shape"): - sess.run(get_next) - - def testUnbatchWithUnknownRankInput(self): - placeholder = array_ops.placeholder(dtypes.int32) - dataset = dataset_ops.Dataset.from_tensors(placeholder).apply( - batching.unbatch()) - iterator = dataset.make_initializable_iterator() - next_elem = iterator.get_next() - - with self.cached_session() as sess: - sess.run(iterator.initializer, feed_dict={placeholder: [0, 1, 2, 3]}) - for i in range(4): - self.assertEqual(i, sess.run(next_elem)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_elem) - - def testUnbatchScalarDataset(self): - data = tuple([math_ops.range(10) for _ in range(3)]) - data = dataset_ops.Dataset.from_tensor_slices(data) - expected_types = (dtypes.int32,) * 3 - data = data.batch(2) - self.assertEqual(expected_types, data.output_types) - data = data.apply(batching.unbatch()) - self.assertEqual(expected_types, data.output_types) - - iterator = data.make_one_shot_iterator() - op = iterator.get_next() - - with self.cached_session() as sess: - for i in range(10): - self.assertEqual((i,) * 3, sess.run(op)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(op) - - def testUnbatchDatasetWithStrings(self): - data = tuple([math_ops.range(10) for _ in range(3)]) - data = dataset_ops.Dataset.from_tensor_slices(data) - data = data.map(lambda x, y, z: (x, string_ops.as_string(y), z)) - expected_types = (dtypes.int32, dtypes.string, dtypes.int32) - data = data.batch(2) - self.assertEqual(expected_types, data.output_types) - data = data.apply(batching.unbatch()) - self.assertEqual(expected_types, data.output_types) - - iterator = data.make_one_shot_iterator() - op = iterator.get_next() - - with self.cached_session() as sess: - for i in range(10): - self.assertEqual((i, compat.as_bytes(str(i)), i), sess.run(op)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(op) - - def testUnbatchDatasetWithSparseTensor(self): - st = sparse_tensor.SparseTensorValue( - indices=[[i, i] for i in range(10)], - values=list(range(10)), - dense_shape=[10, 10]) - data = dataset_ops.Dataset.from_tensors(st) - data = data.apply(batching.unbatch()) - data = data.batch(5) - data = data.apply(batching.unbatch()) - iterator = data.make_one_shot_iterator() - next_element = iterator.get_next() - - with self.cached_session() as sess: - for i in range(10): - st_row = sess.run(next_element) - self.assertEqual([i], st_row.indices) - self.assertEqual([i], st_row.values) - self.assertEqual([10], st_row.dense_shape) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - - def testUnbatchDatasetWithDenseAndSparseTensor(self): - st = sparse_tensor.SparseTensorValue( - indices=[[i, i] for i in range(10)], - values=list(range(10)), - dense_shape=[10, 10]) - data = dataset_ops.Dataset.from_tensors((list(range(10)), st)) - data = data.apply(batching.unbatch()) - data = data.batch(5) - data = data.apply(batching.unbatch()) - iterator = data.make_one_shot_iterator() - next_element = iterator.get_next() - - with self.cached_session() as sess: - for i in range(10): - dense_elem, st_row = sess.run(next_element) - self.assertEqual(i, dense_elem) - self.assertEqual([i], st_row.indices) - self.assertEqual([i], st_row.values) - self.assertEqual([10], st_row.dense_shape) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - - def testUnbatchSingleElementTupleDataset(self): - data = tuple([(math_ops.range(10),) for _ in range(3)]) - data = dataset_ops.Dataset.from_tensor_slices(data) - expected_types = ((dtypes.int32,),) * 3 - data = data.batch(2) - self.assertEqual(expected_types, data.output_types) - data = data.apply(batching.unbatch()) - self.assertEqual(expected_types, data.output_types) - - iterator = data.make_one_shot_iterator() - op = iterator.get_next() - - with self.cached_session() as sess: - for i in range(10): - self.assertEqual(((i,),) * 3, sess.run(op)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(op) - - def testUnbatchMultiElementTupleDataset(self): - data = tuple([(math_ops.range(10 * i, 10 * i + 10), - array_ops.fill([10], "hi")) for i in range(3)]) - data = dataset_ops.Dataset.from_tensor_slices(data) - expected_types = ((dtypes.int32, dtypes.string),) * 3 - data = data.batch(2) - self.assertAllEqual(expected_types, data.output_types) - data = data.apply(batching.unbatch()) - self.assertAllEqual(expected_types, data.output_types) - - iterator = data.make_one_shot_iterator() - op = iterator.get_next() - - with self.cached_session() as sess: - for i in range(10): - self.assertEqual(((i, b"hi"), (10 + i, b"hi"), (20 + i, b"hi")), - sess.run(op)) - - with self.assertRaises(errors.OutOfRangeError): - sess.run(op) - - def testUnbatchEmpty(self): - data = dataset_ops.Dataset.from_tensors( - (constant_op.constant([]), constant_op.constant([], shape=[0, 4]), - constant_op.constant([], shape=[0, 4, 0]))) - data = data.apply(batching.unbatch()) - iterator = data.make_one_shot_iterator() - next_element = iterator.get_next() - - with self.cached_session() as sess: - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - - def testUnbatchStaticShapeMismatch(self): - data = dataset_ops.Dataset.from_tensors((np.arange(7), np.arange(8), - np.arange(9))) - with self.assertRaises(ValueError): - data.apply(batching.unbatch()) - - def testUnbatchDynamicShapeMismatch(self): - ph1 = array_ops.placeholder(dtypes.int32, shape=[None]) - ph2 = array_ops.placeholder(dtypes.int32, shape=None) - data = dataset_ops.Dataset.from_tensors((ph1, ph2)) - data = data.apply(batching.unbatch()) - iterator = data.make_initializable_iterator() - next_element = iterator.get_next() - - with self.cached_session() as sess: - # Mismatch in the 0th dimension. - sess.run( - iterator.initializer, - feed_dict={ - ph1: np.arange(7).astype(np.int32), - ph2: np.arange(8).astype(np.int32) - }) - with self.assertRaises(errors.InvalidArgumentError): - sess.run(next_element) - - # No 0th dimension (i.e. scalar value) for one component. - sess.run( - iterator.initializer, - feed_dict={ - ph1: np.arange(7).astype(np.int32), - ph2: 7 - }) - with self.assertRaises(errors.InvalidArgumentError): - sess.run(next_element) - - @parameterized.named_parameters( - ("Default", None, None), - ("SequentialCalls", 1, None), - ("ParallelCalls", 2, None), - ("ParallelBatches", None, 10), - ) - def testMapAndBatch(self, num_parallel_calls, num_parallel_batches): - """Test a dataset that maps a TF function across its input elements.""" - # The pipeline is TensorSliceDataset -> - # RepeatDataset(count) -> MapAndBatchDataset(square_3, batch_size). - components = (np.arange(7), - np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], - np.array(37.0) * np.arange(7)) - - count = array_ops.placeholder(dtypes.int64, shape=[]) - batch_size = array_ops.placeholder(dtypes.int64, shape=[]) - - def _map_fn(x, y, z): - return math_ops.square(x), math_ops.square(y), math_ops.square(z) - - iterator = ( - dataset_ops.Dataset.from_tensor_slices(components).repeat(count).apply( - batching.map_and_batch( - map_func=_map_fn, - batch_size=batch_size, - num_parallel_calls=num_parallel_calls, - num_parallel_batches=num_parallel_batches)) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - - self.assertEqual([[None] + list(c.shape[1:]) for c in components], - [t.shape.as_list() for t in get_next]) - - with self.cached_session() as sess: - # Batch of a finite input, where the batch_size divides the - # total number of elements. - sess.run(init_op, feed_dict={count: 28, batch_size: 14}) - num_batches = (28 * 7) // 14 - for i in range(num_batches): - result = sess.run(get_next) - for component, result_component in zip(components, result): - for j in range(14): - self.assertAllEqual(component[(i * 14 + j) % 7]**2, - result_component[j]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Batch of a finite input, where the batch_size does not - # divide the total number of elements. - sess.run(init_op, feed_dict={count: 14, batch_size: 8}) - - # We expect (num_batches - 1) full-sized batches. - num_batches = int(math.ceil((14 * 7) / 8)) - for i in range(num_batches - 1): - result = sess.run(get_next) - for component, result_component in zip(components, result): - for j in range(8): - self.assertAllEqual(component[(i * 8 + j) % 7]**2, - result_component[j]) - result = sess.run(get_next) - for component, result_component in zip(components, result): - for j in range((14 * 7) % 8): - self.assertAllEqual(component[((num_batches - 1) * 8 + j) % 7]**2, - result_component[j]) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Batch of an empty input should fail straight away. - sess.run(init_op, feed_dict={count: 0, batch_size: 8}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Empty batch should be an initialization time error. - with self.assertRaises(errors.InvalidArgumentError): - sess.run(init_op, feed_dict={count: 14, batch_size: 0}) - - @parameterized.named_parameters( - ("Even", False), - ("Uneven", True), - ) - def testMapAndBatchPartialBatch(self, drop_remainder): - iterator = ( - dataset_ops.Dataset.range(10).apply( - batching.map_and_batch( - lambda x: array_ops.reshape(x * x, [1]), - batch_size=4, - drop_remainder=drop_remainder)).make_one_shot_iterator()) - if drop_remainder: - self.assertEqual([4, 1], iterator.output_shapes.as_list()) - else: - self.assertEqual([None, 1], iterator.output_shapes.as_list()) - next_element = iterator.get_next() - with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) - if not drop_remainder: - self.assertAllEqual([[64], [81]], sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - - def testMapAndBatchYieldsPartialBatch(self): - iterator = ( - dataset_ops.Dataset.range(10).apply( - batching.map_and_batch(lambda x: array_ops.reshape(x * x, [1]), - 4)).make_one_shot_iterator()) - self.assertEqual([None, 1], iterator.output_shapes.as_list()) - next_element = iterator.get_next() - with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) - self.assertAllEqual([[64], [81]], sess.run(next_element)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - - def testMapAndBatchParallelGetNext(self): - iterator = ( - dataset_ops.Dataset.range(50000).apply( - batching.map_and_batch(lambda x: x, - batch_size=100)).make_one_shot_iterator()) - elements = [] - for _ in range(100): - elements.append(iterator.get_next()) - with self.cached_session() as sess: - for i in range(5): - got = sess.run(elements) - got.sort(key=lambda x: x[0]) - expected = [] - for j in range(100): - expected.append(range(i * 10000 + j * 100, i * 10000 + (j + 1) * 100)) - self.assertAllEqual(got, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(elements) - - def testMapAndBatchParallelGetNextDropRemainder(self): - iterator = ( - dataset_ops.Dataset.range(49999).apply( - batching.map_and_batch( - lambda x: x, batch_size=100, - drop_remainder=True)).make_one_shot_iterator()) - elements = [] - for _ in range(100): - elements.append(iterator.get_next()) - with self.cached_session() as sess: - for i in range(4): - got = sess.run(elements) - got.sort(key=lambda x: x[0]) - expected = [] - for j in range(100): - expected.append(range(i * 10000 + j * 100, i * 10000 + (j + 1) * 100)) - self.assertAllEqual(got, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(elements) - - def testMapAndBatchSparse(self): - - def _sparse(i): - return sparse_tensor.SparseTensorValue( - indices=[[0]], values=(i * [1]), dense_shape=[1]) - - iterator = dataset_ops.Dataset.range(10).apply( - batching.map_and_batch(_sparse, 5)).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - - with self.cached_session() as sess: - sess.run(init_op) - for i in range(2): - actual = sess.run(get_next) - expected = sparse_tensor.SparseTensorValue( - indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], - values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], - dense_shape=[5, 1]) - self.assertTrue(sparse_tensor.is_sparse(actual)) - self.assertSparseValuesEqual(actual, expected) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testMapAndBatchFails(self): - """Test a dataset that maps a TF function across its input elements.""" - dataset = dataset_ops.Dataset.from_tensors( - array_ops.check_numerics( - constant_op.constant(1.0) / constant_op.constant(0.0), "oops")) - batch_size = array_ops.placeholder(dtypes.int64, shape=[]) - iterator = ( - dataset.apply(batching.map_and_batch( - lambda x: x, batch_size)).make_initializable_iterator()) - init_op = iterator.initializer - with self.cached_session() as sess: - with self.assertRaisesRegexp(errors.InvalidArgumentError, "oops"): - sess.run(init_op, feed_dict={batch_size: 14}) - - def testMapAndBatchShapeMismatch(self): - """Test a dataset that maps a TF function across its input elements.""" - - def generator(): - yield [1] - yield [2] - yield [3] - yield [[4, 5, 6]] - - dataset = dataset_ops.Dataset.from_generator( - generator, output_types=dtypes.int32) - batch_size = 4 - iterator = ( - dataset.apply(batching.map_and_batch( - lambda x: x, batch_size)).make_initializable_iterator()) - init_op = iterator.initializer - get_next = iterator.get_next() - with self.cached_session() as sess: - sess.run(init_op) - with self.assertRaisesRegexp(errors.InvalidArgumentError, - "number of elements does not match"): - sess.run(get_next) - - def testMapAndBatchImplicitDispose(self): - # Tests whether a map and batch dataset will be cleaned up correctly when - # the pipeline does not run it until exhaustion. - # The pipeline is TensorSliceDataset -> RepeatDataset(1000) -> - # MapAndBatchDataset(f=square_3, batch_size=100). - components = (np.arange(1000), - np.array([[1, 2, 3]]) * np.arange(1000)[:, np.newaxis], - np.array(37.0) * np.arange(1000)) - - def _map_fn(x, y, z): - return math_ops.square(x), math_ops.square(y), math_ops.square(z) - - dataset = dataset_ops.Dataset.from_tensor_slices(components).repeat( - 1000).apply(batching.map_and_batch(_map_fn, batch_size=100)) - dataset = dataset.prefetch(5) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - with self.cached_session() as sess: - for _ in range(3): - sess.run(get_next) - - @parameterized.named_parameters( - ("1", 0), - ("2", 5), - ("3", 10), - ("4", 90), - ("5", 95), - ("6", 99), - ) - def testMapAndBatchOutOfRangeError(self, threshold): - - def raising_py_fn(i): - if i >= threshold: - raise StopIteration() - else: - return i - - iterator = ( - dataset_ops.Dataset.range(100).apply( - batching.map_and_batch( - lambda x: script_ops.py_func(raising_py_fn, [x], dtypes.int64), - batch_size=10)).make_one_shot_iterator()) - get_next = iterator.get_next() - - with self.cached_session() as sess: - for i in range(threshold // 10): - self.assertAllEqual([i * 10 + j for j in range(10)], sess.run(get_next)) - if threshold % 10 != 0: - self.assertAllEqual( - [threshold // 10 * 10 + j for j in range(threshold % 10)], - sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - @parameterized.named_parameters( - ("1", False, dtypes.bool), - ("2", -42, dtypes.int8), - ("3", -42, dtypes.int16), - ("4", -42, dtypes.int32), - ("5", -42, dtypes.int64), - ("6", 42, dtypes.uint8), - ("7", 42, dtypes.uint16), - ("8", 42.0, dtypes.float16), - ("9", 42.0, dtypes.float32), - ("10", 42.0, dtypes.float64), - ("11", b"hello", dtypes.string), - ) - def testMapAndBatchTypes(self, element, dtype): - - def gen(): - yield element - - dataset = dataset_ops.Dataset.from_generator(gen, dtype).repeat(100).apply( - batching.map_and_batch(lambda x: x, batch_size=10)) - - get_next = dataset.make_one_shot_iterator().get_next() - - with self.cached_session() as sess: - for _ in range(10): - self.assertAllEqual([element for _ in range(10)], sess.run(get_next)) - - -class UnbatchDatasetBenchmark(test.Benchmark): - - def benchmarkNativeUnbatch(self): - batch_sizes = [1, 2, 5, 10, 20, 50] - elems_per_trial = 10000 - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors("element").repeat(None) - batch_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - dataset = dataset.batch(batch_size_placeholder) - dataset = dataset.apply(batching.unbatch()) - dataset = dataset.skip(elems_per_trial) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for batch_size in batch_sizes: - deltas = [] - for _ in range(5): - sess.run( - iterator.initializer, - feed_dict={batch_size_placeholder: batch_size}) - start = time.time() - sess.run(next_element.op) - end = time.time() - deltas.append((end - start) / elems_per_trial) - - median_wall_time = np.median(deltas) - print("Unbatch (native) batch size: %d Median wall time per element:" - " %f microseconds" % (batch_size, median_wall_time * 1e6)) - self.report_benchmark( - iters=10000, - wall_time=median_wall_time, - name="benchmark_unbatch_dataset_native_batch_size_%d" % - batch_size) - - # Include a benchmark of the previous `unbatch()` implementation that uses - # a composition of more primitive ops. Eventually we'd hope to generate code - # that is as good in both cases. - def benchmarkOldUnbatchImplementation(self): - batch_sizes = [1, 2, 5, 10, 20, 50] - elems_per_trial = 10000 - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors("element").repeat(None) - batch_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - dataset = dataset.batch(batch_size_placeholder) - dataset = dataset.flat_map(dataset_ops.Dataset.from_tensor_slices) - dataset = dataset.skip(elems_per_trial) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for batch_size in batch_sizes: - deltas = [] - for _ in range(5): - sess.run( - iterator.initializer, - feed_dict={batch_size_placeholder: batch_size}) - start = time.time() - sess.run(next_element.op) - end = time.time() - deltas.append((end - start) / elems_per_trial) - - median_wall_time = np.median(deltas) - print("Unbatch (unfused) batch size: %d Median wall time per element:" - " %f microseconds" % (batch_size, median_wall_time * 1e6)) - self.report_benchmark( - iters=10000, - wall_time=median_wall_time, - name="benchmark_unbatch_dataset_unfused_batch_size_%d" % - batch_size) - - -if __name__ == "__main__": - test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/csv_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/csv_dataset_test.py index fb75be1fbc..b2f1b43ecf 100644 --- a/tensorflow/python/data/experimental/kernel_tests/csv_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/csv_dataset_test.py @@ -20,14 +20,8 @@ from __future__ import print_function import gzip import os -import string -import tempfile -import time import zlib -import numpy as np - -from tensorflow.python.client import session from tensorflow.python.data.experimental.ops import error_ops from tensorflow.python.data.experimental.ops import readers from tensorflow.python.data.kernel_tests import test_base @@ -38,8 +32,6 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import test_util from tensorflow.python.ops import parsing_ops -from tensorflow.python.platform import gfile -from tensorflow.python.platform import googletest from tensorflow.python.platform import test @@ -537,96 +529,5 @@ class CsvDatasetTest(test_base.DatasetTestBase): record_defaults=record_defaults) -class CsvDatasetBenchmark(test.Benchmark): - """Benchmarks for the various ways of creating a dataset from CSV files. - """ - FLOAT_VAL = '1.23456E12' - STR_VAL = string.ascii_letters * 10 - - def _setUp(self, str_val): - # Since this isn't test.TestCase, have to manually create a test dir - gfile.MakeDirs(googletest.GetTempDir()) - self._temp_dir = tempfile.mkdtemp(dir=googletest.GetTempDir()) - - self._num_cols = [4, 64, 256] - self._num_per_iter = 5000 - self._filenames = [] - for n in self._num_cols: - fn = os.path.join(self._temp_dir, 'file%d.csv' % n) - with open(fn, 'wb') as f: - # Just write 100 rows and use `repeat`... Assumes the cost - # of creating an iterator is not significant - row = ','.join([str_val for _ in range(n)]) - f.write('\n'.join([row for _ in range(100)])) - self._filenames.append(fn) - - def _tearDown(self): - gfile.DeleteRecursively(self._temp_dir) - - def _runBenchmark(self, dataset, num_cols, prefix): - dataset = dataset.skip(self._num_per_iter - 1) - deltas = [] - for _ in range(10): - next_element = dataset.make_one_shot_iterator().get_next() - with session.Session() as sess: - start = time.time() - # NOTE: This depends on the underlying implementation of skip, to have - # the net effect of calling `GetNext` num_per_iter times on the - # input dataset. We do it this way (instead of a python for loop, or - # batching N inputs in one iter) so that the overhead from session.run - # or batch doesn't dominate. If we eventually optimize skip, this has - # to change. - sess.run(next_element) - end = time.time() - deltas.append(end - start) - # Median wall time per CSV record read and decoded - median_wall_time = np.median(deltas) / self._num_per_iter - print('%s num_cols: %d Median wall time: %f' % (prefix, num_cols, - median_wall_time)) - self.report_benchmark( - iters=self._num_per_iter, - wall_time=median_wall_time, - name='%s_with_cols_%d' % (prefix, num_cols)) - - def benchmarkMapWithFloats(self): - self._setUp(self.FLOAT_VAL) - for i in range(len(self._filenames)): - num_cols = self._num_cols[i] - kwargs = {'record_defaults': [[0.0]] * num_cols} - dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() - dataset = dataset.map(lambda l: parsing_ops.decode_csv(l, **kwargs)) # pylint: disable=cell-var-from-loop - self._runBenchmark(dataset, num_cols, 'csv_float_map_decode_csv') - self._tearDown() - - def benchmarkMapWithStrings(self): - self._setUp(self.STR_VAL) - for i in range(len(self._filenames)): - num_cols = self._num_cols[i] - kwargs = {'record_defaults': [['']] * num_cols} - dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() - dataset = dataset.map(lambda l: parsing_ops.decode_csv(l, **kwargs)) # pylint: disable=cell-var-from-loop - self._runBenchmark(dataset, num_cols, 'csv_strings_map_decode_csv') - self._tearDown() - - def benchmarkCsvDatasetWithFloats(self): - self._setUp(self.FLOAT_VAL) - for i in range(len(self._filenames)): - num_cols = self._num_cols[i] - kwargs = {'record_defaults': [[0.0]] * num_cols} - dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() - dataset = readers.CsvDataset(self._filenames[i], **kwargs).repeat() # pylint: disable=cell-var-from-loop - self._runBenchmark(dataset, num_cols, 'csv_float_fused_dataset') - self._tearDown() - - def benchmarkCsvDatasetWithStrings(self): - self._setUp(self.STR_VAL) - for i in range(len(self._filenames)): - num_cols = self._num_cols[i] - kwargs = {'record_defaults': [['']] * num_cols} - dataset = core_readers.TextLineDataset(self._filenames[i]).repeat() - dataset = readers.CsvDataset(self._filenames[i], **kwargs).repeat() # pylint: disable=cell-var-from-loop - self._runBenchmark(dataset, num_cols, 'csv_strings_fused_dataset') - self._tearDown() - if __name__ == '__main__': test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD b/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD index 1d0e6af649..121798ad3e 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/BUILD @@ -221,15 +221,14 @@ py_test( "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:framework_ops", + "//tensorflow/python:framework_test_lib", "//tensorflow/python:math_ops", - "//tensorflow/python:nn_ops", + "//tensorflow/python:nn", "//tensorflow/python:parsing_ops", - "//tensorflow/python:session", "//tensorflow/python:sparse_tensor", "//tensorflow/python/data/experimental/ops:optimization", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/util:nest", "//third_party/py/numpy", "@absl_py//absl/testing:parameterized", ], @@ -249,12 +248,9 @@ py_test( deps = [ "//tensorflow/python:client_testlib", "//tensorflow/python:errors", - "//tensorflow/python:math_ops", - "//tensorflow/python/data/experimental/ops:batching", "//tensorflow/python/data/experimental/ops:optimization", "//tensorflow/python/data/kernel_tests:test_base", "//tensorflow/python/data/ops:dataset_ops", - "//third_party/py/numpy", "@absl_py//absl/testing:parameterized", ], ) diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py index 18b3bc9424..4f05f02669 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/map_vectorization_test.py @@ -17,18 +17,14 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import time - from absl.testing import parameterized import numpy as np from tensorflow.core.example import example_pb2 from tensorflow.core.example import feature_pb2 -from tensorflow.python.client import session from tensorflow.python.data.experimental.ops import optimization from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.util import nest from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors @@ -439,102 +435,5 @@ class MapVectorizationTest(test_base.DatasetTestBase, parameterized.TestCase): ("IteratorGetNext", "IteratorGetNext_1", 1)]) -class MapVectorizationBenchmark(test.Benchmark): - # TODO(rachelim): Add a benchmark for more expensive transformations, such as - # vgg_preprocessing. - - def _run(self, x, num_iters=100, name=None): - deltas = [] - with session.Session() as sess: - for _ in range(5): - # Warm up session... - sess.run(x) - for _ in range(num_iters): - start = time.time() - sess.run(x) - end = time.time() - deltas.append(end - start) - median_time = np.median(deltas) - self.report_benchmark(iters=num_iters, wall_time=median_time, name=name) - return median_time - - def _compare(self, input_dataset, map_fn, batch_size, input_size, str_id): - num_elems = sum(np.prod(x) for x in input_size) - name_template = "{}__batch_size_{}_input_element_size_{}_{}" - unoptimized = input_dataset.map(map_fn).batch(batch_size) - unoptimized_op = unoptimized.make_one_shot_iterator().get_next() - - optimized = input_dataset.map(map_fn).batch(batch_size) - options = dataset_ops.Options() - options.experimental_map_vectorization = True - optimized = optimized.with_options(options) - optimized_op = optimized.make_one_shot_iterator().get_next() - - unoptimized_time = self._run( - unoptimized_op, - name=name_template.format(str_id, batch_size, num_elems, "unoptimized")) - optimized_time = self._run( - optimized_op, - name=name_template.format(str_id, batch_size, num_elems, "optimized")) - - print("Batch size: {}\n" - "Input element size: {}\n" - "Transformation: {}\n" - "Speedup: {}\n".format(batch_size, input_size, str_id, - (unoptimized_time / optimized_time))) - - # Known cheap functions - def benchmarkIdentity(self): - self._benchmark_helper(lambda *args: [array_ops.identity(x) for x in args], - "identity") - - def benchmarkAddConst(self): - self._benchmark_helper(lambda *args: [x + 1 for x in args], "add_const") - - def benchmarkReturnConst(self): - self._benchmark_helper(lambda *args: [constant_op.constant(2)], "ret_const") - - def benchmarkSelect(self): - self._benchmark_helper(lambda *args: args[0], "select") - - def benchmarkCast(self): - self._benchmark_helper( - lambda *args: [math_ops.cast(x, dtypes.float64) for x in args], "cast") - - def benchmarkReshape(self): - self._benchmark_helper( - lambda *args: [array_ops.reshape(x, (-1, 30)) for x in args], "reshape") - - def benchmarkDecodeCSV(self): - csv_fn, csv_factory = _generate_csv_test_case() - self._benchmark_helper(csv_fn, "decode_csv", lambda: [csv_factory()]) - - def benchmarkParseSingleExample(self): - # NOTE: Since we haven't implemented a vectorizer for "SerializeSparse", - # this function is only naively vectorized. - parse_fn, parse_factory = _generate_parse_single_example_test_case() - - self._benchmark_helper(parse_fn, "parse_single_example", - lambda: [parse_factory()]) - - def _default_dataset_factory(self): - input_sizes = [(10, 10, 3), (10, 100, 300)] - for sz in input_sizes: - yield dataset_ops.Dataset.from_tensor_slices(np.random.rand(*sz)) - - def _benchmark_helper(self, map_fn, str_id, base_dataset_factory=None): - if base_dataset_factory is None: - base_dataset_factory = self._default_dataset_factory - - batch_size = 1000 - for base_dataset in base_dataset_factory(): - base_dataset = base_dataset.repeat() - input_size = [ - tuple(shape.as_list()) - for shape in nest.flatten(base_dataset.output_shapes) - ] - self._compare(base_dataset, map_fn, batch_size, input_size, str_id) - - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py index f5a8399124..ea2737c3c7 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py @@ -17,182 +17,18 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import time - from absl.testing import parameterized -import numpy as np -from tensorflow.python.data.experimental.ops import batching from tensorflow.python.data.experimental.ops import optimization from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors -from tensorflow.python.ops import math_ops from tensorflow.python.platform import test # TODO(b/117581999): Add eager coverage for the following tests. class ModelDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): - def testModelMap(self): - k = 1024 * 1024 - dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), - np.random.rand(4 * k, - 1))).repeat() - dataset = dataset.map(math_ops.matmul) - dataset = dataset_ops._ModelDataset(dataset) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - deltas = [] - with self.cached_session() as sess: - for _ in range(5): - sess.run(get_next.op) - for _ in range(100): - start = time.time() - sess.run(get_next.op) - end = time.time() - deltas.append(end - start) - - print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % - (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), - np.max(deltas))) - - def testModelParallelMap(self): - k = 1024 * 1024 - dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), - np.random.rand(4 * k, - 1))).repeat() - dataset = dataset.map( - math_ops.matmul, num_parallel_calls=optimization.AUTOTUNE) - dataset = dataset_ops._ModelDataset(dataset) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - deltas = [] - with self.cached_session() as sess: - for _ in range(5): - sess.run(get_next.op) - for _ in range(100): - start = time.time() - sess.run(get_next.op) - end = time.time() - deltas.append(end - start) - - print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % - (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), - np.max(deltas))) - - @parameterized.named_parameters( - ("Default", False), - ("NUMA", True), - ) - def testModelMapAndBatch(self, numa_aware): - batch_size = 16 - k = 1024 * 1024 - dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), - np.random.rand(4 * k, - 1))).repeat() - dataset = dataset.apply( - batching.map_and_batch( - math_ops.matmul, - num_parallel_calls=optimization.AUTOTUNE, - batch_size=batch_size)) - dataset = dataset_ops._ModelDataset(dataset) - options = dataset_ops.Options() - options.experimental_numa_aware = numa_aware - dataset = dataset.with_options(options) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - deltas = [] - with self.cached_session() as sess: - for _ in range(5): - sess.run(get_next.op) - for _ in range(10): - start = time.time() - sess.run(get_next.op) - end = time.time() - deltas.append(end - start) - - print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % - (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), - np.max(deltas))) - - def testModelParallelInterleave(self): - k = 1024 * 1024 - dataset = dataset_ops.Dataset.from_tensors((np.random.rand(1, 4 * k), - np.random.rand(4 * k, - 1))).repeat() - dataset = dataset.map(math_ops.matmul) - dataset = dataset_ops.Dataset.range(1).repeat().interleave( - lambda _: dataset, - cycle_length=10, - num_parallel_calls=optimization.AUTOTUNE) - dataset = dataset_ops._ModelDataset(dataset) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - deltas = [] - with self.cached_session() as sess: - for _ in range(5): - sess.run(get_next.op) - for _ in range(100): - start = time.time() - sess.run(get_next.op) - end = time.time() - deltas.append(end - start) - - print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % - (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), - np.max(deltas))) - - def testModelNested(self): - k = 1024 * 1024 - a = (np.random.rand(1, 8 * k), np.random.rand(8 * k, 1)) - b = (np.random.rand(1, 4 * k), np.random.rand(4 * k, 1)) - c = (np.random.rand(1, 2 * k), np.random.rand(2 * k, 1)) - dataset = dataset_ops.Dataset.from_tensors((a, b, c)).repeat() - - def f1(a, b, c): - x, y = a - return math_ops.matmul(x, y), b, c - - def f2(a, b, c): - x, y = b - return a, math_ops.matmul(x, y), c - - def f3(a, b, c): - x, y = c - return a, b, math_ops.matmul(x, y) - - dataset = dataset.map(f1, num_parallel_calls=optimization.AUTOTUNE) - dataset = dataset_ops.Dataset.range(1).repeat().interleave( - lambda _: dataset, cycle_length=2) - - dataset = dataset.map(f2, num_parallel_calls=optimization.AUTOTUNE) - dataset = dataset_ops.Dataset.range(1).repeat().interleave( - lambda _: dataset, cycle_length=2) - - dataset = dataset.map(f3, num_parallel_calls=optimization.AUTOTUNE) - dataset = dataset_ops._ModelDataset(dataset) - iterator = dataset.make_one_shot_iterator() - get_next = iterator.get_next() - - deltas = [] - with self.cached_session() as sess: - for _ in range(5): - sess.run(get_next) - for _ in range(100): - start = time.time() - sess.run(get_next) - end = time.time() - deltas.append(end - start) - - print("%f (median), %f (mean), %f (stddev), %f (min), %f (max)\n" % - (np.median(deltas), np.mean(deltas), np.std(deltas), np.min(deltas), - np.max(deltas))) - def testAutotuneOption(self): dataset = dataset_ops.Dataset.from_tensors(0) dataset = dataset.map(lambda x: x).apply( diff --git a/tensorflow/python/data/kernel_tests/BUILD b/tensorflow/python/data/kernel_tests/BUILD index 0cdb44a3b4..0867471d74 100644 --- a/tensorflow/python/data/kernel_tests/BUILD +++ b/tensorflow/python/data/kernel_tests/BUILD @@ -10,35 +10,32 @@ load("//tensorflow:tensorflow.bzl", "tf_py_test") load("//tensorflow:tensorflow.bzl", "cuda_py_test") tf_py_test( - name = "batch_dataset_op_test", + name = "batch_test", size = "small", - srcs = ["batch_dataset_op_test.py"], + srcs = ["batch_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:math_ops", - "//tensorflow/python:session", "//tensorflow/python:sparse_tensor", - "//tensorflow/python:string_ops", - "//tensorflow/python:tensor_shape", - "//tensorflow/python:util", - "//tensorflow/python/data/ops:dataset_ops", ], ) tf_py_test( - name = "cache_dataset_op_test", + name = "cache_test", size = "small", - srcs = ["cache_dataset_op_test.py"], + srcs = ["cache_test.py"], additional_deps = [ ":test_base", "//third_party/py/numpy", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:iterator_ops", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:constant_op", @@ -46,15 +43,13 @@ tf_py_test( "//tensorflow/python:errors", "//tensorflow/python:framework_ops", "//tensorflow/python:variables", - "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/ops:iterator_ops", ], ) tf_py_test( - name = "concatenate_dataset_op_test", + name = "concatenate_test", size = "small", - srcs = ["concatenate_dataset_op_test.py"], + srcs = ["concatenate_test.py"], additional_deps = [ ":test_base", "//third_party/py/numpy", @@ -67,102 +62,94 @@ tf_py_test( ) tf_py_test( - name = "dataset_constructor_op_test", + name = "dataset_checkpoint_test", size = "small", - srcs = ["dataset_constructor_op_test.py"], + srcs = ["dataset_checkpoint_test.py"], additional_deps = [ ":test_base", - "//third_party/py/numpy", - "//tensorflow/core:protos_all_py", - "//tensorflow/python:array_ops", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:iterator_ops", "//tensorflow/python:client_testlib", + "//tensorflow/python:dataset_ops_gen", "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:framework_ops", - "//tensorflow/python:math_ops", - "//tensorflow/python:random_ops", - "//tensorflow/python:resource_variable_ops", - "//tensorflow/python:session", - "//tensorflow/python:sparse_tensor", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:io_ops", + "//tensorflow/python:parsing_ops", + "//tensorflow/python:platform", "//tensorflow/python:tensor_shape", - "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/util:nest", - "//tensorflow/python/data/util:sparse", - ], - tags = [ - "manual", - "nomac", # b/62040583 + "//tensorflow/python:variables", ], ) tf_py_test( - name = "dataset_from_generator_op_test", - size = "medium", - srcs = ["dataset_from_generator_op_test.py"], + name = "dataset_test", + size = "small", + srcs = ["dataset_test.py"], additional_deps = [ ":test_base", + "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", + "//tensorflow/core:protos_all_py", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python/data/util:nest", "//tensorflow/python:client_testlib", - "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", - "//tensorflow/python:errors", - "//tensorflow/python:script_ops", - "//tensorflow/python:session", - "//tensorflow/python:tensor_shape", - "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/util:sparse", + "//tensorflow/python:sparse_tensor", ], ) tf_py_test( - name = "dataset_ops_test", + name = "filter_test", size = "small", - srcs = ["dataset_ops_test.py"], + srcs = ["filter_test.py"], additional_deps = [ ":test_base", - "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", - "//tensorflow/core:protos_all_py", - "//tensorflow/python/data/ops:readers", - "//tensorflow/python/data/util:nest", + "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:functional_ops", + "//tensorflow/python:math_ops", "//tensorflow/python:sparse_tensor", - "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/ops:optional_ops", - "//tensorflow/python/data/util:structure", ], ) tf_py_test( - name = "filter_dataset_op_test", + name = "fixed_length_record_dataset_test", size = "small", - srcs = ["filter_dataset_op_test.py"], + srcs = ["fixed_length_record_dataset_test.py"], additional_deps = [ ":test_base", - "//third_party/py/numpy", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", + "//tensorflow/python:dataset_ops_gen", "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:framework_ops", - "//tensorflow/python:functional_ops", - "//tensorflow/python:math_ops", - "//tensorflow/python:session", - "//tensorflow/python:sparse_tensor", - "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python:io_ops", + "//tensorflow/python:parsing_ops", + "//tensorflow/python:tensor_shape", + "//tensorflow/python:util", + "//tensorflow/python/data/ops:iterator_ops", + "//tensorflow/python/data/ops:readers", ], ) tf_py_test( - name = "flat_map_dataset_op_test", + name = "flat_map_test", size = "medium", - srcs = ["flat_map_dataset_op_test.py"], + srcs = ["flat_map_test.py"], additional_deps = [ ":test_base", "//third_party/py/numpy", + "//tensorflow/core:protos_all_py", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python/data/util:nest", "//tensorflow/python:client_testlib", "//tensorflow/python:errors", "//tensorflow/python:session", @@ -175,65 +162,158 @@ tf_py_test( ) tf_py_test( - name = "list_files_dataset_op_test", + name = "from_generator_test", + size = "medium", + srcs = ["from_generator_test.py"], + additional_deps = [ + ":test_base", + "//third_party/py/numpy", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:script_ops", + "//tensorflow/python:session", + ], +) + +tf_py_test( + name = "from_sparse_tensor_slices_test", size = "small", - srcs = ["list_files_dataset_op_test.py"], + srcs = ["from_sparse_tensor_slices_test.py"], additional_deps = [ ":test_base", + "//third_party/py/numpy", + "//tensorflow/core:protos_all_py", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", "//tensorflow/python:errors", - "//tensorflow/python:util", + "//tensorflow/python:framework_ops", + "//tensorflow/python:math_ops", + "//tensorflow/python:resource_variable_ops", + "//tensorflow/python:session", + "//tensorflow/python:sparse_tensor", + "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/util:nest", ], ) tf_py_test( - name = "inputs_test", + name = "from_tensors_test", size = "small", - srcs = ["inputs_test.py"], + srcs = ["from_tensors_test.py"], additional_deps = [ ":test_base", - "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", - "//tensorflow/python/data/ops:readers", + "//tensorflow/core:protos_all_py", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:framework_ops", + "//tensorflow/python:math_ops", + "//tensorflow/python:resource_variable_ops", + "//tensorflow/python:session", + "//tensorflow/python:sparse_tensor", + "//tensorflow/python:tensor_shape", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/util:nest", + ], + tags = [ + "nomac", # b/62040583 + ], +) + +tf_py_test( + name = "from_tensor_slices_test", + size = "small", + srcs = ["from_tensor_slices_test.py"], + additional_deps = [ + ":test_base", + "//third_party/py/numpy", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", + "//tensorflow/python:errors", "//tensorflow/python:sparse_tensor", + "//tensorflow/python:tensor_shape", "//tensorflow/python/data/ops:dataset_ops", ], ) tf_py_test( - name = "interleave_dataset_op_test", + name = "interleave_test", size = "medium", - srcs = ["interleave_dataset_op_test.py"], + srcs = ["interleave_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/core:protos_all_py", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:script_ops", - "//tensorflow/python:session", "//tensorflow/python:sparse_ops", "//tensorflow/python:sparse_tensor", - "//tensorflow/python:training", + ], +) + +tf_py_test( + name = "iterator_checkpoint_test", + size = "medium", + srcs = ["iterator_checkpoint_test.py"], + additional_deps = [ + ":test_base", "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/eager:context", + "//tensorflow/python/training/checkpointable:util", + "//tensorflow/python:checkpoint_management", + "//tensorflow/python:client_testlib", + "//tensorflow/python:errors", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:math_ops", ], + grpc_enabled = True, ) -cuda_py_test( - name = "iterator_ops_test", +tf_py_test( + name = "iterator_cluster_test", size = "small", - srcs = ["iterator_ops_test.py"], + srcs = ["iterator_cluster_test.py"], + additional_deps = [ + "//tensorflow/core:protos_all_py", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:iterator_ops", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:framework_ops", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:function", + "//tensorflow/python:functional_ops", + "//tensorflow/python:lookup_ops", + "//tensorflow/python:math_ops", + "//tensorflow/python:session", + "//tensorflow/python:string_ops", + ], + grpc_enabled = True, + tags = [ + "no_oss", # Test flaky due to port collisions. + "no_windows", + ], +) + +cuda_py_test( + name = "iterator_test", + size = "medium", + srcs = ["iterator_test.py"], additional_deps = [ - ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/python/data/ops:readers", @@ -271,43 +351,30 @@ cuda_py_test( ) tf_py_test( - name = "iterator_ops_cluster_test", + name = "list_files_test", size = "small", - srcs = ["iterator_ops_cluster_test.py"], + srcs = ["list_files_test.py"], additional_deps = [ - "//tensorflow/core:protos_all_py", + ":test_base", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", "//tensorflow/python:errors", - "//tensorflow/python:framework_ops", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:function", - "//tensorflow/python:functional_ops", - "//tensorflow/python:math_ops", - "//tensorflow/python:session", + "//tensorflow/python:util", "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/ops:iterator_ops", - "//tensorflow/python:constant_op", - "//tensorflow/python:string_ops", - "//tensorflow/python:lookup_ops", - ], - grpc_enabled = True, - tags = [ - "no_oss", # Test flaky due to port collisions. - "no_windows", ], ) tf_py_test( - name = "map_dataset_op_test", + name = "map_test", size = "medium", - srcs = ["map_dataset_op_test.py"], + srcs = ["map_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", "//third_party/py/numpy", "//tensorflow/core:protos_all_py", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:constant_op", @@ -327,7 +394,6 @@ tf_py_test( "//tensorflow/python:string_ops", "//tensorflow/python:tensor_util", "//tensorflow/python:variable_scope", - "//tensorflow/python/data/ops:dataset_ops", ], ) @@ -355,9 +421,9 @@ cuda_py_test( ) cuda_py_test( - name = "optional_ops_test", + name = "optional_test", size = "small", - srcs = ["optional_ops_test.py"], + srcs = ["optional_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", @@ -376,73 +442,58 @@ cuda_py_test( ) tf_py_test( - name = "prefetch_dataset_op_test", + name = "padded_batch_test", size = "small", - srcs = ["prefetch_dataset_op_test.py"], + srcs = ["padded_batch_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", + "//third_party/py/numpy", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:dataset_ops_gen", + "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", "//tensorflow/python:errors", - "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python:sparse_tensor", + "//tensorflow/python:string_ops", + "//tensorflow/python:tensor_shape", + "//tensorflow/python:util", ], ) tf_py_test( - name = "range_dataset_op_test", + name = "prefetch_test", size = "small", - srcs = ["range_dataset_op_test.py"], + srcs = ["prefetch_test.py"], additional_deps = [ ":test_base", + "@absl_py//absl/testing:parameterized", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dataset_ops_gen", "//tensorflow/python:dtypes", "//tensorflow/python:errors", - "//tensorflow/python:framework_test_lib", - "//tensorflow/python:io_ops", - "//tensorflow/python:framework_ops", - "//tensorflow/python:parsing_ops", - "//tensorflow/python:platform", - "//tensorflow/python:tensor_shape", - "//tensorflow/python:variables", - "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/ops:iterator_ops", ], ) tf_py_test( - name = "reader_dataset_ops_test", - size = "medium", - srcs = ["reader_dataset_ops_test.py"], + name = "range_test", + size = "small", + srcs = ["range_test.py"], additional_deps = [ ":test_base", "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/eager:context", - "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:constant_op", - "//tensorflow/python:dataset_ops_gen", - "//tensorflow/python:dtypes", "//tensorflow/python:errors", - "//tensorflow/python:framework_ops", - "//tensorflow/python:io_ops", - "//tensorflow/python:lib", - "//tensorflow/python:parsing_ops", - "//tensorflow/python:tensor_shape", - "//tensorflow/python:util", - "//tensorflow/python/data/ops:iterator_ops", - "//tensorflow/python/data/ops:readers", + "//tensorflow/python:framework_test_lib", ], ) tf_py_test( - name = "reduce_dataset_op_test", + name = "reduce_test", size = "small", - srcs = ["reduce_dataset_op_test.py"], + srcs = ["reduce_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", @@ -450,7 +501,6 @@ tf_py_test( "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", - "//tensorflow/python:errors", "//tensorflow/python:math_ops", "//tensorflow/python:sparse_tensor", "//tensorflow/python/data/ops:dataset_ops", @@ -458,32 +508,56 @@ tf_py_test( ) tf_py_test( - name = "save_restore_experimental_test", + name = "repeat_test", size = "small", - srcs = ["save_restore_experimental_test.py"], + srcs = ["repeat_test.py"], additional_deps = [ - ":reader_dataset_ops_test", ":test_base", + "//third_party/py/numpy", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", "//tensorflow/python/data/ops:dataset_ops", - "//tensorflow/python/data/ops:iterator_ops", - "//tensorflow/python/data/ops:readers", + ], +) + +tf_py_test( + name = "shard_test", + size = "small", + srcs = ["shard_test.py"], + additional_deps = [ + ":test_base", "//tensorflow/python:client_testlib", - "//tensorflow/python:dataset_ops_gen", + "//tensorflow/python:errors", + "//tensorflow/python/data/ops:dataset_ops", + ], +) + +tf_py_test( + name = "shuffle_test", + size = "small", + srcs = ["shuffle_test.py"], + additional_deps = [ + ":test_base", + "@absl_py//absl/testing:parameterized", + "//third_party/py/numpy", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python:framework_ops", - "//tensorflow/python:io_ops", - "//tensorflow/python:parsing_ops", - "//tensorflow/python:platform", - "//tensorflow/python:tensor_shape", - "//tensorflow/python:variables", + "//tensorflow/python:random_seed", + "//tensorflow/python/data/ops:dataset_ops", + "//tensorflow/python/data/ops:iterator_ops", ], ) tf_py_test( - name = "sequence_dataset_op_test", + name = "skip_test", size = "small", - srcs = ["sequence_dataset_op_test.py"], + srcs = ["skip_test.py"], additional_deps = [ ":test_base", "//third_party/py/numpy", @@ -496,34 +570,53 @@ tf_py_test( ) tf_py_test( - name = "shard_dataset_op_test", + name = "take_test", size = "small", - srcs = ["shard_dataset_op_test.py"], + srcs = ["take_test.py"], additional_deps = [ ":test_base", + "//third_party/py/numpy", + "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", + "//tensorflow/python:dtypes", "//tensorflow/python:errors", "//tensorflow/python/data/ops:dataset_ops", ], ) tf_py_test( - name = "shuffle_dataset_op_test", + name = "text_line_dataset_test", size = "small", - srcs = ["shuffle_dataset_op_test.py"], + srcs = ["text_line_dataset_test.py"], additional_deps = [ ":test_base", - "@absl_py//absl/testing:parameterized", - "//third_party/py/numpy", + "//tensorflow/python/data/ops:iterator_ops", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python/eager:context", "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:constant_op", "//tensorflow/python:dtypes", "//tensorflow/python:errors", - "//tensorflow/python:framework_ops", - "//tensorflow/python:random_seed", + "//tensorflow/python:util", + ], +) + +tf_py_test( + name = "tf_record_dataset_test", + size = "small", + srcs = ["tf_record_dataset_test.py"], + additional_deps = [ + ":test_base", "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/data/ops:iterator_ops", + "//tensorflow/python/data/ops:readers", + "//tensorflow/python:array_ops", + "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:lib", + "//tensorflow/python:util", ], ) @@ -543,9 +636,9 @@ py_library( ) tf_py_test( - name = "window_dataset_op_test", + name = "window_test", size = "medium", - srcs = ["window_dataset_op_test.py"], + srcs = ["window_test.py"], additional_deps = [ ":test_base", "@absl_py//absl/testing:parameterized", @@ -561,9 +654,9 @@ tf_py_test( ) tf_py_test( - name = "zip_dataset_op_test", + name = "zip_test", size = "small", - srcs = ["zip_dataset_op_test.py"], + srcs = ["zip_test.py"], additional_deps = [ ":test_base", "//third_party/py/numpy", diff --git a/tensorflow/python/data/kernel_tests/batch_test.py b/tensorflow/python/data/kernel_tests/batch_test.py new file mode 100644 index 0000000000..5b035e5917 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/batch_test.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.Dataset.batch()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl.testing import parameterized +import numpy as np + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.util import nest +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors +from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class BatchTest(test_base.DatasetTestBase, parameterized.TestCase): + + @parameterized.named_parameters( + ('even', 28, 14, False), + ('uneven_with_remainder', 28, 15, False), + ('uneven_without_remainder', 28, 15, True), + ('empty', 0, 14, False), + ) + def testBatchDataset(self, count, batch_size, drop_remainder): + """Tests the batch dataset logic for various input configurations. + + Args: + count: the number of input elements + batch_size: the batch size + drop_remainder: whether a smaller batch size should be produced if batch + size does not divide number of inputs evenly + """ + + # The pipeline is TensorSliceDataset -> MapDataset(square_3) -> + # RepeatDataset(count) -> BatchDataset(batch_size). + components = (np.arange(7), + np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], + np.array(37.0) * np.arange(7)) + + def _map_fn(x, y, z): + return math_ops.square(x), math_ops.square(y), math_ops.square(z) + + dataset = dataset_ops.Dataset.from_tensor_slices(components).map( + _map_fn).repeat(count).batch(batch_size, drop_remainder) + get_next = self.getNext(dataset) + + if drop_remainder: + dim0 = batch_size + else: + dim0 = None + self.assertEqual( + [ts.as_list() for ts in nest.flatten(dataset.output_shapes)], + [[dim0] + list(c.shape[1:]) for c in components]) + + num_full_batches = (count * 7) // batch_size + for i in range(num_full_batches): + result = self.evaluate(get_next()) + for component, result_component in zip(components, result): + for j in range(batch_size): + self.assertAllEqual(component[(i * batch_size + j) % 7]**2, + result_component[j]) + if not drop_remainder and (count * 7) % batch_size > 0: + result = self.evaluate(get_next()) + for component, result_component in zip(components, result): + for j in range((count * 7) % batch_size): + self.assertAllEqual( + component[(num_full_batches * batch_size + j) % 7]**2, + result_component[j]) + with self.assertRaises(errors.OutOfRangeError): + result = self.evaluate(get_next()) + + def testBatchDatasetInvalidBatchSize(self): + dataset = (dataset_ops.Dataset.range(10).batch(0)) + self.assertDatasetProduces( + dataset, expected_error=(errors.InvalidArgumentError, '')) + + def testBatchSparse(self): + + def _sparse(i): + return sparse_tensor.SparseTensorValue( + indices=[[0]], values=(i * [1]), dense_shape=[1]) + + dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5) + expected_output = [ + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], + values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], + dense_shape=[5, 1]) for i in range(2) + ] + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testBatchSparseWithDifferentDenseShapes(self): + + def _sparse(i): + return sparse_tensor.SparseTensorValue( + indices=array_ops.expand_dims( + math_ops.range(i, dtype=dtypes.int64), 1), + values=array_ops.fill([math_ops.to_int32(i)], i), + dense_shape=[i]) + + dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5) + expected_output = [] + for i in range(2): + expected_indices = [] + expected_outputs = [] + for j in range(5): + for k in range(i * 5 + j): + expected_indices.append([j, k]) + expected_outputs.append(i * 5 + j) + expected_output.append( + sparse_tensor.SparseTensorValue( + indices=expected_indices, + values=expected_outputs, + dense_shape=[5, (i + 1) * 5 - 1])) + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testNestedBatchSparse(self): + + def _sparse(i): + return sparse_tensor.SparseTensorValue( + indices=[[0]], values=(i * [1]), dense_shape=[1]) + + dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5).batch(2) + expected_output = [ + sparse_tensor.SparseTensorValue( + indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], + [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0]], + values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + dense_shape=[2, 5, 1]) + ] + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testBatchShapeError(self): + + def generator(): + yield [1.0, 2.0, 3.0] + yield [4.0, 5.0, 6.0] + yield [7.0, 8.0, 9.0, 10.0] + + dataset = ( + dataset_ops.Dataset.from_generator( + generator, dtypes.float32, output_shapes=[None]).batch(3)) + self.assertDatasetProduces( + dataset, + expected_error=( + errors.InvalidArgumentError, + r'Cannot batch tensors with different shapes in component 0. First ' + r'element had shape \[3\] and element 2 had shape \[4\].')) + + +if __name__ == '__main__': + test.main() diff --git a/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py b/tensorflow/python/data/kernel_tests/cache_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/cache_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/cache_test.py index 06ce18a9b4..b561cd58ba 100644 --- a/tensorflow/python/data/kernel_tests/cache_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/cache_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.cache()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -35,7 +35,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class FileCacheDatasetTest(test_base.DatasetTestBase): +class FileCacheTest(test_base.DatasetTestBase): def setUp(self): self.tmp_dir = tempfile.mkdtemp() @@ -166,7 +166,7 @@ class FileCacheDatasetTest(test_base.DatasetTestBase): @test_util.run_all_in_graph_and_eager_modes -class MemoryCacheDatasetTest(test_base.DatasetTestBase): +class MemoryCacheTest(test_base.DatasetTestBase): def testCacheDatasetPassthrough(self): with ops.device("cpu:0"): diff --git a/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py b/tensorflow/python/data/kernel_tests/concatenate_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/concatenate_test.py index 3123e32d8e..5d8bfdc8f3 100644 --- a/tensorflow/python/data/kernel_tests/concatenate_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/concatenate_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.concatenate().""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -29,7 +29,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class ConcatenateDatasetTest(test_base.DatasetTestBase): +class ConcatenateTest(test_base.DatasetTestBase): def testConcatenateDataset(self): input_components = ( diff --git a/tensorflow/python/data/kernel_tests/save_restore_experimental_test.py b/tensorflow/python/data/kernel_tests/dataset_checkpoint_test.py similarity index 51% rename from tensorflow/python/data/kernel_tests/save_restore_experimental_test.py rename to tensorflow/python/data/kernel_tests/dataset_checkpoint_test.py index c07d24ef6e..cdaa4fd4d5 100644 --- a/tensorflow/python/data/kernel_tests/save_restore_experimental_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_checkpoint_test.py @@ -1,4 +1,4 @@ -# Copyright 2018 The TensorFlow Authors. All Rights Reserved. +# Copyright 2017 The TensorFlow Authors. 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. @@ -12,14 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental saving and restoring input pipeline.""" +"""Checkpoint tests for `tf.data.Dataset`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function import os -from tensorflow.python.data.kernel_tests import reader_dataset_ops_test from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import iterator_ops @@ -35,331 +34,7 @@ from tensorflow.python.platform import gfile from tensorflow.python.platform import test -class ExperimentalCheckpointFixedLengthRecordReaderTest( - reader_dataset_ops_test.FixedLengthRecordReaderTestBase): - - def tearDown(self): - # Remove all checkpoint files. - prefix = self._iterator_checkpoint_prefix() - pattern = prefix + "*" - files = gfile.Glob(pattern) - map(gfile.Remove, files) - - def _iterator_checkpoint_prefix(self): - return os.path.join(self.get_temp_dir(), "iterator") - - def _save_op(self, iterator_resource): - iterator_state_variant = gen_dataset_ops.serialize_iterator( - iterator_resource) - save_op = io_ops.write_file( - self._iterator_checkpoint_prefix(), - parsing_ops.serialize_tensor(iterator_state_variant)) - return save_op - - def _restore_op(self, iterator_resource): - iterator_state_variant = parsing_ops.parse_tensor( - io_ops.read_file(self._iterator_checkpoint_prefix()), dtypes.variant) - restore_op = gen_dataset_ops.deserialize_iterator(iterator_resource, - iterator_state_variant) - return restore_op - - def testSaveRestore(self): - - def _build_graph(start, stop): - iterator = dataset_ops.Dataset.range(start, - stop).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - break_point = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(init_op) - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Saving and restoring in same session. - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testRestoreWithoutBuildingDatasetGraph(self): - - def _build_graph(start, stop, num_epochs): - dataset = dataset_ops.Dataset.range(start, stop).repeat(num_epochs) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - num_epochs = 5 - break_point = 5 - break_epoch = 3 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for _ in range(break_epoch): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - # Create an empty IteratorResource and restore the Iterator into it. - output_types = dtypes.int64 - output_shapes = tensor_shape.scalar() - iterator = iterator_ops.Iterator.from_structure(output_types, - output_shapes) - restore_op = self._restore_op(iterator._iterator_resource) - get_next = iterator.get_next() - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - for _ in range(break_epoch + 1, num_epochs): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testRestoreInModifiedGraph(self): - - def _build_graph(start, stop): - dataset = dataset_ops.Dataset.range(start, stop) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - stop_1 = 8 - break_point = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - # Intentionally build a graph with a different value for stop to make sure - # the original dataset graph is actually getting loaded. - init_op, get_next, _, restore_op = _build_graph(start, stop_1) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testInitThenRestore(self): - # Note: Calling init_op before restore_op is redundant. This test just makes - # sure we do not fail if restore is called on an already initialized - # iterator resource. - - def _build_graph(start, stop): - dataset = dataset_ops.Dataset.range(start, stop) - iterator = dataset.make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - # Saving and restoring in different sessions. - start = 2 - stop = 10 - break_point = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(init_op) - sess.run(restore_op) - for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testMultipleSaves(self): - - def _build_graph(start, stop): - iterator = dataset_ops.Dataset.range(start, - stop).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - start = 2 - stop = 10 - break_point1 = 5 - break_point2 = 7 - - with ops.Graph().as_default() as g: - init_op, get_next, save_op, _ = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - for i in range(start, break_point1): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point1, break_point2): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - break_point2 = 7 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph(start, stop) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_point2, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testSaveRestoreWithRepeat(self): - - def _build_graph(start, stop, num_epochs): - iterator = dataset_ops.Dataset.range( - start, stop).repeat(num_epochs).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - start = 2 - stop = 10 - num_epochs = 5 - break_range = 5 - break_epoch = 3 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph( - start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for _ in range(break_epoch - 1): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - for i in range(start, break_range): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - for i in range(break_range, stop): - self.assertEqual(i, sess.run(get_next)) - for _ in range(break_epoch, num_epochs): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - def testSaveRestoreExhaustedIterator(self): - - def _build_graph(start, stop, num_epochs): - iterator = dataset_ops.Dataset.range( - start, stop).repeat(num_epochs).make_initializable_iterator() - init_op = iterator.initializer - get_next = iterator.get_next() - save_op = self._save_op(iterator._iterator_resource) - restore_op = self._restore_op(iterator._iterator_resource) - return init_op, get_next, save_op, restore_op - - start = 2 - stop = 10 - num_epochs = 5 - with ops.Graph().as_default() as g: - init_op, get_next, save_op, restore_op = _build_graph( - start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) - # Note: There is no checkpoint saved currently so a NotFoundError is - # raised. - with self.assertRaises(errors.NotFoundError): - sess.run(restore_op) - for _ in range(num_epochs): - for i in range(start, stop): - self.assertEqual(i, sess.run(get_next)) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - sess.run(save_op) - - with ops.Graph().as_default() as g: - init_op, get_next, _, restore_op = _build_graph(start, stop, num_epochs) - with self.session(graph=g) as sess: - sess.run(restore_op) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - -class ExperimentalCheckpointRangeTest(test_base.DatasetTestBase): +class DatasetCheckpointTest(test_base.DatasetTestBase): def tearDown(self): # Remove all checkpoint files. diff --git a/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py b/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py deleted file mode 100644 index 4a7a946576..0000000000 --- a/tensorflow/python/data/kernel_tests/dataset_constructor_op_test.py +++ /dev/null @@ -1,606 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. 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. -# ============================================================================== -"""Tests for the experimental input pipeline ops.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import time - -import numpy as np - -from tensorflow.core.protobuf import config_pb2 -from tensorflow.python.client import session -from tensorflow.python.data.kernel_tests import test_base -from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.util import nest -from tensorflow.python.framework import dtypes -from tensorflow.python.framework import errors -from tensorflow.python.framework import ops -from tensorflow.python.framework import sparse_tensor -from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import test_util -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import math_ops -from tensorflow.python.ops import resource_variable_ops -from tensorflow.python.platform import test - - -@test_util.run_all_in_graph_and_eager_modes -class DatasetConstructorTest(test_base.DatasetTestBase): - - def testFromTensors(self): - """Test a dataset that represents a single tuple of tensors.""" - components = (np.array(1), np.array([1, 2, 3]), np.array(37.0)) - - dataset = dataset_ops.Dataset.from_tensors(components) - - self.assertEqual([c.shape for c in components], - nest.flatten(dataset.output_shapes)) - - self.assertDatasetProduces(dataset, expected_output=[components]) - - def testFromTensorsSparse(self): - """Test a dataset that represents a single tuple of tensors.""" - components = (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0, 0], [1, 1]]), - values=np.array([-1, 1]), - dense_shape=np.array([2, 2]))) - - dataset = dataset_ops.Dataset.from_tensors(components) - - self.assertEqual( - [tensor_shape.TensorShape(c.dense_shape) for c in components], - [shape for shape in dataset.output_shapes]) - self.assertDatasetProduces(dataset, expected_output=[components]) - - def testFromTensorsMixed(self): - """Test an dataset that represents a single tuple of tensors.""" - components = (np.array(1), np.array([1, 2, 3]), np.array(37.0), - sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0, 0], [1, 1]]), - values=np.array([-1, 1]), - dense_shape=np.array([2, 2]))) - - dataset = dataset_ops.Dataset.from_tensors(components) - self.assertEqual([ - tensor_shape.TensorShape(c.dense_shape) - if sparse_tensor.is_sparse(c) else c.shape for c in components - ], [shape for shape in dataset.output_shapes]) - - self.assertDatasetProduces(dataset, expected_output=[components]) - - def testFromTensorSlices(self): - """Test a dataset that represents the slices from a tuple of tensors.""" - components = ( - np.tile(np.array([[1], [2], [3], [4]]), 20), np.tile( - np.array([[12], [13], [14], [15]]), 22), - np.array([37.0, 38.0, 39.0, 40.0]) - ) - - dataset = dataset_ops.Dataset.from_tensor_slices(components) - get_next = self.getNext(dataset) - - self.assertEqual([c.shape[1:] for c in components], - [shape for shape in dataset.output_shapes]) - - for i in range(4): - results = self.evaluate(get_next()) - for component, result_component in zip(components, results): - self.assertAllEqual(component[i], result_component) - with self.assertRaises(errors.OutOfRangeError): - results = self.evaluate(get_next()) - - def testFromTensorSlicesSparse(self): - """Test a dataset that represents the slices from a tuple of tensors.""" - components = (sparse_tensor.SparseTensorValue( - indices=np.array([[0, 0], [1, 0], [2, 0]]), - values=np.array([0, 0, 0]), - dense_shape=np.array([3, 1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0, 0], [1, 1], [2, 2]]), - values=np.array([1, 2, 3]), - dense_shape=np.array([3, 3]))) - - dataset = dataset_ops.Dataset.from_tensor_slices(components) - - self.assertEqual( - [tensor_shape.TensorShape(c.dense_shape[1:]) for c in components], - [shape for shape in dataset.output_shapes]) - - expected = [ - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([1]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[1]]), - values=np.array([2]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[2]]), - values=np.array([3]), - dense_shape=np.array([3]))), - ] - self.assertDatasetProduces(dataset, expected_output=expected) - - def testFromTensorSlicesMixed(self): - """Test a dataset that represents the slices from a tuple of tensors.""" - components = (np.tile(np.array([[1], [2], [3]]), 20), - np.tile(np.array([[12], [13], [14]]), 22), - np.array([37.0, 38.0, 39.0]), - sparse_tensor.SparseTensorValue( - indices=np.array([[0, 0], [1, 0], [2, 0]]), - values=np.array([0, 0, 0]), - dense_shape=np.array([3, 1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0, 0], [1, 1], [2, 2]]), - values=np.array([1, 2, 3]), - dense_shape=np.array([3, 3]))) - - dataset = dataset_ops.Dataset.from_tensor_slices(components) - get_next = self.getNext(dataset) - self.assertEqual([ - tensor_shape.TensorShape(c.dense_shape[1:]) - if sparse_tensor.is_sparse(c) else c.shape[1:] for c in components - ], [shape for shape in dataset.output_shapes]) - - expected = [ - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([1]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[1]]), - values=np.array([2]), - dense_shape=np.array([3]))), - (sparse_tensor.SparseTensorValue( - indices=np.array([[0]]), - values=np.array([0]), - dense_shape=np.array([1])), - sparse_tensor.SparseTensorValue( - indices=np.array([[2]]), - values=np.array([3]), - dense_shape=np.array([3]))), - ] - for i in range(3): - results = self.evaluate(get_next()) - for component, result_component in zip( - (list(zip(*components[:3]))[i] + expected[i]), results): - if sparse_tensor.is_sparse(component): - self.assertSparseValuesEqual(component, result_component) - else: - self.assertAllEqual(component, result_component) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) - - def testFromTensorSlicesWithDict(self): - components = {"foo": [1, 2, 3], "bar": [[4.0], [5.0], [6.0]]} - dataset = dataset_ops.Dataset.from_tensor_slices(components) - get_next = self.getNext(dataset) - - self.assertEqual(dtypes.int32, dataset.output_types["foo"]) - self.assertEqual(dtypes.float32, dataset.output_types["bar"]) - self.assertEqual((), dataset.output_shapes["foo"]) - self.assertEqual((1,), dataset.output_shapes["bar"]) - - for i in range(3): - results = self.evaluate(get_next()) - self.assertEqual(components["foo"][i], results["foo"]) - self.assertEqual(components["bar"][i], results["bar"]) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) - - def testSkipEagerFromSparseTensorSlices(self): - """Test a dataset based on slices of a `tf.SparseTensor`.""" - st = array_ops.sparse_placeholder(dtypes.float64) - iterator = (dataset_ops.Dataset.from_sparse_tensor_slices(st) - .make_initializable_iterator()) - init_op = iterator.initializer - get_next = sparse_tensor.SparseTensor(*iterator.get_next()) - - with self.cached_session() as sess: - slices = [[1., 2., 3.], [1.], [1.], [1., 2.], [], [1., 2.], [], [], []] - - # Test with sparse tensor in the appropriate order. - indices = np.array( - [[i, j] for i in range(len(slices)) for j in range(len(slices[i]))]) - values = np.array([val for s in slices for val in s]) - dense_shape = np.array([len(slices), max(len(s) for s in slices) + 1]) - sparse_feed = sparse_tensor.SparseTensorValue(indices, values, - dense_shape) - sess.run(init_op, feed_dict={st: sparse_feed}) - for i, s in enumerate(slices): - results = sess.run(get_next) - self.assertAllEqual(s, results.values) - expected_indices = np.array( - [[j] for j in range(len(slices[i]))]).reshape([-1, 1]) - self.assertAllEqual(expected_indices, results.indices) - self.assertAllEqual(dense_shape[1:], results.dense_shape) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # Test with sparse tensor in the reverse order, which is not - # currently supported. - reverse_order_indices = indices[::-1, :] - reverse_order_values = values[::-1] - sparse_feed = sparse_tensor.SparseTensorValue( - reverse_order_indices, reverse_order_values, dense_shape) - with self.assertRaises(errors.UnimplementedError): - sess.run(init_op, feed_dict={st: sparse_feed}) - - # Test with an empty sparse tensor. - empty_indices = np.empty((0, 4), dtype=np.int64) - empty_values = np.empty((0,), dtype=np.float64) - empty_dense_shape = [0, 4, 37, 9] - sparse_feed = sparse_tensor.SparseTensorValue(empty_indices, empty_values, - empty_dense_shape) - sess.run(init_op, feed_dict={st: sparse_feed}) - with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) - - # pylint: disable=g-long-lambda,unnecessary-lambda - def testNestedStructure(self): - components = (np.array([1, 2, 3], dtype=np.int64), - (np.array([4., 5.]), np.array([6., 7.])), - np.array([8, 9, 10], dtype=np.int64)) - - dataset = dataset_ops.Dataset.from_tensors(components) - self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), - dtypes.int64), dataset.output_types) - self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) - - dataset = dataset.shuffle(10, 10) - self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), - dtypes.int64), dataset.output_types) - self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) - - dataset = dataset.repeat(-1) - self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), - dtypes.int64), dataset.output_types) - self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) - - dataset = dataset.filter(lambda x, y, z: True) - self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), - dtypes.int64), dataset.output_types) - self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) - - dataset = dataset.take(5) - self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), - dtypes.int64), dataset.output_types) - self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) - - dataset = dataset.map(lambda x, y, z: ((x, z), (y[0], y[1]))) - self.assertEquals(((dtypes.int64, dtypes.int64), - (dtypes.float64, dtypes.float64)), dataset.output_types) - self.assertEquals((([3], [3]), ([2], [2])), dataset.output_shapes) - - dataset = dataset.flat_map( - lambda x, y: dataset_ops.Dataset.from_tensors(((x[0], x[1]), - (y[0], y[1]))) - ) - self.assertEquals(((dtypes.int64, dtypes.int64), - (dtypes.float64, dtypes.float64)), dataset.output_types) - self.assertEquals((([3], [3]), ([2], [2])), dataset.output_shapes) - - dataset = dataset.batch(32) - self.assertEquals(((dtypes.int64, dtypes.int64), - (dtypes.float64, dtypes.float64)), dataset.output_types) - self.assertEquals((([None, 3], [None, 3]), ([None, 2], [None, 2])), - nest.pack_sequence_as(dataset.output_shapes, [ - s.as_list() - for s in nest.flatten(dataset.output_shapes) - ])) - - # Define a separate set of components with matching leading - # dimension for the from-slices constructor. - components_for_slices = (np.array([1, 2, 3], dtype=np.int64), - (np.array([4., 5., 6.]), np.array([7., 8., 9.])), - np.array([10, 11, 12], dtype=np.int64)) - - dataset = dataset_ops.Dataset.from_tensor_slices(components_for_slices) - self.assertEquals((dtypes.int64, - (dtypes.float64, dtypes.float64), dtypes.int64), - dataset.output_types) - self.assertEquals(([], ([], []), []), dataset.output_shapes) - - # TODO(b/117581999): more specific shapes in eager mode. - def testSkipEagerNestedStructure(self): - components = (np.array([1, 2, 3], dtype=np.int64), (np.array([4., 5.]), - np.array([6., 7.])), - np.array([8, 9, 10], dtype=np.int64)) - - dataset = dataset_ops.Dataset.from_tensors(components) - dataset = dataset.map(lambda x, y, z: ((x, z), (y[0], y[1]))) - - dataset = dataset.flat_map( - lambda x, y: dataset_ops.Dataset.from_tensors( - ((x[0], x[1]), (y[0], y[1])))).batch(32) - - get_next = self.getNext(dataset) - (w, x), (y, z) = get_next() - self.assertEquals(dtypes.int64, w.dtype) - self.assertEquals(dtypes.int64, x.dtype) - self.assertEquals(dtypes.float64, y.dtype) - self.assertEquals(dtypes.float64, z.dtype) - self.assertEquals([None, 3], w.shape.as_list()) - self.assertEquals([None, 3], x.shape.as_list()) - self.assertEquals([None, 2], y.shape.as_list()) - self.assertEquals([None, 2], z.shape.as_list()) - - get_next = self.getNext(dataset) - (w, x), (y, z) = get_next() - self.assertEquals(dtypes.int64, w.dtype) - self.assertEquals(dtypes.int64, x.dtype) - self.assertEquals(dtypes.float64, y.dtype) - self.assertEquals(dtypes.float64, z.dtype) - self.assertEquals([None, 3], w.shape.as_list()) - self.assertEquals([None, 3], x.shape.as_list()) - self.assertEquals([None, 2], y.shape.as_list()) - self.assertEquals([None, 2], z.shape.as_list()) - - def testNestedDict(self): - components = {"a": {"aa": 1, "ab": [2.0, 2.0]}, "b": [3, 3, 3]} - dataset = dataset_ops.Dataset.from_tensors(components) - self.assertEquals(dtypes.int32, dataset.output_types["a"]["aa"]) - self.assertEquals(dtypes.float32, dataset.output_types["a"]["ab"]) - self.assertEquals(dtypes.int32, dataset.output_types["b"]) - self.assertEquals([], dataset.output_shapes["a"]["aa"]) - self.assertEquals([2], dataset.output_shapes["a"]["ab"]) - self.assertEquals([3], dataset.output_shapes["b"]) - - def testNonSequenceNestedStructure(self): - components = np.array([1, 2, 3], dtype=np.int64) - - dataset = dataset_ops.Dataset.from_tensors(components) - self.assertEquals(dtypes.int64, dataset.output_types) - self.assertEquals([3], dataset.output_shapes) - - dataset = dataset.filter( - lambda x: math_ops.reduce_all(math_ops.equal(x, components))) - self.assertEquals(dtypes.int64, dataset.output_types) - self.assertEquals([3], dataset.output_shapes) - - dataset = dataset.map(lambda x: array_ops.stack([x, x])) - self.assertEquals(dtypes.int64, dataset.output_types) - self.assertEquals([2, 3], dataset.output_shapes) - - dataset = dataset.flat_map( - lambda x: dataset_ops.Dataset.from_tensor_slices(x)) - self.assertEquals(dtypes.int64, dataset.output_types) - self.assertEquals([3], dataset.output_shapes) - - get_next = self.getNext(dataset) - self.assertEquals(dtypes.int64, get_next().dtype) - self.assertEquals([3], get_next().shape) - - def testSkipEagerSplitPipelineFailsWithPlacementError(self): - with session.Session( - target="", - config=config_pb2.ConfigProto(device_count={"CPU": 2})) as sess: - - dataset = dataset_ops.Dataset.from_tensors(0) - - # Define a pipeline that attempts to use variables on two - # different devices. - # - # Initialize the variables before creating to iterator, to avoid the - # placement algorithm overriding the DT_RESOURCE colocation constraints. - with ops.device("/cpu:0"): - var_0 = resource_variable_ops.ResourceVariable(initial_value=0) - dataset = dataset.map(lambda x: x + var_0.read_value()) - sess.run(var_0.initializer) - - with ops.device("/cpu:1"): - var_1 = resource_variable_ops.ResourceVariable(initial_value=0) - dataset = dataset.map(lambda x: x + var_1.read_value()) - sess.run(var_1.initializer) - - iterator = dataset.make_initializable_iterator() - sess.run(iterator.initializer) - - with self.assertRaisesRegexp( - errors.FailedPreconditionError, - "Error while reading resource variable Variable"): - sess.run(iterator.get_next()) - - -# TODO(b/119837791): Add eager benchmarks as well. -class DatasetConstructorBenchmark(test.Benchmark): - - def benchmarkSliceRepeatBatch(self): - input_size = 10000 - batch_size = 100 - num_epochs = 100 - - input_data = np.random.randn(input_size) - - dataset = ( - dataset_ops.Dataset.from_tensor_slices(input_data) - .repeat(num_epochs + 1).batch(batch_size)) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - sess.run(iterator.initializer) - # Run one whole epoch to burn in the computation. - for _ in range(input_size // batch_size): - sess.run(next_element) - deltas = [] - try: - while True: - start = time.time() - sess.run(next_element) - deltas.append(time.time() - start) - except errors.OutOfRangeError: - pass - - median_wall_time = np.median(deltas) - print("Slice/repeat/batch with sess.run() input size: %d batch size: %d " - "Median wall time per element: %f" % (input_size, batch_size, - median_wall_time)) - self.report_benchmark( - iters=len(deltas), - wall_time=median_wall_time, - name="benchmark_slice_repeat_batch_input_%d_batch_%d" % (input_size, - batch_size)) - - def benchmarkSliceRepeatBatchCallable(self): - input_size = 10000 - batch_size = 100 - num_epochs = 100 - - input_data = np.random.randn(input_size) - - dataset = ( - dataset_ops.Dataset.from_tensor_slices(input_data) - .repeat(num_epochs + 1).batch(batch_size)) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - sess.run(iterator.initializer) - get_next_element = sess.make_callable(next_element) - # Run one whole epoch to burn in the computation. - for _ in range(input_size // batch_size): - get_next_element() - deltas = [] - try: - while True: - start = time.time() - get_next_element() - deltas.append(time.time() - start) - except errors.OutOfRangeError: - pass - - median_wall_time = np.median(deltas) - print( - "Slice/repeat/batch with callable input size: %d batch size: %d Median" - " wall time per element: %f" % (input_size, batch_size, - median_wall_time)) - self.report_benchmark( - iters=len(deltas), - wall_time=median_wall_time, - name="benchmark_slice_repeat_batch_callable_input_%d_batch_%d" % - (input_size, batch_size)) - - def benchmarkReshapeSliceRepeatCallable(self): - input_size = 10000 - batch_size = 100 - num_epochs = 100 - - input_data = np.random.randn(input_size) - - dataset = ( - dataset_ops.Dataset.from_tensor_slices(input_data.reshape(100, 100)) - .repeat(num_epochs + 1)) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - sess.run(iterator.initializer) - get_next_element = sess.make_callable(next_element) - # Run one whole epoch to burn in the computation. - for _ in range(input_size // batch_size): - get_next_element() - deltas = [] - try: - while True: - start = time.time() - get_next_element() - deltas.append(time.time() - start) - except errors.OutOfRangeError: - pass - - median_wall_time = np.median(deltas) - print("Reshape/slice/repeat with callable input size: %d batch size: %d " - "Median wall time per element: %f" % (input_size, batch_size, - median_wall_time)) - self.report_benchmark( - iters=len(deltas), - wall_time=median_wall_time, - name="benchmark_reshape_slice_repeat_callable_input_%d_batch_%d" % - (input_size, batch_size)) - - def benchmarkSliceBatchCacheRepeatCallable(self): - input_size = 10000 - batch_size = 100 - num_epochs = 100 - - input_data = np.random.randn(input_size) - - dataset = ( - dataset_ops.Dataset.from_tensor_slices(input_data).batch(batch_size) - .cache().repeat(num_epochs + 1)) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - sess.run(iterator.initializer) - get_next_element = sess.make_callable(next_element) - # Run one whole epoch to burn in the computation. - for _ in range(input_size // batch_size): - get_next_element() - deltas = [] - try: - while True: - start = time.time() - get_next_element() - deltas.append(time.time() - start) - except errors.OutOfRangeError: - pass - - median_wall_time = np.median(deltas) - print( - "Slice/batch/cache/repeat with callable input size: %d batch size: %d " - "Median wall time per element: %f" - % (input_size, batch_size, median_wall_time)) - self.report_benchmark( - iters=len(deltas), - wall_time=median_wall_time, - name="benchmark_slice_batch_cache_repeat_callable_input_%d_batch_%d" % - (input_size, batch_size)) - - -if __name__ == "__main__": - test.main() diff --git a/tensorflow/python/data/kernel_tests/dataset_ops_test.py b/tensorflow/python/data/kernel_tests/dataset_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/dataset_ops_test.py rename to tensorflow/python/data/kernel_tests/dataset_test.py index 373cdc0a77..7dbab60f9c 100644 --- a/tensorflow/python/data/kernel_tests/dataset_ops_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the input pipeline ops.""" +"""Tests for `tf.data.Dataset`.""" from __future__ import absolute_import from __future__ import division @@ -37,7 +37,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): +class DatasetTest(test_base.DatasetTestBase, parameterized.TestCase): def testAsSerializedGraph(self): dataset = dataset_ops.Dataset.range(10) @@ -81,7 +81,7 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): lambda: readers.FixedLengthRecordDataset("", 42)), ("FromGenerator", lambda: dataset_ops.Dataset.from_generator( - DatasetOpsTest.make_gen(), dtypes.int32), + DatasetTest.make_gen(), dtypes.int32), 1), ("FromTensors", lambda: dataset_ops.Dataset.from_tensors([42])), ("FromTensorSlices", lambda: dataset_ops.Dataset.from_tensors([42])), @@ -313,6 +313,5 @@ class DatasetOpsTest(test_base.DatasetTestBase, parameterized.TestCase): round_trip_dataset, [self.evaluate(tf_value_fn())], requires_initialization=True) - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py b/tensorflow/python/data/kernel_tests/filter_test.py similarity index 77% rename from tensorflow/python/data/kernel_tests/filter_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/filter_test.py index fba474b97b..afaf954cbc 100644 --- a/tensorflow/python/data/kernel_tests/filter_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/filter_test.py @@ -12,30 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.filter()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import time - import numpy as np -from tensorflow.python.client import session from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors -from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import test_util -from tensorflow.python.ops import array_ops from tensorflow.python.ops import functional_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class FilterDatasetTest(test_base.DatasetTestBase): +class FilterTest(test_base.DatasetTestBase): def testFilterDataset(self): components = ( @@ -129,41 +124,5 @@ class FilterDatasetTest(test_base.DatasetTestBase): [next_element() for next_element in next_elements])) -# TODO(b/119837791): Add eager benchmarks too. -class FilterDatasetBenchmark(test.Benchmark): - - def _benchmark(self, predicate, name): - with ops.Graph().as_default(): - dataset = ( - dataset_ops.Dataset.from_tensors(True).repeat(None).filter(predicate)) - iterator = dataset.make_one_shot_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for _ in range(5): - sess.run(next_element.op) - deltas = [] - for _ in range(100): - start = time.time() - for _ in range(100): - sess.run(next_element.op) - end = time.time() - deltas.append(end - start) - - median_wall_time = np.median(deltas) / 100 - print("Filter dataset using %s. Median wall time: %f" % - (name, median_wall_time)) - self.report_benchmark( - iters=100, - wall_time=median_wall_time, - name="benchmark_filter_dataset_%s" % name) - - def benchmarkSimpleFunction(self): - self._benchmark(array_ops.identity, "simple_function") - - def benchmarkReturnComponentOptimization(self): - self._benchmark(lambda x: x, "return_component") - - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/fixed_length_record_dataset_test.py b/tensorflow/python/data/kernel_tests/fixed_length_record_dataset_test.py new file mode 100644 index 0000000000..9503e57ca7 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/fixed_length_record_dataset_test.py @@ -0,0 +1,171 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.FixedLengthRecordDataset`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gzip +import os +import zlib + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import readers +from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util +from tensorflow.python.platform import test +from tensorflow.python.util import compat + + +@test_util.run_all_in_graph_and_eager_modes +class FixedLengthRecordDatasetTest(test_base.DatasetTestBase): + + def setUp(self): + super(FixedLengthRecordDatasetTest, self).setUp() + self._num_files = 2 + self._num_records = 7 + self._header_bytes = 5 + self._record_bytes = 3 + self._footer_bytes = 2 + + def _record(self, f, r): + return compat.as_bytes(str(f * 2 + r) * self._record_bytes) + + def _createFiles(self, compression_type=None): + filenames = [] + for i in range(self._num_files): + fn = os.path.join(self.get_temp_dir(), "fixed_length_record.%d.txt" % i) + filenames.append(fn) + + contents = [] + contents.append(b"H" * self._header_bytes) + for j in range(self._num_records): + contents.append(self._record(i, j)) + contents.append(b"F" * self._footer_bytes) + contents = b"".join(contents) + + if not compression_type: + with open(fn, "wb") as f: + f.write(contents) + elif compression_type == "GZIP": + with gzip.GzipFile(fn, "wb") as f: + f.write(contents) + elif compression_type == "ZLIB": + contents = zlib.compress(contents) + with open(fn, "wb") as f: + f.write(contents) + else: + raise ValueError("Unsupported compression_type", compression_type) + + return filenames + + def _testFixedLengthRecordDataset(self, compression_type=None): + test_filenames = self._createFiles(compression_type=compression_type) + + def dataset_fn(filenames, num_epochs, batch_size=None): + repeat_dataset = readers.FixedLengthRecordDataset( + filenames, + self._record_bytes, + self._header_bytes, + self._footer_bytes, + compression_type=compression_type).repeat(num_epochs) + if batch_size: + return repeat_dataset.batch(batch_size) + return repeat_dataset + + # Basic test: read from file 0. + self.assertDatasetProduces( + dataset_fn([test_filenames[0]], 1), + expected_output=[ + self._record(0, i) for i in range(self._num_records) + ]) + + # Basic test: read from file 1. + self.assertDatasetProduces( + dataset_fn([test_filenames[1]], 1), + expected_output=[ + self._record(1, i) for i in range(self._num_records) + ]) + + # Basic test: read from both files. + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces( + dataset_fn(test_filenames, 1), expected_output=expected_output) + + # Test repeated iteration through both files. + get_next = self.getNext(dataset_fn(test_filenames, 10)) + for _ in range(10): + for j in range(self._num_files): + for i in range(self._num_records): + self.assertEqual(self._record(j, i), self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + # Test batched and repeated iteration through both files. + get_next = self.getNext(dataset_fn(test_filenames, 10, self._num_records)) + for _ in range(10): + for j in range(self._num_files): + self.assertAllEqual( + [self._record(j, i) for i in range(self._num_records)], + self.evaluate(get_next())) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + def testFixedLengthRecordDatasetNoCompression(self): + self._testFixedLengthRecordDataset() + + def testFixedLengthRecordDatasetGzipCompression(self): + self._testFixedLengthRecordDataset(compression_type="GZIP") + + def testFixedLengthRecordDatasetZlibCompression(self): + self._testFixedLengthRecordDataset(compression_type="ZLIB") + + def testFixedLengthRecordDatasetBuffering(self): + test_filenames = self._createFiles() + dataset = readers.FixedLengthRecordDataset( + test_filenames, + self._record_bytes, + self._header_bytes, + self._footer_bytes, + buffer_size=10) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testFixedLengthRecordDatasetWrongSize(self): + test_filenames = self._createFiles() + dataset = readers.FixedLengthRecordDataset( + test_filenames, + self._record_bytes + 1, # Incorrect record length. + self._header_bytes, + self._footer_bytes, + buffer_size=10) + self.assertDatasetProduces( + dataset, + expected_error=( + errors.InvalidArgumentError, + r"Excluding the header \(5 bytes\) and footer \(2 bytes\), input " + r"file \".*fixed_length_record.0.txt\" has body length 21 bytes, " + r"which is not an exact multiple of the record length \(4 bytes\).") + ) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py b/tensorflow/python/data/kernel_tests/flat_map_test.py similarity index 97% rename from tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/flat_map_test.py index 9292f20637..5f11c2e3a7 100644 --- a/tensorflow/python/data/kernel_tests/flat_map_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/flat_map_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.flat_map()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -33,7 +33,7 @@ from tensorflow.python.training import server_lib @test_util.run_all_in_graph_and_eager_modes -class FlatMapDatasetTest(test_base.DatasetTestBase): +class FlatMapTest(test_base.DatasetTestBase): # pylint: disable=g-long-lambda def testFlatMapDataset(self): diff --git a/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py b/tensorflow/python/data/kernel_tests/from_generator_test.py similarity index 99% rename from tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py rename to tensorflow/python/data/kernel_tests/from_generator_test.py index cb8cb9a77d..4d82c2111c 100644 --- a/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py +++ b/tensorflow/python/data/kernel_tests/from_generator_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for tf.data.Dataset.from_generator().""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -31,7 +31,7 @@ from tensorflow.python.ops import script_ops from tensorflow.python.platform import test -class DatasetConstructorTest(test_base.DatasetTestBase): +class FromGeneratorTest(test_base.DatasetTestBase): def _testFromGenerator(self, generator, elem_sequence, num_repeats, output_types=None): diff --git a/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py b/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py new file mode 100644 index 0000000000..d23ac0ebe9 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/from_sparse_tensor_slices_test.py @@ -0,0 +1,85 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.Dataset.from_sparse_tensor_slices()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors +from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util +from tensorflow.python.ops import array_ops +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class FromSparseTensorSlicesTest(test_base.DatasetTestBase): + + def testSkipEagerFromSparseTensorSlices(self): + """Test a dataset based on slices of a `tf.SparseTensor`.""" + st = array_ops.sparse_placeholder(dtypes.float64) + iterator = (dataset_ops.Dataset.from_sparse_tensor_slices(st) + .make_initializable_iterator()) + init_op = iterator.initializer + get_next = sparse_tensor.SparseTensor(*iterator.get_next()) + + with self.cached_session() as sess: + slices = [[1., 2., 3.], [1.], [1.], [1., 2.], [], [1., 2.], [], [], []] + + # Test with sparse tensor in the appropriate order. + indices = np.array( + [[i, j] for i in range(len(slices)) for j in range(len(slices[i]))]) + values = np.array([val for s in slices for val in s]) + dense_shape = np.array([len(slices), max(len(s) for s in slices) + 1]) + sparse_feed = sparse_tensor.SparseTensorValue(indices, values, + dense_shape) + sess.run(init_op, feed_dict={st: sparse_feed}) + for i, s in enumerate(slices): + results = sess.run(get_next) + self.assertAllEqual(s, results.values) + expected_indices = np.array( + [[j] for j in range(len(slices[i]))]).reshape([-1, 1]) + self.assertAllEqual(expected_indices, results.indices) + self.assertAllEqual(dense_shape[1:], results.dense_shape) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + # Test with sparse tensor in the reverse order, which is not + # currently supported. + reverse_order_indices = indices[::-1, :] + reverse_order_values = values[::-1] + sparse_feed = sparse_tensor.SparseTensorValue( + reverse_order_indices, reverse_order_values, dense_shape) + with self.assertRaises(errors.UnimplementedError): + sess.run(init_op, feed_dict={st: sparse_feed}) + + # Test with an empty sparse tensor. + empty_indices = np.empty((0, 4), dtype=np.int64) + empty_values = np.empty((0,), dtype=np.float64) + empty_dense_shape = [0, 4, 37, 9] + sparse_feed = sparse_tensor.SparseTensorValue(empty_indices, empty_values, + empty_dense_shape) + sess.run(init_op, feed_dict={st: sparse_feed}) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/from_tensor_slices_test.py b/tensorflow/python/data/kernel_tests/from_tensor_slices_test.py new file mode 100644 index 0000000000..9a480e5678 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/from_tensor_slices_test.py @@ -0,0 +1,177 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.Dataset.from_tensor_slices().""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors +from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class FromTensorSlicesTest(test_base.DatasetTestBase): + + def testFromTensorSlices(self): + """Test a dataset that represents the slices from a tuple of tensors.""" + components = ( + np.tile(np.array([[1], [2], [3], [4]]), 20), np.tile( + np.array([[12], [13], [14], [15]]), 22), + np.array([37.0, 38.0, 39.0, 40.0]) + ) + + dataset = dataset_ops.Dataset.from_tensor_slices(components) + get_next = self.getNext(dataset) + + self.assertEqual([c.shape[1:] for c in components], + [shape for shape in dataset.output_shapes]) + + for i in range(4): + results = self.evaluate(get_next()) + for component, result_component in zip(components, results): + self.assertAllEqual(component[i], result_component) + with self.assertRaises(errors.OutOfRangeError): + results = self.evaluate(get_next()) + + def testSkipEagerFromTensorSlicesSparse(self): + """Test a dataset that represents the slices from a tuple of tensors.""" + components = (sparse_tensor.SparseTensorValue( + indices=np.array([[0, 0], [1, 0], [2, 0]]), + values=np.array([0, 0, 0]), + dense_shape=np.array([3, 1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0, 0], [1, 1], [2, 2]]), + values=np.array([1, 2, 3]), + dense_shape=np.array([3, 3]))) + + dataset = dataset_ops.Dataset.from_tensor_slices(components) + + self.assertEqual( + [tensor_shape.TensorShape(c.dense_shape[1:]) for c in components], + [shape for shape in dataset.output_shapes]) + + expected = [ + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([1]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[1]]), + values=np.array([2]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[2]]), + values=np.array([3]), + dense_shape=np.array([3]))), + ] + self.assertDatasetProduces(dataset, expected_output=expected) + + def testFromTensorSlicesMixed(self): + """Test a dataset that represents the slices from a tuple of tensors.""" + components = (np.tile(np.array([[1], [2], [3]]), 20), + np.tile(np.array([[12], [13], [14]]), 22), + np.array([37.0, 38.0, 39.0]), + sparse_tensor.SparseTensorValue( + indices=np.array([[0, 0], [1, 0], [2, 0]]), + values=np.array([0, 0, 0]), + dense_shape=np.array([3, 1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0, 0], [1, 1], [2, 2]]), + values=np.array([1, 2, 3]), + dense_shape=np.array([3, 3]))) + + dataset = dataset_ops.Dataset.from_tensor_slices(components) + get_next = self.getNext(dataset) + self.assertEqual([ + tensor_shape.TensorShape(c.dense_shape[1:]) + if sparse_tensor.is_sparse(c) else c.shape[1:] for c in components + ], [shape for shape in dataset.output_shapes]) + + expected = [ + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([1]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[1]]), + values=np.array([2]), + dense_shape=np.array([3]))), + (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[2]]), + values=np.array([3]), + dense_shape=np.array([3]))), + ] + for i in range(3): + results = self.evaluate(get_next()) + for component, result_component in zip( + (list(zip(*components[:3]))[i] + expected[i]), results): + if sparse_tensor.is_sparse(component): + self.assertSparseValuesEqual(component, result_component) + else: + self.assertAllEqual(component, result_component) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + + def testFromTensorSlicesWithDict(self): + components = {"foo": [1, 2, 3], "bar": [[4.0], [5.0], [6.0]]} + dataset = dataset_ops.Dataset.from_tensor_slices(components) + get_next = self.getNext(dataset) + + self.assertEqual(dtypes.int32, dataset.output_types["foo"]) + self.assertEqual(dtypes.float32, dataset.output_types["bar"]) + self.assertEqual((), dataset.output_shapes["foo"]) + self.assertEqual((1,), dataset.output_shapes["bar"]) + + for i in range(3): + results = self.evaluate(get_next()) + self.assertEqual(components["foo"][i], results["foo"]) + self.assertEqual(components["bar"][i], results["bar"]) + with self.assertRaises(errors.OutOfRangeError): + self.evaluate(get_next()) + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/from_tensors_test.py b/tensorflow/python/data/kernel_tests/from_tensors_test.py new file mode 100644 index 0000000000..2857817e14 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/from_tensors_test.py @@ -0,0 +1,258 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.Dataset.from_tensors().""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.core.protobuf import config_pb2 +from tensorflow.python.client import session +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.util import nest +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors +from tensorflow.python.framework import ops +from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import resource_variable_ops +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class FromTensorsTest(test_base.DatasetTestBase): + + def testFromTensors(self): + """Test a dataset that represents a single tuple of tensors.""" + components = (np.array(1), np.array([1, 2, 3]), np.array(37.0)) + + dataset = dataset_ops.Dataset.from_tensors(components) + + self.assertEqual([c.shape for c in components], + nest.flatten(dataset.output_shapes)) + + self.assertDatasetProduces(dataset, expected_output=[components]) + + def testSkipEagerFromTensorsSparse(self): + """Test a dataset that represents a single tuple of tensors.""" + components = (sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0, 0], [1, 1]]), + values=np.array([-1, 1]), + dense_shape=np.array([2, 2]))) + + dataset = dataset_ops.Dataset.from_tensors(components) + + self.assertEqual( + [tensor_shape.TensorShape(c.dense_shape) for c in components], + [shape for shape in dataset.output_shapes]) + self.assertDatasetProduces(dataset, expected_output=[components]) + + def testFromTensorsMixed(self): + """Test an dataset that represents a single tuple of tensors.""" + components = (np.array(1), np.array([1, 2, 3]), np.array(37.0), + sparse_tensor.SparseTensorValue( + indices=np.array([[0]]), + values=np.array([0]), + dense_shape=np.array([1])), + sparse_tensor.SparseTensorValue( + indices=np.array([[0, 0], [1, 1]]), + values=np.array([-1, 1]), + dense_shape=np.array([2, 2]))) + + dataset = dataset_ops.Dataset.from_tensors(components) + self.assertEqual([ + tensor_shape.TensorShape(c.dense_shape) + if sparse_tensor.is_sparse(c) else c.shape for c in components + ], [shape for shape in dataset.output_shapes]) + + self.assertDatasetProduces(dataset, expected_output=[components]) + + # pylint: disable=g-long-lambda,unnecessary-lambda + def testNestedStructure(self): + components = (np.array([1, 2, 3], dtype=np.int64), + (np.array([4., 5.]), np.array([6., 7.])), + np.array([8, 9, 10], dtype=np.int64)) + + dataset = dataset_ops.Dataset.from_tensors(components) + self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), + dtypes.int64), dataset.output_types) + self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) + + dataset = dataset.shuffle(10, 10) + self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), + dtypes.int64), dataset.output_types) + self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) + + dataset = dataset.repeat(-1) + self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), + dtypes.int64), dataset.output_types) + self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) + + dataset = dataset.filter(lambda x, y, z: True) + self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), + dtypes.int64), dataset.output_types) + self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) + + dataset = dataset.take(5) + self.assertEquals((dtypes.int64, (dtypes.float64, dtypes.float64), + dtypes.int64), dataset.output_types) + self.assertEquals(([3], ([2], [2]), [3]), dataset.output_shapes) + + dataset = dataset.map(lambda x, y, z: ((x, z), (y[0], y[1]))) + self.assertEquals(((dtypes.int64, dtypes.int64), + (dtypes.float64, dtypes.float64)), dataset.output_types) + self.assertEquals((([3], [3]), ([2], [2])), dataset.output_shapes) + + dataset = dataset.flat_map( + lambda x, y: dataset_ops.Dataset.from_tensors(((x[0], x[1]), + (y[0], y[1]))) + ) + self.assertEquals(((dtypes.int64, dtypes.int64), + (dtypes.float64, dtypes.float64)), dataset.output_types) + self.assertEquals((([3], [3]), ([2], [2])), dataset.output_shapes) + + dataset = dataset.batch(32) + self.assertEquals(((dtypes.int64, dtypes.int64), + (dtypes.float64, dtypes.float64)), dataset.output_types) + self.assertEquals((([None, 3], [None, 3]), ([None, 2], [None, 2])), + nest.pack_sequence_as(dataset.output_shapes, [ + s.as_list() + for s in nest.flatten(dataset.output_shapes) + ])) + + # Define a separate set of components with matching leading + # dimension for the from-slices constructor. + components_for_slices = (np.array([1, 2, 3], dtype=np.int64), + (np.array([4., 5., 6.]), np.array([7., 8., 9.])), + np.array([10, 11, 12], dtype=np.int64)) + + dataset = dataset_ops.Dataset.from_tensor_slices(components_for_slices) + self.assertEquals((dtypes.int64, + (dtypes.float64, dtypes.float64), dtypes.int64), + dataset.output_types) + self.assertEquals(([], ([], []), []), dataset.output_shapes) + + # TODO(b/117581999): more specific shapes in eager mode. + def testSkipEagerNestedStructure(self): + components = (np.array([1, 2, 3], dtype=np.int64), (np.array([4., 5.]), + np.array([6., 7.])), + np.array([8, 9, 10], dtype=np.int64)) + + dataset = dataset_ops.Dataset.from_tensors(components) + dataset = dataset.map(lambda x, y, z: ((x, z), (y[0], y[1]))) + + dataset = dataset.flat_map( + lambda x, y: dataset_ops.Dataset.from_tensors( + ((x[0], x[1]), (y[0], y[1])))).batch(32) + + get_next = self.getNext(dataset) + (w, x), (y, z) = get_next() + self.assertEquals(dtypes.int64, w.dtype) + self.assertEquals(dtypes.int64, x.dtype) + self.assertEquals(dtypes.float64, y.dtype) + self.assertEquals(dtypes.float64, z.dtype) + self.assertEquals([None, 3], w.shape.as_list()) + self.assertEquals([None, 3], x.shape.as_list()) + self.assertEquals([None, 2], y.shape.as_list()) + self.assertEquals([None, 2], z.shape.as_list()) + + get_next = self.getNext(dataset) + (w, x), (y, z) = get_next() + self.assertEquals(dtypes.int64, w.dtype) + self.assertEquals(dtypes.int64, x.dtype) + self.assertEquals(dtypes.float64, y.dtype) + self.assertEquals(dtypes.float64, z.dtype) + self.assertEquals([None, 3], w.shape.as_list()) + self.assertEquals([None, 3], x.shape.as_list()) + self.assertEquals([None, 2], y.shape.as_list()) + self.assertEquals([None, 2], z.shape.as_list()) + + def testNestedDict(self): + components = {"a": {"aa": 1, "ab": [2.0, 2.0]}, "b": [3, 3, 3]} + dataset = dataset_ops.Dataset.from_tensors(components) + self.assertEquals(dtypes.int32, dataset.output_types["a"]["aa"]) + self.assertEquals(dtypes.float32, dataset.output_types["a"]["ab"]) + self.assertEquals(dtypes.int32, dataset.output_types["b"]) + self.assertEquals([], dataset.output_shapes["a"]["aa"]) + self.assertEquals([2], dataset.output_shapes["a"]["ab"]) + self.assertEquals([3], dataset.output_shapes["b"]) + + def testNonSequenceNestedStructure(self): + components = np.array([1, 2, 3], dtype=np.int64) + + dataset = dataset_ops.Dataset.from_tensors(components) + self.assertEquals(dtypes.int64, dataset.output_types) + self.assertEquals([3], dataset.output_shapes) + + dataset = dataset.filter( + lambda x: math_ops.reduce_all(math_ops.equal(x, components))) + self.assertEquals(dtypes.int64, dataset.output_types) + self.assertEquals([3], dataset.output_shapes) + + dataset = dataset.map(lambda x: array_ops.stack([x, x])) + self.assertEquals(dtypes.int64, dataset.output_types) + self.assertEquals([2, 3], dataset.output_shapes) + + dataset = dataset.flat_map( + lambda x: dataset_ops.Dataset.from_tensor_slices(x)) + self.assertEquals(dtypes.int64, dataset.output_types) + self.assertEquals([3], dataset.output_shapes) + + get_next = self.getNext(dataset) + self.assertEquals(dtypes.int64, get_next().dtype) + self.assertEquals([3], get_next().shape) + + def testSkipEagerSplitPipelineFailsWithPlacementError(self): + with session.Session( + target="", + config=config_pb2.ConfigProto(device_count={"CPU": 2})) as sess: + + dataset = dataset_ops.Dataset.from_tensors(0) + + # Define a pipeline that attempts to use variables on two + # different devices. + # + # Initialize the variables before creating to iterator, to avoid the + # placement algorithm overriding the DT_RESOURCE colocation constraints. + with ops.device("/cpu:0"): + var_0 = resource_variable_ops.ResourceVariable(initial_value=0) + dataset = dataset.map(lambda x: x + var_0.read_value()) + sess.run(var_0.initializer) + + with ops.device("/cpu:1"): + var_1 = resource_variable_ops.ResourceVariable(initial_value=0) + dataset = dataset.map(lambda x: x + var_1.read_value()) + sess.run(var_1.initializer) + + iterator = dataset.make_initializable_iterator() + sess.run(iterator.initializer) + + with self.assertRaisesRegexp( + errors.FailedPreconditionError, + "Error while reading resource variable Variable"): + sess.run(iterator.get_next()) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/inputs_test.py b/tensorflow/python/data/kernel_tests/inputs_test.py deleted file mode 100644 index 03df502d14..0000000000 --- a/tensorflow/python/data/kernel_tests/inputs_test.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2018 The TensorFlow Authors. 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. -# ============================================================================== -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from absl.testing import parameterized -import numpy as np - -from tensorflow.python.data.kernel_tests import test_base -from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import readers -from tensorflow.python.data.util import nest -from tensorflow.python.framework import dtypes -from tensorflow.python.framework import sparse_tensor -from tensorflow.python.framework import test_util -from tensorflow.python.platform import test - - -@test_util.run_all_in_graph_and_eager_modes -class InputsTest(test_base.DatasetTestBase, parameterized.TestCase): - - @staticmethod - def make_apply_fn(dataset): - - def apply_fn(dataset): - - def _apply_fn(dataset): - return dataset.cache() - - return dataset.apply(_apply_fn) - - return apply_fn - - @staticmethod - def make_gen(): - - def gen(): - yield 42 - - return gen - - @staticmethod - def make_interleave_fn(dataset, num_parallel_calls=None): - - def interleave_fn(dataset): - return dataset.interleave( - lambda x: dataset_ops.Dataset.range(0), - cycle_length=2, - num_parallel_calls=num_parallel_calls) - - return interleave_fn - - @parameterized.named_parameters( - ("FixedLengthRecord", readers.FixedLengthRecordDataset("", 42)), - ("FromGenerator", - dataset_ops.Dataset.from_generator(make_gen.__func__(), dtypes.int32), - 1), - ("FromSparseTensorSlices", - dataset_ops.Dataset.from_sparse_tensor_slices( - sparse_tensor.SparseTensor( - indices=np.array([[0, 0], [1, 0], [2, 0]]), - values=np.array([0, 0, 0]), - dense_shape=np.array([3, 1])))), - ("FromTensors", dataset_ops.Dataset.from_tensors([42])), - ("FromTensorSlices", dataset_ops.Dataset.from_tensors([42])), - ("Range", dataset_ops.Dataset.range(10)), - ("TextLine", readers.TextLineDataset("")), - ("TFRecord", readers.TFRecordDataset(""), 1), - ) - def testDatasetSourceInputs(self, dataset, num_inputs=0): - self.assertEqual(num_inputs, len(dataset._inputs())) - - @parameterized.named_parameters( - ("Apply", make_apply_fn.__func__(dataset_ops.Dataset.range(0)), - dataset_ops.Dataset.range(0)), - ("Batch", lambda x: x.batch(10), dataset_ops.Dataset.range(0)), - ("Cache", lambda x: x.cache(), dataset_ops.Dataset.range(0)), - ("Filter", lambda x: x.filter(lambda x: True), - dataset_ops.Dataset.range(0)), - ("FlatMap", lambda x: x.flat_map(lambda x: dataset_ops.Dataset.range(0)), - dataset_ops.Dataset.range(0)), - ("Interleave", make_interleave_fn.__func__(dataset_ops.Dataset.range(0)), - dataset_ops.Dataset.range(0)), - ("Map", lambda x: x.map(lambda x: x), dataset_ops.Dataset.range(0)), - ("PaddedBatch", lambda x: x.padded_batch(10, []), - dataset_ops.Dataset.range(0)), - ("ParallelInterleave", - make_interleave_fn.__func__(dataset_ops.Dataset.range(0), 2), - dataset_ops.Dataset.range(0)), - ("ParallelMap", lambda x: x.map(lambda x: x, num_parallel_calls=2), - dataset_ops.Dataset.range(0)), - ("Repeat", lambda x: x.repeat(), dataset_ops.Dataset.range(0)), - ("Shuffle", lambda x: x.shuffle(10), dataset_ops.Dataset.range(0)), - ("Skip", lambda x: x.skip(1), dataset_ops.Dataset.range(0)), - ("Take", lambda x: x.take(1), dataset_ops.Dataset.range(0)), - ("Window", lambda x: x.window(10), dataset_ops.Dataset.range(0)), - ) - def testUnaryTransformationInputs(self, dataset_fn, input_dataset): - self.assertEqual([input_dataset], dataset_fn(input_dataset)._inputs()) - - @parameterized.named_parameters( - ("Concatenate", lambda x, y: x.concatenate(y), - dataset_ops.Dataset.range(0), dataset_ops.Dataset.range(1))) - def testBinaryTransformationInputs(self, dataset_fn, input1, input2): - self.assertEqual([input1, input2], dataset_fn(input1, input2)._inputs()) - - @parameterized.named_parameters( - ("ZipOne", dataset_ops.Dataset.zip, (dataset_ops.Dataset.range(0))), - ("ZipNest", dataset_ops.Dataset.zip, - (dataset_ops.Dataset.range(0), - (dataset_ops.Dataset.range(1), dataset_ops.Dataset.range(2)))), - ("ZipTuple", dataset_ops.Dataset.zip, - (dataset_ops.Dataset.range(0), dataset_ops.Dataset.range(1)))) - def testVariadicTransformationInputs(self, dataset_fn, input_datasets): - self.assertEqual( - nest.flatten(input_datasets), - dataset_fn(input_datasets)._inputs()) - - def testCollectInputs(self): - ds1 = dataset_ops.Dataset.range(0) - ds2 = ds1.concatenate(ds1) - ds3 = dataset_ops.Dataset.zip((ds2, ds1, ds2)) - - inputs = [] - queue = [ds3] - while queue: - ds = queue[0] - queue = queue[1:] - queue.extend(ds._inputs()) - inputs.append(ds) - - self.assertEqual(5, inputs.count(ds1)) - self.assertEqual(2, inputs.count(ds2)) - self.assertEqual(1, inputs.count(ds3)) - - -if __name__ == "__main__": - test.main() diff --git a/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py b/tensorflow/python/data/kernel_tests/interleave_test.py similarity index 69% rename from tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/interleave_test.py index f0b16591f7..cd1d850304 100644 --- a/tensorflow/python/data/kernel_tests/interleave_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/interleave_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.interleave()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -116,7 +116,9 @@ def _make_coordinated_sloppy_dataset(input_values, cycle_length, block_length, dataset = dataset_ops.Dataset.from_tensor_slices(input_values).repeat( 2).interleave(interleave_fn, cycle_length, block_length, num_parallel_calls).with_options(options) - return dataset, coordination_events + iterator = dataset.make_one_shot_iterator() + get_next = iterator.get_next() + return get_next, coordination_events def _repeat(values, count): @@ -133,7 +135,7 @@ def _repeat(values, count): @test_util.run_all_in_graph_and_eager_modes -class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): +class InterleaveTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( ("1", [4, 5, 6], 1, 1, [ @@ -191,8 +193,10 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): count).interleave( lambda x: dataset_ops.Dataset.from_tensors(x).repeat(x), cycle_length, block_length, num_parallel_calls) - expected_output = [element for element in _interleave( - _repeat(input_values, count), cycle_length, block_length)] + expected_output = [ + element for element in _interleave( + _repeat(input_values, count), cycle_length, block_length) + ] self.assertDatasetProduces(dataset, expected_output) @parameterized.named_parameters( @@ -249,100 +253,59 @@ class InterleaveDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.OutOfRangeError): self.evaluate(get_next()) - -class InterleaveDatasetTestWithConfig(test_base.DatasetTestBase, - parameterized.TestCase): - - @parameterized.named_parameters( - ("1", np.int64([4, 5, 6]), 2, 1), - ("2", np.int64([4, 5, 6]), 2, 3), - ("3", np.int64([4, 5, 6]), 3, 2), - ("4", np.int64([4, 0, 6]), 2, 3), - ) - @test_util.run_in_graph_and_eager_modes( - config=config_pb2.ConfigProto( - inter_op_parallelism_threads=2, use_per_session_threads=True)) - def testSloppyInterleaveInOrder(self, input_values, cycle_length, - block_length): - dataset, coordination_events = _make_coordinated_sloppy_dataset( - input_values, cycle_length, block_length, num_parallel_calls=1) - get_next = self.getNext(dataset) - for expected_element in _interleave( - _repeat(input_values, 2), cycle_length, block_length): - coordination_events[expected_element].set() - self.assertEqual(expected_element * expected_element, - self.evaluate(get_next())) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) - @parameterized.named_parameters( - ("1", np.int64([4, 5, 6]), 2, 1), - ("2", np.int64([4, 5, 6]), 2, 3), - ("3", np.int64([4, 5, 6]), 3, 2), - ("4", np.int64([4, 0, 6]), 2, 3), + ("1", np.int64([4, 5, 6]), 2, 1, 1), + ("2", np.int64([4, 5, 6]), 2, 1, 2), + ("3", np.int64([4, 5, 6]), 2, 3, 1), + ("4", np.int64([4, 5, 6]), 2, 3, 2), + ("5", np.int64([4, 5, 6]), 3, 2, 1), + ("6", np.int64([4, 5, 6]), 3, 2, 2), + ("7", np.int64([4, 5, 6]), 3, 2, 3), + ("8", np.int64([4, 0, 6]), 2, 3, 1), + ("9", np.int64([4, 0, 6]), 2, 3, 2), ) - @test_util.run_in_graph_and_eager_modes( - config=config_pb2.ConfigProto( - inter_op_parallelism_threads=3, use_per_session_threads=True)) - def testSloppyInterleaveInOrder_2(self, input_values, cycle_length, - block_length): - dataset, coordination_events = _make_coordinated_sloppy_dataset( - input_values, cycle_length, block_length, num_parallel_calls=2) - get_next = self.getNext(dataset) - for expected_element in _interleave( - _repeat(input_values, 2), cycle_length, block_length): - coordination_events[expected_element].set() - self.assertEqual(expected_element * expected_element, - self.evaluate(get_next())) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) + def testSkipEagerSloppyInterleaveInOrder(self, input_values, cycle_length, + block_length, num_parallel_calls): + get_next, coordination_events = _make_coordinated_sloppy_dataset( + input_values, cycle_length, block_length, num_parallel_calls) + config = config_pb2.ConfigProto( + inter_op_parallelism_threads=num_parallel_calls + 1, + use_per_session_threads=True) + with self.cached_session(config=config) as sess: + for expected_element in _interleave( + _repeat(input_values, 2), cycle_length, block_length): + coordination_events[expected_element].set() + self.assertEqual(expected_element * expected_element, + self.evaluate(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) @parameterized.named_parameters( - ("1", np.int64([4, 5, 6]), 2, 1), - ("2", np.int64([4, 5, 6]), 2, 3), - ("3", np.int64([4, 0, 6]), 2, 3), + ("1", np.int64([4, 5, 6]), 2, 1, 2), + ("2", np.int64([4, 5, 6]), 2, 3, 2), + ("3", np.int64([4, 5, 6]), 3, 2, 3), + ("4", np.int64([4, 0, 6]), 2, 3, 2), ) - @test_util.run_in_graph_and_eager_modes( - config=config_pb2.ConfigProto( - inter_op_parallelism_threads=3, use_per_session_threads=True)) - def testSloppyInterleaveOutOfOrder(self, input_values, cycle_length, - block_length): - dataset, coordination_events = _make_coordinated_sloppy_dataset( - input_values, cycle_length, block_length, num_parallel_calls=2) - get_next = self.getNext(dataset) - elements = [ - x for x in _interleave( - _repeat(input_values, 2), cycle_length, block_length) - ] - for i in [1, 4, 7]: - elements[i], elements[i + 1] = elements[i + 1], elements[i] - - for element in elements: - coordination_events[element].set() - self.assertEqual(element * element, self.evaluate(get_next())) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) - - @test_util.run_in_graph_and_eager_modes( - config=config_pb2.ConfigProto( - inter_op_parallelism_threads=4, use_per_session_threads=True)) - def testSloppyInterleaveOutOfOrder_2(self): - input_values, cycle_length, block_length = np.int64([4, 5, 6]), 3, 2 - dataset, coordination_events = _make_coordinated_sloppy_dataset( - input_values, cycle_length, block_length, num_parallel_calls=3) - get_next = self.getNext(dataset) - elements = [ - x for x in _interleave( - _repeat(input_values, 2), cycle_length, block_length) - ] - for i in [1, 4, 7]: - elements[i], elements[i + 1] = elements[i + 1], elements[i] - - for element in elements: - coordination_events[element].set() - self.assertEqual(element * element, self.evaluate(get_next())) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) + def testSkipEagerSloppyInterleaveOutOfOrder(self, input_values, cycle_length, + block_length, num_parallel_calls): + get_next, coordination_events = _make_coordinated_sloppy_dataset( + input_values, cycle_length, block_length, num_parallel_calls) + config = config_pb2.ConfigProto( + inter_op_parallelism_threads=num_parallel_calls + 1, + use_per_session_threads=True) + with self.cached_session(config=config) as sess: + elements = [ + x for x in _interleave( + _repeat(input_values, 2), cycle_length, block_length) + ] + for i in [1, 4, 7]: + elements[i], elements[i + 1] = elements[i + 1], elements[i] + + for element in elements: + coordination_events[element].set() + self.assertEqual(element * element, self.evaluate(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/kernel_tests/iterator_checkpoint_test.py b/tensorflow/python/data/kernel_tests/iterator_checkpoint_test.py new file mode 100644 index 0000000000..fc4164c81a --- /dev/null +++ b/tensorflow/python/data/kernel_tests/iterator_checkpoint_test.py @@ -0,0 +1,129 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Checkpoint tests for `tf.data.Iterator`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import functools +import os + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.eager import context +from tensorflow.python.framework import errors +from tensorflow.python.framework import test_util +from tensorflow.python.ops import math_ops +from tensorflow.python.platform import test +from tensorflow.python.training import checkpoint_management +from tensorflow.python.training.checkpointable import util as checkpointable_utils + + +@test_util.run_all_in_graph_and_eager_modes +class IteratorCheckpointingTest(test_base.DatasetTestBase): + + def testSaveRestoreOneShotIterator(self): + checkpoint_directory = self.get_temp_dir() + checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") + dataset = dataset_ops.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6]).map( + math_ops.square).batch(2) + iterator = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() + get_next = iterator.get_next if context.executing_eagerly( + ) else functools.partial(self.evaluate, iterator.get_next()) + checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) + self.assertAllEqual([1, 4], get_next()) + save_path = checkpoint.save(checkpoint_prefix) + self.assertAllEqual([9, 16], get_next()) + self.assertAllEqual([25, 36], get_next()) + checkpoint.restore(save_path).run_restore_ops() + self.assertAllEqual([9, 16], get_next()) + self.assertAllEqual([25, 36], get_next()) + with self.assertRaises(errors.OutOfRangeError): + get_next() + + def testSaveRestoreMultipleIterator(self): + checkpoint_directory = self.get_temp_dir() + checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") + dataset = dataset_ops.Dataset.from_tensor_slices( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) + dataset = dataset.map(math_ops.square).batch(2) + iterator_1 = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() + get_next_1 = iterator_1.get_next if context.executing_eagerly( + ) else functools.partial(self.evaluate, iterator_1.get_next()) + iterator_2 = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() + get_next_2 = iterator_2.get_next if context.executing_eagerly( + ) else functools.partial(self.evaluate, iterator_2.get_next()) + dataset_2 = dataset_ops.Dataset.range(10) + iterator_3 = iter(dataset_2) if context.executing_eagerly( + ) else dataset_2.make_one_shot_iterator() + get_next_3 = iterator_3.get_next if context.executing_eagerly( + ) else functools.partial(self.evaluate, iterator_3.get_next()) + checkpoint = checkpointable_utils.Checkpoint( + iterator_1=iterator_1, iterator_2=iterator_2, iterator_3=iterator_3) + self.assertAllEqual([1, 4], get_next_1()) + self.assertAllEqual(0, get_next_3()) + self.assertAllEqual(1, get_next_3()) + self.assertAllEqual(2, get_next_3()) + save_path = checkpoint.save(checkpoint_prefix) + self.assertAllEqual([1, 4], get_next_2()) + self.assertAllEqual([9, 16], get_next_2()) + self.assertAllEqual(3, get_next_3()) + checkpoint.restore(save_path).run_restore_ops() + self.assertAllEqual([9, 16], get_next_1()) + self.assertAllEqual([1, 4], get_next_2()) + self.assertAllEqual(3, get_next_3()) + + def testRestoreExhaustedIterator(self): + checkpoint_directory = self.get_temp_dir() + checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") + dataset = dataset_ops.Dataset.range(3) + iterator = iter(dataset) if context.executing_eagerly( + ) else dataset.make_one_shot_iterator() + get_next = iterator.get_next if context.executing_eagerly( + ) else functools.partial(self.evaluate, iterator.get_next()) + checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) + self.assertAllEqual(0, get_next()) + self.assertAllEqual(1, get_next()) + save_path = checkpoint.save(checkpoint_prefix) + self.assertAllEqual(2, get_next()) + checkpoint.restore(save_path).run_restore_ops() + self.assertAllEqual(2, get_next()) + save_path = checkpoint.save(checkpoint_prefix) + checkpoint.restore(save_path).run_restore_ops() + with self.assertRaises(errors.OutOfRangeError): + get_next() + + def testRestoreInReconstructedIteratorInitializable(self): + checkpoint_directory = self.get_temp_dir() + checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") + dataset = dataset_ops.Dataset.range(10) + iterator = iter(dataset) if context.executing_eagerly( + ) else dataset.make_initializable_iterator() + get_next = iterator.get_next + checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) + for i in range(5): + checkpoint.restore( + checkpoint_management.latest_checkpoint( + checkpoint_directory)).initialize_or_restore() + for j in range(2): + self.assertEqual(i * 2 + j, self.evaluate(get_next())) + checkpoint.save(file_prefix=checkpoint_prefix) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py b/tensorflow/python/data/kernel_tests/iterator_cluster_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py rename to tensorflow/python/data/kernel_tests/iterator_cluster_test.py index bf5fd781d6..c1f856ec62 100644 --- a/tensorflow/python/data/kernel_tests/iterator_ops_cluster_test.py +++ b/tensorflow/python/data/kernel_tests/iterator_cluster_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops that need test_util.""" +"""Tests for `tf.data.Iterator` using distributed sessions.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/tensorflow/python/data/kernel_tests/iterator_ops_test.py b/tensorflow/python/data/kernel_tests/iterator_test.py similarity index 87% rename from tensorflow/python/data/kernel_tests/iterator_ops_test.py rename to tensorflow/python/data/kernel_tests/iterator_test.py index 3d4db80883..de95a53e57 100644 --- a/tensorflow/python/data/kernel_tests/iterator_ops_test.py +++ b/tensorflow/python/data/kernel_tests/iterator_test.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Iterator`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import functools import os import warnings @@ -28,7 +27,6 @@ from tensorflow.core.protobuf import cluster_pb2 from tensorflow.core.protobuf import config_pb2 from tensorflow.python.client import session from tensorflow.python.compat import compat as forward_compat -from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import iterator_ops from tensorflow.python.data.ops import readers @@ -51,9 +49,7 @@ from tensorflow.python.ops import parsing_ops from tensorflow.python.ops import script_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test -from tensorflow.python.training import checkpoint_management from tensorflow.python.training import server_lib -from tensorflow.python.training.checkpointable import util as checkpointable_utils from tensorflow.python.util import compat @@ -864,99 +860,5 @@ class IteratorTest(test.TestCase, parameterized.TestCase): self.assertEqual("overridden_name", next_element.op.name) -@test_util.run_all_in_graph_and_eager_modes -class IteratorCheckpointingTest(test_base.DatasetTestBase): - - def testSaveRestoreOneShotIterator(self): - checkpoint_directory = self.get_temp_dir() - checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") - dataset = dataset_ops.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6]).map( - math_ops.square).batch(2) - iterator = iter(dataset) if context.executing_eagerly( - ) else dataset.make_one_shot_iterator() - get_next = iterator.get_next if context.executing_eagerly( - ) else functools.partial(self.evaluate, iterator.get_next()) - checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) - self.assertAllEqual([1, 4], get_next()) - save_path = checkpoint.save(checkpoint_prefix) - self.assertAllEqual([9, 16], get_next()) - self.assertAllEqual([25, 36], get_next()) - checkpoint.restore(save_path).run_restore_ops() - self.assertAllEqual([9, 16], get_next()) - self.assertAllEqual([25, 36], get_next()) - with self.assertRaises(errors.OutOfRangeError): - get_next() - - def testSaveRestoreMultipleIterator(self): - checkpoint_directory = self.get_temp_dir() - checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") - dataset = dataset_ops.Dataset.from_tensor_slices( - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) - dataset = dataset.map(math_ops.square).batch(2) - iterator_1 = iter(dataset) if context.executing_eagerly( - ) else dataset.make_one_shot_iterator() - get_next_1 = iterator_1.get_next if context.executing_eagerly( - ) else functools.partial(self.evaluate, iterator_1.get_next()) - iterator_2 = iter(dataset) if context.executing_eagerly( - ) else dataset.make_one_shot_iterator() - get_next_2 = iterator_2.get_next if context.executing_eagerly( - ) else functools.partial(self.evaluate, iterator_2.get_next()) - dataset_2 = dataset_ops.Dataset.range(10) - iterator_3 = iter(dataset_2) if context.executing_eagerly( - ) else dataset_2.make_one_shot_iterator() - get_next_3 = iterator_3.get_next if context.executing_eagerly( - ) else functools.partial(self.evaluate, iterator_3.get_next()) - checkpoint = checkpointable_utils.Checkpoint( - iterator_1=iterator_1, iterator_2=iterator_2, iterator_3=iterator_3) - self.assertAllEqual([1, 4], get_next_1()) - self.assertAllEqual(0, get_next_3()) - self.assertAllEqual(1, get_next_3()) - self.assertAllEqual(2, get_next_3()) - save_path = checkpoint.save(checkpoint_prefix) - self.assertAllEqual([1, 4], get_next_2()) - self.assertAllEqual([9, 16], get_next_2()) - self.assertAllEqual(3, get_next_3()) - checkpoint.restore(save_path).run_restore_ops() - self.assertAllEqual([9, 16], get_next_1()) - self.assertAllEqual([1, 4], get_next_2()) - self.assertAllEqual(3, get_next_3()) - - def testRestoreExhaustedIterator(self): - checkpoint_directory = self.get_temp_dir() - checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") - dataset = dataset_ops.Dataset.range(3) - iterator = iter(dataset) if context.executing_eagerly( - ) else dataset.make_one_shot_iterator() - get_next = iterator.get_next if context.executing_eagerly( - ) else functools.partial(self.evaluate, iterator.get_next()) - checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) - self.assertAllEqual(0, get_next()) - self.assertAllEqual(1, get_next()) - save_path = checkpoint.save(checkpoint_prefix) - self.assertAllEqual(2, get_next()) - checkpoint.restore(save_path).run_restore_ops() - self.assertAllEqual(2, get_next()) - save_path = checkpoint.save(checkpoint_prefix) - checkpoint.restore(save_path).run_restore_ops() - with self.assertRaises(errors.OutOfRangeError): - get_next() - - def testRestoreInReconstructedIteratorInitializable(self): - checkpoint_directory = self.get_temp_dir() - checkpoint_prefix = os.path.join(checkpoint_directory, "ckpt") - dataset = dataset_ops.Dataset.range(10) - iterator = iter(dataset) if context.executing_eagerly( - ) else dataset.make_initializable_iterator() - get_next = iterator.get_next - checkpoint = checkpointable_utils.Checkpoint(iterator=iterator) - for i in range(5): - checkpoint.restore( - checkpoint_management.latest_checkpoint( - checkpoint_directory)).initialize_or_restore() - for j in range(2): - self.assertEqual(i * 2 + j, self.evaluate(get_next())) - checkpoint.save(file_prefix=checkpoint_prefix) - - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py b/tensorflow/python/data/kernel_tests/list_files_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/list_files_test.py index 7efe3c692a..26c536086b 100644 --- a/tensorflow/python/data/kernel_tests/list_files_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/list_files_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.list_files()`.""" from __future__ import absolute_import from __future__ import division @@ -31,7 +31,7 @@ from tensorflow.python.util import compat @test_util.run_all_in_graph_and_eager_modes -class ListFilesDatasetOpTest(test_base.DatasetTestBase): +class ListFilesTest(test_base.DatasetTestBase): def setUp(self): self.tmp_dir = tempfile.mkdtemp() @@ -208,5 +208,6 @@ class ListFilesDatasetOpTest(test_base.DatasetTestBase): assert_items_equal=True) + if __name__ == '__main__': test.main() diff --git a/tensorflow/python/data/kernel_tests/map_dataset_op_test.py b/tensorflow/python/data/kernel_tests/map_test.py similarity index 90% rename from tensorflow/python/data/kernel_tests/map_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/map_test.py index 187b9da14c..a9c4d79429 100644 --- a/tensorflow/python/data/kernel_tests/map_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/map_test.py @@ -19,7 +19,6 @@ from __future__ import print_function from collections import namedtuple import threading -import time import warnings from absl.testing import parameterized @@ -27,7 +26,6 @@ import numpy as np from tensorflow.core.framework import attr_value_pb2 from tensorflow.core.protobuf import config_pb2 -from tensorflow.python.client import session from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op @@ -521,7 +519,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(init_op) for i in range(10): - self.assertEqual(i * 2 + i ** 2, sess.run(get_next)) + self.assertEqual(i * 2 + i**2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -570,7 +568,7 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(init_op) - self.assertAllEqual(row ** 2, sess.run(get_next)) + self.assertAllEqual(row**2, sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) @@ -1057,108 +1055,5 @@ class MapDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(get_next) -class MapDatasetBenchmark(test.Benchmark): - - def benchmarkChainOfMaps(self): - chain_lengths = [0, 1, 2, 5, 10, 20, 50] - for chain_length in chain_lengths: - for mode in ["general", "single-threaded", "short-circuit"]: - if mode == "general": - map_fn = lambda x: x + 1 - use_inter_op_parallelism = True - print_label = "" - benchmark_label = "" - if mode == "single-threaded": - map_fn = lambda x: x + 1 - use_inter_op_parallelism = False - print_label = " (single threaded mode)" - benchmark_label = "_single_threaded" - if mode == "short-circuit": - map_fn = lambda x: x - use_inter_op_parallelism = True # should not have any significance - print_label = " (short circuit mode)" - benchmark_label = "_short_circuit" - - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors(0).repeat(None) - for _ in range(chain_length): - dataset = dataset_ops.MapDataset( - dataset, - map_fn, - use_inter_op_parallelism=use_inter_op_parallelism) - iterator = dataset.make_one_shot_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for _ in range(5): - sess.run(next_element.op) - deltas = [] - for _ in range(100): - start = time.time() - for _ in range(100): - sess.run(next_element.op) - end = time.time() - deltas.append(end - start) - - median_wall_time = np.median(deltas) / 100 - print("Map dataset chain length%s: %d Median wall time: %f" % - (print_label, chain_length, median_wall_time)) - self.report_benchmark( - iters=1000, - wall_time=median_wall_time, - name="benchmark_map_dataset_chain_latency_%d%s" % - (chain_length, benchmark_label)) - - def benchmarkMapFanOut(self): - fan_outs = [1, 2, 5, 10, 20, 50, 100] - for fan_out in fan_outs: - for mode in ["general", "single-threaded", "short-circuit"]: - if mode == "general": - map_fn = lambda *xs: [x + 1 for x in xs] - use_inter_op_parallelism = True - print_label = "" - benchmark_label = "" - if mode == "single-threaded": - map_fn = lambda *xs: [x + 1 for x in xs] - use_inter_op_parallelism = False - print_label = " (single threaded mode)" - benchmark_label = "_single_threaded" - if mode == "short-circuit": - map_fn = lambda *xs: xs - use_inter_op_parallelism = True # should not have any significance - print_label = " (short circuit mode)" - benchmark_label = "_short_circuit" - - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors( - tuple(0 for _ in range(fan_out))).repeat(None) - dataset = dataset_ops.MapDataset( - dataset, - map_fn, - use_inter_op_parallelism=use_inter_op_parallelism) - iterator = dataset.make_one_shot_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for _ in range(5): - sess.run(next_element[0].op) - deltas = [] - for _ in range(100): - start = time.time() - for _ in range(100): - sess.run(next_element[0].op) - end = time.time() - deltas.append(end - start) - - median_wall_time = np.median(deltas) / 100 - print("Map dataset fan out%s: %d Median wall time: %f" % - (print_label, fan_out, median_wall_time)) - self.report_benchmark( - iters=1000, - wall_time=median_wall_time, - name="benchmark_map_dataset_fan_out_%d%s" % (fan_out, - benchmark_label)) - - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py index afb0939397..2ca9961585 100644 --- a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py +++ b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""MultiDeviceIterator tests.""" +"""Tests for `tf.data.MultiDeviceIterator`.""" from __future__ import absolute_import from __future__ import division @@ -31,7 +31,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.platform import test -# TODO(b/117581999): Add eager coverage for the following tests. +# TODO(b/117581999): Add eager coverage. class MultiDeviceIteratorTest(test_base.DatasetTestBase): def testNoGetNext(self): diff --git a/tensorflow/python/data/kernel_tests/optional_ops_test.py b/tensorflow/python/data/kernel_tests/optional_test.py similarity index 99% rename from tensorflow/python/data/kernel_tests/optional_ops_test.py rename to tensorflow/python/data/kernel_tests/optional_test.py index 5406a202a3..856985e9fd 100644 --- a/tensorflow/python/data/kernel_tests/optional_ops_test.py +++ b/tensorflow/python/data/kernel_tests/optional_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the Optional data type wrapper.""" +"""Tests for `tf.data.Optional`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function diff --git a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/padded_batch_test.py similarity index 58% rename from tensorflow/python/data/kernel_tests/batch_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/padded_batch_test.py index 94c37a0f2c..5f20d7b424 100644 --- a/tensorflow/python/data/kernel_tests/batch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/padded_batch_test.py @@ -13,20 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.padded_batch()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function -import time - from absl.testing import parameterized import numpy as np -from tensorflow.python.client import session from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.util import nest from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors @@ -34,154 +30,17 @@ from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops -from tensorflow.python.ops import math_ops from tensorflow.python.ops import string_ops from tensorflow.python.platform import test from tensorflow.python.util import compat -@test_util.run_all_in_graph_and_eager_modes -class BatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): - - @parameterized.named_parameters( - ('even', 28, 14, False), - ('uneven_with_remainder', 28, 15, False), - ('uneven_without_remainder', 28, 15, True), - ('empty', 0, 14, False), - ) - def testBatchDataset(self, count, batch_size, drop_remainder): - """Tests the batch dataset logic for various input configurations. - - Args: - count: the number of input elements - batch_size: the batch size - drop_remainder: whether a smaller batch size should be produced if batch - size does not divide number of inputs evenly - """ - - # The pipeline is TensorSliceDataset -> MapDataset(square_3) -> - # RepeatDataset(count) -> BatchDataset(batch_size). - components = (np.arange(7), - np.array([[1, 2, 3]]) * np.arange(7)[:, np.newaxis], - np.array(37.0) * np.arange(7)) - - def _map_fn(x, y, z): - return math_ops.square(x), math_ops.square(y), math_ops.square(z) - - dataset = dataset_ops.Dataset.from_tensor_slices(components).map( - _map_fn).repeat(count).batch(batch_size, drop_remainder) - get_next = self.getNext(dataset) - - if drop_remainder: - dim0 = batch_size - else: - dim0 = None - self.assertEqual( - [ts.as_list() for ts in nest.flatten(dataset.output_shapes)], - [[dim0] + list(c.shape[1:]) for c in components]) - - num_full_batches = (count * 7) // batch_size - for i in range(num_full_batches): - result = self.evaluate(get_next()) - for component, result_component in zip(components, result): - for j in range(batch_size): - self.assertAllEqual(component[(i * batch_size + j) % 7]**2, - result_component[j]) - if not drop_remainder and (count * 7) % batch_size > 0: - result = self.evaluate(get_next()) - for component, result_component in zip(components, result): - for j in range((count * 7) % batch_size): - self.assertAllEqual( - component[(num_full_batches * batch_size + j) % 7]**2, - result_component[j]) - with self.assertRaises(errors.OutOfRangeError): - result = self.evaluate(get_next()) - - def testBatchDatasetInvalidBatchSize(self): - dataset = (dataset_ops.Dataset.range(10).batch(0)) - self.assertDatasetProduces( - dataset, expected_error=(errors.InvalidArgumentError, '')) - - def testBatchSparse(self): - - def _sparse(i): - return sparse_tensor.SparseTensorValue( - indices=[[0]], values=(i * [1]), dense_shape=[1]) - - dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5) - expected_output = [ - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], - values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], - dense_shape=[5, 1]) for i in range(2) - ] - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testBatchSparseWithDifferentDenseShapes(self): - - def _sparse(i): - return sparse_tensor.SparseTensorValue( - indices=array_ops.expand_dims( - math_ops.range(i, dtype=dtypes.int64), 1), - values=array_ops.fill([math_ops.to_int32(i)], i), - dense_shape=[i]) - - dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5) - expected_output = [] - for i in range(2): - expected_indices = [] - expected_outputs = [] - for j in range(5): - for k in range(i * 5 + j): - expected_indices.append([j, k]) - expected_outputs.append(i * 5 + j) - expected_output.append( - sparse_tensor.SparseTensorValue( - indices=expected_indices, - values=expected_outputs, - dense_shape=[5, (i + 1) * 5 - 1])) - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testNestedBatchSparse(self): - - def _sparse(i): - return sparse_tensor.SparseTensorValue( - indices=[[0]], values=(i * [1]), dense_shape=[1]) - - dataset = dataset_ops.Dataset.range(10).map(_sparse).batch(5).batch(2) - expected_output = [ - sparse_tensor.SparseTensorValue( - indices=[[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], - [1, 0, 0], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0]], - values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - dense_shape=[2, 5, 1]) - ] - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testBatchShapeError(self): - - def generator(): - yield [1.0, 2.0, 3.0] - yield [4.0, 5.0, 6.0] - yield [7.0, 8.0, 9.0, 10.0] - - dataset = ( - dataset_ops.Dataset.from_generator( - generator, dtypes.float32, output_shapes=[None]).batch(3)) - self.assertDatasetProduces( - dataset, - expected_error=( - errors.InvalidArgumentError, - r'Cannot batch tensors with different shapes in component 0. First ' - r'element had shape \[3\] and element 2 had shape \[4\].')) - - def _random_seq_lens(count): return np.random.randint(20, size=(count,)).astype(np.int32) @test_util.run_all_in_graph_and_eager_modes -class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): +class PaddedBatchTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( ('default_padding', _random_seq_lens(32), 4, [-1], False), @@ -377,56 +236,5 @@ class PaddedBatchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): 5, padded_shapes=shape_as_tensor) -# TODO(b/119837791): Add eager benchmarks too. -class BatchDatasetBenchmark(test.Benchmark): - - def benchmarkBatchSparse(self): - non_zeros_per_row_values = [0, 1, 5, 10, 100] - batch_size_values = [1, 32, 64, 128, 1024] - - sparse_placeholder = array_ops.sparse_placeholder(dtype=dtypes.int64) - batch_size_placeholder = array_ops.placeholder(dtype=dtypes.int64, shape=[]) - - dataset = dataset_ops.Dataset.from_tensors(sparse_placeholder).repeat( - ).batch(batch_size_placeholder) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - for non_zeros_per_row in non_zeros_per_row_values: - - sparse_value = sparse_tensor.SparseTensorValue( - indices=np.arange(non_zeros_per_row, dtype=np.int64)[:, np.newaxis], - values=np.arange(non_zeros_per_row, dtype=np.int64), - dense_shape=[1000]) - - for batch_size in batch_size_values: - - with session.Session() as sess: - sess.run(iterator.initializer, feed_dict={ - sparse_placeholder: sparse_value, - batch_size_placeholder: batch_size}) - # Run five steps to warm up the session caches before taking the - # first measurement. - for _ in range(5): - sess.run(next_element.indices.op) - deltas = [] - for _ in range(100): - start = time.time() - for _ in range(100): - sess.run(next_element.indices.op) - end = time.time() - deltas.append(end - start) - - median_wall_time = np.median(deltas) / 100.0 - - print('Batch sparse dataset non-zeros per row: %d batch_size: %d ' - 'wall time: %f' - % (non_zeros_per_row, batch_size, median_wall_time)) - self.report_benchmark( - iters=10000, wall_time=median_wall_time, - name='benchmark_batch_sparse_dataset_nnz_%d_batch_size_%d' % ( - non_zeros_per_row, batch_size)) - - if __name__ == '__main__': test.main() diff --git a/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py b/tensorflow/python/data/kernel_tests/prefetch_test.py similarity index 93% rename from tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/prefetch_test.py index 41b0689947..a143ba0ac6 100644 --- a/tensorflow/python/data/kernel_tests/prefetch_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/prefetch_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Test PrefetchDataset.""" +"""Tests for `tf.data.Dataset.prefetch()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -27,7 +27,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class PrefetchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): +class PrefetchTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.parameters((-1), (0), (5)) def testBufferSize(self, buffer_size): @@ -40,6 +40,5 @@ class PrefetchDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertDatasetProduces( dataset, expected_error=(errors.InvalidArgumentError, "buffer_size")) - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/range_dataset_op_test.py b/tensorflow/python/data/kernel_tests/range_test.py similarity index 96% rename from tensorflow/python/data/kernel_tests/range_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/range_test.py index 907cb59096..3f5d25e7f3 100644 --- a/tensorflow/python/data/kernel_tests/range_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/range_test.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Test RangeDataset.""" +"""Tests for `tf.data.Dataset.range()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function - from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import errors @@ -26,7 +25,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class RangeDatasetTest(test_base.DatasetTestBase): +class RangeTest(test_base.DatasetTestBase): def testStop(self): dataset = dataset_ops.Dataset.range(5) diff --git a/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py b/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py deleted file mode 100644 index 483a79513a..0000000000 --- a/tensorflow/python/data/kernel_tests/reader_dataset_ops_test.py +++ /dev/null @@ -1,446 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. 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. -# ============================================================================== -"""Tests for the experimental input pipeline ops.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import gzip -import os -import zlib - -from tensorflow.python.data.kernel_tests import test_base -from tensorflow.python.data.ops import dataset_ops -from tensorflow.python.data.ops import readers -from tensorflow.python.eager import context -from tensorflow.python.framework import errors -from tensorflow.python.framework import test_util -from tensorflow.python.lib.io import python_io -from tensorflow.python.platform import test -from tensorflow.python.util import compat - - -try: - import psutil # pylint: disable=g-import-not-at-top - psutil_import_succeeded = True -except ImportError: - psutil_import_succeeded = False - - -@test_util.run_all_in_graph_and_eager_modes -class TextLineDatasetTest(test_base.DatasetTestBase): - - def _lineText(self, f, l): - return compat.as_bytes("%d: %d" % (f, l)) - - def _createFiles(self, - num_files, - num_lines, - crlf=False, - compression_type=None): - filenames = [] - for i in range(num_files): - fn = os.path.join(self.get_temp_dir(), "text_line.%d.txt" % i) - filenames.append(fn) - contents = [] - for j in range(num_lines): - contents.append(self._lineText(i, j)) - # Always include a newline after the record unless it is - # at the end of the file, in which case we include it - if j + 1 != num_lines or i == 0: - contents.append(b"\r\n" if crlf else b"\n") - contents = b"".join(contents) - - if not compression_type: - with open(fn, "wb") as f: - f.write(contents) - elif compression_type == "GZIP": - with gzip.GzipFile(fn, "wb") as f: - f.write(contents) - elif compression_type == "ZLIB": - contents = zlib.compress(contents) - with open(fn, "wb") as f: - f.write(contents) - else: - raise ValueError("Unsupported compression_type", compression_type) - - return filenames - - def _testTextLineDataset(self, compression_type=None): - test_filenames = self._createFiles( - 2, 5, crlf=True, compression_type=compression_type) - - def dataset_fn(filenames, num_epochs, batch_size=None): - repeat_dataset = readers.TextLineDataset( - filenames, compression_type=compression_type).repeat(num_epochs) - if batch_size: - return repeat_dataset.batch(batch_size) - return repeat_dataset - - # Basic test: read from file 0. - expected_output = [self._lineText(0, i) for i in range(5)] - self.assertDatasetProduces( - dataset_fn([test_filenames[0]], 1), expected_output=expected_output) - - # Basic test: read from file 1. - self.assertDatasetProduces( - dataset_fn([test_filenames[1]], 1), - expected_output=[self._lineText(1, i) for i in range(5)]) - - # Basic test: read from both files. - expected_output = [self._lineText(0, i) for i in range(5)] - expected_output.extend([self._lineText(1, i) for i in range(5)]) - self.assertDatasetProduces( - dataset_fn(test_filenames, 1), expected_output=expected_output) - - # Test repeated iteration through both files. - expected_output = [self._lineText(0, i) for i in range(5)] - expected_output.extend([self._lineText(1, i) for i in range(5)]) - self.assertDatasetProduces( - dataset_fn(test_filenames, 10), expected_output=expected_output * 10) - - # Test batched and repeated iteration through both files. - self.assertDatasetProduces( - dataset_fn(test_filenames, 10, 5), - expected_output=[[self._lineText(0, i) for i in range(5)], - [self._lineText(1, i) for i in range(5)]] * 10) - - def testTextLineDatasetNoCompression(self): - self._testTextLineDataset() - - def testTextLineDatasetGzipCompression(self): - self._testTextLineDataset(compression_type="GZIP") - - def testTextLineDatasetZlibCompression(self): - self._testTextLineDataset(compression_type="ZLIB") - - def testTextLineDatasetBuffering(self): - test_filenames = self._createFiles(2, 5, crlf=True) - - repeat_dataset = readers.TextLineDataset(test_filenames, buffer_size=10) - expected_output = [] - for j in range(2): - expected_output.extend([self._lineText(j, i) for i in range(5)]) - self.assertDatasetProduces(repeat_dataset, expected_output=expected_output) - - def testIteratorResourceCleanup(self): - filename = os.path.join(self.get_temp_dir(), "text.txt") - with open(filename, "wt") as f: - for i in range(3): - f.write("%d\n" % (i,)) - with context.eager_mode(): - first_iterator = iter(readers.TextLineDataset(filename)) - self.assertEqual(b"0", next(first_iterator).numpy()) - second_iterator = iter(readers.TextLineDataset(filename)) - self.assertEqual(b"0", next(second_iterator).numpy()) - # Eager kernel caching is based on op attributes, which includes the - # Dataset's output shape. Create a different kernel to test that they - # don't create resources with the same names. - different_kernel_iterator = iter( - readers.TextLineDataset(filename).repeat().batch(16)) - self.assertEqual([16], next(different_kernel_iterator).shape) - # Remove our references to the Python Iterator objects, which (assuming no - # reference cycles) is enough to trigger DestroyResourceOp and close the - # partially-read files. - del first_iterator - del second_iterator - del different_kernel_iterator - if not psutil_import_succeeded: - self.skipTest( - "psutil is required to check that we've closed our files.") - open_files = psutil.Process().open_files() - self.assertNotIn(filename, [open_file.path for open_file in open_files]) - - -class FixedLengthRecordReaderTestBase(test_base.DatasetTestBase): - - def setUp(self): - super(FixedLengthRecordReaderTestBase, self).setUp() - self._num_files = 2 - self._num_records = 7 - self._header_bytes = 5 - self._record_bytes = 3 - self._footer_bytes = 2 - - def _record(self, f, r): - return compat.as_bytes(str(f * 2 + r) * self._record_bytes) - - def _createFiles(self, compression_type=None): - filenames = [] - for i in range(self._num_files): - fn = os.path.join(self.get_temp_dir(), "fixed_length_record.%d.txt" % i) - filenames.append(fn) - - contents = [] - contents.append(b"H" * self._header_bytes) - for j in range(self._num_records): - contents.append(self._record(i, j)) - contents.append(b"F" * self._footer_bytes) - contents = b"".join(contents) - - if not compression_type: - with open(fn, "wb") as f: - f.write(contents) - elif compression_type == "GZIP": - with gzip.GzipFile(fn, "wb") as f: - f.write(contents) - elif compression_type == "ZLIB": - contents = zlib.compress(contents) - with open(fn, "wb") as f: - f.write(contents) - else: - raise ValueError("Unsupported compression_type", compression_type) - - return filenames - - -@test_util.run_all_in_graph_and_eager_modes -class FixedLengthRecordReaderTest(FixedLengthRecordReaderTestBase): - - def _testFixedLengthRecordDataset(self, compression_type=None): - test_filenames = self._createFiles(compression_type=compression_type) - - def dataset_fn(filenames, num_epochs, batch_size=None): - repeat_dataset = readers.FixedLengthRecordDataset( - filenames, - self._record_bytes, - self._header_bytes, - self._footer_bytes, - compression_type=compression_type).repeat(num_epochs) - if batch_size: - return repeat_dataset.batch(batch_size) - return repeat_dataset - - # Basic test: read from file 0. - self.assertDatasetProduces( - dataset_fn([test_filenames[0]], 1), - expected_output=[ - self._record(0, i) for i in range(self._num_records) - ]) - - # Basic test: read from file 1. - self.assertDatasetProduces( - dataset_fn([test_filenames[1]], 1), - expected_output=[ - self._record(1, i) for i in range(self._num_records) - ]) - - # Basic test: read from both files. - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - self.assertDatasetProduces( - dataset_fn(test_filenames, 1), expected_output=expected_output) - - # Test repeated iteration through both files. - get_next = self.getNext(dataset_fn(test_filenames, 10)) - for _ in range(10): - for j in range(self._num_files): - for i in range(self._num_records): - self.assertEqual(self._record(j, i), self.evaluate(get_next())) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) - - # Test batched and repeated iteration through both files. - get_next = self.getNext(dataset_fn(test_filenames, 10, self._num_records)) - for _ in range(10): - for j in range(self._num_files): - self.assertAllEqual( - [self._record(j, i) for i in range(self._num_records)], - self.evaluate(get_next())) - with self.assertRaises(errors.OutOfRangeError): - self.evaluate(get_next()) - - def testFixedLengthRecordDatasetNoCompression(self): - self._testFixedLengthRecordDataset() - - def testFixedLengthRecordDatasetGzipCompression(self): - self._testFixedLengthRecordDataset(compression_type="GZIP") - - def testFixedLengthRecordDatasetZlibCompression(self): - self._testFixedLengthRecordDataset(compression_type="ZLIB") - - def testFixedLengthRecordDatasetBuffering(self): - test_filenames = self._createFiles() - dataset = readers.FixedLengthRecordDataset( - test_filenames, - self._record_bytes, - self._header_bytes, - self._footer_bytes, - buffer_size=10) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testFixedLengthRecordDatasetWrongSize(self): - test_filenames = self._createFiles() - dataset = readers.FixedLengthRecordDataset( - test_filenames, - self._record_bytes + 1, # Incorrect record length. - self._header_bytes, - self._footer_bytes, - buffer_size=10) - self.assertDatasetProduces( - dataset, - expected_error=( - errors.InvalidArgumentError, - r"Excluding the header \(5 bytes\) and footer \(2 bytes\), input " - r"file \".*fixed_length_record.0.txt\" has body length 21 bytes, " - r"which is not an exact multiple of the record length \(4 bytes\).") - ) - - -@test_util.run_all_in_graph_and_eager_modes -class TFRecordDatasetTest(test_base.DatasetTestBase): - - def setUp(self): - super(TFRecordDatasetTest, self).setUp() - self._num_files = 2 - self._num_records = 7 - - self.test_filenames = self._createFiles() - - def dataset_fn(self, - filenames, - compression_type="", - num_epochs=1, - batch_size=None): - - repeat_dataset = readers.TFRecordDataset( - filenames, compression_type).repeat(num_epochs) - if batch_size: - return repeat_dataset.batch(batch_size) - return repeat_dataset - - def _record(self, f, r): - return compat.as_bytes("Record %d of file %d" % (r, f)) - - def _createFiles(self): - filenames = [] - for i in range(self._num_files): - fn = os.path.join(self.get_temp_dir(), "tf_record.%d.txt" % i) - filenames.append(fn) - writer = python_io.TFRecordWriter(fn) - for j in range(self._num_records): - writer.write(self._record(i, j)) - writer.close() - return filenames - - def testReadOneEpoch(self): - # Basic test: read from file 0. - dataset = self.dataset_fn(self.test_filenames[0]) - self.assertDatasetProduces( - dataset, - expected_output=[self._record(0, i) for i in range(self._num_records)]) - - # Basic test: read from file 1. - dataset = self.dataset_fn(self.test_filenames[1]) - self.assertDatasetProduces( - dataset, - expected_output=[self._record(1, i) for i in range(self._num_records)]) - - # Basic test: read from both files. - dataset = self.dataset_fn(self.test_filenames) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testReadTenEpochs(self): - dataset = self.dataset_fn(self.test_filenames, num_epochs=10) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - self.assertDatasetProduces(dataset, expected_output=expected_output * 10) - - def testReadTenEpochsOfBatches(self): - dataset = self.dataset_fn( - self.test_filenames, num_epochs=10, batch_size=self._num_records) - expected_output = [] - for j in range(self._num_files): - expected_output.append( - [self._record(j, i) for i in range(self._num_records)]) - self.assertDatasetProduces(dataset, expected_output=expected_output * 10) - - def testReadZlibFiles(self): - zlib_files = [] - for i, fn in enumerate(self.test_filenames): - with open(fn, "rb") as f: - cdata = zlib.compress(f.read()) - - zfn = os.path.join(self.get_temp_dir(), "tfrecord_%s.z" % i) - with open(zfn, "wb") as f: - f.write(cdata) - zlib_files.append(zfn) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - dataset = self.dataset_fn(zlib_files, compression_type="ZLIB") - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testReadGzipFiles(self): - gzip_files = [] - for i, fn in enumerate(self.test_filenames): - with open(fn, "rb") as f: - gzfn = os.path.join(self.get_temp_dir(), "tfrecord_%s.gz" % i) - with gzip.GzipFile(gzfn, "wb") as gzf: - gzf.write(f.read()) - gzip_files.append(gzfn) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - dataset = self.dataset_fn(gzip_files, compression_type="GZIP") - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testReadWithBuffer(self): - one_mebibyte = 2**20 - dataset = readers.TFRecordDataset( - self.test_filenames, buffer_size=one_mebibyte) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testReadFromDatasetOfFiles(self): - files = dataset_ops.Dataset.from_tensor_slices(self.test_filenames) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - dataset = readers.TFRecordDataset(files) - self.assertDatasetProduces(dataset, expected_output=expected_output) - - def testReadTenEpochsFromDatasetOfFilesInParallel(self): - files = dataset_ops.Dataset.from_tensor_slices( - self.test_filenames).repeat(10) - expected_output = [] - for j in range(self._num_files): - expected_output.extend( - [self._record(j, i) for i in range(self._num_records)]) - dataset = readers.TFRecordDataset(files, num_parallel_reads=4) - self.assertDatasetProduces( - dataset, expected_output=expected_output * 10, assert_items_equal=True) - - -if __name__ == "__main__": - test.main() diff --git a/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py b/tensorflow/python/data/kernel_tests/reduce_test.py similarity index 97% rename from tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/reduce_test.py index 061f0d1343..d7b653961d 100644 --- a/tensorflow/python/data/kernel_tests/reduce_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/reduce_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.reduce()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -32,7 +32,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class ReduceDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): +class ReduceTest(test_base.DatasetTestBase, parameterized.TestCase): def testSum(self): for i in range(10): diff --git a/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py b/tensorflow/python/data/kernel_tests/repeat_test.py similarity index 67% rename from tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/repeat_test.py index 6da4e0dfca..4ef2fc1bfc 100644 --- a/tensorflow/python/data/kernel_tests/sequence_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/repeat_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.repeat()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -26,7 +26,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class SequenceDatasetTest(test_base.DatasetTestBase): +class RepeatTest(test_base.DatasetTestBase): def testRepeatTensorDataset(self): """Test a dataset that repeats its input multiple times.""" @@ -62,57 +62,6 @@ class SequenceDatasetTest(test_base.DatasetTestBase): for component, result_component in zip(components, results): self.assertAllEqual(component, result_component) - def testTakeTensorDataset(self): - components = (np.arange(10),) - - def do_test(count): - dataset = dataset_ops.Dataset.from_tensor_slices(components).take(count) - self.assertEqual([c.shape[1:] for c in components], - [shape for shape in dataset.output_shapes]) - num_output = min(count, 10) if count != -1 else 10 - self.assertDatasetProduces( - dataset, [tuple(components[0][i:i + 1]) for i in range(num_output)]) - - # Take fewer than input size - do_test(4) - - # Take more than input size - do_test(25) - - # Take all of input - do_test(-1) - - # Take nothing - do_test(0) - - def testSkipTensorDataset(self): - components = (np.arange(10),) - - def do_test(count): - dataset = dataset_ops.Dataset.from_tensor_slices(components).skip(count) - self.assertEqual([c.shape[1:] for c in components], - [shape for shape in dataset.output_shapes]) - start_range = min(count, 10) if count != -1 else 10 - self.assertDatasetProduces( - dataset, - [tuple(components[0][i:i + 1]) for i in range(start_range, 10)]) - - # Skip fewer than input size, we should skip - # the first 4 elements and then read the rest. - do_test(4) - - # Skip more than input size: get nothing. - do_test(25) - - # Skip exactly input size. - do_test(10) - - # Set -1 for 'count': skip the entire dataset. - do_test(-1) - - # Skip nothing - do_test(0) - def testRepeatRepeatTensorDataset(self): """Test the composition of repeat datasets.""" components = (np.array(1), np.array([1, 2, 3]), np.array(37.0)) diff --git a/tensorflow/python/data/kernel_tests/shard_dataset_op_test.py b/tensorflow/python/data/kernel_tests/shard_test.py similarity index 96% rename from tensorflow/python/data/kernel_tests/shard_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/shard_test.py index 7dd932d015..928550676d 100644 --- a/tensorflow/python/data/kernel_tests/shard_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/shard_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.shard()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -24,7 +24,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class ShardDatasetOpTest(test_base.DatasetTestBase): +class ShardTest(test_base.DatasetTestBase): def testSimpleCase(self): dataset = dataset_ops.Dataset.range(10).shard(5, 2) @@ -72,6 +72,5 @@ class ShardDatasetOpTest(test_base.DatasetTestBase): dataset = dataset_ops.Dataset.range(10).shard(4, 3) self.assertDatasetProduces(dataset, expected_output=[3, 7]) - if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py b/tensorflow/python/data/kernel_tests/shuffle_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/shuffle_test.py index bf8303ca6e..49460a1a4e 100644 --- a/tensorflow/python/data/kernel_tests/shuffle_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/shuffle_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.shuffle()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -35,7 +35,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class ShuffleDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): +class ShuffleTest(test_base.DatasetTestBase, parameterized.TestCase): def testShuffleDataset(self): components = ( diff --git a/tensorflow/python/data/kernel_tests/skip_test.py b/tensorflow/python/data/kernel_tests/skip_test.py new file mode 100644 index 0000000000..c22be57692 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/skip_test.py @@ -0,0 +1,62 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.Dataset.skip()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import test_util +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class SkipTest(test_base.DatasetTestBase): + + def testSkipTensorDataset(self): + components = (np.arange(10),) + + def do_test(count): + dataset = dataset_ops.Dataset.from_tensor_slices(components).skip(count) + self.assertEqual([c.shape[1:] for c in components], + [shape for shape in dataset.output_shapes]) + start_range = min(count, 10) if count != -1 else 10 + self.assertDatasetProduces( + dataset, + [tuple(components[0][i:i + 1]) for i in range(start_range, 10)]) + + # Skip fewer than input size, we should skip + # the first 4 elements and then read the rest. + do_test(4) + + # Skip more than input size: get nothing. + do_test(25) + + # Skip exactly input size. + do_test(10) + + # Set -1 for 'count': skip the entire dataset. + do_test(-1) + + # Skip nothing + do_test(0) + + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/take_test.py b/tensorflow/python/data/kernel_tests/take_test.py new file mode 100644 index 0000000000..03a7ece2d8 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/take_test.py @@ -0,0 +1,55 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.Dataset.take()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import test_util +from tensorflow.python.platform import test + + +@test_util.run_all_in_graph_and_eager_modes +class TakeTest(test_base.DatasetTestBase): + + def testTakeTensorDataset(self): + components = (np.arange(10),) + + def do_test(count): + dataset = dataset_ops.Dataset.from_tensor_slices(components).take(count) + self.assertEqual([c.shape[1:] for c in components], + [shape for shape in dataset.output_shapes]) + num_output = min(count, 10) if count != -1 else 10 + self.assertDatasetProduces( + dataset, [tuple(components[0][i:i + 1]) for i in range(num_output)]) + + # Take fewer than input size + do_test(4) + + # Take more than input size + do_test(25) + + # Take all of input + do_test(-1) + + # Take nothing + do_test(0) + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/text_line_dataset_test.py b/tensorflow/python/data/kernel_tests/text_line_dataset_test.py new file mode 100644 index 0000000000..4db09a9808 --- /dev/null +++ b/tensorflow/python/data/kernel_tests/text_line_dataset_test.py @@ -0,0 +1,165 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.TextLineDataset`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gzip +import os +import zlib + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import readers +from tensorflow.python.eager import context +from tensorflow.python.framework import test_util +from tensorflow.python.platform import test +from tensorflow.python.util import compat + + +try: + import psutil # pylint: disable=g-import-not-at-top + psutil_import_succeeded = True +except ImportError: + psutil_import_succeeded = False + + +@test_util.run_all_in_graph_and_eager_modes +class TextLineDatasetTest(test_base.DatasetTestBase): + + def _lineText(self, f, l): + return compat.as_bytes("%d: %d" % (f, l)) + + def _createFiles(self, + num_files, + num_lines, + crlf=False, + compression_type=None): + filenames = [] + for i in range(num_files): + fn = os.path.join(self.get_temp_dir(), "text_line.%d.txt" % i) + filenames.append(fn) + contents = [] + for j in range(num_lines): + contents.append(self._lineText(i, j)) + # Always include a newline after the record unless it is + # at the end of the file, in which case we include it + if j + 1 != num_lines or i == 0: + contents.append(b"\r\n" if crlf else b"\n") + contents = b"".join(contents) + + if not compression_type: + with open(fn, "wb") as f: + f.write(contents) + elif compression_type == "GZIP": + with gzip.GzipFile(fn, "wb") as f: + f.write(contents) + elif compression_type == "ZLIB": + contents = zlib.compress(contents) + with open(fn, "wb") as f: + f.write(contents) + else: + raise ValueError("Unsupported compression_type", compression_type) + + return filenames + + def _testTextLineDataset(self, compression_type=None): + test_filenames = self._createFiles( + 2, 5, crlf=True, compression_type=compression_type) + + def dataset_fn(filenames, num_epochs, batch_size=None): + repeat_dataset = readers.TextLineDataset( + filenames, compression_type=compression_type).repeat(num_epochs) + if batch_size: + return repeat_dataset.batch(batch_size) + return repeat_dataset + + # Basic test: read from file 0. + expected_output = [self._lineText(0, i) for i in range(5)] + self.assertDatasetProduces( + dataset_fn([test_filenames[0]], 1), expected_output=expected_output) + + # Basic test: read from file 1. + self.assertDatasetProduces( + dataset_fn([test_filenames[1]], 1), + expected_output=[self._lineText(1, i) for i in range(5)]) + + # Basic test: read from both files. + expected_output = [self._lineText(0, i) for i in range(5)] + expected_output.extend([self._lineText(1, i) for i in range(5)]) + self.assertDatasetProduces( + dataset_fn(test_filenames, 1), expected_output=expected_output) + + # Test repeated iteration through both files. + expected_output = [self._lineText(0, i) for i in range(5)] + expected_output.extend([self._lineText(1, i) for i in range(5)]) + self.assertDatasetProduces( + dataset_fn(test_filenames, 10), expected_output=expected_output * 10) + + # Test batched and repeated iteration through both files. + self.assertDatasetProduces( + dataset_fn(test_filenames, 10, 5), + expected_output=[[self._lineText(0, i) for i in range(5)], + [self._lineText(1, i) for i in range(5)]] * 10) + + def testTextLineDatasetNoCompression(self): + self._testTextLineDataset() + + def testTextLineDatasetGzipCompression(self): + self._testTextLineDataset(compression_type="GZIP") + + def testTextLineDatasetZlibCompression(self): + self._testTextLineDataset(compression_type="ZLIB") + + def testTextLineDatasetBuffering(self): + test_filenames = self._createFiles(2, 5, crlf=True) + + repeat_dataset = readers.TextLineDataset(test_filenames, buffer_size=10) + expected_output = [] + for j in range(2): + expected_output.extend([self._lineText(j, i) for i in range(5)]) + self.assertDatasetProduces(repeat_dataset, expected_output=expected_output) + + def testIteratorResourceCleanup(self): + filename = os.path.join(self.get_temp_dir(), "text.txt") + with open(filename, "wt") as f: + for i in range(3): + f.write("%d\n" % (i,)) + with context.eager_mode(): + first_iterator = iter(readers.TextLineDataset(filename)) + self.assertEqual(b"0", next(first_iterator).numpy()) + second_iterator = iter(readers.TextLineDataset(filename)) + self.assertEqual(b"0", next(second_iterator).numpy()) + # Eager kernel caching is based on op attributes, which includes the + # Dataset's output shape. Create a different kernel to test that they + # don't create resources with the same names. + different_kernel_iterator = iter( + readers.TextLineDataset(filename).repeat().batch(16)) + self.assertEqual([16], next(different_kernel_iterator).shape) + # Remove our references to the Python Iterator objects, which (assuming no + # reference cycles) is enough to trigger DestroyResourceOp and close the + # partially-read files. + del first_iterator + del second_iterator + del different_kernel_iterator + if not psutil_import_succeeded: + self.skipTest( + "psutil is required to check that we've closed our files.") + open_files = psutil.Process().open_files() + self.assertNotIn(filename, [open_file.path for open_file in open_files]) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/tf_record_dataset_test.py b/tensorflow/python/data/kernel_tests/tf_record_dataset_test.py new file mode 100644 index 0000000000..13a70aa88d --- /dev/null +++ b/tensorflow/python/data/kernel_tests/tf_record_dataset_test.py @@ -0,0 +1,170 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.TFRecordDataset`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gzip +import os +import zlib + +from tensorflow.python.data.kernel_tests import test_base +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.data.ops import readers +from tensorflow.python.framework import test_util +from tensorflow.python.lib.io import python_io +from tensorflow.python.platform import test +from tensorflow.python.util import compat + + +@test_util.run_all_in_graph_and_eager_modes +class TFRecordDatasetTest(test_base.DatasetTestBase): + + def setUp(self): + super(TFRecordDatasetTest, self).setUp() + self._num_files = 2 + self._num_records = 7 + + self.test_filenames = self._createFiles() + + def dataset_fn(self, + filenames, + compression_type="", + num_epochs=1, + batch_size=None): + + repeat_dataset = readers.TFRecordDataset( + filenames, compression_type).repeat(num_epochs) + if batch_size: + return repeat_dataset.batch(batch_size) + return repeat_dataset + + def _record(self, f, r): + return compat.as_bytes("Record %d of file %d" % (r, f)) + + def _createFiles(self): + filenames = [] + for i in range(self._num_files): + fn = os.path.join(self.get_temp_dir(), "tf_record.%d.txt" % i) + filenames.append(fn) + writer = python_io.TFRecordWriter(fn) + for j in range(self._num_records): + writer.write(self._record(i, j)) + writer.close() + return filenames + + def testReadOneEpoch(self): + # Basic test: read from file 0. + dataset = self.dataset_fn(self.test_filenames[0]) + self.assertDatasetProduces( + dataset, + expected_output=[self._record(0, i) for i in range(self._num_records)]) + + # Basic test: read from file 1. + dataset = self.dataset_fn(self.test_filenames[1]) + self.assertDatasetProduces( + dataset, + expected_output=[self._record(1, i) for i in range(self._num_records)]) + + # Basic test: read from both files. + dataset = self.dataset_fn(self.test_filenames) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testReadTenEpochs(self): + dataset = self.dataset_fn(self.test_filenames, num_epochs=10) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output * 10) + + def testReadTenEpochsOfBatches(self): + dataset = self.dataset_fn( + self.test_filenames, num_epochs=10, batch_size=self._num_records) + expected_output = [] + for j in range(self._num_files): + expected_output.append( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output * 10) + + def testReadZlibFiles(self): + zlib_files = [] + for i, fn in enumerate(self.test_filenames): + with open(fn, "rb") as f: + cdata = zlib.compress(f.read()) + + zfn = os.path.join(self.get_temp_dir(), "tfrecord_%s.z" % i) + with open(zfn, "wb") as f: + f.write(cdata) + zlib_files.append(zfn) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = self.dataset_fn(zlib_files, compression_type="ZLIB") + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testReadGzipFiles(self): + gzip_files = [] + for i, fn in enumerate(self.test_filenames): + with open(fn, "rb") as f: + gzfn = os.path.join(self.get_temp_dir(), "tfrecord_%s.gz" % i) + with gzip.GzipFile(gzfn, "wb") as gzf: + gzf.write(f.read()) + gzip_files.append(gzfn) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = self.dataset_fn(gzip_files, compression_type="GZIP") + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testReadWithBuffer(self): + one_mebibyte = 2**20 + dataset = readers.TFRecordDataset( + self.test_filenames, buffer_size=one_mebibyte) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testReadFromDatasetOfFiles(self): + files = dataset_ops.Dataset.from_tensor_slices(self.test_filenames) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = readers.TFRecordDataset(files) + self.assertDatasetProduces(dataset, expected_output=expected_output) + + def testReadTenEpochsFromDatasetOfFilesInParallel(self): + files = dataset_ops.Dataset.from_tensor_slices( + self.test_filenames).repeat(10) + expected_output = [] + for j in range(self._num_files): + expected_output.extend( + [self._record(j, i) for i in range(self._num_records)]) + dataset = readers.TFRecordDataset(files, num_parallel_reads=4) + self.assertDatasetProduces( + dataset, expected_output=expected_output * 10, assert_items_equal=True) + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/kernel_tests/window_dataset_op_test.py b/tensorflow/python/data/kernel_tests/window_test.py similarity index 98% rename from tensorflow/python/data/kernel_tests/window_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/window_test.py index 7124cc75f1..d083142ab6 100644 --- a/tensorflow/python/data/kernel_tests/window_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/window_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.window()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -33,7 +33,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class WindowDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): +class WindowTest(test_base.DatasetTestBase, parameterized.TestCase): @parameterized.named_parameters( ("1", 20, 14, 7, 1), diff --git a/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py b/tensorflow/python/data/kernel_tests/zip_test.py similarity index 97% rename from tensorflow/python/data/kernel_tests/zip_dataset_op_test.py rename to tensorflow/python/data/kernel_tests/zip_test.py index c86765addc..477c9fa7da 100644 --- a/tensorflow/python/data/kernel_tests/zip_dataset_op_test.py +++ b/tensorflow/python/data/kernel_tests/zip_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for the experimental input pipeline ops.""" +"""Tests for `tf.data.Dataset.zip()`.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -28,7 +28,7 @@ from tensorflow.python.platform import test @test_util.run_all_in_graph_and_eager_modes -class ZipDatasetTest(test_base.DatasetTestBase): +class ZipTest(test_base.DatasetTestBase): def testZipDataset(self): -- GitLab From b8e155c4a05dca07fcc5505cd773f849e93be7a4 Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Mon, 26 Nov 2018 15:41:59 -0800 Subject: [PATCH 349/672] Place all nodes on CPU in conv_ops_test (FusedConv2D) PiperOrigin-RevId: 222900089 --- tensorflow/core/kernels/conv_ops_test.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tensorflow/core/kernels/conv_ops_test.cc b/tensorflow/core/kernels/conv_ops_test.cc index ef27dfec54..bf98acdecf 100644 --- a/tensorflow/core/kernels/conv_ops_test.cc +++ b/tensorflow/core/kernels/conv_ops_test.cc @@ -550,6 +550,12 @@ class FusedConv2DOpTest : public OpsTestBase { tensorflow::GraphDef graph; TF_ASSERT_OK(root.ToGraphDef(&graph)); + // `FusedConv2D` is available only on CPU, and in this test we don't want to + // compare GPU vs CPU numbers, so place all nodes on CPU. + for (NodeDef& mutable_node : *graph.mutable_node()) { + mutable_node.set_device("/device:CPU:0"); + } + // Disable Grappler constant folding for the test graphs. tensorflow::SessionOptions session_options; tensorflow::RewriterConfig* cfg = -- GitLab From 9339900d3dad8f3cf81beb9924a94f237799057f Mon Sep 17 00:00:00 2001 From: Martin Wicke Date: Mon, 26 Nov 2018 15:51:36 -0800 Subject: [PATCH 350/672] Install converter as a command line utility in the pip package. RELNOTES: Add a command line tool to convert to TF2.0 PiperOrigin-RevId: 222901543 --- tensorflow/tools/pip_package/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index e164853428..001aa22227 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -107,6 +107,7 @@ CONSOLE_SCRIPTS = [ # TensorBoard command, pip will inappropriately remove it during install, # even though the command is not removed, just moved to a different wheel. 'tensorboard = tensorboard.main:run_main', + 'tf_upgrade_v2 = tensorflow.python.tools.compatibility.tf_upgrade_v2:main', ] # pylint: enable=line-too-long -- GitLab From ea3b3dd2af17f96c88d357d993e851d9850908b4 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Mon, 26 Nov 2018 16:07:01 -0800 Subject: [PATCH 351/672] Add templated function to test other datatypes. --- .../tensorrt/convert/convert_nodes_test.cc | 87 +++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 312375a661..471382894c 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -151,6 +151,27 @@ void ExpectTrtDimsEqualsArray(const std::vector& lhs, << " actual: " << DebugString(rhs); } +template +void ExpectArrayNear(const std::vector& lhs, + const std::vector& rhs) { + ASSERT_EQ(lhs.size(), rhs.size()); + for (int i = 0; i < lhs.size(); i++) { + EXPECT_FLOAT_EQ(lhs[i], rhs[i]); + } +} + +// Eigen::half cannot implicitly convert to float which is required for +// EXPECT_FLOAT_EQ. +template <> +void ExpectArrayNear(const std::vector& lhs, + const std::vector& rhs) { + ASSERT_EQ(lhs.size(), rhs.size()); + for (int i = 0; i < lhs.size(); i++) { + EXPECT_FLOAT_EQ(Eigen::half_impl::half_to_float(lhs[i]), + Eigen::half_impl::half_to_float(rhs[i])); + } +} + bool TrtShapedWeightsEquals(const TRT_ShapedWeights& lhs, const TRT_ShapedWeights& rhs) { return TrtDimsEquals(lhs.shape_, rhs.shape_) && lhs.type_ == rhs.type_ && @@ -1964,6 +1985,38 @@ TEST_F(OpConverterTest, ConvertRelu6) { } } +template +void TestConvertSquare(OpConverterTest* test) { + test->Reset(); + typedef typename EnumToDataType::Type CType; + + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), dtype); + auto square = ops::Square(s.WithOpName("my_square"), input); + NodeDef node_def = square.operation.node()->def(); + + test->AddTestTensor("input", {1, 20}); + test->RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(test->GetTensorOrWeights("my_square", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray({1, 20}, output.tensor()->getDimensions()); + + const int num_inputs = 20; + std::vector input_data(num_inputs); + std::vector expected_output_data(num_inputs); + for (int i = 0; i < 20; i++) { + const CType value = CType(i - 9); + input_data[i] = value; + expected_output_data[i] = value * value; + } + std::vector output_data(num_inputs); + test->BuildAndRun( + {{"input", input_data}}, "my_square", + &output_data); + ExpectArrayNear(expected_output_data, output_data); +} + TEST_F(OpConverterTest, ConvertSquare) { { // Input list is empty, should fail. @@ -1972,38 +2025,22 @@ TEST_F(OpConverterTest, ConvertSquare) { node_def, error::INVALID_ARGUMENT, "Square expects one input, at my_square"); } - - // Get the NodeDef for Square. - Scope s = Scope::NewRootScope(); - auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); - auto square = ops::Square(s.WithOpName("my_square"), input); - const NodeDef& node_def = square.operation.node()->def(); - { // Input is weights, should fail. Reset(); - AddTestWeights("input", {1, 2, 3}, {1, 2, 3, 4, -5, 6}); + Scope s = Scope::NewRootScope(); + auto input = ops::Placeholder(s.WithOpName("input"), DT_FLOAT); + auto square = ops::Square(s.WithOpName("my_square"), input); + NodeDef node_def = square.operation.node()->def(); + AddTestWeights("input", {1, 2, 3}, {1, 2, 3, 4, -5, 6}); RunValidationAndConversion(node_def, error::UNIMPLEMENTED, "Square is only implemented for tensors, at my_square"); } - { - // Input is tensor, Ok. - Reset(); - AddTestTensor("input", {1, 2, 3}); - RunValidationAndConversion(node_def); - TRT_TensorOrWeights output; - TF_EXPECT_OK(GetTensorOrWeights("my_square", &output)); - EXPECT_TRUE(output.is_tensor()); - EXPECT_TRUE(TrtDimsEqualsArray({1, 2, 3}, output.tensor()->getDimensions())) - << output.DebugString(); - std::vector output_data(6); - std::vector expected_output_data = {1, 4, 9, 16, 25, 36}; - BuildAndRun("input", {1, 2, 3, 4, -5, 6}, "my_square", &output_data); - for (int i = 0; i < output_data.size(); i++) { - EXPECT_FLOAT_EQ(output_data[i], expected_output_data[i]); - } - } + // OK. Note that kINT32 is not supported by IElementWiseLayer, so we don't + // test DT_INT32 type here. + TestConvertSquare(this); + TestConvertSquare(this); } } // namespace convert -- GitLab From 22f789130667cd58cb33a6f63774a7b08be19dec Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 16:05:07 -0800 Subject: [PATCH 352/672] nn.dilation2d changes for TF 2.0 API Renames `filter` parameter to `filters`, `rates` to `dilations`, adds data_format parameter. PiperOrigin-RevId: 222903663 --- .../python_api/api_def_Dilation2D.pbtxt | 1 + tensorflow/python/ops/nn_ops.py | 67 +++++++++++++++++++ .../tools/api/golden/v2/tensorflow.nn.pbtxt | 2 +- tensorflow/tools/compatibility/renames_v2.py | 46 ++++++++++--- .../tools/compatibility/tf_upgrade_v2.py | 4 ++ 5 files changed, 110 insertions(+), 10 deletions(-) diff --git a/tensorflow/core/api_def/python_api/api_def_Dilation2D.pbtxt b/tensorflow/core/api_def/python_api/api_def_Dilation2D.pbtxt index 6d73ecf1bb..1bd83d9061 100644 --- a/tensorflow/core/api_def/python_api/api_def_Dilation2D.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_Dilation2D.pbtxt @@ -2,5 +2,6 @@ op { graph_op_name: "Dilation2D" endpoint { name: "nn.dilation2d" + deprecation_version: 2 } } diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 755c8ffcd2..0e39dd0fa0 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -207,6 +207,73 @@ class _NonAtrousConvolution(object): name=self.name) +@tf_export("nn.dilation2d", v1=[]) +def dilation2d_v2( + input, # pylint: disable=redefined-builtin + filters, # pylint: disable=redefined-builtin + strides, + padding, + data_format, + dilations, + name=None): + """Computes the grayscale dilation of 4-D `input` and 3-D `filters` tensors. + + The `input` tensor has shape `[batch, in_height, in_width, depth]` and the + `filters` tensor has shape `[filter_height, filter_width, depth]`, i.e., each + input channel is processed independently of the others with its own + structuring function. The `output` tensor has shape + `[batch, out_height, out_width, depth]`. The spatial dimensions of the output + tensor depend on the `padding` algorithm. We currently only support the + default "NHWC" `data_format`. + + In detail, the grayscale morphological 2-D dilation is the max-sum correlation + (for consistency with `conv2d`, we use unmirrored filters): + + output[b, y, x, c] = + max_{dy, dx} input[b, + strides[1] * y + rates[1] * dy, + strides[2] * x + rates[2] * dx, + c] + + filters[dy, dx, c] + + Max-pooling is a special case when the filter has size equal to the pooling + kernel size and contains all zeros. + + Note on duality: The dilation of `input` by the `filters` is equal to the + negation of the erosion of `-input` by the reflected `filters`. + + Args: + input: A `Tensor`. Must be one of the following types: `float32`, `float64`, + `int32`, `uint8`, `int16`, `int8`, `int64`, `bfloat16`, `uint16`, `half`, + `uint32`, `uint64`. + 4-D with shape `[batch, in_height, in_width, depth]`. + filters: A `Tensor`. Must have the same type as `input`. + 3-D with shape `[filter_height, filter_width, depth]`. + strides: A list of `ints` that has length `>= 4`. + The stride of the sliding window for each dimension of the input + tensor. Must be: `[1, stride_height, stride_width, 1]`. + padding: A `string` from: `"SAME", "VALID"`. + The type of padding algorithm to use. + data_format: A `string`, only `"NCHW"` is currently supported. + dilations: A list of `ints` that has length `>= 4`. + The input stride for atrous morphological dilation. Must be: + `[1, rate_height, rate_width, 1]`. + name: A name for the operation (optional). + + Returns: + A `Tensor`. Has the same type as `input`. + """ + if data_format != "NCHW": + raise ValueError("Data formats other than NCHW are not yet supported") + + return gen_nn_ops.dilation2d(input=input, + filter=filters, + strides=strides, + rates=dilations, + padding=padding, + name=name) + + @tf_export("nn.with_space_to_batch") def with_space_to_batch( input, # pylint: disable=redefined-builtin diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index 035a6c76f6..77b5887c1f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -122,7 +122,7 @@ tf_module { } member_method { name: "dilation2d" - argspec: "args=[\'input\', \'filter\', \'strides\', \'rates\', \'padding\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + argspec: "args=[\'input\', \'filters\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "dropout" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index e01360a060..fc4b19fb1c 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -321,7 +321,38 @@ renames = { 'tf.matrix_transpose': 'tf.linalg.transpose', 'tf.matrix_triangular_solve': 'tf.linalg.triangular_solve', 'tf.metrics.accuracy': 'tf.compat.v1.metrics.accuracy', + 'tf.metrics.auc': 'tf.compat.v1.metrics.auc', + 'tf.metrics.average_precision_at_k': 'tf.compat.v1.metrics.average_precision_at_k', + 'tf.metrics.false_negatives': 'tf.compat.v1.metrics.false_negatives', + 'tf.metrics.false_negatives_at_thresholds': 'tf.compat.v1.metrics.false_negatives_at_thresholds', + 'tf.metrics.false_positives': 'tf.compat.v1.metrics.false_positives', + 'tf.metrics.false_positives_at_thresholds': 'tf.compat.v1.metrics.false_positives_at_thresholds', 'tf.metrics.mean': 'tf.compat.v1.metrics.mean', + 'tf.metrics.mean_absolute_error': 'tf.compat.v1.metrics.mean_absolute_error', + 'tf.metrics.mean_cosine_distance': 'tf.compat.v1.metrics.mean_cosine_distance', + 'tf.metrics.mean_iou': 'tf.compat.v1.metrics.mean_iou', + 'tf.metrics.mean_per_class_accuracy': 'tf.compat.v1.metrics.mean_per_class_accuracy', + 'tf.metrics.mean_relative_error': 'tf.compat.v1.metrics.mean_relative_error', + 'tf.metrics.mean_squared_error': 'tf.compat.v1.metrics.mean_squared_error', + 'tf.metrics.mean_tensor': 'tf.compat.v1.metrics.mean_tensor', + 'tf.metrics.percentage_below': 'tf.compat.v1.metrics.percentage_below', + 'tf.metrics.precision': 'tf.compat.v1.metrics.precision', + 'tf.metrics.precision_at_k': 'tf.compat.v1.metrics.precision_at_k', + 'tf.metrics.precision_at_thresholds': 'tf.compat.v1.metrics.precision_at_thresholds', + 'tf.metrics.precision_at_top_k': 'tf.compat.v1.metrics.precision_at_top_k', + 'tf.metrics.recall': 'tf.compat.v1.metrics.recall', + 'tf.metrics.recall_at_k': 'tf.compat.v1.metrics.recall_at_k', + 'tf.metrics.recall_at_thresholds': 'tf.compat.v1.metrics.recall_at_thresholds', + 'tf.metrics.recall_at_top_k': 'tf.compat.v1.metrics.recall_at_top_k', + 'tf.metrics.root_mean_squared_error': 'tf.compat.v1.metrics.root_mean_squared_error', + 'tf.metrics.sensitivity_at_specificity': 'tf.compat.v1.metrics.sensitivity_at_specificity', + 'tf.metrics.sparse_average_precision_at_k': 'tf.compat.v1.metrics.sparse_average_precision_at_k', + 'tf.metrics.sparse_precision_at_k': 'tf.compat.v1.metrics.sparse_precision_at_k', + 'tf.metrics.specificity_at_sensitivity': 'tf.compat.v1.metrics.specificity_at_sensitivity', + 'tf.metrics.true_negatives': 'tf.compat.v1.metrics.true_negatives', + 'tf.metrics.true_negatives_at_thresholds': 'tf.compat.v1.metrics.true_negatives_at_thresholds', + 'tf.metrics.true_positives': 'tf.compat.v1.metrics.true_positives', + 'tf.metrics.true_positives_at_thresholds': 'tf.compat.v1.metrics.true_positives_at_thresholds', 'tf.min_max_variable_partitioner': 'tf.compat.v1.min_max_variable_partitioner', 'tf.model_variables': 'tf.compat.v1.model_variables', 'tf.moving_average_variables': 'tf.compat.v1.moving_average_variables', @@ -352,8 +383,8 @@ renames = { 'tf.nn.xw_plus_b': 'tf.compat.v1.nn.xw_plus_b', 'tf.op_scope': 'tf.compat.v1.op_scope', 'tf.orthogonal_initializer': 'tf.keras.initializers.Orthogonal', - 'tf.parse_example': 'tf.io.parse_example', - 'tf.parse_single_example': 'tf.io.parse_single_example', + 'tf.parse_example': 'tf.compat.v1.parse_example', + 'tf.parse_single_example': 'tf.compat.v1.parse_single_example', 'tf.parse_single_sequence_example': 'tf.io.parse_single_sequence_example', 'tf.parse_tensor': 'tf.io.parse_tensor', 'tf.placeholder': 'tf.compat.v1.placeholder', @@ -390,7 +421,7 @@ renames = { 'tf.read_file': 'tf.io.read_file', 'tf.real': 'tf.math.real', 'tf.reciprocal': 'tf.math.reciprocal', - 'tf.reduce_join': 'tf.strings.reduce_join', + 'tf.reduce_join': 'tf.compat.v1.reduce_join', 'tf.regex_replace': 'tf.strings.regex_replace', 'tf.report_uninitialized_variables': 'tf.compat.v1.report_uninitialized_variables', 'tf.reset_default_graph': 'tf.compat.v1.reset_default_graph', @@ -461,8 +492,8 @@ renames = { 'tf.segment_sum': 'tf.math.segment_sum', 'tf.self_adjoint_eig': 'tf.linalg.eigh', 'tf.self_adjoint_eigvals': 'tf.linalg.eigvalsh', - 'tf.serialize_many_sparse': 'tf.io.serialize_many_sparse', - 'tf.serialize_sparse': 'tf.io.serialize_sparse', + 'tf.serialize_many_sparse': 'tf.compat.v1.serialize_many_sparse', + 'tf.serialize_sparse': 'tf.compat.v1.serialize_sparse', 'tf.serialize_tensor': 'tf.io.serialize_tensor', 'tf.set_random_seed': 'tf.compat.v1.set_random_seed', 'tf.setdiff1d': 'tf.compat.v1.setdiff1d', @@ -580,10 +611,7 @@ renames = { 'tf.train.maybe_batch_join': 'tf.compat.v1.train.maybe_batch_join', 'tf.train.maybe_shuffle_batch': 'tf.compat.v1.train.maybe_shuffle_batch', 'tf.train.maybe_shuffle_batch_join': 'tf.compat.v1.train.maybe_shuffle_batch_join', - 'tf.train.natural_exp_decay': 'tf.compat.v1.train.natural_exp_decay', - 'tf.train.noisy_linear_cosine_decay': 'tf.compat.v1.train.noisy_linear_cosine_decay', - 'tf.train.piecewise_constant': 'tf.train.piecewise_constant_decay', - 'tf.train.polynomial_decay': 'tf.compat.v1.train.polynomial_decay', + 'tf.train.piecewise_constant': 'tf.compat.v1.train.piecewise_constant', 'tf.train.queue_runner.QueueRunner': 'tf.compat.v1.train.queue_runner.QueueRunner', 'tf.train.queue_runner.add_queue_runner': 'tf.compat.v1.train.queue_runner.add_queue_runner', 'tf.train.queue_runner.start_queue_runners': 'tf.compat.v1.train.queue_runner.start_queue_runners', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index eb4e62b895..e8ea9784af 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -91,6 +91,10 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.manip.batch_to_space_nd": { "block_size": "block_shape", }, + "tf.nn.dilation2d": { + "filter": "filters", + "rates": "dilations", + }, "tf.nn.conv3d": { "filter": "filters" }, -- GitLab From 5a08ce9bd17c2678c80b0af70996ebbc4879c937 Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Mon, 26 Nov 2018 16:13:46 -0800 Subject: [PATCH 353/672] Log GPU and cuDNN version information. PiperOrigin-RevId: 222904961 --- tensorflow/stream_executor/BUILD | 11 ++++++++ tensorflow/stream_executor/dnn.h | 7 +++-- tensorflow/stream_executor/logging.proto | 19 +++++++++++++ .../stream_executor/stream_executor_pimpl.cc | 28 ++++++++++++++++++- 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 tensorflow/stream_executor/logging.proto diff --git a/tensorflow/stream_executor/BUILD b/tensorflow/stream_executor/BUILD index 2526e1adaa..74fec09d80 100644 --- a/tensorflow/stream_executor/BUILD +++ b/tensorflow/stream_executor/BUILD @@ -23,6 +23,14 @@ tf_proto_library( protodeps = tf_additional_all_protos(), ) +tf_proto_library( + name = "logging_proto", + srcs = ["logging.proto"], + cc_api_version = 2, + default_header = True, + protodeps = tf_additional_all_protos(), +) + cc_library( name = "stream_executor_impl", srcs = glob( @@ -46,7 +54,9 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":dnn_proto_cc_impl", + ":logging_proto_cc_impl", "//tensorflow/core:lib", + "//tensorflow/core:logger", "//tensorflow/core:ptr_util", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", @@ -63,6 +73,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":dnn_proto_cc", + ":logging_proto_cc", "//tensorflow/core:lib", "//tensorflow/core:ptr_util", "@com_google_absl//absl/strings", diff --git a/tensorflow/stream_executor/dnn.h b/tensorflow/stream_executor/dnn.h index c044a356ef..43738d2d1d 100644 --- a/tensorflow/stream_executor/dnn.h +++ b/tensorflow/stream_executor/dnn.h @@ -906,9 +906,10 @@ class VersionInfo { public: VersionInfo(int major = 0, int minor = 0, int patch = 0) : major_(major), minor_(minor), patch_(patch) {} - int major_version() { return major_; } - int minor_version() { return minor_; } - int patch() { return patch_; } + int major_version() const { return major_; } + int minor_version() const { return minor_; } + int patch() const { return patch_; } + private: int major_; int minor_; diff --git a/tensorflow/stream_executor/logging.proto b/tensorflow/stream_executor/logging.proto new file mode 100644 index 0000000000..2c75500cda --- /dev/null +++ b/tensorflow/stream_executor/logging.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package stream_executor; + +message CudnnVersion { + int32 major = 1; + int32 minor = 2; + int32 patch = 3; +}; + +message ComputeCapability { + int32 major = 1; + int32 minor = 2; +} + +message CudaInfo { + CudnnVersion cudnn_version = 1; + ComputeCapability compute_capability = 2; +} diff --git a/tensorflow/stream_executor/stream_executor_pimpl.cc b/tensorflow/stream_executor/stream_executor_pimpl.cc index d1d0bd9bc2..86bc4ab7d0 100644 --- a/tensorflow/stream_executor/stream_executor_pimpl.cc +++ b/tensorflow/stream_executor/stream_executor_pimpl.cc @@ -23,6 +23,7 @@ limitations under the License. #include #include "absl/strings/str_cat.h" +#include "tensorflow/core/platform/logger.h" #include "tensorflow/core/util/env_var.h" #include "tensorflow/stream_executor/blas.h" #include "tensorflow/stream_executor/fft.h" @@ -33,6 +34,7 @@ limitations under the License. #include "tensorflow/stream_executor/lib/str_util.h" #include "tensorflow/stream_executor/lib/stringprintf.h" #include "tensorflow/stream_executor/lib/threadpool.h" +#include "tensorflow/stream_executor/logging.pb.h" #include "tensorflow/stream_executor/platform/port.h" #include "tensorflow/stream_executor/rng.h" #include "tensorflow/stream_executor/stream_executor_internal.h" @@ -217,7 +219,31 @@ StreamExecutor::~StreamExecutor() { port::Status StreamExecutor::Init(int device_ordinal, DeviceOptions device_options) { device_ordinal_ = device_ordinal; - return implementation_->Init(device_ordinal, std::move(device_options)); + TF_RETURN_IF_ERROR( + implementation_->Init(device_ordinal, std::move(device_options))); + + if (platform_kind_ == PlatformKind::kCuda) { + CudaInfo info; + + int cc_major, cc_minor; + GetDeviceDescription().cuda_compute_capability(&cc_major, &cc_minor); + info.mutable_compute_capability()->set_major(cc_major); + info.mutable_compute_capability()->set_minor(cc_minor); + + if (auto *dnn = AsDnn()) { + port::StatusOr version_or = dnn->GetVersion(); + if (version_or.ok()) { + const auto &version = version_or.ValueOrDie(); + info.mutable_cudnn_version()->set_major(version.major_version()); + info.mutable_cudnn_version()->set_minor(version.minor_version()); + info.mutable_cudnn_version()->set_patch(version.patch()); + } + } + + tensorflow::Logger::Singleton()->LogProto(info); + } + + return port::Status::OK(); } port::Status StreamExecutor::Init() { -- GitLab From 08666e3eb80f144608347f4ffcc49ca51d58316d Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Mon, 26 Nov 2018 16:16:02 -0800 Subject: [PATCH 354/672] Adding `SensitivityAtSpecificity` and `SpecificityAtSensitivity` metrics to the new metrics module. PiperOrigin-RevId: 222905327 --- tensorflow/python/keras/BUILD | 1 + tensorflow/python/keras/metrics.py | 195 ++++++++++++++++++++++++ tensorflow/python/keras/metrics_test.py | 179 ++++++++++++++++++++++ 3 files changed, 375 insertions(+) diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index bac961bb9d..697f591e35 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -306,6 +306,7 @@ py_test( ":keras", "//tensorflow/python:client_testlib", "//third_party/py/numpy", + "@absl_py//absl/testing:parameterized", ], ) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 1ddeb0bee7..60632e5a25 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -1266,6 +1266,201 @@ class Recall(Metric): array_ops.zeros_like(self.thresholds)) +@six.add_metaclass(abc.ABCMeta) +class SensitivitySpecificityBase(Metric): + """Abstract base class for computing sensitivity and specificity. + + For additional information about specificity and sensitivity, see the + following: https://en.wikipedia.org/wiki/Sensitivity_and_specificity + """ + + def __init__(self, value, num_thresholds=200, name=None, dtype=None): + super(SensitivitySpecificityBase, self).__init__(name=name, dtype=dtype) + if num_thresholds <= 0: + raise ValueError('`num_thresholds` must be > 0.') + self.value = value + self.tp = self.add_weight( + 'true_positives', + shape=(num_thresholds,), + initializer=init_ops.zeros_initializer) + self.tn = self.add_weight( + 'true_negatives', + shape=(num_thresholds,), + initializer=init_ops.zeros_initializer) + self.fp = self.add_weight( + 'false_positives', + shape=(num_thresholds,), + initializer=init_ops.zeros_initializer) + self.fn = self.add_weight( + 'false_negatives', + shape=(num_thresholds,), + initializer=init_ops.zeros_initializer) + + # Compute `num_thresholds` thresholds in [0, 1] + if num_thresholds == 1: + self.thresholds = [0.5] + else: + thresholds = [(i + 1) * 1.0 / (num_thresholds - 1) + for i in range(num_thresholds - 2)] + self.thresholds = [0.0] + thresholds + [1.0] + + def update_state(self, y_true, y_pred, sample_weight=None): + """Accumulates confusion matrix statistics. + + Args: + y_true: The ground truth values. + y_pred: The predicted values. + sample_weight: Optional weighting of each example. Defaults to 1. Can be a + `Tensor` whose rank is either 0, or the same rank as `y_true`, and must + be broadcastable to `y_true`. + + Returns: + Update op. + """ + return _update_confusion_matrix_variables({ + _ConfusionMatrix.TRUE_POSITIVES: self.tp, + _ConfusionMatrix.TRUE_NEGATIVES: self.tn, + _ConfusionMatrix.FALSE_POSITIVES: self.fp, + _ConfusionMatrix.FALSE_NEGATIVES: self.fn, + }, y_true, y_pred, self.thresholds, sample_weight) + + +class SensitivityAtSpecificity(SensitivitySpecificityBase): + """Computes the sensitivity at a given specificity. + + `Sensitivity` measures the proportion of actual positives that are correctly + identified as such (tp / (tp + fn)). + `Specificity` measures the proportion of actual negatives that are correctly + identified as such (tn / (tn + fp)). + + This metric creates four local variables, `true_positives`, `true_negatives`, + `false_positives` and `false_negatives` that are used to compute the + sensitivity at the given specificity. The threshold for the given specificity + value is computed and used to evaluate the corresponding sensitivity. + + If `sample_weight` is `None`, weights default to 1. + Use `sample_weight` of 0 to mask values. + + For additional information about specificity and sensitivity, see the + following: https://en.wikipedia.org/wiki/Sensitivity_and_specificity + + Usage: + + ```python + m = tf.metrics.SensitivityAtSpecificity(0.4, num_thresholds=1) + m.update_state([0, 0, 1, 1], [0, 0.5, 0.3, 0.9]) + print('Final result: ', m.result().numpy()) # Final result: 0.5 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile( + 'sgd', + loss='mse', + metrics=[tf.metrics.SensitivityAtSpecificity()]) + ``` + """ + + def __init__(self, specificity, num_thresholds=200, name=None, dtype=None): + """Creates a `SensitivityAtSpecificity` instance. + + Args: + specificity: A scalar value in range `[0, 1]`. + num_thresholds: (Optional) Defaults to 200. The number of thresholds to + use for matching the given specificity. + name: (Optional) string name of the metric instance. + dtype: (Optional) data type of the metric result. + """ + if specificity < 0 or specificity > 1: + raise ValueError('`specificity` must be in the range [0, 1].') + super(SensitivityAtSpecificity, self).__init__( + specificity, num_thresholds=num_thresholds, name=name, dtype=dtype) + + def result(self): + # Calculate specificities at all the thresholds. + specificities = math_ops.div_no_nan(self.tn, self.tn + self.fp) + + # Find the index of the threshold where the specificity is closest to the + # given specificity. + min_index = math_ops.argmin( + math_ops.abs(specificities - self.value), axis=0) + min_index = math_ops.cast(min_index, dtypes.int32) + + # Compute sensitivity at that index. + return math_ops.div_no_nan(self.tp[min_index], + self.tp[min_index] + self.fn[min_index]) + + +class SpecificityAtSensitivity(SensitivitySpecificityBase): + """Computes the specificity at a given sensitivity. + + `Sensitivity` measures the proportion of actual positives that are correctly + identified as such (tp / (tp + fn)). + `Specificity` measures the proportion of actual negatives that are correctly + identified as such (tn / (tn + fp)). + + This metric creates four local variables, `true_positives`, `true_negatives`, + `false_positives` and `false_negatives` that are used to compute the + specificity at the given sensitivity. The threshold for the given sensitivity + value is computed and used to evaluate the corresponding specificity. + + If `sample_weight` is `None`, weights default to 1. + Use `sample_weight` of 0 to mask values. + + For additional information about specificity and sensitivity, see the + following: https://en.wikipedia.org/wiki/Sensitivity_and_specificity + + Usage: + + ```python + m = tf.metrics.SpecificityAtSensitivity(0.8, num_thresholds=1) + m.update_state([0, 0, 1, 1], [0, 0.5, 0.3, 0.9]) + print('Final result: ', m.result().numpy()) # Final result: 1.0 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile( + 'sgd', + loss='mse', + metrics=[tf.metrics.SpecificityAtSensitivity()]) + ``` + """ + + def __init__(self, sensitivity, num_thresholds=200, name=None, dtype=None): + """Creates a `SpecificityAtSensitivity` instance. + + Args: + sensitivity: A scalar value in range `[0, 1]`. + num_thresholds: (Optional) Defaults to 200. The number of thresholds to + use for matching the given specificity. + name: (Optional) string name of the metric instance. + dtype: (Optional) data type of the metric result. + """ + if sensitivity < 0 or sensitivity > 1: + raise ValueError('`sensitivity` must be in the range [0, 1].') + super(SpecificityAtSensitivity, self).__init__( + sensitivity, num_thresholds=num_thresholds, name=name, dtype=dtype) + + def result(self): + # Calculate sensitivities at all the thresholds. + sensitivities = math_ops.div_no_nan(self.tp, self.tp + self.fn) + + # Find the index of the threshold where the sensitivity is closest to the + # given specificity. + min_index = math_ops.argmin( + math_ops.abs(sensitivities - self.value), axis=0) + min_index = math_ops.cast(min_index, dtypes.int32) + + # Compute specificity at that index. + return math_ops.div_no_nan(self.tn[min_index], + self.tn[min_index] + self.fp[min_index]) + + def accuracy(y_true, y_pred): y_pred.get_shape().assert_is_compatible_with(y_true.get_shape()) if y_true.dtype != y_pred.dtype: diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index eeade4f37d..74e5d4d4ce 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function import os +from absl.testing import parameterized import numpy as np from tensorflow.python.eager import context @@ -1023,5 +1024,183 @@ class RecallTest(test.TestCase): 1e-3) +@test_util.run_all_in_graph_and_eager_modes +class SensitivityAtSpecificityTest(test.TestCase, parameterized.TestCase): + + def test_config(self): + s_obj = metrics.SensitivityAtSpecificity( + 0.4, num_thresholds=100, name='sensitivity_at_specificity_1') + self.assertEqual(s_obj.name, 'sensitivity_at_specificity_1') + self.assertLen(s_obj.variables, 4) + self.assertEqual(s_obj.value, 0.4) + self.assertLen(s_obj.thresholds, 100) + + def test_value_is_idempotent(self): + s_obj = metrics.SensitivityAtSpecificity(0.7) + y_pred = random_ops.random_uniform((10, 3), + maxval=1, + dtype=dtypes.float32, + seed=1) + y_true = random_ops.random_uniform((10, 3), + maxval=2, + dtype=dtypes.int64, + seed=1) + update_op = s_obj.update_state(y_true, y_pred) + self.evaluate(variables.variables_initializer(s_obj.variables)) + + # Run several updates. + for _ in range(10): + self.evaluate(update_op) + + # Then verify idempotency. + initial_sensitivity = self.evaluate(s_obj.result()) + for _ in range(10): + self.assertAlmostEqual(initial_sensitivity, self.evaluate(s_obj.result()), + 1e-3) + + def test_unweighted_all_correct(self): + s_obj = metrics.SensitivityAtSpecificity(0.7) + inputs = np.random.randint(0, 2, size=(100, 1)) + y_pred = constant_op.constant(inputs, dtype=dtypes.float32) + y_true = constant_op.constant(inputs) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(1, self.evaluate(result)) + + def test_unweighted_high_specificity(self): + s_obj = metrics.SensitivityAtSpecificity(0.8) + pred_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.1, 0.45, 0.5, 0.8, 0.9] + label_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] + + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(0.8, self.evaluate(result)) + + def test_unweighted_low_specificity(self): + s_obj = metrics.SensitivityAtSpecificity(0.4) + pred_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.25, 0.26, 0.26] + label_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] + + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(0.6, self.evaluate(result)) + + @parameterized.parameters([dtypes.bool, dtypes.int32, dtypes.float32]) + def test_weighted(self, label_dtype): + s_obj = metrics.SensitivityAtSpecificity(0.4) + pred_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.25, 0.26, 0.26] + label_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] + weight_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = math_ops.cast(label_values, dtype=label_dtype) + weights = constant_op.constant(weight_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred, sample_weight=weights) + self.assertAlmostEqual(0.675, self.evaluate(result)) + + def test_invalid_specificity(self): + with self.assertRaisesRegexp( + ValueError, r'`specificity` must be in the range \[0, 1\].'): + metrics.SensitivityAtSpecificity(-1) + + def test_invalid_num_thresholds(self): + with self.assertRaisesRegexp(ValueError, '`num_thresholds` must be > 0.'): + metrics.SensitivityAtSpecificity(0.4, num_thresholds=-1) + + +@test_util.run_all_in_graph_and_eager_modes +class SpecificityAtSensitivityTest(test.TestCase, parameterized.TestCase): + + def test_config(self): + s_obj = metrics.SpecificityAtSensitivity( + 0.4, num_thresholds=100, name='specificity_at_sensitivity_1') + self.assertEqual(s_obj.name, 'specificity_at_sensitivity_1') + self.assertLen(s_obj.variables, 4) + self.assertEqual(s_obj.value, 0.4) + self.assertLen(s_obj.thresholds, 100) + + def test_value_is_idempotent(self): + s_obj = metrics.SpecificityAtSensitivity(0.7) + y_pred = random_ops.random_uniform((10, 3), + maxval=1, + dtype=dtypes.float32, + seed=1) + y_true = random_ops.random_uniform((10, 3), + maxval=2, + dtype=dtypes.int64, + seed=1) + update_op = s_obj.update_state(y_true, y_pred) + self.evaluate(variables.variables_initializer(s_obj.variables)) + + # Run several updates. + for _ in range(10): + self.evaluate(update_op) + + # Then verify idempotency. + initial_specificity = self.evaluate(s_obj.result()) + for _ in range(10): + self.assertAlmostEqual(initial_specificity, self.evaluate(s_obj.result()), + 1e-3) + + def test_unweighted_all_correct(self): + s_obj = metrics.SpecificityAtSensitivity(0.7) + inputs = np.random.randint(0, 2, size=(100, 1)) + y_pred = constant_op.constant(inputs, dtype=dtypes.float32) + y_true = constant_op.constant(inputs) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(1, self.evaluate(result)) + + def test_unweighted_high_sensitivity(self): + s_obj = metrics.SpecificityAtSensitivity(0.8) + pred_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.1, 0.45, 0.5, 0.8, 0.9] + label_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] + + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(0.4, self.evaluate(result)) + + def test_unweighted_low_sensitivity(self): + s_obj = metrics.SpecificityAtSensitivity(0.4) + pred_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.25, 0.26, 0.26] + label_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] + + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(0.6, self.evaluate(result)) + + @parameterized.parameters([dtypes.bool, dtypes.int32, dtypes.float32]) + def test_weighted(self, label_dtype): + s_obj = metrics.SpecificityAtSensitivity(0.4) + pred_values = [0.0, 0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.25, 0.26, 0.26] + label_values = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] + weight_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = math_ops.cast(label_values, dtype=label_dtype) + weights = constant_op.constant(weight_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred, sample_weight=weights) + self.assertAlmostEqual(0.4, self.evaluate(result)) + + def test_invalid_sensitivity(self): + with self.assertRaisesRegexp( + ValueError, r'`sensitivity` must be in the range \[0, 1\].'): + metrics.SpecificityAtSensitivity(-1) + + def test_invalid_num_thresholds(self): + with self.assertRaisesRegexp(ValueError, '`num_thresholds` must be > 0.'): + metrics.SpecificityAtSensitivity(0.4, num_thresholds=-1) + + if __name__ == '__main__': test.main() -- GitLab From 343734b56c2d9014293a2ed1e30ad4e1c7b6e07a Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Mon, 26 Nov 2018 16:22:34 -0800 Subject: [PATCH 355/672] Use if_cuda instead of if_cuda_is_configured if_cuda_is_configured is now a no-op. For xla_gpu_jit this does not matter since its deps are under if_cuda, but it does make a difference for xla_gpu_device. We should at some point refactor both xla_gpu_device and xla_gpu_jit to either uniformly include an if_cuda or to not include it, but there are other hills I want to die on at the moment. PiperOrigin-RevId: 222906280 --- tensorflow/compiler/jit/BUILD | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tensorflow/compiler/jit/BUILD b/tensorflow/compiler/jit/BUILD index 682c0f0cb0..6b0d20bc18 100644 --- a/tensorflow/compiler/jit/BUILD +++ b/tensorflow/compiler/jit/BUILD @@ -23,7 +23,6 @@ package( load("//tensorflow:tensorflow.bzl", "cc_header_only_library") load("//tensorflow:tensorflow.bzl", "tf_cc_test") load("@local_config_cuda//cuda:build_defs.bzl", "if_cuda") -load("@local_config_cuda//cuda:build_defs.bzl", "if_cuda_is_configured") load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test") load("//tensorflow:tensorflow.bzl", "tf_custom_op_py_library") @@ -38,7 +37,7 @@ cc_library( ":xla_cpu_device", ":xla_cpu_jit", "//tensorflow/compiler/plugin", - ] + if_cuda_is_configured([ + ] + if_cuda([ ":xla_gpu_device", ":xla_gpu_jit", ]), -- GitLab From 98e8a01bc8f46f5ca0bff78017d00a15370e2ba1 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Mon, 26 Nov 2018 16:24:56 -0800 Subject: [PATCH 356/672] Some cleanups involving tensorarray gradients and control flow v2. Also mark a bunch of ops as not differentiable. PiperOrigin-RevId: 222906549 --- tensorflow/python/framework/function_def_to_graph.py | 4 +++- tensorflow/python/ops/cond_v2.py | 8 +++++++- tensorflow/python/ops/list_ops.py | 2 ++ tensorflow/python/ops/resource_variable_ops.py | 3 +++ tensorflow/python/ops/while_v2.py | 4 ++++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/framework/function_def_to_graph.py b/tensorflow/python/framework/function_def_to_graph.py index 4d1aabde06..1803cb906d 100644 --- a/tensorflow/python/framework/function_def_to_graph.py +++ b/tensorflow/python/framework/function_def_to_graph.py @@ -174,7 +174,9 @@ def function_def_to_graph_def(fdef, input_shapes=None): # Update inputs of all nodes in graph. for node_def in graph_def.node: for i in range(len(node_def.input)): - node_def.input[i] = nested_to_flat_tensor_name[node_def.input[i]] + # TODO(apassos): how can it not be there? + if node_def.input[i] in nested_to_flat_tensor_name: + node_def.input[i] = nested_to_flat_tensor_name[node_def.input[i]] return graph_def, nested_to_flat_tensor_name diff --git a/tensorflow/python/ops/cond_v2.py b/tensorflow/python/ops/cond_v2.py index 4db59871d3..927c64919d 100644 --- a/tensorflow/python/ops/cond_v2.py +++ b/tensorflow/python/ops/cond_v2.py @@ -25,12 +25,14 @@ from __future__ import print_function import collections +from tensorflow.python.framework import dtypes from tensorflow.python.framework import func_graph as func_graph_module from tensorflow.python.framework import function_def_to_graph from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_util_v2 as util from tensorflow.python.ops import gen_functional_ops +from tensorflow.python.ops import gen_resource_variable_ops from tensorflow.python.ops import gradients_impl from tensorflow.python.util import nest @@ -262,7 +264,11 @@ def _grad_fn(func_graph, grads): # both branches have zero gradient. for i in range(len(result)): if result[i] is None: - result[i] = array_ops.zeros_like(func_graph.inputs[i]) + if func_graph.inputs[i].dtype == dtypes.resource: + result[i] = array_ops.zeros( + gen_resource_variable_ops.variable_shape(func_graph.inputs[i])) + else: + result[i] = array_ops.zeros_like(func_graph.inputs[i]) return result diff --git a/tensorflow/python/ops/list_ops.py b/tensorflow/python/ops/list_ops.py index 515926002d..89ff48ebd9 100644 --- a/tensorflow/python/ops/list_ops.py +++ b/tensorflow/python/ops/list_ops.py @@ -31,6 +31,8 @@ from tensorflow.python.ops.gen_list_ops import * ops.NotDifferentiable("TensorListConcat") +ops.NotDifferentiable("TensorListElementShape") +ops.NotDifferentiable("TensorListLength") ops.NotDifferentiable("TensorListPushBackBatch") diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index c20f8fb938..f614c48485 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -1525,3 +1525,6 @@ def copy_to_graph_uninitialized(var): new_variable._maybe_initialize_checkpointable() # pylint: enable=protected-access return new_variable + +ops.NotDifferentiable("VarIsInitializedOp") +ops.NotDifferentiable("VariableShape") diff --git a/tensorflow/python/ops/while_v2.py b/tensorflow/python/ops/while_v2.py index 1252c7fb03..6821b63d0e 100644 --- a/tensorflow/python/ops/while_v2.py +++ b/tensorflow/python/ops/while_v2.py @@ -839,6 +839,10 @@ def _is_tensor_array_handle(tensor): # TODO(b/118452219): add test coverage for this. tensor = func_graph_module.maybe_captured(tensor) + if isinstance(tensor, ops.EagerTensor): + # Eager execution doesn't quite support legacy tensorarray + return False + return tensor.op.type in TENSOR_ARRAY_HANDLE_OPS -- GitLab From 09070cb9d3897db33f51bd7d3ac7807590290b8d Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Mon, 26 Nov 2018 16:29:18 -0800 Subject: [PATCH 357/672] Fix links in tflite_convert documentation. PiperOrigin-RevId: 222907025 --- tensorflow/lite/g3doc/devguide.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tensorflow/lite/g3doc/devguide.md b/tensorflow/lite/g3doc/devguide.md index 798bf4996a..d42729c7ea 100644 --- a/tensorflow/lite/g3doc/devguide.md +++ b/tensorflow/lite/g3doc/devguide.md @@ -69,17 +69,18 @@ grow in future Tensorflow Lite releases. ## 2. Convert the model format -The [TensorFlow Lite Converter](convert) accepts the following file formats: +The [TensorFlow Lite Converter](convert/index.md) accepts the following file +formats: * `SavedModel` — A `GraphDef` and checkpoint with a signature that labels input and output arguments to a model. See the documentation for converting - SavedModels using [Python](convert/python_api#basic_savedmodel) or using the - [command line](convert/cmdline_examples#savedmodel). + SavedModels using [Python](convert/python_api.md#basic_savedmodel) or using + the [command line](convert/cmdline_examples.md#savedmodel). * `tf.keras` - A HDF5 file containing a model with weights and input and output arguments generated by `tf.Keras`. See [here] for converting HDF5 models. See the documentation for converting HDF5 models using - [Python](convert/python_api#basic_keras_file) or using the - [command line](convert/cmdline_examples#keras). + [Python](convert/python_api.md#basic_keras_file) or using the + [command line](convert/cmdline_examples.md#keras). * `frozen tf.GraphDef` — A subclass of `tf.GraphDef` that does not contain variables. A `GraphDef` can be converted to a `frozen GraphDef` by taking a checkpoint and a `GraphDef`, and converting each variable into a constant @@ -153,10 +154,11 @@ the arguments for specifying the output nodes for inference in the ### Full converter reference -The [TensorFlow Lite Converter](convert/) can be [Python](convert/python_api.md) -or from the [command line](convert/cmdline_examples.md). This allows you to -integrate the conversion step into the model design workflow, ensuring the model -is easy to convert to a mobile inference graph. +The [TensorFlow Lite Converter](convert/index.md) can be +[Python](convert/python_api.md) or from the +[command line](convert/cmdline_examples.md). This allows you to integrate the +conversion step into the model design workflow, ensuring the model is easy to +convert to a mobile inference graph. ### Ops compatibility -- GitLab From 76f1886556a552f22d533d5719eaaaaa1a91a66f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 16:32:23 -0800 Subject: [PATCH 358/672] Delete "device_util" from its old location in training/, all references are to its new location in distribute/. PiperOrigin-RevId: 222907490 --- tensorflow/python/BUILD | 9 --------- tensorflow/python/training/device_util.py | 22 ---------------------- 2 files changed, 31 deletions(-) delete mode 100644 tensorflow/python/training/device_util.py diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 4cfb90c486..19d2af4515 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -3595,15 +3595,6 @@ py_library( ], ) -py_library( - name = "device_util", - srcs = ["training/device_util.py"], - srcs_version = "PY2AND3", - deps = [ - "//tensorflow/python/distribute:device_util", - ], -) - py_library( name = "distribute", srcs = [ diff --git a/tensorflow/python/training/device_util.py b/tensorflow/python/training/device_util.py deleted file mode 100644 index bf8e98052d..0000000000 --- a/tensorflow/python/training/device_util.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2018 The TensorFlow Authors. 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. -# ============================================================================== -"""Deprecated, please use ../distribute/device_util.py.""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -# pylint: disable=wildcard-import -from tensorflow.python.distribute.device_util import * -- GitLab From 958859263d008b5c86a589b7574e5ef704e5176b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 16:35:19 -0800 Subject: [PATCH 359/672] Update ops-related pbtxt files. PiperOrigin-RevId: 222907921 --- .../core/ops/compat/ops_history.v1.pbtxt | 65 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 13 ++++ 2 files changed, 78 insertions(+) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index c855f1c4a0..ba0bf553d0 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -41786,6 +41786,71 @@ op { } } } +op { + name: "QuantizeAndDequantizeV2" + input_arg { + name: "input" + type_attr: "T" + } + input_arg { + name: "input_min" + type_attr: "T" + } + input_arg { + name: "input_max" + type_attr: "T" + } + output_arg { + name: "output" + type_attr: "T" + } + attr { + name: "signed_input" + type: "bool" + default_value { + b: true + } + } + attr { + name: "num_bits" + type: "int" + default_value { + i: 8 + } + } + attr { + name: "range_given" + type: "bool" + default_value { + b: false + } + } + attr { + name: "T" + type: "type" + allowed_values { + list { + type: DT_BFLOAT16 + type: DT_HALF + type: DT_FLOAT + type: DT_DOUBLE + } + } + } + attr { + name: "round_mode" + type: "string" + default_value { + s: "HALF_TO_EVEN" + } + allowed_values { + list { + s: "HALF_TO_EVEN" + s: "HALF_UP" + } + } + } +} op { name: "QuantizeAndDequantizeV3" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index 44cc64dc3b..bae50a7139 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -21090,6 +21090,19 @@ op { } } } + attr { + name: "round_mode" + type: "string" + default_value { + s: "HALF_TO_EVEN" + } + allowed_values { + list { + s: "HALF_TO_EVEN" + s: "HALF_UP" + } + } + } } op { name: "QuantizeAndDequantizeV3" -- GitLab From 35dcdd967ec15956145d7be7835da12ae74fc568 Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Mon, 26 Nov 2018 16:51:20 -0800 Subject: [PATCH 360/672] - Adding V2 API for MeanSquaredError loss. - Deprecating V1 losses APIs. PiperOrigin-RevId: 222910192 --- tensorflow/python/keras/losses.py | 22 ++++++++- tensorflow/python/ops/losses/losses_impl.py | 22 ++++----- ...low.keras.losses.-mean-squared-error.pbtxt | 22 +++++++++ .../golden/v1/tensorflow.keras.losses.pbtxt | 4 ++ ...ensorflow.losses.-mean-squared-error.pbtxt | 22 +++++++++ .../api/golden/v1/tensorflow.losses.pbtxt | 4 ++ ...low.keras.losses.-mean-squared-error.pbtxt | 22 +++++++++ .../golden/v2/tensorflow.keras.losses.pbtxt | 4 ++ ...ensorflow.losses.-mean-squared-error.pbtxt | 22 +++++++++ .../api/golden/v2/tensorflow.losses.pbtxt | 48 ++----------------- 10 files changed, 136 insertions(+), 56 deletions(-) create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-error.pbtxt create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-error.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt diff --git a/tensorflow/python/keras/losses.py b/tensorflow/python/keras/losses.py index 8afe2fadce..1bd9f729c5 100644 --- a/tensorflow/python/keras/losses.py +++ b/tensorflow/python/keras/losses.py @@ -115,8 +115,28 @@ class Loss(object): NotImplementedError('Must be implemented in subclasses.') +@tf_export('losses.MeanSquaredError', 'keras.losses.MeanSquaredError') class MeanSquaredError(Loss): - """Computes the mean of squares of errors between labels and predictions.""" + """Computes the mean of squares of errors between labels and predictions. + + For example, if `y_true` is [0., 0., 1., 1.] and `y_pred` is [1., 1., 1., 0.] + then the mean squared error value is 3/4 (0.75). + + Usage: + + ```python + mse = tf.losses.MeanSquaredError() + loss = mse([0., 0., 1., 1.], [1., 1., 1., 0.]) + print('Loss: ', loss.numpy()) # Loss: 0.75 + ``` + + Usage with tf.keras API: + + ```python + model = keras.models.Model(inputs, outputs) + model.compile('sgd', loss=tf.losses.MeanSquaredError()) + ``` + """ def call(self, y_true, y_pred): """Invokes the `MeanSquaredError` instance. diff --git a/tensorflow/python/ops/losses/losses_impl.py b/tensorflow/python/ops/losses/losses_impl.py index 7c52b28b39..1b470937d4 100644 --- a/tensorflow/python/ops/losses/losses_impl.py +++ b/tensorflow/python/ops/losses/losses_impl.py @@ -133,7 +133,7 @@ def _num_elements(losses): return math_ops.cast(array_ops.size(losses, name=scope), dtype=losses.dtype) -@tf_export("losses.compute_weighted_loss") +@tf_export(v1=["losses.compute_weighted_loss"]) def compute_weighted_loss( losses, weights=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES, reduction=Reduction.SUM_BY_NONZERO_WEIGHTS): @@ -203,7 +203,7 @@ def compute_weighted_loss( return loss -@tf_export("losses.absolute_difference") +@tf_export(v1=["losses.absolute_difference"]) def absolute_difference( labels, predictions, weights=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES, @@ -256,7 +256,7 @@ def absolute_difference( losses, weights, scope, loss_collection, reduction=reduction) -@tf_export("losses.cosine_distance") +@tf_export(v1=["losses.cosine_distance"]) @deprecated_args(None, "dim is deprecated, use axis instead", "dim") def cosine_distance( labels, predictions, axis=None, weights=1.0, scope=None, @@ -312,7 +312,7 @@ def cosine_distance( losses, weights, scope, loss_collection, reduction=reduction) -@tf_export("losses.hinge_loss") +@tf_export(v1=["losses.hinge_loss"]) def hinge_loss(labels, logits, weights=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES, reduction=Reduction.SUM_BY_NONZERO_WEIGHTS): @@ -362,7 +362,7 @@ def hinge_loss(labels, logits, weights=1.0, scope=None, losses, weights, scope, loss_collection, reduction=reduction) -@tf_export("losses.huber_loss") +@tf_export(v1=["losses.huber_loss"]) def huber_loss(labels, predictions, weights=1.0, delta=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES, reduction=Reduction.SUM_BY_NONZERO_WEIGHTS): @@ -440,7 +440,7 @@ def huber_loss(labels, predictions, weights=1.0, delta=1.0, scope=None, losses, weights, scope, loss_collection, reduction=reduction) -@tf_export("losses.log_loss") +@tf_export(v1=["losses.log_loss"]) def log_loss(labels, predictions, weights=1.0, epsilon=1e-7, scope=None, loss_collection=ops.GraphKeys.LOSSES, reduction=Reduction.SUM_BY_NONZERO_WEIGHTS): @@ -497,7 +497,7 @@ def log_loss(labels, predictions, weights=1.0, epsilon=1e-7, scope=None, # TODO(b/37208492): Add reduction arg. -@tf_export("losses.mean_pairwise_squared_error") +@tf_export(v1=["losses.mean_pairwise_squared_error"]) def mean_pairwise_squared_error( labels, predictions, weights=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES): @@ -593,7 +593,7 @@ def mean_pairwise_squared_error( return mean_loss -@tf_export("losses.mean_squared_error") +@tf_export(v1=["losses.mean_squared_error"]) def mean_squared_error( labels, predictions, weights=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES, @@ -646,7 +646,7 @@ def mean_squared_error( losses, weights, scope, loss_collection, reduction=reduction) -@tf_export("losses.sigmoid_cross_entropy") +@tf_export(v1=["losses.sigmoid_cross_entropy"]) def sigmoid_cross_entropy( multi_class_labels, logits, weights=1.0, label_smoothing=0, scope=None, loss_collection=ops.GraphKeys.LOSSES, @@ -710,7 +710,7 @@ def sigmoid_cross_entropy( losses, weights, scope, loss_collection, reduction=reduction) -@tf_export("losses.softmax_cross_entropy") +@tf_export(v1=["losses.softmax_cross_entropy"]) def softmax_cross_entropy( onehot_labels, logits, weights=1.0, label_smoothing=0, scope=None, loss_collection=ops.GraphKeys.LOSSES, @@ -832,7 +832,7 @@ def _remove_squeezable_dimensions( return labels, predictions, weights -@tf_export("losses.sparse_softmax_cross_entropy") +@tf_export(v1=["losses.sparse_softmax_cross_entropy"]) def sparse_softmax_cross_entropy( labels, logits, weights=1.0, scope=None, loss_collection=ops.GraphKeys.LOSSES, diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-error.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-error.pbtxt new file mode 100644 index 0000000000..a571853350 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.-mean-squared-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.keras.losses.MeanSquaredError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt index eca6b91538..a0af6a29f0 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.losses.pbtxt @@ -1,5 +1,9 @@ path: "tensorflow.keras.losses" tf_module { + member { + name: "MeanSquaredError" + mtype: "" + } member_method { name: "KLD" argspec: "args=[\'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt new file mode 100644 index 0000000000..a626d9c7e6 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.losses.-mean-squared-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.losses.MeanSquaredError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt index c1d190ae11..a198db1b35 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.losses.pbtxt @@ -1,5 +1,9 @@ path: "tensorflow.losses" tf_module { + member { + name: "MeanSquaredError" + mtype: "" + } member { name: "Reduction" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-error.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-error.pbtxt new file mode 100644 index 0000000000..a571853350 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.-mean-squared-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.keras.losses.MeanSquaredError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt index 8618c6f1c7..cb156e2248 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.losses.pbtxt @@ -1,5 +1,9 @@ path: "tensorflow.keras.losses" tf_module { + member { + name: "MeanSquaredError" + mtype: "" + } member { name: "Reduction" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt new file mode 100644 index 0000000000..a626d9c7e6 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.losses.-mean-squared-error.pbtxt @@ -0,0 +1,22 @@ +path: "tensorflow.losses.MeanSquaredError" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'reduction\', \'name\'], varargs=None, keywords=None, defaults=[\'sum_over_batch_size\', \'None\'], " + } + member_method { + name: "call" + argspec: "args=[\'self\', \'y_true\', \'y_pred\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt index c1d190ae11..87f5ef3491 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.losses.pbtxt @@ -1,25 +1,17 @@ path: "tensorflow.losses" tf_module { member { - name: "Reduction" + name: "MeanSquaredError" mtype: "" } - member_method { - name: "absolute_difference" - argspec: "args=[\'labels\', \'predictions\', \'weights\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " + member { + name: "Reduction" + mtype: "" } member_method { name: "add_loss" argspec: "args=[\'loss\', \'loss_collection\'], varargs=None, keywords=None, defaults=[\'losses\'], " } - member_method { - name: "compute_weighted_loss" - argspec: "args=[\'losses\', \'weights\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "cosine_distance" - argspec: "args=[\'labels\', \'predictions\', \'axis\', \'weights\', \'scope\', \'loss_collection\', \'reduction\', \'dim\'], varargs=None, keywords=None, defaults=[\'None\', \'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\', \'None\'], " - } member_method { name: "get_losses" argspec: "args=[\'scope\', \'loss_collection\'], varargs=None, keywords=None, defaults=[\'None\', \'losses\'], " @@ -36,36 +28,4 @@ tf_module { name: "get_total_loss" argspec: "args=[\'add_regularization_losses\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'total_loss\'], " } - member_method { - name: "hinge_loss" - argspec: "args=[\'labels\', \'logits\', \'weights\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "huber_loss" - argspec: "args=[\'labels\', \'predictions\', \'weights\', \'delta\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "log_loss" - argspec: "args=[\'labels\', \'predictions\', \'weights\', \'epsilon\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'1e-07\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "mean_pairwise_squared_error" - argspec: "args=[\'labels\', \'predictions\', \'weights\', \'scope\', \'loss_collection\'], varargs=None, keywords=None, defaults=[\'1.0\', \'None\', \'losses\'], " - } - member_method { - name: "mean_squared_error" - argspec: "args=[\'labels\', \'predictions\', \'weights\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "sigmoid_cross_entropy" - argspec: "args=[\'multi_class_labels\', \'logits\', \'weights\', \'label_smoothing\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "softmax_cross_entropy" - argspec: "args=[\'onehot_labels\', \'logits\', \'weights\', \'label_smoothing\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } - member_method { - name: "sparse_softmax_cross_entropy" - argspec: "args=[\'labels\', \'logits\', \'weights\', \'scope\', \'loss_collection\', \'reduction\'], varargs=None, keywords=None, defaults=[\'1.0\', \'None\', \'losses\', \'weighted_sum_by_nonzero_weights\'], " - } } -- GitLab From eea816869a0a85ab5d9427060a8b113fe709c623 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Mon, 26 Nov 2018 16:51:23 -0800 Subject: [PATCH 361/672] Automated rollback of commit 72f193b5c9f306d258b289afd7a7977af7b8f5f7 PiperOrigin-RevId: 222910206 --- configure.py | 1 + tensorflow/BUILD | 6 ++++++ tensorflow/core/BUILD | 8 ++++---- tensorflow/tensorflow.bzl | 8 ++++++-- tools/bazel.rc | 1 + 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/configure.py b/configure.py index 0b16fe1314..dfb87550b1 100644 --- a/configure.py +++ b/configure.py @@ -1694,6 +1694,7 @@ def main(): config_info_line('nohdfs', 'Disable HDFS support.') config_info_line('noignite', 'Disable Apacha Ignite support.') config_info_line('nokafka', 'Disable Apache Kafka support.') + config_info_line('nonccl', 'Disable NVIDIA NCCL support.') if __name__ == '__main__': diff --git a/tensorflow/BUILD b/tensorflow/BUILD index 17577afecb..fd4b94202a 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -246,6 +246,12 @@ config_setting( visibility = ["//visibility:public"], ) +config_setting( + name = "no_nccl_support", + define_values = {"no_nccl_support": "true"}, + visibility = ["//visibility:public"], +) + # Crosses between platforms and file system libraries not supported on those # platforms due to limitations in nested select() statements. config_setting( diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 781ada7b46..bd5bbaa310 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -95,7 +95,7 @@ load("//tensorflow:tensorflow.bzl", "tf_cc_test_gpu") load("//tensorflow:tensorflow.bzl", "tf_cc_tests_gpu") load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test") load("//tensorflow:tensorflow.bzl", "tf_version_info_genrule") -load("//tensorflow:tensorflow.bzl", "if_not_tx2_llvm_or_windows_cuda") +load("//tensorflow:tensorflow.bzl", "if_nccl") load("//tensorflow:tensorflow.bzl", "tf_cuda_only_cc_test") # For platform specific build config @@ -1416,9 +1416,7 @@ cc_library( "//tensorflow/core/kernels:summary_kernels", "//tensorflow/core/kernels:training_ops", "//tensorflow/core/kernels:word2vec_kernels", - ] + tf_additional_cloud_kernel_deps() + if_not_tx2_llvm_or_windows_cuda([ - "//tensorflow/core/kernels:nccl_kernels", - ]) + if_not_windows([ + ] + tf_additional_cloud_kernel_deps() + if_not_windows([ "//tensorflow/core/kernels:fact_op", "//tensorflow/core/kernels:array_not_windows", "//tensorflow/core/kernels:math_not_windows", @@ -1443,6 +1441,8 @@ cc_library( ]) + if_cuda([ "//tensorflow/core/grappler/optimizers:gpu_swapping_kernels", "//tensorflow/core/grappler/optimizers:gpu_swapping_ops", + ]) + if_nccl([ + "//tensorflow/core/kernels:nccl_kernels", ]), ) diff --git a/tensorflow/tensorflow.bzl b/tensorflow/tensorflow.bzl index 2d67d1f466..4bc68445ac 100644 --- a/tensorflow/tensorflow.bzl +++ b/tensorflow/tensorflow.bzl @@ -203,8 +203,12 @@ def if_override_eigen_strong_inline(a): "//conditions:default": [], }) -def if_not_tx2_llvm_or_windows_cuda(a): - return if_not_windows_cuda(a) +def if_nccl(a): + return select({ + "//tensorflow:no_nccl_support": [], + "//tensorflow:windows": [], + "//conditions:default": a, + }) def get_win_copts(is_external = False): WINDOWS_COPTS = [ diff --git a/tools/bazel.rc b/tools/bazel.rc index 8c2052ee8a..1fdf51f53e 100644 --- a/tools/bazel.rc +++ b/tools/bazel.rc @@ -72,6 +72,7 @@ build:nogcp --define=no_gcp_support=true build:nohdfs --define=no_hdfs_support=true build:nokafka --define=no_kafka_support=true build:noignite --define=no_ignite_support=true +build:nonccl --define=no_nccl_support=true build --define=use_fast_cpp_protos=true build --define=allow_oversize_protos=true -- GitLab From 08ae34d7744b30a3837fae9c9114c80d55e89fdb Mon Sep 17 00:00:00 2001 From: Rick Chao Date: Mon, 26 Nov 2018 17:05:46 -0800 Subject: [PATCH 362/672] Export InMemoryEvaluatorHook class to estimator.experimental PiperOrigin-RevId: 222912301 --- ...perimental.-in-memory-evaluator-hook.pbtxt | 30 +++++++++++++++++++ .../tensorflow.estimator.experimental.pbtxt | 4 +++ ...perimental.-in-memory-evaluator-hook.pbtxt | 30 +++++++++++++++++++ .../tensorflow.estimator.experimental.pbtxt | 4 +++ 4 files changed, 68 insertions(+) create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt new file mode 100644 index 0000000000..aba120218c --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt @@ -0,0 +1,30 @@ +path: "tensorflow.estimator.experimental.InMemoryEvaluatorHook" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'estimator\', \'input_fn\', \'steps\', \'hooks\', \'name\', \'every_n_iter\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'100\'], " + } + member_method { + name: "after_create_session" + argspec: "args=[\'self\', \'session\', \'coord\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "after_run" + argspec: "args=[\'self\', \'run_context\', \'run_values\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "before_run" + argspec: "args=[\'self\', \'run_context\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "begin" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "end" + argspec: "args=[\'self\', \'session\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt index cabca3e883..4b287e1f80 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt @@ -1,5 +1,9 @@ path: "tensorflow.estimator.experimental" tf_module { + member { + name: "InMemoryEvaluatorHook" + mtype: "" + } member { name: "LinearSDCA" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt new file mode 100644 index 0000000000..aba120218c --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.-in-memory-evaluator-hook.pbtxt @@ -0,0 +1,30 @@ +path: "tensorflow.estimator.experimental.InMemoryEvaluatorHook" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + member_method { + name: "__init__" + argspec: "args=[\'self\', \'estimator\', \'input_fn\', \'steps\', \'hooks\', \'name\', \'every_n_iter\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'100\'], " + } + member_method { + name: "after_create_session" + argspec: "args=[\'self\', \'session\', \'coord\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "after_run" + argspec: "args=[\'self\', \'run_context\', \'run_values\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "before_run" + argspec: "args=[\'self\', \'run_context\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "begin" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "end" + argspec: "args=[\'self\', \'session\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt index cabca3e883..4b287e1f80 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt @@ -1,5 +1,9 @@ path: "tensorflow.estimator.experimental" tf_module { + member { + name: "InMemoryEvaluatorHook" + mtype: "" + } member { name: "LinearSDCA" mtype: "" -- GitLab From bd445e7e9d4ed703fc162a985751c160cb00f2af Mon Sep 17 00:00:00 2001 From: Zhenyu Tan Date: Mon, 26 Nov 2018 17:08:55 -0800 Subject: [PATCH 363/672] Expose decay in kwargs. A later design is required for scheduable decay objects. PiperOrigin-RevId: 222912708 --- .../python/keras/optimizer_v2/adadelta.py | 25 +++-- .../python/keras/optimizer_v2/adagrad.py | 31 ++---- .../python/keras/optimizer_v2/adagrad_test.py | 44 ++++++++ tensorflow/python/keras/optimizer_v2/adam.py | 29 +++-- .../python/keras/optimizer_v2/adam_test.py | 103 +++++++++++++----- .../python/keras/optimizer_v2/adamax.py | 32 +++--- .../python/keras/optimizer_v2/adamax_test.py | 84 +++++++++++--- tensorflow/python/keras/optimizer_v2/ftrl.py | 45 ++++---- .../keras/optimizer_v2/gradient_descent.py | 35 +++--- .../optimizer_v2/gradient_descent_test.py | 68 +++++++++++- tensorflow/python/keras/optimizer_v2/nadam.py | 53 +++++++-- .../python/keras/optimizer_v2/nadam_test.py | 59 ++++++++-- .../python/keras/optimizer_v2/optimizer_v2.py | 28 ++++- .../python/keras/optimizer_v2/rmsprop.py | 37 ++++--- .../python/keras/optimizer_v2/rmsprop_test.py | 67 ++++++++++++ 15 files changed, 565 insertions(+), 175 deletions(-) diff --git a/tensorflow/python/keras/optimizer_v2/adadelta.py b/tensorflow/python/keras/optimizer_v2/adadelta.py index 21a3f06f4f..e1d7ecb558 100644 --- a/tensorflow/python/keras/optimizer_v2/adadelta.py +++ b/tensorflow/python/keras/optimizer_v2/adadelta.py @@ -19,7 +19,6 @@ from __future__ import division from __future__ import print_function from tensorflow.python.keras.optimizer_v2 import optimizer_v2 -from tensorflow.python.ops import math_ops from tensorflow.python.training import training_ops @@ -55,7 +54,8 @@ class Adadelta(optimizer_v2.OptimizerV2): learning_rate=0.001, rho=0.95, epsilon=1e-7, - name='Adadelta'): + name='Adadelta', + **kwargs): """Construct a new Adadelta optimizer. Adadelta is a more robust extension of Adagrad that adapts learning rates @@ -73,6 +73,7 @@ class Adadelta(optimizer_v2.OptimizerV2): to better conditioning the grad update. name: Optional name prefix for the operations created when applying gradients. Defaults to "Adadelta". + **kwargs: keyword arguments. Allowed to be {`decay`} @compatibility(eager) When eager execution is enabled, `learning_rate`, `rho`, and `epsilon` can @@ -81,8 +82,9 @@ class Adadelta(optimizer_v2.OptimizerV2): invocations of optimizer functions. @end_compatibility """ - super(Adadelta, self).__init__(name) + super(Adadelta, self).__init__(name, **kwargs) self._set_hyper('learning_rate', learning_rate) + self._set_hyper('decay', self._initial_decay) self._set_hyper('rho', rho) self._set_hyper('epsilon', epsilon) @@ -92,28 +94,32 @@ class Adadelta(optimizer_v2.OptimizerV2): self.add_slot(v, 'accum_var') def _resource_apply_dense(self, grad, var): + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) accum_grad = self.get_slot(var, 'accum_grad') accum_var = self.get_slot(var, 'accum_var') return training_ops.resource_apply_adadelta( var.handle, accum_grad.handle, accum_var.handle, - math_ops.cast(self._get_hyper('learning_rate'), grad.dtype.base_dtype), - math_ops.cast(self._get_hyper('rho'), grad.dtype.base_dtype), - math_ops.cast(self._get_hyper('epsilon'), grad.dtype.base_dtype), + lr_t, + self._get_hyper('rho', var_dtype), + self._get_hyper('epsilon', var_dtype), grad, use_locking=self._use_locking) def _resource_apply_sparse(self, grad, var, indices): + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) accum_grad = self.get_slot(var, 'accum_grad') accum_var = self.get_slot(var, 'accum_var') return training_ops.resource_sparse_apply_adadelta( var.handle, accum_grad.handle, accum_var.handle, - math_ops.cast(self._get_hyper('learning_rate'), grad.dtype.base_dtype), - math_ops.cast(self._get_hyper('rho'), grad.dtype.base_dtype), - math_ops.cast(self._get_hyper('epsilon'), grad.dtype.base_dtype), + lr_t, + self._get_hyper('rho', var_dtype), + self._get_hyper('epsilon', var_dtype), grad, indices, use_locking=self._use_locking) @@ -122,6 +128,7 @@ class Adadelta(optimizer_v2.OptimizerV2): config = super(Adadelta, self).get_config() config.update({ 'learning_rate': self._serialize_hyperparameter('learning_rate'), + 'decay': self._serialize_hyperparameter('decay'), 'rho': self._serialize_hyperparameter('rho'), 'epsilon': self._serialize_hyperparameter('epsilon'), }) diff --git a/tensorflow/python/keras/optimizer_v2/adagrad.py b/tensorflow/python/keras/optimizer_v2/adagrad.py index 7d090e8b84..0896f95f94 100644 --- a/tensorflow/python/keras/optimizer_v2/adagrad.py +++ b/tensorflow/python/keras/optimizer_v2/adagrad.py @@ -21,7 +21,6 @@ from __future__ import print_function from tensorflow.python.framework import ops from tensorflow.python.keras.optimizer_v2 import optimizer_v2 from tensorflow.python.ops import array_ops -from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import init_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops @@ -55,7 +54,8 @@ class Adagrad(optimizer_v2.OptimizerV2): learning_rate=0.001, initial_accumulator_value=0.1, epsilon=1e-7, - name='Adagrad'): + name='Adagrad', + **kwargs): """Construct a new Adagrad optimizer. Args: @@ -66,6 +66,7 @@ class Adagrad(optimizer_v2.OptimizerV2): Starting value for the accumulators, must be positive. name: Optional name prefix for the operations created when applying gradients. Defaults to "Adagrad". + **kwargs: keyword arguments. Allowed to be {`decay`} Raises: ValueError: If the `initial_accumulator_value` or `epsilon` is invalid. @@ -82,8 +83,9 @@ class Adagrad(optimizer_v2.OptimizerV2): initial_accumulator_value) if epsilon < 1e-7: raise ValueError('epsilon must be larger than 1e-7: %s' % epsilon) - super(Adagrad, self).__init__(name) + super(Adagrad, self).__init__(name, **kwargs) self._set_hyper('learning_rate', learning_rate) + self._set_hyper('decay', self._initial_decay) self._initial_accumulator_value = initial_accumulator_value self._set_hyper('epsilon', epsilon) @@ -94,25 +96,16 @@ class Adagrad(optimizer_v2.OptimizerV2): self._initial_accumulator_value, dtype=dtype) self.add_slot(var, 'accumulator', init) - def _init_constant_op(self, v, dtype): - def init(): - # Use a Tensor instead of initializer if variable does not have - # static shape. - init_constant = gen_array_ops.fill(array_ops.shape(v), - self._initial_accumulator_value) - return math_ops.cast(init_constant, dtype) - return init - def _resource_apply_dense(self, grad, var): var_dtype = var.dtype.base_dtype - learning_rate = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) - epsilon = math_ops.cast(self._get_hyper('epsilon'), var_dtype) + lr_t = self._decayed_lr(var_dtype) + epsilon = self._get_hyper('epsilon', var_dtype) acc = self.get_slot(var, 'accumulator') acc_t = state_ops.assign_add( acc, math_ops.square(grad), use_locking=self._use_locking) var_update = state_ops.assign_sub( - var, learning_rate * grad / (math_ops.sqrt(acc_t) + epsilon)) + var, lr_t * grad / (math_ops.sqrt(acc_t) + epsilon)) return var_update def _resource_apply_sparse(self, grad, var, indices): @@ -123,21 +116,21 @@ class Adagrad(optimizer_v2.OptimizerV2): return x.value() var_dtype = var.dtype.base_dtype - learning_rate = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) - epsilon = math_ops.cast(self._get_hyper('epsilon'), var_dtype) + lr_t = self._decayed_lr(var_dtype) + epsilon = self._get_hyper('epsilon', var_dtype) acc = self.get_slot(var, 'accumulator') acc_t = _resource_scatter_add(acc, indices, math_ops.square(grad)) acc_t_slice = array_ops.gather(acc_t, indices) var_update = _resource_scatter_add( - var, indices, - -learning_rate * grad / (math_ops.sqrt(acc_t_slice) + epsilon)) + var, indices, -lr_t * grad / (math_ops.sqrt(acc_t_slice) + epsilon)) return var_update def get_config(self): config = super(Adagrad, self).get_config() config.update({ 'learning_rate': self._serialize_hyperparameter('learning_rate'), + 'decay': self._serialize_hyperparameter('decay'), 'initial_accumulator_value': self._initial_accumulator_value, 'epsilon': self._serialize_hyperparameter('epsilon'), }) diff --git a/tensorflow/python/keras/optimizer_v2/adagrad_test.py b/tensorflow/python/keras/optimizer_v2/adagrad_test.py index 7d0f55c7d7..5ddeb1ad80 100644 --- a/tensorflow/python/keras/optimizer_v2/adagrad_test.py +++ b/tensorflow/python/keras/optimizer_v2/adagrad_test.py @@ -116,6 +116,50 @@ class AdagradOptimizerTest(test.TestCase): with context.eager_mode(): self.doTestBasic(use_callable_params=True) + def testBasicWithLearningRateDecay(self): + for dtype in [dtypes.float32, dtypes.float64]: + with self.cached_session(): + var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) + var1_np = np.array([3.0, 4.0], dtype=dtype.as_numpy_dtype) + grads0_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) + grads1_np = np.array([0.01, 0.01], dtype=dtype.as_numpy_dtype) + var0 = resource_variable_ops.ResourceVariable(var0_np) + var1 = resource_variable_ops.ResourceVariable(var1_np) + grads0 = constant_op.constant(grads0_np) + grads1 = constant_op.constant(grads1_np) + + learning_rate = 3.0 + decay = 0.5 + + ada_opt = adagrad.Adagrad(learning_rate, decay=decay) + + accum0_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) + accum1_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) + + if not context.executing_eagerly(): + ada_update = ada_opt.apply_gradients( + zip([grads0, grads1], [var0, var1])) + self.evaluate(variables.global_variables_initializer()) + + # Fetch params to validate initial values + v0_val, v1_val = self.evaluate([var0, var1]) + self.assertAllClose([1.0, 2.0], v0_val) + self.assertAllClose([3.0, 4.0], v1_val) + + # Run 3 steps of adagrad + for t in range(3): + if not context.executing_eagerly(): + self.evaluate(ada_update) + else: + ada_opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + lr_np = learning_rate / (1 + decay * t) + var0_np, accum0_np = adagrad_update_numpy(var0_np, accum0_np, + grads0_np, lr_np) + var1_np, accum1_np = adagrad_update_numpy(var1_np, accum1_np, + grads1_np, lr_np) + self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) + self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): diff --git a/tensorflow/python/keras/optimizer_v2/adam.py b/tensorflow/python/keras/optimizer_v2/adam.py index fd5918dbfa..a3f12909aa 100644 --- a/tensorflow/python/keras/optimizer_v2/adam.py +++ b/tensorflow/python/keras/optimizer_v2/adam.py @@ -50,7 +50,8 @@ class Adam(optimizer_v2.OptimizerV2): beta_2=0.999, epsilon=1e-7, amsgrad=False, - name='Adam'): + name='Adam', + **kwargs): r"""Construct a new Adam optimizer. If amsgrad = False: @@ -122,10 +123,12 @@ class Adam(optimizer_v2.OptimizerV2): a callable that takes no arguments and returns the actual value to use. This can be useful for changing these values across different invocations of optimizer functions. @end_compatibility + **kwargs: keyword arguments. Allowed to be {`decay`} """ - super(Adam, self).__init__(name) + super(Adam, self).__init__(name, **kwargs) self._set_hyper('learning_rate', learning_rate) + self._set_hyper('decay', self._initial_decay) self._set_hyper('beta_1', beta_1) self._set_hyper('beta_2', beta_2) self._set_hyper('epsilon', epsilon) @@ -141,12 +144,13 @@ class Adam(optimizer_v2.OptimizerV2): self.add_slot(var, 'v') def _resource_apply_dense(self, grad, var): - grad_dtype = grad.dtype.base_dtype + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) m = self.get_slot(var, 'm') v = self.get_slot(var, 'v') - local_step = math_ops.cast(self.iterations + 1, grad_dtype) - beta_1_t = math_ops.cast(self._get_hyper('beta_1'), grad_dtype) - beta_2_t = math_ops.cast(self._get_hyper('beta_2'), grad_dtype) + beta_1_t = self._get_hyper('beta_1', var_dtype) + beta_2_t = self._get_hyper('beta_2', var_dtype) + local_step = math_ops.cast(self.iterations + 1, var_dtype) beta_1_power = math_ops.pow(beta_1_t, local_step) beta_2_power = math_ops.pow(beta_2_t, local_step) return training_ops.resource_apply_adam( @@ -155,22 +159,22 @@ class Adam(optimizer_v2.OptimizerV2): v.handle, beta_1_power, beta_2_power, - math_ops.cast(self._get_hyper('learning_rate'), grad_dtype), + lr_t, beta_1_t, beta_2_t, - math_ops.cast(self._get_hyper('epsilon'), grad_dtype), + self._get_hyper('epsilon', var_dtype), grad, use_locking=self._use_locking) def _resource_apply_sparse(self, grad, var, indices): var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) + beta_1_t = self._get_hyper('beta_1', var_dtype) + beta_2_t = self._get_hyper('beta_2', var_dtype) local_step = math_ops.cast(self.iterations + 1, var_dtype) - beta_1_t = math_ops.cast(self._get_hyper('beta_1'), var_dtype) - beta_2_t = math_ops.cast(self._get_hyper('beta_2'), var_dtype) beta_1_power = math_ops.pow(beta_1_t, local_step) beta_2_power = math_ops.pow(beta_2_t, local_step) - lr_t = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) - epsilon_t = math_ops.cast(self._get_hyper('epsilon'), var_dtype) + epsilon_t = self._get_hyper('epsilon', var_dtype) lr = (lr_t * math_ops.sqrt(1 - beta_2_power) / (1 - beta_1_power)) # m_t = beta1 * m + (1 - beta1) * g_t @@ -201,6 +205,7 @@ class Adam(optimizer_v2.OptimizerV2): config = super(Adam, self).get_config() config.update({ 'learning_rate': self._serialize_hyperparameter('learning_rate'), + 'decay': self._serialize_hyperparameter('decay'), 'beta_1': self._serialize_hyperparameter('beta_1'), 'beta_2': self._serialize_hyperparameter('beta_2'), 'epsilon': self._serialize_hyperparameter('epsilon'), diff --git a/tensorflow/python/keras/optimizer_v2/adam_test.py b/tensorflow/python/keras/optimizer_v2/adam_test.py index 20780ead9c..e2bc6a39f9 100644 --- a/tensorflow/python/keras/optimizer_v2/adam_test.py +++ b/tensorflow/python/keras/optimizer_v2/adam_test.py @@ -38,16 +38,16 @@ def adam_update_numpy(param, t, m, v, - alpha=0.001, + lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-7): - alpha_t = alpha * np.sqrt(1 - beta2**t) / (1 - beta1**t) + lr_t = lr * np.sqrt(1 - beta2**(t + 1)) / (1 - beta1**(t + 1)) m_t = beta1 * m + (1 - beta1) * g_t v_t = beta2 * v + (1 - beta2) * g_t * g_t - param_t = param - alpha_t * m_t / (np.sqrt(v_t) + epsilon) + param_t = param - lr_t * m_t / (np.sqrt(v_t) + epsilon) return param_t, m_t, v_t @@ -90,13 +90,13 @@ class AdamOptimizerTest(test.TestCase): self.assertAllClose([1.0, 1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 3.0, 4.0], self.evaluate(var1)) - beta1_power, beta2_power = get_beta_accumulators(opt, dtype) - + beta_1_power, beta_2_power = get_beta_accumulators(opt, dtype) # Run 3 steps of Adam - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, self.evaluate(beta1_power)) - self.assertAllCloseAccordingToType(0.999**t, - self.evaluate(beta2_power)) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), + self.evaluate(beta_1_power)) + self.assertAllCloseAccordingToType(0.999**(t + 1), + self.evaluate(beta_2_power)) update.run() var0_np, m0, v0 = adam_update_numpy(var0_np, grads0_np, t, m0, v0) @@ -177,21 +177,21 @@ class AdamOptimizerTest(test.TestCase): epsilon = epsilon() opt = adam.Adam(learning_rate=learning_rate) - update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + if not context.executing_eagerly(): + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) self.evaluate(variables.global_variables_initializer()) # Run 3 steps of Adam - for t in range(1, 4): - if not context.executing_eagerly(): - self.evaluate(update) - elif t > 1: - opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - + for t in range(3): beta_1_power, beta_2_power = get_beta_accumulators(opt, dtype) self.assertAllCloseAccordingToType(0.9**(t + 1), self.evaluate(beta_1_power)) self.assertAllCloseAccordingToType(0.999**(t + 1), self.evaluate(beta_2_power)) + if not context.executing_eagerly(): + self.evaluate(update) + else: + opt.apply_gradients(zip([grads0, grads1], [var0, var1])) var0_np, m0, v0 = adam_update_numpy(var0_np, grads0_np, t, m0, v0) var1_np, m1, v1 = adam_update_numpy(var1_np, grads1_np, t, m1, v1) @@ -208,6 +208,52 @@ class AdamOptimizerTest(test.TestCase): with context.eager_mode(): self.doTestBasic(use_callable_params=True) + def testBasicWithLearningRateDecay(self): + for i, dtype in enumerate([dtypes.half, dtypes.float32, dtypes.float64]): + with self.session(graph=ops.Graph()): + # Initialize variables for numpy implementation. + m0, v0, m1, v1 = 0.0, 0.0, 0.0, 0.0 + var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) + grads0_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) + var1_np = np.array([3.0, 4.0], dtype=dtype.as_numpy_dtype) + grads1_np = np.array([0.01, 0.01], dtype=dtype.as_numpy_dtype) + + var0 = resource_variable_ops.ResourceVariable( + var0_np, name="var0_%d" % i) + var1 = resource_variable_ops.ResourceVariable( + var1_np, name="var1_%d" % i) + grads0 = constant_op.constant(grads0_np) + grads1 = constant_op.constant(grads1_np) + + learning_rate = 0.001 + beta_1 = 0.9 + beta_2 = 0.999 + epsilon = 1e-7 + decay = 0.5 + + opt = adam.Adam( + learning_rate=learning_rate, + beta_1=beta_1, + beta_2=beta_2, + epsilon=epsilon, + decay=decay) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + + self.evaluate(variables.global_variables_initializer()) + # Run 3 steps of Adam + for t in range(3): + self.evaluate(update) + lr_np = learning_rate / (1 + decay * t) + + var0_np, m0, v0 = adam_update_numpy( + var0_np, grads0_np, t, m0, v0, lr=lr_np) + var1_np, m1, v1 = adam_update_numpy( + var1_np, grads1_np, t, m1, v1, lr=lr_np) + + # Validate updated params + self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) + self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + def testTensorLearningRate(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: with self.cached_session(): @@ -230,13 +276,13 @@ class AdamOptimizerTest(test.TestCase): self.assertAllClose([1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 4.0], self.evaluate(var1)) - beta1_power, beta2_power = get_beta_accumulators(opt, dtype) - + beta_1_power, beta_2_power = get_beta_accumulators(opt, dtype) # Run 3 steps of Adam - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, self.evaluate(beta1_power)) - self.assertAllCloseAccordingToType(0.999**t, - self.evaluate(beta2_power)) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), + self.evaluate(beta_1_power)) + self.assertAllCloseAccordingToType(0.999**(t + 1), + self.evaluate(beta_2_power)) update.run() var0_np, m0, v0 = adam_update_numpy(var0_np, grads0_np, t, m0, v0) @@ -265,17 +311,18 @@ class AdamOptimizerTest(test.TestCase): update2 = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - beta1_power, beta2_power = get_beta_accumulators(opt, dtype) + beta_1_power, beta_2_power = get_beta_accumulators(opt, dtype) # Fetch params to validate initial values self.assertAllClose([1.0, 2.0], self.evaluate(var0)) self.assertAllClose([3.0, 4.0], self.evaluate(var1)) # Run 3 steps of intertwined Adam1 and Adam2. - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, self.evaluate(beta1_power)) - self.assertAllCloseAccordingToType(0.999**t, - self.evaluate(beta2_power)) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), + self.evaluate(beta_1_power)) + self.assertAllCloseAccordingToType(0.999**(t + 1), + self.evaluate(beta_2_power)) if t % 2 == 0: update1.run() else: @@ -296,7 +343,7 @@ class AdamOptimizerTest(test.TestCase): opt.minimize(lambda: v1 + v2, var_list=[v1, v2]) # There should be iteration, hyper variables, and two unique slot # variables for v1 and v2 respectively. - self.assertEqual(9, len(set(opt.variables()))) + self.assertEqual(10, len(set(opt.variables()))) def testAmsgradWithError(self): with self.assertRaisesRegexp(ValueError, diff --git a/tensorflow/python/keras/optimizer_v2/adamax.py b/tensorflow/python/keras/optimizer_v2/adamax.py index 67b678f862..ddd78584f8 100644 --- a/tensorflow/python/keras/optimizer_v2/adamax.py +++ b/tensorflow/python/keras/optimizer_v2/adamax.py @@ -44,7 +44,8 @@ class Adamax(adam.Adam): beta_1=0.9, beta_2=0.999, epsilon=1e-7, - name='Adamax'): + name='Adamax', + **kwargs): """Construct a new Adamax optimizer. Initialization: @@ -87,6 +88,7 @@ class Adamax(adam.Adam): epsilon: A small constant for numerical stability. name: Optional name for the operations created when applying gradients. Defaults to "Adamax". + **kwargs: keyword arguments. Allowed to be {`decay`} """ # pylint: disable=useless-super-delegation super(Adamax, self).__init__( @@ -95,38 +97,40 @@ class Adamax(adam.Adam): beta_2=beta_2, epsilon=epsilon, amsgrad=False, - name=name) + name=name, + **kwargs) # pylint: enable=useless-super-delegation def _resource_apply_dense(self, grad, var): - grad_dtype = grad.dtype.base_dtype + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) m = self.get_slot(var, 'm') v = self.get_slot(var, 'v') - local_step = math_ops.cast(self.iterations + 1, grad_dtype) - beta_1_t = math_ops.cast(self._get_hyper('beta_1'), grad_dtype) - beta_2_t = math_ops.cast(self._get_hyper('beta_2'), grad_dtype) + beta_1_t = self._get_hyper('beta_1', var_dtype) + beta_2_t = self._get_hyper('beta_2', var_dtype) + local_step = math_ops.cast(self.iterations + 1, var_dtype) beta_1_power = math_ops.pow(beta_1_t, local_step) return training_ops.resource_apply_ada_max( var.handle, m.handle, v.handle, beta_1_power, - math_ops.cast(self._get_hyper('learning_rate'), grad_dtype), + lr_t, beta_1_t, beta_2_t, - math_ops.cast(self._get_hyper('epsilon'), grad_dtype), + self._get_hyper('epsilon', var_dtype), grad, use_locking=self._use_locking) def _resource_apply_sparse(self, grad, var, indices): - grad_dtype = grad.dtype.base_dtype + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) - local_step = math_ops.cast(self.iterations + 1, grad_dtype) - beta_1_t = math_ops.cast(self._get_hyper('beta_1'), grad_dtype) - beta_2_t = math_ops.cast(self._get_hyper('beta_2'), grad_dtype) + beta_1_t = self._get_hyper('beta_1', var_dtype) + beta_2_t = self._get_hyper('beta_2', var_dtype) + local_step = math_ops.cast(self.iterations + 1, var_dtype) beta_1_power = math_ops.pow(beta_1_t, local_step) - lr_t = math_ops.cast(self._get_hyper('learning_rate'), grad_dtype) - epsilon_t = math_ops.cast(self._get_hyper('epsilon'), grad_dtype) + epsilon_t = self._get_hyper('epsilon', var_dtype) # m_t = beta1 * m + (1 - beta1) * g_t m = self.get_slot(var, 'm') diff --git a/tensorflow/python/keras/optimizer_v2/adamax_test.py b/tensorflow/python/keras/optimizer_v2/adamax_test.py index c6b45ccbe9..aa215b0faf 100644 --- a/tensorflow/python/keras/optimizer_v2/adamax_test.py +++ b/tensorflow/python/keras/optimizer_v2/adamax_test.py @@ -44,7 +44,7 @@ def adamax_update_numpy(param, epsilon=1e-8): m_t = beta1 * m + (1 - beta1) * g_t v_t = np.maximum(beta2 * v, np.abs(g_t)) - param_t = param - (alpha / (1 - beta1**t)) * (m_t / (v_t + epsilon)) + param_t = param - (alpha / (1 - beta1**(t + 1))) * (m_t / (v_t + epsilon)) return param_t, m_t, v_t @@ -61,8 +61,8 @@ def adamax_sparse_update_numpy(param, m_t, v_t, param_t = np.copy(m), np.copy(v), np.copy(param) m_t_slice = beta1 * m[indices] + (1 - beta1) * g_t v_t_slice = np.maximum(beta2 * v[indices], np.abs(g_t)) - param_t_slice = param[indices] - ((alpha / (1 - beta1**t)) * - (m_t_slice / (v_t_slice + epsilon))) + param_t_slice = param[indices] - ( + (alpha / (1 - beta1**(t + 1))) * (m_t_slice / (v_t_slice + epsilon))) m_t[indices] = m_t_slice v_t[indices] = v_t_slice param_t[indices] = param_t_slice @@ -111,8 +111,8 @@ class AdamaxOptimizerTest(test.TestCase): beta1_power = get_beta_accumulators(opt, dtype) # Run 3 steps of Adamax - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), beta1_power.eval()) update.run() var0_np, m0, v0 = adamax_sparse_update_numpy( @@ -190,7 +190,8 @@ class AdamaxOptimizerTest(test.TestCase): grads1 = constant_op.constant(grads1_np) opt = adamax.Adamax() - update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + if not context.executing_eagerly(): + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) if not context.executing_eagerly(): self.evaluate(variables.global_variables_initializer()) @@ -199,18 +200,71 @@ class AdamaxOptimizerTest(test.TestCase): self.assertAllClose([3.0, 4.0], self.evaluate(var1)) # Run 3 steps of Adamax - for t in range(1, 4): + for t in range(3): + beta_1_power = get_beta_accumulators(opt, dtype) + self.assertAllCloseAccordingToType(0.9**(t + 1), + self.evaluate(beta_1_power)) if not context.executing_eagerly(): self.evaluate(update) - elif t > 1: + else: opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + var0_np, m0, v0 = adamax_update_numpy(var0_np, grads0_np, t, m0, v0) + var1_np, m1, v1 = adamax_update_numpy(var1_np, grads1_np, t, m1, v1) + + # Validate updated params + self.assertAllCloseAccordingToType( + var0_np, self.evaluate(var0), rtol=1e-2) + self.assertAllCloseAccordingToType( + var1_np, self.evaluate(var1), rtol=1e-2) + + @test_util.run_in_graph_and_eager_modes(reset_test=True) + def testBasicWithLearningRateDecay(self): + for i, dtype in enumerate([dtypes.half, dtypes.float32, dtypes.float64]): + with self.session(graph=ops.Graph()): + # Initialize variables for numpy implementation. + m0, v0, m1, v1 = 0.0, 0.0, 0.0, 0.0 + var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) + grads0_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) + var1_np = np.array([3.0, 4.0], dtype=dtype.as_numpy_dtype) + grads1_np = np.array([0.01, 0.01], dtype=dtype.as_numpy_dtype) + + var0 = resource_variable_ops.ResourceVariable( + var0_np, name="var0_%d" % i) + var1 = resource_variable_ops.ResourceVariable( + var1_np, name="var1_%d" % i) + + grads0 = constant_op.constant(grads0_np) + grads1 = constant_op.constant(grads1_np) + + learning_rate = 0.001 + decay = 0.002 + opt = adamax.Adamax(learning_rate=learning_rate, decay=decay) + if not context.executing_eagerly(): + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + + if not context.executing_eagerly(): + self.evaluate(variables.global_variables_initializer()) + # Fetch params to validate initial values + self.assertAllClose([1.0, 2.0], self.evaluate(var0)) + self.assertAllClose([3.0, 4.0], self.evaluate(var1)) + + # Run 3 steps of Adamax + for t in range(3): beta_1_power = get_beta_accumulators(opt, dtype) self.assertAllCloseAccordingToType(0.9**(t + 1), self.evaluate(beta_1_power)) + if not context.executing_eagerly(): + self.evaluate(update) + else: + opt.apply_gradients(zip([grads0, grads1], [var0, var1])) - var0_np, m0, v0 = adamax_update_numpy(var0_np, grads0_np, t, m0, v0) - var1_np, m1, v1 = adamax_update_numpy(var1_np, grads1_np, t, m1, v1) + lr = learning_rate / (1 + decay * t) + + var0_np, m0, v0 = adamax_update_numpy( + var0_np, grads0_np, t, m0, v0, alpha=lr) + var1_np, m1, v1 = adamax_update_numpy( + var1_np, grads1_np, t, m1, v1, alpha=lr) # Validate updated params self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0), @@ -243,8 +297,8 @@ class AdamaxOptimizerTest(test.TestCase): beta1_power = get_beta_accumulators(opt, dtype) # Run 3 steps of Adamax - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), beta1_power.eval()) update.run() var0_np, m0, v0 = adamax_update_numpy(var0_np, grads0_np, t, m0, v0) @@ -280,8 +334,8 @@ class AdamaxOptimizerTest(test.TestCase): self.assertAllClose([3.0, 4.0], var1.eval()) # Run 3 steps of intertwined Adamax1 and Adamax2. - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), beta1_power.eval()) if t % 2 == 0: update1.run() else: @@ -302,7 +356,7 @@ class AdamaxOptimizerTest(test.TestCase): opt.minimize(lambda: v1 + v2, var_list=[v1, v2]) # There should be iteration, hyper variables, and two unique slot # variables for v1 and v2 respectively. - self.assertEqual(9, len(set(opt.variables()))) + self.assertEqual(10, len(set(opt.variables()))) if __name__ == "__main__": diff --git a/tensorflow/python/keras/optimizer_v2/ftrl.py b/tensorflow/python/keras/optimizer_v2/ftrl.py index 2faf65eab3..e278e352f5 100644 --- a/tensorflow/python/keras/optimizer_v2/ftrl.py +++ b/tensorflow/python/keras/optimizer_v2/ftrl.py @@ -40,7 +40,8 @@ class Ftrl(optimizer_v2.OptimizerV2): l1_regularization_strength=0.0, l2_regularization_strength=0.0, name='Ftrl', - l2_shrinkage_regularization_strength=0.0): + l2_shrinkage_regularization_strength=0.0, + **kwargs): r"""Construct a new FTRL optimizer. Args: @@ -68,7 +69,8 @@ class Ftrl(optimizer_v2.OptimizerV2): w_{t+1} = w_t - lr_t / (1 + 2*L2*lr_t) * g_t - 2*L2_shrinkage*lr_t / (1 + 2*L2*lr_t) * w_t where lr_t is the learning rate at t. - When input is sparse shrinkage will only happen on the active weights. + When input is sparse shrinkage will only happen on the active weights.\ + **kwargs: keyword arguments. Allowed to be {`decay`} Raises: ValueError: If one of the arguments is invalid. @@ -77,7 +79,7 @@ class Ftrl(optimizer_v2.OptimizerV2): See [paper] (https://www.eecs.tufts.edu/~dsculley/papers/ad-click-prediction.pdf) """ - super(Ftrl, self).__init__(name) + super(Ftrl, self).__init__(name, **kwargs) if initial_accumulator_value < 0.0: raise ValueError( @@ -100,6 +102,7 @@ class Ftrl(optimizer_v2.OptimizerV2): ' or zero' % l2_shrinkage_regularization_strength) self._set_hyper('learning_rate', learning_rate) + self._set_hyper('decay', self._initial_decay) self._set_hyper('learning_rate_power', learning_rate_power) self._set_hyper('l1_regularization_strength', l1_regularization_strength) self._set_hyper('l2_regularization_strength', l2_regularization_strength) @@ -118,13 +121,12 @@ class Ftrl(optimizer_v2.OptimizerV2): def _resource_apply_dense(self, grad, var): var_dtype = var.dtype.base_dtype - learning_rate = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) - learning_rate_power = math_ops.cast( - self._get_hyper('learning_rate_power'), var_dtype) - l1_regularization_strength = math_ops.cast( - self._get_hyper('l1_regularization_strength'), var_dtype) - l2_regularization_strength = math_ops.cast( - self._get_hyper('l2_regularization_strength'), var_dtype) + lr_t = self._decayed_lr(var_dtype) + learning_rate_power = self._get_hyper('learning_rate_power', var_dtype) + l1_regularization_strength = self._get_hyper('l1_regularization_strength', + var_dtype) + l2_regularization_strength = self._get_hyper('l2_regularization_strength', + var_dtype) accum = self.get_slot(var, 'accumulator') linear = self.get_slot(var, 'linear') if self._l2_shrinkage_regularization_strength <= 0.0: @@ -133,7 +135,7 @@ class Ftrl(optimizer_v2.OptimizerV2): accum.handle, linear.handle, grad, - learning_rate, + lr_t, l1_regularization_strength, l2_regularization_strength, learning_rate_power, @@ -144,7 +146,7 @@ class Ftrl(optimizer_v2.OptimizerV2): accum.handle, linear.handle, grad, - learning_rate, + lr_t, l1_regularization_strength, l2_regularization_strength, math_ops.cast(self._l2_shrinkage_regularization_strength, var_dtype), @@ -153,13 +155,12 @@ class Ftrl(optimizer_v2.OptimizerV2): def _resource_apply_sparse(self, grad, var, indices): var_dtype = var.dtype.base_dtype - learning_rate = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) - learning_rate_power = math_ops.cast( - self._get_hyper('learning_rate_power'), var_dtype) - l1_regularization_strength = math_ops.cast( - self._get_hyper('l1_regularization_strength'), var_dtype) - l2_regularization_strength = math_ops.cast( - self._get_hyper('l2_regularization_strength'), var_dtype) + lr_t = self._decayed_lr(var_dtype) + learning_rate_power = self._get_hyper('learning_rate_power', var_dtype) + l1_regularization_strength = self._get_hyper('l1_regularization_strength', + var_dtype) + l2_regularization_strength = self._get_hyper('l2_regularization_strength', + var_dtype) accum = self.get_slot(var, 'accumulator') linear = self.get_slot(var, 'linear') if self._l2_shrinkage_regularization_strength <= 0.0: @@ -169,7 +170,7 @@ class Ftrl(optimizer_v2.OptimizerV2): linear.handle, grad, indices, - learning_rate, + lr_t, l1_regularization_strength, l2_regularization_strength, learning_rate_power, @@ -181,7 +182,7 @@ class Ftrl(optimizer_v2.OptimizerV2): linear.handle, grad, indices, - learning_rate, + lr_t, l1_regularization_strength, l2_regularization_strength, math_ops.cast(self._l2_shrinkage_regularization_strength, var_dtype), @@ -193,6 +194,8 @@ class Ftrl(optimizer_v2.OptimizerV2): config.update({ 'learning_rate': self._serialize_hyperparameter('learning_rate'), + 'decay': + self._serialize_hyperparameter('decay'), 'initial_accumulator_value': self._initial_accumulator_value, 'learning_rate_power': diff --git a/tensorflow/python/keras/optimizer_v2/gradient_descent.py b/tensorflow/python/keras/optimizer_v2/gradient_descent.py index 90106c941c..03e4515e02 100644 --- a/tensorflow/python/keras/optimizer_v2/gradient_descent.py +++ b/tensorflow/python/keras/optimizer_v2/gradient_descent.py @@ -19,7 +19,6 @@ from __future__ import print_function from tensorflow.python.framework import ops from tensorflow.python.keras.optimizer_v2 import optimizer_v2 -from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.training import training_ops @@ -62,7 +61,8 @@ class SGD(optimizer_v2.OptimizerV2): learning_rate=0.001, momentum=0.0, nesterov=False, - name="SGD"): + name="SGD", + **kwargs): """Construct a new Stochastic Gradient Descent or Momentum optimizer. Arguments: @@ -72,9 +72,11 @@ class SGD(optimizer_v2.OptimizerV2): nesterov: boolean. Whether to apply Nesterov momentum. name: Optional name prefix for the operations created when applying gradients. Defaults to 'SGD'. + **kwargs: keyword arguments. Allowed to be {`decay`} """ - super(SGD, self).__init__(name) + super(SGD, self).__init__(name, **kwargs) self._set_hyper("learning_rate", learning_rate) + self._set_hyper("decay", self._initial_decay) self._momentum = False if isinstance(momentum, ops.Tensor) or callable(momentum) or momentum > 0: @@ -91,44 +93,44 @@ class SGD(optimizer_v2.OptimizerV2): self.add_slot(var, "momentum") def _resource_apply_dense(self, grad, var): - learning_rate = self._get_hyper("learning_rate") + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) if self._momentum: momentum_var = self.get_slot(var, "momentum") return training_ops.resource_apply_momentum( var.handle, momentum_var.handle, - math_ops.cast(learning_rate, grad.dtype.base_dtype), + lr_t, grad, - math_ops.cast(self._get_hyper("momentum"), grad.dtype.base_dtype), + self._get_hyper("momentum", var_dtype), use_locking=self._use_locking, use_nesterov=self._nesterov) else: return training_ops.resource_apply_gradient_descent( - var.handle, - math_ops.cast(learning_rate, grad.dtype.base_dtype), - grad, - use_locking=self._use_locking) + var.handle, lr_t, grad, use_locking=self._use_locking) def _resource_apply_sparse_duplicate_indices(self, grad, var, indices): if self._momentum: return super(SGD, self)._resource_apply_sparse_duplicate_indices( grad, var, indices) else: - return resource_variable_ops.resource_scatter_add( - var.handle, indices, -grad * math_ops.cast( - self._get_hyper("learning_rate"), grad.dtype.base_dtype)) + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) + return resource_variable_ops.resource_scatter_add(var.handle, indices, + -grad * lr_t) def _resource_apply_sparse(self, grad, var, indices): # This method is only needed for momentum optimization. - learning_rate = self._get_hyper("learning_rate") + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) momentum_var = self.get_slot(var, "momentum") return training_ops.resource_sparse_apply_momentum( var.handle, momentum_var.handle, - math_ops.cast(learning_rate, grad.dtype.base_dtype), + lr_t, grad, indices, - math_ops.cast(self._get_hyper("momentum"), grad.dtype.base_dtype), + self._get_hyper("momentum", var_dtype), use_locking=self._use_locking, use_nesterov=self._nesterov) @@ -136,6 +138,7 @@ class SGD(optimizer_v2.OptimizerV2): config = super(SGD, self).get_config() config.update({ "learning_rate": self._serialize_hyperparameter("learning_rate"), + "decay": self._serialize_hyperparameter("decay"), "momentum": self._serialize_hyperparameter("momentum"), "nesterov": self._nesterov, }) diff --git a/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py b/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py index fa7cca1420..348d2728c8 100644 --- a/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py +++ b/tensorflow/python/keras/optimizer_v2/gradient_descent_test.py @@ -47,7 +47,6 @@ class GradientDescentOptimizerTest(test.TestCase): grads0 = constant_op.constant([0.1, 0.1], dtype=dtype) grads1 = constant_op.constant([0.01, 0.01], dtype=dtype) sgd = gradient_descent.SGD(3.0) - # self.assertFalse(sgd._initial_decay) sgd_op = sgd.apply_gradients(zip([grads0, grads1], [var0, var1])) self.evaluate(variables.global_variables_initializer()) # Run 1 step of sgd @@ -58,6 +57,43 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([3.0 - 3.0 * 0.01, 4.0 - 3.0 * 0.01], self.evaluate(var1)) + @test_util.run_in_graph_and_eager_modes + def testBasicWithLearningRateDecay(self): + for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: + with self.cached_session(): + var0 = resource_variable_ops.ResourceVariable([1.0, 2.0], dtype=dtype) + var1 = resource_variable_ops.ResourceVariable([3.0, 4.0], dtype=dtype) + grads0 = constant_op.constant([0.1, 0.1], dtype=dtype) + grads1 = constant_op.constant([0.01, 0.01], dtype=dtype) + learning_rate = 3.0 + decay = 0.5 + sgd = gradient_descent.SGD(learning_rate=learning_rate, decay=decay) + if not context.executing_eagerly(): + sgd_op = sgd.apply_gradients(zip([grads0, grads1], [var0, var1])) + self.evaluate(variables.global_variables_initializer()) + # Run 2 steps of sgd + if not context.executing_eagerly(): + self.evaluate(sgd_op) + else: + sgd.apply_gradients(zip([grads0, grads1], [var0, var1])) + # Validate updated params + self.assertAllCloseAccordingToType([1.0 - 3.0 * 0.1, 2.0 - 3.0 * 0.1], + self.evaluate(var0)) + self.assertAllCloseAccordingToType([3.0 - 3.0 * 0.01, 4.0 - 3.0 * 0.01], + self.evaluate(var1)) + + if not context.executing_eagerly(): + self.evaluate(sgd_op) + else: + sgd.apply_gradients(zip([grads0, grads1], [var0, var1])) + # Validate updated params + self.assertAllCloseAccordingToType( + [1.0 - 3.0 * 0.1 - 2.0 * 0.1, 2.0 - 3.0 * 0.1 - 2.0 * 0.1], + self.evaluate(var0)) + self.assertAllCloseAccordingToType( + [3.0 - 3.0 * 0.01 - 2.0 * 0.01, 4.0 - 3.0 * 0.01 - 2.0 * 0.01], + self.evaluate(var1)) + @test_util.run_in_graph_and_eager_modes def testBasicCallableParams(self): for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: @@ -170,6 +206,36 @@ class GradientDescentOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType([[3.0], [4.0 - 3.0 * 0.01]], self.evaluate(var1)) + def testSparseBasicWithLearningRateDecay(self): + for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: + with self.cached_session(): + var0 = variables.Variable([[1.0], [2.0]], dtype=dtype) + var1 = variables.Variable([[3.0], [4.0]], dtype=dtype) + grads0 = ops.IndexedSlices( + constant_op.constant([0.1], shape=[1, 1], dtype=dtype), + constant_op.constant([0]), constant_op.constant([2, 1])) + grads1 = ops.IndexedSlices( + constant_op.constant([0.01], shape=[1, 1], dtype=dtype), + constant_op.constant([1]), constant_op.constant([2, 1])) + sgd_op = gradient_descent.SGD( + 3.0, decay=0.5).apply_gradients( + zip([grads0, grads1], [var0, var1])) + self.evaluate(variables.global_variables_initializer()) + # Run 2 steps of sgd + self.evaluate(sgd_op) + # Validate updated params + self.assertAllCloseAccordingToType([[1.0 - 3.0 * 0.1], [2.0]], + self.evaluate(var0)) + self.assertAllCloseAccordingToType([[3.0], [4.0 - 3.0 * 0.01]], + self.evaluate(var1)) + + self.evaluate(sgd_op) + # Validate updated params + self.assertAllCloseAccordingToType( + [[1.0 - 3.0 * 0.1 - 2.0 * 0.1], [2.0]], self.evaluate(var0)) + self.assertAllCloseAccordingToType( + [[3.0], [4.0 - 3.0 * 0.01 - 2.0 * 0.01]], self.evaluate(var1)) + def testCapturingInDefunWhileExecutingEagerly(self): with context.eager_mode(): optimizer = gradient_descent.SGD(1.0) diff --git a/tensorflow/python/keras/optimizer_v2/nadam.py b/tensorflow/python/keras/optimizer_v2/nadam.py index 4be421a73f..00b095e0dc 100644 --- a/tensorflow/python/keras/optimizer_v2/nadam.py +++ b/tensorflow/python/keras/optimizer_v2/nadam.py @@ -53,13 +53,46 @@ class Nadam(adam.Adam): See [Dozat, T., 2015](http://cs229.stanford.edu/proj2015/054_report.pdf). """ + def __init__(self, + learning_rate=0.001, + beta_1=0.9, + beta_2=0.999, + epsilon=1e-7, + name='Nadam', + **kwargs): + """Construct a new Nadam optimizer. + + Args: + learning_rate: A Tensor or a floating point value. The learning rate. + beta_1: A float value or a constant float tensor. The exponential decay + rate for the 1st moment estimates. + beta_2: A float value or a constant float tensor. The exponential decay + rate for the exponentially weighted infinity norm. + epsilon: A small constant for numerical stability. + name: Optional name for the operations created when applying gradients. + Defaults to "Adamax". + **kwargs: keyword arguments. Allowed to be {`decay`} + """ + + # pylint: disable=useless-super-delegation + super(Nadam, self).__init__( + learning_rate=learning_rate, + beta_1=beta_1, + beta_2=beta_2, + epsilon=epsilon, + amsgrad=False, + name=name, + **kwargs) + # pylint: enable=useless-super-delegation + def _resource_apply_dense(self, grad, var): - grad_dtype = grad.dtype.base_dtype + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) m = self.get_slot(var, 'm') v = self.get_slot(var, 'v') - local_step = math_ops.cast(self.iterations + 1, grad_dtype) - beta_1_t = math_ops.cast(self._get_hyper('beta_1'), grad_dtype) - beta_2_t = math_ops.cast(self._get_hyper('beta_2'), grad_dtype) + beta_1_t = self._get_hyper('beta_1', var_dtype) + beta_2_t = self._get_hyper('beta_2', var_dtype) + local_step = math_ops.cast(self.iterations + 1, var_dtype) beta_1_power = math_ops.pow(beta_1_t, local_step) beta_2_power = math_ops.pow(beta_2_t, local_step) return training_ops.resource_apply_adam( @@ -68,23 +101,23 @@ class Nadam(adam.Adam): v.handle, beta_1_power, beta_2_power, - math_ops.cast(self._get_hyper('learning_rate'), grad_dtype), + lr_t, beta_1_t, beta_2_t, - math_ops.cast(self._get_hyper('epsilon'), grad_dtype), + self._get_hyper('epsilon', var_dtype), grad, use_locking=self._use_locking, use_nesterov=True) def _resource_apply_sparse(self, grad, var, indices): var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) + beta_1_t = self._get_hyper('beta_1', var_dtype) + beta_2_t = self._get_hyper('beta_2', var_dtype) local_step = math_ops.cast(self.iterations + 1, var_dtype) - beta_1_t = math_ops.cast(self._get_hyper('beta_1'), var_dtype) - beta_2_t = math_ops.cast(self._get_hyper('beta_2'), var_dtype) beta_1_power = math_ops.pow(beta_1_t, local_step) beta_2_power = math_ops.pow(beta_2_t, local_step) - lr_t = math_ops.cast(self._get_hyper('learning_rate'), var_dtype) - epsilon_t = math_ops.cast(self._get_hyper('epsilon'), var_dtype) + epsilon_t = self._get_hyper('epsilon', var_dtype) lr = (lr_t * math_ops.sqrt(1 - beta_2_power) / (1 - beta_1_power)) # m_t = beta1 * m + (1 - beta1) * g_t diff --git a/tensorflow/python/keras/optimizer_v2/nadam_test.py b/tensorflow/python/keras/optimizer_v2/nadam_test.py index 9cc81b1d11..b7132bbea7 100644 --- a/tensorflow/python/keras/optimizer_v2/nadam_test.py +++ b/tensorflow/python/keras/optimizer_v2/nadam_test.py @@ -48,7 +48,7 @@ def nadam_update_numpy(param, beta1=0.9, beta2=0.999, epsilon=1e-8): - alpha_t = alpha * np.sqrt(1 - beta2**t) / (1 - beta1**t) + alpha_t = alpha * np.sqrt(1 - beta2**(t + 1)) / (1 - beta1**(t + 1)) m_t = beta1 * m + (1 - beta1) * g_t v_t = beta2 * v + (1 - beta2) * g_t * g_t @@ -97,9 +97,9 @@ class NadamOptimizerTest(test.TestCase): beta1_power, beta2_power = get_beta_accumulators(opt, dtype) # Run 3 steps of Nadam - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) - self.assertAllCloseAccordingToType(0.999**t, beta2_power.eval()) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), beta1_power.eval()) + self.assertAllCloseAccordingToType(0.999**(t + 1), beta2_power.eval()) update.run() var0_np, m0, v0 = nadam_update_numpy( @@ -146,9 +146,9 @@ class NadamOptimizerTest(test.TestCase): beta1_power, beta2_power = get_beta_accumulators(opt, dtype) # Run 3 steps of Nadam - for t in range(1, 4): - self.assertAllCloseAccordingToType(0.9**t, beta1_power.eval()) - self.assertAllCloseAccordingToType(0.999**t, beta2_power.eval()) + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), beta1_power.eval()) + self.assertAllCloseAccordingToType(0.999**(t + 1), beta2_power.eval()) update.run() var0_np, m0, v0 = nadam_update_numpy(var0_np, grads0_np, t, m0, v0) @@ -158,12 +158,51 @@ class NadamOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, var0.eval()) self.assertAllCloseAccordingToType(var1_np, var1.eval()) - def testBasic(self): - self.doTestBasic(use_resource=False) - def testResourceBasic(self): self.doTestBasic(use_resource=True) + def testBasicWithLearningRateDecay(self): + for dtype in [dtypes.half, dtypes.float32, dtypes.float64]: + with self.cached_session(): + # Initialize variables for numpy implementation. + m0, v0, m1, v1 = 0.0, 0.0, 0.0, 0.0 + var0_np = np.array([1.0, 2.0], dtype=dtype.as_numpy_dtype) + grads0_np = np.array([0.1, 0.1], dtype=dtype.as_numpy_dtype) + var1_np = np.array([3.0, 4.0], dtype=dtype.as_numpy_dtype) + grads1_np = np.array([0.01, 0.01], dtype=dtype.as_numpy_dtype) + + var0 = resource_variable_ops.ResourceVariable(var0_np) + var1 = resource_variable_ops.ResourceVariable(var1_np) + grads0 = constant_op.constant(grads0_np) + grads1 = constant_op.constant(grads1_np) + learning_rate = 0.001 + decay = 0.5 + opt = nadam.Nadam(learning_rate=learning_rate, decay=decay) + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + variables.global_variables_initializer().run() + + # Fetch params to validate initial values + self.assertAllClose([1.0, 2.0], var0.eval()) + self.assertAllClose([3.0, 4.0], var1.eval()) + + beta1_power, beta2_power = get_beta_accumulators(opt, dtype) + + # Run 3 steps of Nadam + for t in range(3): + self.assertAllCloseAccordingToType(0.9**(t + 1), beta1_power.eval()) + self.assertAllCloseAccordingToType(0.999**(t + 1), beta2_power.eval()) + update.run() + + lr = learning_rate / (1 + decay * t) + var0_np, m0, v0 = nadam_update_numpy( + var0_np, grads0_np, t, m0, v0, alpha=lr) + var1_np, m1, v1 = nadam_update_numpy( + var1_np, grads1_np, t, m1, v1, alpha=lr) + + # Validate updated params + self.assertAllCloseAccordingToType(var0_np, var0.eval()) + self.assertAllCloseAccordingToType(var1_np, var1.eval()) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/keras/optimizer_v2/optimizer_v2.py b/tensorflow/python/keras/optimizer_v2/optimizer_v2.py index fa7cfa5b8a..ee0076703f 100644 --- a/tensorflow/python/keras/optimizer_v2/optimizer_v2.py +++ b/tensorflow/python/keras/optimizer_v2/optimizer_v2.py @@ -33,6 +33,7 @@ from tensorflow.python.keras import backend from tensorflow.python.keras import initializers from tensorflow.python.keras.engine import base_layer from tensorflow.python.ops import gradients +from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables as tf_variables from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import distribution_strategy_context @@ -114,7 +115,7 @@ class OptimizerV2(optimizer_v1.Optimizer): """ - def __init__(self, name): + def __init__(self, name, **kwargs): """Create a new Optimizer. This must be called by the constructors of subclasses. @@ -128,6 +129,7 @@ class OptimizerV2(optimizer_v1.Optimizer): Args: name: A non-empty string. The name to use for accumulators created for the optimizer. + **kwargs: keyword arguments. Allowed to be {`decay`} Raises: ValueError: If name is malformed. @@ -140,6 +142,12 @@ class OptimizerV2(optimizer_v1.Optimizer): # dict: {variable name : {slot name : variable}} self._slots = {} self._weights = [] + + decay = kwargs.pop("decay", 0.0) + if decay < 0.: + raise ValueError("decay cannot be less than 0: {}".format(decay)) + self._initial_decay = decay + self._prepared = False def minimize(self, @@ -345,9 +353,14 @@ class OptimizerV2(optimizer_v1.Optimizer): else: backend.set_value(self._hyper[name], value) - def _get_hyper(self, name): + def _get_hyper(self, name, dtype=None): value = self._hyper[name] - return self._call_if_callable(value) + if callable(value): + value = value() + if dtype: + return math_ops.cast(value, dtype) + else: + return value def __getattribute__(self, name): """Overridden to support hyperparameter access.""" @@ -422,6 +435,15 @@ class OptimizerV2(optimizer_v1.Optimizer): self._prepare() return self._iterations + def _decayed_lr(self, var_dtype): + """Get decayed learning rate as a Tensor with dtype=var_dtype.""" + lr_t = self._get_hyper("learning_rate", var_dtype) + if self._initial_decay > 0.: + local_step = math_ops.cast(self.iterations, var_dtype) + decay_t = self._get_hyper("decay", var_dtype) + lr_t = lr_t / (1. + decay_t * local_step) + return lr_t + @abc.abstractmethod def get_config(self): """Returns the config of the optimimizer. diff --git a/tensorflow/python/keras/optimizer_v2/rmsprop.py b/tensorflow/python/keras/optimizer_v2/rmsprop.py index eae5620349..6a5b334fc4 100644 --- a/tensorflow/python/keras/optimizer_v2/rmsprop.py +++ b/tensorflow/python/keras/optimizer_v2/rmsprop.py @@ -19,7 +19,6 @@ from __future__ import print_function from tensorflow.python.framework import ops from tensorflow.python.keras.optimizer_v2 import optimizer_v2 -from tensorflow.python.ops import math_ops from tensorflow.python.training import training_ops @@ -58,7 +57,8 @@ class RMSprop(optimizer_v2.OptimizerV2): momentum=0.0, epsilon=1e-7, centered=False, - name="RMSprop"): + name="RMSprop", + **kwargs): """Construct a new RMSprop optimizer. Note that in the dense implementation of this algorithm, variables and their @@ -88,9 +88,11 @@ class RMSprop(optimizer_v2.OptimizerV2): `epsilon` can each be a callable that takes no arguments and returns the actual value to use. This can be useful for changing these values across different invocations of optimizer functions. @end_compatibility + **kwargs: keyword arguments. Allowed to be {`decay`} """ - super(RMSprop, self).__init__(name) + super(RMSprop, self).__init__(name, **kwargs) self._set_hyper("learning_rate", learning_rate) + self._set_hyper("decay", self._initial_decay) self._set_hyper("rho", rho) self._momentum = False @@ -111,13 +113,13 @@ class RMSprop(optimizer_v2.OptimizerV2): self.add_slot(var, "mg") def _resource_apply_dense(self, grad, var): + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) rms = self.get_slot(var, "rms") mom = self.get_slot(var, "momentum") - learning_rate = math_ops.cast( - self._get_hyper("learning_rate"), grad.dtype.base_dtype) - rho = math_ops.cast(self._get_hyper("rho"), grad.dtype.base_dtype) - momentum = math_ops.cast(self._get_hyper("momentum"), grad.dtype.base_dtype) - epsilon = math_ops.cast(self._get_hyper("epsilon"), grad.dtype.base_dtype) + rho = self._get_hyper("rho", var_dtype) + momentum = self._get_hyper("momentum", var_dtype) + epsilon = self._get_hyper("epsilon", var_dtype) if self._centered: mg = self.get_slot(var, "mg") return training_ops.resource_apply_centered_rms_prop( @@ -125,7 +127,7 @@ class RMSprop(optimizer_v2.OptimizerV2): mg.handle, rms.handle, mom.handle, - learning_rate, + lr_t, rho, momentum, epsilon, @@ -136,7 +138,7 @@ class RMSprop(optimizer_v2.OptimizerV2): var.handle, rms.handle, mom.handle, - learning_rate, + lr_t, rho, momentum, epsilon, @@ -144,13 +146,13 @@ class RMSprop(optimizer_v2.OptimizerV2): use_locking=self._use_locking) def _resource_apply_sparse(self, grad, var, indices): + var_dtype = var.dtype.base_dtype + lr_t = self._decayed_lr(var_dtype) rms = self.get_slot(var, "rms") mom = self.get_slot(var, "momentum") - learning_rate = math_ops.cast( - self._get_hyper("learning_rate"), grad.dtype.base_dtype) - rho = math_ops.cast(self._get_hyper("rho"), grad.dtype.base_dtype) - momentum = math_ops.cast(self._get_hyper("momentum"), grad.dtype.base_dtype) - epsilon = math_ops.cast(self._get_hyper("epsilon"), grad.dtype.base_dtype) + rho = self._get_hyper("rho", var_dtype) + momentum = self._get_hyper("momentum", var_dtype) + epsilon = self._get_hyper("epsilon", var_dtype) if self._centered: mg = self.get_slot(var, "mg") return training_ops.resource_sparse_apply_centered_rms_prop( @@ -158,7 +160,7 @@ class RMSprop(optimizer_v2.OptimizerV2): mg.handle, rms.handle, mom.handle, - learning_rate, + lr_t, rho, momentum, epsilon, @@ -170,7 +172,7 @@ class RMSprop(optimizer_v2.OptimizerV2): var.handle, rms.handle, mom.handle, - learning_rate, + lr_t, rho, momentum, epsilon, @@ -182,6 +184,7 @@ class RMSprop(optimizer_v2.OptimizerV2): config = super(RMSprop, self).get_config() config.update({ "learning_rate": self._serialize_hyperparameter("learning_rate"), + "decay": self._serialize_hyperparameter("decay"), "rho": self._serialize_hyperparameter("rho"), "momentum": self._serialize_hyperparameter("momentum"), "epsilon": self._serialize_hyperparameter("epsilon"), diff --git a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py index 62b64d5cf9..a320cc0c49 100644 --- a/tensorflow/python/keras/optimizer_v2/rmsprop_test.py +++ b/tensorflow/python/keras/optimizer_v2/rmsprop_test.py @@ -158,6 +158,73 @@ class RMSpropOptimizerTest(test.TestCase): self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + def testDenseWithLearningRateDecay(self): + var0_np = np.array([1.0, 2.0]) + grads0_np = np.array([0.1, 0.2]) + var1_np = np.array([3.0, 4.0]) + grads1_np = np.array([0.01, 0.2]) + + var0 = resource_variable_ops.ResourceVariable(var0_np) + var1 = resource_variable_ops.ResourceVariable(var1_np) + grads0 = constant_op.constant(grads0_np) + grads1 = constant_op.constant(grads1_np) + learning_rate = 0.01 + rho = 0.9 + momentum = 0.0 + epsilon = 1e-7 + centered = False + decay = 0.5 + opt = rmsprop.RMSprop( + learning_rate=learning_rate, + rho=rho, + momentum=momentum, + epsilon=epsilon, + centered=centered, + decay=decay) + + update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) + self.evaluate(variables.global_variables_initializer()) + + rms0 = opt.get_slot(var0, "rms") + self.assertTrue(rms0 is not None) + rms1 = opt.get_slot(var1, "rms") + self.assertTrue(rms1 is not None) + mom0 = opt.get_slot(var0, "momentum") + self.assertTrue(mom0 is not None) + mom1 = opt.get_slot(var1, "momentum") + self.assertTrue(mom1 is not None) + + mg0_np = np.array([0.0, 0.0]) + mg1_np = np.array([0.0, 0.0]) + rms0_np = np.array([0.0, 0.0]) + rms1_np = np.array([0.0, 0.0]) + mom0_np = np.array([0.0, 0.0]) + mom1_np = np.array([0.0, 0.0]) + + # Fetch params to validate initial values + self.assertAllClose([1.0, 2.0], self.evaluate(var0)) + self.assertAllClose([3.0, 4.0], self.evaluate(var1)) + + # Run 4 steps of RMSprop + for t in range(2): + self.evaluate(update) + + lr = learning_rate / (1 + decay * t) + var0_np, mg0_np, rms0_np, mom0_np = self._rmsprop_update_numpy( + var0_np, grads0_np, mg0_np, rms0_np, mom0_np, lr, rho, momentum, + epsilon, centered) + var1_np, mg1_np, rms1_np, mom1_np = self._rmsprop_update_numpy( + var1_np, grads1_np, mg1_np, rms1_np, mom1_np, lr, rho, momentum, + epsilon, centered) + + # Validate updated params + self.assertAllCloseAccordingToType(rms0_np, self.evaluate(rms0)) + self.assertAllCloseAccordingToType(rms1_np, self.evaluate(rms1)) + self.assertAllCloseAccordingToType(mom0_np, self.evaluate(mom0)) + self.assertAllCloseAccordingToType(mom1_np, self.evaluate(mom1)) + self.assertAllCloseAccordingToType(var0_np, self.evaluate(var0)) + self.assertAllCloseAccordingToType(var1_np, self.evaluate(var1)) + def testMinimizeSparseResourceVariable(self): for dtype in [dtypes.float32, dtypes.float64]: with self.cached_session(): -- GitLab From cb74272050f4563f8eddee851470986ba6662d91 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Mon, 26 Nov 2018 17:32:18 -0800 Subject: [PATCH 364/672] Add `evaluate` to Benchmark to be compatible with TestCase PiperOrigin-RevId: 222915339 --- tensorflow/python/platform/benchmark.py | 13 +++++++++++++ .../api/golden/v1/tensorflow.test.-benchmark.pbtxt | 4 ++++ .../api/golden/v2/tensorflow.test.-benchmark.pbtxt | 4 ++++ 3 files changed, 21 insertions(+) diff --git a/tensorflow/python/platform/benchmark.py b/tensorflow/python/platform/benchmark.py index 4f7abb311a..d6773d7b81 100644 --- a/tensorflow/python/platform/benchmark.py +++ b/tensorflow/python/platform/benchmark.py @@ -30,6 +30,7 @@ from tensorflow.core.protobuf import config_pb2 from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.core.util import test_log_pb2 from tensorflow.python.client import timeline +from tensorflow.python.framework import ops from tensorflow.python.platform import app from tensorflow.python.platform import gfile from tensorflow.python.platform import tf_logging as logging @@ -299,6 +300,18 @@ class TensorFlowBenchmark(Benchmark): benchmark_values["extras"].update(unreported_extras) return benchmark_values + def evaluate(self, tensors): + """Evaluates tensors and returns numpy values. + + Args: + tensors: A Tensor or a nested list/tuple of Tensors. + + Returns: + tensors numpy values. + """ + sess = ops.get_default_session() or self.cached_session() + return sess.run(tensors) + def _run_benchmarks(regex): """Run benchmarks that match regex `regex`. diff --git a/tensorflow/tools/api/golden/v1/tensorflow.test.-benchmark.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.test.-benchmark.pbtxt index df528e26b6..6fc489c860 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.test.-benchmark.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.test.-benchmark.pbtxt @@ -6,6 +6,10 @@ tf_class { member_method { name: "__init__" } + member_method { + name: "evaluate" + argspec: "args=[\'self\', \'tensors\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "is_abstract" argspec: "args=[\'cls\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.test.-benchmark.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.test.-benchmark.pbtxt index df528e26b6..6fc489c860 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.test.-benchmark.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.test.-benchmark.pbtxt @@ -6,6 +6,10 @@ tf_class { member_method { name: "__init__" } + member_method { + name: "evaluate" + argspec: "args=[\'self\', \'tensors\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "is_abstract" argspec: "args=[\'cls\'], varargs=None, keywords=None, defaults=None" -- GitLab From b84cc997427594a52200c8949c36928ba3aad123 Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Mon, 26 Nov 2018 17:39:09 -0800 Subject: [PATCH 365/672] Improve readability of base_layer.py to improve the experience of users who use the code as a form of documentation (in particular people who subclass Layer). The general principle is to: - Have the Layer class come first in the file - Have subclassable methods come first in the list of methods - Then other public methods, roughly in order of importance - Then private methods - Move auxiliary utilities to a dedicated file PiperOrigin-RevId: 222916181 --- tensorflow/contrib/eager/python/network.py | 4 +- .../contrib/tpu/python/tpu/keras_support.py | 7 +- tensorflow/python/keras/BUILD | 1 + tensorflow/python/keras/engine/base_layer.py | 1894 ++++++++--------- .../python/keras/engine/base_layer_utils.py | 236 ++ tensorflow/python/keras/engine/network.py | 16 +- .../python/keras/optimizer_v2/optimizer_v2.py | 4 +- tensorflow/python/layers/base.py | 11 +- 8 files changed, 1108 insertions(+), 1065 deletions(-) create mode 100644 tensorflow/python/keras/engine/base_layer_utils.py diff --git a/tensorflow/contrib/eager/python/network.py b/tensorflow/contrib/eager/python/network.py index f801d9a47b..5cc0c4f23d 100644 --- a/tensorflow/contrib/eager/python/network.py +++ b/tensorflow/contrib/eager/python/network.py @@ -24,7 +24,7 @@ import weakref from tensorflow.python.eager import context from tensorflow.python.framework import ops -from tensorflow.python.keras.engine import base_layer as keras_base_layer +from tensorflow.python.keras.engine import base_layer_utils from tensorflow.python.layers import base from tensorflow.python.ops import variable_scope from tensorflow.python.platform import tf_logging as logging @@ -220,7 +220,7 @@ class Network(base.Layer): avoid_names = parent_network._owned_layers name_uid_map = parent_network._sub_layer_name_uids else: - name_uid_map = keras_base_layer.get_default_graph_uid_map() + name_uid_map = base_layer_utils.get_default_graph_uid_map() # Figure out which names we have to avoid based on which variable scope # we're nested in. strip_name = self._default_parent_variable_scope.name diff --git a/tensorflow/contrib/tpu/python/tpu/keras_support.py b/tensorflow/contrib/tpu/python/tpu/keras_support.py index c4db4aa0c7..cf3b2e68e9 100644 --- a/tensorflow/contrib/tpu/python/tpu/keras_support.py +++ b/tensorflow/contrib/tpu/python/tpu/keras_support.py @@ -81,6 +81,7 @@ from tensorflow.python.keras import metrics as metrics_module from tensorflow.python.keras import models from tensorflow.python.keras import optimizers as keras_optimizers from tensorflow.python.keras.engine import base_layer +from tensorflow.python.keras.engine import base_layer_utils from tensorflow.python.keras.engine import training_arrays from tensorflow.python.keras.engine import training_utils from tensorflow.python.keras.layers import embeddings @@ -438,7 +439,7 @@ class TPURewriteContext(object): self._default_placeholder = array_ops.placeholder self._default_name_scope = ops.name_scope - self._default_make_variable = base_layer.make_variable + self._default_make_variable = base_layer_utils.make_variable self._default_random_normal = random_ops.random_normal self._default_qr = gen_linalg_ops.qr @@ -486,14 +487,14 @@ class TPURewriteContext(object): gen_linalg_ops.qr = qr ops.name_scope = _name_scope - base_layer.make_variable = variable_scope.get_variable + base_layer_utils.make_variable = variable_scope.get_variable logging.info('Overriding default placeholder.') return def __exit__(self, exc_type, exc_val, exc_tb): array_ops.placeholder = self._default_placeholder ops.name_scope = self._default_name_scope - base_layer.make_variable = self._default_make_variable + base_layer_utils.make_variable = self._default_make_variable random_ops.random_normal = self._default_random_normal gen_linalg_ops.qr = self._default_qr diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index 697f591e35..a7f01817fb 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -122,6 +122,7 @@ py_library( "constraints.py", "engine/__init__.py", "engine/base_layer.py", + "engine/base_layer_utils.py", "engine/distributed_training_utils.py", "engine/input_layer.py", "engine/input_spec.py", diff --git a/tensorflow/python/keras/engine/base_layer.py b/tensorflow/python/keras/engine/base_layer.py index 5426965509..8b795935c1 100644 --- a/tensorflow/python/keras/engine/base_layer.py +++ b/tensorflow/python/keras/engine/base_layer.py @@ -18,8 +18,6 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import collections as collections_lib -import enum # pylint: disable=g-bad-import-order import functools import inspect # Necessary supplement to tf_inspect to deal with variadic args. @@ -36,6 +34,7 @@ from tensorflow.python.keras import backend from tensorflow.python.keras import constraints from tensorflow.python.keras import initializers from tensorflow.python.keras import regularizers +from tensorflow.python.keras.engine import base_layer_utils from tensorflow.python.keras.engine import input_spec from tensorflow.python.keras.utils import generic_utils from tensorflow.python.keras.utils import tf_utils @@ -43,7 +42,6 @@ from tensorflow.python.keras.utils import tf_utils from tensorflow.python.keras.utils.generic_utils import to_snake_case # pylint: disable=unused-import from tensorflow.python.keras.utils.tf_utils import is_tensor_or_tensor_list # pylint: disable=unused-import from tensorflow.python.ops import array_ops -from tensorflow.python.ops import init_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables as tf_variables from tensorflow.python.training.checkpointable import base as checkpointable @@ -55,28 +53,6 @@ from tensorflow.python.util.tf_export import tf_export from tensorflow.tools.docs import doc_controls -class CallConvention(enum.Enum): - """Calling conventions for passing `Layer` inputs to `Layer.call`.""" - # The Layer takes inputs as its first argument, named "inputs" for - # compatibility with the signature of Layer.__call__. This is the mode assumed - # for Layers which are not subclassed Models. - EXPLICIT_INPUTS_ARGUMENT = 1 - # The Layer takes a single positional argument, not named "inputs". It's - # treated like an "inputs" argument. - SINGLE_POSITIONAL_ARGUMENT = 2 - # The Layer has multiple positional arguments to which its inputs should be - # bound. - POSITIONAL_ARGUMENTS_ARE_INPUTS = 3 - - -def _create_mean_metric(value, name=None): - # TODO(psv): Remove this import when b/110718070 is fixed. - from tensorflow.python.keras import metrics as metrics_module # pylint: disable=g-import-not-at-top - metric_obj = metrics_module.Mean(name=name) - result = metric_obj(value) - return metric_obj, result - - @tf_export('keras.layers.Layer') class Layer(checkpointable.CheckpointableBase): """Base layer class. @@ -111,10 +87,6 @@ class Layer(checkpointable.CheckpointableBase): name: The name of the layer (string). dtype: Default dtype of the layer's weights (default of `None` means use the type of the first input). - trainable_variables: List of trainable variables. - non_trainable_variables: List of non-trainable variables. - variables: List of all variables of this layer, trainable and - non-trainable. updates: List of update ops of this layer. losses: List of losses added by this layer. trainable_weights: List of variables to be included in backprop. @@ -159,9 +131,9 @@ class Layer(checkpointable.CheckpointableBase): self.built = False # Provides information about which inputs are compatible with the layer. self.input_spec = None + self.supports_masking = False self._init_set_name(name) - self._activity_regularizer = kwargs.pop('activity_regularizer', None) self._trainable_weights = [] self._non_trainable_weights = [] @@ -190,15 +162,14 @@ class Layer(checkpointable.CheckpointableBase): self._call_fn_args = function_utils.fn_args(self.call) self._compute_previous_mask = ('mask' in self._call_fn_args or hasattr(self, 'compute_mask')) - self._call_convention = CallConvention.EXPLICIT_INPUTS_ARGUMENT + self._call_convention = (base_layer_utils + .CallConvention.EXPLICIT_INPUTS_ARGUMENT) # These lists will be filled via successive calls # to self._add_inbound_node(). self._inbound_nodes = [] self._outbound_nodes = [] - self.supports_masking = False - call_argspec = tf_inspect.getfullargspec(self.call) if 'training' in call_argspec.args: self._expects_training_arg = True @@ -228,543 +199,292 @@ class Layer(checkpointable.CheckpointableBase): else: self._initial_weights = None - def _init_set_name(self, name, zero_based=True): - if not name: - self._name = unique_layer_name( - generic_utils.to_snake_case(self.__class__.__name__), - zero_based=zero_based) - else: - self._name = name - - @property - def dtype(self): - return self._dtype - - @property - def name(self): - return self._name - - @property - def activity_regularizer(self): - """Optional regularizer function for the output of this layer.""" - return self._activity_regularizer - - @activity_regularizer.setter - def activity_regularizer(self, regularizer): - """Optional regularizer function for the output of this layer.""" - self._activity_regularizer = self._no_dependency(regularizer) - - @property - def trainable_weights(self): - return self._trainable_weights if self.trainable else [] - - @property - def non_trainable_weights(self): - if self.trainable: - return self._non_trainable_weights - else: - return self._trainable_weights + self._non_trainable_weights - - @property - def trainable_variables(self): - return self.trainable_weights + def build(self, input_shape): + """Creates the variables of the layer.""" + self.built = True - @property - def non_trainable_variables(self): - return self.non_trainable_weights + @doc_controls.for_subclass_implementers + def call(self, inputs, **kwargs): # pylint: disable=unused-argument + """This is where the layer's logic lives. - @property - def weights(self): - """Returns the list of all layer variables/weights. + Arguments: + inputs: Input tensor, or list/tuple of input tensors. + **kwargs: Additional keyword arguments. Returns: - A list of variables. + A tensor or list/tuple of tensors. """ - return self.trainable_weights + self.non_trainable_weights + return inputs - @property - def variables(self): - """Returns the list of all layer variables/weights. + @doc_controls.for_subclass_implementers + def add_weight(self, + name, + shape, + dtype=None, + initializer=None, + regularizer=None, + trainable=None, + constraint=None, + partitioner=None, + use_resource=None, + synchronization=tf_variables.VariableSynchronization.AUTO, + aggregation=tf_variables.VariableAggregation.NONE, + **kwargs): + """Adds a new variable to the layer, or gets an existing one; returns it. - Returns: - A list of variables. - """ - return self.weights + Arguments: + name: variable name. + shape: variable shape. + dtype: The type of the variable. Defaults to `self.dtype` or `float32`. + initializer: initializer instance (callable). + regularizer: regularizer instance (callable). + trainable: whether the variable should be part of the layer's + "trainable_variables" (e.g. variables, biases) + or "non_trainable_variables" (e.g. BatchNorm mean, stddev). + Note, if the current variable scope is marked as non-trainable + then this parameter is ignored and any added variables are also + marked as non-trainable. `trainable` defaults to `True` unless + `synchronization` is set to `ON_READ`. + constraint: constraint instance (callable). + partitioner: Partitioner to be passed to the `Checkpointable` API. + use_resource: Whether to use `ResourceVariable`. + synchronization: Indicates when a distributed a variable will be + aggregated. Accepted values are constants defined in the class + `tf.VariableSynchronization`. By default the synchronization is set to + `AUTO` and the current `DistributionStrategy` chooses + when to synchronize. If `synchronization` is set to `ON_READ`, + `trainable` must not be set to `True`. + aggregation: Indicates how a distributed variable will be aggregated. + Accepted values are constants defined in the class + `tf.VariableAggregation`. + **kwargs: Additional keyword arguments. Accepted values are `getter` and + `collections`. - @property - def updates(self): - if not self.trainable and not self.stateful: - return [] - return self._updates + Returns: + The created variable. Usually either a `Variable` or `ResourceVariable` + instance. If `partitioner` is not `None`, a `PartitionedVariable` + instance is returned. - @doc_controls.for_subclass_implementers - def add_update(self, updates, inputs=None): - """Add update op(s), potentially dependent on layer inputs. + Raises: + RuntimeError: If called with partioned variable regularization and + eager execution is enabled. + ValueError: When giving unsupported dtype and no initializer or when + trainable has been set to True with synchronization set as `ON_READ`. + """ + # Validate optional keyword arguments. + for kwarg in kwargs: + if kwarg not in ['getter', 'collections']: + raise TypeError('Unknown keyword argument:', kwarg) + getter = kwargs.pop('getter', None) + collections = kwargs.pop('collections', None) - Weight updates (for instance, the updates of the moving mean and variance - in a BatchNormalization layer) may be dependent on the inputs passed - when calling a layer. Hence, when reusing the same layer on - different inputs `a` and `b`, some entries in `layer.updates` may be - dependent on `a` and some on `b`. This method automatically keeps track - of dependencies. + if dtype is None: + dtype = self.dtype or backend.floatx() + dtype = dtypes.as_dtype(dtype) + initializer = initializers.get(initializer) + regularizer = regularizers.get(regularizer) + constraint = constraints.get(constraint) - The `get_updates_for` method allows to retrieve the updates relevant to a - specific set of inputs. + if synchronization == tf_variables.VariableSynchronization.ON_READ: + if trainable: + raise ValueError( + 'Synchronization value can be set to ' + 'VariableSynchronization.ON_READ only for non-trainable variables. ' + 'You have specified trainable=True and ' + 'synchronization=VariableSynchronization.ON_READ.') + else: + # Set trainable to be false when variable is to be synced on read. + trainable = False + elif trainable is None: + trainable = True - This call is ignored when eager execution is enabled (in that case, variable - updates are run on the fly and thus do not need to be tracked for later - execution). + # Initialize variable when no initializer provided + if initializer is None: + # If dtype is DT_FLOAT, provide a uniform unit scaling initializer + if dtype.is_floating: + initializer = initializers.glorot_uniform() + # If dtype is DT_INT/DT_UINT, provide a default value `zero` + # If dtype is DT_BOOL, provide a default value `FALSE` + elif dtype.is_integer or dtype.is_unsigned or dtype.is_bool: + initializer = initializers.zeros() + # NOTES:Do we need to support for handling DT_STRING and DT_COMPLEX here? + else: + raise ValueError('An initializer for variable %s of type %s is required' + ' for layer %s' % (name, dtype.base_dtype, self.name)) - Arguments: - updates: Update op, or list/tuple of update ops. - inputs: If anything other than None is passed, it signals the updates - are conditional on some of the layer's inputs, - and thus they should only be run where these inputs are available. - This is the case for BatchNormalization updates, for instance. - If None, the updates will be taken into account unconditionally, - and you are responsible for making sure that any dependency they might - have is available at runtime. - A step counter might fall into this category. - """ - if context.executing_eagerly(): - return # Updates already applied when in eager mode. + variable = self._add_variable_with_custom_getter( + name=name, + shape=shape, + # TODO(allenl): a `make_variable` equivalent should be added as a + # `Checkpointable` method. + getter=getter or base_layer_utils.make_variable, + # Manage errors in Layer rather than Checkpointable. + overwrite=True, + initializer=initializer, + dtype=dtype, + constraint=constraint, + trainable=trainable and self.trainable, + partitioner=partitioner, + use_resource=use_resource, + collections=collections, + synchronization=synchronization, + aggregation=aggregation) + backend.track_variable(variable) - def process_update(x): - if isinstance(x, ops.Operation): - return x - elif hasattr(x, 'op'): - return x.op - else: - return ops.convert_to_tensor(x) + if regularizer is not None: + # TODO(fchollet): in the future, this should be handled at the + # level of variable creation, and weight regularization losses + # should be variable attributes. + self._handle_weight_regularization(name, variable, regularizer) - updates = generic_utils.to_list(updates) - updates = [process_update(x) for x in updates] - self._updates += updates - if inputs is None: - for u in updates: - u._unconditional_update = True # pylint: disable=protected-access + if trainable: + self._trainable_weights.append(variable) else: - for u in updates: - u._unconditional_update = False # pylint: disable=protected-access + self._non_trainable_weights.append(variable) + return variable - def get_updates_for(self, inputs): - """Retrieves updates relevant to a specific set of inputs. + def get_config(self): + """Returns the config of the layer. - Arguments: - inputs: Input tensor or list/tuple of input tensors. + A layer config is a Python dictionary (serializable) + containing the configuration of a layer. + The same layer can be reinstantiated later + (without its trained weights) from this configuration. - Returns: - List of update ops of the layer that depend on `inputs`. + The config of a layer does not include connectivity + information, nor the layer class name. These are handled + by `Network` (one layer of abstraction above). - Raises: - RuntimeError: If called in Eager mode. + Returns: + Python dictionary. """ - # Updates disabled if layer is not trainable and not explicitly stateful. - if not self.trainable and not self.stateful: - return [] - - if inputs is None: - # Requesting unconditional updates. - return [x for x in self.updates if x._unconditional_update] # pylint: disable=protected-access + config = {'name': self.name, 'trainable': self.trainable} + if hasattr(self, '_batch_input_shape'): + config['batch_input_shape'] = self._batch_input_shape + if hasattr(self, 'dtype'): + config['dtype'] = self.dtype + return config - # Requesting input-conditional updates. - inputs = nest.flatten(inputs) - reachable = tf_utils.get_reachable_from_inputs(inputs, self.updates) - updates = [] - for update in self.updates: - if update in reachable: - updates.append(update) - return updates + @classmethod + def from_config(cls, config): + """Creates a layer from its config. - @property - def losses(self): - """Losses which are associated with this `Layer`. + This method is the reverse of `get_config`, + capable of instantiating the same layer from the config + dictionary. It does not handle layer connectivity + (handled by Network), nor weights (handled by `set_weights`). - Variable regularization tensors are created when this property is accessed, - so it is eager safe: accessing `losses` under a `tf.GradientTape` will - propagate gradients back to the corresponding variables. + Arguments: + config: A Python dictionary, typically the + output of get_config. Returns: - A list of tensors. + A layer instance. """ - collected_losses = [] - if context.executing_eagerly(): - collected_losses.extend(self._eager_losses) - else: - collected_losses.extend(self._losses) - for regularizer in self._callable_losses: - loss_tensor = regularizer() - if loss_tensor is not None: - collected_losses.append(loss_tensor) - return collected_losses - - @doc_controls.for_subclass_implementers - def add_loss(self, losses, inputs=None): - """Add loss tensor(s), potentially dependent on layer inputs. - - Some losses (for instance, activity regularization losses) may be dependent - on the inputs passed when calling a layer. Hence, when reusing the same - layer on different inputs `a` and `b`, some entries in `layer.losses` may - be dependent on `a` and some on `b`. This method automatically keeps track - of dependencies. + return cls(**config) - The `get_losses_for` method allows to retrieve the losses relevant to a - specific set of inputs. + def compute_output_shape(self, input_shape): + """Computes the output shape of the layer. - Note that `add_loss` is not supported when executing eagerly. Instead, - variable regularizers may be added through `add_variable`. Activity - regularization is not supported directly (but such losses may be returned - from `Layer.call()`). + Assumes that the layer will be built + to match that input shape provided. Arguments: - losses: Loss tensor, or list/tuple of tensors. Rather than tensors, losses - may also be zero-argument callables which create a loss tensor. - inputs: Ignored when executing eagerly. If anything other than None is - passed, it signals the losses are conditional on some of the layer's - inputs, and thus they should only be run where these inputs are - available. This is the case for activity regularization losses, for - instance. If `None` is passed, the losses are assumed - to be unconditional, and will apply across all dataflows of the layer - (e.g. weight regularization losses). - """ - losses = generic_utils.to_list(losses) + input_shape: Shape tuple (tuple of integers) + or list of shape tuples (one per output tensor of the layer). + Shape tuples can include None for free dimensions, + instead of an integer. - def _tag_unconditional(loss): - if callable(loss): - loss = loss() - if loss is None: - return None # Will be filtered out when computing the .losses property - if not tensor_util.is_tensor(loss): - loss = ops.convert_to_tensor(loss, dtype=backend.floatx()) - loss._unconditional_loss = (inputs is None) # pylint: disable=protected-access - return loss + Returns: + An input shape tuple. + """ + if context.executing_eagerly(): + # In this case we build the model first in order to do shape inference. + # This is acceptable because the framework only calls + # `compute_output_shape` on shape values that the layer would later be + # built for. It would however cause issues in case a user attempts to + # use `compute_output_shape` manually (these users will have to + # implement `compute_output_shape` themselves). + self.build(input_shape) + with context.graph_mode(): + graph = func_graph.FuncGraph('graph') + with graph.as_default(): + if isinstance(input_shape, list): + inputs = [base_layer_utils.generate_placeholders_from_shape(shape) + for shape in input_shape] + else: + inputs = base_layer_utils.generate_placeholders_from_shape( + input_shape) - for loss in losses: - if callable(loss): - self._callable_losses.append( - functools.partial(_tag_unconditional, loss)) + try: + if self._expects_training_arg: + outputs = self(inputs, training=False) + else: + outputs = self(inputs) + except TypeError: + raise NotImplementedError('We could not automatically infer ' + 'the static shape of the layer\'s output.' + ' Please implement the ' + '`compute_output_shape` method on your ' + 'layer (%s).' % self.__class__.__name__) + if isinstance(outputs, list): + return [output.shape for output in outputs] else: - if context.executing_eagerly(): - self._eager_losses.append(_tag_unconditional(loss)) - else: - self._losses.append(_tag_unconditional(loss)) + return outputs.shape + raise NotImplementedError - @doc_controls.for_subclass_implementers - def add_metric(self, value, aggregation=None, name=None): - """Adds metric tensor to the layer. + def compute_mask(self, inputs, mask=None): # pylint: disable=unused-argument + """Computes an output mask tensor. - Args: - value: Metric tensor. - aggregation: Sample-wise metric reduction function. If `aggregation=None`, - it indicates that the metric tensor provided has been aggregated - already. eg, `model.add_metric(BinaryAccuracy(name='acc')(y_true, - y_pred))`. If aggregation='mean', the given metric tensor will be - sample-wise reduced using `mean` function. eg, `model.add_metric( - tf.reduce_mean(outputs), name='output_mean', aggregation='mean')`. - name: String metric name. + Arguments: + inputs: Tensor or list of tensors. + mask: Tensor or list of tensors. - Raises: - ValueError: If `aggregation` is anything other than None or `mean`. + Returns: + None or a tensor (or list of tensors, + one per output tensor of the layer). """ - if aggregation is not None and aggregation != 'mean': - raise ValueError( - 'We currently support only `mean` sample-wise metric aggregation. ' - 'You provided aggregation=`%s`' % aggregation) - - if tf_utils.is_symbolic_tensor(value): - self._symbolic_add_metric(value, aggregation, name) - else: - self._eager_add_metric(value, aggregation, name) - - def _get_existing_metric(self, name=None): - match = [m for m in self._metrics if m.name == name] - if not match: - return - if len(match) > 1: - raise ValueError( - 'Please provide different names for the metrics you have added. ' - 'We found {} metrics with the name: "{}"'.format(len(match), name)) - return match[0] - - def _eager_add_metric(self, value, aggregation=None, name=None): - # If the given metric is available in `metrics` list we just update state - # on it, otherwise we create a new metric instance and - # add it to the `metrics` list. - match = self._get_existing_metric(name) - if match: - match(value) # Update the metric state. - return - else: - if aggregation is None: - raise ValueError('We do not support adding an aggregated metric tensor ' - 'in `call` in eager execution.') - metric_obj, _ = _create_mean_metric(value, name) - self._metrics.append(metric_obj) - - def _symbolic_add_metric(self, value, aggregation=None, name=None): - if aggregation is None: - # Iterate over the metrics and check if the given metric exists already. - # This can happen when a metric instance is created in subclassed model - # layer `__init__` and we have tracked that instance already in - # model.__setattr__. - match = self._get_existing_metric(name) - if match: - result_tensor = value - if match.name not in self._metrics_tensors: - self._metrics_tensors[match.name] = result_tensor - return + if not self.supports_masking: + if mask is not None: + if isinstance(mask, list): + if any(m is not None for m in mask): + raise TypeError('Layer ' + self.name + ' does not support masking, ' + 'but was passed an input_mask: ' + str(mask)) else: - raise ValueError( - 'We currently do not support reusing a metric instance.') - else: - # We track the instance using the metadata on the result tensor. - result_tensor = value - metric_obj = result_tensor._metric_obj - else: - # If a non-aggregated tensor is given as input (ie. `aggregation` is - # explicitly set to `mean`), we wrap the tensor in `Mean` metric. - metric_obj, result_tensor = _create_mean_metric(value, name) - self._metrics.append(metric_obj) - self._metrics_tensors[metric_obj.name] = result_tensor + raise TypeError('Layer ' + self.name + ' does not support masking, ' + 'but was passed an input_mask: ' + str(mask)) + # masking not explicitly supported: return None as mask + return None + # if masking is explicitly supported, by default + # carry over the input mask + return mask - def get_losses_for(self, inputs): - """Retrieves losses relevant to a specific set of inputs. + def __call__(self, inputs, *args, **kwargs): + """Wraps `call`, applying pre- and post-processing steps. Arguments: - inputs: Input tensor or list/tuple of input tensors. + inputs: input tensor(s). + *args: additional positional arguments to be passed to `self.call`. + **kwargs: additional keyword arguments to be passed to `self.call`. Returns: - List of loss tensors of the layer that depend on `inputs`. + Output tensor(s). + + Note: + - The following optional keyword arguments are reserved for specific uses: + * `training`: Boolean scalar tensor of Python boolean indicating + whether the `call` is meant for training or inference. + * `mask`: Boolean input mask. + - If the layer's `call` method takes a `mask` argument (as some Keras + layers do), its default value will be set to the mask generated + for `inputs` by the previous layer (if `input` did come from + a layer that generated a corresponding mask, i.e. if it came from + a Keras layer with masking support. Raises: - RuntimeError: If called in Eager mode. + ValueError: if the layer's `call` method returns None (an invalid value). """ - if inputs is None: - # Requesting unconditional losses. - return [x for x in self.losses if x._unconditional_loss] # pylint: disable=protected-access - - # Requesting input-conditional losses. - inputs = nest.flatten(inputs) - # Retrieve the set of tensors in the TF graph that depend on `inputs`. - # The losses we want to return will be part of this set. - # To avoid unnecessary work, we stop the search in case all of - # `self.losses` have been retrieved. - reachable = tf_utils.get_reachable_from_inputs(inputs, self.losses) - losses = [] - for loss in self.losses: - if loss in reachable: - losses.append(loss) - return losses - - def _name_scope(self): - return self.name - - def build(self, input_shape): - """Creates the variables of the layer.""" - self.built = True - - @doc_controls.for_subclass_implementers - def add_variable(self, *args, **kwargs): - """Alias for `add_weight`.""" - return self.add_weight(*args, **kwargs) - - @doc_controls.for_subclass_implementers - def add_weight(self, - name, - shape, - dtype=None, - initializer=None, - regularizer=None, - trainable=None, - constraint=None, - partitioner=None, - use_resource=None, - synchronization=tf_variables.VariableSynchronization.AUTO, - aggregation=tf_variables.VariableAggregation.NONE, - **kwargs): - """Adds a new variable to the layer, or gets an existing one; returns it. - - Arguments: - name: variable name. - shape: variable shape. - dtype: The type of the variable. Defaults to `self.dtype` or `float32`. - initializer: initializer instance (callable). - regularizer: regularizer instance (callable). - trainable: whether the variable should be part of the layer's - "trainable_variables" (e.g. variables, biases) - or "non_trainable_variables" (e.g. BatchNorm mean, stddev). - Note, if the current variable scope is marked as non-trainable - then this parameter is ignored and any added variables are also - marked as non-trainable. `trainable` defaults to `True` unless - `synchronization` is set to `ON_READ`. - constraint: constraint instance (callable). - partitioner: Partitioner to be passed to the `Checkpointable` API. - use_resource: Whether to use `ResourceVariable`. - synchronization: Indicates when a distributed a variable will be - aggregated. Accepted values are constants defined in the class - `tf.VariableSynchronization`. By default the synchronization is set to - `AUTO` and the current `DistributionStrategy` chooses - when to synchronize. If `synchronization` is set to `ON_READ`, - `trainable` must not be set to `True`. - aggregation: Indicates how a distributed variable will be aggregated. - Accepted values are constants defined in the class - `tf.VariableAggregation`. - **kwargs: Additional keyword arguments. Accepted values are `getter` and - `collections`. - - Returns: - The created variable. Usually either a `Variable` or `ResourceVariable` - instance. If `partitioner` is not `None`, a `PartitionedVariable` - instance is returned. - - Raises: - RuntimeError: If called with partioned variable regularization and - eager execution is enabled. - ValueError: When giving unsupported dtype and no initializer or when - trainable has been set to True with synchronization set as `ON_READ`. - """ - # Validate optional keyword arguments. - for kwarg in kwargs: - if kwarg not in ['getter', 'collections']: - raise TypeError('Unknown keyword argument:', kwarg) - getter = kwargs.pop('getter', None) - collections = kwargs.pop('collections', None) - - if dtype is None: - dtype = self.dtype or backend.floatx() - dtype = dtypes.as_dtype(dtype) - initializer = initializers.get(initializer) - regularizer = regularizers.get(regularizer) - constraint = constraints.get(constraint) - - if synchronization == tf_variables.VariableSynchronization.ON_READ: - if trainable: - raise ValueError( - 'Synchronization value can be set to ' - 'VariableSynchronization.ON_READ only for non-trainable variables. ' - 'You have specified trainable=True and ' - 'synchronization=VariableSynchronization.ON_READ.') - else: - # Set trainable to be false when variable is to be synced on read. - trainable = False - elif trainable is None: - trainable = True - - # Initialize variable when no initializer provided - if initializer is None: - # If dtype is DT_FLOAT, provide a uniform unit scaling initializer - if dtype.is_floating: - initializer = initializers.glorot_uniform() - # If dtype is DT_INT/DT_UINT, provide a default value `zero` - # If dtype is DT_BOOL, provide a default value `FALSE` - elif dtype.is_integer or dtype.is_unsigned or dtype.is_bool: - initializer = initializers.zeros() - # NOTES:Do we need to support for handling DT_STRING and DT_COMPLEX here? - else: - raise ValueError('An initializer for variable %s of type %s is required' - ' for layer %s' % (name, dtype.base_dtype, self.name)) - - variable = self._add_variable_with_custom_getter( - name=name, - shape=shape, - # TODO(allenl): a `make_variable` equivalent should be added as a - # `Checkpointable` method. - getter=getter or make_variable, - # Manage errors in Layer rather than Checkpointable. - overwrite=True, - initializer=initializer, - dtype=dtype, - constraint=constraint, - trainable=trainable and self.trainable, - partitioner=partitioner, - use_resource=use_resource, - collections=collections, - synchronization=synchronization, - aggregation=aggregation) - backend.track_variable(variable) - - if regularizer is not None: - # TODO(fchollet): in the future, this should be handled at the - # level of variable creation, and weight regularization losses - # should be variable attributes. - self._handle_weight_regularization(name, variable, regularizer) - - if trainable: - self._trainable_weights.append(variable) - else: - self._non_trainable_weights.append(variable) - return variable - - def _handle_weight_regularization(self, name, variable, regularizer): - """Create lambdas which compute regularization losses.""" - - def _loss_for_variable(v): - """Creates a regularization loss `Tensor` for variable `v`.""" - with ops.colocate_with(v): - with ops.name_scope(name + '/Regularizer'): - regularization = regularizer(v) - return regularization - - if isinstance(variable, tf_variables.PartitionedVariable): - for v in variable: - self.add_loss(functools.partial(_loss_for_variable, v)) - else: - self.add_loss(functools.partial(_loss_for_variable, variable)) - - def _handle_activity_regularization(self, inputs, outputs): - # Apply activity regularization. - # Note that it should be applied every time the layer creates a new - # output, since it is output-specific. - if self._activity_regularizer: - output_list = nest.flatten(outputs) - with ops.name_scope('ActivityRegularizer'): - for output in output_list: - activity_loss = self._activity_regularizer(output) - batch_size = math_ops.cast( - array_ops.shape(output)[0], activity_loss.dtype) - # Make activity regularization strength batch-agnostic. - mean_activity_loss = activity_loss / batch_size - self.add_loss(mean_activity_loss, inputs=inputs) - - @doc_controls.for_subclass_implementers - def call(self, inputs, **kwargs): # pylint: disable=unused-argument - """This is where the layer's logic lives. - - Arguments: - inputs: Input tensor, or list/tuple of input tensors. - **kwargs: Additional keyword arguments. - - Returns: - A tensor or list/tuple of tensors. - """ - return inputs - - def __call__(self, inputs, *args, **kwargs): - """Wraps `call`, applying pre- and post-processing steps. - - Arguments: - inputs: input tensor(s). - *args: additional positional arguments to be passed to `self.call`. - **kwargs: additional keyword arguments to be passed to `self.call`. - - Returns: - Output tensor(s). - - Note: - - The following optional keyword arguments are reserved for specific uses: - * `training`: Boolean scalar tensor of Python boolean indicating - whether the `call` is meant for training or inference. - * `mask`: Boolean input mask. - - If the layer's `call` method takes a `mask` argument (as some Keras - layers do), its default value will be set to the mask generated - for `inputs` by the previous layer (if `input` did come from - a layer that generated a corresponding mask, i.e. if it came from - a Keras layer with masking support. - - Raises: - ValueError: if the layer's `call` method returns None (an invalid value). - """ - input_list = nest.flatten(inputs) + input_list = nest.flatten(inputs) if context.executing_eagerly(): # Accept NumPy inputs by converting to Tensors when executing eagerly. @@ -783,7 +503,7 @@ class Layer(checkpointable.CheckpointableBase): previous_mask = None if build_graph and (not hasattr(self, '_compute_previous_mask') or self._compute_previous_mask): - previous_mask = collect_previous_mask(inputs) + previous_mask = base_layer_utils.collect_previous_mask(inputs) if not hasattr(self, '_call_fn_args'): self._call_fn_args = self._no_dependency( function_utils.fn_args(self.call)) @@ -859,7 +579,7 @@ class Layer(checkpointable.CheckpointableBase): '(layer: ' + self.name + ').') self._handle_activity_regularization(inputs, outputs) self._set_mask_metadata(inputs, outputs, previous_mask) - if have_all_keras_metadata(inputs): + if base_layer_utils.have_all_keras_metadata(inputs): inputs, outputs = self._set_connectivity_metadata_( inputs, outputs, args, kwargs) if hasattr(self, '_set_inputs') and not self.inputs: @@ -882,312 +602,299 @@ class Layer(checkpointable.CheckpointableBase): del self._initial_weights return outputs - def apply(self, inputs, *args, **kwargs): - """Apply the layer on a input. + @property + def dtype(self): + return self._dtype + + @property + def name(self): + return self._name - This simply wraps `self.__call__`. + @property + def activity_regularizer(self): + """Optional regularizer function for the output of this layer.""" + return self._activity_regularizer - Arguments: - inputs: Input tensor(s). - *args: additional positional arguments to be passed to `self.call`. - **kwargs: additional keyword arguments to be passed to `self.call`. + @activity_regularizer.setter + def activity_regularizer(self, regularizer): + """Optional regularizer function for the output of this layer.""" + self._activity_regularizer = self._no_dependency(regularizer) - Returns: - Output tensor(s). - """ - return self.__call__(inputs, *args, **kwargs) + @property + def trainable_weights(self): + return self._trainable_weights if self.trainable else [] - def _set_mask_metadata(self, inputs, outputs, previous_mask): - # In some cases the mask of the outputs has already been computed by - # inner layers and does not need to be recomputed by this layer. - mask_already_computed = all( - hasattr(x, '_keras_mask') for x in generic_utils.to_list(outputs)) - if hasattr(self, 'compute_mask') and not mask_already_computed: - output_mask = self.compute_mask(inputs, previous_mask) + @property + def non_trainable_weights(self): + if self.trainable: + return self._non_trainable_weights else: - output_mask = None - if isinstance(outputs, (list, tuple)): - if output_mask is None: - output_mask = [None for _ in range(len(outputs))] - for x, m in zip(outputs, output_mask): - try: - x._keras_mask = m # pylint: disable=protected-access - except AttributeError: - pass # C type such as dict. Masking not supported in this case. - else: - try: - outputs._keras_mask = output_mask # pylint: disable=protected-access - except AttributeError: - pass # C type such as dict. Masking not supported in this case. + return self._trainable_weights + self._non_trainable_weights - def _set_connectivity_metadata_(self, inputs, outputs, args, kwargs): - call_convention = getattr(self, '_call_convention', - CallConvention.EXPLICIT_INPUTS_ARGUMENT) - if args: - if call_convention == CallConvention.EXPLICIT_INPUTS_ARGUMENT: - raise TypeError( - 'This layer ("{}") takes an `inputs` argument in `call()`, ' - 'and only the `inputs` argument may be specified as a positional ' - 'argument. Pass everything else as a keyword argument ' - '(those arguments will not be tracked ' - 'as inputs to the layer).'.format(self.name)) - elif call_convention == CallConvention.SINGLE_POSITIONAL_ARGUMENT: - raise TypeError( - 'This layer ("{}") takes a single positional argument in `call()`,' - ' which is by convention the `inputs` argument, ' - 'and only this argument may be specified as a positional argument. ' - 'Pass everything else as a keyword argument ' - '(those arguments will not be tracked ' - 'as inputs to the layer).'.format(self.name)) + @property + def weights(self): + """Returns the list of all layer variables/weights. - # If the layer returns tensors from its inputs, unmodified, - # we copy them to avoid loss of tensor metadata. - output_ls = nest.flatten(outputs) - output_ls_copy = [] - for x in output_ls: - if x in nest.flatten(inputs): - with ops.name_scope(self.name): - x = array_ops.identity(x) - output_ls_copy.append(x) - if len(output_ls_copy) == 1: - outputs = output_ls_copy[0] - else: - outputs = output_ls_copy + Returns: + A list of variables. + """ + return self.trainable_weights + self.non_trainable_weights - inputs, kwargs = self._inputs_from_call_args( - call_args=(inputs,) + args, call_kwargs=kwargs) - # Add an inbound node to the layer, so it can keep track of this call. - # This updates the layer history of the output tensor(s). - kwargs.pop('mask', None) # `mask` should not be serialized. - self._add_inbound_node( - input_tensors=inputs, output_tensors=outputs, arguments=kwargs) - return inputs, outputs + @property + def updates(self): + if not self.trainable and not self.stateful: + return [] + return self._updates - def _inputs_from_call_args(self, call_args, call_kwargs): - """Get Layer inputs from __call__ *args and **kwargs. + @property + def losses(self): + """Losses which are associated with this `Layer`. - Args: - call_args: The positional arguments passed to __call__. - call_kwargs: The keyword argument dict passed to __call__. + Variable regularization tensors are created when this property is accessed, + so it is eager safe: accessing `losses` under a `tf.GradientTape` will + propagate gradients back to the corresponding variables. Returns: - A tuple of (inputs, non_input_kwargs). These may be the same objects as - were passed in (call_args and call_kwargs). + A list of tensors. """ - call_convention = getattr(self, '_call_convention', - CallConvention.EXPLICIT_INPUTS_ARGUMENT) - if (call_convention in ( - CallConvention.EXPLICIT_INPUTS_ARGUMENT, - CallConvention.SINGLE_POSITIONAL_ARGUMENT)): - assert len(call_args) == 1 # TypeError raised earlier in __call__. - return call_args[0], call_kwargs + collected_losses = [] + if context.executing_eagerly(): + collected_losses.extend(self._eager_losses) else: - call_arg_spec = tf_inspect.getfullargspec(self.call) - # There is no explicit "inputs" argument expected or provided to - # call(). Arguments which have default values are considered non-inputs, - # and arguments without are considered inputs. - if call_arg_spec.defaults: - if call_arg_spec.varargs is not None: - raise TypeError( - 'Layers may not accept both positional arguments and ' - 'arguments with default values (unable to determine which ' - 'are inputs to the layer). ' - 'Issue occurred with layer "%s"' % (self.name)) - keyword_arg_names = set( - call_arg_spec.args[-len(call_arg_spec.defaults):]) + collected_losses.extend(self._losses) + for regularizer in self._callable_losses: + loss_tensor = regularizer() + if loss_tensor is not None: + collected_losses.append(loss_tensor) + return collected_losses + + @doc_controls.for_subclass_implementers + def add_loss(self, losses, inputs=None): + """Add loss tensor(s), potentially dependent on layer inputs. + + Some losses (for instance, activity regularization losses) may be dependent + on the inputs passed when calling a layer. Hence, when reusing the same + layer on different inputs `a` and `b`, some entries in `layer.losses` may + be dependent on `a` and some on `b`. This method automatically keeps track + of dependencies. + + The `get_losses_for` method allows to retrieve the losses relevant to a + specific set of inputs. + + Note that `add_loss` is not supported when executing eagerly. Instead, + variable regularizers may be added through `add_variable`. Activity + regularization is not supported directly (but such losses may be returned + from `Layer.call()`). + + Arguments: + losses: Loss tensor, or list/tuple of tensors. Rather than tensors, losses + may also be zero-argument callables which create a loss tensor. + inputs: Ignored when executing eagerly. If anything other than None is + passed, it signals the losses are conditional on some of the layer's + inputs, and thus they should only be run where these inputs are + available. This is the case for activity regularization losses, for + instance. If `None` is passed, the losses are assumed + to be unconditional, and will apply across all dataflows of the layer + (e.g. weight regularization losses). + """ + losses = generic_utils.to_list(losses) + + def _tag_unconditional(loss): + if callable(loss): + loss = loss() + if loss is None: + return None # Will be filtered out when computing the .losses property + if not tensor_util.is_tensor(loss): + loss = ops.convert_to_tensor(loss, dtype=backend.floatx()) + loss._unconditional_loss = (inputs is None) # pylint: disable=protected-access + return loss + + for loss in losses: + if callable(loss): + self._callable_losses.append( + functools.partial(_tag_unconditional, loss)) else: - keyword_arg_names = set() - # Training is never an input argument name, to allow signatures like - # call(x, training). - keyword_arg_names.add('training') - _, unwrapped_call = tf_decorator.unwrap(self.call) - bound_args = inspect.getcallargs( - unwrapped_call, *call_args, **call_kwargs) - if call_arg_spec.varkw is not None: - var_kwargs = bound_args.pop(call_arg_spec.varkw) - bound_args.update(var_kwargs) - keyword_arg_names = keyword_arg_names.union(var_kwargs.keys()) - all_args = call_arg_spec.args - if all_args and bound_args[all_args[0]] is self: - # Ignore the 'self' argument of methods - bound_args.pop(call_arg_spec.args[0]) - all_args = all_args[1:] - non_input_arg_values = {} - input_arg_values = [] - remaining_args_are_keyword = False - for argument_name in all_args: - if argument_name in keyword_arg_names: - remaining_args_are_keyword = True - else: - if remaining_args_are_keyword: - raise TypeError( - 'Found a positional argument in a layer call after a non-input ' - 'argument. All arguments after "training" must be keyword ' - 'arguments, and are not tracked as inputs to the layer. ' - 'Issue occurred with layer "%s"' % (self.name)) - if remaining_args_are_keyword: - non_input_arg_values[argument_name] = bound_args[argument_name] + if context.executing_eagerly(): + self._eager_losses.append(_tag_unconditional(loss)) else: - input_arg_values.append(bound_args[argument_name]) - if call_arg_spec.varargs is not None: - input_arg_values.extend(bound_args[call_arg_spec.varargs]) - return input_arg_values, non_input_arg_values + self._losses.append(_tag_unconditional(loss)) - def compute_output_shape(self, input_shape): - """Computes the output shape of the layer. + @doc_controls.for_subclass_implementers + def add_metric(self, value, aggregation=None, name=None): + """Adds metric tensor to the layer. - Assumes that the layer will be built - to match that input shape provided. + Args: + value: Metric tensor. + aggregation: Sample-wise metric reduction function. If `aggregation=None`, + it indicates that the metric tensor provided has been aggregated + already. eg, `model.add_metric(BinaryAccuracy(name='acc')(y_true, + y_pred))`. If aggregation='mean', the given metric tensor will be + sample-wise reduced using `mean` function. eg, `model.add_metric( + tf.reduce_mean(outputs), name='output_mean', aggregation='mean')`. + name: String metric name. - Arguments: - input_shape: Shape tuple (tuple of integers) - or list of shape tuples (one per output tensor of the layer). - Shape tuples can include None for free dimensions, - instead of an integer. + Raises: + ValueError: If `aggregation` is anything other than None or `mean`. + """ + if aggregation is not None and aggregation != 'mean': + raise ValueError( + 'We currently support only `mean` sample-wise metric aggregation. ' + 'You provided aggregation=`%s`' % aggregation) - Returns: - An input shape tuple. + if tf_utils.is_symbolic_tensor(value): + self._symbolic_add_metric(value, aggregation, name) + else: + self._eager_add_metric(value, aggregation, name) + + @doc_controls.for_subclass_implementers + def add_update(self, updates, inputs=None): + """Add update op(s), potentially dependent on layer inputs. + + Weight updates (for instance, the updates of the moving mean and variance + in a BatchNormalization layer) may be dependent on the inputs passed + when calling a layer. Hence, when reusing the same layer on + different inputs `a` and `b`, some entries in `layer.updates` may be + dependent on `a` and some on `b`. This method automatically keeps track + of dependencies. + + The `get_updates_for` method allows to retrieve the updates relevant to a + specific set of inputs. + + This call is ignored when eager execution is enabled (in that case, variable + updates are run on the fly and thus do not need to be tracked for later + execution). + + Arguments: + updates: Update op, or list/tuple of update ops. + inputs: If anything other than None is passed, it signals the updates + are conditional on some of the layer's inputs, + and thus they should only be run where these inputs are available. + This is the case for BatchNormalization updates, for instance. + If None, the updates will be taken into account unconditionally, + and you are responsible for making sure that any dependency they might + have is available at runtime. + A step counter might fall into this category. """ if context.executing_eagerly(): - # In this case we build the model first in order to do shape inference. - # This is acceptable because the framework only calls - # `compute_output_shape` on shape values that the layer would later be - # built for. It would however cause issues in case a user attempts to - # use `compute_output_shape` manually (these users will have to - # implement `compute_output_shape` themselves). - self.build(input_shape) - with context.graph_mode(): - graph = func_graph.FuncGraph('graph') - with graph.as_default(): - if isinstance(input_shape, list): - inputs = [generate_placeholders_from_shape(shape) - for shape in input_shape] - else: - inputs = generate_placeholders_from_shape(input_shape) + return # Updates already applied when in eager mode. - try: - if self._expects_training_arg: - outputs = self(inputs, training=False) - else: - outputs = self(inputs) - except TypeError: - raise NotImplementedError('We could not automatically infer ' - 'the static shape of the layer\'s output.' - ' Please implement the ' - '`compute_output_shape` method on your ' - 'layer (%s).' % self.__class__.__name__) - if isinstance(outputs, list): - return [output.shape for output in outputs] + def process_update(x): + if isinstance(x, ops.Operation): + return x + elif hasattr(x, 'op'): + return x.op else: - return outputs.shape - raise NotImplementedError + return ops.convert_to_tensor(x) - def compute_mask(self, inputs, mask=None): # pylint: disable=unused-argument - """Computes an output mask tensor. + updates = generic_utils.to_list(updates) + updates = [process_update(x) for x in updates] + self._updates += updates + if inputs is None: + for u in updates: + u._unconditional_update = True # pylint: disable=protected-access + else: + for u in updates: + u._unconditional_update = False # pylint: disable=protected-access + + def set_weights(self, weights): + """Sets the weights of the layer, from Numpy arrays. Arguments: - inputs: Tensor or list of tensors. - mask: Tensor or list of tensors. + weights: a list of Numpy arrays. The number + of arrays and their shape must match + number of the dimensions of the weights + of the layer (i.e. it should match the + output of `get_weights`). + + Raises: + ValueError: If the provided weights list does not match the + layer's specifications. + """ + params = self.weights + if len(params) != len(weights): + raise ValueError('You called `set_weights(weights)` on layer "' + + self.name + '" with a weight list of length ' + + str(len(weights)) + ', but the layer was expecting ' + + str(len(params)) + ' weights. Provided weights: ' + + str(weights)[:50] + '...') + if not params: + return + weight_value_tuples = [] + param_values = backend.batch_get_value(params) + for pv, p, w in zip(param_values, params, weights): + if pv.shape != w.shape: + raise ValueError('Layer weight shape ' + str(pv.shape) + + ' not compatible with ' + 'provided weight shape ' + str(w.shape)) + weight_value_tuples.append((p, w)) + backend.batch_set_value(weight_value_tuples) + + def get_weights(self): + """Returns the current weights of the layer. Returns: - None or a tensor (or list of tensors, - one per output tensor of the layer). + Weights values as a list of numpy arrays. """ - if not self.supports_masking: - if mask is not None: - if isinstance(mask, list): - if any(m is not None for m in mask): - raise TypeError('Layer ' + self.name + ' does not support masking, ' - 'but was passed an input_mask: ' + str(mask)) - else: - raise TypeError('Layer ' + self.name + ' does not support masking, ' - 'but was passed an input_mask: ' + str(mask)) - # masking not explicitly supported: return None as mask - return None - # if masking is explicitly supported, by default - # carry over the input mask - return mask + params = self.weights + return backend.batch_get_value(params) - def _add_inbound_node(self, - input_tensors, - output_tensors, - arguments=None): - """Internal method to create an inbound node for the layer. + def get_updates_for(self, inputs): + """Retrieves updates relevant to a specific set of inputs. Arguments: - input_tensors: list of input tensors. - output_tensors: list of output tensors. - arguments: dictionary of keyword arguments that were passed to the - `call` method of the layer at the call that created the node. - """ - input_tensors = nest.flatten(input_tensors) - output_tensors = nest.flatten(output_tensors) + inputs: Input tensor or list/tuple of input tensors. - # Collect input tensor(s) coordinates. - inbound_layers = [] - node_indices = [] - tensor_indices = [] - for x in input_tensors: - assert hasattr(x, '_keras_history') - inbound_layer, node_index, tensor_index = x._keras_history # pylint: disable=protected-access - inbound_layers.append(inbound_layer) - node_indices.append(node_index) - tensor_indices.append(tensor_index) + Returns: + List of update ops of the layer that depend on `inputs`. - # Create node, add it to inbound nodes. - Node( - self, - inbound_layers=inbound_layers, - node_indices=node_indices, - tensor_indices=tensor_indices, - input_tensors=input_tensors, - output_tensors=output_tensors, - arguments=arguments) + Raises: + RuntimeError: If called in Eager mode. + """ + # Updates disabled if layer is not trainable and not explicitly stateful. + if not self.trainable and not self.stateful: + return [] - # Update tensor history metadata. - for i in range(len(output_tensors)): - # The metadata attribute consists of 1) a layer instance - # 2) a node index for the layer, 3) a tensor index for the node. - # The allows layer reuse (multiple nodes per layer) and multi-output - # or multi-input layers (e.g. a layer can return multiple tensors, - # and each can be sent to a different layer). - output_tensors[i]._keras_history = (self, len(self._inbound_nodes) - 1, i) # pylint: disable=protected-access + if inputs is None: + # Requesting unconditional updates. + return [x for x in self.updates if x._unconditional_update] # pylint: disable=protected-access - def _get_node_attribute_at_index(self, node_index, attr, attr_name): - """Private utility to retrieves an attribute (e.g. inputs) from a node. + # Requesting input-conditional updates. + inputs = nest.flatten(inputs) + reachable = tf_utils.get_reachable_from_inputs(inputs, self.updates) + updates = [] + for update in self.updates: + if update in reachable: + updates.append(update) + return updates - This is used to implement the methods: - - get_input_shape_at - - get_output_shape_at - - get_input_at - etc... + def get_losses_for(self, inputs): + """Retrieves losses relevant to a specific set of inputs. Arguments: - node_index: Integer index of the node from which - to retrieve the attribute. - attr: Exact node attribute name. - attr_name: Human-readable attribute name, for error messages. + inputs: Input tensor or list/tuple of input tensors. Returns: - The layer's attribute `attr` at the node of index `node_index`. + List of loss tensors of the layer that depend on `inputs`. Raises: - RuntimeError: If the layer has no inbound nodes, or if called in Eager - mode. - ValueError: If the index provided does not match any node. + RuntimeError: If called in Eager mode. """ - if not self._inbound_nodes: - raise RuntimeError('The layer has never been called ' - 'and thus has no defined ' + attr_name + '.') - if not len(self._inbound_nodes) > node_index: - raise ValueError('Asked to get ' + attr_name + ' at node ' + - str(node_index) + ', but the layer has only ' + - str(len(self._inbound_nodes)) + ' inbound nodes.') - values = getattr(self._inbound_nodes[node_index], attr) - if len(values) == 1: - return values[0] - else: - return values + if inputs is None: + # Requesting unconditional losses. + return [x for x in self.losses if x._unconditional_loss] # pylint: disable=protected-access + + # Requesting input-conditional losses. + inputs = nest.flatten(inputs) + # Retrieve the set of tensors in the TF graph that depend on `inputs`. + # The losses we want to return will be part of this set. + # To avoid unnecessary work, we stop the search in case all of + # `self.losses` have been retrieved. + reachable = tf_utils.get_reachable_from_inputs(inputs, self.losses) + losses = [] + for loss in self.losses: + if loss in reachable: + losses.append(loss) + return losses def get_input_mask_at(self, node_index): """Retrieves the input mask tensor(s) of a layer at a given node. @@ -1482,99 +1189,379 @@ class Layer(checkpointable.CheckpointableBase): 'Use `get_output_shape_at(node_index)` ' 'instead.' % self.name) - @property - @doc_controls.do_not_doc_inheritable - def inbound_nodes(self): - """Deprecated, do NOT use! Only for compatibility with external Keras.""" - return self._inbound_nodes + @property + @doc_controls.do_not_doc_inheritable + def inbound_nodes(self): + """Deprecated, do NOT use! Only for compatibility with external Keras.""" + return self._inbound_nodes + + @property + @doc_controls.do_not_doc_inheritable + def outbound_nodes(self): + """Deprecated, do NOT use! Only for compatibility with external Keras.""" + return self._outbound_nodes + + ############################################################################## + # Methods & attributes below are public aliases of other methods. # + ############################################################################## + + def apply(self, inputs, *args, **kwargs): + """Apply the layer on a input. + + This is an alias of `self.__call__`. + + Arguments: + inputs: Input tensor(s). + *args: additional positional arguments to be passed to `self.call`. + **kwargs: additional keyword arguments to be passed to `self.call`. + + Returns: + Output tensor(s). + """ + return self.__call__(inputs, *args, **kwargs) + + @doc_controls.for_subclass_implementers + def add_variable(self, *args, **kwargs): + """Alias for `add_weight`.""" + return self.add_weight(*args, **kwargs) + + @property + def variables(self): + """Returns the list of all layer variables/weights. + + Alias of `self.weights`. + + Returns: + A list of variables. + """ + return self.weights + + @property + def trainable_variables(self): + return self.trainable_weights + + @property + def non_trainable_variables(self): + return self.non_trainable_weights + + ############################################################################## + # Methods & attributes below are all private and only used by the framework. # + ############################################################################## + + def _name_scope(self): + return self.name + + def _init_set_name(self, name, zero_based=True): + if not name: + self._name = base_layer_utils.unique_layer_name( + generic_utils.to_snake_case(self.__class__.__name__), + zero_based=zero_based) + else: + self._name = name + + def _get_existing_metric(self, name=None): + match = [m for m in self._metrics if m.name == name] + if not match: + return + if len(match) > 1: + raise ValueError( + 'Please provide different names for the metrics you have added. ' + 'We found {} metrics with the name: "{}"'.format(len(match), name)) + return match[0] + + def _eager_add_metric(self, value, aggregation=None, name=None): + # If the given metric is available in `metrics` list we just update state + # on it, otherwise we create a new metric instance and + # add it to the `metrics` list. + match = self._get_existing_metric(name) + if match: + match(value) # Update the metric state. + return + else: + if aggregation is None: + raise ValueError('We do not support adding an aggregated metric tensor ' + 'in `call` in eager execution.') + metric_obj, _ = base_layer_utils.create_mean_metric(value, name) + self._metrics.append(metric_obj) + + def _symbolic_add_metric(self, value, aggregation=None, name=None): + if aggregation is None: + # Iterate over the metrics and check if the given metric exists already. + # This can happen when a metric instance is created in subclassed model + # layer `__init__` and we have tracked that instance already in + # model.__setattr__. + match = self._get_existing_metric(name) + if match: + result_tensor = value + if match.name not in self._metrics_tensors: + self._metrics_tensors[match.name] = result_tensor + return + else: + raise ValueError( + 'We currently do not support reusing a metric instance.') + else: + # We track the instance using the metadata on the result tensor. + result_tensor = value + metric_obj = result_tensor._metric_obj + else: + # If a non-aggregated tensor is given as input (ie. `aggregation` is + # explicitly set to `mean`), we wrap the tensor in `Mean` metric. + metric_obj, result_tensor = base_layer_utils.create_mean_metric( + value, name) + self._metrics.append(metric_obj) + self._metrics_tensors[metric_obj.name] = result_tensor + + def _handle_weight_regularization(self, name, variable, regularizer): + """Create lambdas which compute regularization losses.""" + + def _loss_for_variable(v): + """Creates a regularization loss `Tensor` for variable `v`.""" + with ops.colocate_with(v): + with ops.name_scope(name + '/Regularizer'): + regularization = regularizer(v) + return regularization + + if isinstance(variable, tf_variables.PartitionedVariable): + for v in variable: + self.add_loss(functools.partial(_loss_for_variable, v)) + else: + self.add_loss(functools.partial(_loss_for_variable, variable)) + + def _handle_activity_regularization(self, inputs, outputs): + # Apply activity regularization. + # Note that it should be applied every time the layer creates a new + # output, since it is output-specific. + if self._activity_regularizer: + output_list = nest.flatten(outputs) + with ops.name_scope('ActivityRegularizer'): + for output in output_list: + activity_loss = self._activity_regularizer(output) + batch_size = math_ops.cast( + array_ops.shape(output)[0], activity_loss.dtype) + # Make activity regularization strength batch-agnostic. + mean_activity_loss = activity_loss / batch_size + self.add_loss(mean_activity_loss, inputs=inputs) + + def _set_mask_metadata(self, inputs, outputs, previous_mask): + # In some cases the mask of the outputs has already been computed by + # inner layers and does not need to be recomputed by this layer. + mask_already_computed = all( + hasattr(x, '_keras_mask') for x in generic_utils.to_list(outputs)) + if hasattr(self, 'compute_mask') and not mask_already_computed: + output_mask = self.compute_mask(inputs, previous_mask) + else: + output_mask = None + if isinstance(outputs, (list, tuple)): + if output_mask is None: + output_mask = [None for _ in range(len(outputs))] + for x, m in zip(outputs, output_mask): + try: + x._keras_mask = m # pylint: disable=protected-access + except AttributeError: + pass # C type such as dict. Masking not supported in this case. + else: + try: + outputs._keras_mask = output_mask # pylint: disable=protected-access + except AttributeError: + pass # C type such as dict. Masking not supported in this case. + + def _set_connectivity_metadata_(self, inputs, outputs, args, kwargs): + call_convention = getattr( + self, '_call_convention', + base_layer_utils.CallConvention.EXPLICIT_INPUTS_ARGUMENT) + if args: + if call_convention == (base_layer_utils + .CallConvention.EXPLICIT_INPUTS_ARGUMENT): + raise TypeError( + 'This layer ("{}") takes an `inputs` argument in `call()`, ' + 'and only the `inputs` argument may be specified as a positional ' + 'argument. Pass everything else as a keyword argument ' + '(those arguments will not be tracked ' + 'as inputs to the layer).'.format(self.name)) + elif call_convention == (base_layer_utils + .CallConvention.SINGLE_POSITIONAL_ARGUMENT): + raise TypeError( + 'This layer ("{}") takes a single positional argument in `call()`,' + ' which is by convention the `inputs` argument, ' + 'and only this argument may be specified as a positional argument. ' + 'Pass everything else as a keyword argument ' + '(those arguments will not be tracked ' + 'as inputs to the layer).'.format(self.name)) + + # If the layer returns tensors from its inputs, unmodified, + # we copy them to avoid loss of tensor metadata. + output_ls = nest.flatten(outputs) + output_ls_copy = [] + for x in output_ls: + if x in nest.flatten(inputs): + with ops.name_scope(self.name): + x = array_ops.identity(x) + output_ls_copy.append(x) + if len(output_ls_copy) == 1: + outputs = output_ls_copy[0] + else: + outputs = output_ls_copy - @property - @doc_controls.do_not_doc_inheritable - def outbound_nodes(self): - """Deprecated, do NOT use! Only for compatibility with external Keras.""" - return self._outbound_nodes + inputs, kwargs = self._inputs_from_call_args( + call_args=(inputs,) + args, call_kwargs=kwargs) + # Add an inbound node to the layer, so it can keep track of this call. + # This updates the layer history of the output tensor(s). + kwargs.pop('mask', None) # `mask` should not be serialized. + self._add_inbound_node( + input_tensors=inputs, output_tensors=outputs, arguments=kwargs) + return inputs, outputs - def set_weights(self, weights): - """Sets the weights of the layer, from Numpy arrays. + def _inputs_from_call_args(self, call_args, call_kwargs): + """Get Layer inputs from __call__ *args and **kwargs. - Arguments: - weights: a list of Numpy arrays. The number - of arrays and their shape must match - number of the dimensions of the weights - of the layer (i.e. it should match the - output of `get_weights`). + Args: + call_args: The positional arguments passed to __call__. + call_kwargs: The keyword argument dict passed to __call__. - Raises: - ValueError: If the provided weights list does not match the - layer's specifications. + Returns: + A tuple of (inputs, non_input_kwargs). These may be the same objects as + were passed in (call_args and call_kwargs). """ - params = self.weights - if len(params) != len(weights): - raise ValueError('You called `set_weights(weights)` on layer "' + - self.name + '" with a weight list of length ' + - str(len(weights)) + ', but the layer was expecting ' + - str(len(params)) + ' weights. Provided weights: ' + - str(weights)[:50] + '...') - if not params: - return - weight_value_tuples = [] - param_values = backend.batch_get_value(params) - for pv, p, w in zip(param_values, params, weights): - if pv.shape != w.shape: - raise ValueError('Layer weight shape ' + str(pv.shape) + - ' not compatible with ' - 'provided weight shape ' + str(w.shape)) - weight_value_tuples.append((p, w)) - backend.batch_set_value(weight_value_tuples) + call_convention = getattr( + self, '_call_convention', + base_layer_utils.CallConvention.EXPLICIT_INPUTS_ARGUMENT) + if (call_convention in ( + base_layer_utils.CallConvention.EXPLICIT_INPUTS_ARGUMENT, + base_layer_utils.CallConvention.SINGLE_POSITIONAL_ARGUMENT)): + assert len(call_args) == 1 # TypeError raised earlier in __call__. + return call_args[0], call_kwargs + else: + call_arg_spec = tf_inspect.getfullargspec(self.call) + # There is no explicit "inputs" argument expected or provided to + # call(). Arguments which have default values are considered non-inputs, + # and arguments without are considered inputs. + if call_arg_spec.defaults: + if call_arg_spec.varargs is not None: + raise TypeError( + 'Layers may not accept both positional arguments and ' + 'arguments with default values (unable to determine which ' + 'are inputs to the layer). ' + 'Issue occurred with layer "%s"' % (self.name)) + keyword_arg_names = set( + call_arg_spec.args[-len(call_arg_spec.defaults):]) + else: + keyword_arg_names = set() + # Training is never an input argument name, to allow signatures like + # call(x, training). + keyword_arg_names.add('training') + _, unwrapped_call = tf_decorator.unwrap(self.call) + bound_args = inspect.getcallargs( + unwrapped_call, *call_args, **call_kwargs) + if call_arg_spec.varkw is not None: + var_kwargs = bound_args.pop(call_arg_spec.varkw) + bound_args.update(var_kwargs) + keyword_arg_names = keyword_arg_names.union(var_kwargs.keys()) + all_args = call_arg_spec.args + if all_args and bound_args[all_args[0]] is self: + # Ignore the 'self' argument of methods + bound_args.pop(call_arg_spec.args[0]) + all_args = all_args[1:] + non_input_arg_values = {} + input_arg_values = [] + remaining_args_are_keyword = False + for argument_name in all_args: + if argument_name in keyword_arg_names: + remaining_args_are_keyword = True + else: + if remaining_args_are_keyword: + raise TypeError( + 'Found a positional argument in a layer call after a non-input ' + 'argument. All arguments after "training" must be keyword ' + 'arguments, and are not tracked as inputs to the layer. ' + 'Issue occurred with layer "%s"' % (self.name)) + if remaining_args_are_keyword: + non_input_arg_values[argument_name] = bound_args[argument_name] + else: + input_arg_values.append(bound_args[argument_name]) + if call_arg_spec.varargs is not None: + input_arg_values.extend(bound_args[call_arg_spec.varargs]) + return input_arg_values, non_input_arg_values - def get_weights(self): - """Returns the current weights of the layer. + def _add_inbound_node(self, + input_tensors, + output_tensors, + arguments=None): + """Internal method to create an inbound node for the layer. - Returns: - Weights values as a list of numpy arrays. + Arguments: + input_tensors: list of input tensors. + output_tensors: list of output tensors. + arguments: dictionary of keyword arguments that were passed to the + `call` method of the layer at the call that created the node. """ - params = self.weights - return backend.batch_get_value(params) - - def get_config(self): - """Returns the config of the layer. + input_tensors = nest.flatten(input_tensors) + output_tensors = nest.flatten(output_tensors) - A layer config is a Python dictionary (serializable) - containing the configuration of a layer. - The same layer can be reinstantiated later - (without its trained weights) from this configuration. + # Collect input tensor(s) coordinates. + inbound_layers = [] + node_indices = [] + tensor_indices = [] + for x in input_tensors: + assert hasattr(x, '_keras_history') + inbound_layer, node_index, tensor_index = x._keras_history # pylint: disable=protected-access + inbound_layers.append(inbound_layer) + node_indices.append(node_index) + tensor_indices.append(tensor_index) - The config of a layer does not include connectivity - information, nor the layer class name. These are handled - by `Network` (one layer of abstraction above). + # Create node, add it to inbound nodes. + Node( + self, + inbound_layers=inbound_layers, + node_indices=node_indices, + tensor_indices=tensor_indices, + input_tensors=input_tensors, + output_tensors=output_tensors, + arguments=arguments) - Returns: - Python dictionary. - """ - config = {'name': self.name, 'trainable': self.trainable} - if hasattr(self, '_batch_input_shape'): - config['batch_input_shape'] = self._batch_input_shape - if hasattr(self, 'dtype'): - config['dtype'] = self.dtype - return config + # Update tensor history metadata. + for i in range(len(output_tensors)): + # The metadata attribute consists of 1) a layer instance + # 2) a node index for the layer, 3) a tensor index for the node. + # The allows layer reuse (multiple nodes per layer) and multi-output + # or multi-input layers (e.g. a layer can return multiple tensors, + # and each can be sent to a different layer). + output_tensors[i]._keras_history = (self, len(self._inbound_nodes) - 1, i) # pylint: disable=protected-access - @classmethod - def from_config(cls, config): - """Creates a layer from its config. + def _get_node_attribute_at_index(self, node_index, attr, attr_name): + """Private utility to retrieves an attribute (e.g. inputs) from a node. - This method is the reverse of `get_config`, - capable of instantiating the same layer from the config - dictionary. It does not handle layer connectivity - (handled by Network), nor weights (handled by `set_weights`). + This is used to implement the methods: + - get_input_shape_at + - get_output_shape_at + - get_input_at + etc... Arguments: - config: A Python dictionary, typically the - output of get_config. + node_index: Integer index of the node from which + to retrieve the attribute. + attr: Exact node attribute name. + attr_name: Human-readable attribute name, for error messages. Returns: - A layer instance. + The layer's attribute `attr` at the node of index `node_index`. + + Raises: + RuntimeError: If the layer has no inbound nodes, or if called in Eager + mode. + ValueError: If the index provided does not match any node. """ - return cls(**config) + if not self._inbound_nodes: + raise RuntimeError('The layer has never been called ' + 'and thus has no defined ' + attr_name + '.') + if not len(self._inbound_nodes) > node_index: + raise ValueError('Asked to get ' + attr_name + ' at node ' + + str(node_index) + ', but the layer has only ' + + str(len(self._inbound_nodes)) + ' inbound nodes.') + values = getattr(self._inbound_nodes[node_index], attr) + if len(values) == 1: + return values[0] + else: + return values @property def _static_graph_friendly(self): @@ -1706,197 +1693,12 @@ class Node(object): } -def unique_layer_name(name, name_uid_map=None, avoid_names=None, namespace='', - zero_based=False): - """Makes a layer name (or arbitrary string) unique within a TensorFlow graph. - - Arguments: - name: String name to make unique. - name_uid_map: An optional defaultdict(int) to use when creating unique - names. If None (default), uses a per-Graph dictionary. - avoid_names: An optional set or dict with names which should not be used. If - None (default) does not avoid any names. - namespace: Gets a name which is unique within the (graph, namespace). Layers - which are not Networks use a blank namespace and so get graph-global - names. - zero_based: If True, name sequences start with no suffix (e.g. "dense", - "dense_1"). If False, naming is one-based ("dense_1", "dense_2"). - - Returns: - Unique string name. - - Example: - - ```python - _unique_layer_name('dense') # dense_1 - _unique_layer_name('dense') # dense_2 - ``` - """ - if name_uid_map is None: - name_uid_map = get_default_graph_uid_map() - if avoid_names is None: - avoid_names = set() - proposed_name = None - while proposed_name is None or proposed_name in avoid_names: - name_key = (namespace, name) - if zero_based: - number = name_uid_map[name_key] - if number: - proposed_name = name + '_' + str(number) - else: - proposed_name = name - name_uid_map[name_key] += 1 - else: - name_uid_map[name_key] += 1 - proposed_name = name + '_' + str(name_uid_map[name_key]) - return proposed_name - - -def have_all_keras_metadata(iterable_or_element): - if not isinstance(iterable_or_element, (list, tuple)): - iterable = [iterable_or_element] - else: - iterable = nest.flatten(iterable_or_element) - return all(hasattr(x, '_keras_history') for x in iterable) - - -def collect_previous_mask(input_tensors): - """Retrieves the output mask(s) of the previous node. - - Arguments: - input_tensors: A tensor or list of tensors. - - Returns: - A mask tensor or list of mask tensors. - """ - input_tensors = nest.flatten(input_tensors) - masks = [] - for x in input_tensors: - if hasattr(x, '_keras_mask'): - mask = x._keras_mask # pylint: disable=protected-access - masks.append(mask) - else: - masks.append(None) - if len(masks) == 1: - return masks[0] - return masks - - -def get_default_graph_uid_map(): - # TODO(fchollet): refactor this into backend. - graph = ops.get_default_graph() - name_uid_map = backend.PER_GRAPH_LAYER_NAME_UIDS.get(graph, None) - if name_uid_map is None: - name_uid_map = collections_lib.defaultdict(int) - backend.PER_GRAPH_LAYER_NAME_UIDS[graph] = name_uid_map - return name_uid_map - - -def make_variable(name, - shape=None, - dtype=dtypes.float32, - initializer=None, - partition_info=None, - trainable=None, - caching_device=None, - validate_shape=True, - constraint=None, - use_resource=None, - collections=None, - synchronization=tf_variables.VariableSynchronization.AUTO, - aggregation=tf_variables.VariableAggregation.NONE, - partitioner=None): # pylint: disable=unused-argument - """Temporary util to create a variable (relies on `variable_scope.variable`). - - Some reuse-related technicalities prevent us from using - `variable_scope.get_variable()` directly, so we use a subcomponent - that has fewer constraints (`variable_scope.variable()`). - - In the longer term, it seems like a similar "default variable creator" method - should exist in `CheckpointableBase` instead. When this happens, we can get - rid of this temporary solution. - - TODO(fchollet): remove this method when no longer needed. - TODO(fchollet): handle `partitioner` argument. - - Arguments: - name: Variable name. - shape: Variable shape. - dtype: The type of the variable. Defaults to `self.dtype` or `float32`. - initializer: Initializer instance (callable). - partition_info: Not handled at this time. - trainable: Whether the variable should be part of the layer's - "trainable_variables" (e.g. variables, biases) - or "non_trainable_variables" (e.g. BatchNorm mean, stddev). - Note, if the current variable scope is marked as non-trainable - then this parameter is ignored and any added variables are also - marked as non-trainable. `trainable` defaults to `True` unless - `synchronization` is set to `ON_READ`. - caching_device: Passed to `tf.Variable`. - validate_shape: Passed to `tf.Variable`. - constraint: Constraint instance (callable). - use_resource: Whether to use a `ResourceVariable`. - collections: List of graph collections keys. The new variable is added to - these collections. Defaults to `[GraphKeys.GLOBAL_VARIABLES]`. - synchronization: Indicates when a distributed a variable will be - aggregated. Accepted values are constants defined in the class - `tf.VariableSynchronization`. By default the synchronization is set to - `AUTO` and the current `DistributionStrategy` chooses - when to synchronize. If `synchronization` is set to `ON_READ`, - `trainable` must not be set to `True`. - aggregation: Indicates how a distributed variable will be aggregated. - Accepted values are constants defined in the class - `tf.VariableAggregation`. - partitioner: Not handled at this time. - - Returns: - Variable instance. - """ - initializing_from_value = False - if initializer is not None and not callable(initializer): - initializing_from_value = True - - with ops.init_scope(): - if initializing_from_value: - init_val = initializer - variable_dtype = None - else: - # Instantiate initializer if provided initializer is a type object. - if isinstance(initializer, type(init_ops.Initializer)): - initializer = initializer(dtype=dtype) - init_val = lambda: initializer( # pylint: disable=g-long-lambda - shape, dtype=dtype, partition_info=partition_info) - variable_dtype = dtype.base_dtype - if use_resource is None: - use_resource = True - - # TODO(apassos,rohanj) figure out how to remove collections from here so we - # can remove the V1. - v = tf_variables.VariableV1( - initial_value=init_val, - name=name, - trainable=trainable, - caching_device=caching_device, - dtype=variable_dtype, - validate_shape=validate_shape, - constraint=constraint, - use_resource=use_resource, - collections=collections, - synchronization=synchronization, - aggregation=aggregation) - return v - - def default(method): """Decorates a method to detect overrides in subclasses.""" method._is_default = True return method -def generate_placeholders_from_shape(shape): - return array_ops.placeholder(shape=shape, dtype=backend.floatx()) - - # Avoid breaking users who directly import this symbol from this file. # TODO(fchollet): remove this. InputSpec = input_spec.InputSpec # pylint:disable=invalid-name diff --git a/tensorflow/python/keras/engine/base_layer_utils.py b/tensorflow/python/keras/engine/base_layer_utils.py new file mode 100644 index 0000000000..d2f947f177 --- /dev/null +++ b/tensorflow/python/keras/engine/base_layer_utils.py @@ -0,0 +1,236 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Contains private utilities used mainly by the base Layer class.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections as collections_lib +import enum + +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.keras import backend +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import init_ops +from tensorflow.python.ops import variables as tf_variables +from tensorflow.python.util import nest + + +class CallConvention(enum.Enum): + """Calling conventions for passing `Layer` inputs to `Layer.call`.""" + # The Layer takes inputs as its first argument, named "inputs" for + # compatibility with the signature of Layer.__call__. This is the mode assumed + # for Layers which are not subclassed Models. + EXPLICIT_INPUTS_ARGUMENT = 1 + # The Layer takes a single positional argument, not named "inputs". It's + # treated like an "inputs" argument. + SINGLE_POSITIONAL_ARGUMENT = 2 + # The Layer has multiple positional arguments to which its inputs should be + # bound. + POSITIONAL_ARGUMENTS_ARE_INPUTS = 3 + + +def create_mean_metric(value, name=None): + # TODO(psv): Remove this import when b/110718070 is fixed. + from tensorflow.python.keras import metrics as metrics_module # pylint: disable=g-import-not-at-top + metric_obj = metrics_module.Mean(name=name) + result = metric_obj(value) + return metric_obj, result + + +def make_variable(name, + shape=None, + dtype=dtypes.float32, + initializer=None, + partition_info=None, + trainable=None, + caching_device=None, + validate_shape=True, + constraint=None, + use_resource=None, + collections=None, + synchronization=tf_variables.VariableSynchronization.AUTO, + aggregation=tf_variables.VariableAggregation.NONE, + partitioner=None): # pylint: disable=unused-argument + """Temporary util to create a variable (relies on `variable_scope.variable`). + + Some reuse-related technicalities prevent us from using + `variable_scope.get_variable()` directly, so we use a subcomponent + that has fewer constraints (`variable_scope.variable()`). + + In the longer term, it seems like a similar "default variable creator" method + should exist in `CheckpointableBase` instead. When this happens, we can get + rid of this temporary solution. + + TODO(fchollet): remove this method when no longer needed. + TODO(fchollet): handle `partitioner` argument. + + Arguments: + name: Variable name. + shape: Variable shape. + dtype: The type of the variable. Defaults to `self.dtype` or `float32`. + initializer: Initializer instance (callable). + partition_info: Not handled at this time. + trainable: Whether the variable should be part of the layer's + "trainable_variables" (e.g. variables, biases) + or "non_trainable_variables" (e.g. BatchNorm mean, stddev). + Note, if the current variable scope is marked as non-trainable + then this parameter is ignored and any added variables are also + marked as non-trainable. `trainable` defaults to `True` unless + `synchronization` is set to `ON_READ`. + caching_device: Passed to `tf.Variable`. + validate_shape: Passed to `tf.Variable`. + constraint: Constraint instance (callable). + use_resource: Whether to use a `ResourceVariable`. + collections: List of graph collections keys. The new variable is added to + these collections. Defaults to `[GraphKeys.GLOBAL_VARIABLES]`. + synchronization: Indicates when a distributed a variable will be + aggregated. Accepted values are constants defined in the class + `tf.VariableSynchronization`. By default the synchronization is set to + `AUTO` and the current `DistributionStrategy` chooses + when to synchronize. If `synchronization` is set to `ON_READ`, + `trainable` must not be set to `True`. + aggregation: Indicates how a distributed variable will be aggregated. + Accepted values are constants defined in the class + `tf.VariableAggregation`. + partitioner: Not handled at this time. + + Returns: + Variable instance. + """ + initializing_from_value = False + if initializer is not None and not callable(initializer): + initializing_from_value = True + + with ops.init_scope(): + if initializing_from_value: + init_val = initializer + variable_dtype = None + else: + # Instantiate initializer if provided initializer is a type object. + if isinstance(initializer, type(init_ops.Initializer)): + initializer = initializer(dtype=dtype) + init_val = lambda: initializer( # pylint: disable=g-long-lambda + shape, dtype=dtype, partition_info=partition_info) + variable_dtype = dtype.base_dtype + if use_resource is None: + use_resource = True + + # TODO(apassos,rohanj) figure out how to remove collections from here so we + # can remove the V1. + v = tf_variables.VariableV1( + initial_value=init_val, + name=name, + trainable=trainable, + caching_device=caching_device, + dtype=variable_dtype, + validate_shape=validate_shape, + constraint=constraint, + use_resource=use_resource, + collections=collections, + synchronization=synchronization, + aggregation=aggregation) + return v + + +def get_default_graph_uid_map(): + # TODO(fchollet): refactor this into backend. + graph = ops.get_default_graph() + name_uid_map = backend.PER_GRAPH_LAYER_NAME_UIDS.get(graph, None) + if name_uid_map is None: + name_uid_map = collections_lib.defaultdict(int) + backend.PER_GRAPH_LAYER_NAME_UIDS[graph] = name_uid_map + return name_uid_map + + +def unique_layer_name(name, name_uid_map=None, avoid_names=None, namespace='', + zero_based=False): + """Makes a layer name (or arbitrary string) unique within a TensorFlow graph. + + Arguments: + name: String name to make unique. + name_uid_map: An optional defaultdict(int) to use when creating unique + names. If None (default), uses a per-Graph dictionary. + avoid_names: An optional set or dict with names which should not be used. If + None (default) does not avoid any names. + namespace: Gets a name which is unique within the (graph, namespace). Layers + which are not Networks use a blank namespace and so get graph-global + names. + zero_based: If True, name sequences start with no suffix (e.g. "dense", + "dense_1"). If False, naming is one-based ("dense_1", "dense_2"). + + Returns: + Unique string name. + + Example: + + ```python + _unique_layer_name('dense') # dense_1 + _unique_layer_name('dense') # dense_2 + ``` + """ + if name_uid_map is None: + name_uid_map = get_default_graph_uid_map() + if avoid_names is None: + avoid_names = set() + proposed_name = None + while proposed_name is None or proposed_name in avoid_names: + name_key = (namespace, name) + if zero_based: + number = name_uid_map[name_key] + if number: + proposed_name = name + '_' + str(number) + else: + proposed_name = name + name_uid_map[name_key] += 1 + else: + name_uid_map[name_key] += 1 + proposed_name = name + '_' + str(name_uid_map[name_key]) + return proposed_name + + +def collect_previous_mask(input_tensors): + """Retrieves the output mask(s) of the previous node. + + Arguments: + input_tensors: A tensor or list of tensors. + + Returns: + A mask tensor or list of mask tensors. + """ + input_tensors = nest.flatten(input_tensors) + masks = [] + for x in input_tensors: + if hasattr(x, '_keras_mask'): + mask = x._keras_mask # pylint: disable=protected-access + masks.append(mask) + else: + masks.append(None) + if len(masks) == 1: + return masks[0] + return masks + + +def have_all_keras_metadata(iterable_or_element): + if not isinstance(iterable_or_element, (list, tuple)): + iterable = [iterable_or_element] + else: + iterable = nest.flatten(iterable_or_element) + return all(hasattr(x, '_keras_history') for x in iterable) + + +def generate_placeholders_from_shape(shape): + return array_ops.placeholder(shape=shape, dtype=backend.floatx()) diff --git a/tensorflow/python/keras/engine/network.py b/tensorflow/python/keras/engine/network.py index f854cdd4e0..1040fd8ea3 100644 --- a/tensorflow/python/keras/engine/network.py +++ b/tensorflow/python/keras/engine/network.py @@ -36,6 +36,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape from tensorflow.python.keras import backend from tensorflow.python.keras.engine import base_layer +from tensorflow.python.keras.engine import base_layer_utils from tensorflow.python.keras.engine import saving from tensorflow.python.keras.utils import generic_utils from tensorflow.python.keras.utils import layer_utils @@ -162,7 +163,8 @@ class Network(base_layer.Layer): @checkpointable.no_automatic_dependency_tracking def _init_graph_network(self, inputs, outputs, name=None): - self._call_convention = base_layer.CallConvention.EXPLICIT_INPUTS_ARGUMENT + self._call_convention = (base_layer_utils + .CallConvention.EXPLICIT_INPUTS_ARGUMENT) # Normalize and set self.inputs, self.outputs. if isinstance(inputs, (list, tuple)): self.inputs = list(inputs) # Tensor or list of tensors. @@ -305,7 +307,7 @@ class Network(base_layer.Layer): return self._call_is_graph_friendly def _determine_call_convention(self, call_argspec): - """Decides how `self.call()` is invoked. See base_layer.CallConvention.""" + """Decides how `self.call()` is invoked. See `CallConvention`.""" if call_argspec.varargs: may_take_single_argument = False else: @@ -337,11 +339,11 @@ class Network(base_layer.Layer): "Model.call() takes a single positional argument (to which " "inputs are passed by convention) and a separate 'inputs' " "argument. Unable to determine which arguments are inputs.") - return base_layer.CallConvention.SINGLE_POSITIONAL_ARGUMENT + return base_layer_utils.CallConvention.SINGLE_POSITIONAL_ARGUMENT if 'inputs' in call_argspec.args: - return base_layer.CallConvention.EXPLICIT_INPUTS_ARGUMENT + return base_layer_utils.CallConvention.EXPLICIT_INPUTS_ARGUMENT else: - return base_layer.CallConvention.POSITIONAL_ARGUMENTS_ARE_INPUTS + return base_layer_utils.CallConvention.POSITIONAL_ARGUMENTS_ARE_INPUTS def _track_layers(self, layers): """Add Checkpointable dependencies on a list of Layers.""" @@ -807,10 +809,10 @@ class Network(base_layer.Layer): graph = func_graph.FuncGraph('graph') with graph.as_default(): if isinstance(input_shape, list): - x = [base_layer.generate_placeholders_from_shape(shape) + x = [base_layer_utils.generate_placeholders_from_shape(shape) for shape in input_shape] else: - x = base_layer.generate_placeholders_from_shape(input_shape) + x = base_layer_utils.generate_placeholders_from_shape(input_shape) kwargs = {} num_call_args = len(tf_inspect.getfullargspec(self.call).args) diff --git a/tensorflow/python/keras/optimizer_v2/optimizer_v2.py b/tensorflow/python/keras/optimizer_v2/optimizer_v2.py index ee0076703f..0101ea8b97 100644 --- a/tensorflow/python/keras/optimizer_v2/optimizer_v2.py +++ b/tensorflow/python/keras/optimizer_v2/optimizer_v2.py @@ -31,7 +31,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.keras import backend from tensorflow.python.keras import initializers -from tensorflow.python.keras.engine import base_layer +from tensorflow.python.keras.engine import base_layer_utils from tensorflow.python.ops import gradients from tensorflow.python.ops import math_ops from tensorflow.python.ops import variables as tf_variables @@ -550,7 +550,7 @@ class OptimizerV2(optimizer_v1.Optimizer): variable = self._add_variable_with_custom_getter( name=name, shape=shape, - getter=base_layer.make_variable, + getter=base_layer_utils.make_variable, overwrite=True, initializer=initializer, dtype=dtype, diff --git a/tensorflow/python/layers/base.py b/tensorflow/python/layers/base.py index 42086e4c3e..bfe591f875 100644 --- a/tensorflow/python/layers/base.py +++ b/tensorflow/python/layers/base.py @@ -23,6 +23,7 @@ from tensorflow.python.eager import context from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.keras.engine import base_layer +from tensorflow.python.keras.engine import base_layer_utils from tensorflow.python.ops import variable_scope as vs from tensorflow.python.ops import variables as tf_variables from tensorflow.python.util import function_utils @@ -242,11 +243,11 @@ class Layer(base_layer.Layer): def _make_unique_name(self, name_uid_map=None, avoid_names=None, namespace='', zero_based=False): base_name = base_layer.to_snake_case(self.__class__.__name__) - name = base_layer.unique_layer_name(base_name, - name_uid_map=name_uid_map, - avoid_names=avoid_names, - namespace=namespace, - zero_based=zero_based) + name = base_layer_utils.unique_layer_name(base_name, + name_uid_map=name_uid_map, + avoid_names=avoid_names, + namespace=namespace, + zero_based=zero_based) return (name, base_name) @property -- GitLab From 5d013e9d011a13bcfca8e013690b1f0375e8bf49 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 17:44:45 -0800 Subject: [PATCH 366/672] This CL avoids superfluous construction of backwards graphs for nested function calls. It delays construction of backwards graph to when a tape is actually used to compute a gradient. PiperOrigin-RevId: 222916814 --- tensorflow/python/eager/function.py | 115 ++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 33 deletions(-) diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index eff7a384b8..68cdb1a871 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -424,7 +424,10 @@ class Function(object): if (tape.should_record(tensor_inputs) or tape.should_record(self._captured_inputs)): - return self._backprop_call(args) + if context.executing_eagerly(): + return self._eager_backprop_call(args) + else: + return self._backprop_call_with_delayed_rewrite(args) # Only need to override the gradient in graph mode and when we have outputs. if context.executing_eagerly() or not self.outputs: @@ -450,37 +453,40 @@ class Function(object): name: The name to register the gradient as. """ @ops.RegisterGradient(name) - def grad_fn(op, *doutputs): # pylint: disable=unused-variable - """Gradients of this function.""" - if self._backward_graph_function is None: - self._construct_backprop_function() + def _registered_grad_fn(op, *doutputs): # pylint: disable=unused-variable + return self._grad_fn(op, *doutputs) - # pylint: disable=protected-access - self._forward_function.add_to_graph(op.graph) - num_inference_outputs = self._inference_function._num_outputs - - # Rewrite an inference call op to be a forward call op - if op.get_attr("f").name.encode() == self._inference_function.name: - func = attr_value_pb2.AttrValue( - func=attr_value_pb2.NameAttrList( - name=self._forward_function.name)) - op._set_attr("f", func) - types = attr_value_pb2.AttrValue.ListValue( - type=self._forward_function._output_types) - op._set_attr("Tout", attr_value_pb2.AttrValue(list=types)) - for i in range( - num_inference_outputs, len(self._forward_function._output_types)): - t = ops.Tensor(op, i, self._forward_function._output_types[i]) - t.set_shape(self._forward_function._output_shapes[i]) - func_graph_output = self._forward_function._func_graph_outputs[i] - custom_gradient.copy_handle_data(func_graph_output, t) - op._outputs.append(t) - # pylint: enable=protected-access - # Compute the gradients using the side outputs - side_outputs = op.outputs[num_inference_outputs:] - args = list(doutputs[:num_inference_outputs]) + list(side_outputs) - return self._backward_graph_function._call_flat( # pylint: disable=protected-access - (a for a in args if a is not None)) + def _grad_fn(self, op, *doutputs): + """Gradients of this function.""" + if self._backward_graph_function is None: + self._construct_backprop_function() + + # pylint: disable=protected-access + self._forward_function.add_to_graph(op.graph) + num_inference_outputs = self._inference_function._num_outputs + + # Rewrite an inference call op to be a forward call op + if op.get_attr("f").name.encode() == self._inference_function.name: + func = attr_value_pb2.AttrValue( + func=attr_value_pb2.NameAttrList( + name=self._forward_function.name)) + op._set_attr("f", func) + types = attr_value_pb2.AttrValue.ListValue( + type=self._forward_function._output_types) + op._set_attr("Tout", attr_value_pb2.AttrValue(list=types)) + for i in range( + num_inference_outputs, len(self._forward_function._output_types)): + t = ops.Tensor(op, i, self._forward_function._output_types[i]) + t.set_shape(self._forward_function._output_shapes[i]) + func_graph_output = self._forward_function._func_graph_outputs[i] + custom_gradient.copy_handle_data(func_graph_output, t) + op._outputs.append(t) + # pylint: enable=protected-access + # Compute the gradients using the side outputs + side_outputs = op.outputs[num_inference_outputs:] + args = list(doutputs[:num_inference_outputs]) + list(side_outputs) + return self._backward_graph_function._call_flat( # pylint: disable=protected-access + (a for a in args if a is not None)) @property def name(self): @@ -623,10 +629,13 @@ class Function(object): self._func_graph.outputs + backwards_graph_captures, forward_function_attr) - def _backprop_call(self, args): + def _eager_backprop_call(self, args): """Calls the forward function and records the result on a tape. - (Only records results on a tape if the function has outputs) + This method fully constructs the forward and backward functions before + calling the function and recording them on the tape. + + (Only records results on a tape if the function has outputs). Args: args: All inputs to the function, including resolved captured inputs @@ -668,6 +677,46 @@ class Function(object): args, backward_function) return self._build_call_outputs(real_outputs) + def _backprop_call_with_delayed_rewrite(self, args): + """Calls the inference function and records the result on a tape. + + The recorded backwards function will construct the backwards graph and + rewrite the inference function to the forward function. This only happens + if the recorded backwards function ends up being used to compute gradients. + + This approach avoids constructing unnecessary graphs, but it only works if + we are calling this function when not executing eagerly. + + (Only records results on a tape if the function has outputs) + + Args: + args: All inputs to the function, including resolved captured inputs + + Returns: + The call output. + """ + ctx = context.context() + + if not self._gradient_name: + self._gradient_name = "PartitionedCall-%s" % ops.uid() + self._register_gradient(self._gradient_name) + with ops.get_default_graph().gradient_override_map( + {"PartitionedCall": self._gradient_name, + "StatefulPartitionedCall": self._gradient_name}): + outputs = self._inference_function.call(ctx, args) + + if isinstance(outputs, ops.Operation) or outputs is None: + return outputs + + call_op = outputs[0].op + + def backward_function(*args): + return self._grad_fn(call_op, *args) + + tape.record_operation(self._inference_function.signature.name, outputs, + args, backward_function) + return self._build_call_outputs(outputs) + def _build_call_outputs(self, result): """Maps the fdef output list to actual output structure. -- GitLab From ab7cfa02796670d5061da81e683914b28218749f Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Mon, 26 Nov 2018 18:06:10 -0800 Subject: [PATCH 367/672] Add run_deprecated_v1 to test_util PiperOrigin-RevId: 222919298 --- tensorflow/python/framework/test_util.py | 34 ++++++++++++++++++- tensorflow/python/framework/test_util_test.py | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index 7c486b2cbe..a034032e39 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -960,7 +960,7 @@ def run_in_graph_and_eager_modes(func=None, def decorator(f): if tf_inspect.isclass(f): raise ValueError( - "`run_test_in_graph_and_eager_modes` only supports test methods. " + "`run_in_graph_and_eager_modes` only supports test methods. " "Did you mean to use `run_all_in_graph_and_eager_modes`?") def decorated(self, *args, **kwargs): @@ -1005,6 +1005,38 @@ def run_in_graph_and_eager_modes(func=None, return decorator +def run_deprecated_v1(func=None): + """Execute the decorated test in graph mode. + + This function returns a decorator intended to be applied to tests that have + not been updated to a style that is compatible with both TensorFlow 1.x and + 2.x. When this decorated is applied, the test body will be run in + an environment where API calls construct graphs instead of executing eagerly. + + Args: + func: function to be annotated. If `func` is None, this method returns a + decorator the can be applied to a function. If `func` is not None this + returns the decorator applied to `func`. + Returns: + Returns a decorator that will run the decorated test method in graph mode. + """ + + def decorator(f): + if tf_inspect.isclass(f): + raise ValueError("`run_deprecated_v1` only supports test methods.") + + def decorated(self, *args, **kwargs): + with context.graph_mode(): + f(self, *args, **kwargs) + + return decorated + + if func is not None: + return decorator(func) + + return decorator + + @tf_export("test.is_gpu_available") def is_gpu_available(cuda_only=False, min_cuda_compute_capability=None): """Returns whether TensorFlow can access a GPU. diff --git a/tensorflow/python/framework/test_util_test.py b/tensorflow/python/framework/test_util_test.py index cbefe86481..2a37253db6 100644 --- a/tensorflow/python/framework/test_util_test.py +++ b/tensorflow/python/framework/test_util_test.py @@ -681,7 +681,7 @@ class TestUtilTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIsNone(test_util.get_node_def_from_graph("bar", graph_def)) def test_run_in_eager_and_graph_modes_test_class(self): - msg = "`run_test_in_graph_and_eager_modes` only supports test methods.*" + msg = "`run_in_graph_and_eager_modes` only supports test methods.*" with self.assertRaisesRegexp(ValueError, msg): @test_util.run_in_graph_and_eager_modes() class Foo(object): -- GitLab From 290c330ee86ea8068d8a274d8202999f53eb2b35 Mon Sep 17 00:00:00 2001 From: Jonathan Hseu Date: Mon, 26 Nov 2018 18:30:06 -0800 Subject: [PATCH 368/672] TF 2.0: Change the semantics of tf.nn.dropout to be consistent with tf.keras.layers.Dropout. PiperOrigin-RevId: 222921458 --- .../python/kernel_tests/core_rnn_cell_test.py | 6 +- .../rnn/python/kernel_tests/core_rnn_test.py | 2 +- tensorflow/python/ops/nn_ops.py | 68 ++++++++++++++++++- .../tools/api/golden/v2/tensorflow.nn.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 27 +++++++- .../tools/compatibility/tf_upgrade_v2_test.py | 16 +++++ 6 files changed, 114 insertions(+), 7 deletions(-) diff --git a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py index 245fa68eae..7d57b0413a 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_cell_test.py @@ -906,7 +906,7 @@ class DropoutWrapperTest(test.TestCase): def testDropoutWrapperKeepNoOutput(self): keep_all = variable_scope.get_variable("all", initializer=1.0) - keep_none = variable_scope.get_variable("none", initializer=1e-10) + keep_none = variable_scope.get_variable("none", initializer=1e-6) res = self._testDropoutWrapper( input_keep_prob=keep_all, output_keep_prob=keep_none, @@ -922,7 +922,7 @@ class DropoutWrapperTest(test.TestCase): def testDropoutWrapperKeepNoStateExceptLSTMCellMemory(self): keep_all = variable_scope.get_variable("all", initializer=1.0) - keep_none = variable_scope.get_variable("none", initializer=1e-10) + keep_none = variable_scope.get_variable("none", initializer=1e-6) # Even though we dropout state, by default DropoutWrapper never # drops out the memory ("c") term of an LSTMStateTuple. res = self._testDropoutWrapper( @@ -943,7 +943,7 @@ class DropoutWrapperTest(test.TestCase): def testDropoutWrapperKeepNoInput(self): keep_all = variable_scope.get_variable("all", initializer=1.0) - keep_none = variable_scope.get_variable("none", initializer=1e-10) + keep_none = variable_scope.get_variable("none", initializer=1e-6) true_full_output = np.array( [[[0.751109, 0.751109, 0.751109]], [[0.895509, 0.895509, 0.895509]]], dtype=np.float32) diff --git a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_test.py b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_test.py index 5cba54dd3d..ef372b947c 100644 --- a/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_test.py +++ b/tensorflow/contrib/rnn/python/kernel_tests/core_rnn_test.py @@ -227,7 +227,7 @@ class RNNTest(test.TestCase): def testDropout(self): cell = Plus1RNNCell() full_dropout_cell = rnn_cell.DropoutWrapper( - cell, input_keep_prob=1e-12, seed=0) + cell, input_keep_prob=1e-6, seed=0) (name, dep), = full_dropout_cell._checkpoint_dependencies self.assertIs(dep, cell) self.assertEqual("cell", name) diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 0e39dd0fa0..5655960aae 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -2791,7 +2791,7 @@ def _get_noise_shape(x, noise_shape): return noise_shape -@tf_export("nn.dropout") +@tf_export(v1=["nn.dropout"]) def dropout(x, keep_prob, noise_shape=None, seed=None, name=None): # pylint: disable=invalid-name """Computes dropout. @@ -2850,8 +2850,74 @@ def dropout(x, keep_prob, noise_shape=None, seed=None, name=None): # pylint: di if tensor_util.constant_value(keep_prob) == 1: return x + rate = 1 - keep_prob + + return dropout_v2(x, rate, noise_shape=noise_shape, seed=seed, name=name) + + +@tf_export("nn.dropout", v1=[]) +def dropout_v2(x, rate, noise_shape=None, seed=None, name=None): # pylint: disable=invalid-name + """Computes dropout. + + With probability `rate`, drops elements of `x`. Input that are kept are + scaled up by `1 / (1 - rate)`, otherwise outputs `0`. The scaling is so that + the expected sum is unchanged. + + By default, each element is kept or dropped independently. If `noise_shape` + is specified, it must be + [broadcastable](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) + to the shape of `x`, and only dimensions with `noise_shape[i] == shape(x)[i]` + will make independent decisions. For example, if `shape(x) = [k, l, m, n]` + and `noise_shape = [k, 1, 1, n]`, each batch and channel component will be + kept independently and each row and column will be kept or not kept together. + + Args: + x: A floating point tensor. + rate: A scalar `Tensor` with the same type as x. The probability + that each element is dropped. For example, setting rate=0.1 would drop + 10% of input elements. + noise_shape: A 1-D `Tensor` of type `int32`, representing the + shape for randomly generated keep/drop flags. + seed: A Python integer. Used to create random seeds. See + `tf.set_random_seed` + for behavior. + name: A name for this operation (optional). + + Returns: + A Tensor of the same shape of `x`. + + Raises: + ValueError: If `keep_prob` is not in `(0, 1]` or if `x` is not a floating + point tensor. + """ + with ops.name_scope(name, "dropout", [x]) as name: + x = ops.convert_to_tensor(x, name="x") + if not x.dtype.is_floating: + raise ValueError("x has to be a floating point tensor since it's going to" + " be scaled. Got a %s tensor instead." % x.dtype) + if isinstance(rate, numbers.Real) and not 0 <= rate < 1: + raise ValueError("rate must be a scalar tensor or a float in the " + "range [0, 1), got %g" % rate) + + # Early return if nothing needs to be dropped. + if isinstance(rate, float) and rate == 0: + return x + if context.executing_eagerly(): + if isinstance(rate, ops.EagerTensor): + if rate.numpy() == 0: + return x + else: + rate = ops.convert_to_tensor( + rate, dtype=x.dtype, name="rate") + rate.get_shape().assert_is_compatible_with(tensor_shape.scalar()) + + # Do nothing if we know rate == 0 + if tensor_util.constant_value(rate) == 0: + return x + noise_shape = _get_noise_shape(x, noise_shape) + keep_prob = 1 - rate # uniform [keep_prob, 1.0 + keep_prob) random_tensor = keep_prob random_tensor += random_ops.random_uniform( diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index 77b5887c1f..0bfea74e40 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -126,7 +126,7 @@ tf_module { } member_method { name: "dropout" - argspec: "args=[\'x\', \'keep_prob\', \'noise_shape\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " + argspec: "args=[\'x\', \'rate\', \'noise_shape\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " } member_method { name: "elu" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index e8ea9784af..178521f6b3 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -559,7 +559,9 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): } # Specially handled functions. - self.function_handle = {} + self.function_handle = { + "tf.nn.dropout": self._dropout_handler, + } decay_function_comment = ( "ERROR: has been changed to return a callable instead " @@ -668,6 +670,29 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): if name not in self.function_warnings and name not in excluded_renames } + @staticmethod + def _dropout_handler(file_edit_recorder, node): + if len(node.args) < 2: + comment = ("ERROR: tf.nn.dropout did not take arguments, so automatic " + "transformation was disabled. tf.nn.dropout has changed " + "the semantics of the second argument.") + file_edit_recorder.add( + comment, + node.lineno, + node.col_offset, + "tf.nn.dropout", + "tf.nn.dropout", + error="tf.nn.dropout requires manual check.") + else: + comment = ("WARNING: tf.nn.dropout has changed the semantics of the " + "second argument. Please check the transformation.\n") + file_edit_recorder.add( + comment, + node.args[1].lineno, + node.args[1].col_offset, + "", + "1 - ") + if __name__ == "__main__": parser = argparse.ArgumentParser( diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index 7baa1cafdd..65d77a2c9a 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -116,6 +116,22 @@ class TestUpgrade(test_util.TensorFlowTestCase): self.assertEqual(errors, ["test.py:1: %s requires manual check." % ns]) self.assertIn("loss_reduction has been changed", report) + def testDropout(self): + text = "tf.nn.dropout(x, keep_prob, name=\"foo\")\n" + _, unused_report, unused_errors, new_text = self._upgrade(text) + self.assertEqual( + new_text, + "tf.nn.dropout(x, 1 - keep_prob, name=\"foo\")\n", + ) + + text = "tf.nn.dropout(x)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(new_text, text) + self.assertEqual( + errors, + ["test.py:1: tf.nn.dropout requires manual check."] + ) + def testCountNonZeroChanges(self): text = ( "tf.math.count_nonzero(input_tensor=input, dtype=dtype, name=name, " -- GitLab From 9f3d9b54478359e9258895d3335731183bfd8e45 Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Mon, 26 Nov 2018 18:41:51 -0800 Subject: [PATCH 369/672] Automated rollback of commit 5a08ce9bd17c2678c80b0af70996ebbc4879c937 PiperOrigin-RevId: 222922435 --- tensorflow/stream_executor/BUILD | 11 -------- tensorflow/stream_executor/dnn.h | 7 ++--- tensorflow/stream_executor/logging.proto | 19 ------------- .../stream_executor/stream_executor_pimpl.cc | 28 +------------------ 4 files changed, 4 insertions(+), 61 deletions(-) delete mode 100644 tensorflow/stream_executor/logging.proto diff --git a/tensorflow/stream_executor/BUILD b/tensorflow/stream_executor/BUILD index 74fec09d80..2526e1adaa 100644 --- a/tensorflow/stream_executor/BUILD +++ b/tensorflow/stream_executor/BUILD @@ -23,14 +23,6 @@ tf_proto_library( protodeps = tf_additional_all_protos(), ) -tf_proto_library( - name = "logging_proto", - srcs = ["logging.proto"], - cc_api_version = 2, - default_header = True, - protodeps = tf_additional_all_protos(), -) - cc_library( name = "stream_executor_impl", srcs = glob( @@ -54,9 +46,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":dnn_proto_cc_impl", - ":logging_proto_cc_impl", "//tensorflow/core:lib", - "//tensorflow/core:logger", "//tensorflow/core:ptr_util", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", @@ -73,7 +63,6 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":dnn_proto_cc", - ":logging_proto_cc", "//tensorflow/core:lib", "//tensorflow/core:ptr_util", "@com_google_absl//absl/strings", diff --git a/tensorflow/stream_executor/dnn.h b/tensorflow/stream_executor/dnn.h index 43738d2d1d..c044a356ef 100644 --- a/tensorflow/stream_executor/dnn.h +++ b/tensorflow/stream_executor/dnn.h @@ -906,10 +906,9 @@ class VersionInfo { public: VersionInfo(int major = 0, int minor = 0, int patch = 0) : major_(major), minor_(minor), patch_(patch) {} - int major_version() const { return major_; } - int minor_version() const { return minor_; } - int patch() const { return patch_; } - + int major_version() { return major_; } + int minor_version() { return minor_; } + int patch() { return patch_; } private: int major_; int minor_; diff --git a/tensorflow/stream_executor/logging.proto b/tensorflow/stream_executor/logging.proto deleted file mode 100644 index 2c75500cda..0000000000 --- a/tensorflow/stream_executor/logging.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package stream_executor; - -message CudnnVersion { - int32 major = 1; - int32 minor = 2; - int32 patch = 3; -}; - -message ComputeCapability { - int32 major = 1; - int32 minor = 2; -} - -message CudaInfo { - CudnnVersion cudnn_version = 1; - ComputeCapability compute_capability = 2; -} diff --git a/tensorflow/stream_executor/stream_executor_pimpl.cc b/tensorflow/stream_executor/stream_executor_pimpl.cc index 86bc4ab7d0..d1d0bd9bc2 100644 --- a/tensorflow/stream_executor/stream_executor_pimpl.cc +++ b/tensorflow/stream_executor/stream_executor_pimpl.cc @@ -23,7 +23,6 @@ limitations under the License. #include #include "absl/strings/str_cat.h" -#include "tensorflow/core/platform/logger.h" #include "tensorflow/core/util/env_var.h" #include "tensorflow/stream_executor/blas.h" #include "tensorflow/stream_executor/fft.h" @@ -34,7 +33,6 @@ limitations under the License. #include "tensorflow/stream_executor/lib/str_util.h" #include "tensorflow/stream_executor/lib/stringprintf.h" #include "tensorflow/stream_executor/lib/threadpool.h" -#include "tensorflow/stream_executor/logging.pb.h" #include "tensorflow/stream_executor/platform/port.h" #include "tensorflow/stream_executor/rng.h" #include "tensorflow/stream_executor/stream_executor_internal.h" @@ -219,31 +217,7 @@ StreamExecutor::~StreamExecutor() { port::Status StreamExecutor::Init(int device_ordinal, DeviceOptions device_options) { device_ordinal_ = device_ordinal; - TF_RETURN_IF_ERROR( - implementation_->Init(device_ordinal, std::move(device_options))); - - if (platform_kind_ == PlatformKind::kCuda) { - CudaInfo info; - - int cc_major, cc_minor; - GetDeviceDescription().cuda_compute_capability(&cc_major, &cc_minor); - info.mutable_compute_capability()->set_major(cc_major); - info.mutable_compute_capability()->set_minor(cc_minor); - - if (auto *dnn = AsDnn()) { - port::StatusOr version_or = dnn->GetVersion(); - if (version_or.ok()) { - const auto &version = version_or.ValueOrDie(); - info.mutable_cudnn_version()->set_major(version.major_version()); - info.mutable_cudnn_version()->set_minor(version.minor_version()); - info.mutable_cudnn_version()->set_patch(version.patch()); - } - } - - tensorflow::Logger::Singleton()->LogProto(info); - } - - return port::Status::OK(); + return implementation_->Init(device_ordinal, std::move(device_options)); } port::Status StreamExecutor::Init() { -- GitLab From 516e122b4c0f1ac83ab5abb5fb993277c8ebf2db Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 19:00:56 -0800 Subject: [PATCH 370/672] Close resource file after loading model file. PiperOrigin-RevId: 222923990 --- .../android/smartreply/SmartReplyClient.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tensorflow/lite/models/smartreply/demo/app/src/main/java/com/example/android/smartreply/SmartReplyClient.java b/tensorflow/lite/models/smartreply/demo/app/src/main/java/com/example/android/smartreply/SmartReplyClient.java index d5b1ac0ffb..fbd75051e7 100644 --- a/tensorflow/lite/models/smartreply/demo/app/src/main/java/com/example/android/smartreply/SmartReplyClient.java +++ b/tensorflow/lite/models/smartreply/demo/app/src/main/java/com/example/android/smartreply/SmartReplyClient.java @@ -90,29 +90,26 @@ public class SmartReplyClient implements AutoCloseable { } private MappedByteBuffer loadModelFile() throws IOException { - AssetFileDescriptor fileDescriptor = context.getAssets().openFd(MODEL_PATH); - FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor()); - try { + try (AssetFileDescriptor fileDescriptor = context.getAssets().openFd(MODEL_PATH); + FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor())) { FileChannel fileChannel = inputStream.getChannel(); long startOffset = fileDescriptor.getStartOffset(); long declaredLength = fileDescriptor.getDeclaredLength(); return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength); - } finally { - inputStream.close(); } } private String[] loadBackoffList() throws IOException { List labelList = new ArrayList(); - BufferedReader reader = - new BufferedReader(new InputStreamReader(context.getAssets().open(BACKOFF_PATH))); - String line; - while ((line = reader.readLine()) != null) { - if (!line.isEmpty()) { - labelList.add(line); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(context.getAssets().open(BACKOFF_PATH)))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.isEmpty()) { + labelList.add(line); + } } } - reader.close(); String[] ans = new String[labelList.size()]; labelList.toArray(ans); return ans; -- GitLab From 75f6bf69fc4ef363a906ac5f958af1ae40a328d8 Mon Sep 17 00:00:00 2001 From: Jonathan Hseu Date: Mon, 26 Nov 2018 19:03:46 -0800 Subject: [PATCH 371/672] Remove colocate_gradients_with_ops in TF 2.0 and default it to True. PiperOrigin-RevId: 222924432 --- .../contrib/optimizer_v2/optimizer_v2.py | 16 +-- tensorflow/python/ops/gradients_impl.py | 115 +++++++++++++++++- .../tools/api/golden/v2/tensorflow.pbtxt | 2 +- tensorflow/tools/compatibility/ast_edits.py | 11 +- .../tools/compatibility/tf_upgrade_v2.py | 24 ++++ .../tools/compatibility/tf_upgrade_v2_test.py | 34 ++++++ 6 files changed, 184 insertions(+), 18 deletions(-) diff --git a/tensorflow/contrib/optimizer_v2/optimizer_v2.py b/tensorflow/contrib/optimizer_v2/optimizer_v2.py index a72db5e12f..747f5b9b8b 100644 --- a/tensorflow/contrib/optimizer_v2/optimizer_v2.py +++ b/tensorflow/contrib/optimizer_v2/optimizer_v2.py @@ -658,7 +658,6 @@ class OptimizerV2(optimizer_v1.Optimizer): var_list=None, gate_gradients=GATE_OP, aggregation_method=None, - colocate_gradients_with_ops=False, name=None, grad_loss=None, stop_gradients=None, @@ -681,8 +680,6 @@ class OptimizerV2(optimizer_v1.Optimizer): `GATE_NONE`, `GATE_OP`, or `GATE_GRAPH`. aggregation_method: Specifies the method used to combine gradient terms. Valid values are defined in the class `AggregationMethod`. - colocate_gradients_with_ops: If True, try colocating gradients with the - corresponding op. name: Optional name for the returned operation. grad_loss: Optional. A `Tensor` holding the gradient computed for `loss`. stop_gradients: Optional. A Tensor or list of tensors not to differentiate @@ -705,8 +702,8 @@ class OptimizerV2(optimizer_v1.Optimizer): Minimization (and gradient computation) is done with respect to the elements of `var_list` if not None, else with respect to any trainable variables created during the execution of the `loss` function. - `gate_gradients`, `aggregation_method`, `colocate_gradients_with_ops` and - `grad_loss` are ignored when eager execution is enabled. + `gate_gradients`, `aggregation_method`, and `grad_loss` are ignored when + eager execution is enabled. @end_compatibility """ grads_and_vars = self.compute_gradients( @@ -714,7 +711,6 @@ class OptimizerV2(optimizer_v1.Optimizer): var_list=var_list, gate_gradients=gate_gradients, aggregation_method=aggregation_method, - colocate_gradients_with_ops=colocate_gradients_with_ops, grad_loss=grad_loss, stop_gradients=stop_gradients, scale_loss_by_num_replicas=scale_loss_by_num_replicas) @@ -734,7 +730,6 @@ class OptimizerV2(optimizer_v1.Optimizer): var_list=None, gate_gradients=GATE_OP, aggregation_method=None, - colocate_gradients_with_ops=False, grad_loss=None, stop_gradients=None, scale_loss_by_num_replicas=None): @@ -757,8 +752,6 @@ class OptimizerV2(optimizer_v1.Optimizer): `GATE_NONE`, `GATE_OP`, or `GATE_GRAPH`. aggregation_method: Specifies the method used to combine gradient terms. Valid values are defined in the class `AggregationMethod`. - colocate_gradients_with_ops: If True, try colocating gradients with the - corresponding op. grad_loss: Optional. A `Tensor` holding the gradient computed for `loss`. stop_gradients: Optional. A Tensor or list of tensors not to differentiate through. @@ -777,8 +770,8 @@ class OptimizerV2(optimizer_v1.Optimizer): not callable. @compatibility(eager) - When eager execution is enabled, `gate_gradients`, `aggregation_method`, - and `colocate_gradients_with_ops` are ignored. + When eager execution is enabled, `gate_gradients`, and `aggregation_method` + are ignored. @end_compatibility """ # TODO(josh11b): Test that we handle weight decay in a reasonable way. @@ -833,7 +826,6 @@ class OptimizerV2(optimizer_v1.Optimizer): grad_ys=grad_loss, gate_gradients=(gate_gradients == optimizer_v1.Optimizer.GATE_OP), aggregation_method=aggregation_method, - colocate_gradients_with_ops=colocate_gradients_with_ops, stop_gradients=stop_gradients) if gate_gradients == optimizer_v1.Optimizer.GATE_GRAPH: grads = control_flow_ops.tuple(grads) diff --git a/tensorflow/python/ops/gradients_impl.py b/tensorflow/python/ops/gradients_impl.py index 27cee9113d..c8f5cb8349 100644 --- a/tensorflow/python/ops/gradients_impl.py +++ b/tensorflow/python/ops/gradients_impl.py @@ -539,7 +539,7 @@ def _Consumers(t, func_graphs): return consumers -@tf_export("gradients") +@tf_export(v1=["gradients"]) def gradients(ys, xs, grad_ys=None, @@ -655,6 +655,119 @@ def gradients(ys, unconnected_gradients) +@tf_export("gradients", v1=[]) +def gradients_v2(ys, # pylint: disable=invalid-name + xs, + grad_ys=None, + name="gradients", + gate_gradients=False, + aggregation_method=None, + stop_gradients=None, + unconnected_gradients=UnconnectedGradients.NONE): + """Constructs symbolic derivatives of sum of `ys` w.r.t. x in `xs`. + + `ys` and `xs` are each a `Tensor` or a list of tensors. `grad_ys` + is a list of `Tensor`, holding the gradients received by the + `ys`. The list must be the same length as `ys`. + + `gradients()` adds ops to the graph to output the derivatives of `ys` with + respect to `xs`. It returns a list of `Tensor` of length `len(xs)` where + each tensor is the `sum(dy/dx)` for y in `ys`. + + `grad_ys` is a list of tensors of the same length as `ys` that holds + the initial gradients for each y in `ys`. When `grad_ys` is None, + we fill in a tensor of '1's of the shape of y for each y in `ys`. A + user can provide their own initial `grad_ys` to compute the + derivatives using a different initial gradient for each y (e.g., if + one wanted to weight the gradient differently for each value in + each y). + + `stop_gradients` is a `Tensor` or a list of tensors to be considered constant + with respect to all `xs`. These tensors will not be backpropagated through, + as though they had been explicitly disconnected using `stop_gradient`. Among + other things, this allows computation of partial derivatives as opposed to + total derivatives. For example: + + ```python + a = tf.constant(0.) + b = 2 * a + g = tf.gradients(a + b, [a, b], stop_gradients=[a, b]) + ``` + + Here the partial derivatives `g` evaluate to `[1.0, 1.0]`, compared to the + total derivatives `tf.gradients(a + b, [a, b])`, which take into account the + influence of `a` on `b` and evaluate to `[3.0, 1.0]`. Note that the above is + equivalent to: + + ```python + a = tf.stop_gradient(tf.constant(0.)) + b = tf.stop_gradient(2 * a) + g = tf.gradients(a + b, [a, b]) + ``` + + `stop_gradients` provides a way of stopping gradient after the graph has + already been constructed, as compared to `tf.stop_gradient` which is used + during graph construction. When the two approaches are combined, + backpropagation stops at both `tf.stop_gradient` nodes and nodes in + `stop_gradients`, whichever is encountered first. + + All integer tensors are considered constant with respect to all `xs`, as if + they were included in `stop_gradients`. + + `unconnected_gradients` determines the value returned for each x in xs if it + is unconnected in the graph to ys. By default this is None to safeguard + against errors. MAthematically these gradients are zero which can be requested + using the `'zero'` option. `tf.UnconnectedGradients` provides the + following options and behaviors: + + ```python + a = tf.ones([1, 2]) + b = tf.ones([3, 1]) + g1 = tf.gradients([b], [a], unnconnected_gradients='none') + sess.run(g1) # [None] + + g2 = tf.gradients([b], [a], unconnected_gradients='zero') + sess.run(g2) # [array([[0., 0.]], dtype=float32)] + ``` + + + Args: + ys: A `Tensor` or list of tensors to be differentiated. + xs: A `Tensor` or list of tensors to be used for differentiation. + grad_ys: Optional. A `Tensor` or list of tensors the same size as + `ys` and holding the gradients computed for each y in `ys`. + name: Optional name to use for grouping all the gradient ops together. + defaults to 'gradients'. + gate_gradients: If True, add a tuple around the gradients returned + for an operations. This avoids some race conditions. + aggregation_method: Specifies the method used to combine gradient terms. + Accepted values are constants defined in the class `AggregationMethod`. + stop_gradients: Optional. A `Tensor` or list of tensors not to differentiate + through. + unconnected_gradients: Optional. Specifies the gradient value returned when + the given input tensors are unconnected. Accepted values are constants + defined in the class `tf.UnconnectedGradients` and the default value is + `none`. + + Returns: + A list of `sum(dy/dx)` for each x in `xs`. + + Raises: + LookupError: if one of the operations between `x` and `y` does not + have a registered gradient function. + ValueError: if the arguments are invalid. + RuntimeError: if called in Eager mode. + + """ + # Creating the gradient graph for control flow mutates Operations. + # _mutation_lock ensures a Session.run call cannot occur between creating and + # mutating new ops. + with ops.get_default_graph()._mutation_lock(): # pylint: disable=protected-access + return _GradientsHelper(ys, xs, grad_ys, name, True, gate_gradients, + aggregation_method, stop_gradients, + unconnected_gradients) + + def _GradientsHelper(ys, xs, grad_ys=None, diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index a380b0d99f..a48095eb91 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -686,7 +686,7 @@ tf_module { } member_method { name: "gradients" - argspec: "args=[\'ys\', \'xs\', \'grad_ys\', \'name\', \'colocate_gradients_with_ops\', \'gate_gradients\', \'aggregation_method\', \'stop_gradients\', \'unconnected_gradients\'], varargs=None, keywords=None, defaults=[\'None\', \'gradients\', \'False\', \'False\', \'None\', \'None\', \'UnconnectedGradients.NONE\'], " + argspec: "args=[\'ys\', \'xs\', \'grad_ys\', \'name\', \'gate_gradients\', \'aggregation_method\', \'stop_gradients\', \'unconnected_gradients\'], varargs=None, keywords=None, defaults=[\'None\', \'gradients\', \'False\', \'None\', \'None\', \'UnconnectedGradients.NONE\'], " } member_method { name: "greater" diff --git a/tensorflow/tools/compatibility/ast_edits.py b/tensorflow/tools/compatibility/ast_edits.py index 56c67b8356..5edb4d4759 100644 --- a/tensorflow/tools/compatibility/ast_edits.py +++ b/tensorflow/tools/compatibility/ast_edits.py @@ -209,11 +209,11 @@ class _ASTCallVisitor(ast.NodeVisitor): items = [] while not isinstance(curr, ast.Name): if not isinstance(curr, ast.Attribute): - return None + return None, None items.append(curr.attr) curr = curr.value items.append(curr.id) - return ".".join(reversed(items)) + return ".".join(reversed(items)), items[0] def _find_true_position(self, node): """Return correct line number and column offset for a given node. @@ -278,7 +278,7 @@ class _ASTCallVisitor(ast.NodeVisitor): """ # Find a simple attribute name path e.g. "tf.foo.bar" - full_name = self._get_attribute_full_path(node.func) + full_name, name = self._get_attribute_full_path(node.func) # Make sure the func is marked as being part of a call node.func.is_function_for_call = True @@ -286,6 +286,9 @@ class _ASTCallVisitor(ast.NodeVisitor): if full_name: # Call special handlers function_handles = self._api_change_spec.function_handle + glob_name = "*.{}".format(name) + if glob_name in function_handles: + function_handles[glob_name](self._file_edit, node) if full_name in function_handles: function_handles[full_name](self._file_edit, node) @@ -358,7 +361,7 @@ class _ASTCallVisitor(ast.NodeVisitor): Args: node: Node that is of type ast.Attribute """ - full_name = self._get_attribute_full_path(node) + full_name, _ = self._get_attribute_full_path(node) if full_name: self._rename_functions(node, full_name) self._print_warning_for_function(node, full_name) diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 178521f6b3..3588db395e 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -561,6 +561,10 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # Specially handled functions. self.function_handle = { "tf.nn.dropout": self._dropout_handler, + "tf.gradients": self._colocate_handler("tf.gradients"), + "*.minimize": self._colocate_handler("Optimizer.minimize"), + "*.compute_gradients": + self._colocate_handler("Optimizer.compute_gradients"), } decay_function_comment = ( @@ -693,6 +697,26 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "", "1 - ") + @staticmethod + def _colocate_handler(name): + def _helper(file_edit_recorder, node): + for keyword in node.keywords: + if keyword.arg == "colocate_gradients_with_ops": + # TODO(jhseu): Since ast_edit.py does string replacement, there's no + # straightforward way to remove the argument. Try to fix before 2.0 is + # final. + comment = ("For tf.gradients and tf.Optimizer.minimize, " + "colocate_gradients_with_op has been removed and now " + "defaults to True.") + file_edit_recorder.add( + comment, + node.lineno, + node.col_offset, + "", + "", + error="{} requires manual check.".format(name)) + return _helper + if __name__ == "__main__": parser = argparse.ArgumentParser( diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index 65d77a2c9a..bda748f274 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -178,6 +178,40 @@ class TestUpgrade(test_util.TensorFlowTestCase): ) self.assertEqual(new_text, expected_text) + def testColocateGradientsWithOps(self): + text = "tf.gradients(a, foo=False)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(text, new_text) + self.assertEqual(errors, []) + + text = "tf.gradients(a, colocate_gradients_with_ops=False)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(text, new_text) + self.assertEqual(errors, ["test.py:1: tf.gradients requires manual check."]) + + text = "optimizer.minimize(a, foo=False)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(text, new_text) + self.assertEqual(errors, []) + + text = "optimizer.minimize(a, colocate_gradients_with_ops=False)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(text, new_text) + self.assertEqual(errors, + ["test.py:1: Optimizer.minimize requires manual check."]) + + text = "optimizer.compute_gradients(a, foo=False)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(text, new_text) + self.assertEqual(errors, []) + + text = "optimizer.compute_gradients(a, colocate_gradients_with_ops=False)\n" + _, unused_report, errors, new_text = self._upgrade(text) + self.assertEqual(text, new_text) + self.assertEqual(errors, + ["test.py:1: Optimizer.compute_gradients " + "requires manual check."]) + class TestUpgradeFiles(test_util.TensorFlowTestCase): -- GitLab From 6d3d0de39f3eaecdbf7fbdb52a7a02b2539efeeb Mon Sep 17 00:00:00 2001 From: qiezi Date: Tue, 27 Nov 2018 11:18:09 +0800 Subject: [PATCH 372/672] #23987: LARSOptimizer initializes _learning_rate_tensor and _momentum_tensor in _prepare method --- .../contrib/opt/python/training/lars_optimizer.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tensorflow/contrib/opt/python/training/lars_optimizer.py b/tensorflow/contrib/opt/python/training/lars_optimizer.py index a8dafd9a4c..205d6c3949 100644 --- a/tensorflow/contrib/opt/python/training/lars_optimizer.py +++ b/tensorflow/contrib/opt/python/training/lars_optimizer.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import linalg_ops from tensorflow.python.ops import math_ops @@ -162,3 +163,14 @@ class LARSOptimizer(optimizer.Optimizer): math_ops.cast(self._momentum_tensor, grad.dtype), use_locking=self._use_locking, use_nesterov=self._use_nesterov) + + def _prepare(self): + learning_rate = self._learning_rate + if callable(learning_rate): + learning_rate = learning_rate() + self._learning_rate_tensor = ops.convert_to_tensor(learning_rate, + name="learning_rate") + momentum = self._momentum + if callable(momentum): + momentum = momentum() + self._momentum_tensor = ops.convert_to_tensor(momentum, name="momentum") \ No newline at end of file -- GitLab From 82fd59f0e4ba87e6410002ee5017b411568a0060 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 19:37:28 -0800 Subject: [PATCH 373/672] Add vmodule support to TF OSS logging. Setting the environment variable TF_CPP_VMODULE=foo=7,bar=7 will cause the "foo" and "bar" translation units (foo.{h.cc},bar.{h.cc}) to have a VLOG level of 7, meaning VLOG(0) to VLOG(7) in those translation units will be logged to stderr (as LOG(ERROR) does). PiperOrigin-RevId: 222927031 --- tensorflow/core/BUILD | 2 + tensorflow/core/platform/default/logging.cc | 119 +++++++++++++++++--- tensorflow/core/platform/default/logging.h | 44 ++++++-- 3 files changed, 143 insertions(+), 22 deletions(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index bd5bbaa310..437c368356 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -3428,6 +3428,8 @@ tf_cc_tests( "platform/profile_utils/cpu_utils_test.cc", "platform/stacktrace_handler_test.cc", "platform/subprocess_test.cc", + "platform/vmodule_benchmark_test.cc", + "platform/vmodule_test.cc", ], deps = [ ":lib", diff --git a/tensorflow/core/platform/default/logging.cc b/tensorflow/core/platform/default/logging.cc index 133ae45a55..26bd8542fd 100644 --- a/tensorflow/core/platform/default/logging.cc +++ b/tensorflow/core/platform/default/logging.cc @@ -21,18 +21,18 @@ limitations under the License. #include #include #include -#include #endif #include +#include #include +#include +#include + namespace tensorflow { namespace internal { -LogMessage::LogMessage(const char* fname, int line, int severity) - : fname_(fname), line_(line), severity_(severity) {} - #if defined(PLATFORM_POSIX_ANDROID) void LogMessage::GenerateLogMessage() { int android_log_level; @@ -94,24 +94,90 @@ void LogMessage::GenerateLogMessage() { namespace { +int ParseInteger(const char* str, size_t size) { + // Ideally we would use env_var / safe_strto64, but it is + // hard to use here without pulling in a lot of dependencies, + // so we use std:istringstream instead + string integer_str(str, size); + std::istringstream ss(integer_str); + int level = 0; + ss >> level; + return level; +} + // Parse log level (int64) from environment variable (char*) int64 LogLevelStrToInt(const char* tf_env_var_val) { if (tf_env_var_val == nullptr) { return 0; } + return ParseInteger(tf_env_var_val, strlen(tf_env_var_val)); +} - // Ideally we would use env_var / safe_strto64, but it is - // hard to use here without pulling in a lot of dependencies, - // so we use std:istringstream instead - string min_log_level(tf_env_var_val); - std::istringstream ss(min_log_level); - int64 level; - if (!(ss >> level)) { - // Invalid vlog level setting, set level to default (0) - level = 0; +// Using StringPiece breaks Windows build. +struct StringData { + struct Hasher { + size_t operator()(const StringData& sdata) const { + // For dependency reasons, we cannot use hash.h here. Use DBJHash instead. + size_t hash = 5381; + const char* data = sdata.data; + for (const char* top = data + sdata.size; data < top; ++data) { + hash = ((hash << 5) + hash) + (*data); + } + return hash; + } + }; + + StringData() = default; + StringData(const char* data, size_t size) : data(data), size(size) {} + + bool operator==(const StringData& rhs) const { + return size == rhs.size && memcmp(data, rhs.data, size) == 0; } - return level; + const char* data = nullptr; + size_t size = 0; +}; + +using VmoduleMap = std::unordered_map; + +// Returns a mapping from module name to VLOG level, derived from the +// TF_CPP_VMOUDLE environment variable; ownership is transferred to the caller. +VmoduleMap* VmodulesMapFromEnv() { + // The value of the env var is supposed to be of the form: + // "foo=1,bar=2,baz=3" + const char* env = getenv("TF_CPP_VMODULE"); + if (env == nullptr) { + // If there is no TF_CPP_VMODULE configuration (most common case), return + // nullptr so that the ShouldVlogModule() API can fast bail out of it. + return nullptr; + } + // The memory returned by getenv() can be invalidated by following getenv() or + // setenv() calls. And since we keep references to it in the VmoduleMap in + // form of StringData objects, make a copy of it. + const char* env_data = strdup(env); + VmoduleMap* result = new VmoduleMap(); + while (true) { + const char* eq = strchr(env_data, '='); + if (eq == nullptr) { + break; + } + const char* after_eq = eq + 1; + + // Comma either points at the next comma delimiter, or at a null terminator. + // We check that the integer we parse ends at this delimiter. + const char* comma = strchr(after_eq, ','); + const char* new_env_data; + if (comma == nullptr) { + comma = strchr(after_eq, '\0'); + new_env_data = comma; + } else { + new_env_data = comma + 1; + } + (*result)[StringData(env_data, eq - env_data)] = + ParseInteger(after_eq, comma - after_eq); + env_data = new_env_data; + } + return result; } } // namespace @@ -146,10 +212,15 @@ int64 MinVLogLevelFromEnv() { #endif } +LogMessage::LogMessage(const char* fname, int line, int severity) + : fname_(fname), line_(line), severity_(severity) {} + LogMessage::~LogMessage() { // Read the min log level once during the first call to logging. static int64 min_log_level = MinLogLevelFromEnv(); - if (TF_PREDICT_TRUE(severity_ >= min_log_level)) GenerateLogMessage(); + if (severity_ >= min_log_level) { + GenerateLogMessage(); + } } int64 LogMessage::MinVLogLevel() { @@ -157,6 +228,24 @@ int64 LogMessage::MinVLogLevel() { return min_vlog_level; } +bool LogMessage::VmoduleActivated(const char* fname, int level) { + if (level <= MinVLogLevel()) { + return true; + } + static VmoduleMap* vmodules = VmodulesMapFromEnv(); + if (TF_PREDICT_TRUE(vmodules == nullptr)) { + return false; + } + const char* last_slash = strrchr(fname, '/'); + const char* module_start = last_slash == nullptr ? fname : last_slash + 1; + const char* dot_after = strchr(module_start, '.'); + const char* module_limit = + dot_after == nullptr ? strchr(fname, '\0') : dot_after; + StringData module(module_start, module_limit - module_start); + auto it = vmodules->find(module); + return it != vmodules->end() && it->second >= level; +} + LogMessageFatal::LogMessageFatal(const char* file, int line) : LogMessage(file, line, FATAL) {} LogMessageFatal::~LogMessageFatal() { diff --git a/tensorflow/core/platform/default/logging.h b/tensorflow/core/platform/default/logging.h index 08a692fff7..bb8735ed32 100644 --- a/tensorflow/core/platform/default/logging.h +++ b/tensorflow/core/platform/default/logging.h @@ -46,6 +46,17 @@ class LogMessage : public std::basic_ostringstream { // but VLOG(3) will not. Defaults to 0. static int64 MinVLogLevel(); + // Returns whether VLOG level lvl is activated for the file fname. + // + // E.g. if the environment variable TF_CPP_VMODULE contains foo=3 and fname is + // foo.cc and lvl is <= 3, this will return true. It will also return true if + // the level is lower or equal to TF_CPP_MIN_VLOG_LEVEL (default zero). + // + // It is expected that the result of this query will be cached in the VLOG-ing + // call site to avoid repeated lookups. This routine performs a hash-map + // access against the VLOG-ing specification provided by the env var. + static bool VmoduleActivated(const char* fname, int level); + protected: void GenerateLogMessage(); @@ -55,6 +66,13 @@ class LogMessage : public std::basic_ostringstream { int severity_; }; +// Uses the lower operator & precedence to voidify a LogMessage reference, so +// that the ternary VLOG() implementation is balanced, type wise. +struct Voidifier { + template + void operator&(const T&)const {} +}; + // LogMessageFatal ensures the process will exit in failure after // logging this message. class LogMessageFatal : public LogMessage { @@ -77,18 +95,30 @@ class LogMessageFatal : public LogMessage { #define LOG(severity) _TF_LOG_##severity #ifdef IS_MOBILE_PLATFORM + // Turn VLOG off when under mobile devices for considerations of binary size. #define VLOG_IS_ON(lvl) ((lvl) <= 0) + #else -// Otherwise, Set TF_CPP_MIN_VLOG_LEVEL environment to update minimum log level -// of VLOG -#define VLOG_IS_ON(lvl) \ - ((lvl) <= ::tensorflow::internal::LogMessage::MinVLogLevel()) + +// Otherwise, set TF_CPP_MIN_VLOG_LEVEL environment to update minimum log level +// of VLOG, or TF_CPP_VMODULE to set the minimum log level for individual +// translation units. +#define VLOG_IS_ON(lvl) \ + (([](int level, const char* fname) { \ + static const bool vmodule_activated = \ + ::tensorflow::internal::LogMessage::VmoduleActivated(fname, level); \ + return vmodule_activated; \ + })(lvl, __FILE__)) + #endif -#define VLOG(lvl) \ - if (TF_PREDICT_FALSE(VLOG_IS_ON(lvl))) \ - ::tensorflow::internal::LogMessage(__FILE__, __LINE__, tensorflow::INFO) +#define VLOG(level) \ + TF_PREDICT_TRUE(!VLOG_IS_ON(level)) \ + ? (void)0 \ + : ::tensorflow::internal::Voidifier() & \ + ::tensorflow::internal::LogMessage(__FILE__, __LINE__, \ + tensorflow::INFO) // CHECK dies with a fatal error if condition is not true. It is *not* // controlled by NDEBUG, so the check will be executed regardless of -- GitLab From 2d3c95d36766bd47a5df98ab07bf870c97758149 Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Mon, 26 Nov 2018 20:06:56 -0800 Subject: [PATCH 374/672] [tf.data] Moving Unbatch benchmarks with others benchmarks. PiperOrigin-RevId: 222929316 --- .../python/data/experimental/benchmarks/BUILD | 40 +++++-- .../benchmarks/unbatch_benchmark.py | 107 ++++++++++++++++++ .../experimental/kernel_tests/unbatch_test.py | 75 ------------ 3 files changed, 135 insertions(+), 87 deletions(-) create mode 100644 tensorflow/python/data/experimental/benchmarks/unbatch_benchmark.py diff --git a/tensorflow/python/data/experimental/benchmarks/BUILD b/tensorflow/python/data/experimental/benchmarks/BUILD index 075863d34f..8175116c6e 100644 --- a/tensorflow/python/data/experimental/benchmarks/BUILD +++ b/tensorflow/python/data/experimental/benchmarks/BUILD @@ -7,6 +7,21 @@ exports_files(["LICENSE"]) load("//tensorflow:tensorflow.bzl", "cuda_py_test") load("//tensorflow:tensorflow.bzl", "py_test") +py_test( + name = "autotune_benchmark", + srcs = ["autotune_benchmark.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:client_testlib", + "//tensorflow/python:math_ops", + "//tensorflow/python:session", + "//tensorflow/python/data/experimental/ops:batching", + "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python/data/ops:dataset_ops", + "//third_party/py/numpy", + ], +) + py_test( name = "csv_dataset_benchmark", srcs = ["csv_dataset_benchmark.py"], @@ -63,15 +78,17 @@ py_test( ) py_test( - name = "autotune_benchmark", - srcs = ["autotune_benchmark.py"], + name = "matching_files_benchmark", + size = "small", + srcs = ["matching_files_benchmark.py"], srcs_version = "PY2AND3", deps = [ + "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", - "//tensorflow/python:math_ops", - "//tensorflow/python:session", - "//tensorflow/python/data/experimental/ops:batching", - "//tensorflow/python/data/experimental/ops:optimization", + "//tensorflow/python:dtypes", + "//tensorflow/python:errors", + "//tensorflow/python:util", + "//tensorflow/python/data/experimental/ops:matching_files", "//tensorflow/python/data/ops:dataset_ops", "//third_party/py/numpy", ], @@ -92,17 +109,16 @@ py_test( ) py_test( - name = "matching_files_benchmark", - size = "small", - srcs = ["matching_files_benchmark.py"], + name = "unbatch_benchmark", + srcs = ["unbatch_benchmark.py"], srcs_version = "PY2AND3", deps = [ "//tensorflow/python:array_ops", "//tensorflow/python:client_testlib", "//tensorflow/python:dtypes", - "//tensorflow/python:errors", - "//tensorflow/python:util", - "//tensorflow/python/data/experimental/ops:matching_files", + "//tensorflow/python:framework_ops", + "//tensorflow/python:session", + "//tensorflow/python/data/experimental/ops:batching", "//tensorflow/python/data/ops:dataset_ops", "//third_party/py/numpy", ], diff --git a/tensorflow/python/data/experimental/benchmarks/unbatch_benchmark.py b/tensorflow/python/data/experimental/benchmarks/unbatch_benchmark.py new file mode 100644 index 0000000000..c40d479823 --- /dev/null +++ b/tensorflow/python/data/experimental/benchmarks/unbatch_benchmark.py @@ -0,0 +1,107 @@ +# Copyright 2017 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for `tf.data.experimental.unbatch()`.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time + +import numpy as np + +from tensorflow.python.client import session +from tensorflow.python.data.experimental.ops import batching +from tensorflow.python.data.ops import dataset_ops +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.platform import test + + +class UnbatchBenchmark(test.Benchmark): + """Benchmarks for `tf.data.experimental.unbatch()`.""" + + def benchmarkNativeUnbatch(self): + batch_sizes = [1, 2, 5, 10, 20, 50] + elems_per_trial = 10000 + with ops.Graph().as_default(): + dataset = dataset_ops.Dataset.from_tensors("element").repeat(None) + batch_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) + dataset = dataset.batch(batch_size_placeholder) + dataset = dataset.apply(batching.unbatch()) + dataset = dataset.skip(elems_per_trial) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for batch_size in batch_sizes: + deltas = [] + for _ in range(5): + sess.run( + iterator.initializer, + feed_dict={batch_size_placeholder: batch_size}) + start = time.time() + sess.run(next_element.op) + end = time.time() + deltas.append((end - start) / elems_per_trial) + + median_wall_time = np.median(deltas) + print("Unbatch (native) batch size: %d Median wall time per element:" + " %f microseconds" % (batch_size, median_wall_time * 1e6)) + self.report_benchmark( + iters=10000, + wall_time=median_wall_time, + name="native_batch_size_%d" % + batch_size) + + # Include a benchmark of the previous `unbatch()` implementation that uses + # a composition of more primitive ops. Eventually we'd hope to generate code + # that is as good in both cases. + def benchmarkOldUnbatchImplementation(self): + batch_sizes = [1, 2, 5, 10, 20, 50] + elems_per_trial = 10000 + with ops.Graph().as_default(): + dataset = dataset_ops.Dataset.from_tensors("element").repeat(None) + batch_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) + dataset = dataset.batch(batch_size_placeholder) + dataset = dataset.flat_map(dataset_ops.Dataset.from_tensor_slices) + dataset = dataset.skip(elems_per_trial) + iterator = dataset.make_initializable_iterator() + next_element = iterator.get_next() + + with session.Session() as sess: + for batch_size in batch_sizes: + deltas = [] + for _ in range(5): + sess.run( + iterator.initializer, + feed_dict={batch_size_placeholder: batch_size}) + start = time.time() + sess.run(next_element.op) + end = time.time() + deltas.append((end - start) / elems_per_trial) + + median_wall_time = np.median(deltas) + print("Unbatch (unfused) batch size: %d Median wall time per element:" + " %f microseconds" % (batch_size, median_wall_time * 1e6)) + self.report_benchmark( + iters=10000, + wall_time=median_wall_time, + name="unfused_batch_size_%d" % + batch_size) + + +if __name__ == "__main__": + test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py index 0278a208cb..f9b800fe67 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py @@ -17,19 +17,16 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import time from absl.testing import parameterized import numpy as np -from tensorflow.python.client import session from tensorflow.python.data.experimental.ops import batching from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors -from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops @@ -224,77 +221,5 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(next_element) -class UnbatchBenchmark(test.Benchmark): - - def benchmarkNativeUnbatch(self): - batch_sizes = [1, 2, 5, 10, 20, 50] - elems_per_trial = 10000 - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors("element").repeat(None) - batch_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - dataset = dataset.batch(batch_size_placeholder) - dataset = dataset.apply(batching.unbatch()) - dataset = dataset.skip(elems_per_trial) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for batch_size in batch_sizes: - deltas = [] - for _ in range(5): - sess.run( - iterator.initializer, - feed_dict={batch_size_placeholder: batch_size}) - start = time.time() - sess.run(next_element.op) - end = time.time() - deltas.append((end - start) / elems_per_trial) - - median_wall_time = np.median(deltas) - print("Unbatch (native) batch size: %d Median wall time per element:" - " %f microseconds" % (batch_size, median_wall_time * 1e6)) - self.report_benchmark( - iters=10000, - wall_time=median_wall_time, - name="benchmark_unbatch_dataset_native_batch_size_%d" % - batch_size) - - # Include a benchmark of the previous `unbatch()` implementation that uses - # a composition of more primitive ops. Eventually we'd hope to generate code - # that is as good in both cases. - def benchmarkOldUnbatchImplementation(self): - batch_sizes = [1, 2, 5, 10, 20, 50] - elems_per_trial = 10000 - with ops.Graph().as_default(): - dataset = dataset_ops.Dataset.from_tensors("element").repeat(None) - batch_size_placeholder = array_ops.placeholder(dtypes.int64, shape=[]) - dataset = dataset.batch(batch_size_placeholder) - dataset = dataset.flat_map(dataset_ops.Dataset.from_tensor_slices) - dataset = dataset.skip(elems_per_trial) - iterator = dataset.make_initializable_iterator() - next_element = iterator.get_next() - - with session.Session() as sess: - for batch_size in batch_sizes: - deltas = [] - for _ in range(5): - sess.run( - iterator.initializer, - feed_dict={batch_size_placeholder: batch_size}) - start = time.time() - sess.run(next_element.op) - end = time.time() - deltas.append((end - start) / elems_per_trial) - - median_wall_time = np.median(deltas) - print("Unbatch (unfused) batch size: %d Median wall time per element:" - " %f microseconds" % (batch_size, median_wall_time * 1e6)) - self.report_benchmark( - iters=10000, - wall_time=median_wall_time, - name="benchmark_unbatch_dataset_unfused_batch_size_%d" % - batch_size) - - if __name__ == "__main__": test.main() -- GitLab From e0daeb19bde631543c0df691f37b06e2377a31fe Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 26 Nov 2018 20:28:44 -0800 Subject: [PATCH 375/672] Add data_format, rename Targmax for nn.max_pool_with_argmax for TF 2.0 PiperOrigin-RevId: 222930810 --- .../api_def_MaxPoolWithArgmax.pbtxt | 1 + tensorflow/python/ops/nn_ops.py | 61 +++++++++++++++++++ .../tools/api/golden/v2/tensorflow.nn.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 3 + 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/api_def/python_api/api_def_MaxPoolWithArgmax.pbtxt b/tensorflow/core/api_def/python_api/api_def_MaxPoolWithArgmax.pbtxt index 7d8abca5f1..13a1a0b5df 100644 --- a/tensorflow/core/api_def/python_api/api_def_MaxPoolWithArgmax.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_MaxPoolWithArgmax.pbtxt @@ -2,5 +2,6 @@ op { graph_op_name: "MaxPoolWithArgmax" endpoint { name: "nn.max_pool_with_argmax" + deprecation_version: 2 } } diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 5655960aae..2596f8e9bc 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -2675,6 +2675,67 @@ def max_pool(value, ksize, strides, padding, data_format="NHWC", name=None): name=name) +# pylint: disable=redefined-builtin +@tf_export("nn.max_pool_with_argmax", v1=[]) +def max_pool_with_argmax_v2(input, + ksize, + strides, + padding, + data_format="NHWC", + output_dtype=dtypes.int64, + name=None): + """Performs max pooling on the input and outputs both max values and indices. + + The indices in `argmax` are flattened, so that a maximum value at position + `[b, y, x, c]` becomes flattened index + `((b * height + y) * width + x) * channels + c`. + + The indices returned are always in `[0, height) x [0, width)` before + flattening, even if padding is involved and the mathematically correct answer + is outside (either negative or too large). This is a bug, but fixing it is + difficult to do in a safe backwards compatible way, especially due to + flattening. + + Args: + input: A `Tensor`. Must be one of the following types: `float32`, `float64`, + `int32`, `uint8`, `int16`, `int8`, `int64`, `bfloat16`, `uint16`, `half`, + `uint32`, `uint64`. + 4-D with shape `[batch, height, width, channels]`. Input to pool over. + ksize: A list of `ints` that has length `>= 4`. + The size of the window for each dimension of the input tensor. + strides: A list of `ints` that has length `>= 4`. + The stride of the sliding window for each dimension of the + input tensor. + padding: A `string` from: `"SAME", "VALID"`. + The type of padding algorithm to use. + data_format: An optional `string`, must be set to `"NHWC"`. Defaults to + `"NHWC"`. + Specify the data format of the input and output data. + output_dtype: An optional `tf.DType` from: `tf.int32, tf.int64`. + Defaults to `tf.int64`. + The dtype of the returned argmax tensor. + name: A name for the operation (optional). + + Returns: + A tuple of `Tensor` objects (output, argmax). + + output: A `Tensor`. Has the same type as `input`. + argmax: A `Tensor` of type `output_dtype`. + """ + + if data_format != "NHWC": + raise ValueError("Data formats other than 'NHWC' are not yet supported") + + return gen_nn_ops.max_pool_with_argmax(input=input, + ksize=ksize, + strides=strides, + padding=padding, + Targmax=output_dtype, + name=name) + +# pylint: enable=redefined-builtin + + @ops.RegisterStatistics("Conv2D", "flops") def _calc_conv_flops(graph, node): """Calculates the compute resources needed for Conv2D.""" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index 0bfea74e40..04b189784a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -206,7 +206,7 @@ tf_module { } member_method { name: "max_pool_with_argmax" - argspec: "args=[\'input\', \'ksize\', \'strides\', \'padding\', \'Targmax\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " + argspec: "args=[\'input\', \'ksize\', \'strides\', \'padding\', \'data_format\', \'output_dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'NHWC\', \"\", \'None\'], " } member_method { name: "moments" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 3588db395e..7433e0ecbf 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -77,6 +77,9 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.sparse.split": { "split_dim": "axis", }, + "tf.max_pool_with_argmax": { + "Targmax": "output_dtype", + }, "tf.multinomial": { "output_dtype": "dtype", }, -- GitLab From 4fbbeea283de57deb681699a93694871a297d286 Mon Sep 17 00:00:00 2001 From: Asim Shankar Date: Mon, 26 Nov 2018 22:11:19 -0800 Subject: [PATCH 376/672] [TensorRT]: Define a shape function. This will help address some of the issues encountered when using TensorRT using other language APIs. See context in #23853#issuecomment-441867084 PiperOrigin-RevId: 222937978 --- .../contrib/tensorrt/ops/trt_engine_op.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc b/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc index ce04e5806e..92405906eb 100644 --- a/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc +++ b/tensorflow/contrib/tensorrt/ops/trt_engine_op.cc @@ -16,6 +16,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT +#include "tensorflow/core/framework/common_shape_fns.h" #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/shape_inference.h" @@ -43,15 +44,15 @@ REGISTER_OP("TRTEngineOp") .Attr("calibration_data: string = ''") .Attr("use_calibration: bool = true") .Input("in_tensor: InT") - .Output("out_tensor: OutT"); -// TODO(jie): TF requires concrete output shape for concrete input shapes. -// This is tricky for batch dimension, since we cannot ensure which input -// would carry the correct batch dimension (for the current stage of the -// implementation, we do require all input tensor to carry the same batch -// size, but this could change in the future). Hence we disable shape -// inference function as a workaround. -// .SetShapeFn(shape_inference::TRTEngineOpShapeInference); - + .Output("out_tensor: OutT") + // TODO(jie): TF requires concrete output shape for concrete input shapes. + // This is tricky for batch dimension, since we cannot ensure which input + // would carry the correct batch dimension (for the current stage of the + // implementation, we do require all input tensor to carry the same batch + // size, but this could change in the future). Hence we disable shape + // inference function as a workaround. + // .SetShapeFn(shape_inference::TRTEngineOpShapeInference); + .SetShapeFn(shape_inference::UnknownShape); } // namespace tensorflow #endif // GOOGLE_TENSORRT -- GitLab From 1899ac3d56e578b2b685f883bd1455dd0717ee02 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Tue, 27 Nov 2018 00:52:48 -0800 Subject: [PATCH 377/672] Make use of the Iota function that gets passed a shape. This avoids manual broadcasts which are handled automatically by the Iota op. PiperOrigin-RevId: 222949991 --- .../tf2xla/kernels/conv_op_helpers.cc | 77 ++++++++++--------- .../tf2xla/kernels/matrix_band_part_op.cc | 9 ++- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc b/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc index b1046fcc00..641fefafb3 100644 --- a/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc +++ b/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc @@ -64,60 +64,63 @@ xla::Shape ExpandedFilterShapeForDepthwiseConvolution(const xla::Shape& shape) { // 0 0 1 1 0 0 0 0 1 1 0 0 // 0 0 0 0 1 1 0 0 0 0 1 1 // -// The first step is to create a one tensor, A, that is [3] -// 0 1 2 +// The first step is to create a iota A with iota_dimension = 2 +// 0 0 0 0 0 0 0 0 0 0 0 0 +// 1 1 1 1 1 1 1 1 1 1 1 1 +// 2 2 2 2 2 2 2 2 2 2 2 2 // -// and another tensor, B, that is [3 * 2] -// 0 1 2 3 4 5 +// 0 0 0 0 0 0 0 0 0 0 0 0 +// 1 1 1 1 1 1 1 1 1 1 1 1 +// 2 2 2 2 2 2 2 2 2 2 2 2 // -// and divide B it by 2 to get -// 0 0 1 1 2 2 +// and another iota B with iota_dimension = 3 +// 0 1 2 3 4 5 0 1 2 3 4 5 +// 0 1 2 3 4 5 0 1 2 3 4 5 +// 0 1 2 3 4 5 0 1 2 3 4 5 // -// then we broadcast the B to [2, 2, 3, 3 * 2] -// 0 0 1 1 2 2 0 0 1 1 2 2 -// 0 0 1 1 2 2 0 0 1 1 2 2 -// 0 0 1 1 2 2 0 0 1 1 2 2 +// 0 1 2 3 4 5 0 1 2 3 4 5 +// 0 1 2 3 4 5 0 1 2 3 4 5 +// 0 1 2 3 4 5 0 1 2 3 4 5 // -// 0 0 1 1 2 2 0 0 1 1 2 2 -// 0 0 1 1 2 2 0 0 1 1 2 2 -// 0 0 1 1 2 2 0 0 1 1 2 2 +// and divide B by 2 to get +// 0 0 1 1 2 2 0 0 1 1 2 2 +// 0 0 1 1 2 2 0 0 1 1 2 2 +// 0 0 1 1 2 2 0 0 1 1 2 2 // -// Finally compare A and broadcasted B in dimension 2 amd return the result at -// the beginning of the comment. +// 0 0 1 1 2 2 0 0 1 1 2 2 +// 0 0 1 1 2 2 0 0 1 1 2 2 +// 0 0 1 1 2 2 0 0 1 1 2 2 +// +// Finally compare A and B and return the result at the beginning of the +// comment. xla::XlaOp CreateExpandedFilterMask(const xla::Shape& filter_shape, xla::XlaBuilder* builder) { xla::Shape expanded_filter_shape = ExpandedFilterShapeForDepthwiseConvolution(filter_shape); int64 depthwise_multiplier = filter_shape.dimensions(filter_shape.dimensions_size() - 1); - int64 input_feature = - filter_shape.dimensions(filter_shape.dimensions_size() - 2); - - // Create a M sized linspace and an M*N sized linspace that will be - // broadcasted into perpendicular dimensions and compared. - xla::XlaOp input_feature_iota = xla::Iota(builder, xla::S32, input_feature); - xla::XlaOp expanded_feature_iota = - xla::Iota(builder, xla::S32, input_feature * depthwise_multiplier); - // Divide the M*N sized linspace by the depthwise_multiplier to create - // [0 0 1 1 2 2] in the example in the function comment. + // Create two iotas with the shape of the expanded filter, one of them with + // the iota dimension chosen as the feature dimension, and the other a iota + // with the iota dimension chosen as the expanded output feature dimension. + std::vector iota_dimensions(expanded_filter_shape.dimensions().begin(), + expanded_filter_shape.dimensions().end()); + xla::Shape iota_shape = xla::ShapeUtil::MakeShape(xla::S32, iota_dimensions); + xla::XlaOp input_feature_iota = xla::Iota( + builder, iota_shape, /*iota_dimension=*/iota_dimensions.size() - 2); + xla::XlaOp expanded_feature_iota = xla::Iota( + builder, iota_shape, /*iota_dimension=*/iota_dimensions.size() - 1); + + // Divide 'expanded_feature_iota' by the depthwise_multiplier to create + // [0 0 1 1 2 2] ... in the example in the function comment. expanded_feature_iota = xla::Div(expanded_feature_iota, XlaHelpers::IntegerLiteral(builder, DataType::DT_INT32, depthwise_multiplier)); - // Broadcast the N*M linspace to [H, W, ..., M, M*N]. - std::vector expanded_feature_broadcast_dims( - expanded_filter_shape.dimensions().begin(), - expanded_filter_shape.dimensions().end()); - expanded_feature_broadcast_dims.pop_back(); - auto broadcasted_expanded_feature_iota = - xla::Broadcast(expanded_feature_iota, expanded_feature_broadcast_dims); - - // Compare the broadcasted linspace to the input feature linspace in the - // input feature dimension to create a diagonal predicate. - return xla::Eq(broadcasted_expanded_feature_iota, input_feature_iota, - {expanded_filter_shape.dimensions_size() - 2}); + // Compare 'input_feature_iota' with 'expanded_feature_iota' to create a + // diagonal predicate. + return xla::Eq(expanded_feature_iota, input_feature_iota); } // Reshapes a filter of shape [H, W, ..., M, N] to [H, W, ..., 1, M*N]. Used to diff --git a/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc b/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc index a99b74565d..2dd0a710e4 100644 --- a/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc @@ -17,6 +17,7 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_kernel.h" #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/xla_builder.h" +#include "tensorflow/compiler/xla/shape_util.h" #include "tensorflow/core/framework/tensor_shape.h" namespace tensorflow { @@ -60,11 +61,11 @@ class MatrixBandPartOp : public XlaOpKernel { // Compute 'offset', which is how many diagonals we are above/below the // diagonal. - xla::XlaOp iota_m = xla::Iota(builder, index_xla_type, m); - xla::XlaOp iota_n = xla::Iota(builder, index_xla_type, n); + xla::Shape iota_shape = xla::ShapeUtil::MakeShape(index_xla_type, {m, n}); + xla::XlaOp iota_m = xla::Iota(builder, iota_shape, /*iota_dimension=*/0); + xla::XlaOp iota_n = xla::Iota(builder, iota_shape, /*iota_dimension=*/1); - auto offset = xla::Sub(xla::Broadcast(iota_n, {m}), iota_m, - /*broadcast_dimensions=*/{0}); + auto offset = xla::Sub(iota_n, iota_m); // If num_lower or num_upper are negative, include all lower/upper // diagonals. -- GitLab From ac167c39b44c3255848f671bfcece4fb50b264a9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 01:02:58 -0800 Subject: [PATCH 378/672] compat: Update forward compatibility horizon to 2018-11-27 PiperOrigin-RevId: 222951259 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 4e84b5ee48..cb359cd084 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 26) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 27) @tf_export("compat.forward_compatible") -- GitLab From b5b6628931a2db98a94c55e90c0df5db5cb4fa5b Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Tue, 27 Nov 2018 02:54:53 -0800 Subject: [PATCH 379/672] Replaced deprecated tf.create_partitioned_variables with tf.get_variable PiperOrigin-RevId: 222963167 --- .../python/layers/embedding_ops_test.py | 51 ++++++++++------- .../contrib/tpu/python/tpu/tpu_embedding.py | 11 ++-- .../python/kernel_tests/embedding_ops_test.py | 10 ++-- .../saver_large_partitioned_variable_test.py | 9 ++- tensorflow/python/training/saver_test.py | 56 ++++++------------- 5 files changed, 66 insertions(+), 71 deletions(-) diff --git a/tensorflow/contrib/layers/python/layers/embedding_ops_test.py b/tensorflow/contrib/layers/python/layers/embedding_ops_test.py index 8015a571e1..295c721fce 100644 --- a/tensorflow/contrib/layers/python/layers/embedding_ops_test.py +++ b/tensorflow/contrib/layers/python/layers/embedding_ops_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import itertools import math +import sys import numpy as np @@ -36,6 +37,7 @@ from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import init_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import partitioned_variables +from tensorflow.python.ops import variable_scope from tensorflow.python.platform import test from tensorflow.python.util import compat @@ -48,11 +50,13 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): assert num_shards > 0 assert num_shards <= vocab_size - embedding_weights = partitioned_variables.create_partitioned_variables( + initializer = init_ops.truncated_normal_initializer( + mean=0.0, stddev=1.0 / math.sqrt(vocab_size), dtype=dtypes.float32) + embedding_weights = list(variable_scope.get_variable( + "embedding_weights", shape=[vocab_size, embed_dim], - slicing=[num_shards, 1], - initializer=init_ops.truncated_normal_initializer( - mean=0.0, stddev=1.0 / math.sqrt(vocab_size), dtype=dtypes.float32)) + partitioner=partitioned_variables.fixed_size_partitioner(num_shards), + initializer=initializer)) for w in embedding_weights: w.initializer.run() embedding_weights = [w.eval() for w in embedding_weights] @@ -256,6 +260,13 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): embedding_weights, sparse_ids, sparse_weights) +# pylint: disable=invalid-name +def local_variable_scope(): + """Create a variable scope named like the caller function.""" + return variable_scope.variable_scope(sys._getframe(1).f_code.co_name) +# pylint: enable=invalid-name + + class ScatteredEmbeddingLookupTest(test.TestCase): def setUp(self): @@ -266,17 +277,18 @@ class ScatteredEmbeddingLookupTest(test.TestCase): assert num_shards > 0 assert num_shards <= size - embedding_weights = partitioned_variables.create_partitioned_variables( + embedding_weights = list(variable_scope.get_variable( + "embedding_weights", shape=[size], - slicing=[num_shards], + partitioner=partitioned_variables.fixed_size_partitioner(num_shards), initializer=init_ops.truncated_normal_initializer( - mean=0.0, stddev=1.0, dtype=dtypes.float32)) + mean=0.0, stddev=1.0, dtype=dtypes.float32))) for w in embedding_weights: w.initializer.run() return embedding_weights def test_scattered_embedding_consistency(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedding_weights = self._random_weights() values = constant_op.constant(["foo", "foo"]) @@ -288,7 +300,7 @@ class ScatteredEmbeddingLookupTest(test.TestCase): embedding_lookup_result[1]) def test_scattered_embedding_multiple_partition(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedding_weights = self._random_weights(num_shards=7) values = constant_op.constant([4, 4, 5]) @@ -304,7 +316,7 @@ class ScatteredEmbeddingLookupTest(test.TestCase): self.assertGreater(embedding_diff, 0) def test_scattered_embedding_coverage(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): size = 8 embedding_weights = self._random_weights(size=size, num_shards=3) values = constant_op.constant(["foo"]) @@ -316,7 +328,7 @@ class ScatteredEmbeddingLookupTest(test.TestCase): self.assertEqual(len(np.unique(embedding_lookup_result[0])), size) def test_scattered_embedding_multi_dimension(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedding_weights = self._random_weights() values = constant_op.constant([["foo", "bar", "bar"], ["bar", "bar", "foo"]]) @@ -329,7 +341,7 @@ class ScatteredEmbeddingLookupTest(test.TestCase): embedding_lookup_result[1][2]) def test_scattered_embedding_lookup_sparse(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedding_weights = self._random_weights(num_shards=3) sparse_tensor = sparse_tensor_lib.SparseTensor( values=["foo", "bar", "foo", "bar"], @@ -358,7 +370,7 @@ class ScatteredEmbeddingLookupTest(test.TestCase): embeds = np.random.randn(n_embed, d_embed) idx = np.random.randint(0, n_embed, idx_shape) - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedded_np = embeds[idx] embedded_tf = embedding_ops.embedding_lookup_unique(embeds, idx).eval() @@ -370,7 +382,7 @@ class ScatteredEmbeddingLookupTest(test.TestCase): idx = np.random.randint(0, 5, 10) idx2d = np.random.randint(0, 5, (10, 2)) - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedded_np = embeds[idx] embedded_np2d = embeds[idx2d] embedded_tf = embedding_ops.embedding_lookup_unique(embeds, idx).eval() @@ -398,17 +410,18 @@ class SampledScatteredEmbeddingLookupTest(test.TestCase): assert num_shards > 0 assert num_shards <= size - embedding_weights = partitioned_variables.create_partitioned_variables( + embedding_weights = list(variable_scope.get_variable( + "embedding_weights", shape=[size], - slicing=[num_shards], + partitioner=partitioned_variables.fixed_size_partitioner(num_shards), initializer=init_ops.truncated_normal_initializer( - mean=0.0, stddev=1.0, dtype=dtypes.float32)) + mean=0.0, stddev=1.0, dtype=dtypes.float32))) for w in embedding_weights: w.initializer.run() return embedding_weights def test_hashed_embedding_consistency(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedding_weights = self._random_weights() values = constant_op.constant(["foo", "foo"]) # The first three sampled_candidates are equal, so the first three @@ -429,7 +442,7 @@ class SampledScatteredEmbeddingLookupTest(test.TestCase): embedding_lookup_result[1][3]) def test_hashed_embedding_multi_dimension(self): - with self.cached_session(): + with self.cached_session(), local_variable_scope(): embedding_weights = self._random_weights() values = constant_op.constant([["foo", "bar", "bar"], ["bar", "bar", "foo"]]) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_embedding.py b/tensorflow/contrib/tpu/python/tpu/tpu_embedding.py index 3fe896426a..ccba8a46c7 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_embedding.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_embedding.py @@ -1069,17 +1069,14 @@ def _create_partitioned_variables(name, 'As TPU embedding is not optimized for small tables, ' 'please consider other ways for this embedding lookup.') - slicing = [num_hosts, 1] - - # TODO(shizhiw): deprecated, use tf.get_variable()? - return partitioned_variables.create_partitioned_variables( - name=name, - slicing=slicing, + return list(variable_scope.get_variable( + name, shape=(vocabulary_size, embedding_dimension), + partitioner=partitioned_variables.fixed_size_partitioner(num_hosts), dtype=dtypes.float32, initializer=initializer, collections=collections, - trainable=False) + trainable=False)) @ops.RegisterGradient('TPUEmbeddingActivations') diff --git a/tensorflow/python/kernel_tests/embedding_ops_test.py b/tensorflow/python/kernel_tests/embedding_ops_test.py index 443f54a958..dba3409c9e 100644 --- a/tensorflow/python/kernel_tests/embedding_ops_test.py +++ b/tensorflow/python/kernel_tests/embedding_ops_test.py @@ -758,11 +758,13 @@ class SafeEmbeddingLookupSparseTest(test.TestCase): assert num_shards > 0 assert num_shards <= vocab_size - embedding_weights = partitioned_variables.create_partitioned_variables( + initializer = init_ops.truncated_normal_initializer( + mean=0.0, stddev=1.0 / math.sqrt(vocab_size), dtype=dtypes.float32) + embedding_weights = list(variable_scope.get_variable( + name="embedding_weights", shape=[vocab_size, embed_dim], - slicing=[num_shards, 1], - initializer=init_ops.truncated_normal_initializer( - mean=0.0, stddev=1.0 / math.sqrt(vocab_size), dtype=dtypes.float32)) + partitioner=partitioned_variables.fixed_size_partitioner(num_shards), + initializer=initializer)) for w in embedding_weights: w.initializer.run() embedding_weights = [w.eval() for w in embedding_weights] diff --git a/tensorflow/python/training/saver_large_partitioned_variable_test.py b/tensorflow/python/training/saver_large_partitioned_variable_test.py index 1a44511cfe..84458836d0 100644 --- a/tensorflow/python/training/saver_large_partitioned_variable_test.py +++ b/tensorflow/python/training/saver_large_partitioned_variable_test.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import partitioned_variables +from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.training import saver @@ -44,8 +45,12 @@ class SaverLargePartitionedVariableTest(test.TestCase): # split into smaller sized variables. init = lambda shape, dtype, partition_info: constant_op.constant( True, dtype, shape) - partitioned_var = partitioned_variables.create_partitioned_variables( - [1 << 31], [4], init, dtype=dtypes.bool, name=var_name) + partitioned_var = list(variable_scope.get_variable( + var_name, + shape=[1 << 31], + partitioner=partitioned_variables.fixed_size_partitioner(4), + initializer=init, + dtype=dtypes.bool)) variables.global_variables_initializer().run() save = saver.Saver(partitioned_var) val = save.save(sess, save_path) diff --git a/tensorflow/python/training/saver_test.py b/tensorflow/python/training/saver_test.py index eb2690985d..be49e6e715 100644 --- a/tensorflow/python/training/saver_test.py +++ b/tensorflow/python/training/saver_test.py @@ -998,19 +998,12 @@ class SaveRestoreShardedTest(test.TestCase): call_saver_with_dict = False # updated by test loop below - def _save(slices=None, partitioner=None): + def _save(partitioner=None): with self.session(graph=ops_lib.Graph()) as sess: # Calls .eval() to return the ndarray that makes up the full variable. rnd = random_ops.random_uniform(var_full_shape).eval() - if slices: - assert not partitioner - # TODO(apassos): make create_partitioned_variables take use_resource - # option to make this test passable without creating a named - # variable_scope. - vs = partitioned_variables.create_partitioned_variables( - var_full_shape, slices, rnd, name=var_name) - elif partitioner: + if partitioner: vs = [ variable_scope.get_variable( var_name, @@ -1027,7 +1020,7 @@ class SaveRestoreShardedTest(test.TestCase): variables.global_variables_initializer().run() if call_saver_with_dict: - saver = saver_module.Saver({var_name: (vs if slices else vs[0])}) + saver = saver_module.Saver({var_name: vs[0]}) else: saver = saver_module.Saver(vs) actual_path = saver.save(sess, saved_path) @@ -1035,16 +1028,9 @@ class SaveRestoreShardedTest(test.TestCase): return rnd - def _restore(slices=None, partitioner=None): + def _restore(partitioner=None): with self.session(graph=ops_lib.Graph()) as sess: - if slices: - assert not partitioner - new_vs = partitioned_variables.create_partitioned_variables( - var_full_shape, - slices, - array_ops.zeros(var_full_shape), # != original contents. - name=var_name) - elif partitioner: + if partitioner: new_vs = [ variable_scope.get_variable( var_name, @@ -1063,7 +1049,7 @@ class SaveRestoreShardedTest(test.TestCase): variables.global_variables_initializer().run() if call_saver_with_dict: saver = saver_module.Saver({ - var_name: (new_vs if slices else new_vs[0]) + var_name: new_vs[0] }) else: saver = saver_module.Saver(new_vs) @@ -1071,11 +1057,7 @@ class SaveRestoreShardedTest(test.TestCase): if partitioner: return new_vs[0].as_tensor().eval() - elif slices and slices[0] != 1: - return array_ops.concat(new_vs, 0).eval() - elif slices and slices[1] != 1: - return array_ops.concat(new_vs, 1).eval() - else: # Non-sliced. + else: return new_vs[0].eval() for call_saver_with_dict in {False, True}: @@ -1086,27 +1068,23 @@ class SaveRestoreShardedTest(test.TestCase): restored_full = _restore() self.assertAllEqual(saved_full, restored_full) - # Saves 10 horizontal parts of a partitioned variable. - # Restores into a full variable, non-sliced. - saved_full = _save(slices=[10, 1]) - restored_full = _restore() - self.assertAllEqual(saved_full, restored_full) - - # Restores into a different number/orientation of slices. - restored_full = _restore(slices=[2, 1]) # 2 horizon parts. - self.assertAllEqual(saved_full, restored_full) - restored_full = _restore(slices=[1, 3]) # 3 vertical parts. + # Restores into the same number of partitions. + restored_full = _restore( + partitioner=partitioned_variables.fixed_size_partitioner( + num_shards=2)) self.assertAllEqual(saved_full, restored_full) - # Restores into a PartitionedVariable + # Restores into a different number of partitions. restored_full = _restore( partitioner=partitioned_variables.fixed_size_partitioner( - num_shards=2)) + num_shards=3)) self.assertAllEqual(saved_full, restored_full) - # Now, saves a full variable and restores in slices. + # Now, saves a full variable and restores PartitionedVariable. saved_full = _save() - restored_full = _restore(slices=[1, 3]) + restored_full = _restore( + partitioner=partitioned_variables.fixed_size_partitioner( + num_shards=3)) self.assertAllEqual(saved_full, restored_full) def testPartitionedVariable(self): -- GitLab From 733ea8ac2c71989988cea7662a3acae4240362c7 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Tue, 27 Nov 2018 02:54:59 -0800 Subject: [PATCH 380/672] Removed duplicated _Overload* methods in variables Prior to this change all variable classes (Variable, RefVariable and ResourceVariable) had their own copy/pasted implementation of _OverloadOperator and _OverloadAllOperators. This was unnecessary since a single implementation in the base class would work just as well. The change also fixes the __name__ and __module__ of the operator wrapper functions. PiperOrigin-RevId: 222963169 --- .../python/kernel_tests/variables_test.py | 7 ++ .../python/ops/resource_variable_ops.py | 35 -------- tensorflow/python/ops/variables.py | 82 ++++++------------- 3 files changed, 31 insertions(+), 93 deletions(-) diff --git a/tensorflow/python/kernel_tests/variables_test.py b/tensorflow/python/kernel_tests/variables_test.py index 2bb75109b1..faa9f82067 100644 --- a/tensorflow/python/kernel_tests/variables_test.py +++ b/tensorflow/python/kernel_tests/variables_test.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import functools import operator import numpy as np @@ -309,6 +310,12 @@ class VariablesTestCase(test.TestCase): self.assertEqual([var_x], variables.trainable_variables("scope_1")) self.assertEqual([var_y], variables.trainable_variables("scope_2")) + def testOperatorWrapping(self): + for attr in functools.WRAPPER_ASSIGNMENTS: + self.assertEqual( + getattr(variables.Variable.__add__, attr), + getattr(ops.Tensor.__add__, attr)) + def testOperators(self): with self.cached_session(): var_f = variables.Variable([2.0]) diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index f614c48485..5c74dffb05 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -805,16 +805,6 @@ class ResourceVariable(variables.RefVariable): return ResourceVariable( variable_def=variable_def, import_scope=import_scope) - @staticmethod - def _OverloadAllOperators(): # pylint: disable=invalid-name - """Register overloads for all operators.""" - for operator in ops.Tensor.OVERLOADABLE_OPERATORS: - ResourceVariable._OverloadOperator(operator) - # For slicing, bind getitem differently than a tensor (use SliceHelperVar - # instead) - # pylint: disable=protected-access - setattr(ResourceVariable, "__getitem__", array_ops._SliceHelperVar) - def _AsTensor(self): return self.value() @@ -826,30 +816,6 @@ class ResourceVariable(variables.RefVariable): """Unsupported.""" raise NotImplementedError("ResourceVariable does not implement set_shape()") - @staticmethod - def _OverloadOperator(operator): # pylint: disable=invalid-name - """Defer an operator overload to `ops.Tensor`. - - We pull the operator out of ops.Tensor dynamically to avoid ordering issues. - - Args: - operator: string. The operator name. - """ - - tensor_oper = getattr(ops.Tensor, operator) - def _run_op(a, *args): - # pylint: disable=protected-access - value = a._AsTensor() - return tensor_oper(value, *args) - - # Propagate __doc__ to wrapper - try: - _run_op.__doc__ = tensor_oper.__doc__ - except AttributeError: - pass - - setattr(ResourceVariable, operator, _run_op) - __array_priority__ = 100 def is_initialized(self, name=None): @@ -1435,7 +1401,6 @@ ops.register_tensor_conversion_function( variables.Variable, variables.Variable._TensorConversionFunction) # pylint: disable=protected-access # pylint: disable=protected-access -ResourceVariable._OverloadAllOperators() ops.register_dense_tensor_like_type(ResourceVariable) diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index 438bc912c7..f72b19bcdd 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -18,7 +18,7 @@ from __future__ import division from __future__ import print_function import enum # pylint: disable=g-bad-import-order - +import functools import os import six @@ -861,18 +861,18 @@ class Variable(six.with_metaclass(VariableMetaclass, else: return v.value() - @staticmethod - def _OverloadAllOperators(): # pylint: disable=invalid-name + @classmethod + def _OverloadAllOperators(cls): # pylint: disable=invalid-name """Register overloads for all operators.""" for operator in ops.Tensor.OVERLOADABLE_OPERATORS: - Variable._OverloadOperator(operator) + cls._OverloadOperator(operator) # For slicing, bind getitem differently than a tensor (use SliceHelperVar # instead) # pylint: disable=protected-access - setattr(Variable, "__getitem__", array_ops._SliceHelperVar) + setattr(cls, "__getitem__", array_ops._SliceHelperVar) - @staticmethod - def _OverloadOperator(operator): # pylint: disable=invalid-name + @classmethod + def _OverloadOperator(cls, operator): # pylint: disable=invalid-name """Defer an operator overload to `ops.Tensor`. We pull the operator out of ops.Tensor dynamically to avoid ordering issues. @@ -880,17 +880,26 @@ class Variable(six.with_metaclass(VariableMetaclass, Args: operator: string. The operator name. """ + tensor_oper = getattr(ops.Tensor, operator) - def _run_op(a, *args): + def _run_op(a, *args, **kwargs): # pylint: disable=protected-access - return getattr(ops.Tensor, operator)(a._AsTensor(), *args) - # Propagate __doc__ to wrapper - try: - _run_op.__doc__ = getattr(ops.Tensor, operator).__doc__ - except AttributeError: - pass + return tensor_oper(a._AsTensor(), *args, **kwargs) - setattr(Variable, operator, _run_op) + functools.update_wrapper(_run_op, tensor_oper) + setattr(cls, operator, _run_op) + + def __iter__(self): + """Dummy method to prevent iteration. Do not call. + + NOTE(mrry): If we register __getitem__ as an overloaded operator, + Python will valiantly attempt to iterate over the variable's Tensor from 0 + to infinity. Declaring this method prevents this unintended behavior. + + Raises: + TypeError: when invoked. + """ + raise TypeError("'Variable' object is not iterable.") # NOTE(mrry): This enables the Variable's overloaded "right" binary # operators to run when the left operand is an ndarray, because it @@ -1577,18 +1586,6 @@ class RefVariable(VariableV1): """ return self._snapshot - def __iter__(self): - """Dummy method to prevent iteration. Do not call. - - NOTE(mrry): If we register __getitem__ as an overloaded operator, - Python will valiantly attempt to iterate over the variable's Tensor from 0 - to infinity. Declaring this method prevents this unintended behavior. - - Raises: - TypeError: when invoked. - """ - raise TypeError("'Variable' object is not iterable.") - def value(self): """Returns the last snapshot of this variable. @@ -2124,37 +2121,6 @@ class RefVariable(VariableV1): else: return v.value() - @staticmethod - def _OverloadAllOperators(): # pylint: disable=invalid-name - """Register overloads for all operators.""" - for operator in ops.Tensor.OVERLOADABLE_OPERATORS: - Variable._OverloadOperator(operator) # pylint: disable=protected-access - # For slicing, bind getitem differently than a tensor (use SliceHelperVar - # instead) - # pylint: disable=protected-access - setattr(Variable, "__getitem__", array_ops._SliceHelperVar) - - @staticmethod - def _OverloadOperator(operator): # pylint: disable=invalid-name - """Defer an operator overload to `ops.Tensor`. - - We pull the operator out of ops.Tensor dynamically to avoid ordering issues. - - Args: - operator: string. The operator name. - """ - - def _run_op(a, *args): - # pylint: disable=protected-access - return getattr(ops.Tensor, operator)(a._AsTensor(), *args) - # Propagate __doc__ to wrapper - try: - _run_op.__doc__ = getattr(ops.Tensor, operator).__doc__ - except AttributeError: - pass - - setattr(Variable, operator, _run_op) - def _gather_saveables_for_checkpoint(self): """For implementing `Checkpointable`. This object is saveable on its own.""" return {checkpointable.VARIABLE_VALUE_KEY: self} -- GitLab From e4efa68f3ca39da953040990c45ab9435e6c5aee Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 03:30:39 -0800 Subject: [PATCH 381/672] Visibility change for tensorflow contrib library. PiperOrigin-RevId: 222966504 --- tensorflow/contrib/tpu/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/contrib/tpu/BUILD b/tensorflow/contrib/tpu/BUILD index a0a9cb3f31..999274018b 100644 --- a/tensorflow/contrib/tpu/BUILD +++ b/tensorflow/contrib/tpu/BUILD @@ -14,6 +14,7 @@ load("//tensorflow:tensorflow.bzl", "tf_py_test") package( default_visibility = [ "//cloud/vmm/testing/tests/tpu:__subpackages__", + "//knowledge/cerebra/sense/im2query:__subpackages__", "//learning/brain:__subpackages__", "//learning/deepmind:__subpackages__", "//medical/pathology:__subpackages__", -- GitLab From 5bb5d6db8ac8f48ba2636ae18844cb584b837904 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Tue, 27 Nov 2018 03:34:09 -0800 Subject: [PATCH 382/672] Pushed Variable.from_proto implementation to RefVariable It was not generic enough to be in the base class. PiperOrigin-RevId: 222966856 --- tensorflow/python/ops/resource_variable_ops.py | 2 +- tensorflow/python/ops/variables.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index 5c74dffb05..f9faa3e945 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -1433,7 +1433,7 @@ def _from_proto_fn(v, import_scope=None): """Creates Variable or ResourceVariable from VariableDef as needed.""" if v.is_resource: return ResourceVariable.from_proto(v, import_scope=import_scope) - return variables.Variable.from_proto(v, import_scope=import_scope) + return variables.RefVariable.from_proto(v, import_scope=import_scope) ops.register_proto_function( diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index f72b19bcdd..a001374e9a 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -968,8 +968,7 @@ class Variable(six.with_metaclass(VariableMetaclass, @staticmethod def from_proto(variable_def, import_scope=None): """Returns a `Variable` object created from `variable_def`.""" - return RefVariable(variable_def=variable_def, - import_scope=import_scope) + raise NotImplementedError class SaveSliceInfo(object): """Information on how to save this Variable as a slice. @@ -2344,6 +2343,12 @@ class RefVariable(VariableV1): else: return None + @staticmethod + def from_proto(variable_def, import_scope=None): + """Returns a `Variable` object created from `variable_def`.""" + return RefVariable(variable_def=variable_def, + import_scope=import_scope) + def __iadd__(self, other): logging.log_first_n( logging.WARN, -- GitLab From 956e75535d25d5fdabac4a3a25f85881762cbc0f Mon Sep 17 00:00:00 2001 From: Peter Buchlovsky Date: Tue, 27 Nov 2018 04:31:08 -0800 Subject: [PATCH 383/672] Fix incompatible device colocation warning. PiperOrigin-RevId: 222971307 --- tensorflow/python/distribute/mirrored_strategy.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/distribute/mirrored_strategy.py b/tensorflow/python/distribute/mirrored_strategy.py index 402a94c2b7..d6d40df5ce 100644 --- a/tensorflow/python/distribute/mirrored_strategy.py +++ b/tensorflow/python/distribute/mirrored_strategy.py @@ -457,7 +457,8 @@ class MirroredExtended(distribute_lib.DistributionStrategyExtended): if self._cluster_spec: worker_device_pairs = self._worker_devices else: - worker_device_pairs = [("/job:localhost", self._devices)] + worker = device_util.canonicalize("/device:CPU:0") + worker_device_pairs = [(worker, self._devices)] return values.DatasetIterator(dataset, worker_device_pairs, self._num_replicas_in_sync) @@ -471,7 +472,8 @@ class MirroredExtended(distribute_lib.DistributionStrategyExtended): worker_device_pairs = self._worker_devices else: num_workers = 1 - worker_device_pairs = [("/job:localhost", self._devices)] + worker = device_util.canonicalize("/device:CPU:0") + worker_device_pairs = [(worker, self._devices)] for i in range(num_workers): input_contexts.append(distribute_lib.InputContext( num_input_pipelines=num_workers, -- GitLab From f56925c38e4fe67fba3e4da7ee8bbb72b1e69d38 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 05:38:43 -0800 Subject: [PATCH 384/672] update eigen to the commit: https://bitbucket.org/eigen/eigen/commits/efda481cbd7a PiperOrigin-RevId: 222976986 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index d9d40874a4..0725bd0e8a 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -134,11 +134,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "eigen_archive", build_file = clean_dep("//third_party:eigen.BUILD"), - sha256 = "8fa7ba1af23f0320be05f4658061138d6eb8dd1f320669cbf305b3a034f9d1c2", - strip_prefix = "eigen-eigen-ea671884cc96", + sha256 = "fc0f871496cdaec892245afc9890e8267f73b0fcec5a7f75be0dc914e2972023", + strip_prefix = "eigen-eigen-efda481cbd7a", urls = [ - "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/ea671884cc96.tar.gz", - "https://bitbucket.org/eigen/eigen/get/ea671884cc96.tar.gz", + "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/efda481cbd7a.tar.gz", + "https://bitbucket.org/eigen/eigen/get/efda481cbd7a.tar.gz", ], ) -- GitLab From 84337310517914ca4b4d6eb35295a65758bc6d75 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 08:17:25 -0800 Subject: [PATCH 385/672] Unittest to show overflow characteristics of AveragePool. PiperOrigin-RevId: 222993846 --- tensorflow/lite/kernels/pooling_test.cc | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tensorflow/lite/kernels/pooling_test.cc b/tensorflow/lite/kernels/pooling_test.cc index 80eef02509..98777f1c13 100644 --- a/tensorflow/lite/kernels/pooling_test.cc +++ b/tensorflow/lite/kernels/pooling_test.cc @@ -67,6 +67,10 @@ class QuantizedPoolingOpModel : public BasePoolingOpModel { QuantizeAndPopulate(input_, data); } + void SetInput(const std::vector& data) { + QuantizeAndPopulate(input_, data); + } + std::vector GetOutput() { return ExtractVector(output_); } std::vector GetDequantizedOutput() { return Dequantize(ExtractVector(output_), @@ -106,6 +110,45 @@ TEST(QuantizedPoolingOpTest, AveragePool) { EXPECT_THAT(m.GetOutput(), ElementsAreArray({44, 92})); } +// Send in a white image, expect a white pixel. +TEST(QuantizedPoolingOpTest, AveragePoolImageSize16) { + int image_size = 16; + QuantizedPoolingOpModel m( + BuiltinOperator_AVERAGE_POOL_2D, + /*input=*/{TensorType_UINT8, {1, image_size, image_size, 1}, 0, 16}, + /*filter_width=*/image_size, + /*filter_height=*/image_size, + /*output=*/{TensorType_UINT8, {}, 0, 16}); + + std::vector input(image_size * image_size, 16.f); + m.SetInput(input); + m.Invoke(); + + EXPECT_THAT(m.GetOutput(), ::testing::ElementsAre(255)); + EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({16}))); +} + +// Send in a white image, expect something other than a white pixel, due to +// overflow. +TEST(QuantizedPoolingOpTest, AveragePoolImageSize17) { + int image_size = 17; + QuantizedPoolingOpModel m( + BuiltinOperator_AVERAGE_POOL_2D, + /*input=*/{TensorType_UINT8, {1, image_size, image_size, 1}, 0, 16}, + /*filter_width=*/image_size, + /*filter_height=*/image_size, + /*output=*/{TensorType_UINT8, {}, 0, 16}); + + std::vector input(image_size * image_size, 16.f); + m.SetInput(input); + m.Invoke(); + + // Ordinarily we would see '255' here. However, the optimized version of + // AveragePool uses a uint16 accumulator which causes it to overflow for + // images this large. + EXPECT_THAT(m.GetOutput(), ::testing::ElementsAre(28)); +} + TEST(FloatPoolingOpTest, MaxPool) { FloatPoolingOpModel m(BuiltinOperator_MAX_POOL_2D, /*input=*/{TensorType_FLOAT32, {1, 2, 4, 1}}, -- GitLab From 7a0d3c9dd52889a9424b4f9907ad55a5f76fa6df Mon Sep 17 00:00:00 2001 From: Yanan Cao Date: Tue, 27 Nov 2018 08:35:25 -0800 Subject: [PATCH 386/672] Link ArgMax custom call op in xla_cpu_jit PiperOrigin-RevId: 222996011 --- tensorflow/compiler/jit/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/compiler/jit/BUILD b/tensorflow/compiler/jit/BUILD index 6b0d20bc18..1f6dadf1ac 100644 --- a/tensorflow/compiler/jit/BUILD +++ b/tensorflow/compiler/jit/BUILD @@ -50,6 +50,7 @@ cc_library( deps = [ ":jit_compilation_passes", "//tensorflow/compiler/jit/kernels:xla_ops", + "//tensorflow/compiler/tf2xla/kernels:xla_cpu_only_ops", "//tensorflow/compiler/tf2xla/kernels:xla_dummy_ops", "//tensorflow/compiler/tf2xla/kernels:xla_ops", "//tensorflow/compiler/xla/service:cpu_plugin", -- GitLab From b0cfc0bf65e8372d9cf6da078509e1988d5e2fad Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Tue, 27 Nov 2018 08:46:21 -0800 Subject: [PATCH 387/672] [TF:XLA] Small refactorings of XlaContext and XlaOpKernelContext. No functional changes intended. * Add an XlaOpKernelContext::xla_context() method, and change most users of XlaContext::Get() to use XlaOpKernelContext methods instead. * Remove XlaContext::CreateResource, which had a confusing API that mirror XlaResource's constructor. Replace it with XlaContext::AddResource, which takes ownership of a resource, and add helper methods to build XlaResources. * Rename XlaResource::tensor_array_size to XlaResource::max_array_size, since it also applies to stacks as well as tensor arrays. * Remove XlaContext::RepresentationShape and XlaContext::allow_cpu_custom_calls. XlaContext already has a reference to the XlaCompiler, and these can be determined from XlaCompiler::options(), and are therefore redundant. PiperOrigin-RevId: 222997360 --- tensorflow/compiler/tf2xla/kernels/arg_op.cc | 2 +- tensorflow/compiler/tf2xla/kernels/if_op.cc | 2 +- .../compiler/tf2xla/kernels/index_ops_cpu.cc | 2 +- .../compiler/tf2xla/kernels/retval_op.cc | 3 +- .../compiler/tf2xla/kernels/sendrecv_ops.cc | 4 +- .../compiler/tf2xla/kernels/stack_ops.cc | 19 +++---- .../tf2xla/kernels/tensor_array_ops.cc | 33 +++++------ .../compiler/tf2xla/kernels/while_op.cc | 2 +- tensorflow/compiler/tf2xla/xla_compiler.cc | 40 +++++++------- tensorflow/compiler/tf2xla/xla_compiler.h | 2 +- .../compiler/tf2xla/xla_compiler_test.cc | 6 +- tensorflow/compiler/tf2xla/xla_context.cc | 35 ++---------- tensorflow/compiler/tf2xla/xla_context.h | 32 +---------- tensorflow/compiler/tf2xla/xla_op_kernel.cc | 55 ++++++++++--------- tensorflow/compiler/tf2xla/xla_op_kernel.h | 2 + tensorflow/compiler/tf2xla/xla_resource.cc | 35 +++++++++--- tensorflow/compiler/tf2xla/xla_resource.h | 19 +++++-- 17 files changed, 134 insertions(+), 159 deletions(-) diff --git a/tensorflow/compiler/tf2xla/kernels/arg_op.cc b/tensorflow/compiler/tf2xla/kernels/arg_op.cc index 2db2514397..795ea09831 100644 --- a/tensorflow/compiler/tf2xla/kernels/arg_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/arg_op.cc @@ -50,7 +50,7 @@ class XlaArgOp : public XlaOpKernel { return; } - const XlaExpression& arg = XlaContext::Get(ctx).args()[index_]; + const XlaExpression& arg = ctx->xla_context()->args()[index_]; OP_REQUIRES(ctx, arg.kind() != XlaExpression::Kind::kInvalid, errors::InvalidArgument("Invalid/missing argument expression")); ctx->SetOutputExpression(0, arg); diff --git a/tensorflow/compiler/tf2xla/kernels/if_op.cc b/tensorflow/compiler/tf2xla/kernels/if_op.cc index 56da50f140..b5e0839125 100644 --- a/tensorflow/compiler/tf2xla/kernels/if_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/if_op.cc @@ -72,7 +72,7 @@ void XlaIfOp::Compile(XlaOpKernelContext* ctx) { arg.shape = resource->shape(); OP_REQUIRES(ctx, arg.initialized, errors::Unimplemented("Uninitialized arguments: ", arg.name)); - arg.tensor_array_size = resource->tensor_array_size(); + arg.max_array_size = resource->max_array_size(); for (const auto& gradient : resource->tensor_array_gradients()) { arg.tensor_array_gradients.insert(gradient.first); } diff --git a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc index 20b7176041..e2c05b648b 100644 --- a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc +++ b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc @@ -72,7 +72,7 @@ class ArgMaxCustomCallOp : public XlaOpKernel { // Fall back to XLA ArgMax HLO when CustomCall is not allowed or when input // shape isn't supported. - if (!XlaContext::Get(ctx).allow_cpu_custom_calls() || + if (!ctx->compiler()->options().allow_cpu_custom_calls || (input_dims != 1 && input_dims != 2)) { xla::XlaOp output = XlaHelpers::ArgMax(ctx->Input(0), output_type, axis); ctx->SetOutput(0, output); diff --git a/tensorflow/compiler/tf2xla/kernels/retval_op.cc b/tensorflow/compiler/tf2xla/kernels/retval_op.cc index 6970dd0a00..e4046c7955 100644 --- a/tensorflow/compiler/tf2xla/kernels/retval_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/retval_op.cc @@ -47,8 +47,7 @@ class RetvalOp : public XlaOpKernel { // compilation. OP_REQUIRES_OK(ctx, frame->SetRetval(index_, input)); } else { - XlaContext& xla_context = XlaContext::Get(ctx); - xla_context.SetRetval(index_, ctx->InputExpression(0)); + ctx->xla_context()->SetRetval(index_, ctx->InputExpression(0)); } } diff --git a/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc b/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc index a7f5a8f169..84470b230d 100644 --- a/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc @@ -42,7 +42,7 @@ SendOp::SendOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) { } void SendOp::Compile(XlaOpKernelContext* ctx) { - XlaCompiler* compiler = XlaContext::Get(ctx).compiler(); + XlaCompiler* compiler = ctx->compiler(); xla::ChannelHandle channel; OP_REQUIRES_OK(ctx, compiler->GetChannelHandle(tensor_name_, &channel)); xla::Send(ctx->Input(0), channel); @@ -73,7 +73,7 @@ RecvOp::RecvOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) { } void RecvOp::Compile(XlaOpKernelContext* ctx) { - XlaCompiler* compiler = XlaContext::Get(ctx).compiler(); + XlaCompiler* compiler = ctx->compiler(); xla::ChannelHandle channel; OP_REQUIRES_OK(ctx, compiler->GetChannelHandle(tensor_name_, &channel)); ctx->SetOutput(0, xla::Recv(ctx->builder(), shape_, channel)); diff --git a/tensorflow/compiler/tf2xla/kernels/stack_ops.cc b/tensorflow/compiler/tf2xla/kernels/stack_ops.cc index 7b96b43ad8..8e9e4daf99 100644 --- a/tensorflow/compiler/tf2xla/kernels/stack_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/stack_ops.cc @@ -69,7 +69,7 @@ Status MaybeInitializeStack(xla::XlaBuilder* builder, XlaResource* resource, } TensorShape stack_shape; - stack_shape.AddDim(resource->tensor_array_size()); + stack_shape.AddDim(resource->max_array_size()); stack_shape.AppendShape(elem_shape); if (!resource->initialized()) { @@ -97,10 +97,10 @@ class StackOp : public XlaOpKernel { } void Compile(XlaOpKernelContext* ctx) override { - int64 size; - OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntScalar(0, &size)); + int64 max_size; + OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntScalar(0, &max_size)); OP_REQUIRES( - ctx, size >= 0, + ctx, max_size >= 0, errors::InvalidArgument( "XLA compilation requires a fixed stack size upper bound. If " "you are using tf.while_loop, set the maximum_iterations parameter " @@ -108,14 +108,9 @@ class StackOp : public XlaOpKernel { // We defer initializing the Stack resource until we see the first push. // Otherwise we do not know the shape of the stack elements. - xla::XlaOp value; - XlaContext& xc = XlaContext::Get(ctx); - XlaResource* resource; - string name = absl::StrCat("Stack: ", stack_name_); - OP_REQUIRES_OK( - ctx, xc.CreateResource(XlaResource::kStack, -1, std::move(name), dtype_, - TensorShape(), value, /*tensor_array_size=*/size, - /*tensor_array_gradients=*/{}, &resource)); + XlaResource* resource = + ctx->xla_context()->AddResource(XlaResource::CreateStack( + /*name=*/absl::StrCat("Stack: ", stack_name_), dtype_, max_size)); ctx->SetResourceOutput(0, resource); } diff --git a/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc b/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc index 252967a746..939d7e1951 100644 --- a/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc @@ -61,8 +61,8 @@ Status MaybeInitializeTensorArray(xla::XlaBuilder* builder, " but op has dtype ", DataTypeString(dtype), "."); } - TF_RET_CHECK(resource->tensor_array_size() >= 0) - << resource->name() << " size " << resource->tensor_array_size(); + TF_RET_CHECK(resource->max_array_size() >= 0) + << resource->name() << " size " << resource->max_array_size(); if (!resource->initialized()) { TF_RETURN_IF_ERROR(resource->SetTypeAndShape(dtype, elem_shape)); @@ -78,7 +78,7 @@ Status MaybeInitializeTensorArray(xla::XlaBuilder* builder, XLAShapeToTensorShape(shape_or_status.ValueOrDie(), &shape)); TensorShape ta_shape; - ta_shape.AddDim(resource->tensor_array_size()); + ta_shape.AddDim(resource->max_array_size()); ta_shape.AppendShape(elem_shape); if (ta_shape != shape) { return errors::InvalidArgument( @@ -114,7 +114,7 @@ Status CheckTensorArrayIsInitialized(const string& op_name, Status GetTensorArrayShape(const XlaResource* resource, xla::XlaBuilder* builder, TensorShape* shape) { *shape = resource->shape(); - shape->InsertDim(0, resource->tensor_array_size()); + shape->InsertDim(0, resource->max_array_size()); return Status::OK(); } @@ -166,13 +166,10 @@ class TensorArrayOp : public XlaOpKernel { value = xla::Broadcast(zero, ta_shape.dim_sizes()); } - XlaContext& xc = XlaContext::Get(ctx); - XlaResource* var; - string name = absl::StrCat("TensorArray: ", tensor_array_name_); - OP_REQUIRES_OK( - ctx, xc.CreateResource(XlaResource::kTensorArray, -1, std::move(name), - dtype_, shape, value, /*tensor_array_size=*/size, - /*tensor_array_gradients=*/{}, &var)); + XlaResource* var = + ctx->xla_context()->AddResource(XlaResource::CreateTensorArray( + /*name=*/absl::StrCat("TensorArray: ", tensor_array_name_), dtype_, + shape, /*initial_value=*/value, /*max_array_size=*/size)); ctx->SetResourceOutput(0, var); Tensor flow(DT_FLOAT, TensorShape({})); @@ -517,14 +514,13 @@ class TensorArraySplitOp : public XlaOpKernel { xla::XlaOp ta = resource->value(); TensorShape ta_shape; - ta_shape.AddDim(resource->tensor_array_size()); + ta_shape.AddDim(resource->max_array_size()); ta_shape.AppendShape(elem_shape); - OP_REQUIRES( - ctx, lengths.size() == resource->tensor_array_size(), - errors::InvalidArgument( - "TensorArray's size is not equal to the size of lengths (", - lengths.size(), " vs. ", resource->tensor_array_size(), ")")); + OP_REQUIRES(ctx, lengths.size() == resource->max_array_size(), + errors::InvalidArgument( + "TensorArray's size is not equal to the size of lengths (", + lengths.size(), " vs. ", resource->max_array_size(), ")")); const xla::XlaOp value = ctx->Input(1); const xla::XlaOp flow = ctx->Input(3); @@ -562,8 +558,7 @@ class TensorArraySizeOp : public XlaOpKernel { XlaResource* var; OP_REQUIRES_OK(ctx, ctx->GetResourceInput(0, &var)); Tensor size_tensor(DT_INT32, {}); - size_tensor.scalar()() = - static_cast(var->tensor_array_size()); + size_tensor.scalar()() = static_cast(var->max_array_size()); ctx->SetConstantOutput(0, size_tensor); } diff --git a/tensorflow/compiler/tf2xla/kernels/while_op.cc b/tensorflow/compiler/tf2xla/kernels/while_op.cc index 559414eeaa..ce007fc04a 100644 --- a/tensorflow/compiler/tf2xla/kernels/while_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/while_op.cc @@ -64,7 +64,7 @@ Status MakeXlaCompilerArgumentsFromInputs( if (!arg.initialized) { *has_uninitialized_vars = true; } - arg.tensor_array_size = resource->tensor_array_size(); + arg.max_array_size = resource->max_array_size(); for (const auto& gradient : resource->tensor_array_gradients()) { arg.tensor_array_gradients.insert(gradient.first); } diff --git a/tensorflow/compiler/tf2xla/xla_compiler.cc b/tensorflow/compiler/tf2xla/xla_compiler.cc index 8036bc6844..7fdd60145f 100644 --- a/tensorflow/compiler/tf2xla/xla_compiler.cc +++ b/tensorflow/compiler/tf2xla/xla_compiler.cc @@ -326,10 +326,10 @@ Status BuildComputation( bool XlaCompiler::Argument::operator==( const XlaCompiler::Argument& other) const { - if (std::tie(kind, resource_kind, type, name, initialized, tensor_array_size, + if (std::tie(kind, resource_kind, type, name, initialized, max_array_size, tensor_array_gradients) != std::tie(other.kind, other.resource_kind, other.type, other.name, - other.initialized, other.tensor_array_size, + other.initialized, other.max_array_size, other.tensor_array_gradients)) { return false; } @@ -359,8 +359,8 @@ string XlaCompiler::Argument::HumanString() const { string output = absl::StrCat("kind=resource", common, " resource_kind=", XlaResource::KindToString(resource_kind), " initialized=", initialized); - if (tensor_array_size >= 0) { - absl::StrAppend(&output, " tensor_array_size=", tensor_array_size); + if (max_array_size >= 0) { + absl::StrAppend(&output, " max_array_size=", max_array_size); } if (!tensor_array_gradients.empty()) { absl::StrAppend(&output, " tensor_array_gradients=", @@ -567,12 +567,12 @@ Status XlaCompiler::XLAShapeForArgument(const XlaCompiler::Argument& arg, return Status::OK(); } case XlaResource::kTensorArray: { - if (arg.tensor_array_size < 0) { + if (arg.max_array_size < 0) { return errors::InvalidArgument( - "Negative tensor_array_size in XLAShapeForArgument"); + "Negative max_array_size in XLAShapeForArgument"); } TensorShape shape; - shape.AddDim(arg.tensor_array_size); + shape.AddDim(arg.max_array_size); shape.AppendShape(arg.shape); TF_RETURN_IF_ERROR(TensorShapeToXLAShape(arg.type, shape, xla_shape)); @@ -584,12 +584,12 @@ Status XlaCompiler::XLAShapeForArgument(const XlaCompiler::Argument& arg, return Status::OK(); } case XlaResource::kStack: { - if (arg.tensor_array_size < 0) { + if (arg.max_array_size < 0) { return errors::InvalidArgument( - "Negative tensor_array_size in XLAShapeForArgument"); + "Negative max_array_size in XLAShapeForArgument"); } TensorShape shape; - shape.AddDim(arg.tensor_array_size); + shape.AddDim(arg.max_array_size); shape.AppendShape(arg.shape); xla::Shape buffer_shape; TF_RETURN_IF_ERROR( @@ -635,21 +635,23 @@ Status XlaCompiler::BuildArguments( const XlaCompiler::Argument& arg = args[i]; XlaExpression& arg_expression = (*arg_expressions)[i]; switch (arg.kind) { - case XlaCompiler::Argument::kResource: + case XlaCompiler::Argument::kResource: { TF_RET_CHECK(arg.resource_kind != XlaResource::kInvalid); // TODO(phawkins): this code assumes that resource arguments do not // alias. - XlaResource* resource; - TF_RETURN_IF_ERROR(context->CreateResource( - arg.resource_kind, i, arg.name, arg.type, arg.shape, xla::XlaOp(), - /*tensor_array_size=*/arg.tensor_array_size, - /*tensor_array_gradients=*/arg.tensor_array_gradients, &resource)); + XlaResource* resource = + context->AddResource(absl::make_unique( + arg.resource_kind, i, arg.name, arg.type, arg.shape, + xla::XlaOp(), + /*max_array_size=*/arg.max_array_size, + /*tensor_array_gradients=*/arg.tensor_array_gradients, + /*tensor_array_multiple_writes_aggregate=*/true)); arg_expression = XlaExpression::Resource(resource); if (arg.initialized) { input_mapping->push_back(i); } - break; + } case XlaCompiler::Argument::kParameter: case XlaCompiler::Argument::kToken: { input_mapping->push_back(i); @@ -923,9 +925,7 @@ Status XlaCompiler::CompileGraph(const XlaCompiler::CompileOptions& options, options_.device_type, name)); xla::XlaBuilder builder(name); - XlaContext* context = - new XlaContext(this, &builder, options_.allow_cpu_custom_calls, - &options_.shape_representation_fn); + XlaContext* context = new XlaContext(this, &builder); core::ScopedUnref context_unref(context); std::vector real_args(args.begin(), args.end()); diff --git a/tensorflow/compiler/tf2xla/xla_compiler.h b/tensorflow/compiler/tf2xla/xla_compiler.h index 6342612468..0d801b73a8 100644 --- a/tensorflow/compiler/tf2xla/xla_compiler.h +++ b/tensorflow/compiler/tf2xla/xla_compiler.h @@ -150,7 +150,7 @@ class XlaCompiler { // For a TensorArray or Stack resource, what is the array's declared size? // (Used for lazy initialization.) - int64 tensor_array_size = -1; + int64 max_array_size = -1; // TensorArray resource parameters are passed as (array, gradient array 0, // ..., gradient array k), where the gradient arrays are in the same order diff --git a/tensorflow/compiler/tf2xla/xla_compiler_test.cc b/tensorflow/compiler/tf2xla/xla_compiler_test.cc index eba5d77efa..fe2a5f5b0c 100644 --- a/tensorflow/compiler/tf2xla/xla_compiler_test.cc +++ b/tensorflow/compiler/tf2xla/xla_compiler_test.cc @@ -650,7 +650,7 @@ TEST_F(XlaCompilerTest, CanPassTensorArraysToAndFromComputation) { args[0].initialized = true; args[0].type = DT_INT32; args[0].shape = TensorShape({}); - args[0].tensor_array_size = 2; + args[0].max_array_size = 2; args[0].tensor_array_gradients = {"grad2"}; // Compiles the graph. @@ -709,7 +709,7 @@ TEST_F(XlaCompilerTest, UnwrittenTensorArrayGradientsAreNotComputationOutputs) { args[0].initialized = true; args[0].type = DT_INT32; args[0].shape = TensorShape({}); - args[0].tensor_array_size = 2; + args[0].max_array_size = 2; args[0].tensor_array_gradients = {"grad1"}; // Compiles the graph. @@ -741,7 +741,7 @@ TEST_F(XlaCompilerTest, NewTensorArrayGradientsAreComputationOutputs) { args[0].initialized = true; args[0].type = DT_INT32; args[0].shape = TensorShape({}); - args[0].tensor_array_size = 2; + args[0].max_array_size = 2; args[0].tensor_array_gradients = {"grad1"}; // Compiles the graph. diff --git a/tensorflow/compiler/tf2xla/xla_context.cc b/tensorflow/compiler/tf2xla/xla_context.cc index 43095fbb47..a69af70503 100644 --- a/tensorflow/compiler/tf2xla/xla_context.cc +++ b/tensorflow/compiler/tf2xla/xla_context.cc @@ -54,25 +54,14 @@ const char XlaContext::kXlaContextResourceName[] = "_xla_context"; return *context; } -/* static */ XlaContext& XlaContext::Get(const XlaOpKernelContext* ctx) { - return Get(ctx->op_kernel_context()); -} - void XlaContext::set_args(std::vector args) { args_ = std::move(args); } -XlaContext::XlaContext( - XlaCompiler* compiler, xla::XlaBuilder* builder, - bool allow_cpu_custom_calls, - const std::function( - const TensorShape&, DataType)>* shape_representation_fn) - : compiler_(compiler), - builder_(builder), - allow_cpu_custom_calls_(allow_cpu_custom_calls), - shape_representation_fn_(shape_representation_fn) {} +XlaContext::XlaContext(XlaCompiler* compiler, xla::XlaBuilder* builder) + : compiler_(compiler), builder_(builder) {} -string XlaContext::DebugString() { return "TLA JIT context"; } +string XlaContext::DebugString() { return "XLA JIT context"; } void XlaContext::SetRetval(int index, const XlaExpression& expression) { if (retvals_.size() <= index) { @@ -81,21 +70,9 @@ void XlaContext::SetRetval(int index, const XlaExpression& expression) { retvals_[index] = expression; } -Status XlaContext::CreateResource( - XlaResource::Kind kind, int arg_num, string name, DataType type, - TensorShape shape, const xla::XlaOp& handle, int64 tensor_array_size, - const std::set& tensor_array_gradients, XlaResource** resource) { - resources_.emplace_back( - new XlaResource(kind, arg_num, std::move(name), type, std::move(shape), - handle, tensor_array_size, tensor_array_gradients, - /*tensor_array_multiple_writes_aggregate=*/false)); - *resource = resources_.back().get(); - return Status::OK(); -} - -xla::StatusOr XlaContext::RepresentationShape( - const TensorShape& shape, DataType type) const { - return (*shape_representation_fn_)(shape, type); +XlaResource* XlaContext::AddResource(std::unique_ptr resource) { + resources_.push_back(std::move(resource)); + return resources_.back().get(); } const xla::XlaComputation* XlaContext::GetOrCreateMax(const DataType type) { diff --git a/tensorflow/compiler/tf2xla/xla_context.h b/tensorflow/compiler/tf2xla/xla_context.h index dbfd344c9b..0767d1faac 100644 --- a/tensorflow/compiler/tf2xla/xla_context.h +++ b/tensorflow/compiler/tf2xla/xla_context.h @@ -41,14 +41,10 @@ class XlaContext : public ResourceBase { public: // Retrieves the XlaContext of the current compilation. static XlaContext& Get(const OpKernelContext* ctx); - static XlaContext& Get(const XlaOpKernelContext* ctx); // Creates a new XlaContext. See the documentation on the class data fields // for descriptions of the arguments. - XlaContext(XlaCompiler* compiler, xla::XlaBuilder* builder, - bool allow_cpu_custom_calls, - const std::function( - const TensorShape&, DataType)>* shape_representation_fn); + XlaContext(XlaCompiler* compiler, xla::XlaBuilder* builder); // Virtual method defined by ResourceBase. string DebugString() override; @@ -58,8 +54,6 @@ class XlaContext : public ResourceBase { // Returns the XlaBuilder that Ops use for compiling new expressions. xla::XlaBuilder* builder() { return builder_; } - bool allow_cpu_custom_calls() const { return allow_cpu_custom_calls_; } - const std::vector& args() const { return args_; } void set_args(std::vector args); @@ -70,25 +64,13 @@ class XlaContext : public ResourceBase { // grows the return values vector to size index+1 if it is smaller. void SetRetval(int index, const XlaExpression& expression); - // Creates a resource with resource `kind` and initial value `handle`. `name` - // is a descriptive name for use in error messages. See the `XlaResource` - // constructor for a description of the remaining arguments. - // Fails if the resource already exists. - Status CreateResource(XlaResource::Kind kind, int arg_num, string name, - DataType type, TensorShape shape, - const xla::XlaOp& handle, int64 tensor_array_size, - const std::set& tensor_array_gradients, - XlaResource** resource); + // Adds 'resource' to the set of resources owned by the context. + XlaResource* AddResource(std::unique_ptr resource); const std::vector>& resources() { return resources_; } - // Returns the XLA shape to be used to represent a variable of TF `shape` - // and `type`, or of an argument or return value of a top-level computation. - xla::StatusOr RepresentationShape(const TensorShape& shape, - DataType type) const; - // Get an XLA lambda to compute Max. This is cached in the // XlaContext since it may be used by multiple Ops. There is a // separate specialization of the computation for each DataType. @@ -118,9 +100,6 @@ class XlaContext : public ResourceBase { // The XlaBuilder used to construct the subgraph's compiled representation. xla::XlaBuilder* builder_; - // Allow ops to emit CustomCall operations for CPU. - const bool allow_cpu_custom_calls_; - // Arguments to the Tensorflow graph, indexed by _Arg index. // Includes both compile-time constant arguments and runtime parameters. std::vector args_; @@ -131,11 +110,6 @@ class XlaContext : public ResourceBase { // Holds ownership of resources. The resources are not ordered. std::vector> resources_; - // Describes the on-host shapes of parameters and return values. Also see: - // XlaDevice::Options::shape_representation_fn. - const std::function(const TensorShape&, DataType)>* - shape_representation_fn_; - // Cache of prebuilt computations indexed by their type. using ComputationMap = std::map; diff --git a/tensorflow/compiler/tf2xla/xla_op_kernel.cc b/tensorflow/compiler/tf2xla/xla_op_kernel.cc index 8dd8def054..58808c76de 100644 --- a/tensorflow/compiler/tf2xla/xla_op_kernel.cc +++ b/tensorflow/compiler/tf2xla/xla_op_kernel.cc @@ -36,8 +36,16 @@ bool XlaOpKernelContext::ValidateInputsAreSameShape(OpKernel* op) { return context_->ValidateInputsAreSameShape(op); } +XlaContext* XlaOpKernelContext::xla_context() const { + return &XlaContext::Get(context_); +} + xla::XlaBuilder* XlaOpKernelContext::builder() const { - return XlaContext::Get(this).builder(); + return xla_context()->builder(); +} + +XlaCompiler* XlaOpKernelContext::compiler() const { + return xla_context()->compiler(); } // Retrieves an XlaExpression that was allocated by a previous Op. @@ -338,8 +346,8 @@ Status XlaOpKernelContext::ConstantInputList( namespace { Status ReadVariableInputTensor(const Tensor& tensor, DataType type, - const OpKernelContext* ctx, TensorShape* shape, - xla::XlaOp* value) { + const XlaOpKernelContext* ctx, + TensorShape* shape, xla::XlaOp* value) { const XlaExpression* expression = CastExpressionFromTensor(tensor); XlaResource* variable = expression->resource(); TF_RET_CHECK(variable != nullptr); @@ -357,10 +365,9 @@ Status ReadVariableInputTensor(const Tensor& tensor, DataType type, *shape = variable->shape(); } - XlaContext& xla_context = XlaContext::Get(ctx); - TF_ASSIGN_OR_RETURN( - xla::Shape representation_shape, - xla_context.RepresentationShape(variable->shape(), variable->type())); + TF_ASSIGN_OR_RETURN(xla::Shape representation_shape, + ctx->compiler()->options().shape_representation_fn( + variable->shape(), variable->type())); xla::Shape xla_shape; TF_RETURN_IF_ERROR( TensorShapeToXLAShape(variable->type(), variable->shape(), &xla_shape)); @@ -377,15 +384,15 @@ Status ReadVariableInputTensor(const Tensor& tensor, DataType type, Status XlaOpKernelContext::ReadVariableInput(int index, DataType type, TensorShape* shape, xla::XlaOp* value) { - return ReadVariableInputTensor(context_->input(index), type, context_, shape, + return ReadVariableInputTensor(context_->input(index), type, this, shape, value); } Status XlaOpKernelContext::ReadVariableInput(absl::string_view name, DataType type, TensorShape* shape, xla::XlaOp* value) { - return ReadVariableInputTensor(GetInputTensorByName(name), type, context_, - shape, value); + return ReadVariableInputTensor(GetInputTensorByName(name), type, this, shape, + value); } Status XlaOpKernelContext::GetVariableTypeAndShape(int index, DataType* type, @@ -464,7 +471,7 @@ Status XlaOpKernelContext::GetResourceInput(int index, XlaResource** resource) { namespace { Status AssignVariableTensor(const Tensor& tensor, DataType type, - const OpKernelContext* ctx, xla::XlaOp handle, + const XlaOpKernelContext* ctx, xla::XlaOp handle, xla::XlaBuilder* builder) { const XlaExpression* expression = CastExpressionFromTensor(tensor); XlaResource* variable = expression->resource(); @@ -481,9 +488,9 @@ Status AssignVariableTensor(const Tensor& tensor, DataType type, TF_RETURN_IF_ERROR(variable->SetTypeAndShape(type, shape)); - XlaContext& xla_context = XlaContext::Get(ctx); - TF_ASSIGN_OR_RETURN(xla::Shape representation_shape, - xla_context.RepresentationShape(shape, type)); + TF_ASSIGN_OR_RETURN( + xla::Shape representation_shape, + ctx->compiler()->options().shape_representation_fn(shape, type)); xla::Shape xla_shape; TF_RETURN_IF_ERROR(TensorShapeToXLAShape(type, shape, &xla_shape)); if (!xla::ShapeUtil::Compatible(xla_shape, representation_shape)) { @@ -498,19 +505,15 @@ Status AssignVariableTensor(const Tensor& tensor, DataType type, Status XlaOpKernelContext::AssignVariable(int input_index, DataType type, xla::XlaOp handle) { TF_RET_CHECK(handle.valid()); - return AssignVariableTensor(context_->input(input_index), type, context_, - handle, builder()); + return AssignVariableTensor(context_->input(input_index), type, this, handle, + builder()); } Status XlaOpKernelContext::AssignVariable(absl::string_view name, DataType type, xla::XlaOp handle) { TF_RET_CHECK(handle.valid()); - return AssignVariableTensor(GetInputTensorByName(name), type, context_, - handle, builder()); -} - -XlaCompiler* XlaOpKernelContext::compiler() const { - return XlaContext::Get(context_).compiler(); + return AssignVariableTensor(GetInputTensorByName(name), type, this, handle, + builder()); } void XlaOpKernelContext::CtxFailure(const Status& s) { @@ -530,22 +533,22 @@ void XlaOpKernelContext::CtxFailureWithWarning(const char* file, int line, const xla::XlaComputation* XlaOpKernelContext::GetOrCreateMax( const DataType type) { - return XlaContext::Get(context_).GetOrCreateMax(type); + return xla_context()->GetOrCreateMax(type); } const xla::XlaComputation* XlaOpKernelContext::GetOrCreateMin( const DataType type) { - return XlaContext::Get(context_).GetOrCreateMin(type); + return xla_context()->GetOrCreateMin(type); } const xla::XlaComputation* XlaOpKernelContext::GetOrCreateAdd( const DataType type) { - return XlaContext::Get(context_).GetOrCreateAdd(type); + return xla_context()->GetOrCreateAdd(type); } const xla::XlaComputation* XlaOpKernelContext::GetOrCreateMul( const DataType type) { - return XlaContext::Get(context_).GetOrCreateMul(type); + return xla_context()->GetOrCreateMul(type); } const Tensor& XlaOpKernelContext::GetInputTensorByName(absl::string_view name) { diff --git a/tensorflow/compiler/tf2xla/xla_op_kernel.h b/tensorflow/compiler/tf2xla/xla_op_kernel.h index c06efa2c47..1858844bc0 100644 --- a/tensorflow/compiler/tf2xla/xla_op_kernel.h +++ b/tensorflow/compiler/tf2xla/xla_op_kernel.h @@ -60,6 +60,8 @@ class XlaOpKernelContext { public: explicit XlaOpKernelContext(OpKernelContext* context); + XlaContext* xla_context() const; + // Returns the XLA XlaBuilder containing the output of compilation. xla::XlaBuilder* builder() const; diff --git a/tensorflow/compiler/tf2xla/xla_resource.cc b/tensorflow/compiler/tf2xla/xla_resource.cc index a322eb9015..48a3c01272 100644 --- a/tensorflow/compiler/tf2xla/xla_resource.cc +++ b/tensorflow/compiler/tf2xla/xla_resource.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "tensorflow/compiler/tf2xla/shape_util.h" #include "tensorflow/compiler/tf2xla/sharding_util.h" #include "tensorflow/compiler/tf2xla/xla_context.h" @@ -39,9 +40,29 @@ namespace tensorflow { } } +/*static*/ std::unique_ptr XlaResource::CreateStack( + string name, DataType type, int64 max_size) { + return absl::make_unique( + XlaResource::kStack, /*arg_num=*/-1, std::move(name), type, TensorShape(), + /*initial_value=*/xla::XlaOp(), + /*max_array_size=*/max_size, + /*tensor_array_gradients=*/std::set{}, + /*tensor_array_multiple_writes_aggregate=*/false); +} + +/*static*/ std::unique_ptr XlaResource::CreateTensorArray( + string name, DataType type, TensorShape shape, xla::XlaOp initial_value, + int64 max_array_size) { + return absl::make_unique( + XlaResource::kTensorArray, /*arg_num=*/-1, std::move(name), type, shape, + initial_value, max_array_size, + /*tensor_array_gradients=*/std::set{}, + /*tensor_array_multiple_writes_aggregate=*/false); +} + XlaResource::XlaResource(Kind kind, int arg_num, string name, DataType type, TensorShape shape, const xla::XlaOp& initial_value, - int64 tensor_array_size, + int64 max_array_size, const std::set& tensor_array_gradients, bool tensor_array_multiple_writes_aggregate) : kind_(kind), @@ -51,7 +72,7 @@ XlaResource::XlaResource(Kind kind, int arg_num, string name, DataType type, shape_(std::move(shape)), value_(initial_value), initial_value_(initial_value), - tensor_array_size_(tensor_array_size), + max_array_size_(max_array_size), tensor_array_multiple_writes_aggregate_( tensor_array_multiple_writes_aggregate) { CHECK(kind_ != kInvalid); @@ -60,7 +81,7 @@ XlaResource::XlaResource(Kind kind, int arg_num, string name, DataType type, tensor_array_gradients_[gradient].reset(new XlaResource( /*kind=*/kTensorArray, /*arg_num=*/-1, /*name=*/absl::StrCat("TensorArrayGrad: ", name_), type_, shape_, - xla::XlaOp(), tensor_array_size_, /*tensor_array_gradients=*/{}, + xla::XlaOp(), max_array_size_, /*tensor_array_gradients=*/{}, /*tensor_array_multiple_writes_aggregate=*/true)); } } @@ -113,7 +134,7 @@ Status XlaResource::SetZeroValue(xla::XlaBuilder* builder) { } case kTensorArray: { TensorShape ta_shape; - ta_shape.AddDim(tensor_array_size_); + ta_shape.AddDim(max_array_size_); ta_shape.AppendShape(shape_); value_ = xla::Broadcast(XlaHelpers::Zero(builder, type_), ta_shape.dim_sizes()); @@ -121,7 +142,7 @@ Status XlaResource::SetZeroValue(xla::XlaBuilder* builder) { } case kStack: { TensorShape ta_shape; - ta_shape.AddDim(tensor_array_size_); + ta_shape.AddDim(max_array_size_); ta_shape.AppendShape(shape_); value_ = xla::Tuple(builder, {xla::Broadcast(XlaHelpers::Zero(builder, type_), @@ -146,14 +167,14 @@ Status XlaResource::GetOrCreateTensorArrayGradient(const string& source, std::unique_ptr& gradient = tensor_array_gradients_[source]; if (!gradient) { TensorShape ta_shape; - ta_shape.AddDim(tensor_array_size_); + ta_shape.AddDim(max_array_size_); ta_shape.AppendShape(shape_); xla::XlaOp gradient_value = xla::Broadcast(XlaHelpers::Zero(builder, type_), ta_shape.dim_sizes()); gradient.reset( new XlaResource(/*kind=*/kTensorArray, /*arg_num=*/-1, /*name=*/absl::StrCat("TensorArrayGrad: ", name_), - type_, shape_, gradient_value, tensor_array_size_, + type_, shape_, gradient_value, max_array_size_, /*tensor_array_gradients=*/{}, /*tensor_array_multiple_writes_aggregate=*/true)); } diff --git a/tensorflow/compiler/tf2xla/xla_resource.h b/tensorflow/compiler/tf2xla/xla_resource.h index 857b9a928b..736588bb8b 100644 --- a/tensorflow/compiler/tf2xla/xla_resource.h +++ b/tensorflow/compiler/tf2xla/xla_resource.h @@ -38,9 +38,18 @@ class XlaResource { }; static absl::string_view KindToString(Kind kind); + // Creates a new Stack resource. + static std::unique_ptr CreateStack(string name, DataType type, + int64 max_size); + + // Creates a new TensorArray resource. + static std::unique_ptr CreateTensorArray( + string name, DataType type, TensorShape shape, xla::XlaOp initial_value, + int64 max_array_size); + XlaResource(Kind kind, int arg_num, string name, DataType type, TensorShape shape, const xla::XlaOp& initial_value, - int64 tensor_array_size, + int64 max_array_size, const std::set& tensor_array_gradients, bool tensor_array_multiple_writes_aggregate); @@ -119,12 +128,12 @@ class XlaResource { // TODO(phawkins): refactor this code to use subclasses, rather than putting // kind-specific fields in XlaResource. - // 'tensor_array_size' stores the expected size of the TensorArray or Stack. + // 'max_array_size' stores the expected size of the TensorArray or Stack. // We need to store this since sometimes TensorArrays must be initialized // lazily since we do not know the element shape at construction time. // Used by both TensorArrays and Stacks. - int64 tensor_array_size() const { return tensor_array_size_; } - void set_tensor_array_size(int64 size) { tensor_array_size_ = size; } + int64 max_array_size() const { return max_array_size_; } + void set_max_array_size(int64 size) { max_array_size_ = size; } bool tensor_array_multiple_writes_aggregate() const { return tensor_array_multiple_writes_aggregate_; @@ -151,7 +160,7 @@ class XlaResource { xla::XlaOp value_; xla::XlaOp initial_value_; - int64 tensor_array_size_ = -1; + int64 max_array_size_ = -1; bool tensor_array_multiple_writes_aggregate_ = false; std::map> tensor_array_gradients_; -- GitLab From f382bd6279141fe169e5aa8ab0867f18840ee037 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 27 Nov 2018 08:55:01 -0800 Subject: [PATCH 388/672] Remove train.VocabInfo from TF 2.0 API. PiperOrigin-RevId: 222998560 --- .../python/training/warm_starting_util.py | 2 +- .../v2/tensorflow.train.-vocab-info.pbtxt | 43 ------------------- .../api/golden/v2/tensorflow.train.pbtxt | 4 -- tensorflow/tools/compatibility/renames_v2.py | 1 + 4 files changed, 2 insertions(+), 48 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-vocab-info.pbtxt diff --git a/tensorflow/python/training/warm_starting_util.py b/tensorflow/python/training/warm_starting_util.py index 3649d313ae..19dc04e8fb 100644 --- a/tensorflow/python/training/warm_starting_util.py +++ b/tensorflow/python/training/warm_starting_util.py @@ -32,7 +32,7 @@ from tensorflow.python.training import saver from tensorflow.python.util.tf_export import tf_export -@tf_export("train.VocabInfo") +@tf_export(v1=["train.VocabInfo"]) class VocabInfo( collections.namedtuple("VocabInfo", [ "new_vocab", diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-vocab-info.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-vocab-info.pbtxt deleted file mode 100644 index 39b946b82f..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-vocab-info.pbtxt +++ /dev/null @@ -1,43 +0,0 @@ -path: "tensorflow.train.VocabInfo" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "axis" - mtype: "" - } - member { - name: "backup_initializer" - mtype: "" - } - member { - name: "new_vocab" - mtype: "" - } - member { - name: "new_vocab_size" - mtype: "" - } - member { - name: "num_oov_buckets" - mtype: "" - } - member { - name: "old_vocab" - mtype: "" - } - member { - name: "old_vocab_size" - mtype: "" - } - member_method { - name: "__init__" - } - member_method { - name: "count" - } - member_method { - name: "index" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt index 91e1e0582e..d47bc09e66 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt @@ -208,10 +208,6 @@ tf_module { name: "Supervisor" mtype: "" } - member { - name: "VocabInfo" - mtype: "" - } member { name: "WorkerSessionCreator" mtype: "" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index fc4b19fb1c..c5efc04d04 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -588,6 +588,7 @@ renames = { 'tf.train.Saver': 'tf.compat.v1.train.Saver', 'tf.train.SaverDef': 'tf.compat.v1.train.SaverDef', 'tf.train.SyncReplicasOptimizer': 'tf.compat.v1.train.SyncReplicasOptimizer', + 'tf.train.VocabInfo': 'tf.compat.v1.train.VocabInfo', 'tf.train.add_queue_runner': 'tf.compat.v1.train.add_queue_runner', 'tf.train.assert_global_step': 'tf.compat.v1.train.assert_global_step', 'tf.train.basic_train_loop': 'tf.compat.v1.train.basic_train_loop', -- GitLab From 7753011748cfd804b0ea48e66e36f3f3ed3805be Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 27 Nov 2018 09:44:57 -0800 Subject: [PATCH 389/672] Temporarily disable unit tests for half precision - investigating possible TRT bug --- tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 471382894c..c6cd765887 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -2040,7 +2040,9 @@ TEST_F(OpConverterTest, ConvertSquare) { // OK. Note that kINT32 is not supported by IElementWiseLayer, so we don't // test DT_INT32 type here. TestConvertSquare(this); - TestConvertSquare(this); + // TODO(tmorris): Looks like there may be a bug with this layer for FP16 + // inputs. Disabling for now. + // TestConvertSquare(this); } } // namespace convert -- GitLab From 249bd81c3c3aa8dc89d8fcef8927df49fc8c42ec Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Tue, 27 Nov 2018 09:52:46 -0800 Subject: [PATCH 390/672] Automated rollback of commit 5bb5d6db8ac8f48ba2636ae18844cb584b837904 PiperOrigin-RevId: 223007492 --- tensorflow/python/ops/resource_variable_ops.py | 2 +- tensorflow/python/ops/variables.py | 9 ++------- third_party/libxsmm.BUILD | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index f9faa3e945..5c74dffb05 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -1433,7 +1433,7 @@ def _from_proto_fn(v, import_scope=None): """Creates Variable or ResourceVariable from VariableDef as needed.""" if v.is_resource: return ResourceVariable.from_proto(v, import_scope=import_scope) - return variables.RefVariable.from_proto(v, import_scope=import_scope) + return variables.Variable.from_proto(v, import_scope=import_scope) ops.register_proto_function( diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index a001374e9a..f72b19bcdd 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -968,7 +968,8 @@ class Variable(six.with_metaclass(VariableMetaclass, @staticmethod def from_proto(variable_def, import_scope=None): """Returns a `Variable` object created from `variable_def`.""" - raise NotImplementedError + return RefVariable(variable_def=variable_def, + import_scope=import_scope) class SaveSliceInfo(object): """Information on how to save this Variable as a slice. @@ -2343,12 +2344,6 @@ class RefVariable(VariableV1): else: return None - @staticmethod - def from_proto(variable_def, import_scope=None): - """Returns a `Variable` object created from `variable_def`.""" - return RefVariable(variable_def=variable_def, - import_scope=import_scope) - def __iadd__(self, other): logging.log_first_n( logging.WARN, diff --git a/third_party/libxsmm.BUILD b/third_party/libxsmm.BUILD index ee49d281ab..dc7dcc9517 100644 --- a/third_party/libxsmm.BUILD +++ b/third_party/libxsmm.BUILD @@ -38,8 +38,8 @@ genrule( ":libxsmm_interface", ], visibility = [ - "//third_party/eigen3:__pkg__", "//tensorflow/core/kernels:__pkg__", + "//third_party/eigen3:__pkg__", ], ) -- GitLab From bfd9b3254a0e1a8782e63a36fe03ab748b7cbafe Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 27 Nov 2018 09:58:23 -0800 Subject: [PATCH 391/672] Fix clang-format issues --- tensorflow/contrib/tensorrt/convert/convert_nodes.cc | 12 ++++++------ .../contrib/tensorrt/convert/convert_nodes_test.cc | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index b1fa6a51d4..4238ffea79 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -1985,7 +1985,8 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { } if (!inputs.at(0).is_tensor()) { return tensorflow::errors::Unimplemented( - node_def.op(), " is only implemented for tensors, at ", node_def.name()); + node_def.op(), " is only implemented for tensors, at ", + node_def.name()); } static const std::unordered_map ops{ {"Relu", nvinfer1::ActivationType::kRELU}, @@ -1994,9 +1995,9 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { }; auto op_pair = ops.find(node_def.op()); if (op_pair == ops.end()) { - return tensorflow::errors::Unimplemented( - "Activation op: ", node_def.op(), " not supported at: ", - node_def.name()); + return tensorflow::errors::Unimplemented("Activation op: ", node_def.op(), + " not supported at: ", + node_def.name()); } if (params->validation_only) return tensorflow::Status::OK(); @@ -2004,8 +2005,7 @@ tensorflow::Status ConvertActivation(OpConverterParams* params) { const nvinfer1::ITensor* tensor = inputs.at(0).tensor(); nvinfer1::IActivationLayer* layer = params->converter->network()->addActivation( - *const_cast(tensor), - op_pair->second); + *const_cast(tensor), op_pair->second); TFTRT_RETURN_ERROR_IF_NULLPTR(layer, node_def.name()); nvinfer1::ITensor* output_tensor = layer->getOutput(0); // Set quantization range for output of Sigmoid, Tanh. diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 45e901bf5b..724dc0e224 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -1968,9 +1968,8 @@ TEST_F(OpConverterTest, ConvertActivation) { { // Input list is empty, should fail. NodeDef node_def = MakeNodeDef("my_act", "Relu", {}); - RunValidationAndConversion( - node_def, error::INVALID_ARGUMENT, - "Relu expects one input, at my_act"); + RunValidationAndConversion(node_def, error::INVALID_ARGUMENT, + "Relu expects one input, at my_act"); } { // Input is weights, should fail. -- GitLab From edf88fcda80a19be56d396075a8fa2b4e822b9a4 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 09:59:18 -0800 Subject: [PATCH 392/672] Remove ad-hoc vmodule test from tests. PiperOrigin-RevId: 223008525 --- tensorflow/core/BUILD | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 437c368356..6821ac7eb7 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -3429,7 +3429,6 @@ tf_cc_tests( "platform/stacktrace_handler_test.cc", "platform/subprocess_test.cc", "platform/vmodule_benchmark_test.cc", - "platform/vmodule_test.cc", ], deps = [ ":lib", @@ -3443,6 +3442,20 @@ tf_cc_tests( ], ) +tf_cc_test( + name = "vmodule_test", + srcs = ["platform/vmodule_test.cc"], + tags = ["optonly"], + deps = [ + ":lib", + ":lib_internal", + ":lib_test_internal", + ":protos_all_cc", + ":test", + "//third_party/eigen3", + ], +) + tf_cc_test( name = "lib_random_random_distributions_test", srcs = ["lib/random/random_distributions_test.cc"], -- GitLab From 3c4b9f19a9d85d899dd312e8c945b47bb2341e5a Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Tue, 27 Nov 2018 10:07:07 -0800 Subject: [PATCH 393/672] Fix compilation issue --- tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 724dc0e224..0096bf99cd 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -1998,7 +1998,7 @@ TEST_F(OpConverterTest, ConvertActivation) { auto act = ops::Tanh(s.WithOpName("my_act"), input); return act.operation.node()->def(); } - ASSERT_TRUE(false); + EXPECT_TRUE(false); return NodeDef(); }; // Get expected output for activation layer. @@ -2010,7 +2010,7 @@ TEST_F(OpConverterTest, ConvertActivation) { } else if (op_name == "Tanh") { return std::tanh(input); } - ASSERT_TRUE(false); + EXPECT_TRUE(false); return 0; }; @@ -2027,7 +2027,7 @@ TEST_F(OpConverterTest, ConvertActivation) { const std::vector input_data = {-100, -2, -1, 0, 1, 100}; std::vector output_data(6); - BuildAndRun("input", input_data, "my_act", &output_data); + BuildAndRun({{"input", input_data}}, "my_act", &output_data); for (int i = 0; i < input_data.size(); i++) { const float expected_output = get_act_output(op_name, input_data[i]); EXPECT_FLOAT_EQ(output_data[i], expected_output); -- GitLab From b17d53c0cd07bbae46a55dc9c12d3f48a1c19604 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 27 Nov 2018 10:05:22 -0800 Subject: [PATCH 394/672] Replace a few calls of Session `run` with `evaluate` In order to support tests running in eager mode we need to avoid unnecessary use of Sessions in tests. This moves to remove some of the uses of the `run` function in favor of `evaluate`. PiperOrigin-RevId: 223009795 --- .../compiler/tests/categorical_op_test.py | 20 +- tensorflow/compiler/tests/concat_ops_test.py | 20 +- tensorflow/compiler/tests/dense_layer_test.py | 6 +- tensorflow/compiler/tests/eager_test.py | 4 +- tensorflow/compiler/tests/function_test.py | 12 +- tensorflow/compiler/tests/listdiff_op_test.py | 4 +- tensorflow/compiler/tests/lstm_test.py | 8 +- tensorflow/compiler/tests/placeholder_test.py | 2 +- tensorflow/compiler/tests/random_ops_test.py | 16 +- .../tests/stateless_random_ops_test.py | 2 +- .../compiler/tests/tensor_array_ops_test.py | 2 +- .../compiler/tests/variable_ops_test.py | 42 +- tensorflow/compiler/tests/xla_device_test.py | 2 +- .../autograph/integration_tests/keras_test.py | 4 +- .../integration_tests/list_literals_test.py | 2 +- .../speech_commands/input_data_test.py | 2 +- .../speech_commands/label_wav_test.py | 2 +- .../speech_commands/wav_to_features_test.py | 2 +- .../lstm/unidirectional_sequence_lstm_test.py | 2 +- .../autograph/converters/asserts_test.py | 2 +- .../autograph/converters/call_trees_test.py | 4 +- .../python/autograph/converters/lists_test.py | 8 +- .../converters/side_effect_guards_test.py | 30 +- .../autograph/converters/slices_test.py | 2 +- .../python/autograph/core/errors_test.py | 6 +- tensorflow/python/autograph/impl/api_test.py | 46 +- .../autograph/lang/special_functions_test.py | 12 +- .../autograph/operators/control_flow_test.py | 14 +- .../operators/data_structures_test.py | 20 +- .../autograph/operators/exceptions_test.py | 6 +- .../autograph/operators/logical_test.py | 14 +- .../autograph/operators/py_builtins_test.py | 28 +- .../python/autograph/operators/slices_test.py | 8 +- .../python/autograph/utils/misc_test.py | 4 +- .../python/autograph/utils/py_func_test.py | 18 +- .../autograph/utils/tensor_list_test.py | 8 +- .../client/session_clusterspec_prop_test.py | 6 +- .../python/client/session_partial_run_test.py | 2 +- tensorflow/python/client/timeline_test.py | 4 +- tensorflow/python/client/virtual_gpu_test.py | 2 +- .../bucket_by_sequence_length_test.py | 14 +- .../kernel_tests/copy_to_device_test.py | 133 ++-- .../experimental/kernel_tests/counter_test.py | 12 +- .../dense_to_sparse_batch_test.py | 16 +- .../directed_interleave_dataset_test.py | 14 +- .../kernel_tests/enumerate_dataset_test.py | 8 +- .../kernel_tests/filter_dataset_op_test.py | 4 +- .../function_buffering_resource_test.py | 70 +- .../kernel_tests/group_by_reducer_test.py | 10 +- .../kernel_tests/group_by_window_test.py | 56 +- .../kernel_tests/ignore_errors_test.py | 24 +- .../kernel_tests/indexed_dataset_ops_test.py | 11 +- .../make_batched_features_dataset_test.py | 6 +- .../kernel_tests/make_csv_dataset_test.py | 12 +- .../make_tf_record_dataset_test.py | 12 +- .../kernel_tests/map_and_batch_test.py | 68 +- .../kernel_tests/map_defun_op_test.py | 6 +- .../optimization/model_dataset_test.py | 4 +- .../optimization/optimize_dataset_test.py | 4 +- .../kernel_tests/override_threadpool_test.py | 4 +- .../kernel_tests/parallel_interleave_test.py | 70 +- .../kernel_tests/prefetch_to_device_test.py | 40 +- .../experimental/kernel_tests/scan_test.py | 12 +- .../range_dataset_serialization_test.py | 30 +- .../serialization_integration_test.py | 6 +- .../shuffle_dataset_serialization_test.py | 4 +- .../kernel_tests/shuffle_and_repeat_test.py | 6 +- .../experimental/kernel_tests/sleep_test.py | 6 +- .../kernel_tests/sql_dataset_test.py | 169 ++--- .../kernel_tests/stats_dataset_ops_test.py | 137 ++-- .../experimental/kernel_tests/unbatch_test.py | 34 +- .../experimental/kernel_tests/unique_test.py | 6 +- .../multi_device_iterator_test.py | 115 ++-- tensorflow/python/data/util/convert_test.py | 146 ++-- .../python/debug/cli/analyzer_cli_test.py | 2 +- .../lib/debug_graph_reconstruction_test.py | 14 +- .../debug/lib/session_debug_multi_gpu_test.py | 2 +- .../python/debug/lib/source_utils_test.py | 4 +- .../python/distribute/input_ops_test.py | 19 +- tensorflow/python/eager/def_function_test.py | 8 +- .../python/eager/function_gradients_test.py | 2 +- tensorflow/python/eager/function_test.py | 4 +- .../feature_column/feature_column_test.py | 8 +- .../feature_column/feature_column_v2_test.py | 11 +- .../python/framework/file_system_test.py | 2 +- tensorflow/python/framework/function_test.py | 62 +- .../python/framework/graph_util_test.py | 12 +- tensorflow/python/framework/importer_test.py | 14 +- .../python/framework/meta_graph_test.py | 18 +- tensorflow/python/framework/ops_test.py | 16 +- .../python/framework/smart_cond_test.py | 8 +- .../python/framework/sparse_tensor_test.py | 2 +- tensorflow/python/framework/subscribe_test.py | 28 +- .../python/framework/tensor_util_test.py | 2 +- .../python/grappler/constant_folding_test.py | 2 +- .../python/grappler/layout_optimizer_test.py | 48 +- .../python/grappler/memory_optimizer_test.py | 12 +- tensorflow/python/keras/backend_test.py | 2 +- .../python/keras/layers/recurrent_test.py | 4 +- tensorflow/python/keras/metrics_test.py | 10 +- .../python/keras/optimizer_v2/ftrl_test.py | 32 +- .../python/kernel_tests/accumulate_n_test.py | 2 +- .../python/kernel_tests/aggregate_ops_test.py | 2 +- .../python/kernel_tests/array_ops_test.py | 14 +- .../python/kernel_tests/attention_ops_test.py | 2 +- .../python/kernel_tests/barrier_ops_test.py | 6 +- .../python/kernel_tests/base64_ops_test.py | 2 +- .../python/kernel_tests/basic_gpu_test.py | 8 +- .../boosted_trees/quantile_ops_test.py | 14 +- .../boosted_trees/stats_ops_test.py | 58 +- .../python/kernel_tests/bucketize_op_test.py | 8 +- .../candidate_sampler_ops_test.py | 2 +- .../python/kernel_tests/cast_op_test.py | 4 +- .../python/kernel_tests/cholesky_op_test.py | 4 +- .../python/kernel_tests/concat_op_test.py | 126 ++-- .../conditional_accumulator_test.py | 14 +- .../kernel_tests/control_flow_ops_py_test.py | 92 +-- .../python/kernel_tests/conv_ops_3d_test.py | 10 +- .../python/kernel_tests/conv_ops_test.py | 16 +- .../python/kernel_tests/ctc_loss_op_test.py | 43 +- .../kernel_tests/cwise_ops_binary_test.py | 14 +- .../python/kernel_tests/cwise_ops_test.py | 14 +- .../kernel_tests/decode_image_op_test.py | 8 +- .../kernel_tests/decode_jpeg_op_test.py | 6 +- .../dense_update_ops_no_tsan_test.py | 8 +- .../kernel_tests/depthtospace_op_test.py | 2 +- .../kernel_tests/depthwise_conv_op_test.py | 6 +- .../kernel_tests/determinant_op_test.py | 2 +- .../distributions/categorical_test.py | 4 +- .../distributions/special_math_test.py | 4 +- .../kernel_tests/distributions/util_test.py | 4 +- .../kernel_tests/division_future_test.py | 2 +- .../python/kernel_tests/division_past_test.py | 2 +- .../kernel_tests/draw_bounding_box_op_test.py | 2 +- .../kernel_tests/dynamic_partition_op_test.py | 32 +- .../python/kernel_tests/embedding_ops_test.py | 4 +- .../python/kernel_tests/fifo_queue_test.py | 134 ++-- .../fractional_avg_pool_op_test.py | 4 +- .../fractional_max_pool_op_test.py | 4 +- .../kernel_tests/functional_ops_test.py | 52 +- .../kernel_tests/gradient_correctness_test.py | 8 +- .../python/kernel_tests/init_ops_test.py | 16 +- .../python/kernel_tests/inplace_ops_test.py | 2 +- tensorflow/python/kernel_tests/io_ops_test.py | 4 +- .../linalg/linear_operator_circulant_test.py | 4 +- .../linalg/linear_operator_diag_test.py | 4 +- .../linalg/linear_operator_identity_test.py | 12 +- .../linalg/linear_operator_util_test.py | 4 +- .../python/kernel_tests/list_ops_test.py | 2 +- .../python/kernel_tests/listdiff_op_test.py | 2 +- .../python/kernel_tests/lookup_ops_test.py | 10 +- tensorflow/python/kernel_tests/losses_test.py | 4 +- .../matrix_exponential_op_test.py | 2 +- .../kernel_tests/matrix_inverse_op_test.py | 2 +- .../kernel_tests/matrix_logarithm_op_test.py | 2 +- .../kernel_tests/matrix_solve_op_test.py | 2 +- .../matrix_square_root_op_test.py | 2 +- .../python/kernel_tests/metrics_test.py | 457 ++++++------- .../neon_depthwise_conv_op_test.py | 6 +- .../python/kernel_tests/norm_op_test.py | 2 +- .../kernel_tests/nth_element_op_test.py | 2 +- .../kernel_tests/padding_fifo_queue_test.py | 124 ++-- .../parse_single_example_op_test.py | 2 +- .../python/kernel_tests/parsing_ops_test.py | 6 +- .../kernel_tests/pooling_ops_3d_test.py | 2 +- .../python/kernel_tests/pooling_ops_test.py | 2 +- .../kernel_tests/priority_queue_test.py | 22 +- .../python/kernel_tests/py_func_test.py | 14 +- tensorflow/python/kernel_tests/qr_op_test.py | 4 +- .../random/multinomial_op_big_test.py | 6 +- .../kernel_tests/random/random_gamma_test.py | 2 +- .../kernel_tests/random/random_ops_test.py | 12 +- .../random/random_poisson_test.py | 2 +- .../random/random_shuffle_queue_test.py | 118 ++-- .../random/stateless_random_ops_test.py | 2 +- .../python/kernel_tests/reader_ops_test.py | 628 +++++++++--------- .../python/kernel_tests/record_input_test.py | 16 +- .../kernel_tests/reduce_benchmark_test.py | 4 +- .../python/kernel_tests/reduction_ops_test.py | 22 +- .../python/kernel_tests/relu_op_test.py | 2 +- .../resource_variable_ops_test.py | 8 +- .../kernel_tests/scatter_nd_ops_test.py | 26 +- .../kernel_tests/self_adjoint_eig_op_test.py | 4 +- .../python/kernel_tests/session_ops_test.py | 46 +- tensorflow/python/kernel_tests/sets_test.py | 8 +- .../python/kernel_tests/shape_ops_test.py | 4 +- .../signal/reconstruction_ops_test.py | 8 +- .../kernel_tests/signal/spectral_ops_test.py | 8 +- .../python/kernel_tests/slice_op_test.py | 6 +- .../kernel_tests/spacetodepth_op_test.py | 2 +- .../python/kernel_tests/sparse_add_op_test.py | 31 +- .../kernel_tests/sparse_concat_op_test.py | 16 +- .../sparse_conditional_accumulator_test.py | 36 +- .../kernel_tests/sparse_cross_op_test.py | 34 +- .../python/kernel_tests/sparse_ops_test.py | 34 +- .../kernel_tests/sparse_reorder_op_test.py | 4 +- .../kernel_tests/sparse_reshape_op_test.py | 4 +- .../sparse_serialization_ops_test.py | 2 +- .../sparse_tensors_map_ops_test.py | 15 +- .../kernel_tests/sparse_xent_op_test.py | 10 +- .../python/kernel_tests/stack_ops_test.py | 10 +- .../kernel_tests/string_length_op_test.py | 6 +- .../kernel_tests/string_split_op_test.py | 28 +- .../kernel_tests/string_strip_op_test.py | 6 +- .../kernel_tests/summary_v1_audio_op_test.py | 2 +- .../kernel_tests/summary_v1_image_op_test.py | 4 +- .../kernel_tests/summary_v1_ops_test.py | 6 +- .../kernel_tests/summary_v1_tensor_op_test.py | 14 +- tensorflow/python/kernel_tests/svd_op_test.py | 6 +- .../python/kernel_tests/template_test.py | 8 +- .../kernel_tests/tensor_array_ops_test.py | 8 +- .../python/kernel_tests/topk_op_test.py | 2 +- .../kernel_tests/unicode_transcode_op_test.py | 56 +- .../python/kernel_tests/unique_op_test.py | 24 +- .../python/kernel_tests/variable_ops_test.py | 2 +- .../kernel_tests/variable_scope_test.py | 34 +- .../python/kernel_tests/variables_test.py | 18 +- .../python/kernel_tests/while_v2_test.py | 56 +- .../python/kernel_tests/xent_op_test.py | 10 +- .../python/layers/convolutional_test.py | 16 +- tensorflow/python/layers/core_test.py | 2 +- .../python/layers/normalization_test.py | 139 ++-- tensorflow/python/ops/bitwise_ops_test.py | 5 +- tensorflow/python/ops/clip_ops_test.py | 4 +- .../python/ops/control_flow_ops_test.py | 16 +- tensorflow/python/ops/gradients_test.py | 28 +- tensorflow/python/ops/image_grad_test.py | 8 +- tensorflow/python/ops/image_ops_test.py | 93 +-- tensorflow/python/ops/init_ops_test.py | 4 +- tensorflow/python/ops/math_ops_test.py | 4 +- tensorflow/python/ops/nccl_ops_test.py | 2 +- tensorflow/python/ops/nn_batchnorm_test.py | 13 +- .../python/ops/nn_fused_batchnorm_test.py | 8 +- .../ops/parallel_for/control_flow_ops_test.py | 6 +- .../python/ops/parallel_for/gradients_test.py | 10 +- .../python/ops/quantized_conv_ops_test.py | 2 +- tensorflow/python/ops/quantized_ops_test.py | 4 +- .../ops/ragged/ragged_gather_nd_op_test.py | 2 +- .../ops/ragged/ragged_segment_op_test.py | 8 +- .../ragged_tensor_bounding_shape_op_test.py | 30 +- .../python/ops/ragged/ragged_tensor_test.py | 110 +-- .../python/profiler/model_analyzer_test.py | 30 +- .../python/profiler/profile_context_test.py | 20 +- tensorflow/python/saved_model/loader_test.py | 8 +- .../python/saved_model/saved_model_test.py | 42 +- .../python/saved_model/simple_save_test.py | 2 +- tensorflow/python/tools/strip_unused_test.py | 4 +- tensorflow/python/training/adagrad_da_test.py | 16 +- .../training/basic_session_run_hooks_test.py | 32 +- .../python/training/checkpoint_ops_test.py | 2 +- tensorflow/python/training/ftrl_test.py | 36 +- tensorflow/python/training/input_test.py | 108 +-- .../training/learning_rate_decay_test.py | 33 +- .../training/learning_rate_decay_v2_test.py | 33 +- .../python/training/monitored_session_test.py | 16 +- .../python/training/moving_averages_test.py | 14 +- .../python/training/proximal_adagrad_test.py | 20 +- .../proximal_gradient_descent_test.py | 16 +- .../python/training/quantize_training_test.py | 4 +- tensorflow/python/training/saver_test.py | 78 +-- ...lib_same_variables_clear_container_test.py | 8 +- .../training/server_lib_sparse_job_test.py | 2 +- tensorflow/python/training/supervisor_test.py | 10 +- .../training/warm_starting_util_test.py | 80 +-- 264 files changed, 3055 insertions(+), 2968 deletions(-) diff --git a/tensorflow/compiler/tests/categorical_op_test.py b/tensorflow/compiler/tests/categorical_op_test.py index f4918e50dc..5d5e486f61 100644 --- a/tensorflow/compiler/tests/categorical_op_test.py +++ b/tensorflow/compiler/tests/categorical_op_test.py @@ -57,11 +57,11 @@ class CategoricalTest(xla_test.XLATestCase): Returns: Frequencies from sampled classes; shape [batch_size, num_classes]. """ - with self.cached_session() as sess, self.test_scope(): + with self.cached_session(), self.test_scope(): random_seed.set_random_seed(1618) op = random_ops.multinomial(logits, num_samples, output_dtype=dtypes.int32) - d = sess.run(op) + d = self.evaluate(op) batch_size, num_classes = logits.shape freqs_mat = [] @@ -80,15 +80,15 @@ class CategoricalTest(xla_test.XLATestCase): def _testRngIsNotConstant(self, rng, dtype, output_dtype): # Tests that 'rng' does not always return the same value. - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): x = rng(dtype, output_dtype) # The random-number generator, if working correctly, should produce the # same output multiple times with low probability. - y = sess.run(x) - z = sess.run(x) - w = sess.run(x) + y = self.evaluate(x) + z = self.evaluate(x) + w = self.evaluate(x) # We use exact equality here. If the random-number generator is producing # deterministic output, all three outputs will be bitwise identical. @@ -108,12 +108,12 @@ class CategoricalTest(xla_test.XLATestCase): def testCategoricalIsInRange(self): for dtype in self.float_types: for output_dtype in self.output_dtypes(): - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): x = random_ops.multinomial( array_ops.ones(shape=[1, 20], dtype=dtype), 1000, output_dtype=output_dtype) - y = sess.run(x) + y = self.evaluate(x) self.assertTrue((y >= 0).sum() == 1000) self.assertTrue((y < 20).sum() == 1000) @@ -170,11 +170,11 @@ class CategoricalTest(xla_test.XLATestCase): self.assertEqual(s0 == s1, np.all(v0 == v1)) def testEmpty(self): - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): x = random_ops.multinomial( array_ops.zeros([42, 40]), 0, output_dtype=dtypes.int32) - y = sess.run(x) + y = self.evaluate(x) self.assertEqual(y.shape, (42, 0)) def testEmptyStateless(self): diff --git a/tensorflow/compiler/tests/concat_ops_test.py b/tensorflow/compiler/tests/concat_ops_test.py index 30fbe6f701..2187f57960 100644 --- a/tensorflow/compiler/tests/concat_ops_test.py +++ b/tensorflow/compiler/tests/concat_ops_test.py @@ -254,7 +254,7 @@ class ConcatTest(xla_test.XLATestCase): def DISABLED_testZeroSize(self): # Verify that concat doesn't crash and burn for zero size inputs np.random.seed(7) - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): for shape0 in (), (2,): axis = len(shape0) @@ -270,7 +270,7 @@ class ConcatTest(xla_test.XLATestCase): self.assertAllEqual(c.eval(), correct) # Check gradients dc = np.random.randn(*c.get_shape().as_list()) - dxs = sess.run(gradients_impl.gradients(c, xs, dc)) + dxs = self.evaluate(gradients_impl.gradients(c, xs, dc)) self.assertAllEqual(dc, np.concatenate(dxs, axis=axis)) def testConcatTuple(self): @@ -330,47 +330,47 @@ class ConcatTest(xla_test.XLATestCase): class ConcatOffsetTest(xla_test.XLATestCase): def testBasic(self): - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): cdim = constant_op.constant(1, dtypes.int32) s0 = constant_op.constant([2, 3, 5], dtypes.int32) s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = sess.run(off) + ans = self.evaluate(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) class PackTest(xla_test.XLATestCase): def testBasic(self): - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): s0 = constant_op.constant([2, 3, 5], dtypes.int32) s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) packed = array_ops.stack([s0, s1, s2]) - ans = sess.run(packed) + ans = self.evaluate(packed) self.assertAllEqual(ans, [[2, 3, 5], [2, 7, 5], [2, 20, 5]]) def testScalars(self): - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): s0 = constant_op.constant(2, dtypes.int32) s1 = constant_op.constant(3, dtypes.int32) s2 = constant_op.constant(5, dtypes.int32) packed = array_ops.stack([s0, s1, s2]) - ans = sess.run(packed) + ans = self.evaluate(packed) self.assertAllEqual(ans, [2, 3, 5]) def testEmpty(self): - with self.cached_session() as sess: + with self.cached_session(): with self.test_scope(): s0 = constant_op.constant([[]], dtypes.int32) s1 = constant_op.constant([[]], dtypes.int32) s2 = constant_op.constant([[]], dtypes.int32) packed = array_ops.stack([s0, s1, s2]) - ans = sess.run(packed) + ans = self.evaluate(packed) self.assertAllEqual(ans, [[[]], [[]], [[]]]) diff --git a/tensorflow/compiler/tests/dense_layer_test.py b/tensorflow/compiler/tests/dense_layer_test.py index 23c94cf245..bf5ea7b1fb 100644 --- a/tensorflow/compiler/tests/dense_layer_test.py +++ b/tensorflow/compiler/tests/dense_layer_test.py @@ -72,7 +72,7 @@ class DenseLayerTest(test.TestCase): x = array_ops.placeholder(shape=[None, None, 3], dtype=np.float32) y = layers.dense(x, 3) - sess.run(variables.initialize_all_variables()) + self.evaluate(variables.initialize_all_variables()) run_metadata = config_pb2.RunMetadata() test_utils.RunWithWarmup( sess, @@ -97,7 +97,7 @@ class DenseLayerTest(test.TestCase): with jit_scope(): y = layers.dense(x, 3) - sess.run(variables.initialize_all_variables()) + self.evaluate(variables.initialize_all_variables()) run_metadata = config_pb2.RunMetadata() test_utils.RunWithWarmup( sess, @@ -126,7 +126,7 @@ class DenseLayerTest(test.TestCase): with jit_scope(): y = layers.dense(x, 3) - sess.run(variables.initialize_all_variables()) + self.evaluate(variables.initialize_all_variables()) run_metadata = config_pb2.RunMetadata() test_utils.RunWithWarmup( sess, diff --git a/tensorflow/compiler/tests/eager_test.py b/tensorflow/compiler/tests/eager_test.py index 63cee550fd..2af32b537b 100644 --- a/tensorflow/compiler/tests/eager_test.py +++ b/tensorflow/compiler/tests/eager_test.py @@ -101,12 +101,12 @@ class EagerTest(xla_test.XLATestCase): self.assertAllEqual(15, product) # Run some ops graphly - with context.graph_mode(), self.cached_session() as sess: + with context.graph_mode(), self.cached_session(): with self.test_scope(): three = constant_op.constant(3) five = constant_op.constant(5) product = three * five - self.assertAllEqual(15, sess.run(product)) + self.assertAllEqual(15, self.evaluate(product)) def testDegenerateSlices(self): with self.test_scope(): diff --git a/tensorflow/compiler/tests/function_test.py b/tensorflow/compiler/tests/function_test.py index b1891b918c..a61827c2ae 100644 --- a/tensorflow/compiler/tests/function_test.py +++ b/tensorflow/compiler/tests/function_test.py @@ -40,7 +40,7 @@ class FunctionTest(xla_test.XLATestCase): bval = np.array([5, 6, 7, 8]).reshape([2, 2]).astype(np.float32) expected = APlus2B(aval, bval) - with self.cached_session() as sess: + with self.cached_session(): @function.Defun(dtypes.float32, dtypes.float32) def Foo(a, b): @@ -50,7 +50,7 @@ class FunctionTest(xla_test.XLATestCase): b = constant_op.constant(bval, name="b") with self.test_scope(): call_f = Foo(a, b) - result = sess.run(call_f) + result = self.evaluate(call_f) self.assertAllClose(result, expected, rtol=1e-3) def testNestedFunctions(self): @@ -66,7 +66,7 @@ class FunctionTest(xla_test.XLATestCase): bval = np.array([4, 3, 2, 1]).reshape([2, 2]).astype(np.float32) expected = APlus2B(aval, bval) - with self.cached_session() as sess: + with self.cached_session(): @function.Defun(dtypes.float32, dtypes.float32) def Foo(a, b): @@ -76,7 +76,7 @@ class FunctionTest(xla_test.XLATestCase): b = constant_op.constant(bval, name="b") with self.test_scope(): call_g = Foo(a, b) - result = sess.run(call_g) + result = self.evaluate(call_g) self.assertAllClose(result, expected, rtol=1e-3) def testFunctionMultipleRetvals(self): @@ -90,7 +90,7 @@ class FunctionTest(xla_test.XLATestCase): bval = np.array([5, 6, 7, 8]).reshape([2, 2]).astype(np.float32) expected = Func(aval, bval) - with self.cached_session() as sess: + with self.cached_session(): @function.Defun(dtypes.float32, dtypes.float32) def Foo(a, b): @@ -100,7 +100,7 @@ class FunctionTest(xla_test.XLATestCase): b = constant_op.constant(bval, name="b") with self.test_scope(): call_f = Foo(a, b) - result = sess.run(call_f) + result = self.evaluate(call_f) self.assertAllClose(result, expected, rtol=1e-3) def testCompileTimeConstantsInDefun(self): diff --git a/tensorflow/compiler/tests/listdiff_op_test.py b/tensorflow/compiler/tests/listdiff_op_test.py index 58622114e4..0210201fa7 100644 --- a/tensorflow/compiler/tests/listdiff_op_test.py +++ b/tensorflow/compiler/tests/listdiff_op_test.py @@ -33,13 +33,13 @@ class ListDiffTest(xla_test.XLATestCase): def _testListDiff(self, x, y, out, idx): for dtype in [dtypes.int32, dtypes.int64]: for index_dtype in [dtypes.int32, dtypes.int64]: - with self.cached_session() as sess: + with self.cached_session(): x_tensor = ops.convert_to_tensor(x, dtype=dtype) y_tensor = ops.convert_to_tensor(y, dtype=dtype) with self.test_scope(): out_tensor, idx_tensor = array_ops.listdiff( x_tensor, y_tensor, out_idx=index_dtype) - tf_out, tf_idx = sess.run([out_tensor, idx_tensor]) + tf_out, tf_idx = self.evaluate([out_tensor, idx_tensor]) self.assertAllEqual(out, tf_out) self.assertAllEqual(idx, tf_idx) self.assertEqual(1, out_tensor.get_shape().ndims) diff --git a/tensorflow/compiler/tests/lstm_test.py b/tensorflow/compiler/tests/lstm_test.py index 265c0b6d14..776ed899e6 100644 --- a/tensorflow/compiler/tests/lstm_test.py +++ b/tensorflow/compiler/tests/lstm_test.py @@ -88,8 +88,8 @@ class LSTMTest(test.TestCase): (basename, m_prev_scalar, c_prev_scalar, pad_scalar)) # Initialize variables and run the unrolled LSTM step. - sess.run(variables.global_variables_initializer()) - return sess.run([m, c]) + self.evaluate(variables.global_variables_initializer()) + return self.evaluate([m, c]) def testLSTMCell(self): # Run with all-0 weights, no padding. @@ -173,8 +173,8 @@ class LSTMTest(test.TestCase): (basename, m_init_scalar, c_init_scalar, pad_scalar)) # Initialize variables and run the unrolled LSTM layer. - sess.run(variables.global_variables_initializer()) - return sess.run(out_seq) + self.evaluate(variables.global_variables_initializer()) + return self.evaluate(out_seq) def testLSTMLayer(self): # Run with all-0 weights, no padding. diff --git a/tensorflow/compiler/tests/placeholder_test.py b/tensorflow/compiler/tests/placeholder_test.py index 77bb839409..9671ae0ae9 100644 --- a/tensorflow/compiler/tests/placeholder_test.py +++ b/tensorflow/compiler/tests/placeholder_test.py @@ -33,7 +33,7 @@ class PlaceholderTest(xla_test.XLATestCase): ph = array_ops.placeholder_with_default(v, shape=[]) out = ph * 2 sess.run(variables.variables_initializer([v])) - self.assertEqual(8.0, sess.run(out)) + self.assertEqual(8.0, self.evaluate(out)) def test_placeholder_with_default_fed(self): with self.cached_session() as sess, self.test_scope(): diff --git a/tensorflow/compiler/tests/random_ops_test.py b/tensorflow/compiler/tests/random_ops_test.py index 36ef6ed5fe..97ffad34c0 100644 --- a/tensorflow/compiler/tests/random_ops_test.py +++ b/tensorflow/compiler/tests/random_ops_test.py @@ -46,9 +46,9 @@ class RandomOpsTest(xla_test.XLATestCase): # The random-number generator, if working correctly, should produce the # same output multiple times with low probability. - y = sess.run(x) - z = sess.run(x) - w = sess.run(x) + y = self.evaluate(x) + z = self.evaluate(x) + w = self.evaluate(x) # We use exact equality here. If the random-number generator is producing # deterministic output, all three outputs will be bitwise identical. @@ -83,7 +83,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.test_scope(): x = random_ops.random_uniform( shape=[1000], dtype=dtype, minval=-2, maxval=33) - y = sess.run(x) + y = self.evaluate(x) self.assertTrue((y >= -2).sum() == 1000) self.assertTrue((y < 33).sum() == 1000) @@ -102,7 +102,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.cached_session() as sess: with self.test_scope(): x = random_ops.truncated_normal(shape=[count], dtype=dtype) - y = sess.run(x) + y = self.evaluate(x) def normal_cdf(x): return .5 * math.erfc(-x / math.sqrt(2)) @@ -111,7 +111,7 @@ class RandomOpsTest(xla_test.XLATestCase): return math.exp(-(x**2) / 2.) / math.sqrt(2 * math.pi) def probit(x, sess=sess): - return sess.run(special_math.ndtri(x)) + return self.evaluate(special_math.ndtri(x)) a = -2. b = 2. @@ -148,7 +148,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.test_scope(): x = math_ops.range(1 << 16) shuffle = random_ops.random_shuffle(x) - result = sess.run(shuffle) + result = self.evaluate(shuffle) expected = range(1 << 16) # Compare sets to avoid randomness behavior changes but make sure still # have all the values. @@ -159,7 +159,7 @@ class RandomOpsTest(xla_test.XLATestCase): with self.test_scope(): x = array_ops.diag(math_ops.range(20)) shuffle = random_ops.random_shuffle(x) - result = sess.run(shuffle) + result = self.evaluate(shuffle) expected = np.diag(range(20)).flatten() # Compare sets to avoid randomness behavior changes but make sure still # have all the values. diff --git a/tensorflow/compiler/tests/stateless_random_ops_test.py b/tensorflow/compiler/tests/stateless_random_ops_test.py index 21708aa158..ee7ca7e6f1 100644 --- a/tensorflow/compiler/tests/stateless_random_ops_test.py +++ b/tensorflow/compiler/tests/stateless_random_ops_test.py @@ -156,7 +156,7 @@ class StatelessRandomOpsTest(xla_test.XLATestCase): return math.exp(-(x**2) / 2.) / math.sqrt(2 * math.pi) def probit(x, sess=sess): - return sess.run(special_math.ndtri(x)) + return self.evaluate(special_math.ndtri(x)) a = -2. b = 2. diff --git a/tensorflow/compiler/tests/tensor_array_ops_test.py b/tensorflow/compiler/tests/tensor_array_ops_test.py index c8208adb58..d7e26d79c4 100644 --- a/tensorflow/compiler/tests/tensor_array_ops_test.py +++ b/tensorflow/compiler/tests/tensor_array_ops_test.py @@ -505,7 +505,7 @@ class TensorArrayTest(xla_test.XLATestCase): [-0.5, 1.5], # read(0) gradient [20.0, 30.0, 40.0, 50.0], # concat gradient ]) - grad_vals = sess.run(grad_r) # 2 + 2 entries + grad_vals = self.evaluate(grad_r) # 2 + 2 entries self.assertAllClose([2.0 - 0.5 + 20.0, 3.0 + 1.5 + 30.0], grad_vals[0]) self.assertAllEqual([4.0 + 40.0, 5.0 + 50.0], grad_vals[1]) diff --git a/tensorflow/compiler/tests/variable_ops_test.py b/tensorflow/compiler/tests/variable_ops_test.py index 77cdeac816..fcd7ac5ba1 100644 --- a/tensorflow/compiler/tests/variable_ops_test.py +++ b/tensorflow/compiler/tests/variable_ops_test.py @@ -77,7 +77,7 @@ class VariableOpsTest(xla_test.XLATestCase): sess.run(variables.variables_initializer([v])) x = v.sparse_read(2) self.assertAllClose( - np.array([8j, 9, 10, 11]).astype(dtype), sess.run(x)) + np.array([8j, 9, 10, 11]).astype(dtype), self.evaluate(x)) def testSparseRead1DIndices(self): for dtype in self.numeric_types: @@ -89,7 +89,7 @@ class VariableOpsTest(xla_test.XLATestCase): x = v.sparse_read([2, 1]) self.assertAllClose( np.array([[8, 9, 10, 11], [4, 5, 6j, 7]]).astype(dtype), - sess.run(x)) + self.evaluate(x)) def testSparseRead2DIndices(self): for dtype in self.numeric_types: @@ -102,7 +102,7 @@ class VariableOpsTest(xla_test.XLATestCase): self.assertAllClose( np.array([[[8, 9, 10, 11], [4, 5, 6, 7]], [[0, 1, 2j, 3], [8, 9, 10, 11]]]).astype(dtype), - sess.run(x)) + self.evaluate(x)) def testSparseRead2DIndices3DTensor(self): for dtype in self.numeric_types: @@ -115,9 +115,9 @@ class VariableOpsTest(xla_test.XLATestCase): x = v.sparse_read([[2, 1], [3, 0]]) self.assertAllClose( np.array( - [[[[20, 21, 22], [23, 24j, 25]], [[10, 11, 12], [13, 14, 15]] - ], [[[30, 31, 32], [33, 34, 35]], [[0, 1, 2], [3, 4, 5]]] - ],).astype(dtype), sess.run(x)) + [[[[20, 21, 22], [23, 24j, 25]], [[10, 11, 12], [13, 14, 15]]], + [[[30, 31, 32], [33, 34, 35]], [[0, 1, 2], [3, 4, 5]]] + ],).astype(dtype), self.evaluate(x)) def testShape(self): for dtype in self.numeric_types: @@ -229,7 +229,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_add( handle, [0], constant_op.constant([[2]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertAllEqual(sess.run(read), [[3], [7]]) + self.assertAllEqual(self.evaluate(read), [[3], [7]]) def testScatterSub(self): with self.test_session() as sess, self.test_scope(): @@ -242,7 +242,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_sub( handle, [1], constant_op.constant([[2]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertAllEqual(sess.run(read), [[4], [-1]]) + self.assertAllEqual(self.evaluate(read), [[4], [-1]]) def testScatterMul(self): with self.test_session() as sess, self.test_scope(): @@ -255,7 +255,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_mul( handle, [0], constant_op.constant([[5]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[5]]) + self.assertEqual(self.evaluate(read), [[5]]) def testScatterDiv(self): with self.test_session() as sess, self.test_scope(): @@ -268,7 +268,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_div( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertAllEqual(sess.run(read), [[2]]) + self.assertAllEqual(self.evaluate(read), [[2]]) def testScatterMin(self): with self.test_session() as sess, self.test_scope(): @@ -281,7 +281,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_min( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[3]]) + self.assertEqual(self.evaluate(read), [[3]]) def testScatterMax(self): with self.test_session() as sess, self.test_scope(): @@ -294,7 +294,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_max( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[6]]) + self.assertEqual(self.evaluate(read), [[6]]) def testScatterUpdate(self): with self.test_session() as sess, self.test_scope(): @@ -307,7 +307,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_update( handle, [0], constant_op.constant([[3]], dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[3]]) + self.assertEqual(self.evaluate(read), [[3]]) def testScatterAddScalar(self): with self.test_session() as sess, self.test_scope(): @@ -320,7 +320,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_add( handle, [0], constant_op.constant(2, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[3]]) + self.assertEqual(self.evaluate(read), [[3]]) def testScatterSubScalar(self): with self.test_session() as sess, self.test_scope(): @@ -333,7 +333,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_sub( handle, [0], constant_op.constant(2, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[-1]]) + self.assertEqual(self.evaluate(read), [[-1]]) def testScatterMulScalar(self): with self.test_session() as sess, self.test_scope(): @@ -346,7 +346,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_mul( handle, [0], constant_op.constant(5, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[5]]) + self.assertEqual(self.evaluate(read), [[5]]) def testScatterDivScalar(self): with self.test_session() as sess, self.test_scope(): @@ -359,7 +359,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_div( handle, [0], constant_op.constant(3, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[2]]) + self.assertEqual(self.evaluate(read), [[2]]) def testScatterMinScalar(self): with self.test_session() as sess, self.test_scope(): @@ -372,7 +372,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_min( handle, [0], constant_op.constant(3, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[3]]) + self.assertEqual(self.evaluate(read), [[3]]) def testScatterMaxScalar(self): with self.test_session() as sess, self.test_scope(): @@ -385,7 +385,7 @@ class VariableOpsTest(xla_test.XLATestCase): resource_variable_ops.resource_scatter_max( handle, [0], constant_op.constant(3, dtype=dtypes.int32))) read = resource_variable_ops.read_variable_op(handle, dtype=dtypes.int32) - self.assertEqual(sess.run(read), [[6]]) + self.assertEqual(self.evaluate(read), [[6]]) def testScatterNdAddOps(self): with self.test_session() as sess, self.test_scope(): @@ -400,7 +400,7 @@ class VariableOpsTest(xla_test.XLATestCase): sess.run(gen_state_ops.resource_scatter_nd_add(handle, indices, updates)) read = resource_variable_ops.read_variable_op( handle, dtype=dtypes.float32) - self.assertAllClose(expected, sess.run(read)) + self.assertAllClose(expected, self.evaluate(read)) def testScatterNdUpdateAddOps(self): with self.test_session() as sess, self.test_scope(): @@ -416,7 +416,7 @@ class VariableOpsTest(xla_test.XLATestCase): gen_state_ops.resource_scatter_nd_update(handle, indices, updates)) read = resource_variable_ops.read_variable_op( handle, dtype=dtypes.float32) - self.assertAllClose(expected, sess.run(read)) + self.assertAllClose(expected, self.evaluate(read)) class StridedSliceAssignChecker(object): diff --git a/tensorflow/compiler/tests/xla_device_test.py b/tensorflow/compiler/tests/xla_device_test.py index 28d61fb07d..ef55292b1b 100644 --- a/tensorflow/compiler/tests/xla_device_test.py +++ b/tensorflow/compiler/tests/xla_device_test.py @@ -81,7 +81,7 @@ class XlaDeviceTest(xla_test.XLATestCase): with self.cached_session() as sess: with self.test_scope(): x = gen_control_flow_ops.control_trigger() - sess.run(x) + self.evaluate(x) if __name__ == "__main__": diff --git a/tensorflow/examples/autograph/integration_tests/keras_test.py b/tensorflow/examples/autograph/integration_tests/keras_test.py index dca7c07b47..fc0b073696 100644 --- a/tensorflow/examples/autograph/integration_tests/keras_test.py +++ b/tensorflow/examples/autograph/integration_tests/keras_test.py @@ -93,10 +93,10 @@ class KerasTest(tf.test.TestCase): init = tf.global_variables_initializer() with tf.Session() as sess: - sess.run(init) + self.evaluate(init) sample_input = tf.random_uniform((1, 10, 10, 1)) output = model(sample_input) # pylint: disable=not-callable - self.assertEqual(sess.run(output).shape, (1, 3)) + self.assertEqual(self.evaluate(output).shape, (1, 3)) if __name__ == '__main__': diff --git a/tensorflow/examples/autograph/integration_tests/list_literals_test.py b/tensorflow/examples/autograph/integration_tests/list_literals_test.py index 917f5ff9d8..e85d4abcfc 100644 --- a/tensorflow/examples/autograph/integration_tests/list_literals_test.py +++ b/tensorflow/examples/autograph/integration_tests/list_literals_test.py @@ -34,7 +34,7 @@ class ListLiteralsTest(tf.test.TestCase): result = converted() with self.cached_session() as sess: - self.assertAllEqual(sess.run(result), [1, 2, 3]) + self.assertAllEqual(self.evaluate(result), [1, 2, 3]) if __name__ == '__main__': diff --git a/tensorflow/examples/speech_commands/input_data_test.py b/tensorflow/examples/speech_commands/input_data_test.py index b766ba6de0..33b58b9d09 100644 --- a/tensorflow/examples/speech_commands/input_data_test.py +++ b/tensorflow/examples/speech_commands/input_data_test.py @@ -35,7 +35,7 @@ class InputDataTest(test.TestCase): with self.cached_session() as sess: sample_data = tf.zeros([32000, 2]) wav_encoder = contrib_audio.encode_wav(sample_data, 16000) - wav_data = sess.run(wav_encoder) + wav_data = self.evaluate(wav_encoder) return wav_data def _saveTestWavFile(self, filename, wav_data): diff --git a/tensorflow/examples/speech_commands/label_wav_test.py b/tensorflow/examples/speech_commands/label_wav_test.py index f0af2a4798..77a88f98e1 100644 --- a/tensorflow/examples/speech_commands/label_wav_test.py +++ b/tensorflow/examples/speech_commands/label_wav_test.py @@ -33,7 +33,7 @@ class LabelWavTest(test.TestCase): with self.cached_session() as sess: sample_data = tf.zeros([1000, 2]) wav_encoder = contrib_audio.encode_wav(sample_data, 16000) - wav_data = sess.run(wav_encoder) + wav_data = self.evaluate(wav_encoder) return wav_data def _saveTestWavFile(self, filename, wav_data): diff --git a/tensorflow/examples/speech_commands/wav_to_features_test.py b/tensorflow/examples/speech_commands/wav_to_features_test.py index 87f2987693..cb8ea912fa 100644 --- a/tensorflow/examples/speech_commands/wav_to_features_test.py +++ b/tensorflow/examples/speech_commands/wav_to_features_test.py @@ -33,7 +33,7 @@ class WavToFeaturesTest(test.TestCase): with self.cached_session() as sess: sample_data = tf.zeros([32000, 2]) wav_encoder = contrib_audio.encode_wav(sample_data, 16000) - wav_data = sess.run(wav_encoder) + wav_data = self.evaluate(wav_encoder) return wav_data def _saveTestWavFile(self, filename, wav_data): diff --git a/tensorflow/lite/experimental/examples/lstm/unidirectional_sequence_lstm_test.py b/tensorflow/lite/experimental/examples/lstm/unidirectional_sequence_lstm_test.py index eeb48d1231..9c00d0501a 100644 --- a/tensorflow/lite/experimental/examples/lstm/unidirectional_sequence_lstm_test.py +++ b/tensorflow/lite/experimental/examples/lstm/unidirectional_sequence_lstm_test.py @@ -111,7 +111,7 @@ class UnidirectionalSequenceLstmTest(test_util.TensorFlowTestCase): # Initialize variables init = tf.global_variables_initializer() - sess.run(init) + self.evaluate(init) for _ in range(TRAIN_STEPS): batch_x, batch_y = self.mnist.train.next_batch( batch_size=self.batch_size, shuffle=False) diff --git a/tensorflow/python/autograph/converters/asserts_test.py b/tensorflow/python/autograph/converters/asserts_test.py index eef628aeb6..803b6a06da 100644 --- a/tensorflow/python/autograph/converters/asserts_test.py +++ b/tensorflow/python/autograph/converters/asserts_test.py @@ -41,7 +41,7 @@ class AssertsTest(converter_testing.TestCase): op = result.test_fn(constant_op.constant(False)) with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, 'test message'): - sess.run(op) + self.evaluate(op) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/converters/call_trees_test.py b/tensorflow/python/autograph/converters/call_trees_test.py index 916c736fb4..9d760167a9 100644 --- a/tensorflow/python/autograph/converters/call_trees_test.py +++ b/tensorflow/python/autograph/converters/call_trees_test.py @@ -94,7 +94,7 @@ class CallTreesTest(converter_testing.TestCase): dtypes.int64) as result: with self.cached_session() as sess: self.assertTrue(isinstance(result.test_fn(), ops.Tensor)) - self.assertIn(sess.run(result.test_fn()), (0, 1, 2)) + self.assertIn(self.evaluate(result.test_fn()), (0, 1, 2)) def test_uncompiled_modules(self): @@ -113,7 +113,7 @@ class CallTreesTest(converter_testing.TestCase): with self.compiled(node, ns) as result: with self.cached_session() as sess: result_tensor = result.test_fn(constant_op.constant(1)) - self.assertEquals(sess.run(result_tensor), 3) + self.assertEquals(self.evaluate(result_tensor), 3) def test_call_to_decorated_function(self): diff --git a/tensorflow/python/autograph/converters/lists_test.py b/tensorflow/python/autograph/converters/lists_test.py index f6da845fcc..39843c7d74 100644 --- a/tensorflow/python/autograph/converters/lists_test.py +++ b/tensorflow/python/autograph/converters/lists_test.py @@ -68,7 +68,7 @@ class ListTest(converter_testing.TestCase): with self.cached_session() as sess: tl = result.test_fn() r = list_ops.tensor_list_stack(tl, dtypes.int32) - self.assertAllEqual(sess.run(r), [1, 2, 3]) + self.assertAllEqual(self.evaluate(r), [1, 2, 3]) def test_list_pop(self): @@ -91,8 +91,8 @@ class ListTest(converter_testing.TestCase): with self.cached_session() as sess: ts, tl = result.test_fn() r = list_ops.tensor_list_stack(tl, dtypes.int32) - self.assertAllEqual(sess.run(r), [1, 2]) - self.assertAllEqual(sess.run(ts), 3) + self.assertAllEqual(self.evaluate(r), [1, 2]) + self.assertAllEqual(self.evaluate(ts), 3) def test_double_list_pop(self): @@ -123,7 +123,7 @@ class ListTest(converter_testing.TestCase): with self.compiled(node, {}, array_ops.stack, dtypes.int32) as result: with self.cached_session() as sess: - self.assertAllEqual(sess.run(result.test_fn()), [1, 2, 3]) + self.assertAllEqual(self.evaluate(result.test_fn()), [1, 2, 3]) # TODO(mdan): Add a test with tf.stack with axis kwarg. diff --git a/tensorflow/python/autograph/converters/side_effect_guards_test.py b/tensorflow/python/autograph/converters/side_effect_guards_test.py index cef3199169..f6d0f73b5b 100644 --- a/tensorflow/python/autograph/converters/side_effect_guards_test.py +++ b/tensorflow/python/autograph/converters/side_effect_guards_test.py @@ -48,12 +48,12 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - sess.run(v.initializer) - sess.run(result.test_fn(v)) + self.evaluate(v.initializer) + self.evaluate(result.test_fn(v)) # TODO(mdan): Add support for this use case. # Right now the variable `a` is not conditioned on the `assign` because # there's no way to add control dependencies to a variable object. - self.assertEqual(2, sess.run(v)) + self.assertEqual(2, self.evaluate(v)) def test_side_effect_on_used_variable(self): @@ -69,11 +69,11 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - sess.run(v.initializer) - sess.run(result.test_fn(v)) + self.evaluate(v.initializer) + self.evaluate(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. # Right now it's 3 or 4 based on whether the read is synchronized. - self.assertEqual(3, sess.run(v)) + self.assertEqual(3, self.evaluate(v)) def test_side_effect_on_tensor(self): @@ -109,10 +109,10 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign_add) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - sess.run(v.initializer) - sess.run(result.test_fn(v)) + self.evaluate(v.initializer) + self.evaluate(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. - self.assertEqual(4, sess.run(v)) + self.assertEqual(4, self.evaluate(v)) def test_multiline_nested_block(self): @@ -130,10 +130,10 @@ class SideEffectGuardsTest(converter_testing.TestCase): with self.compiled(node, {}, state_ops.assign, ops.name_scope) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - sess.run(v.initializer) - sess.run(result.test_fn(v)) + self.evaluate(v.initializer) + self.evaluate(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. - self.assertEqual(3, sess.run(v)) + self.assertEqual(3, self.evaluate(v)) def test_multiline_block_unsafe(self): @@ -153,10 +153,10 @@ class SideEffectGuardsTest(converter_testing.TestCase): state_ops.assign_add) as result: with self.cached_session() as sess: v = variable_scope.get_variable('test', initializer=2) - sess.run(v.initializer) - sess.run(result.test_fn(v)) + self.evaluate(v.initializer) + self.evaluate(result.test_fn(v)) # TODO(mdan): Ensure the result of test_fn(v) is also deterministic. - self.assertEqual(4, sess.run(v)) + self.assertEqual(4, self.evaluate(v)) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/converters/slices_test.py b/tensorflow/python/autograph/converters/slices_test.py index e190a7cfe8..bd049afdfc 100644 --- a/tensorflow/python/autograph/converters/slices_test.py +++ b/tensorflow/python/autograph/converters/slices_test.py @@ -49,7 +49,7 @@ class SliceTest(converter_testing.TestCase): tl = list_ops.tensor_list_from_tensor( [1, 2], element_shape=constant_op.constant([], dtype=dtypes.int32)) y = result.test_fn(tl) - self.assertEqual(2, sess.run(y)) + self.assertEqual(2, self.evaluate(y)) def test_index_access_multiple_definitions(self): diff --git a/tensorflow/python/autograph/core/errors_test.py b/tensorflow/python/autograph/core/errors_test.py index aa6c293268..00c8a726ed 100644 --- a/tensorflow/python/autograph/core/errors_test.py +++ b/tensorflow/python/autograph/core/errors_test.py @@ -55,7 +55,7 @@ class RuntimeErrorsTest(test.TestCase): with self.assertRaises(errors.TfRuntimeError) as cm: with errors.improved_errors(zero_div_caller): with self.cached_session() as sess: - sess.run(ops) + self.evaluate(ops) for frame in cm.exception.custom_traceback: _, _, function_name, _ = frame @@ -70,7 +70,7 @@ class RuntimeErrorsTest(test.TestCase): with self.assertRaises(errors.TfRuntimeError) as cm: with errors.improved_errors(zero_div_caller): with self.cached_session() as sess: - sess.run(ops) + self.evaluate(ops) all_function_names = set() for frame in cm.exception.custom_traceback: @@ -87,7 +87,7 @@ class RuntimeErrorsTest(test.TestCase): with self.assertRaises(tf_errors.InvalidArgumentError): with errors.improved_errors(zero_div_caller): with self.cached_session() as sess: - sess.run(ops) + self.evaluate(ops) def test_improved_errors_validation(self): with self.assertRaisesRegexp( diff --git a/tensorflow/python/autograph/impl/api_test.py b/tensorflow/python/autograph/impl/api_test.py index ef577568c4..44cb99d657 100644 --- a/tensorflow/python/autograph/impl/api_test.py +++ b/tensorflow/python/autograph/impl/api_test.py @@ -63,7 +63,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], sess.run(x).tolist()) + self.assertListEqual([0, 1], self.evaluate(x).tolist()) def test_decorator_does_not_recurse(self): @@ -83,7 +83,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], sess.run(x).tolist()) + self.assertListEqual([0, 1], self.evaluate(x).tolist()) def test_decorator_calls_unconverted_graph(self): @@ -104,7 +104,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], sess.run(x).tolist()) + self.assertListEqual([0, 1], self.evaluate(x).tolist()) def test_decorator_calls_unconverted_py_func(self): @@ -130,7 +130,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], sess.run(x).tolist()) + self.assertListEqual([0, 1], self.evaluate(x).tolist()) def test_decorator_calls_decorated(self): @@ -153,7 +153,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], sess.run(x).tolist()) + self.assertListEqual([0, 1], self.evaluate(x).tolist()) def test_decorator_preserves_argspec(self): @@ -192,7 +192,7 @@ class ApiTest(test.TestCase): x = tc.test_method( constant_op.constant([2, 4]), constant_op.constant(1), constant_op.constant(-2)) - self.assertListEqual([0, 1], sess.run(x).tolist()) + self.assertListEqual([0, 1], self.evaluate(x).tolist()) def test_converted_call_builtin(self): x = api.converted_call(range, None, converter.ConversionOptions(), 3) @@ -208,7 +208,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = api.converted_call(test_fn, None, converter.ConversionOptions(), constant_op.constant(-1)) - self.assertEqual(1, sess.run(x)) + self.assertEqual(1, self.evaluate(x)) def test_converted_call_method_explicit_owner(self): # TODO(mdan): Implement. @@ -234,7 +234,7 @@ class ApiTest(test.TestCase): tc = TestClass(constant_op.constant(-1)) x = api.converted_call(tc.test_method, None, converter.ConversionOptions(), tc) - self.assertEqual(1, sess.run(x)) + self.assertEqual(1, self.evaluate(x)) def test_converted_call_method_by_class(self): @@ -252,7 +252,7 @@ class ApiTest(test.TestCase): tc = TestClass(constant_op.constant(-1)) x = api.converted_call(TestClass.test_method, None, converter.ConversionOptions(), tc) - self.assertEqual(1, sess.run(x)) + self.assertEqual(1, self.evaluate(x)) def test_converted_call_callable_object(self): @@ -269,7 +269,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: tc = TestClass(constant_op.constant(-1)) x = api.converted_call(tc, None, converter.ConversionOptions()) - self.assertEqual(1, sess.run(x)) + self.assertEqual(1, self.evaluate(x)) def test_converted_call_constructor(self): @@ -288,7 +288,7 @@ class ApiTest(test.TestCase): constant_op.constant(-1)) # tc is now a converted object. x = tc.test_method() - self.assertEqual(1, sess.run(x)) + self.assertEqual(1, self.evaluate(x)) def test_converted_call_already_converted(self): @@ -298,12 +298,12 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = api.converted_call(f, None, converter.ConversionOptions(), constant_op.constant(0)) - self.assertTrue(sess.run(x)) + self.assertTrue(self.evaluate(x)) converted_f = api.to_graph(f) x = api.converted_call(converted_f, None, converter.ConversionOptions(), constant_op.constant(0)) - self.assertTrue(sess.run(x)) + self.assertTrue(self.evaluate(x)) def test_converted_call_no_user_code(self): @@ -334,8 +334,8 @@ class ApiTest(test.TestCase): constant_op.constant([[0.0]]), training=True) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - self.assertAllEqual([[0.0, 0.0]], sess.run(x)) + self.evaluate(variables.global_variables_initializer()) + self.assertAllEqual([[0.0, 0.0]], self.evaluate(x)) def test_converted_call_whitelisted_method_extra_self(self): @@ -349,8 +349,8 @@ class ApiTest(test.TestCase): model, constant_op.constant([[0.0]]), training=True) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - self.assertAllEqual([[0.0, 0.0]], sess.run(x)) + self.evaluate(variables.global_variables_initializer()) + self.assertAllEqual([[0.0, 0.0]], self.evaluate(x)) def test_converted_call_whitelisted_method_via_owner(self): @@ -364,8 +364,8 @@ class ApiTest(test.TestCase): constant_op.constant([[0.0]]), training=True) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - self.assertAllEqual([[0.0, 0.0]], sess.run(x)) + self.evaluate(variables.global_variables_initializer()) + self.assertAllEqual([[0.0, 0.0]], self.evaluate(x)) def test_converted_call_lambda(self): @@ -376,8 +376,8 @@ class ApiTest(test.TestCase): x = api.converted_call(l, None, opts, constant_op.constant(0)) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - self.assertAllEqual(True, sess.run(x)) + self.evaluate(variables.global_variables_initializer()) + self.assertAllEqual(True, self.evaluate(x)) def test_to_graph_basic(self): @@ -390,7 +390,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = compiled_fn(constant_op.constant([4, 8]), 4) - self.assertListEqual([1, 2], sess.run(x).tolist()) + self.assertListEqual([1, 2], self.evaluate(x).tolist()) def test_to_graph_with_defaults(self): @@ -405,7 +405,7 @@ class ApiTest(test.TestCase): with self.cached_session() as sess: x = compiled_fn(constant_op.constant([4, 8])) - self.assertListEqual([1, 2], sess.run(x).tolist()) + self.assertListEqual([1, 2], self.evaluate(x).tolist()) def test_to_code_basic(self): diff --git a/tensorflow/python/autograph/lang/special_functions_test.py b/tensorflow/python/autograph/lang/special_functions_test.py index 123ee65b32..8d40f4036c 100644 --- a/tensorflow/python/autograph/lang/special_functions_test.py +++ b/tensorflow/python/autograph/lang/special_functions_test.py @@ -36,7 +36,7 @@ class SpecialFunctionsTest(test.TestCase): python_one = special_functions.match_staging_level(1, 1) with self.cached_session() as sess: self.assertTrue(tensor_util.is_tensor(tensor_one)) - self.assertAllEqual(sess.run(tensor_one), 1) + self.assertAllEqual(self.evaluate(tensor_one), 1) self.assertEqual(python_one, 1) def test_tensor_list_empty_list(self): @@ -45,21 +45,21 @@ class SpecialFunctionsTest(test.TestCase): element_shape=()) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(sl), []) + self.assertAllEqual(self.evaluate(sl), []) l = special_functions.tensor_list((), element_dtype=dtypes.int32, element_shape=()) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(sl), []) + self.assertAllEqual(self.evaluate(sl), []) def test_tensor_list_tensor(self): l = special_functions.tensor_list( constant_op.constant([], dtype=dtypes.int32)) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(sl), []) + self.assertAllEqual(self.evaluate(sl), []) def test_tensor_list_unsupported_initializer(self): with self.assertRaisesRegexp(ValueError, 'unknown type'): @@ -76,7 +76,7 @@ class SpecialFunctionsTest(test.TestCase): l = special_functions.tensor_list(elements) sl = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(sl), [[1, 2], [3, 4]]) + self.assertAllEqual(self.evaluate(sl), [[1, 2], [3, 4]]) def test_tensor_list_array_from_elements(self): elements = [constant_op.constant([1, 2]), constant_op.constant([3, 4])] @@ -84,7 +84,7 @@ class SpecialFunctionsTest(test.TestCase): l = special_functions.tensor_list(elements, use_tensor_array=True) sl = l.stack() with self.cached_session() as sess: - self.assertAllEqual(sess.run(sl), [[1, 2], [3, 4]]) + self.assertAllEqual(self.evaluate(sl), [[1, 2], [3, 4]]) def test_stack(self): self.assertEqual(special_functions.stack(1, strict=False), 1) diff --git a/tensorflow/python/autograph/operators/control_flow_test.py b/tensorflow/python/autograph/operators/control_flow_test.py index 2dea18dc5f..05b5660941 100644 --- a/tensorflow/python/autograph/operators/control_flow_test.py +++ b/tensorflow/python/autograph/operators/control_flow_test.py @@ -35,7 +35,7 @@ class ForLoopTest(test.TestCase): body=lambda i, s: (s + i,), init_state=(0,)) with self.cached_session() as sess: - self.assertEqual((10,), sess.run(s)) + self.assertEqual((10,), self.evaluate(s)) def test_python(self): s = control_flow.for_stmt( @@ -53,7 +53,7 @@ class ForLoopTest(test.TestCase): body=lambda i, s: (s + i,), init_state=(0,)) with self.cached_session() as sess: - self.assertEqual((10,), sess.run(s)) + self.assertEqual((10,), self.evaluate(s)) class WhileLoopTest(test.TestCase): @@ -66,7 +66,7 @@ class WhileLoopTest(test.TestCase): init_state=(0, 0), extra_deps=(n,)) with self.cached_session() as sess: - self.assertEqual((5, 10), sess.run(results)) + self.assertEqual((5, 10), self.evaluate(results)) def test_python(self): n = 5 @@ -90,9 +90,9 @@ class IfStmtTest(test.TestCase): def test_tensor(self): with self.cached_session() as sess: t = self.single_return_if_stmt(constant_op.constant(True)) - self.assertEqual(1, sess.run(t)) + self.assertEqual(1, self.evaluate(t)) t = self.single_return_if_stmt(constant_op.constant(False)) - self.assertEqual(-1, sess.run(t)) + self.assertEqual(-1, self.evaluate(t)) def test_python(self): self.assertEqual(1, self.single_return_if_stmt(True)) @@ -101,9 +101,9 @@ class IfStmtTest(test.TestCase): def test_tensor_multiple_returns(self): with self.cached_session() as sess: t = self.multi_return_if_stmt(constant_op.constant(True)) - self.assertAllEqual([1, 2], sess.run(t)) + self.assertAllEqual([1, 2], self.evaluate(t)) t = self.multi_return_if_stmt(constant_op.constant(False)) - self.assertAllEqual([-1, -2], sess.run(t)) + self.assertAllEqual([-1, -2], self.evaluate(t)) def test_python_multiple_returns(self): self.assertEqual((1, 2), self.multi_return_if_stmt(True)) diff --git a/tensorflow/python/autograph/operators/data_structures_test.py b/tensorflow/python/autograph/operators/data_structures_test.py index 72476ccb6b..0433e3f130 100644 --- a/tensorflow/python/autograph/operators/data_structures_test.py +++ b/tensorflow/python/autograph/operators/data_structures_test.py @@ -43,7 +43,7 @@ class ListTest(test.TestCase): l = data_structures.tf_tensor_list_new([3, 4, 5]) t = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(t), [3, 4, 5]) + self.assertAllEqual(self.evaluate(t), [3, 4, 5]) def test_tf_tensor_list_new_empty(self): l = data_structures.tf_tensor_list_new([], @@ -51,13 +51,13 @@ class ListTest(test.TestCase): element_shape=()) t = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(t), []) + self.assertAllEqual(self.evaluate(t), []) def test_tf_tensor_list_new_from_tensor(self): l = data_structures.tf_tensor_list_new(constant_op.constant([3, 4, 5])) t = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(t), [3, 4, 5]) + self.assertAllEqual(self.evaluate(t), [3, 4, 5]) def test_tf_tensor_list_new_illegal_input(self): with self.assertRaises(ValueError): @@ -77,7 +77,7 @@ class ListTest(test.TestCase): l = data_structures.tf_tensor_array_new([3, 4, 5]) t = l.stack() with self.cached_session() as sess: - self.assertAllEqual(sess.run(t), [3, 4, 5]) + self.assertAllEqual(self.evaluate(t), [3, 4, 5]) def test_tf_tensor_array_new_illegal_input(self): with self.assertRaises(ValueError): @@ -102,15 +102,15 @@ class ListTest(test.TestCase): t = list_ops.tensor_list_stack(l, element_dtype=x.dtype) with self.cached_session() as sess: - self.assertAllEqual(sess.run(t), [[1, 2, 3]]) + self.assertAllEqual(self.evaluate(t), [[1, 2, 3]]) def test_append_tensorarray(self): l = tensor_array_ops.TensorArray(dtypes.int32, size=0, dynamic_size=True) l1 = data_structures.list_append(l, 1) l2 = data_structures.list_append(l1, 2) with self.cached_session() as sess: - self.assertAllEqual(sess.run(l1.stack()), [1]) - self.assertAllEqual(sess.run(l2.stack()), [1, 2]) + self.assertAllEqual(self.evaluate(l1.stack()), [1]) + self.assertAllEqual(self.evaluate(l2.stack()), [1, 2]) def test_append_python(self): l = [] @@ -131,10 +131,10 @@ class ListTest(test.TestCase): with self.cached_session() as sess: l, x = data_structures.list_pop(l, None, opts) - self.assertAllEqual(sess.run(x), [3, 4]) + self.assertAllEqual(self.evaluate(x), [3, 4]) t = list_ops.tensor_list_stack(l, element_dtype=initial_list.dtype) - self.assertAllEqual(sess.run(t), [[1, 2]]) + self.assertAllEqual(self.evaluate(t), [[1, 2]]) def test_pop_python(self): l = [1, 2, 3] @@ -152,7 +152,7 @@ class ListTest(test.TestCase): with self.cached_session() as sess: t = data_structures.list_stack(l, opts) - self.assertAllEqual(sess.run(t), sess.run(initial_list)) + self.assertAllEqual(self.evaluate(t), self.evaluate(initial_list)) def test_stack_tensor_list_empty(self): l = list_ops.empty_tensor_list( diff --git a/tensorflow/python/autograph/operators/exceptions_test.py b/tensorflow/python/autograph/operators/exceptions_test.py index 186535d05b..24d3f1bd35 100644 --- a/tensorflow/python/autograph/operators/exceptions_test.py +++ b/tensorflow/python/autograph/operators/exceptions_test.py @@ -30,7 +30,7 @@ class ExceptionsTest(test.TestCase): with self.cached_session() as sess: t = exceptions.assert_stmt( constant_op.constant(True), lambda: constant_op.constant('ignored')) - sess.run(t) + self.evaluate(t) def test_assert_tf_triggered(self): with self.cached_session() as sess: @@ -40,7 +40,7 @@ class ExceptionsTest(test.TestCase): with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, 'test message'): - sess.run(t) + self.evaluate(t) def test_assert_tf_multiple_printed_values(self): two_tensors = [ @@ -53,7 +53,7 @@ class ExceptionsTest(test.TestCase): with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, 'test message.*another message'): - sess.run(t) + self.evaluate(t) def test_assert_python_untriggered(self): side_effect_trace = [] diff --git a/tensorflow/python/autograph/operators/logical_test.py b/tensorflow/python/autograph/operators/logical_test.py index d6649f7b2b..ebf6458f01 100644 --- a/tensorflow/python/autograph/operators/logical_test.py +++ b/tensorflow/python/autograph/operators/logical_test.py @@ -45,11 +45,11 @@ class LogicalOperatorsTest(test.TestCase): def test_and_tf(self): with self.cached_session() as sess: t = logical.and_(self._tf_true, self._tf_true) - self.assertEqual(sess.run(t), True) + self.assertEqual(self.evaluate(t), True) t = logical.and_(self._tf_true, lambda: True) - self.assertEqual(sess.run(t), True) + self.assertEqual(self.evaluate(t), True) t = logical.and_(self._tf_false, lambda: True) - self.assertEqual(sess.run(t), False) + self.assertEqual(self.evaluate(t), False) # TODO(mdan): Add a test for ops with side effects. def test_or_python(self): @@ -63,11 +63,11 @@ class LogicalOperatorsTest(test.TestCase): def test_or_tf(self): with self.cached_session() as sess: t = logical.or_(self._tf_false, self._tf_true) - self.assertEqual(sess.run(t), True) + self.assertEqual(self.evaluate(t), True) t = logical.or_(self._tf_false, lambda: True) - self.assertEqual(sess.run(t), True) + self.assertEqual(self.evaluate(t), True) t = logical.or_(self._tf_true, lambda: True) - self.assertEqual(sess.run(t), True) + self.assertEqual(self.evaluate(t), True) # TODO(mdan): Add a test for ops with side effects. def test_not_python(self): @@ -78,7 +78,7 @@ class LogicalOperatorsTest(test.TestCase): def test_not_tf(self): with self.cached_session() as sess: t = logical.not_(self._tf_false()) - self.assertEqual(sess.run(t), True) + self.assertEqual(self.evaluate(t), True) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/operators/py_builtins_test.py b/tensorflow/python/autograph/operators/py_builtins_test.py index 443e30a475..4d9eec77c3 100644 --- a/tensorflow/python/autograph/operators/py_builtins_test.py +++ b/tensorflow/python/autograph/operators/py_builtins_test.py @@ -38,29 +38,29 @@ class PyBuiltinsTest(test.TestCase): self.assertEqual(py_builtins.abs_(-1), 1) with self.cached_session() as sess: t = py_builtins.abs_(constant_op.constant(-1)) - self.assertEqual(sess.run(t), 1) + self.assertEqual(self.evaluate(t), 1) t = py_builtins.abs_(constant_op.constant([-1, 2, -3])) - self.assertAllEqual(sess.run(t), [1, 2, 3]) + self.assertAllEqual(self.evaluate(t), [1, 2, 3]) def test_float(self): self.assertEqual(py_builtins.float_(10), 10.0) self.assertEqual(py_builtins.float_('10.0'), 10.0) with self.cached_session() as sess: t = py_builtins.float_(constant_op.constant(1, dtype=dtypes.int64)) - self.assertEqual(sess.run(t), 1.0) + self.assertEqual(self.evaluate(t), 1.0) st = py_builtins.float_(constant_op.constant('1.0')) - self.assertEqual(sess.run(st), 1.0) + self.assertEqual(self.evaluate(st), 1.0) def test_int(self): self.assertEqual(py_builtins.int_(10.0), 10) self.assertEqual(py_builtins.int_('11', 2), 3) with self.cached_session() as sess: t = py_builtins.int_(constant_op.constant(1, dtype=dtypes.float64)) - self.assertEqual(sess.run(t), 1) + self.assertEqual(self.evaluate(t), 1) st = py_builtins.int_(constant_op.constant('1')) - self.assertEqual(sess.run(st), 1) + self.assertEqual(self.evaluate(st), 1) st = py_builtins.int_(constant_op.constant('1'), 10) - self.assertEqual(sess.run(st), 1) + self.assertEqual(self.evaluate(st), 1) def test_int_unsupported_base(self): t = constant_op.constant(1, dtype=dtypes.float64) @@ -73,9 +73,9 @@ class PyBuiltinsTest(test.TestCase): t = py_builtins.len_(constant_op.constant([[1], [2], [3]])) self.assertEqual(t, 3) ta = py_builtins.len_(tensor_array_ops.TensorArray(dtypes.int32, size=5)) - self.assertEqual(sess.run(ta), 5) + self.assertEqual(self.evaluate(ta), 5) tl = py_builtins.len_(data_structures.tf_tensor_list_new([3, 4, 5])) - self.assertEqual(sess.run(tl), 3) + self.assertEqual(self.evaluate(tl), 3) def test_len_scalar(self): with self.assertRaises(ValueError): @@ -120,18 +120,18 @@ class PyBuiltinsTest(test.TestCase): def test_range_tensor(self): with self.cached_session() as sess: r = py_builtins.range_(constant_op.constant(3)) - self.assertAllEqual(sess.run(r), [0, 1, 2]) + self.assertAllEqual(self.evaluate(r), [0, 1, 2]) r = py_builtins.range_(1, constant_op.constant(3)) - self.assertAllEqual(sess.run(r), [1, 2]) + self.assertAllEqual(self.evaluate(r), [1, 2]) r = py_builtins.range_(2, 0, constant_op.constant(-1)) - self.assertAllEqual(sess.run(r), [2, 1]) + self.assertAllEqual(self.evaluate(r), [2, 1]) def test_range_tensor_empty_range(self): with self.session() as sess: r = py_builtins.range_(constant_op.constant(-3)) - self.assertAllEqual(sess.run(r), []) + self.assertAllEqual(self.evaluate(r), []) r = py_builtins.range_(5, constant_op.constant(2)) - self.assertAllEqual(sess.run(r), []) + self.assertAllEqual(self.evaluate(r), []) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/operators/slices_test.py b/tensorflow/python/autograph/operators/slices_test.py index 9e4865b3c6..d444054fd7 100644 --- a/tensorflow/python/autograph/operators/slices_test.py +++ b/tensorflow/python/autograph/operators/slices_test.py @@ -34,7 +34,7 @@ class SlicesTest(test.TestCase): with self.cached_session() as sess: t = list_ops.tensor_list_stack(l, element_dtype=initial_list.dtype) - self.assertAllEqual(sess.run(t), [[5, 6], [3, 4]]) + self.assertAllEqual(self.evaluate(t), [[5, 6], [3, 4]]) def test_get_item_tensor_list(self): initial_list = constant_op.constant([[1, 2], [3, 4]]) @@ -44,7 +44,7 @@ class SlicesTest(test.TestCase): l, 1, slices.GetItemOpts(element_dtype=initial_list.dtype)) with self.cached_session() as sess: - self.assertAllEqual(sess.run(t), [3, 4]) + self.assertAllEqual(self.evaluate(t), [3, 4]) def test_get_item_tensor_string(self): initial_str = constant_op.constant('abcd') @@ -52,14 +52,14 @@ class SlicesTest(test.TestCase): slices.GetItemOpts(element_dtype=initial_str.dtype)) with self.cached_session() as sess: - self.assertEqual(sess.run(t), b'b') + self.assertEqual(self.evaluate(t), b'b') initial_list_str = constant_op.constant(['abcd', 'bcde']) t = slices.get_item(initial_list_str, 1, slices.GetItemOpts(element_dtype=initial_str.dtype)) with self.cached_session() as sess: - self.assertEqual(sess.run(t), b'bcde') + self.assertEqual(self.evaluate(t), b'bcde') if __name__ == '__main__': diff --git a/tensorflow/python/autograph/utils/misc_test.py b/tensorflow/python/autograph/utils/misc_test.py index 8d2b0d6e13..c813e0f5c9 100644 --- a/tensorflow/python/autograph/utils/misc_test.py +++ b/tensorflow/python/autograph/utils/misc_test.py @@ -32,7 +32,7 @@ class MiscTest(test.TestCase): new_a = alias_tensors(a) self.assertFalse(new_a is a) with self.cached_session() as sess: - self.assertEqual(1, sess.run(new_a)) + self.assertEqual(1, self.evaluate(new_a)) def test_alias_tensors(self): a = constant(1) @@ -47,7 +47,7 @@ class MiscTest(test.TestCase): self.assertTrue(new_s is s) self.assertTrue(new_l is l) with self.cached_session() as sess: - self.assertEqual(1, sess.run(new_a)) + self.assertEqual(1, self.evaluate(new_a)) if __name__ == '__main__': diff --git a/tensorflow/python/autograph/utils/py_func_test.py b/tensorflow/python/autograph/utils/py_func_test.py index 1c220d9492..28cefd8c3e 100644 --- a/tensorflow/python/autograph/utils/py_func_test.py +++ b/tensorflow/python/autograph/utils/py_func_test.py @@ -34,13 +34,13 @@ class PyFuncTest(test.TestCase): with self.cached_session() as sess: result = py_func.wrap_py_func(test_fn, dtypes.int64, (1, constant_op.constant(1), 1)) - self.assertEqual(3, sess.run(result)) + self.assertEqual(3, self.evaluate(result)) result = py_func.wrap_py_func(test_fn, dtypes.int64, (1, 1, 1)) - self.assertEqual(3, sess.run(result)) + self.assertEqual(3, self.evaluate(result)) result = py_func.wrap_py_func( test_fn, dtypes.int64, (constant_op.constant(1), 1, constant_op.constant(1))) - self.assertEqual(3, sess.run(result)) + self.assertEqual(3, self.evaluate(result)) def test_wrap_py_func_complex_args(self): @@ -54,10 +54,10 @@ class PyFuncTest(test.TestCase): with self.cached_session() as sess: result = py_func.wrap_py_func(test_fn, dtypes.int64, (7, TestClass())) - self.assertEqual(35, sess.run(result)) + self.assertEqual(35, self.evaluate(result)) result = py_func.wrap_py_func(test_fn, dtypes.int64, (constant_op.constant(7), TestClass())) - self.assertEqual(35, sess.run(result)) + self.assertEqual(35, self.evaluate(result)) def test_wrap_py_func_kwargs(self): @@ -74,13 +74,13 @@ class PyFuncTest(test.TestCase): 'c': 11, 'd': TestClass(13) }) - self.assertEqual(178, sess.run(result)) + self.assertEqual(178, self.evaluate(result)) result = py_func.wrap_py_func(test_fn, dtypes.int64, (constant_op.constant(7), TestClass(5)), { 'c': constant_op.constant(11), 'd': TestClass(13) }) - self.assertEqual(178, sess.run(result)) + self.assertEqual(178, self.evaluate(result)) def test_wrap_py_func_dummy_return(self): @@ -91,11 +91,11 @@ class PyFuncTest(test.TestCase): with self.cached_session() as sess: result = py_func.wrap_py_func(test_fn, None, (5,), use_dummy_return=True) - self.assertEqual(1, sess.run(result)) + self.assertEqual(1, self.evaluate(result)) self.assertEqual([1], side_counter) result = py_func.wrap_py_func( test_fn, None, (constant_op.constant(5),), use_dummy_return=True) - self.assertEqual(1, sess.run(result)) + self.assertEqual(1, self.evaluate(result)) self.assertEqual([2], side_counter) diff --git a/tensorflow/python/autograph/utils/tensor_list_test.py b/tensorflow/python/autograph/utils/tensor_list_test.py index 697c166eb1..c655f773b0 100644 --- a/tensorflow/python/autograph/utils/tensor_list_test.py +++ b/tensorflow/python/autograph/utils/tensor_list_test.py @@ -43,13 +43,13 @@ class TensorListTest(test.TestCase): l = tl.dynamic_list_append(l, 1) s = list_ops.tensor_list_stack(l, element_dtype=dtypes.int32) with self.cached_session() as sess: - self.assertAllEqual(sess.run(s), [1]) + self.assertAllEqual(self.evaluate(s), [1]) l = tensor_array_ops.TensorArray(dtypes.int32, size=0, dynamic_size=True) l = tl.dynamic_list_append(l, 1) s = l.stack() with self.cached_session() as sess: - self.assertAllEqual(sess.run(s), [1]) + self.assertAllEqual(self.evaluate(s), [1]) l = tl.TensorList(self._shape(()), dtypes.int32) l = tl.dynamic_list_append(l, 1) @@ -92,7 +92,7 @@ class TensorListTest(test.TestCase): a2 = l.pop() c4 = l.count() with Session() as sess: - c1, c2, c3, c4, a, a2 = sess.run([c1, c2, c3, c4, a, a2]) + c1, c2, c3, c4, a, a2 = self.evaluate([c1, c2, c3, c4, a, a2]) self.assertEqual(c1, 1) self.assertEqual(c2, 2) self.assertEqual(c3, 1) @@ -108,7 +108,7 @@ class TensorListTest(test.TestCase): l[0] = b l1 = l[0] with self.cached_session() as sess: - l0, l1, a, b = sess.run([l0, l1, a, b]) + l0, l1, a, b = self.evaluate([l0, l1, a, b]) self.assertEqual(l0, a) self.assertEqual(l1, b) diff --git a/tensorflow/python/client/session_clusterspec_prop_test.py b/tensorflow/python/client/session_clusterspec_prop_test.py index df020f88a8..224f880ed1 100644 --- a/tensorflow/python/client/session_clusterspec_prop_test.py +++ b/tensorflow/python/client/session_clusterspec_prop_test.py @@ -62,7 +62,7 @@ class SessionClusterSpecPropagationTest(test_util.TensorFlowTestCase): const = constant_op.constant(17) sess = session.Session(server1.target, config=config) - output = sess.run(const) + output = self.evaluate(const) self.assertEqual(17, output) def testClusterSpecPropagationWorker2Placement(self): @@ -106,7 +106,7 @@ class SessionClusterSpecPropagationTest(test_util.TensorFlowTestCase): with ops.Graph().as_default() as g, ops.device('/job:worker/task:0'): const = constant_op.constant(17) sess = session.Session(server1.target, config=config, graph=g) - output = sess.run(const) + output = self.evaluate(const) self.assertEqual(17, output) def testCanonicalDeviceNames(self): @@ -208,7 +208,7 @@ class SessionClusterSpecPropagationTest(test_util.TensorFlowTestCase): with ops.device('/job:worker/task:0/cpu:0'): sum3 = sum1 + sum2 sess = session.Session(server1.target, config=config, graph=g) - output = sess.run(sum3) + output = self.evaluate(sum3) self.assertEqual(40, output) def testLegacyDeviceNames(self): diff --git a/tensorflow/python/client/session_partial_run_test.py b/tensorflow/python/client/session_partial_run_test.py index 92ca47efa9..a9bd5ab7e0 100644 --- a/tensorflow/python/client/session_partial_run_test.py +++ b/tensorflow/python/client/session_partial_run_test.py @@ -117,7 +117,7 @@ class PartialRunTest(test_util.TensorFlowTestCase): a = constant_op.constant(2.0, dtypes.float32) b = a * 2 c = b * 3 - r1 = sess.run([b, c]) + r1 = self.evaluate([b, c]) h = sess.partial_run_setup([b, c], []) r2 = sess.partial_run(h, [b, c]) self.assertEqual(r1, r2) diff --git a/tensorflow/python/client/timeline_test.py b/tensorflow/python/client/timeline_test.py index dfd0147643..f9bd50957a 100644 --- a/tensorflow/python/client/timeline_test.py +++ b/tensorflow/python/client/timeline_test.py @@ -147,7 +147,7 @@ class TimelineTest(test.TestCase): num2 = variables.Variable(2.0, name='num2') with ops.device('/cpu:2'): result = num1 + num2 + num1 * num2 - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) sess.run(result, options=run_options, run_metadata=run_metadata) self.assertTrue(run_metadata.HasField('step_stats')) @@ -176,7 +176,7 @@ class TimelineTest(test.TestCase): num2 = variables.Variable(2.0, name='num2') with ops.device('/cpu:2'): result = num1 + num2 + num1 * num2 - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) sess.run(result, options=run_options, run_metadata=run_metadata) self.assertTrue(run_metadata.HasField('step_stats')) step_stats = run_metadata.step_stats diff --git a/tensorflow/python/client/virtual_gpu_test.py b/tensorflow/python/client/virtual_gpu_test.py index 5892e0fc84..e82ee0666c 100644 --- a/tensorflow/python/client/virtual_gpu_test.py +++ b/tensorflow/python/client/virtual_gpu_test.py @@ -216,7 +216,7 @@ class VirtualGpuTest(test_util.TensorFlowTestCase): for d in self._util.devices: with ops.device(d): var = variables.Variable(random_ops.random_uniform(mat_shape)) - sess.run(var.initializer) + self.evaluate(var.initializer) data.append(var) s = data[0] for i in range(1, len(data)): diff --git a/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py b/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py index 3903ec49b9..af20e50fb9 100644 --- a/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/bucket_by_sequence_length_test.py @@ -110,9 +110,9 @@ class BucketBySequenceLengthTest(test_base.DatasetTestBase): with self.cached_session() as sess: batches = [] for _ in range(4): - batches.append(sess.run(batch)) + batches.append(self.evaluate(batch)) with self.assertRaises(errors.OutOfRangeError): - sess.run(batch) + self.evaluate(batch) batch_sizes_val = [] lengths_val = [] for batch in batches: @@ -160,9 +160,9 @@ class BucketBySequenceLengthTest(test_base.DatasetTestBase): with self.cached_session() as sess: batches = [] for _ in range(3): - batches.append(sess.run(batch)) + batches.append(self.evaluate(batch)) with self.assertRaisesOpError("bucket_boundaries"): - sess.run(batch) + self.evaluate(batch) batch_sizes_val = [] lengths_val = [] for batch in batches: @@ -197,9 +197,9 @@ class BucketBySequenceLengthTest(test_base.DatasetTestBase): with self.cached_session() as sess: batches = [] for _ in range(5): - batches.append(sess.run(batch)) + batches.append(self.evaluate(batch)) with self.assertRaises(errors.OutOfRangeError): - sess.run(batch) + self.evaluate(batch) self.assertAllEqual(batches[0], [[1, 0], [1, 1]]) @@ -300,7 +300,7 @@ class BucketBySequenceLengthTest(test_base.DatasetTestBase): with self.cached_session() as sess: with self.assertRaises(errors.OutOfRangeError): while True: - output = sess.run(batch) + output = self.evaluate(batch) sprs_tensor = (tuple([tuple(idx) for idx in output.indices]), tuple(output.values)) all_sparse_tensors.add(sprs_tensor) diff --git a/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py index cea8bd6f0b..7edaab81f4 100644 --- a/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/copy_to_device_test.py @@ -57,9 +57,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceInt32(self): host_dataset = dataset_ops.Dataset.from_tensors([0, 1, 2, 3]) @@ -82,9 +82,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - self.assertAllEqual([0, 1, 2, 3], sess.run(next_element)) + self.assertAllEqual([0, 1, 2, 3], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToSameDevice(self): host_dataset = dataset_ops.Dataset.range(10) @@ -108,9 +108,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceWithPrefetch(self): host_dataset = dataset_ops.Dataset.range(10) @@ -134,9 +134,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyDictToDevice(self): host_dataset = dataset_ops.Dataset.range(10).map(lambda x: {"a": x}) @@ -160,9 +160,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual({"a": i}, sess.run(next_element)) + self.assertEqual({"a": i}, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyDictToDeviceWithPrefetch(self): host_dataset = dataset_ops.Dataset.range(10).map(lambda x: {"a": x}) @@ -186,9 +186,9 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual({"a": i}, sess.run(next_element)) + self.assertEqual({"a": i}, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopySparseTensorsToDevice(self): @@ -217,12 +217,12 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - actual = sess.run(next_element) + actual = self.evaluate(next_element) self.assertAllEqual([i], actual.values) self.assertAllEqual([[0, 0]], actual.indices) self.assertAllEqual([2, 2], actual.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopySparseTensorsToDeviceWithPrefetch(self): @@ -251,12 +251,12 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - actual = sess.run(next_element) + actual = self.evaluate(next_element) self.assertAllEqual([i], actual.values) self.assertAllEqual([[0, 0]], actual.indices) self.assertAllEqual([2, 2], actual.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpu(self): if not test_util.is_gpu_available(): @@ -271,11 +271,11 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuWithPrefetch(self): if not test_util.is_gpu_available(): @@ -290,11 +290,11 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuWithMap(self): if not test_util.is_gpu_available(): @@ -323,14 +323,14 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(10): - x, y, z = sess.run(next_element) + x, y, z = self.evaluate(next_element) self.assertEqual(i**2, x) self.assertEqual(float(i**2), y) self.assertEqual(util_compat.as_bytes(str(i)), z) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuInt32(self): if not test_util.is_gpu_available(): @@ -345,10 +345,10 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) - self.assertAllEqual([0, 1, 2, 3], sess.run(next_element)) + self.evaluate(iterator.initializer) + self.assertAllEqual([0, 1, 2, 3], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuInt32AndPrefetch(self): if not test_util.is_gpu_available(): @@ -363,10 +363,10 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) - self.assertAllEqual([0, 1, 2, 3], sess.run(next_element)) + self.evaluate(iterator.initializer) + self.assertAllEqual([0, 1, 2, 3], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuStrings(self): if not test_util.is_gpu_available(): @@ -381,10 +381,10 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) - self.assertAllEqual([b"a", b"b", b"c"], sess.run(next_element)) + self.evaluate(iterator.initializer) + self.assertAllEqual([b"a", b"b", b"c"], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuStringsAndPrefetch(self): if not test_util.is_gpu_available(): @@ -399,10 +399,10 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) - self.assertAllEqual([b"a", b"b", b"c"], sess.run(next_element)) + self.evaluate(iterator.initializer) + self.assertAllEqual([b"a", b"b", b"c"], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDevicePingPongCPUGPU(self): if not test_util.is_gpu_available(): @@ -420,11 +420,11 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceWithReInit(self): host_dataset = dataset_ops.Dataset.range(10) @@ -447,14 +447,14 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(5): - self.assertEqual(i, sess.run(next_element)) - sess.run(iterator.initializer) + self.assertEqual(i, self.evaluate(next_element)) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceWithReInitAndPrefetch(self): host_dataset = dataset_ops.Dataset.range(10) @@ -477,14 +477,14 @@ class CopyToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(5): - self.assertEqual(i, sess.run(next_element)) - sess.run(iterator.initializer) + self.assertEqual(i, self.evaluate(next_element)) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuWithReInit(self): if not test_util.is_gpu_available(): @@ -499,14 +499,14 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(5): - self.assertEqual(i, sess.run(next_element)) - sess.run(iterator.initializer) + self.assertEqual(i, self.evaluate(next_element)) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testCopyToDeviceGpuWithReInitAndPrefetch(self): if not test_util.is_gpu_available(): @@ -521,14 +521,14 @@ class CopyToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(5): - self.assertEqual(i, sess.run(next_element)) - sess.run(iterator.initializer) + self.assertEqual(i, self.evaluate(next_element)) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testIteratorGetNextAsOptionalOnGPU(self): if not test_util.is_gpu_available(): @@ -547,24 +547,25 @@ class CopyToDeviceTest(test_base.DatasetTestBase): # Before initializing the iterator, evaluating the optional fails with # a FailedPreconditionError. with self.assertRaises(errors.FailedPreconditionError): - sess.run(elem_has_value_t) + self.evaluate(elem_has_value_t) with self.assertRaises(errors.FailedPreconditionError): - sess.run(elem_value_t) + self.evaluate(elem_value_t) # For each element of the dataset, assert that the optional evaluates to # the expected value. - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(3): - elem_has_value, elem_value = sess.run([elem_has_value_t, elem_value_t]) + elem_has_value, elem_value = self.evaluate( + [elem_has_value_t, elem_value_t]) self.assertTrue(elem_has_value) self.assertEqual(i, elem_value) # After exhausting the iterator, `next_elem.has_value()` will evaluate to # false, and attempting to get the value will fail. for _ in range(2): - self.assertFalse(sess.run(elem_has_value_t)) + self.assertFalse(self.evaluate(elem_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): - sess.run(elem_value_t) + self.evaluate(elem_value_t) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/counter_test.py b/tensorflow/python/data/experimental/kernel_tests/counter_test.py index 4e114ac479..d1dd07a879 100644 --- a/tensorflow/python/data/experimental/kernel_tests/counter_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/counter_test.py @@ -38,13 +38,13 @@ class CounterTest(test_base.DatasetTestBase): negative_get_next = negative_iterator.get_next() with self.cached_session() as sess: - self.assertEqual(3, sess.run(get_next)) - self.assertEqual(3 + 4, sess.run(get_next)) - self.assertEqual(3 + 2 * 4, sess.run(get_next)) + self.assertEqual(3, self.evaluate(get_next)) + self.assertEqual(3 + 4, self.evaluate(get_next)) + self.assertEqual(3 + 2 * 4, self.evaluate(get_next)) - self.assertEqual(0, sess.run(negative_get_next)) - self.assertEqual(-1, sess.run(negative_get_next)) - self.assertEqual(-2, sess.run(negative_get_next)) + self.assertEqual(0, self.evaluate(negative_get_next)) + self.assertEqual(-1, self.evaluate(negative_get_next)) + self.assertEqual(-2, self.evaluate(negative_get_next)) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py b/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py index 73be6cbcca..d9bbfb9c99 100644 --- a/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/dense_to_sparse_batch_test.py @@ -41,10 +41,10 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for start in range(0, len(components), 4): - results = sess.run(get_next) + results = self.evaluate(get_next) self.assertAllEqual([[i, j] for i, c in enumerate(components[start:start + 4]) for j in range(c)], results.indices) @@ -56,7 +56,7 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): results.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testDenseToSparseBatchDatasetWithUnknownShape(self): components = np.random.randint(5, size=(40,)).astype(np.int32) @@ -69,10 +69,10 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for start in range(0, len(components), 4): - results = sess.run(get_next) + results = self.evaluate(get_next) self.assertAllEqual([[i, j, z] for i, c in enumerate(components[start:start + 4]) for j in range(c) @@ -89,7 +89,7 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): ], results.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testDenseToSparseBatchDatasetWithInvalidShape(self): input_tensor = array_ops.constant([[1]]) @@ -111,13 +111,13 @@ class DenseToSparseBatchTest(test_base.DatasetTestBase): sess.run(init_op, feed_dict={input_tensor: [[1]]}) with self.assertRaisesRegexp(errors.InvalidArgumentError, "incompatible with the row shape"): - sess.run(get_next) + self.evaluate(get_next) # Initialize with an input tensor that is larger than `row_shape`. sess.run(init_op, feed_dict={input_tensor: range(13)}) with self.assertRaisesRegexp(errors.DataLossError, "larger than the row shape"): - sess.run(get_next) + self.evaluate(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py index 796a692c56..768a8d774b 100644 --- a/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/directed_interleave_dataset_test.py @@ -40,12 +40,12 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for _ in range(100): for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def _normalize(self, vec): return vec / vec.sum() @@ -71,9 +71,9 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: freqs = np.zeros([num_datasets]) for _ in range(num_samples): - freqs[sess.run(next_element)] += 1 + freqs[self.evaluate(next_element)] += 1 with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) return freqs @@ -107,9 +107,9 @@ class DirectedInterleaveDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in choice_array: - self.assertEqual(words[i], sess.run(next_element)) + self.assertEqual(words[i], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testErrors(self): with self.assertRaisesRegexp(ValueError, diff --git a/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py index e54235d9f8..f32d1d0a6f 100644 --- a/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/enumerate_dataset_test.py @@ -44,12 +44,12 @@ class EnumerateDatasetTest(test_base.DatasetTestBase): [t.shape for t in get_next[1]]) with self.cached_session() as sess: - sess.run(init_op) - self.assertEqual((20, (b"a", 1, 37.0)), sess.run(get_next)) - self.assertEqual((21, (b"b", 2, 38.0)), sess.run(get_next)) + self.evaluate(init_op) + self.assertEqual((20, (b"a", 1, 37.0)), self.evaluate(get_next)) + self.assertEqual((21, (b"b", 2, 38.0)), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/filter_dataset_op_test.py b/tensorflow/python/data/experimental/kernel_tests/filter_dataset_op_test.py index c6ee88c676..4f8cb1246f 100644 --- a/tensorflow/python/data/experimental/kernel_tests/filter_dataset_op_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/filter_dataset_op_test.py @@ -52,12 +52,12 @@ class FilterBenchmark(test.Benchmark): with session.Session() as sess: for _ in range(10): - sess.run(next_element.op) + self.evaluate(next_element.op) deltas = [] for _ in range(100): start = time.time() for _ in range(100): - sess.run(next_element.op) + self.evaluate(next_element.op) end = time.time() deltas.append(end - start) diff --git a/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py b/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py index d38452e265..860442571e 100644 --- a/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/function_buffering_resource_test.py @@ -94,18 +94,18 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): device0, device1) with self.test_session(config=worker_config) as sess: - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [1.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [2.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [3.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [4.0]) self._event.wait() - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [5.0]) - sess.run(destroy_op) + self.evaluate(destroy_op) def testSameDeviceCPU(self): self._prefetch_fn_helper_one_shot("same_device_cpu", @@ -135,35 +135,35 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): ds, ds_iterator, "reinit", device0, device1) with self.test_session(config=worker_config) as sess: - sess.run(ds_iterator.initializer) - elem = sess.run(prefetch_op) + self.evaluate(ds_iterator.initializer) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [1.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [2.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [3.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [4.0]) self._event.wait() - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [5.0]) # Lets reset the function buffering resource and reinitialize the # iterator. Should be able to go through this again. self._event.clear() - sess.run(reset_op) - sess.run(ds_iterator.initializer) - elem = sess.run(prefetch_op) + self.evaluate(reset_op) + self.evaluate(ds_iterator.initializer) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [1.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [2.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [3.0]) - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [4.0]) self._event.wait() - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [5.0]) - sess.run(destroy_op) + self.evaluate(destroy_op) def testReinitializationOutOfRange(self): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) @@ -175,30 +175,30 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): ds, ds_iterator, "reinit", device0, device1) with self.test_session(config=worker_config) as sess: - sess.run(ds_iterator.initializer) + self.evaluate(ds_iterator.initializer) for i in range(1, 10): - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [float(i)]) # Try fetching after its over twice to test out end of sequence. with self.assertRaises(errors.OutOfRangeError): - sess.run(prefetch_op) + self.evaluate(prefetch_op) with self.assertRaises(errors.OutOfRangeError): - sess.run(prefetch_op) + self.evaluate(prefetch_op) # Now reset everything and try it out again. self._event.clear() - sess.run(reset_op) - sess.run(ds_iterator.initializer) + self.evaluate(reset_op) + self.evaluate(ds_iterator.initializer) for i in range(1, 10): - elem = sess.run(prefetch_op) + elem = self.evaluate(prefetch_op) self.assertEqual(elem, [float(i)]) # Try fetching after its over twice to test out end of sequence. with self.assertRaises(errors.OutOfRangeError): - sess.run(prefetch_op) + self.evaluate(prefetch_op) with self.assertRaises(errors.OutOfRangeError): - sess.run(prefetch_op) + self.evaluate(prefetch_op) - sess.run(destroy_op) + self.evaluate(destroy_op) def testStringsGPU(self): if not test_util.is_gpu_available(): @@ -235,13 +235,13 @@ class FunctionBufferingResourceTest(test_base.DatasetTestBase): buffer_resource_handle, ignore_lookup_error=True) with self.cached_session() as sess: - self.assertEqual([b"a"], sess.run(prefetch_op)) - self.assertEqual([b"b"], sess.run(prefetch_op)) - self.assertEqual([b"c"], sess.run(prefetch_op)) + self.assertEqual([b"a"], self.evaluate(prefetch_op)) + self.assertEqual([b"b"], self.evaluate(prefetch_op)) + self.assertEqual([b"c"], self.evaluate(prefetch_op)) with self.assertRaises(errors.OutOfRangeError): - sess.run(prefetch_op) + self.evaluate(prefetch_op) - sess.run(destroy_op) + self.evaluate(destroy_op) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py b/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py index 9030328593..f9856500c5 100644 --- a/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/group_by_reducer_test.py @@ -39,10 +39,10 @@ class GroupByReducerTest(test_base.DatasetTestBase): get_next = dataset.make_one_shot_iterator().get_next() with self.cached_session() as sess: for expected in values: - got = sess.run(get_next) + got = self.evaluate(get_next) self.assertEqual(got, expected) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testSum(self): reducer = grouping.Reducer( @@ -127,11 +127,11 @@ class GroupByReducerTest(test_base.DatasetTestBase): iterator = dataset.make_one_shot_iterator() get_next = iterator.get_next() with self.cached_session() as sess: - x, y = sess.run(get_next) + x, y = self.evaluate(get_next) self.assertAllEqual([0] * (2**i), x) self.assertAllEqual(np.array(1, ndmin=i), y) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testTypeMismatch(self): reducer = grouping.Reducer( @@ -190,7 +190,7 @@ class GroupByReducerTest(test_base.DatasetTestBase): grouping.group_by_reducer(lambda x, y: np.int64(0), reducer)) get_next = dataset.make_one_shot_iterator().get_next() with self.cached_session() as sess: - x, y = sess.run(get_next) + x, y = self.evaluate(get_next) self.assertAllEqual(x, np.asarray([x for x in range(10)])) self.assertEqual(y, 45) diff --git a/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py b/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py index 557d56e8b9..d5a36e7cb1 100644 --- a/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/group_by_window_test.py @@ -68,9 +68,9 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) - which_bucket, bucketed_values = sess.run(get_next) + which_bucket, bucketed_values = self.evaluate(get_next) self.assertEqual(0, which_bucket) @@ -103,11 +103,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) # Get two minibatches (one containing even values, one containing odds) - which_bucket_even, bucketed_values_even = sess.run(get_next) - which_bucket_odd, bucketed_values_odd = sess.run(get_next) + which_bucket_even, bucketed_values_even = self.evaluate(get_next) + which_bucket_odd, bucketed_values_odd = self.evaluate(get_next) # Count number of bucket_tensors. self.assertEqual(3, len(bucketed_values_even)) @@ -174,11 +174,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) # Get two minibatches ([0, 2, ...] and [64, 66, ...]) - which_bucket0, bucketed_values_even0 = sess.run(get_next) - which_bucket1, bucketed_values_even1 = sess.run(get_next) + which_bucket0, bucketed_values_even0 = self.evaluate(get_next) + which_bucket1, bucketed_values_even1 = self.evaluate(get_next) # Ensure that bucket 1 was completely filtered out self.assertAllEqual(0, which_bucket0) @@ -207,11 +207,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) with self.assertRaises(errors.OutOfRangeError): batches = 0 while True: - result = sess.run(get_next) + result = self.evaluate(get_next) is_even = all(x % 2 == 0 for x in result) is_odd = all(x % 2 == 1 for x in result) self.assertTrue(is_even or is_odd) @@ -232,11 +232,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) counts = [] with self.assertRaises(errors.OutOfRangeError): while True: - result = sess.run(get_next) + result = self.evaluate(get_next) self.assertTrue( all(x % 2 == 0 for x in result) or all(x % 2 == 1) @@ -259,16 +259,16 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) # The input is infinite, so this test demonstrates that: # 1. We produce output without having to consume the entire input, # 2. Different buckets can produce output at different rates, and # 3. For deterministic input, the output is deterministic. for _ in range(3): - self.assertAllEqual([0, 0, 0, 0], sess.run(get_next)) - self.assertAllEqual([1, 1, 1, 1], sess.run(get_next)) - self.assertAllEqual([2, 2, 2, 2], sess.run(get_next)) - self.assertAllEqual([0, 0, 0, 0], sess.run(get_next)) + self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) + self.assertAllEqual([1, 1, 1, 1], self.evaluate(get_next)) + self.assertAllEqual([2, 2, 2, 2], self.evaluate(get_next)) + self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) def testSmallGroups(self): components = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], dtype=np.int64) @@ -280,13 +280,13 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) - self.assertAllEqual([0, 0, 0, 0], sess.run(get_next)) - self.assertAllEqual([1, 1, 1, 1], sess.run(get_next)) + self.evaluate(init_op) + self.assertAllEqual([0, 0, 0, 0], self.evaluate(get_next)) + self.assertAllEqual([1, 1, 1, 1], self.evaluate(get_next)) # The small outputs at the end are deterministically produced in key # order. - self.assertAllEqual([0, 0, 0], sess.run(get_next)) - self.assertAllEqual([1], sess.run(get_next)) + self.assertAllEqual([0, 0, 0], self.evaluate(get_next)) + self.assertAllEqual([1], self.evaluate(get_next)) def testEmpty(self): iterator = ( @@ -297,11 +297,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) with self.assertRaisesRegexp( errors.InvalidArgumentError, "Window size must be greater than zero, but got 0."): - print(sess.run(get_next)) + print(self.evaluate(get_next)) def testReduceFuncError(self): components = np.random.randint(100, size=(200,)).astype(np.int64) @@ -323,9 +323,9 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) with self.assertRaises(errors.InvalidArgumentError): - sess.run(get_next) + self.evaluate(get_next) def testConsumeWindowDatasetMoreThanOnce(self): components = np.random.randint(50, size=(200,)).astype(np.int64) @@ -351,11 +351,11 @@ class GroupByWindowTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) counts = [] with self.assertRaises(errors.OutOfRangeError): while True: - tight_result, multiple_of_10_result = sess.run(get_next) + tight_result, multiple_of_10_result = self.evaluate(get_next) self.assertEqual(0, multiple_of_10_result.shape[1] % 10) self.assertAllEqual(tight_result, multiple_of_10_result[:, :tight_result.shape[1]]) diff --git a/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py b/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py index c0ec1486ab..522b196060 100644 --- a/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/ignore_errors_test.py @@ -47,11 +47,11 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for x in [1., 2., 3., 5.]: - self.assertEqual(x, sess.run(get_next)) + self.assertEqual(x, self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testParallelMapIgnoreError(self): components = np.array([1., 2., 3., np.nan, 5.]).astype(np.float32) @@ -65,11 +65,11 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for x in [1., 2., 3., 5.]: - self.assertEqual(x, sess.run(get_next)) + self.assertEqual(x, self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testReadFileIgnoreError(self): @@ -93,22 +93,22 @@ class IgnoreErrorsTest(test_base.DatasetTestBase): with self.cached_session() as sess: # All of the files are present. - sess.run(init_op) + self.evaluate(init_op) for filename in filenames: - self.assertEqual(compat.as_bytes(filename), sess.run(get_next)) + self.assertEqual(compat.as_bytes(filename), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Delete one of the files. os.remove(filenames[0]) # Attempting to read filenames[0] will fail, but ignore_errors() # will catch the error. - sess.run(init_op) + self.evaluate(init_op) for filename in filenames[1:]: - self.assertEqual(compat.as_bytes(filename), sess.run(get_next)) + self.assertEqual(compat.as_bytes(filename), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py b/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py index c93a8353ce..0a436034a8 100644 --- a/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/indexed_dataset_ops_test.py @@ -46,14 +46,14 @@ class IndexedDatasetOpsTest(test_base.DatasetTestBase): handle, index, output_types=[dtypes.uint64], output_shapes=[[]]) with self.cached_session() as sess: - sess.run(materialize) + self.evaluate(materialize) self.assertEqual([3], sess.run(get_op, feed_dict={index: 3})) def testIdentityIndexedDataset(self): ds = indexed_dataset_ops.IdentityIndexedDataset(16) materialized = ds.materialize() with self.cached_session() as sess: - sess.run(materialized.initializer) + self.evaluate(materialized.initializer) placeholder = array_ops.placeholder(dtypes.uint64, shape=[]) for i in range(16): output = sess.run( @@ -68,12 +68,13 @@ class IndexedDatasetOpsTest(test_base.DatasetTestBase): itr = ds.make_initializable_iterator() n = itr.get_next() with self.cached_session() as sess: - sess.run(itr.initializer) + self.evaluate(itr.initializer) for i in range(16): - output = sess.run(n) + output = self.evaluate(n) self.assertEqual(i, output) with self.assertRaises(errors.OutOfRangeError): - sess.run(n) + self.evaluate(n) + if __name__ == "__main__": test.main() diff --git a/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py index 91ae8cb1bd..109b3696b8 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_batched_features_dataset_test.py @@ -112,14 +112,14 @@ class MakeBatchedFeaturesDatasetTest( next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for file_batch, _, _, _, record_batch, _ in self._next_expected_batch( range(self._num_files), 2, 10): - actual_batch = sess.run(next_element) + actual_batch = self.evaluate(next_element) self.assertAllEqual(file_batch, actual_batch["file"]) self.assertAllEqual(record_batch, actual_batch["record"]) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testReadWithFusedShuffleRepeatDataset(self): num_epochs = 5 diff --git a/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py index e4bf089184..1f509384d7 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_csv_dataset_test.py @@ -90,7 +90,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): batch_size, num_epochs, ): - actual_features = sess.run(nxt) + actual_features = self.evaluate(nxt) if label_name is not None: expected_labels = expected_features.pop(label_name) @@ -102,7 +102,7 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): self.assertAllEqual(expected_features[k], actual_features[k]) with self.assertRaises(errors.OutOfRangeError): - sess.run(nxt) + self.evaluate(nxt) def _test_dataset(self, inputs, @@ -607,8 +607,8 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): outputs1 = dataset1.make_one_shot_iterator().get_next() outputs2 = dataset2.make_one_shot_iterator().get_next() for _ in range(total_records // batch_size): - batch1 = nest.flatten(sess.run(outputs1)) - batch2 = nest.flatten(sess.run(outputs2)) + batch1 = nest.flatten(self.evaluate(outputs1)) + batch2 = nest.flatten(self.evaluate(outputs2)) for i in range(len(batch1)): self.assertAllEqual(batch1[i], batch2[i]) @@ -639,8 +639,8 @@ class MakeCsvDatasetTest(test_base.DatasetTestBase): outputs2 = dataset2.make_one_shot_iterator().get_next() all_equal = False for _ in range(total_records // batch_size): - batch1 = nest.flatten(sess.run(outputs1)) - batch2 = nest.flatten(sess.run(outputs2)) + batch1 = nest.flatten(self.evaluate(outputs1)) + batch2 = nest.flatten(self.evaluate(outputs2)) for i in range(len(batch1)): all_equal = all_equal and np.array_equal(batch1[i], batch2[i]) self.assertFalse(all_equal) diff --git a/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py index 657cf3c00e..0bb7b7c5f3 100644 --- a/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/make_tf_record_dataset_test.py @@ -105,7 +105,7 @@ class MakeTFRecordDatasetTest( for expected_batch in self._next_expected_batch( file_indices, batch_size, num_epochs, interleave_cycle_length, drop_final_batch, use_parser_fn): - actual_batch = sess.run(outputs) + actual_batch = self.evaluate(outputs) self.assertAllEqual(expected_batch, actual_batch) def _read_test(self, batch_size, num_epochs, file_index=None, @@ -135,7 +135,7 @@ class MakeTFRecordDatasetTest( interleave_cycle_length=num_parallel_reads, drop_final_batch=drop_final_batch, use_parser_fn=parser_fn) with self.assertRaises(errors.OutOfRangeError): - sess.run(outputs) + self.evaluate(outputs) def testRead(self): for batch_size in [1, 2]: @@ -188,19 +188,19 @@ class MakeTFRecordDatasetTest( iterator = dataset.make_initializable_iterator() next_element = iterator.get_next() - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) first_batches = [] try: while True: - first_batches.append(sess.run(next_element)) + first_batches.append(self.evaluate(next_element)) except errors.OutOfRangeError: pass - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) second_batches = [] try: while True: - second_batches.append(sess.run(next_element)) + second_batches.append(self.evaluate(next_element)) except errors.OutOfRangeError: pass diff --git a/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py b/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py index 5ead6d1c75..8449c0651d 100644 --- a/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/map_and_batch_test.py @@ -89,13 +89,13 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): sess.run(init_op, feed_dict={count: 28, batch_size: 14}) num_batches = (28 * 7) // 14 for i in range(num_batches): - result = sess.run(get_next) + result = self.evaluate(get_next) for component, result_component in zip(components, result): for j in range(14): self.assertAllEqual(component[(i * 14 + j) % 7]**2, result_component[j]) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Batch of a finite input, where the batch_size does not # divide the total number of elements. @@ -104,23 +104,23 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): # We expect (num_batches - 1) full-sized batches. num_batches = int(math.ceil((14 * 7) / 8)) for i in range(num_batches - 1): - result = sess.run(get_next) + result = self.evaluate(get_next) for component, result_component in zip(components, result): for j in range(8): self.assertAllEqual(component[(i * 8 + j) % 7]**2, result_component[j]) - result = sess.run(get_next) + result = self.evaluate(get_next) for component, result_component in zip(components, result): for j in range((14 * 7) % 8): self.assertAllEqual(component[((num_batches - 1) * 8 + j) % 7]**2, result_component[j]) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Batch of an empty input should fail straight away. sess.run(init_op, feed_dict={count: 0, batch_size: 8}) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Empty batch should be an initialization time error. with self.assertRaises(errors.InvalidArgumentError): @@ -152,12 +152,12 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual([None, 1], iterator.output_shapes.as_list()) next_element = iterator.get_next() with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) + self.assertAllEqual([[0], [1], [4], [9]], self.evaluate(next_element)) + self.assertAllEqual([[16], [25], [36], [49]], self.evaluate(next_element)) if not drop_remainder: - self.assertAllEqual([[64], [81]], sess.run(next_element)) + self.assertAllEqual([[64], [81]], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) @parameterized.named_parameters( ("Normal", False), @@ -177,11 +177,11 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertEqual([None, 1], iterator.output_shapes.as_list()) next_element = iterator.get_next() with self.cached_session() as sess: - self.assertAllEqual([[0], [1], [4], [9]], sess.run(next_element)) - self.assertAllEqual([[16], [25], [36], [49]], sess.run(next_element)) - self.assertAllEqual([[64], [81]], sess.run(next_element)) + self.assertAllEqual([[0], [1], [4], [9]], self.evaluate(next_element)) + self.assertAllEqual([[16], [25], [36], [49]], self.evaluate(next_element)) + self.assertAllEqual([[64], [81]], self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) @parameterized.named_parameters( ("Normal", False), @@ -201,14 +201,14 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): elements.append(iterator.get_next()) with self.cached_session() as sess: for i in range(5): - got = sess.run(elements) + got = self.evaluate(elements) got.sort(key=lambda x: x[0]) expected = [] for j in range(100): expected.append(range(i * 10000 + j * 100, i * 10000 + (j + 1) * 100)) self.assertAllEqual(got, expected) with self.assertRaises(errors.OutOfRangeError): - sess.run(elements) + self.evaluate(elements) @parameterized.named_parameters( ("Normal", False), @@ -230,14 +230,14 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): elements.append(iterator.get_next()) with self.cached_session() as sess: for i in range(4): - got = sess.run(elements) + got = self.evaluate(elements) got.sort(key=lambda x: x[0]) expected = [] for j in range(100): expected.append(range(i * 10000 + j * 100, i * 10000 + (j + 1) * 100)) self.assertAllEqual(got, expected) with self.assertRaises(errors.OutOfRangeError): - sess.run(elements) + self.evaluate(elements) @parameterized.named_parameters( ("Normal", False), @@ -261,9 +261,9 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for i in range(2): - actual = sess.run(get_next) + actual = self.evaluate(get_next) expected = sparse_tensor.SparseTensorValue( indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], values=[i * 5, i * 5 + 1, i * 5 + 2, i * 5 + 3, i * 5 + 4], @@ -271,7 +271,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): self.assertTrue(sparse_tensor.is_sparse(actual)) self.assertSparseValuesEqual(actual, expected) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) @parameterized.named_parameters( ("Normal", False), @@ -321,10 +321,10 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): init_op = iterator.initializer get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) with self.assertRaisesRegexp(errors.InvalidArgumentError, "number of elements does not match"): - sess.run(get_next) + self.evaluate(get_next) @parameterized.named_parameters( ("Normal", False), @@ -354,7 +354,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for _ in range(3): - sess.run(get_next) + self.evaluate(get_next) @parameterized.named_parameters( ("1", 0, False), @@ -393,13 +393,14 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(threshold // 10): - self.assertAllEqual([i * 10 + j for j in range(10)], sess.run(get_next)) + self.assertAllEqual([i * 10 + j for j in range(10)], + self.evaluate(get_next)) if threshold % 10 != 0: self.assertAllEqual( [threshold // 10 * 10 + j for j in range(threshold % 10)], - sess.run(get_next)) + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) @parameterized.named_parameters( ("1", False, dtypes.bool, False), @@ -442,7 +443,8 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for _ in range(10): - self.assertAllEqual([element for _ in range(10)], sess.run(get_next)) + self.assertAllEqual([element for _ in range(10)], + self.evaluate(get_next)) @parameterized.named_parameters( ("Identity", None, lambda x: x, None), @@ -462,7 +464,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): else: expected = map_fn( sess.run(self.structuredElement(structure, shape=[10]))) - self.assertAllEqual(expected, sess.run(get_next)) + self.assertAllEqual(expected, self.evaluate(get_next)) def testShortCircuitCapturedInput(self): captured_t = array_ops.placeholder(dtypes.int64, shape=[]) @@ -473,7 +475,7 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={captured_t: 42}) - self.assertAllEqual([42] * 10, sess.run(get_next)) + self.assertAllEqual([42] * 10, self.evaluate(get_next)) @parameterized.named_parameters( ("Normal", False), @@ -501,13 +503,13 @@ class MapAndBatchTest(test_base.DatasetTestBase, parameterized.TestCase): print("Case %d" % i) if i < 5: self.assertAllEqual([i * 10 + j + 1 for j in range(10)], - sess.run(get_next)) + self.evaluate(get_next)) else: self.assertAllEqual( [((i * 10) + j) * ((i * 10) + j) for j in range(10)], - sess.run(get_next)) + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py b/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py index 11694540fa..6042ca1c63 100644 --- a/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/map_defun_op_test.py @@ -218,7 +218,7 @@ class MapDefunTest(test_base.DatasetTestBase): def _assert_op_cancelled(self, sess, map_defun_op): with self.assertRaisesRegexp(errors.CancelledError, "was cancelled"): - sess.run(map_defun_op) + self.evaluate(map_defun_op) def testMapDefunWithParentCancellation(self): # Checks that a cancellation of the parent graph is threaded through to @@ -260,10 +260,10 @@ class MapDefunBenchmark(test.Benchmark): with session.Session() as sess: # Warm up the session for _ in range(5): - sess.run(op) + self.evaluate(op) start = time.time() for _ in range(num_iters): - sess.run(op) + self.evaluate(op) end = time.time() mean_us = (end - start) * 1e6 / num_iters self.report_benchmark( diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py index ea2737c3c7..d3c121491a 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/model_dataset_test.py @@ -41,9 +41,9 @@ class ModelDatasetTest(test_base.DatasetTestBase, parameterized.TestCase): get_next = iterator.get_next() with self.cached_session() as sess: - self.assertEqual(0, sess.run(get_next)) + self.assertEqual(0, self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/optimization/optimize_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/optimization/optimize_dataset_test.py index 510b197ddf..df26a2c0cd 100644 --- a/tensorflow/python/data/experimental/kernel_tests/optimization/optimize_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/optimization/optimize_dataset_test.py @@ -51,7 +51,7 @@ class OptimizeDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: sess.run(init_op, {input_t: np.ones([512, 1024, 1025], np.int32)}) - sess.run(get_next) + self.evaluate(get_next) # TODO(b/117581999): Add eager coverage for the following tests. def testSkipEagerOptimizationLargeInputFromTensorSlices(self): @@ -64,7 +64,7 @@ class OptimizeDatasetTest(test_base.DatasetTestBase): with self.cached_session() as sess: sess.run(init_op, {input_t: np.ones([1, 512, 1024, 1025], np.int32)}) - sess.run(get_next) + self.evaluate(get_next) def testOptimizationNestedDataset(self): diff --git a/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py b/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py index 497c011b92..1dfe854f18 100644 --- a/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/override_threadpool_test.py @@ -55,11 +55,11 @@ class OverrideThreadpoolTest(test_base.DatasetTestBase, next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) thread_ids = [] try: while True: - thread_ids.append(sess.run(next_element)) + thread_ids.append(self.evaluate(next_element)) except errors.OutOfRangeError: pass self.assertLen(thread_ids, len(set(thread_ids))) diff --git a/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py b/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py index 90ac250df7..77f0dc8e81 100644 --- a/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/parallel_interleave_test.py @@ -195,9 +195,9 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): [[4] * 4, [5] * 5, [6] * 6] * self.repeat_count, 1, 1): self.write_coordination_events[expected_element].set() self.assertEqual(expected_element * expected_element, - sess.run(self.next_element)) + self.evaluate(self.next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testSingleThreaded(self): self._testSingleThreaded() @@ -235,10 +235,10 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): for expected_element in self._interleave( [[3] * 3, [7] * 7, [4] * 4] * self.repeat_count, 2, 1): self.write_coordination_events[expected_element].set() - output = sess.run(self.next_element) + output = self.evaluate(self.next_element) self.assertEqual(expected_element * expected_element, output) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def _testTwoThreadsNoContention(self, sloppy=False): # num_threads > 1. @@ -262,7 +262,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self.write_coordination_events[expected_element].set() if done_first_event: # First event starts the worker threads. self.read_coordination_events[expected_element].acquire() - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) if not done_first_event: self.read_coordination_events[expected_element].acquire() done_first_event = True @@ -270,7 +270,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testTwoThreadsNoContention(self): self._testTwoThreadsNoContention() @@ -309,7 +309,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): else: self.write_coordination_events[expected_element].set() time.sleep(0.5) # Sleep to consistently "avoid" the race condition. - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) if not done_first_event: done_first_event = True self.assertTrue( @@ -318,7 +318,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testTwoThreadsNoContentionWithRaces(self): self._testTwoThreadsNoContentionWithRaces() @@ -348,7 +348,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self.write_coordination_events[expected_element].set() if done_first_event: # First event starts the worker threads. self.read_coordination_events[expected_element].acquire() - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) if not done_first_event: done_first_event = True self.read_coordination_events[expected_element].acquire() @@ -356,7 +356,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testTwoThreadsNoContentionBlockLength(self): self._testTwoThreadsNoContentionBlockLength() @@ -396,7 +396,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): else: self.write_coordination_events[expected_element].set() time.sleep(0.5) # Sleep to consistently "avoid" the race condition. - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) if not done_first_event: done_first_event = True self.assertTrue( @@ -405,7 +405,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testTwoThreadsNoContentionWithRacesAndBlocking(self): self._testTwoThreadsNoContentionWithRacesAndBlocking() @@ -428,7 +428,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self.prefetch_input_elements: 0, }) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testEmptyInput(self): self._testEmptyInput() @@ -451,7 +451,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self.prefetch_input_elements: 0, }) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testNonEmptyInputIntoEmptyOutputs(self): self._testNonEmptyInputIntoEmptyOutputs() @@ -484,7 +484,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): # presence of finishing iterators. if done_first_event and not (sloppy and (i in race_indices)): self.read_coordination_events[expected_element].acquire() - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) if not done_first_event or (sloppy and (i in race_indices)): done_first_event = True self.read_coordination_events[expected_element].acquire() @@ -520,10 +520,10 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): ] for element in mis_ordering: self.write_coordination_events[element].set() - self.assertEqual(element * element, sess.run(self.next_element)) + self.assertEqual(element * element, self.evaluate(self.next_element)) self.assertTrue(self.read_coordination_events[element].acquire(False)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testBlockLengthWithContentionSloppy(self): with self.cached_session() as sess: @@ -549,7 +549,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self.write_coordination_events[expected_element].set() if done_first_event: # First event starts the worker threads. self.read_coordination_events[expected_element].acquire() - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) if not done_first_event: self.read_coordination_events[expected_element].acquire() done_first_event = True @@ -557,7 +557,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def _testEarlyExit(self, sloppy=False): # Exiting without consuming all input should not block @@ -575,7 +575,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): }) for i in range(4, 7): self.write_coordination_events[i].set() - elem = sess.run(self.next_element) # Start all workers + elem = self.evaluate(self.next_element) # Start all workers # Allow the one successful worker to progress beyond the py_func again. elem = int(math.sqrt(elem)) self.write_coordination_events[elem].set() @@ -608,7 +608,7 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): with self.cached_session() as sess: output_values = [] for _ in range(30): - output_values.append(sess.run(iterator.get_next())) + output_values.append(self.evaluate(iterator.get_next())) expected_values = self._interleave( [[4] * 4, [5] * 5, [6] * 6] * self.repeat_count, 1, 2) @@ -637,13 +637,13 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): get_next = iterator.get_next() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for i in range(10): for j in range(2): expected = [i, 0] if j % 2 == 0 else [0, -i] - self.assertAllEqual(expected, sess.run(get_next)) + self.assertAllEqual(expected, self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def testErrorsInOutputFn(self): with self.cached_session() as sess: @@ -668,15 +668,15 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self.error = ValueError() self.write_coordination_events[expected_element].set() with self.assertRaises(errors.InvalidArgumentError): - sess.run(self.next_element) + self.evaluate(self.next_element) else: self.write_coordination_events[expected_element].set() - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) self.assertEqual(expected_element * expected_element, actual_element, "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testErrorsInInputFn(self): @@ -720,14 +720,14 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self._interleave([[4] * 4, [5], [6] * 6] * self.repeat_count, 2, 1)): if expected_element == 5: with self.assertRaises(errors.InvalidArgumentError): - sess.run(self.next_element) + self.evaluate(self.next_element) else: - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) self.assertEqual(expected_element, actual_element, "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testErrorsInInterleaveFn(self): @@ -769,14 +769,14 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): self._interleave([[4] * 4, [5], [6] * 6] * self.repeat_count, 2, 1)): if expected_element == 5: with self.assertRaises(errors.InvalidArgumentError): - sess.run(self.next_element) + self.evaluate(self.next_element) else: - actual_element = sess.run(self.next_element) + actual_element = self.evaluate(self.next_element) self.assertEqual(expected_element, actual_element, "At index %s: %s expected, got: %s" % (i, expected_element, actual_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(self.next_element) + self.evaluate(self.next_element) def testShutdownRace(self): dataset = dataset_ops.Dataset.range(20) @@ -796,10 +796,10 @@ class ParallelInterleaveTest(test_base.DatasetTestBase): with self.cached_session() as sess: for _ in range(2): elements = [] - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) try: while True: - elements.extend(sess.run(next_element)) + elements.extend(self.evaluate(next_element)) except errors.OutOfRangeError: pass results.append(elements) diff --git a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py index f73725366c..8fc18e1ccd 100644 --- a/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/prefetch_to_device_test.py @@ -57,9 +57,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testPrefetchToSameDevice(self): host_dataset = dataset_ops.Dataset.range(10) @@ -87,9 +87,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testPrefetchDictToDevice(self): host_dataset = dataset_ops.Dataset.range(10).map(lambda x: {"a": x}) @@ -117,9 +117,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - self.assertEqual({"a": i}, sess.run(next_element)) + self.assertEqual({"a": i}, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testPrefetchSparseTensorsToDevice(self): def make_tensor(i): @@ -150,12 +150,12 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: for i in range(10): - actual = sess.run(next_element) + actual = self.evaluate(next_element) self.assertAllEqual([i], actual.values) self.assertAllEqual([[0, 0]], actual.indices) self.assertAllEqual([2, 2], actual.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testPrefetchToDeviceGpu(self): if not test_util.is_gpu_available(): @@ -170,9 +170,9 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testPrefetchToDeviceWithReInit(self): host_dataset = dataset_ops.Dataset.range(10) @@ -199,14 +199,14 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): worker_config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=worker_config) as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(5): - self.assertEqual(i, sess.run(next_element)) - sess.run(iterator.initializer) + self.assertEqual(i, self.evaluate(next_element)) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testPrefetchToDeviceGpuWithReInit(self): if not test_util.is_gpu_available(): @@ -220,14 +220,14 @@ class PrefetchToDeviceTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(5): - self.assertEqual(i, sess.run(next_element)) - sess.run(iterator.initializer) + self.assertEqual(i, self.evaluate(next_element)) + self.evaluate(iterator.initializer) for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/scan_test.py b/tensorflow/python/data/experimental/kernel_tests/scan_test.py index 0730455431..dc8a7bca27 100644 --- a/tensorflow/python/data/experimental/kernel_tests/scan_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/scan_test.py @@ -60,9 +60,9 @@ class ScanTest(test_base.DatasetTestBase): feed_dict={start: start_val, step: step_val, take: take_val}) for expected, _ in zip( itertools.count(start_val, step_val), range(take_val)): - self.assertEqual(expected, sess.run(next_element)) + self.assertEqual(expected, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) @test_util.run_in_graph_and_eager_modes def testFibonacci(self): @@ -110,9 +110,9 @@ class ScanTest(test_base.DatasetTestBase): feed_dict={start: start_val, step: step_val, take: take_val}) for expected, _ in zip( itertools.count(start_val, step_val), range(take_val)): - self.assertEqual(expected, sess.run(next_element).values[0]) + self.assertEqual(expected, self.evaluate(next_element).values[0]) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testChangingStateShape(self): # Test the fixed-point shape invariant calculations: start with @@ -136,11 +136,11 @@ class ScanTest(test_base.DatasetTestBase): with self.cached_session() as sess: for i in range(5): - (longer_vector_val, larger_rank_val), _ = sess.run(next_element) + (longer_vector_val, larger_rank_val), _ = self.evaluate(next_element) self.assertAllEqual([0] * (2**i), longer_vector_val) self.assertAllEqual(np.array(1, ndmin=i), larger_rank_val) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testIncorrectStateType(self): diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py index ef99d01c73..aeb338dfd5 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/range_dataset_serialization_test.py @@ -71,36 +71,36 @@ class RangeDatasetSerializationTest( with ops.Graph().as_default() as g: init_op, get_next, save_op, _ = _build_graph(start, stop) with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) + self.evaluate(variables.global_variables_initializer()) + self.evaluate(init_op) for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) + self.assertEqual(i, self.evaluate(get_next)) + self.evaluate(save_op) with ops.Graph().as_default() as g: init_op, get_next, _, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - sess.run(init_op) - sess.run(restore_op) + self.evaluate(init_op) + self.evaluate(restore_op) for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) + self.assertEqual(i, self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Saving and restoring in same session. with ops.Graph().as_default() as g: init_op, get_next, save_op, restore_op = _build_graph(start, stop) with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - sess.run(init_op) + self.evaluate(variables.global_variables_initializer()) + self.evaluate(init_op) for i in range(start, break_point): - self.assertEqual(i, sess.run(get_next)) - sess.run(save_op) - sess.run(restore_op) + self.assertEqual(i, self.evaluate(get_next)) + self.evaluate(save_op) + self.evaluate(restore_op) for i in range(break_point, stop): - self.assertEqual(i, sess.run(get_next)) + self.assertEqual(i, self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) def _build_range_dataset(self, start, stop): return dataset_ops.Dataset.range(start, stop) diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py index 88d5c896c9..12fa0989d0 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/serialization_integration_test.py @@ -60,9 +60,9 @@ class SerializationIntegrationTest(test.TestCase): init_ops, get_next_ops, saver = self._build_graph(num_pipelines, num_outputs) with self.session(graph=g) as sess: - sess.run(init_ops) + self.evaluate(init_ops) for _ in range(break_point): - output = sess.run(get_next_ops) + output = self.evaluate(get_next_ops) for i in range(num_pipelines): all_outputs[i].append(output[i]) saver.save(sess, self._ckpt_path()) @@ -73,7 +73,7 @@ class SerializationIntegrationTest(test.TestCase): with self.session(graph=g) as sess: saver.restore(sess, self._ckpt_path()) for _ in range(num_outputs - break_point): - output = sess.run(get_next_ops) + output = self.evaluate(get_next_ops) for i in range(num_pipelines): all_outputs[i].append(output[i]) diff --git a/tensorflow/python/data/experimental/kernel_tests/serialization/shuffle_dataset_serialization_test.py b/tensorflow/python/data/experimental/kernel_tests/serialization/shuffle_dataset_serialization_test.py index a04f1ddafc..e753a7a15b 100644 --- a/tensorflow/python/data/experimental/kernel_tests/serialization/shuffle_dataset_serialization_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/serialization/shuffle_dataset_serialization_test.py @@ -138,9 +138,9 @@ class ShuffleDatasetSerializationTest( saver = saver_lib.Saver(allow_empty=True) with self.session(graph=g) as sess: self._save(sess, saver) - expected = [sess.run(get_next_ops) for _ in range(num_outputs)] + expected = [self.evaluate(get_next_ops) for _ in range(num_outputs)] self._restore(saver, sess) - actual = [sess.run(get_next_ops) for _ in range(num_outputs)] + actual = [self.evaluate(get_next_ops) for _ in range(num_outputs)] self.match(expected, actual) diff --git a/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py b/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py index c208963a86..2e8b93feaf 100644 --- a/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/shuffle_and_repeat_test.py @@ -38,10 +38,10 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): outputs = [] with self.cached_session() as sess: for _ in range(num_outputs): - outputs.append(sess.run(get_next)) + outputs.append(self.evaluate(get_next)) if verify_exhausted: with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) return outputs def testCorrectOutput(self): @@ -108,7 +108,7 @@ class ShuffleAndRepeatTest(test_base.DatasetTestBase): shuffle_ops.shuffle_and_repeat(buffer_size=21)) get_next_op = ds.make_one_shot_iterator().get_next() with self.session(graph=g) as sess: - sess.run(get_next_op) + self.evaluate(get_next_op) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/sleep_test.py b/tensorflow/python/data/experimental/kernel_tests/sleep_test.py index bf53acc82a..1a6d5522ef 100644 --- a/tensorflow/python/data/experimental/kernel_tests/sleep_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/sleep_test.py @@ -38,14 +38,14 @@ class SleepTest(test_base.DatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) start_time = time.time() for i in range(10): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) end_time = time.time() self.assertGreater(end_time - start_time, (10 * sleep_microseconds) / 1e6) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py b/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py index a2c1169638..eb66927ee5 100644 --- a/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/sql_dataset_test.py @@ -39,10 +39,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) for _ in range(2): # Dataset is repeated. See setUp. - self.assertEqual((b"John", b"Doe", b"Hi!"), sess.run(get_next)) - self.assertEqual((b"Jane", b"Moe", b"Hi again!"), sess.run(get_next)) + self.assertEqual((b"John", b"Doe", b"Hi!"), self.evaluate(get_next)) + self.assertEqual((b"Jane", b"Moe", b"Hi again!"), + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that SqlDataset works on a join query. def testReadResultSetJoinQuery(self): @@ -58,9 +59,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ON students.first_name = people.first_name " "AND students.last_name = people.last_name" }) - self.assertEqual((b"John", b"California", b"Hi!"), sess.run(get_next)) + self.assertEqual((b"John", b"California", b"Hi!"), + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that SqlDataset can read a database entry with a null-terminator # in the middle of the text and place the entry in a `string` tensor. @@ -75,10 +77,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT first_name, last_name, favorite_nonsense_word " "FROM students ORDER BY first_name DESC" }) - self.assertEqual((b"John", b"Doe", b"n\0nsense"), sess.run(get_next)) - self.assertEqual((b"Jane", b"Moe", b"nonsense\0"), sess.run(get_next)) + self.assertEqual((b"John", b"Doe", b"n\0nsense"), self.evaluate(get_next)) + self.assertEqual((b"Jane", b"Moe", b"nonsense\0"), + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that SqlDataset works when used on two different queries. # Because the output types of the dataset must be determined at graph-creation @@ -93,21 +96,22 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, last_name, motto FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", b"Doe", b"Hi!"), sess.run(get_next)) - self.assertEqual((b"Jane", b"Moe", b"Hi again!"), sess.run(get_next)) + self.assertEqual((b"John", b"Doe", b"Hi!"), self.evaluate(get_next)) + self.assertEqual((b"Jane", b"Moe", b"Hi again!"), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) sess.run( init_op, feed_dict={ self.query: "SELECT first_name, last_name, state FROM people " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", b"Doe", b"California"), sess.run(get_next)) + self.assertEqual((b"John", b"Doe", b"California"), + self.evaluate(get_next)) self.assertEqual((b"Benjamin", b"Franklin", b"Pennsylvania"), - sess.run(get_next)) + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that an `OutOfRangeError` is raised on the first call to # `get_next_str_only` if result set is empty. @@ -122,7 +126,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "WHERE first_name = 'Nonexistent'" }) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that an error is raised when `driver_name` is invalid. def testReadResultSetWithInvalidDriverName(self): @@ -151,7 +155,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) with self.assertRaises(errors.UnknownError): - sess.run(get_next) + self.evaluate(get_next) # Test that an error is raised when there is a syntax error in `query`. def testReadResultSetOfQueryWithSyntaxError(self): @@ -166,7 +170,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) with self.assertRaises(errors.UnknownError): - sess.run(get_next) + self.evaluate(get_next) # Test that an error is raised when the number of columns in `query` # does not match the length of `output_types`. @@ -181,7 +185,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) with self.assertRaises(errors.InvalidArgumentError): - sess.run(get_next) + self.evaluate(get_next) # Test that no results are returned when `query` is an insert query rather # than a select query. In particular, the error refers to the number of @@ -199,7 +203,7 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "VALUES ('Foo', 'Bar', 'Baz'), ('Fizz', 'Buzz', 'Fizzbuzz')" }) with self.assertRaises(errors.InvalidArgumentError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer from a SQLite database table and # place it in an `int8` tensor. @@ -212,10 +216,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), sess.run(get_next)) - self.assertEqual((b"Jane", 127), sess.run(get_next)) + self.assertEqual((b"John", 9), self.evaluate(get_next)) + self.assertEqual((b"Jane", 127), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a negative or 0-valued integer from a # SQLite database table and place it in an `int8` tensor. @@ -230,9 +234,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "FROM students " "WHERE first_name = 'John' ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0, -2), sess.run(get_next)) + self.assertEqual((b"John", 0, -2), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a large (positive or negative) integer from # a SQLite database table and place it in an `int8` tensor. @@ -246,11 +250,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT desk_number, favorite_negative_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((9, -2), sess.run(get_next)) + self.assertEqual((9, -2), self.evaluate(get_next)) # Max and min values of int8 - self.assertEqual((127, -128), sess.run(get_next)) + self.assertEqual((127, -128), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer from a SQLite database table and # place it in an `int16` tensor. @@ -263,10 +267,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), sess.run(get_next)) - self.assertEqual((b"Jane", 127), sess.run(get_next)) + self.assertEqual((b"John", 9), self.evaluate(get_next)) + self.assertEqual((b"Jane", 127), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a negative or 0-valued integer from a # SQLite database table and place it in an `int16` tensor. @@ -281,9 +285,9 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "FROM students " "WHERE first_name = 'John' ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0, -2), sess.run(get_next)) + self.assertEqual((b"John", 0, -2), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a large (positive or negative) integer from # a SQLite database table and place it in an `int16` tensor. @@ -297,11 +301,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "FROM students ORDER BY first_name DESC" }) # Max value of int16 - self.assertEqual((b"John", 32767), sess.run(get_next)) + self.assertEqual((b"John", 32767), self.evaluate(get_next)) # Min value of int16 - self.assertEqual((b"Jane", -32768), sess.run(get_next)) + self.assertEqual((b"Jane", -32768), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer from a SQLite database table and # place it in an `int32` tensor. @@ -314,8 +318,8 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), sess.run(get_next)) - self.assertEqual((b"Jane", 127), sess.run(get_next)) + self.assertEqual((b"John", 9), self.evaluate(get_next)) + self.assertEqual((b"Jane", 127), self.evaluate(get_next)) # Test that `SqlDataset` can read a negative or 0-valued integer from a # SQLite database table and place it in an `int32` tensor. @@ -328,10 +332,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, income FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0), sess.run(get_next)) - self.assertEqual((b"Jane", -20000), sess.run(get_next)) + self.assertEqual((b"John", 0), self.evaluate(get_next)) + self.assertEqual((b"Jane", -20000), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a large (positive or negative) integer from # a SQLite database table and place it in an `int32` tensor. @@ -345,11 +349,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Max value of int32 - self.assertEqual((b"John", 2147483647), sess.run(get_next)) + self.assertEqual((b"John", 2147483647), self.evaluate(get_next)) # Min value of int32 - self.assertEqual((b"Jane", -2147483648), sess.run(get_next)) + self.assertEqual((b"Jane", -2147483648), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a numeric `varchar` from a SQLite database # table and place it in an `int32` tensor. @@ -362,10 +366,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, school_id FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 123), sess.run(get_next)) - self.assertEqual((b"Jane", 1000), sess.run(get_next)) + self.assertEqual((b"John", 123), self.evaluate(get_next)) + self.assertEqual((b"Jane", 1000), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer from a SQLite database table # and place it in an `int64` tensor. @@ -378,10 +382,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), sess.run(get_next)) - self.assertEqual((b"Jane", 127), sess.run(get_next)) + self.assertEqual((b"John", 9), self.evaluate(get_next)) + self.assertEqual((b"Jane", 127), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a negative or 0-valued integer from a # SQLite database table and place it in an `int64` tensor. @@ -394,10 +398,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, income FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 0), sess.run(get_next)) - self.assertEqual((b"Jane", -20000), sess.run(get_next)) + self.assertEqual((b"John", 0), self.evaluate(get_next)) + self.assertEqual((b"Jane", -20000), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a large (positive or negative) integer from # a SQLite database table and place it in an `int64` tensor. @@ -412,11 +416,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Max value of int64 - self.assertEqual((b"John", 9223372036854775807), sess.run(get_next)) + self.assertEqual((b"John", 9223372036854775807), self.evaluate(get_next)) # Min value of int64 - self.assertEqual((b"Jane", -9223372036854775808), sess.run(get_next)) + self.assertEqual((b"Jane", -9223372036854775808), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer from a SQLite database table and # place it in a `uint8` tensor. @@ -429,10 +433,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), sess.run(get_next)) - self.assertEqual((b"Jane", 127), sess.run(get_next)) + self.assertEqual((b"John", 9), self.evaluate(get_next)) + self.assertEqual((b"Jane", 127), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read the minimum and maximum uint8 values from a # SQLite database table and place them in `uint8` tensors. @@ -446,11 +450,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Min value of uint8 - self.assertEqual((b"John", 0), sess.run(get_next)) + self.assertEqual((b"John", 0), self.evaluate(get_next)) # Max value of uint8 - self.assertEqual((b"Jane", 255), sess.run(get_next)) + self.assertEqual((b"Jane", 255), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer from a SQLite database table # and place it in a `uint16` tensor. @@ -463,10 +467,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, desk_number FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", 9), sess.run(get_next)) - self.assertEqual((b"Jane", 127), sess.run(get_next)) + self.assertEqual((b"John", 9), self.evaluate(get_next)) + self.assertEqual((b"Jane", 127), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read the minimum and maximum uint16 values from a # SQLite database table and place them in `uint16` tensors. @@ -480,11 +484,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name DESC" }) # Min value of uint16 - self.assertEqual((b"John", 0), sess.run(get_next)) + self.assertEqual((b"John", 0), self.evaluate(get_next)) # Max value of uint16 - self.assertEqual((b"Jane", 65535), sess.run(get_next)) + self.assertEqual((b"Jane", 65535), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a 0-valued and 1-valued integer from a # SQLite database table and place them as `True` and `False` respectively @@ -499,10 +503,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT first_name, registration_complete FROM students " "ORDER BY first_name DESC" }) - self.assertEqual((b"John", True), sess.run(get_next)) - self.assertEqual((b"Jane", False), sess.run(get_next)) + self.assertEqual((b"John", True), self.evaluate(get_next)) + self.assertEqual((b"Jane", False), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read an integer that is not 0-valued or 1-valued # from a SQLite database table and place it as `True` in a `bool` tensor. @@ -515,10 +519,10 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.query: "SELECT first_name, favorite_medium_sized_number " "FROM students ORDER BY first_name DESC" }) - self.assertEqual((b"John", True), sess.run(get_next)) - self.assertEqual((b"Jane", True), sess.run(get_next)) + self.assertEqual((b"John", True), self.evaluate(get_next)) + self.assertEqual((b"Jane", True), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a float from a SQLite database table # and place it in a `float64` tensor. @@ -533,10 +537,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "SELECT first_name, last_name, victories FROM townspeople " "ORDER BY first_name" }) - self.assertEqual((b"George", b"Washington", 20.0), sess.run(get_next)) - self.assertEqual((b"John", b"Adams", -19.95), sess.run(get_next)) + self.assertEqual((b"George", b"Washington", 20.0), + self.evaluate(get_next)) + self.assertEqual((b"John", b"Adams", -19.95), self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a float from a SQLite database table beyond # the precision of 64-bit IEEE, without throwing an error. Test that @@ -555,13 +560,13 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): self.assertEqual( (b"George", b"Washington", 1331241.321342132321324589798264627463827647382647382643874), - sess.run(get_next)) + self.evaluate(get_next)) self.assertEqual( (b"John", b"Adams", 1331241321342132321324589798264627463827647382647382643874.0), - sess.run(get_next)) + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) # Test that `SqlDataset` can read a float from a SQLite database table, # representing the largest integer representable as a 64-bit IEEE float @@ -579,11 +584,11 @@ class SqlDatasetTest(sql_dataset_test_base.SqlDatasetTestBase): "ORDER BY first_name" }) self.assertNotEqual((b"George", b"Washington", 9007199254740992.0), - sess.run(get_next)) + self.evaluate(get_next)) self.assertNotEqual((b"John", b"Adams", 9007199254740991.0), - sess.run(get_next)) + self.evaluate(get_next)) with self.assertRaises(errors.OutOfRangeError): - sess.run(get_next) + self.evaluate(get_next) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py b/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py index d5f265d8a8..e816006933 100644 --- a/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/stats_dataset_ops_test.py @@ -70,18 +70,18 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) expected_sum = 0.0 for i in range(100): self.assertAllEqual( - np.array([i] * i, dtype=np.int64), sess.run(next_element)) - summary_str = sess.run(summary_t) + np.array([i] * i, dtype=np.int64), self.evaluate(next_element)) + summary_str = self.evaluate(summary_t) self._assertSummaryHasCount(summary_str, "bytes_produced", float(i + 1)) expected_sum += i * 8.0 self._assertSummaryHasSum(summary_str, "bytes_produced", expected_sum) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - summary_str = sess.run(summary_t) + self.evaluate(next_element) + summary_str = self.evaluate(summary_t) self._assertSummaryHasCount(summary_str, "bytes_produced", 100.0) self._assertSummaryHasSum(summary_str, "bytes_produced", expected_sum) @@ -95,14 +95,15 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(100): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency", float(i + 1)) + self.evaluate(summary_t), "record_latency", float(i + 1)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 100.0) + self.evaluate(next_element) + self._assertSummaryHasCount( + self.evaluate(summary_t), "record_latency", 100.0) def testPrefetchBufferUtilization(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -114,11 +115,11 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(100): self.assertAllEqual( - np.array([i] * i, dtype=np.int64), sess.run(next_element)) - summary_str = sess.run(summary_t) + np.array([i] * i, dtype=np.int64), self.evaluate(next_element)) + summary_str = self.evaluate(summary_t) self._assertSummaryHasCount(summary_str, "Prefetch::buffer_utilization", float(i + 1)) self._assertSummaryContains(summary_str, "Prefetch::buffer_capacity") @@ -126,8 +127,8 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): self._assertSummaryHasRange(summary_str, "Prefetch::buffer_utilization", 0, 1) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - summary_str = sess.run(summary_t) + self.evaluate(next_element) + summary_str = self.evaluate(summary_t) self._assertSummaryHasCount(summary_str, "Prefetch::buffer_utilization", 100) @@ -141,17 +142,17 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(10): self.assertAllEqual( - np.array([i] * i, dtype=np.int64), sess.run(next_element)) - summary_str = sess.run(summary_t) + np.array([i] * i, dtype=np.int64), self.evaluate(next_element)) + summary_str = self.evaluate(summary_t) self._assertSummaryHasScalarValue(summary_str, "Prefetch::buffer_capacity", 0) self._assertSummaryHasScalarValue(summary_str, "Prefetch::buffer_size", 0) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testFilteredElementsStats(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -163,20 +164,21 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.test_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(34): - self.assertEqual(i * 3, sess.run(next_element)) + self.assertEqual(i * 3, self.evaluate(next_element)) if i is not 0: self._assertSummaryHasScalarValue( - sess.run(summary_t), "Filter::dropped_elements", float(i * 2)) + self.evaluate(summary_t), "Filter::dropped_elements", + float(i * 2)) self._assertSummaryHasScalarValue( - sess.run(summary_t), "Filter::filtered_elements", float(i + 1)) + self.evaluate(summary_t), "Filter::filtered_elements", float(i + 1)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) self._assertSummaryHasScalarValue( - sess.run(summary_t), "Filter::dropped_elements", 67.0) + self.evaluate(summary_t), "Filter::dropped_elements", 67.0) self._assertSummaryHasScalarValue( - sess.run(summary_t), "Filter::filtered_elements", 34.0) + self.evaluate(summary_t), "Filter::filtered_elements", 34.0) def testMapBufferUtilization(self, dataset_transformation): @@ -257,15 +259,16 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): with self.cached_session() as sess: for j in range(5): - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(100): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency", float((j * 100) + i + 1)) + self.evaluate(summary_t), "record_latency", + float((j * 100) + i + 1)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency", (j + 1) * 100.0) + self.evaluate(summary_t), "record_latency", (j + 1) * 100.0) def testNoAggregatorRegistered(self, dataset_transformation): dataset = dataset_ops.Dataset.range(100).apply( @@ -274,11 +277,11 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): next_element = iterator.get_next() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(100): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testMultipleTags(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -291,18 +294,19 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(100): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency", float(i + 1)) + self.evaluate(summary_t), "record_latency", float(i + 1)) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency_2", float(i + 1)) + self.evaluate(summary_t), "record_latency_2", float(i + 1)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 100.0) + self.evaluate(next_element) + self._assertSummaryHasCount( + self.evaluate(summary_t), "record_latency", 100.0) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency_2", 100.0) + self.evaluate(summary_t), "record_latency_2", 100.0) def testRepeatedTags(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -315,14 +319,15 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for i in range(100): - self.assertEqual(i, sess.run(next_element)) + self.assertEqual(i, self.evaluate(next_element)) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency", float(2 * (i + 1))) + self.evaluate(summary_t), "record_latency", float(2 * (i + 1))) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 200.0) + self.evaluate(next_element) + self._assertSummaryHasCount( + self.evaluate(summary_t), "record_latency", 200.0) def testMultipleIteratorsSameAggregator(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -335,14 +340,15 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.cached_session() as sess: - sess.run([iterator_0.initializer, iterator_1.initializer]) + self.evaluate([iterator_0.initializer, iterator_1.initializer]) for i in range(100): - self.assertEqual(i * 2, sess.run(next_element)) + self.assertEqual(i * 2, self.evaluate(next_element)) self._assertSummaryHasCount( - sess.run(summary_t), "record_latency", float(2 * (i + 1))) + self.evaluate(summary_t), "record_latency", float(2 * (i + 1))) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) - self._assertSummaryHasCount(sess.run(summary_t), "record_latency", 200.0) + self.evaluate(next_element) + self._assertSummaryHasCount( + self.evaluate(summary_t), "record_latency", 200.0) def testMultipleDatasetWithPrefixes(self, dataset_transformation): aggregator = stats_aggregator.StatsAggregator() @@ -358,19 +364,19 @@ class StatsDatasetTest(stats_dataset_test_base.StatsDatasetTestBase): summary_t = aggregator.get_summary() with self.test_session() as sess: - sess.run([iterator_0.initializer, iterator_1.initializer]) + self.evaluate([iterator_0.initializer, iterator_1.initializer]) for i in range(100): - self.assertEqual(i * 2, sess.run(next_element)) + self.assertEqual(i * 2, self.evaluate(next_element)) self._assertSummaryHasCount( - sess.run(summary_t), "dataset1_record_latency", float(i + 1)) + self.evaluate(summary_t), "dataset1_record_latency", float(i + 1)) self._assertSummaryHasCount( - sess.run(summary_t), "dataset2_record_latency", float(i + 1)) + self.evaluate(summary_t), "dataset2_record_latency", float(i + 1)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) self._assertSummaryHasCount( - sess.run(summary_t), "dataset1_record_latency", 100.0) + self.evaluate(summary_t), "dataset1_record_latency", 100.0) self._assertSummaryHasCount( - sess.run(summary_t), "dataset2_record_latency", 100.0) + self.evaluate(summary_t), "dataset2_record_latency", 100.0) @parameterized.named_parameters( @@ -417,20 +423,21 @@ class FeatureStatsDatasetTest( summary_t = aggregator.get_summary() with self.test_session() as sess: - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for _ in range(num_output): - sess.run(next_element) + self.evaluate(next_element) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) self._assertSummaryHasCount( - sess.run(summary_t), "record_stats_features", total_records) + self.evaluate(summary_t), "record_stats_features", total_records) self._assertSummaryHasCount( - sess.run(summary_t), "record_stats_feature-values", total_records) + self.evaluate(summary_t), "record_stats_feature-values", + total_records) self._assertSummaryHasSum( - sess.run(summary_t), "record_stats_features", total_records * 4) + self.evaluate(summary_t), "record_stats_features", total_records * 4) self._assertSummaryHasSum( - sess.run(summary_t), "record_stats_feature-values", + self.evaluate(summary_t), "record_stats_feature-values", self._sum_keywords(1) * num_epochs + 3 * total_records) diff --git a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py index f9b800fe67..cb94bb4144 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unbatch_test.py @@ -47,9 +47,9 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: sess.run(iterator.initializer, feed_dict={placeholder: [0, 1, 2, 3]}) for i in range(4): - self.assertEqual(i, sess.run(next_elem)) + self.assertEqual(i, self.evaluate(next_elem)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_elem) + self.evaluate(next_elem) def testUnbatchScalarDataset(self): data = tuple([math_ops.range(10) for _ in range(3)]) @@ -65,10 +65,10 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual((i,) * 3, sess.run(op)) + self.assertEqual((i,) * 3, self.evaluate(op)) with self.assertRaises(errors.OutOfRangeError): - sess.run(op) + self.evaluate(op) def testUnbatchDatasetWithStrings(self): data = tuple([math_ops.range(10) for _ in range(3)]) @@ -85,10 +85,10 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual((i, compat.as_bytes(str(i)), i), sess.run(op)) + self.assertEqual((i, compat.as_bytes(str(i)), i), self.evaluate(op)) with self.assertRaises(errors.OutOfRangeError): - sess.run(op) + self.evaluate(op) def testUnbatchDatasetWithSparseTensor(self): st = sparse_tensor.SparseTensorValue( @@ -104,12 +104,12 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - st_row = sess.run(next_element) + st_row = self.evaluate(next_element) self.assertEqual([i], st_row.indices) self.assertEqual([i], st_row.values) self.assertEqual([10], st_row.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testUnbatchDatasetWithDenseAndSparseTensor(self): st = sparse_tensor.SparseTensorValue( @@ -125,13 +125,13 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - dense_elem, st_row = sess.run(next_element) + dense_elem, st_row = self.evaluate(next_element) self.assertEqual(i, dense_elem) self.assertEqual([i], st_row.indices) self.assertEqual([i], st_row.values) self.assertEqual([10], st_row.dense_shape) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testUnbatchSingleElementTupleDataset(self): data = tuple([(math_ops.range(10),) for _ in range(3)]) @@ -147,10 +147,10 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): - self.assertEqual(((i,),) * 3, sess.run(op)) + self.assertEqual(((i,),) * 3, self.evaluate(op)) with self.assertRaises(errors.OutOfRangeError): - sess.run(op) + self.evaluate(op) def testUnbatchMultiElementTupleDataset(self): data = tuple([(math_ops.range(10 * i, 10 * i + 10), @@ -168,10 +168,10 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: for i in range(10): self.assertEqual(((i, b"hi"), (10 + i, b"hi"), (20 + i, b"hi")), - sess.run(op)) + self.evaluate(op)) with self.assertRaises(errors.OutOfRangeError): - sess.run(op) + self.evaluate(op) def testUnbatchEmpty(self): data = dataset_ops.Dataset.from_tensors( @@ -183,7 +183,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): with self.cached_session() as sess: with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testUnbatchStaticShapeMismatch(self): data = dataset_ops.Dataset.from_tensors((np.arange(7), np.arange(8), @@ -208,7 +208,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): ph2: np.arange(8).astype(np.int32) }) with self.assertRaises(errors.InvalidArgumentError): - sess.run(next_element) + self.evaluate(next_element) # No 0th dimension (i.e. scalar value) for one component. sess.run( @@ -218,7 +218,7 @@ class UnbatchTest(test_base.DatasetTestBase, parameterized.TestCase): ph2: 7 }) with self.assertRaises(errors.InvalidArgumentError): - sess.run(next_element) + self.evaluate(next_element) if __name__ == "__main__": diff --git a/tensorflow/python/data/experimental/kernel_tests/unique_test.py b/tensorflow/python/data/experimental/kernel_tests/unique_test.py index 847cff26b0..91f4bc84e9 100644 --- a/tensorflow/python/data/experimental/kernel_tests/unique_test.py +++ b/tensorflow/python/data/experimental/kernel_tests/unique_test.py @@ -49,13 +49,13 @@ class UniqueTest(test_base.DatasetTestBase): with self.cached_session() as sess: for test_case, expected in test_cases: current_test_case = test_case - sess.run(iterator.initializer) + self.evaluate(iterator.initializer) for element in expected: if dtype == dtypes.string: element = compat.as_bytes(element) - self.assertAllEqual(element, sess.run(next_element)) + self.assertAllEqual(element, self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testSimpleInt(self): for dtype in [dtypes.int32, dtypes.int64]: diff --git a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py index 2ca9961585..886c9acc03 100644 --- a/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py +++ b/tensorflow/python/data/kernel_tests/multi_device_iterator_test.py @@ -41,7 +41,7 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) def testBasic(self): dataset = dataset_ops.Dataset.range(10) @@ -51,13 +51,13 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, sess.run(elem_on_1)) - self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) def testOneOnSameDevice(self): with ops.device("/cpu:0"): @@ -68,13 +68,13 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, sess.run(elem_on_1)) - self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) def testRepeatDevices(self): with ops.device("/cpu:0"): @@ -86,17 +86,17 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 20, 4): - self.assertEqual(i, sess.run(elem_on_1)) - self.assertEqual(i + 1, sess.run(elem_on_2)) - self.assertEqual(i + 2, sess.run(elem_on_3)) - self.assertEqual(i + 3, sess.run(elem_on_4)) + self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(i + 2, self.evaluate(elem_on_3)) + self.assertEqual(i + 3, self.evaluate(elem_on_4)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) - sess.run(elem_on_3) - sess.run(elem_on_4) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) + self.evaluate(elem_on_3) + self.evaluate(elem_on_4) def testNotFullyDivisible(self): dataset = dataset_ops.Dataset.range(9) @@ -106,14 +106,14 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 8, 2): - self.assertEqual(i, sess.run(elem_on_1)) - self.assertEqual(i + 1, sess.run(elem_on_2)) - self.assertEqual(8, sess.run(elem_on_1)) + self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) + self.assertEqual(8, self.evaluate(elem_on_1)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) def testGetNextAsOptional(self): dataset = dataset_ops.Dataset.range(9) @@ -127,7 +127,7 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 8, 2): elem_on_1_has_value, elem_on_1_value = sess.run( [elem_on_1_has_value_t, elem_on_1_t]) @@ -141,12 +141,12 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): [elem_on_1_has_value_t, elem_on_1_t]) self.assertTrue(elem_on_1_has_value) self.assertEqual(8, elem_on_1_value) - self.assertFalse(sess.run(elem_on_1_has_value_t)) - self.assertFalse(sess.run(elem_on_2_has_value_t)) + self.assertFalse(self.evaluate(elem_on_1_has_value_t)) + self.assertFalse(self.evaluate(elem_on_2_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): - sess.run(elem_on_1_t) + self.evaluate(elem_on_1_t) with self.assertRaises(errors.InvalidArgumentError): - sess.run(elem_on_2_t) + self.evaluate(elem_on_2_t) def testUneven(self): dataset = dataset_ops.Dataset.range(10) @@ -156,14 +156,14 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i, self.evaluate(elem_on_1)) for i in range(0, 10, 2): - self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) def testMultipleInitializations(self): with ops.device("/cpu:0"): @@ -180,7 +180,8 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): with self.test_session(config=config) as sess: for i in range(1000): sess.run(init_op, feed_dict={epoch: i}) - self.assertEqual([(i, 0), (i, 1)], sess.run([elem_on_1, elem_on_2])) + self.assertEqual([(i, 0), (i, 1)], self.evaluate([elem_on_1, + elem_on_2])) def testBasicGpu(self): if not test_util.is_gpu_available(): @@ -193,13 +194,13 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2, "GPU": 1}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, sess.run(elem_on_1)) - self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) def testUnevenGpu(self): if not test_util.is_gpu_available(): @@ -212,14 +213,14 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2, "GPU": 1}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, sess.run(elem_on_1)) + self.assertEqual(i, self.evaluate(elem_on_1)) for i in range(0, 10, 2): - self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) def testGetNextAsOptionalGpu(self): if not test_util.is_gpu_available(): @@ -236,7 +237,7 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 2, "GPU": 1}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 8, 2): elem_on_1_has_value, elem_on_1_value = sess.run( [elem_on_1_has_value_t, elem_on_1_t]) @@ -250,12 +251,12 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): [elem_on_1_has_value_t, elem_on_1_t]) self.assertTrue(elem_on_1_has_value) self.assertEqual(8, elem_on_1_value) - self.assertFalse(sess.run(elem_on_1_has_value_t)) - self.assertFalse(sess.run(elem_on_2_has_value_t)) + self.assertFalse(self.evaluate(elem_on_1_has_value_t)) + self.assertFalse(self.evaluate(elem_on_2_has_value_t)) with self.assertRaises(errors.InvalidArgumentError): - sess.run(elem_on_1_t) + self.evaluate(elem_on_1_t) with self.assertRaises(errors.InvalidArgumentError): - sess.run(elem_on_2_t) + self.evaluate(elem_on_2_t) def testOptimization(self): dataset = dataset_ops.Dataset.range(10) @@ -273,13 +274,13 @@ class MultiDeviceIteratorTest(test_base.DatasetTestBase): config = config_pb2.ConfigProto(device_count={"CPU": 3}) with self.test_session(config=config) as sess: - sess.run(multi_device_iterator.initializer) + self.evaluate(multi_device_iterator.initializer) for i in range(0, 10, 2): - self.assertEqual(i, sess.run(elem_on_1)) - self.assertEqual(i + 1, sess.run(elem_on_2)) + self.assertEqual(i, self.evaluate(elem_on_1)) + self.assertEqual(i + 1, self.evaluate(elem_on_2)) with self.assertRaises(errors.OutOfRangeError): - sess.run(elem_on_1) - sess.run(elem_on_2) + self.evaluate(elem_on_1) + self.evaluate(elem_on_2) if __name__ == "__main__": diff --git a/tensorflow/python/data/util/convert_test.py b/tensorflow/python/data/util/convert_test.py index 89c3afb296..3058e2b3f6 100644 --- a/tensorflow/python/data/util/convert_test.py +++ b/tensorflow/python/data/util/convert_test.py @@ -30,47 +30,52 @@ class ConvertTest(test.TestCase): def testInteger(self): resp = convert.optional_param_to_tensor("foo", 3) - with self.cached_session() as sess: - self.assertEqual(3, sess.run(resp)) + self.assertEqual(3, self.evaluate(resp)) def testIntegerDefault(self): resp = convert.optional_param_to_tensor("foo", None) - with self.cached_session() as sess: - self.assertEqual(0, sess.run(resp)) + self.assertEqual(0, self.evaluate(resp)) def testStringDefault(self): resp = convert.optional_param_to_tensor("bar", None, "default", dtypes.string) - with self.cached_session() as sess: - self.assertEqual(compat.as_bytes("default"), sess.run(resp)) + self.assertEqual(compat.as_bytes("default"), self.evaluate(resp)) def testString(self): resp = convert.optional_param_to_tensor("bar", "value", "default", dtypes.string) - with self.cached_session() as sess: - self.assertEqual(compat.as_bytes("value"), sess.run(resp)) + self.assertEqual(compat.as_bytes("value"), self.evaluate(resp)) def testPartialShapeToTensorKnownDimension(self): - with self.cached_session() as sess: - self.assertAllEqual([1], sess.run(convert.partial_shape_to_tensor( - tensor_shape.TensorShape([1])))) - self.assertAllEqual([1], sess.run(convert.partial_shape_to_tensor((1,)))) - self.assertAllEqual([1], sess.run(convert.partial_shape_to_tensor([1]))) - self.assertAllEqual([1], sess.run(convert.partial_shape_to_tensor( - constant_op.constant([1], dtype=dtypes.int64)))) + self.assertAllEqual([1], + self.evaluate( + convert.partial_shape_to_tensor( + tensor_shape.TensorShape([1])))) + self.assertAllEqual([1], self.evaluate( + convert.partial_shape_to_tensor((1,)))) + self.assertAllEqual([1], self.evaluate( + convert.partial_shape_to_tensor([1]))) + self.assertAllEqual([1], + self.evaluate( + convert.partial_shape_to_tensor( + constant_op.constant([1], dtype=dtypes.int64)))) def testPartialShapeToTensorUnknownDimension(self): - with self.cached_session() as sess: - self.assertAllEqual([-1], sess.run(convert.partial_shape_to_tensor( - tensor_shape.TensorShape([None])))) - self.assertAllEqual([-1], sess.run(convert.partial_shape_to_tensor( - (None,)))) - self.assertAllEqual([-1], sess.run(convert.partial_shape_to_tensor( - [None]))) - self.assertAllEqual([-1], sess.run(convert.partial_shape_to_tensor( - [-1]))) - self.assertAllEqual([-1], sess.run(convert.partial_shape_to_tensor( - constant_op.constant([-1], dtype=dtypes.int64)))) + self.assertAllEqual([-1], + self.evaluate( + convert.partial_shape_to_tensor( + tensor_shape.TensorShape([None])))) + self.assertAllEqual([-1], + self.evaluate(convert.partial_shape_to_tensor((None,)))) + self.assertAllEqual([-1], + self.evaluate(convert.partial_shape_to_tensor([None]))) + self.assertAllEqual([-1], + self.evaluate(convert.partial_shape_to_tensor([-1]))) + self.assertAllEqual([-1], + self.evaluate( + convert.partial_shape_to_tensor( + constant_op.constant([-1], + dtype=dtypes.int64)))) with self.assertRaisesRegexp( ValueError, r"The given shape .* must be a 1-D tensor of tf.int64 " @@ -84,42 +89,63 @@ class ConvertTest(test.TestCase): convert.partial_shape_to_tensor(constant_op.constant([1., 1.])) def testPartialShapeToTensorMultipleDimensions(self): - with self.cached_session() as sess: - self.assertAllEqual([3, 6], sess.run(convert.partial_shape_to_tensor( - tensor_shape.TensorShape([3, 6])))) - self.assertAllEqual([3, 6], sess.run(convert.partial_shape_to_tensor( - (3, 6)))) - self.assertAllEqual([3, 6], sess.run(convert.partial_shape_to_tensor( - [3, 6]))) - self.assertAllEqual([3, 6], sess.run(convert.partial_shape_to_tensor( - constant_op.constant([3, 6], dtype=dtypes.int64)))) - - self.assertAllEqual([3, -1], sess.run(convert.partial_shape_to_tensor( - tensor_shape.TensorShape([3, None])))) - self.assertAllEqual([3, -1], sess.run(convert.partial_shape_to_tensor( - (3, None)))) - self.assertAllEqual([3, -1], sess.run(convert.partial_shape_to_tensor( - [3, None]))) - self.assertAllEqual([3, -1], sess.run(convert.partial_shape_to_tensor( - constant_op.constant([3, -1], dtype=dtypes.int64)))) - - self.assertAllEqual([-1, -1], sess.run(convert.partial_shape_to_tensor( - tensor_shape.TensorShape([None, None])))) - self.assertAllEqual([-1, -1], sess.run(convert.partial_shape_to_tensor( - (None, None)))) - self.assertAllEqual([-1, -1], sess.run(convert.partial_shape_to_tensor( - [None, None]))) - self.assertAllEqual([-1, -1], sess.run(convert.partial_shape_to_tensor( - constant_op.constant([-1, -1], dtype=dtypes.int64)))) + self.assertAllEqual([3, 6], + self.evaluate( + convert.partial_shape_to_tensor( + tensor_shape.TensorShape([3, 6])))) + self.assertAllEqual([3, 6], + self.evaluate(convert.partial_shape_to_tensor((3, 6)))) + self.assertAllEqual([3, 6], + self.evaluate(convert.partial_shape_to_tensor([3, 6]))) + self.assertAllEqual([3, 6], + self.evaluate( + convert.partial_shape_to_tensor( + constant_op.constant([3, 6], + dtype=dtypes.int64)))) + + self.assertAllEqual([3, -1], + self.evaluate( + convert.partial_shape_to_tensor( + tensor_shape.TensorShape([3, None])))) + self.assertAllEqual([3, -1], + self.evaluate( + convert.partial_shape_to_tensor((3, None)))) + self.assertAllEqual([3, -1], + self.evaluate( + convert.partial_shape_to_tensor([3, None]))) + self.assertAllEqual([3, -1], + self.evaluate( + convert.partial_shape_to_tensor( + constant_op.constant([3, -1], + dtype=dtypes.int64)))) + + self.assertAllEqual([-1, -1], + self.evaluate( + convert.partial_shape_to_tensor( + tensor_shape.TensorShape([None, None])))) + self.assertAllEqual([-1, -1], + self.evaluate( + convert.partial_shape_to_tensor((None, None)))) + self.assertAllEqual([-1, -1], + self.evaluate( + convert.partial_shape_to_tensor([None, None]))) + self.assertAllEqual([-1, -1], + self.evaluate( + convert.partial_shape_to_tensor( + constant_op.constant([-1, -1], + dtype=dtypes.int64)))) def testPartialShapeToTensorScalar(self): - with self.cached_session() as sess: - self.assertAllEqual([], sess.run(convert.partial_shape_to_tensor( - tensor_shape.TensorShape([])))) - self.assertAllEqual([], sess.run(convert.partial_shape_to_tensor(()))) - self.assertAllEqual([], sess.run(convert.partial_shape_to_tensor([]))) - self.assertAllEqual([], sess.run(convert.partial_shape_to_tensor( - constant_op.constant([], dtype=dtypes.int64)))) + self.assertAllEqual([], + self.evaluate( + convert.partial_shape_to_tensor( + tensor_shape.TensorShape([])))) + self.assertAllEqual([], self.evaluate(convert.partial_shape_to_tensor(()))) + self.assertAllEqual([], self.evaluate(convert.partial_shape_to_tensor([]))) + self.assertAllEqual([], + self.evaluate( + convert.partial_shape_to_tensor( + constant_op.constant([], dtype=dtypes.int64)))) if __name__ == "__main__": diff --git a/tensorflow/python/debug/cli/analyzer_cli_test.py b/tensorflow/python/debug/cli/analyzer_cli_test.py index f197a9e4dc..5aa7d1bb4c 100644 --- a/tensorflow/python/debug/cli/analyzer_cli_test.py +++ b/tensorflow/python/debug/cli/analyzer_cli_test.py @@ -1583,7 +1583,7 @@ class AnalyzerCLISimpleMulAddTest(test_util.TensorFlowTestCase): x = variables.VariableV1([1, 3, 3, 7], name="x") _, idx = array_ops.unique(x, name="x_unique") idx_times_two = math_ops.multiply(idx, 2, name="idx_times_two") - sess.run(x.initializer) + self.evaluate(x.initializer) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph( diff --git a/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py b/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py index 1f67f8a0d4..34030c0adc 100644 --- a/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py +++ b/tensorflow/python/debug/lib/debug_graph_reconstruction_test.py @@ -126,8 +126,8 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): u = variables.Variable([12.0], name="u") v = variables.Variable([30.0], name="v") w = math_ops.add(u, v, name="w") - sess.run(u.initializer) - sess.run(v.initializer) + self.evaluate(u.initializer) + self.evaluate(v.initializer) self._compareOriginalAndReconstructedGraphDefs( sess, w, expected_output=[42.0]) @@ -139,7 +139,7 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): b = math_ops.add(a, a, name="b") with ops.control_dependencies([a, b]): c = math_ops.multiply(b, b, name="c") - sess.run(a.initializer) + self.evaluate(a.initializer) self._compareOriginalAndReconstructedGraphDefs( sess, c, expected_output=400.0) @@ -150,8 +150,8 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): y = variables.Variable(20.0, name="y") cond = control_flow_ops.cond( x > y, lambda: math_ops.add(x, 1), lambda: math_ops.add(y, 1)) - sess.run(x.initializer) - sess.run(y.initializer) + self.evaluate(x.initializer) + self.evaluate(y.initializer) self._compareOriginalAndReconstructedGraphDefs( sess, cond, expected_output=21.0) @@ -173,8 +173,8 @@ class ReconstructNonDebugGraphTest(test_util.TensorFlowTestCase): toy_loss = x * (u - v) train_op = gradient_descent.GradientDescentOptimizer( learning_rate=0.1).minimize(toy_loss, name="train_op") - sess.run(u.initializer) - sess.run(v.initializer) + self.evaluate(u.initializer) + self.evaluate(v.initializer) self._compareOriginalAndReconstructedGraphDefs(sess, train_op) diff --git a/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py b/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py index b0dc25851c..8eef45392f 100644 --- a/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py +++ b/tensorflow/python/debug/lib/session_debug_multi_gpu_test.py @@ -67,7 +67,7 @@ class SessionDebugMultiGPUTest(test_util.TensorFlowTestCase): u1 = math_ops.multiply(v, v, name="u1") w = math_ops.subtract(u1, u0, name="w") - sess.run(v.initializer) + self.evaluate(v.initializer) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph(run_options, sess.graph, diff --git a/tensorflow/python/debug/lib/source_utils_test.py b/tensorflow/python/debug/lib/source_utils_test.py index 4a8d4eaa99..a16d68329a 100644 --- a/tensorflow/python/debug/lib/source_utils_test.py +++ b/tensorflow/python/debug/lib/source_utils_test.py @@ -109,8 +109,8 @@ class SourceHelperTest(test_util.TensorFlowTestCase): self.w = math_ops.matmul(self.u, self.v, name="w") self.w_line_number = line_number_above() - sess.run(self.u.initializer) - sess.run(self.v.initializer) + self.evaluate(self.u.initializer) + self.evaluate(self.v.initializer) run_options = config_pb2.RunOptions(output_partition_graphs=True) debug_utils.watch_graph( diff --git a/tensorflow/python/distribute/input_ops_test.py b/tensorflow/python/distribute/input_ops_test.py index cbb93e8995..2689dbbec8 100644 --- a/tensorflow/python/distribute/input_ops_test.py +++ b/tensorflow/python/distribute/input_ops_test.py @@ -92,9 +92,9 @@ class AutoShardDatasetTest(test.TestCase): with self.cached_session() as sess: for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - self.assertAllEqual(record_fn(r, f), sess.run(next_element)) + self.assertAllEqual(record_fn(r, f), self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testTFRecordDataset(self): dataset = readers.TFRecordDataset(self._createTFRecordFiles()) @@ -138,10 +138,10 @@ class AutoShardDatasetTest(test.TestCase): actual, expected = [], [] for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - actual.append(sess.run(next_element)) + actual.append(self.evaluate(next_element)) expected.append(self._record(r, f)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) self.assertAllEqual(expected, actual) def testComplexPipeline(self): @@ -171,9 +171,9 @@ class AutoShardDatasetTest(test.TestCase): num_iterations = (self._num_files * self._num_records * num_epochs) // ( self._num_shards * batch_size) for _ in range(num_iterations): - actual.extend(sess.run(next_element)) + actual.extend(self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) expected = [] for f in range(0, self._num_files, self._num_shards): @@ -205,12 +205,13 @@ class AutoShardDatasetTest(test.TestCase): with self.cached_session() as sess: for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - self.assertAllEqual(self._record(r, f), sess.run(next_element)) + self.assertAllEqual(self._record(r, f), self.evaluate(next_element)) for f in range(self._shard_index, self._num_files, self._num_shards): for r in range(self._num_records): - self.assertAllEqual(self._text_line(r, f), sess.run(next_element)) + self.assertAllEqual( + self._text_line(r, f), self.evaluate(next_element)) with self.assertRaises(errors.OutOfRangeError): - sess.run(next_element) + self.evaluate(next_element) def testTextLineReader(self): dataset = readers.TextLineDataset(self._createTextFiles()) diff --git a/tensorflow/python/eager/def_function_test.py b/tensorflow/python/eager/def_function_test.py index f0f71a219e..54991344b7 100644 --- a/tensorflow/python/eager/def_function_test.py +++ b/tensorflow/python/eager/def_function_test.py @@ -149,9 +149,9 @@ class DefFunctionTest(test.TestCase): result = fn(3.0) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllEqual(sess.run(state[0]), 2.0) - self.assertAllEqual(sess.run(result), 6.0) + self.assertAllEqual(self.evaluate(result), 6.0) def testLegacyGraphModeVariablesNonTrivialInitializer(self): with ops.Graph().as_default(), self.test_session() as sess: @@ -168,9 +168,9 @@ class DefFunctionTest(test.TestCase): result = fn(3.0) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllEqual(sess.run(state[0]), 6.0) - self.assertAllEqual(sess.run(result), 18.0) + self.assertAllEqual(self.evaluate(result), 18.0) def testLegacyGraphModeInputDependentInitializerFails(self): with ops.Graph().as_default(): diff --git a/tensorflow/python/eager/function_gradients_test.py b/tensorflow/python/eager/function_gradients_test.py index d4f8aaa7e3..1ba596573f 100644 --- a/tensorflow/python/eager/function_gradients_test.py +++ b/tensorflow/python/eager/function_gradients_test.py @@ -78,7 +78,7 @@ class FunctionGradientsTest(test.TestCase, parameterized.TestCase): c = constant_op.constant([[2.]]) f_c = f(c) g, = gradients_impl.gradients(f_c, c) - self.assertAllEqual(sess.run(g).values, [[1.0]]) + self.assertAllEqual(self.evaluate(g).values, [[1.0]]) def testNoSymGradNestedDefun(self): diff --git a/tensorflow/python/eager/function_test.py b/tensorflow/python/eager/function_test.py index b58b09140d..a206b1f791 100644 --- a/tensorflow/python/eager/function_test.py +++ b/tensorflow/python/eager/function_test.py @@ -564,7 +564,7 @@ class FunctionTest(test.TestCase, parameterized.TestCase): variables.global_variables_initializer().run() call = def_function.function(o.call) op = call() - self.assertAllEqual(sess.run(op), 2.0) + self.assertAllEqual(self.evaluate(op), 2.0) def testGraphModeManyFunctions(self): with ops.Graph().as_default(), self.cached_session(): @@ -1732,7 +1732,7 @@ class FunctionTest(test.TestCase, parameterized.TestCase): function.register(cpu_boost, x) y = gpu_boost(x) - y_value = sess.run(y) + y_value = self.evaluate(y) if test.is_gpu_available(): self.assertEqual(y_value, 5.0) diff --git a/tensorflow/python/feature_column/feature_column_test.py b/tensorflow/python/feature_column/feature_column_test.py index e9b11c3960..2c70d66810 100644 --- a/tensorflow/python/feature_column/feature_column_test.py +++ b/tensorflow/python/feature_column/feature_column_test.py @@ -1027,7 +1027,7 @@ class CrossedColumnTest(test.TestCase): outputs = _transform_features(features, [price_cross_wire]) output = outputs[price_cross_wire] with self.cached_session() as sess: - output_val = sess.run(output) + output_val = self.evaluate(output) self.assertAllEqual( [[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [1, 3]], output_val.indices) for val in output_val.values: @@ -1886,7 +1886,8 @@ class LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], + self.evaluate(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc._numeric_column('price') @@ -2525,7 +2526,8 @@ class _LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], + self.evaluate(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc._numeric_column('price') diff --git a/tensorflow/python/feature_column/feature_column_v2_test.py b/tensorflow/python/feature_column/feature_column_v2_test.py index 115763f656..23131e22ed 100644 --- a/tensorflow/python/feature_column/feature_column_v2_test.py +++ b/tensorflow/python/feature_column/feature_column_v2_test.py @@ -1188,7 +1188,7 @@ class CrossedColumnTest(test.TestCase): outputs = fc._transform_features_v2(features, [price_cross_wire], None) output = outputs[price_cross_wire] with self.cached_session() as sess: - output_val = sess.run(output) + output_val = self.evaluate(output) self.assertAllEqual( [[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [1, 3]], output_val.indices) for val in output_val.values: @@ -2088,7 +2088,8 @@ class LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [100 - 10 + 5.]], sess.run(net)) + self.assertAllClose([[10 - 1000 + 5.], [100 - 10 + 5.]], + self.evaluate(net)) coord.request_stop() coord.join(threads) @@ -2124,7 +2125,8 @@ class LinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], + self.evaluate(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc.numeric_column('price') @@ -2843,7 +2845,8 @@ class OldLinearModelTest(test.TestCase): sess.run(body_style_var.assign([[-10.], [-100.], [-1000.]])) sess.run(bias.assign([5.])) - self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], sess.run(net)) + self.assertAllClose([[10 - 1000 + 5.], [1000 - 10 + 5.]], + self.evaluate(net)) def test_with_1d_unknown_shape_sparse_tensor(self): price = fc.numeric_column('price') diff --git a/tensorflow/python/framework/file_system_test.py b/tensorflow/python/framework/file_system_test.py index 6901715e5d..066d34e781 100644 --- a/tensorflow/python/framework/file_system_test.py +++ b/tensorflow/python/framework/file_system_test.py @@ -42,7 +42,7 @@ class FileSystemTest(test.TestCase): queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) queue.enqueue_many([["test://foo"]]).run() queue.close().run() - key, value = sess.run(reader.read(queue)) + key, value = self.evaluate(reader.read(queue)) self.assertEqual(key, compat.as_bytes("test://foo")) self.assertEqual(value, compat.as_bytes("AAAAAAAAAA")) diff --git a/tensorflow/python/framework/function_test.py b/tensorflow/python/framework/function_test.py index 971219d5b0..1a17a48050 100644 --- a/tensorflow/python/framework/function_test.py +++ b/tensorflow/python/framework/function_test.py @@ -102,7 +102,7 @@ class FunctionTest(test.TestCase): call = MyIdentityFunc([18.0]) self.assertEqual("MyIdentity", call.op.name) with session.Session() as sess: - self.assertAllEqual([18.0], sess.run(call)) + self.assertAllEqual([18.0], self.evaluate(call)) def testIdentityImplicitDeref(self): @@ -116,8 +116,8 @@ class FunctionTest(test.TestCase): self.assertEqual("MyIdentity", call.op.name) for cfg in _OptimizerOptions(): with session.Session(config=cfg) as sess: - sess.run(var.initializer) - self.assertAllEqual([18.0], sess.run(call)) + self.evaluate(var.initializer) + self.assertAllEqual([18.0], self.evaluate(call)) def testIdentityOutputName(self): @@ -130,7 +130,7 @@ class FunctionTest(test.TestCase): call = MyIdentityFunc([18.0]) self.assertEqual("MyIdentity", call.op.name) with session.Session() as sess: - self.assertAllEqual([18.0], sess.run(call)) + self.assertAllEqual([18.0], self.evaluate(call)) def testTooManyOutputNames(self): @@ -158,7 +158,7 @@ class FunctionTest(test.TestCase): call = APlus2B([1.0], [2.0]) self.assertEqual("APlus2B", call.op.name) with session.Session() as sess: - self.assertAllEqual([5.0], sess.run(call)) + self.assertAllEqual([5.0], self.evaluate(call)) def testFunctionWithNoOutput(self): @@ -187,7 +187,7 @@ class FunctionTest(test.TestCase): call = APlus2B([1.0], [2.0]) self.assertEqual("APlus2B", call.op.name) with session.Session() as sess: - self.assertAllEqual([5.0], sess.run(call)) + self.assertAllEqual([5.0], self.evaluate(call)) def testDefineFunctionDuplicateOutputs(self): @@ -224,8 +224,8 @@ class FunctionTest(test.TestCase): call_g = XSquarePlusOneGrad([2.0], [0.1]) with session.Session() as sess: - self.assertAllClose([5.0], sess.run(call_f)) - self.assertAllClose([0.4], sess.run(call_g)) + self.assertAllClose([5.0], self.evaluate(call_f)) + self.assertAllClose([0.4], self.evaluate(call_g)) def testTanhSymGrad(self): @@ -365,7 +365,7 @@ class FunctionTest(test.TestCase): else: dx, dy = gradients_impl.gradients([z], [x, y]) with session.Session() as sess: - dx_val, dy_val = sess.run([dx, dy]) + dx_val, dy_val = self.evaluate([dx, dy]) self.assertEqual([2.0], dx_val) self.assertEqual([0.0], dy_val) @@ -387,7 +387,7 @@ class FunctionTest(test.TestCase): call = AConstant() self.assertEqual("AConstant", call.op.name) with session.Session() as sess: - self.assertAllEqual([42], sess.run(call)) + self.assertAllEqual([42], self.evaluate(call)) def testDefineFunctionNames(self): @@ -468,7 +468,7 @@ class FunctionTest(test.TestCase): loop = control_flow_ops.while_loop(lambda x: x < 1e5, Body, [1.0]) - ans = sess.run(loop) + ans = self.evaluate(loop) self.assertAllClose(ans, 131072.) def testControlFlowStrictness(self): @@ -650,8 +650,8 @@ class FunctionTest(test.TestCase): # pylint: enable=unexpected-keyword-arg self.assertEqual("next", call2.op.name) with session.Session() as sess: - self.assertAllEqual([1], sess.run(call1)) - self.assertAllEqual([0], sess.run(call2)) + self.assertAllEqual([1], self.evaluate(call1)) + self.assertAllEqual([0], self.evaluate(call2)) def testNestedFunction(self): @@ -794,7 +794,7 @@ class FunctionTest(test.TestCase): y = Foo() with self.session(graph=g) as sess: - self.assertEqual(sess.run(y), 10) + self.assertEqual(self.evaluate(y), 10) def testCaptureInCond(self): g = ops.Graph() @@ -809,8 +809,8 @@ class FunctionTest(test.TestCase): z = Foo(False) with self.session(graph=g) as sess: - self.assertEqual(sess.run(y), 1) - self.assertEqual(sess.run(z), 2) + self.assertEqual(self.evaluate(y), 1) + self.assertEqual(self.evaluate(z), 2) def testStableName(self): @@ -854,7 +854,7 @@ class FunctionTest(test.TestCase): z = Bar(x) with self.session(graph=g) as sess: - v0, v1 = sess.run([y, z]) + v0, v1 = self.evaluate([y, z]) self.assertAllEqual(v0, 20.) self.assertAllEqual(v1, 20.) @@ -900,7 +900,7 @@ class FunctionTest(test.TestCase): self.assertEqual(global_vars[0].name, "linear/w:0") with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) output_val = sess.run( output_op, feed_dict={input_op: np.random.rand(32, 100)}) self.assertEqual(output_val.shape, (32, 100)) @@ -928,7 +928,7 @@ class FunctionTest(test.TestCase): self.assertEqual(global_vars[0].name, "vs1/var:0") with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) out1, out2 = sess.run( [out1_op, out2_op], feed_dict={input_op: np.linspace(1, 10, 10)}) self.assertAllEqual(out1, np.linspace(2, 11, 10)) @@ -991,8 +991,8 @@ class FunctionTest(test.TestCase): result_2 = Bar(constant_op.constant(100, dtype=dtypes.int64)) with session.Session() as sess: - self.assertEqual(4.0, sess.run(result_1)) - self.assertEqual(100, sess.run(result_2)) + self.assertEqual(4.0, self.evaluate(result_1)) + self.assertEqual(100, self.evaluate(result_2)) self.assertEqual((4.0, 100), sess.run((result_1, result_2))) def testStatefulFunction(self): @@ -1052,8 +1052,8 @@ class FunctionTest(test.TestCase): for config in _OptimizerOptions(): config.device_count["CPU"] = 2 with session.Session(config=config) as sess: - self.assertEqual(42.0, sess.run(f_0)) - self.assertEqual(44.0, sess.run(f_1)) + self.assertEqual(42.0, self.evaluate(f_0)) + self.assertEqual(44.0, self.evaluate(f_1)) self.assertEqual((42.0, 44.0), sess.run((f_0, f_1))) def testGuaranteedConstsAreCaptured(self): @@ -1076,7 +1076,7 @@ class FunctionTest(test.TestCase): return output with self.session(use_gpu=False) as sess: - sess.run(var.initializer) + self.evaluate(var.initializer) _ = sess.run(CapturesGuaranteedConst(), {also_not_const: 1.0}) def testSameFunctionDifferentGrads(self): @@ -1127,7 +1127,7 @@ class FunctionTest(test.TestCase): dx2, = gradients_impl.gradients(ys=[y2], xs=[x2]) with self.session(graph=g) as sess: - v0, v1, v2 = sess.run([dx0, dx1, dx2]) + v0, v1, v2 = self.evaluate([dx0, dx1, dx2]) self.assertAllEqual(v0, 2.) self.assertAllEqual(v1, 101.) @@ -1532,7 +1532,7 @@ class UnrollLSTMTest(test.TestCase): tf_logging.info("time: %f txt size: %d gdef bin size: %d", finish - start, len(str(gdef)), len(gdef.SerializeToString())) with g.as_default(), session.Session(config=cfg) as sess: - return sess.run(m) + return self.evaluate(m) mv0 = RunForward("complete") for cfg in _OptimizerOptions(): @@ -1561,7 +1561,7 @@ class UnrollLSTMTest(test.TestCase): tf_logging.info("time: %f txt size: %d gdef bin size: %d", finish - start, len(str(gdef)), len(gdef.SerializeToString())) with g.as_default(), session.Session(config=cfg) as sess: - return sess.run(dw) + return self.evaluate(dw) d0 = RunForwardBackward("complete") for cfg in _OptimizerOptions(): @@ -1651,8 +1651,8 @@ class ModuleFunctionTest(test.TestCase): y = LinearWithCApi(a, b, c) z = Linear2WithCApi(a, b, c, d, e) with session.Session() as sess: - self.assertAllEqual([[1]], sess.run(y)) - self.assertAllEqual([[5]], sess.run(z)) + self.assertAllEqual([[1]], self.evaluate(y)) + self.assertAllEqual([[5]], self.evaluate(z)) class VariableHoistingTest(test.TestCase): @@ -1704,8 +1704,8 @@ class VariableHoistingTest(test.TestCase): self.assertEqual("Foo/b", b.op.name) with self.session(graph=g) as sess: - sess.run(variables.global_variables_initializer()) - w, b, x, y0, loss, dw, db = sess.run([w, b, x, y0, loss, dw, db]) + self.evaluate(variables.global_variables_initializer()) + w, b, x, y0, loss, dw, db = self.evaluate([w, b, x, y0, loss, dw, db]) self.assertAllEqual(w.shape, (64, 64)) self.assertAllClose(np.sum(w), 2050.44) diff --git a/tensorflow/python/framework/graph_util_test.py b/tensorflow/python/framework/graph_util_test.py index 563a177dd0..10a01c71f2 100644 --- a/tensorflow/python/framework/graph_util_test.py +++ b/tensorflow/python/framework/graph_util_test.py @@ -210,8 +210,8 @@ class DeviceFunctionsTest(test.TestCase): with session.Session() as sess: init = variables.variables_initializer([variable_node]) - sess.run(init) - output = sess.run(output_node) + self.evaluate(init) + output = self.evaluate(output_node) self.assertNear(4.0, output, 0.00001) variable_graph_def = sess.graph.as_graph_def() @@ -242,8 +242,8 @@ class DeviceFunctionsTest(test.TestCase): output_node = math_ops_lib.multiply( variable_node, 2.0, name="output_node") with session.Session() as sess: - sess.run(variable_node.initializer) - output = sess.run(output_node) + self.evaluate(variable_node.initializer) + output = self.evaluate(output_node) self.assertNear(2.0, output, 0.00001) variable_graph_def = sess.graph.as_graph_def() # First get the constant_graph_def when variable_names_whitelist is @@ -256,7 +256,7 @@ class DeviceFunctionsTest(test.TestCase): # Then initialize the unused variable, and get another # constant_graph_def when variable_names_whitelist is not set. - sess.run(another_variable.initializer) + self.evaluate(another_variable.initializer) constant_graph_def_without_variable_whitelist = ( graph_util.convert_variables_to_constants( sess, variable_graph_def, ["output_node"])) @@ -295,7 +295,7 @@ class DeviceFunctionsTest(test.TestCase): ["Variable", "VariableV2", "VarHandleOp", "ReadVariableOp"]) with session.Session() as sess: output_node = sess.graph.get_tensor_by_name("output_node:0") - output = sess.run(output_node) + output = self.evaluate(output_node) self.assertNear(2.0, output, 0.00001) def create_node_def(self, op, name, inputs): diff --git a/tensorflow/python/framework/importer_test.py b/tensorflow/python/framework/importer_test.py index fc7367649e..66e80b5585 100644 --- a/tensorflow/python/framework/importer_test.py +++ b/tensorflow/python/framework/importer_test.py @@ -397,11 +397,11 @@ class ImportGraphDefTest(test.TestCase): # Run the imported graph. # TODO(b/76173421): make this work (currently DCHECKS) # with self.cached_session() as sess: - # sess.run(imported_init) - # self.assertEqual(sess.run(imported_var), 1.0) - # self.assertEqual(sess.run(imported_assign), 2.0) - # self.assertEqual(list(sess.run(imported_shape)), []) - # self.assertEqual(list(sess.run(new_var_shape)), []) + # self.evaluate(imported_init) + # self.assertEqual(self.evaluate(imported_var), 1.0) + # self.assertEqual(self.evaluate(imported_assign), 2.0) + # self.assertEqual(list(self.evaluate(imported_shape)), []) + # self.assertEqual(list(self.evaluate(new_var_shape)), []) def testWhileLoop(self): # Produce GraphDef containing while loop. @@ -418,7 +418,7 @@ class ImportGraphDefTest(test.TestCase): return_elements=[r.name]) self.assertEqual(imported_r.name, "import/" + r.name) with self.cached_session() as sess: - self.assertEqual(sess.run(imported_r), 10) + self.assertEqual(self.evaluate(imported_r), 10) def testImportWhileLoopInCond(self): # Produce GraphDef containing while loop. @@ -458,7 +458,7 @@ class ImportGraphDefTest(test.TestCase): lambda i: i < 2, ImportFn, [0], shape_invariants=[tensor_shape.TensorShape(None)]) with self.cached_session() as sess: - self.assertEqual(sess.run(out), 10) + self.assertEqual(self.evaluate(out), 10) def testTypeMismatchInGraphDef(self): # TODO(skyewm): improve error message diff --git a/tensorflow/python/framework/meta_graph_test.py b/tensorflow/python/framework/meta_graph_test.py index 84e7f361bb..cc93f8b1b8 100644 --- a/tensorflow/python/framework/meta_graph_test.py +++ b/tensorflow/python/framework/meta_graph_test.py @@ -492,8 +492,8 @@ class ScopedMetaGraphTest(test.TestCase): init_op = variables.global_variables_initializer() grad = gradients_impl.gradients([output], [var]) with session.Session() as sess: - sess.run(init_op) - expected_grad_value = sess.run(grad) + self.evaluate(init_op) + expected_grad_value = self.evaluate(grad) # Restore the MetaGraphDef into a new Graph with an import scope. with ops.Graph().as_default(): @@ -518,8 +518,8 @@ class ScopedMetaGraphTest(test.TestCase): init_op = variables.global_variables_initializer() with session.Session() as sess: - sess.run(init_op) - actual_grad_value = sess.run(grad) + self.evaluate(init_op) + actual_grad_value = self.evaluate(grad) self.assertEqual(expected_grad_value, actual_grad_value) def testImportWhileLoopInWhileLoop(self): @@ -544,8 +544,8 @@ class ScopedMetaGraphTest(test.TestCase): _, x = control_flow_ops.while_loop(lambda i, x: i < 2, body, [0, 0.0], name="") with session.Session() as sess: - sess.run(variables.global_variables_initializer()) - sess.run(x) + self.evaluate(variables.global_variables_initializer()) + self.evaluate(x) def testScopedImportUnderNameScope(self): graph = ops.Graph() @@ -868,8 +868,8 @@ class MetaGraphWithVariableScopeTest(test.TestCase): _, update_op = metrics.mean(values) initializer = variables.local_variables_initializer() - sess.run(initializer) - sess.run(update_op) + self.evaluate(initializer) + self.evaluate(update_op) meta_graph.export_scoped_meta_graph( filename=meta_graph_filename, graph=graph) @@ -880,7 +880,7 @@ class MetaGraphWithVariableScopeTest(test.TestCase): with self.session(graph=graph) as sess: meta_graph.import_scoped_meta_graph(meta_graph_filename) initializer = variables.local_variables_initializer() - sess.run(initializer) + self.evaluate(initializer) # Verifies that importing an old meta_graph where "local_variables" # collection is of node_list type works, but cannot build initializer diff --git a/tensorflow/python/framework/ops_test.py b/tensorflow/python/framework/ops_test.py index 3957d1de53..32a24521ad 100644 --- a/tensorflow/python/framework/ops_test.py +++ b/tensorflow/python/framework/ops_test.py @@ -503,7 +503,7 @@ class OperationTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp( errors.InvalidArgumentError, "Graph is invalid, contains a cycle with 2 nodes"): - sess.run(x) + self.evaluate(x) def testUpdateInput(self): g = ops.Graph() @@ -517,21 +517,21 @@ class OperationTest(test_util.TensorFlowTestCase): self.assertEquals(x.consumers(), []) self.assertEquals(y.consumers(), [z.op, z.op]) with session.Session(graph=g) as sess: - self.assertEquals(sess.run(z), 4) + self.assertEquals(self.evaluate(z), 4) z.op._update_input(0, x) # pylint: disable=protected-access self.assertEquals(list(z.op.inputs), [x, y]) self.assertEquals(x.consumers(), [z.op]) self.assertEquals(y.consumers(), [z.op]) with session.Session(graph=g) as sess: - self.assertEquals(sess.run(z), 3) + self.assertEquals(self.evaluate(z), 3) z.op._update_input(1, y) # pylint: disable=protected-access self.assertEquals(list(z.op.inputs), [x, y]) self.assertEquals(x.consumers(), [z.op]) self.assertEquals(y.consumers(), [z.op]) with session.Session(graph=g) as sess: - self.assertEquals(sess.run(z), 3) + self.assertEquals(self.evaluate(z), 3) def testUpdateInputGraphError(self): g_0 = ops.Graph() @@ -557,7 +557,7 @@ class OperationTest(test_util.TensorFlowTestCase): errors.InvalidArgumentError, "Input 0 of node add was passed string from Const_1:0 incompatible " "with expected int32"): - sess.run(z) + self.evaluate(z) def testUpdateInputShapeError(self): g = ops.Graph() @@ -2390,7 +2390,7 @@ class GraphTest(test_util.TensorFlowTestCase): c = math_ops.add(a, b) # Create a session we can delete with session.Session(graph=g) as sess: - sess.run(c) + self.evaluate(c) # Delete all references and trigger gc del g del a @@ -2406,7 +2406,7 @@ class GraphTest(test_util.TensorFlowTestCase): math_ops.add([1, 2], [1, 2, 3]) a = constant_op.constant(1) with session.Session() as sess: - sess.run(a) + self.evaluate(a) def testRunnableAfterInvalidShapeWithKernelLabelMap(self): g = ops.Graph() @@ -2416,7 +2416,7 @@ class GraphTest(test_util.TensorFlowTestCase): test_ops.kernel_label_required(1) a = constant_op.constant(1) with session.Session() as sess: - sess.run(a) + self.evaluate(a) class AttrScopeTest(test_util.TensorFlowTestCase): diff --git a/tensorflow/python/framework/smart_cond_test.py b/tensorflow/python/framework/smart_cond_test.py index b8a9672b06..174ada9fe1 100644 --- a/tensorflow/python/framework/smart_cond_test.py +++ b/tensorflow/python/framework/smart_cond_test.py @@ -109,8 +109,8 @@ class SmartCaseTest(test_util.TensorFlowTestCase): exclusive=True) with session.Session() as sess: # No feed_dict necessary - self.assertEqual(sess.run(y), 1) - self.assertEqual(sess.run(z), 1) + self.assertEqual(self.evaluate(y), 1) + self.assertEqual(self.evaluate(z), 1) def testFalse(self): conditions = [(False, raise_exception)] @@ -121,8 +121,8 @@ class SmartCaseTest(test_util.TensorFlowTestCase): default=lambda: constant_op.constant(1), exclusive=True) with session.Session() as sess: - self.assertEqual(sess.run(y), 1) - self.assertEqual(sess.run(z), 1) + self.assertEqual(self.evaluate(y), 1) + self.assertEqual(self.evaluate(z), 1) def testMix(self): x = array_ops.placeholder(dtype=dtypes.int32, shape=[]) diff --git a/tensorflow/python/framework/sparse_tensor_test.py b/tensorflow/python/framework/sparse_tensor_test.py index 2f7591abbd..9ee1bd75a5 100644 --- a/tensorflow/python/framework/sparse_tensor_test.py +++ b/tensorflow/python/framework/sparse_tensor_test.py @@ -50,7 +50,7 @@ class SparseTensorTest(test_util.TensorFlowTestCase): self.assertAllEqual(indices, value.indices) self.assertAllEqual(values, value.values) self.assertAllEqual(shape, value.dense_shape) - sess_run_value = sess.run(sp) + sess_run_value = self.evaluate(sp) self.assertAllEqual(sess_run_value.indices, value.indices) self.assertAllEqual(sess_run_value.values, value.values) self.assertAllEqual(sess_run_value.dense_shape, value.dense_shape) diff --git a/tensorflow/python/framework/subscribe_test.py b/tensorflow/python/framework/subscribe_test.py index cab426844d..5322204ce6 100644 --- a/tensorflow/python/framework/subscribe_test.py +++ b/tensorflow/python/framework/subscribe_test.py @@ -66,9 +66,9 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertTrue(c.op in d.op.control_inputs) with self.cached_session() as sess: - c_out = sess.run([c]) - n_out = sess.run([n]) - d_out = sess.run([d]) + c_out = self.evaluate([c]) + n_out = self.evaluate([n]) + d_out = self.evaluate([d]) self.assertEqual(n_out, [-2]) self.assertEqual(c_out, [2]) @@ -145,8 +145,8 @@ class SubscribeTest(test_util.TensorFlowTestCase): lambda t: script_ops.py_func(sub, [t], [t.dtype])) with self.cached_session() as sess: - c_out = sess.run([c]) - d_out = sess.run([d]) + c_out = self.evaluate([c]) + d_out = self.evaluate([d]) self.assertEqual(c_out, [42]) self.assertEqual(d_out, [11]) @@ -205,7 +205,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): # Expect the three side effect graphs to have been evaluated. with self.cached_session() as sess: - sess.run([c_sub]) + self.evaluate([c_sub]) self.assertIn('graph1', shared) self.assertIn('graph2', shared) self.assertIn('graph3', shared) @@ -229,20 +229,20 @@ class SubscribeTest(test_util.TensorFlowTestCase): with self.cached_session() as sess: # Initialize the variables first. - sess.run([v1.initializer]) - sess.run([v2.initializer]) + self.evaluate([v1.initializer]) + self.evaluate([v2.initializer]) # Expect the side effects to be triggered when evaluating the add op as # it will read the value of the variable. - sess.run([add]) + self.evaluate([add]) self.assertEqual(1, len(shared)) # Expect the side effect not to be triggered when evaluating the assign # op as it will not access the 'read' output of the variable. - sess.run([assign_v1]) + self.evaluate([assign_v1]) self.assertEqual(1, len(shared)) - sess.run([add]) + self.evaluate([add]) self.assertEqual(2, len(shared)) # Make sure the values read from the variable match the expected ones. @@ -273,7 +273,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertFalse(subscribe._is_subscribed_identity(tensor_array.handle)) with self.cached_session() as sess: - sess.run([reader]) + self.evaluate([reader]) self.assertEqual(0, len(shared)) def testMultipleOutputs(self): @@ -304,7 +304,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): lambda t: script_ops.py_func(sub, [t], [t.dtype])) with self.cached_session() as sess: - sess.run([neg]) + self.evaluate([neg]) # All three ops have been processed. self.assertEqual(3, len(shared)) @@ -375,7 +375,7 @@ class SubscribeTest(test_util.TensorFlowTestCase): self.assertIsNot(context(subscriptions[0]), context(subscriptions[1])) with self.cached_session() as sess: - sess.run(cond) + self.evaluate(cond) self.assertEqual(3, len(results)) diff --git a/tensorflow/python/framework/tensor_util_test.py b/tensorflow/python/framework/tensor_util_test.py index bdf759f220..87d65c8c46 100644 --- a/tensorflow/python/framework/tensor_util_test.py +++ b/tensorflow/python/framework/tensor_util_test.py @@ -771,7 +771,7 @@ class TensorUtilTest(test.TestCase): with self.cached_session() as sess: ma = MockArray(np.array([10, 20, 30])) t = ops.convert_to_tensor(ma) - a = sess.run(t) + a = self.evaluate(t) self.assertEquals(np.int64, a.dtype) self.assertAllClose(np.array([10, 20, 30], dtype=np.int64), a) diff --git a/tensorflow/python/grappler/constant_folding_test.py b/tensorflow/python/grappler/constant_folding_test.py index ab1d0ed25b..30c1e14681 100644 --- a/tensorflow/python/grappler/constant_folding_test.py +++ b/tensorflow/python/grappler/constant_folding_test.py @@ -61,7 +61,7 @@ class ConstantFoldingTest(test.TestCase): back_prop=False, parallel_iterations=1) with session.Session() as sess: - y_v = sess.run(y) + y_v = self.evaluate(y) self.assertAllEqual(np.zeros([10, 20, 30]), y_v) diff --git a/tensorflow/python/grappler/layout_optimizer_test.py b/tensorflow/python/grappler/layout_optimizer_test.py index 7b68d5e80d..55ccfbb93c 100644 --- a/tensorflow/python/grappler/layout_optimizer_test.py +++ b/tensorflow/python/grappler/layout_optimizer_test.py @@ -241,7 +241,7 @@ class LayoutOptimizerTest(test.TestCase): if restore: saver.restore(sess, checkpoint_path) else: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) np.random.seed(0) for _ in range(2): @@ -262,7 +262,7 @@ class LayoutOptimizerTest(test.TestCase): output = _two_layer_model(x) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -365,7 +365,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(pad) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -396,7 +396,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -425,7 +425,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(cast) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -456,7 +456,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(squeeze) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -486,7 +486,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(squeeze) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -516,7 +516,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(squeeze) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -545,7 +545,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -574,7 +574,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -603,7 +603,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -632,7 +632,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -662,7 +662,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -691,7 +691,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reduce_sum) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -724,7 +724,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(concat) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -835,7 +835,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(reverse) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -905,7 +905,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(select) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -966,7 +966,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(select) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1179,7 +1179,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(s) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1214,7 +1214,7 @@ class LayoutOptimizerTest(test.TestCase): output = array_ops.identity(s) with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1347,7 +1347,7 @@ class LayoutOptimizerTest(test.TestCase): output = _loop() with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1374,7 +1374,7 @@ class LayoutOptimizerTest(test.TestCase): output = _loop_with_branch() with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1398,7 +1398,7 @@ class LayoutOptimizerTest(test.TestCase): output = _loop_with_vec_and_4d() with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() @@ -1422,7 +1422,7 @@ class LayoutOptimizerTest(test.TestCase): output = _model_with_second_port() with session.Session(config=_get_config(False)) as sess: - output_val_ref = sess.run(output) + output_val_ref = self.evaluate(output) with session.Session(config=_get_config()) as sess: metadata = config_pb2.RunMetadata() diff --git a/tensorflow/python/grappler/memory_optimizer_test.py b/tensorflow/python/grappler/memory_optimizer_test.py index 98cbb1a4b6..d233629cbb 100644 --- a/tensorflow/python/grappler/memory_optimizer_test.py +++ b/tensorflow/python/grappler/memory_optimizer_test.py @@ -231,10 +231,10 @@ class MemoryOptimizerRecomputeTest(test.TestCase): train_op = graph.get_operation_by_name(train_op_name) loss_op = graph.get_tensor_by_name(loss_op_name) with session.Session(config=config, graph=graph) as sess: - sess.run(init_op) - sess.run(train_op) - sess.run(train_op) - return sess.run(loss_op) + self.evaluate(init_op) + self.evaluate(train_op) + self.evaluate(train_op) + return self.evaluate(loss_op) def testRecomputationRewritingNoErrors(self): """Tests that graph output is not significantly different with rewriting.""" @@ -295,8 +295,8 @@ class MemoryOptimizerRecomputeTest(test.TestCase): rewrite_options=manual_memory_config) session_config = config_pb2.ConfigProto(graph_options=graph_options) with session.Session(config=session_config) as sess: - sess.run(init_op) - sess.run(train_op) + self.evaluate(init_op) + self.evaluate(train_op) def testHintDoesRewrite(self): graph = self._annotated_graph()[0] diff --git a/tensorflow/python/keras/backend_test.py b/tensorflow/python/keras/backend_test.py index a727e99f66..48fdd56e9f 100644 --- a/tensorflow/python/keras/backend_test.py +++ b/tensorflow/python/keras/backend_test.py @@ -136,7 +136,7 @@ class BackendUtilsTest(test.TestCase): x = keras.Input((3,)) y = keras.layers.BatchNormalization()(x) if not context.executing_eagerly(): - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) sess.run(y, feed_dict={x: np.random.random((2, 3))}) def test_learning_phase_scope(self): diff --git a/tensorflow/python/keras/layers/recurrent_test.py b/tensorflow/python/keras/layers/recurrent_test.py index 7172571f7c..b1449069e3 100644 --- a/tensorflow/python/keras/layers/recurrent_test.py +++ b/tensorflow/python/keras/layers/recurrent_test.py @@ -1013,8 +1013,8 @@ class RNNTest(test.TestCase): inputs, _ = cell(inputs, initial_state) output = inputs if not context.executing_eagerly(): - sess.run(variables_lib.global_variables_initializer()) - output = sess.run(output) + self.evaluate(variables_lib.global_variables_initializer()) + output = self.evaluate(output) return output random_seed.set_random_seed(12345) diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index 74e5d4d4ce..f049b10721 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -322,19 +322,19 @@ class KerasMetricsTest(test.TestCase): m = metrics.Mean() v = array_ops.placeholder(dtypes.float32) w = array_ops.placeholder(dtypes.float32) - sess.run(variables.variables_initializer(m.variables)) + self.evaluate(variables.variables_initializer(m.variables)) # check __call__() result_t = m(v, sample_weight=w) result = sess.run(result_t, feed_dict=({v: 100, w: 0.5})) - self.assertEqual(sess.run(m.total), 50) - self.assertEqual(sess.run(m.count), 0.5) + self.assertEqual(self.evaluate(m.total), 50) + self.assertEqual(self.evaluate(m.count), 0.5) self.assertEqual(result, 50 / 0.5) # check update_state() and result() result = sess.run(result_t, feed_dict=({v: [1, 5], w: [1, 0.2]})) - self.assertAlmostEqual(sess.run(m.total), 52, 2) # 50 + 1 + 5 * 0.2 - self.assertAlmostEqual(sess.run(m.count), 1.7, 2) # 0.5 + 1.2 + self.assertAlmostEqual(self.evaluate(m.total), 52, 2) # 50 + 1 + 5 * 0.2 + self.assertAlmostEqual(self.evaluate(m.count), 1.7, 2) # 0.5 + 1.2 self.assertAlmostEqual(result, 52 / 1.7, 2) @test_util.run_in_graph_and_eager_modes diff --git a/tensorflow/python/keras/optimizer_v2/ftrl_test.py b/tensorflow/python/keras/optimizer_v2/ftrl_test.py index c14cf75c26..ca8c33dfa6 100644 --- a/tensorflow/python/keras/optimizer_v2/ftrl_test.py +++ b/tensorflow/python/keras/optimizer_v2/ftrl_test.py @@ -54,7 +54,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([0.0, 0.0], v0_val) self.assertAllClose([0.0, 0.0], v1_val) @@ -62,7 +62,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-2.60260963, -4.29698515]), v0_val) self.assertAllCloseAccordingToType( @@ -90,14 +90,14 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run 3 steps FTRL for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-2.55607247, -3.98729396]), v0_val) self.assertAllCloseAccordingToType( @@ -137,14 +137,14 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run 10 steps FTRL for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-7.66718769, -10.91273689]), v0_val) self.assertAllCloseAccordingToType( @@ -166,7 +166,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) @@ -174,7 +174,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.24059935, -0.46829352]), v0_val) self.assertAllCloseAccordingToType( @@ -203,7 +203,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) @@ -211,7 +211,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.22578995, -0.44345796]), v0_val) self.assertAllCloseAccordingToType( @@ -239,7 +239,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([[1.0], [2.0]], v0_val) self.assertAllCloseAccordingToType([[4.0], [3.0]], v1_val) @@ -247,7 +247,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([[-0.22578995], [2.]], v0_val) self.assertAllCloseAccordingToType([[4.], [-0.13229476]], v1_val) @@ -275,7 +275,7 @@ class FtrlOptimizerTest(test.TestCase): update1 = opt1.apply_gradients([(grads1, var1)]) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([1.0, 2.0], v1_val) @@ -284,7 +284,7 @@ class FtrlOptimizerTest(test.TestCase): update0.run() update1.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) # var0 is experiencing L2 shrinkage so it should be smaller than var1 # in magnitude. self.assertTrue((v0_val**2 < v1_val**2).all()) @@ -313,7 +313,7 @@ class FtrlOptimizerTest(test.TestCase): variables.global_variables_initializer().run() sess = ops.get_default_session() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) if is_sparse: self.assertAllCloseAccordingToType([[0.0], [0.0]], v0_val) self.assertAllCloseAccordingToType([[0.0], [0.0]], v1_val) @@ -325,7 +325,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(steps): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) return v0_val, v1_val # When variables are initialized with Zero, FTRL-Proximal has two properties: diff --git a/tensorflow/python/kernel_tests/accumulate_n_test.py b/tensorflow/python/kernel_tests/accumulate_n_test.py index ae24cf8f14..c7f11f854d 100644 --- a/tensorflow/python/kernel_tests/accumulate_n_test.py +++ b/tensorflow/python/kernel_tests/accumulate_n_test.py @@ -65,7 +65,7 @@ class AccumulateNV2Test(test_util.TensorFlowTestCase): for _ in range(0, num_inputs) ] accum_n = math_ops.accumulate_n(input_vars) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) accum_n_grad = gradients.gradients(accum_n, input_vars) self.assertAllEqual( np.repeat(1.0, num_inputs), # d/dx (x + y + ...) = 1 diff --git a/tensorflow/python/kernel_tests/aggregate_ops_test.py b/tensorflow/python/kernel_tests/aggregate_ops_test.py index 0f15319cb5..874d616658 100644 --- a/tensorflow/python/kernel_tests/aggregate_ops_test.py +++ b/tensorflow/python/kernel_tests/aggregate_ops_test.py @@ -61,7 +61,7 @@ class AddNTest(test.TestCase): for dtype in self._supported_types(): for count in range(1, self._MAX_N + 1): data = [self._buildData((2, 2), dtype) for _ in range(count)] - actual = sess.run(math_ops.add_n(data)) + actual = self.evaluate(math_ops.add_n(data)) expected = np.sum(np.vstack( [np.expand_dims(d, 0) for d in data]), axis=0) tol = 5e-3 if dtype == dtypes.float16 else 5e-7 diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py index d345138ec7..afc158f697 100644 --- a/tensorflow/python/kernel_tests/array_ops_test.py +++ b/tensorflow/python/kernel_tests/array_ops_test.py @@ -833,7 +833,7 @@ class StridedSliceGradTest(test_util.TensorFlowTestCase): index = constant_op.constant(1, dtype=dtypes.int64) b = 2. * a[index] grad, = gradients_impl.gradients(b, a) - self.assertAllEqual(sess.run(grad), [0., 2., 0.]) + self.assertAllEqual(self.evaluate(grad), [0., 2., 0.]) class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): @@ -846,7 +846,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32), shape=(4, 1, 1))) varshape = variables.Variable([6, 4, 4], dtype=dtypes.int32) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) begin = constant_op.constant([0, 0, 0]) end = constant_op.constant([4, 1, 1]) strides = constant_op.constant([1, 1, 1]) @@ -859,7 +859,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32), shape=(4, 1, 1)) original_shape = constant_op.constant([6, 4, 4], dtype=dtypes.int64) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) begin = constant_op.constant([0, 0, 0], dtype=dtypes.int64) end = constant_op.constant([4, 1, 1], dtype=dtypes.int64) strides = constant_op.constant([1, 1, 1], dtype=dtypes.int64) @@ -873,7 +873,7 @@ class StridedSliceGradTypeTest(test_util.TensorFlowTestCase): math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32), shape=(4, 1, 1)) original_shape = constant_op.constant([6, 4, 4], dtype=dtypes.int64) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) begin = constant_op.constant([0, 0, 0], dtype=dtypes.int32) end = constant_op.constant([4, 1, 1], dtype=dtypes.int64) strides = constant_op.constant([1, 1, 1], dtype=dtypes.int64) @@ -1042,7 +1042,7 @@ class SliceAssignTest(test_util.TensorFlowTestCase): too_large_val = constant_op.constant([3, 4], dtype=dtypes.int64) v = resource_variable_ops.ResourceVariable(init_val) with self.cached_session() as sess: - sess.run(v.initializer) + self.evaluate(v.initializer) with self.assertRaises(ValueError): sess.run(v[:].assign(too_large_val)) with self.assertRaises(ValueError): @@ -1269,7 +1269,7 @@ class GuaranteeConstOpTest(test_util.TensorFlowTestCase): initializer=init_ops.constant_initializer(10.0), use_resource=use_resource) guarantee_a = array_ops.guarantee_const(a) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(10.0, guarantee_a.eval()) def testResourceRejection(self): @@ -1279,7 +1279,7 @@ class GuaranteeConstOpTest(test_util.TensorFlowTestCase): initializer=init_ops.constant_initializer(10.0), use_resource=True) guarantee_a = array_ops.guarantee_const(a.handle) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) with self.assertRaisesWithPredicateMatch(errors.InvalidArgumentError, "cannot be a resource variable"): guarantee_a.eval() diff --git a/tensorflow/python/kernel_tests/attention_ops_test.py b/tensorflow/python/kernel_tests/attention_ops_test.py index 14db06b783..00dba9996d 100644 --- a/tensorflow/python/kernel_tests/attention_ops_test.py +++ b/tensorflow/python/kernel_tests/attention_ops_test.py @@ -85,7 +85,7 @@ class ExtractGlimpseTest(test.TestCase): # Evaluate the TensorFlow Graph. with self.cached_session() as sess: - value_rows, value_cols = sess.run([glimpse_rows, glimpse_cols]) + value_rows, value_cols = self.evaluate([glimpse_rows, glimpse_cols]) # Check dimensions of returned glimpse. self.assertEqual(value_rows.shape[1], glimpse_sizes[0]) diff --git a/tensorflow/python/kernel_tests/barrier_ops_test.py b/tensorflow/python/kernel_tests/barrier_ops_test.py index 4d36b3a465..495bbe7b34 100644 --- a/tensorflow/python/kernel_tests/barrier_ops_test.py +++ b/tensorflow/python/kernel_tests/barrier_ops_test.py @@ -229,7 +229,7 @@ class BarrierTest(test.TestCase): insert_ops = [b.insert_many(0, [k], [v]) for k, v in zip(keys, values)] take_t = b.take_many(10) - sess.run(insert_ops) + self.evaluate(insert_ops) self.assertEquals(size_t.eval(), [10]) indices_val, keys_val, values_val = sess.run( @@ -491,9 +491,9 @@ class BarrierTest(test.TestCase): b = data_flow_ops.Barrier( (dtypes.float32, dtypes.float32), shapes=((), ()), name="B") take_t = b.take_many(1, allow_small_batch=True) - sess.run(b.close(cancel)) + self.evaluate(b.close(cancel)) with self.assertRaisesOpError("is closed and has insufficient elements"): - sess.run(take_t) + self.evaluate(take_t) def testClosedEmptyBarrierTakeManyAllowSmallBatchRaises(self): self._testClosedEmptyBarrierTakeManyAllowSmallBatchRaises(cancel=False) diff --git a/tensorflow/python/kernel_tests/base64_ops_test.py b/tensorflow/python/kernel_tests/base64_ops_test.py index 1b399942ef..bb903d827f 100644 --- a/tensorflow/python/kernel_tests/base64_ops_test.py +++ b/tensorflow/python/kernel_tests/base64_ops_test.py @@ -93,7 +93,7 @@ class Base64OpsTest(test_util.TensorFlowTestCase): decoded = string_ops.decode_base64(encoded) with self.cached_session() as sess: - encoded_value, decoded_value = sess.run([encoded, decoded]) + encoded_value, decoded_value = self.evaluate([encoded, decoded]) self.assertEqual(encoded_value.shape, msg.shape) self.assertEqual(decoded_value.shape, msg.shape) diff --git a/tensorflow/python/kernel_tests/basic_gpu_test.py b/tensorflow/python/kernel_tests/basic_gpu_test.py index ac5cbc810a..cd33048121 100644 --- a/tensorflow/python/kernel_tests/basic_gpu_test.py +++ b/tensorflow/python/kernel_tests/basic_gpu_test.py @@ -44,13 +44,13 @@ class GPUBinaryOpsTest(test.TestCase): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) - tf_gpu = sess.run(out) + tf_gpu = self.evaluate(out) with self.cached_session(use_gpu=False) as sess: inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) - tf_cpu = sess.run(out) + tf_cpu = self.evaluate(out) self.assertAllClose(tf_cpu, tf_gpu) @@ -96,7 +96,7 @@ class MathBuiltinUnaryTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: inx = ops.convert_to_tensor(x) ofunc = tf_func(inx) - tf_out = sess.run(ofunc) + tf_out = self.evaluate(ofunc) self.assertAllClose(np_out, tf_out) def _inv(self, x): @@ -148,7 +148,7 @@ class MathBuiltinUnaryTest(test.TestCase): iny = ops.convert_to_tensor(y + 0.1) ofunc = inx / iny out_func2 = math_ops.floor(ofunc) - tf_out = sess.run(out_func2) + tf_out = self.evaluate(out_func2) self.assertAllClose(np_out, tf_out) diff --git a/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py index 12afb6a2ad..1a7b1a7e90 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/quantile_ops_test.py @@ -98,8 +98,8 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): quantile_accumulator_handle, num_features=2) quantiles = boosted_trees_ops.boosted_trees_bucketize( [self._feature_0, self._feature_1], buckets) - sess.run(summary_op) - sess.run(flush_op) + self.evaluate(summary_op) + self.evaluate(flush_op) self.assertAllClose(self._feature_0_boundaries, buckets[0].eval()) self.assertAllClose(self._feature_1_boundaries, buckets[1].eval()) @@ -132,8 +132,8 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): quantile_accumulator_handle_1, num_features=1) quantiles = boosted_trees_ops.boosted_trees_bucketize( [self._feature_0, self._feature_1], bucket_0 + bucket_1) - sess.run([summary_op_0, summary_op_1]) - sess.run([flush_op_0, flush_op_1]) + self.evaluate([summary_op_0, summary_op_1]) + self.evaluate([flush_op_0, flush_op_1]) self.assertAllClose(self._feature_0_boundaries, bucket_0[0].eval()) self.assertAllClose(self._feature_1_boundaries, bucket_1[0].eval()) @@ -158,7 +158,7 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): self._example_weights) with ops.control_dependencies([summaries]): flush = accumulator.flush() - sess.run(flush) + self.evaluate(flush) self.assertAllClose(self._feature_0_boundaries, buckets[0].eval()) self.assertAllClose(self._feature_1_boundaries, buckets[1].eval()) save.save(sess, save_path) @@ -185,12 +185,12 @@ class QuantileOpsTest(test_util.TensorFlowTestCase): summaries = accumulator.add_summaries([self._feature_0, self._feature_1], self._example_weights) - sess.run(summaries) + self.evaluate(summaries) buckets = accumulator.get_bucket_boundaries() self.assertAllClose([], buckets[0].eval()) self.assertAllClose([], buckets[1].eval()) save.save(sess, save_path) - sess.run(accumulator.flush()) + self.evaluate(accumulator.flush()) self.assertAllClose(self._feature_0_boundaries, buckets[0].eval()) self.assertAllClose(self._feature_1_boundaries, buckets[1].eval()) diff --git a/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py b/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py index cc3984015d..e1036b0b75 100644 --- a/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py +++ b/tensorflow/python/kernel_tests/boosted_trees/stats_ops_test.py @@ -65,16 +65,16 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) self.assertAllClose([[0.004775, 0.41184], [0.02823, 0.41184]], - sess.run(gains_list)) - self.assertAllEqual([[1, 1], [1, 1]], sess.run(thresholds_list)) + self.evaluate(gains_list)) + self.assertAllEqual([[1, 1], [1, 1]], self.evaluate(thresholds_list)) # The left node contrib will be later added to the previous node value to # make the left node value, and the same for right node contrib. self.assertAllClose([[[-.416667], [.568966]], [[-.6], [-.75]]], - sess.run(left_node_contribs_list)) + self.evaluate(left_node_contribs_list)) self.assertAllClose([[[-.592593], [-.75]], [[-.076923], [.568966]]], - sess.run(right_node_contribs_list)) + self.evaluate(right_node_contribs_list)) def testCalculateBestGainsWithL2(self): """Testing Gain calculation with L2.""" @@ -113,16 +113,16 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) self.assertAllClose([[0., 0.33931375], [0.01879096, 0.33931375]], - sess.run(gains_list)) - self.assertAllEqual([[0, 1], [1, 1]], sess.run(thresholds_list)) + self.evaluate(gains_list)) + self.assertAllEqual([[0, 1], [1, 1]], self.evaluate(thresholds_list)) # The left node contrib will be later added to the previous node value to # make the left node value, and the same for right node contrib. self.assertAllClose([[[0.], [.485294]], [[-.5], [-.6]]], - sess.run(left_node_contribs_list)) + self.evaluate(left_node_contribs_list)) self.assertAllClose([[[-.424658], [-.6]], [[-.043478], [.485294]]], - sess.run(right_node_contribs_list)) + self.evaluate(right_node_contribs_list)) def testCalculateBestGainsWithL1(self): """Testing Gain calculation with L1.""" @@ -162,18 +162,18 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[0, 1], [1, 1]], sess.run(thresholds_list)) + self.assertAllEqual([[0, 1], [1, 1]], self.evaluate(thresholds_list)) - self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) self.assertAllClose([[[0.0], [0.3965517]], [[-0.4], [-0.5]]], - sess.run(left_node_contribs_list)) + self.evaluate(left_node_contribs_list)) self.assertAllClose([[[-0.3333333], [-0.5]], [[0.0], [0.396552]]], - sess.run(right_node_contribs_list)) + self.evaluate(right_node_contribs_list)) # Gain should also include an adjustment of the gradient by l1. self.assertAllClose([[0.0, 0.191207], [0.01, 0.191207]], - sess.run(gains_list)) + self.evaluate(gains_list)) def testCalculateBestGainsWithTreeComplexity(self): """Testing Gain calculation with L2.""" @@ -214,18 +214,18 @@ class StatsOpsTest(test_util.TensorFlowTestCase): min_node_weight=0, max_splits=max_splits) - self.assertAllEqual([[1, 2], [1, 2]], sess.run(node_ids_list)) + self.assertAllEqual([[1, 2], [1, 2]], self.evaluate(node_ids_list)) self.assertAllClose([[-3., -2.66068625], [-2.98120904, -2.66068625]], - sess.run(gains_list)) + self.evaluate(gains_list)) - self.assertAllEqual([[0, 1], [1, 1]], sess.run(thresholds_list)) + self.assertAllEqual([[0, 1], [1, 1]], self.evaluate(thresholds_list)) # The left node contrib will be later added to the previous node value to # make the left node value, and the same for right node contrib. self.assertAllClose([[[0.], [.485294]], [[-.5], [-.6]]], - sess.run(left_node_contribs_list)) + self.evaluate(left_node_contribs_list)) self.assertAllClose([[[-.424658], [-.6]], [[-.043478], [.485294]]], - sess.run(right_node_contribs_list)) + self.evaluate(right_node_contribs_list)) def testCalculateBestGainsWithMinNodeWeight(self): """Testing Gain calculation without any regularization.""" @@ -266,13 +266,13 @@ class StatsOpsTest(test_util.TensorFlowTestCase): # We can't split node 1 on feature 1 and node 2 on feature 2 because of # the min node weight. - self.assertAllEqual([[2], [1]], sess.run(node_ids_list)) - self.assertAllClose([[0.384314], [0.098013]], sess.run(gains_list)) - self.assertAllEqual([[1], [1]], sess.run(thresholds_list)) + self.assertAllEqual([[2], [1]], self.evaluate(node_ids_list)) + self.assertAllClose([[0.384314], [0.098013]], self.evaluate(gains_list)) + self.assertAllEqual([[1], [1]], self.evaluate(thresholds_list)) self.assertAllClose([[[0.4852941]], [[-.6]]], - sess.run(left_node_contribs_list)) + self.evaluate(left_node_contribs_list)) self.assertAllClose([[[-0.75]], [[-0.014925]]], - sess.run(right_node_contribs_list)) + self.evaluate(right_node_contribs_list)) def testCalculateBestGainsWithMinNodeWeightNoSplitOnFeturePossible(self): """Testing Gain calculation without any regularization.""" @@ -311,9 +311,9 @@ class StatsOpsTest(test_util.TensorFlowTestCase): max_splits=max_splits) # We can't split either of the nodes on the first feature - self.assertEqual(2, len(sess.run(node_ids_list))) - self.assertAllEqual([], sess.run(node_ids_list)[0]) - self.assertAllEqual([1], sess.run(node_ids_list)[1]) + self.assertEqual(2, len(self.evaluate(node_ids_list))) + self.assertAllEqual([], self.evaluate(node_ids_list)[0]) + self.assertAllEqual([1], self.evaluate(node_ids_list)[1]) # Now check when we can't split on any feature (node_ids_list, _, _, _, @@ -325,7 +325,7 @@ class StatsOpsTest(test_util.TensorFlowTestCase): tree_complexity=0.0, min_node_weight=10, max_splits=max_splits) - self.assertAllEqual([[], []], sess.run(node_ids_list)) + self.assertAllEqual([[], []], self.evaluate(node_ids_list)) def testMakeStatsSummarySimple(self): """Simple test for MakeStatsSummary.""" diff --git a/tensorflow/python/kernel_tests/bucketize_op_test.py b/tensorflow/python/kernel_tests/bucketize_op_test.py index 57413e6af5..f40ca82527 100644 --- a/tensorflow/python/kernel_tests/bucketize_op_test.py +++ b/tensorflow/python/kernel_tests/bucketize_op_test.py @@ -32,7 +32,7 @@ class BucketizationOpTest(test.TestCase): boundaries=[0, 3, 8, 11]) expected_out = [0, 1, 1, 2, 2, 3, 3, 4, 4] with self.session(use_gpu=True) as sess: - self.assertAllEqual(expected_out, sess.run(op)) + self.assertAllEqual(expected_out, self.evaluate(op)) def testFloat(self): op = math_ops._bucketize( @@ -40,7 +40,7 @@ class BucketizationOpTest(test.TestCase): boundaries=[0., 3., 8., 11.]) expected_out = [0, 1, 1, 2, 2, 3, 3, 4, 4] with self.session(use_gpu=True) as sess: - self.assertAllEqual(expected_out, sess.run(op)) + self.assertAllEqual(expected_out, self.evaluate(op)) def test2DInput(self): op = math_ops._bucketize( @@ -48,7 +48,7 @@ class BucketizationOpTest(test.TestCase): boundaries=[0, 3, 8, 11]) expected_out = [[0, 1, 1, 2, 2], [3, 3, 4, 4, 1]] with self.session(use_gpu=True) as sess: - self.assertAllEqual(expected_out, sess.run(op)) + self.assertAllEqual(expected_out, self.evaluate(op)) def testInvalidBoundariesOrder(self): op = math_ops._bucketize( @@ -56,7 +56,7 @@ class BucketizationOpTest(test.TestCase): with self.session(use_gpu=True) as sess: with self.assertRaisesRegexp( errors_impl.InvalidArgumentError, "Expected sorted boundaries"): - sess.run(op) + self.evaluate(op) def testBoundariesNotList(self): with self.assertRaisesRegexp( diff --git a/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py b/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py index 46ab71537f..031accee55 100644 --- a/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py +++ b/tensorflow/python/kernel_tests/candidate_sampler_ops_test.py @@ -97,7 +97,7 @@ class RangeSamplerOpsTest(test.TestCase): true_classes, self.NUM_TRUE, self.NUM_SAMPLED, True) accidental_hits = candidate_sampling_ops.compute_accidental_hits( true_classes, sampled_candidates, self.NUM_TRUE) - indices, ids, weights = sess.run(accidental_hits) + indices, ids, weights = self.evaluate(accidental_hits) self.assertEqual(1, accidental_hits[0].get_shape().ndims) self.assertEqual(1, accidental_hits[1].get_shape().ndims) diff --git a/tensorflow/python/kernel_tests/cast_op_test.py b/tensorflow/python/kernel_tests/cast_op_test.py index bc49cd5a04..2cfe084d95 100644 --- a/tensorflow/python/kernel_tests/cast_op_test.py +++ b/tensorflow/python/kernel_tests/cast_op_test.py @@ -187,7 +187,7 @@ class CastOpTest(test.TestCase): y = variables.Variable(True, dtype=dtypes.bool) cast = math_ops.cast(y, x.dtype) variables.global_variables_initializer().run() - self.assertEqual(1.0, sess.run(cast)) + self.assertEqual(1.0, self.evaluate(cast)) def testGradients(self): t = [dtypes.float32, dtypes.float64, dtypes.complex64, dtypes.complex128] @@ -229,7 +229,7 @@ class SaturateCastTest(test.TestCase): [lo, lo + 1, lo // 2, hi // 2, hi - 1, hi], dtype=in_type) y = math_ops.saturate_cast(x, dtype=out_type) self.assertEqual(y.dtype, out_type) - x, y = sess.run([x, y]) + x, y = self.evaluate([x, y]) correct = np.maximum(out_type.min, np.minimum(out_type.max, x)) self.assertAllEqual(correct, y) diff --git a/tensorflow/python/kernel_tests/cholesky_op_test.py b/tensorflow/python/kernel_tests/cholesky_op_test.py index fa41a03b54..1a509a43d1 100644 --- a/tensorflow/python/kernel_tests/cholesky_op_test.py +++ b/tensorflow/python/kernel_tests/cholesky_op_test.py @@ -97,7 +97,7 @@ def TriAngInvCompositeGrad(l, grad): class CholeskyOpTest(test.TestCase): def _verifyCholeskyBase(self, sess, x, chol, verification): - chol_np, verification_np = sess.run([chol, verification]) + chol_np, verification_np = self.evaluate([chol, verification]) self.assertAllClose(x, verification_np) self.assertShapeEqual(x, chol) # Check that the cholesky is lower triangular, and has positive diagonal @@ -183,7 +183,7 @@ class CholeskyOpTest(test.TestCase): matrix2 = math_ops.matmul(matrix2, matrix2, adjoint_a=True) c1 = linalg_ops.cholesky(matrix1) c2 = linalg_ops.cholesky(matrix2) - c1_val, c2_val = sess.run([c1, c2]) + c1_val, c2_val = self.evaluate([c1, c2]) self.assertAllClose(c1_val, c2_val) diff --git a/tensorflow/python/kernel_tests/concat_op_test.py b/tensorflow/python/kernel_tests/concat_op_test.py index 149302831b..27137f76bd 100644 --- a/tensorflow/python/kernel_tests/concat_op_test.py +++ b/tensorflow/python/kernel_tests/concat_op_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import gradient_checker @@ -65,7 +66,7 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result[:, 4:], params[p2]) def testInt32GPU(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): p1 = np.random.rand(2, 3).astype("i") p2 = np.random.rand(2, 3).astype("i") x1 = constant_op.constant(p1) @@ -76,13 +77,13 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result[2:, :], p2) def testRefType(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): p1 = np.random.rand(4, 4).astype("f") p2 = np.random.rand(4, 4).astype("f") v1 = variables.Variable(p1) v2 = variables.Variable(p2) c = array_ops.concat([v1, v2], 0) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) result = self.evaluate(c) self.assertEqual(result.shape, c.get_shape()) @@ -172,7 +173,7 @@ class ConcatOpTest(test.TestCase): # Test both positive and negative concat axis. # -2 and 1 correspond to the same axis for 3-dimensional tensors. for axis in [-2, 1]: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): inp = [] inp_tensors = [] for x in [1, 2, 6]: @@ -203,7 +204,7 @@ class ConcatOpTest(test.TestCase): self._testGradientsSimple(dtypes.complex64) def testGradientsFirstDim(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): inp = [] inp_tensors = [] for x in [1, 2, 6]: @@ -230,7 +231,7 @@ class ConcatOpTest(test.TestCase): # Test both positive and negative concat axis. # -1 and 2 correspond to the same axis for 3-dimensional tensors. for axis in [-1, 2]: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): inp = [] inp_tensors = [] for x in [1, 2, 6]: @@ -261,7 +262,7 @@ class ConcatOpTest(test.TestCase): # Random dim to concat on concat_dim = np.random.randint(5) concat_dim_sizes = np.random.randint(1, 5, size=num_tensors) - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): inp = [] inp_tensors = [] for x in concat_dim_sizes: @@ -358,7 +359,7 @@ class ConcatOpTest(test.TestCase): def testZeroSize(self): # Verify that concat doesn't crash and burn for zero size inputs np.random.seed(7) - with self.session(use_gpu=True) as sess: + with test_util.use_gpu(): for shape0 in (), (2,): axis = len(shape0) for shape1 in (), (3,): @@ -370,10 +371,10 @@ class ConcatOpTest(test.TestCase): # TODO(irving): Make tf.concat handle map, then drop list(). xs = list(map(constant_op.constant, [x0, x1])) c = array_ops.concat(xs, axis) - self.assertAllEqual(c.eval(), correct) + self.assertAllEqual(self.evaluate(c), correct) # Check gradients dc = np.random.randn(*c.get_shape().as_list()) - dxs = sess.run(gradients_impl.gradients(c, xs, dc)) + dxs = self.evaluate(gradients_impl.gradients(c, xs, dc)) self.assertAllEqual(dc, np.concatenate(dxs, axis=axis)) def testTensorConcatDim0Grad(self): @@ -473,18 +474,17 @@ class ConcatOpTest(test.TestCase): def testConcatTuple(self): c1 = np.random.rand(4, 4) c2 = np.random.rand(4, 4) - with self.cached_session(): - concat_list_t = array_ops.concat([c1, c2], 0) - concat_tuple_t = array_ops.concat((c1, c2), 0) - self.assertAllEqual(concat_list_t.eval(), self.evaluate(concat_tuple_t)) + concat_list_t = array_ops.concat([c1, c2], 0) + concat_tuple_t = array_ops.concat((c1, c2), 0) + self.assertAllEqual( + self.evaluate(concat_list_t), self.evaluate(concat_tuple_t)) def testConcatNoScalars(self): - with self.cached_session(): - scalar = constant_op.constant(7) - dim = array_ops.placeholder(dtypes.int32) - with self.assertRaisesRegexp( - ValueError, r"Can't concatenate scalars \(use tf\.stack instead\)"): - array_ops.concat([scalar, scalar, scalar], dim) + scalar = constant_op.constant(7) + dim = array_ops.placeholder(dtypes.int32) + with self.assertRaisesRegexp( + ValueError, r"Can't concatenate scalars \(use tf\.stack instead\)"): + array_ops.concat([scalar, scalar, scalar], dim) # important as gpu implementation could fail if # shared memory is not large for all the inputs @@ -523,21 +523,21 @@ class ConcatOpTest(test.TestCase): self.assertAllEqual(result[index], params[p[i]]) def testConcatEmpty(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): t1 = [] t2 = [] - output = gen_array_ops.concat_v2([t1, t2], 0).eval() - self.assertFalse(output) # Checks that output is empty + output = gen_array_ops.concat_v2([t1, t2], 0) + self.assertFalse(self.evaluate(output)) # Checks that output is empty def testConcatInvalidAxis(self): with self.assertRaises(ValueError): - with self.session(use_gpu=True): + with test_util.use_gpu(): t1 = [1] t2 = [2] gen_array_ops.concat_v2([t1, t2], 1).eval() def testConcatNegativeAxis(self): - with self.session(use_gpu=True): + with test_util.use_gpu(): t1 = [[1, 2, 3], [4, 5, 6]] t2 = [[7, 8, 9], [10, 11, 12]] @@ -608,7 +608,7 @@ class ConcatOpTest(test.TestCase): def testConcatAxisType(self): for dtype in [dtypes.int32, dtypes.int64]: - with self.cached_session(use_gpu=True): + with test_util.use_gpu(): t1 = [[1, 2, 3], [4, 5, 6]] t2 = [[7, 8, 9], [10, 11, 12]] @@ -621,65 +621,61 @@ class ConcatOpTest(test.TestCase): class ConcatOffsetTest(test.TestCase): def testBasic(self): - with self.session(use_gpu=True) as sess: + with test_util.use_gpu(): cdim = constant_op.constant(1, dtypes.int32) s0 = constant_op.constant([2, 3, 5], dtypes.int32) s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = sess.run(off) + ans = self.evaluate(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) def testNotVector(self): - with self.cached_session() as sess: - cdim = constant_op.constant(1, dtypes.int32) - s0 = constant_op.constant([[2, 3, 5]], dtypes.int32) - s1 = constant_op.constant([[2, 7, 5]], dtypes.int32) - off = gen_array_ops.concat_offset(cdim, [s0, s1]) - with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, - r"should be a vector"): - sess.run(off) + cdim = constant_op.constant(1, dtypes.int32) + s0 = constant_op.constant([[2, 3, 5]], dtypes.int32) + s1 = constant_op.constant([[2, 7, 5]], dtypes.int32) + off = gen_array_ops.concat_offset(cdim, [s0, s1]) + with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, + r"should be a vector"): + self.evaluate(off) def testConcatDimOutOfRange(self): - with self.cached_session() as sess: - cdim = constant_op.constant(4, dtypes.int32) - s0 = constant_op.constant([2, 3, 5], dtypes.int32) - s1 = constant_op.constant([2, 7, 5], dtypes.int32) - off = gen_array_ops.concat_offset(cdim, [s0, s1]) - with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, - r"Concat dim is out of range: 4 vs. 3"): - sess.run(off) + cdim = constant_op.constant(4, dtypes.int32) + s0 = constant_op.constant([2, 3, 5], dtypes.int32) + s1 = constant_op.constant([2, 7, 5], dtypes.int32) + off = gen_array_ops.concat_offset(cdim, [s0, s1]) + with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, + r"Concat dim is out of range: 4 vs. 3"): + self.evaluate(off) def testDimMismatch(self): - with self.cached_session() as sess: - cdim = constant_op.constant(1, dtypes.int32) - s0 = constant_op.constant([2, 3, 5], dtypes.int32) - s1 = constant_op.constant([2, 7, 5, 10], dtypes.int32) - off = gen_array_ops.concat_offset(cdim, [s0, s1]) - with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, - r"should contain 3 elem"): - sess.run(off) + cdim = constant_op.constant(1, dtypes.int32) + s0 = constant_op.constant([2, 3, 5], dtypes.int32) + s1 = constant_op.constant([2, 7, 5, 10], dtypes.int32) + off = gen_array_ops.concat_offset(cdim, [s0, s1]) + with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, + r"should contain 3 elem"): + self.evaluate(off) def testSizeMismatch(self): - with self.cached_session() as sess: - cdim = constant_op.constant(1, dtypes.int32) - s0 = constant_op.constant([2, 3, 5], dtypes.int32) - s1 = constant_op.constant([2, 7, 10], dtypes.int32) - off = gen_array_ops.concat_offset(cdim, [s0, s1]) - with self.assertRaisesRegexp( - errors_impl.InvalidArgumentError, - r"All dimensions except 1 must match. Input 1 has shape \[2 7 10\] " - r"and doesn't match input 0 with shape \[2 3 5\]."): - sess.run(off) + cdim = constant_op.constant(1, dtypes.int32) + s0 = constant_op.constant([2, 3, 5], dtypes.int32) + s1 = constant_op.constant([2, 7, 10], dtypes.int32) + off = gen_array_ops.concat_offset(cdim, [s0, s1]) + with self.assertRaisesRegexp( + errors_impl.InvalidArgumentError, + r"All dimensions except 1 must match. Input 1 has shape \[2 7 10\] " + r"and doesn't match input 0 with shape \[2 3 5\]."): + self.evaluate(off) def testNegativeDim(self): - with self.session(use_gpu=True) as sess: + with test_util.use_gpu(): cdim = constant_op.constant(-2, dtypes.int32) s0 = constant_op.constant([2, 3, 5], dtypes.int32) s1 = constant_op.constant([2, 7, 5], dtypes.int32) s2 = constant_op.constant([2, 20, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = sess.run(off) + ans = self.evaluate(off) self.assertAllEqual(ans, [[0, 0, 0], [0, 3, 0], [0, 10, 0]]) cdim = constant_op.constant(-3, dtypes.int32) @@ -687,7 +683,7 @@ class ConcatOffsetTest(test.TestCase): s1 = constant_op.constant([1, 3, 5], dtypes.int32) s2 = constant_op.constant([3, 3, 5], dtypes.int32) off = gen_array_ops.concat_offset(cdim, [s0, s1, s2]) - ans = sess.run(off) + ans = self.evaluate(off) self.assertAllEqual(ans, [[0, 0, 0], [2, 0, 0], [3, 0, 0]]) diff --git a/tensorflow/python/kernel_tests/conditional_accumulator_test.py b/tensorflow/python/kernel_tests/conditional_accumulator_test.py index 893cb7cce3..7ee1a4bc32 100644 --- a/tensorflow/python/kernel_tests/conditional_accumulator_test.py +++ b/tensorflow/python/kernel_tests/conditional_accumulator_test.py @@ -111,7 +111,7 @@ class ConditionalAccumulatorTest(test.TestCase): for e in elems: q.apply_grad((e,)).run() - result = sess.run(q.take_grad(1)) + result = self.evaluate(q.take_grad(1)) self.assertEqual(sum(elems) / len(elems), result) @@ -424,7 +424,7 @@ class ConditionalAccumulatorTest(test.TestCase): takeg_t = q.take_grad(1) def apply_grad(accum_op): - sess.run(accum_op) + self.evaluate(accum_op) threads = [ self.checkedThread( @@ -451,14 +451,14 @@ class ConditionalAccumulatorTest(test.TestCase): def apply_grad(): for accum_op in accum_ops: time.sleep(1.0) - sess.run(accum_op) + self.evaluate(accum_op) apply_grad_thread = self.checkedThread(target=apply_grad) results = [] def take_grad(): - results.append(sess.run(takeg_t)) + results.append(self.evaluate(takeg_t)) threads = [self.checkedThread(target=take_grad) for _ in range(10)] @@ -485,12 +485,12 @@ class ConditionalAccumulatorTest(test.TestCase): def apply_grad(): time.sleep(1.0) for accum_op in accum_ops: - sess.run(accum_op) + self.evaluate(accum_op) return_array = [] def take_grad(): - return_array.append(sess.run(takeg_t)) + return_array.append(self.evaluate(takeg_t)) accum_thread = self.checkedThread(target=apply_grad) takeg_thread = self.checkedThread(target=take_grad) @@ -503,7 +503,7 @@ class ConditionalAccumulatorTest(test.TestCase): def _blocking_takeg(self, sess, takeg_op): with self.assertRaisesOpError("was cancelled"): - sess.run(takeg_op) + self.evaluate(takeg_op) def testAccumulatorCancel(self): with self.cached_session() as sess: diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 9a198d445f..37654abd18 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -593,7 +593,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: [math_ops.add(x, 1), math_ops.add(x, 2)] fn2 = lambda: [y, y] r = control_flow_ops.cond(pred, fn1, fn2) - self.assertAllEqual([11, 12], sess.run(r)) + self.assertAllEqual([11, 12], self.evaluate(r)) def testCondListOutput(self): with self.cached_session() as sess: @@ -603,7 +603,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: [math_ops.add(x, y), math_ops.add(x, y)] fn2 = lambda: [y, y] r = control_flow_ops.cond(pred, fn1, fn2) - test_result = sess.run(r) + test_result = self.evaluate(r) self.assertListEqual([210, 210], test_result) def testTupleOutput(self): @@ -614,7 +614,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: (math_ops.add(x, y), math_ops.add(x, y)) fn2 = lambda: (y, y) r = control_flow_ops.cond(pred, fn1, fn2) - test_result = sess.run(r) + test_result = self.evaluate(r) self.assertTupleEqual((210, 210), test_result) def testDictOutput(self): @@ -625,7 +625,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: {"a": math_ops.add(x, y), "b": math_ops.add(x, y)} fn2 = lambda: {"a": y, "b": y} r = control_flow_ops.cond(pred, fn1, fn2) - test_result = sess.run(r) + test_result = self.evaluate(r) self.assertDictEqual({"a": 210, "b": 210}, test_result) def testEmbeddedListOutput(self): @@ -638,7 +638,7 @@ class ControlFlowTest(test.TestCase): # Pass strict=True flag as cond_v2 allows for tensors to be # in nested output structures as singletons r = control_flow_ops.cond(pred, fn1, fn2, strict=True) - test_result = sess.run(r) + test_result = self.evaluate(r) self.assertListEqual([[210, 210]], test_result) def testEmbeddedTupleOutput(self): @@ -649,7 +649,7 @@ class ControlFlowTest(test.TestCase): fn1 = lambda: ((math_ops.add(x, y), math_ops.add(x, y))) fn2 = lambda: ((y, y)) r = control_flow_ops.cond(pred, fn1, fn2) - test_result = sess.run(r) + test_result = self.evaluate(r) self.assertTupleEqual(((210, 210)), test_result) def testEmbeddedDictOutput(self): @@ -662,7 +662,7 @@ class ControlFlowTest(test.TestCase): fn2 = lambda: {"a": {"c": y}, "b": {"d": y}} r = control_flow_ops.cond(pred, fn1, fn2) - test_result = sess.run(r) + test_result = self.evaluate(r) self.assertDictEqual({"a": {"c": 210}, "b": {"d": 210}}, test_result) def testCheckNestedOutputStruct(self): @@ -677,7 +677,7 @@ class ControlFlowTest(test.TestCase): with self.assertRaisesRegexp( ValueError, v2_msg if control_flow_ops.ENABLE_COND_V2 else v1_msg): r = control_flow_ops.cond(pred, fn1, fn2) - test_result = sess.run(r) + self.evaluate(r) def testCondRef(self): @@ -731,7 +731,7 @@ class ControlFlowTest(test.TestCase): with ops.control_dependencies([v_t_op]): orig_v = array_ops.identity(v) merged_op = control_flow_ops.merge([assign_v, orig_v]) - self.assertAllEqual([1.0], sess.run(merged_op.output)) + self.assertAllEqual([1.0], self.evaluate(merged_op.output)) def testCondSwitchIdentity(self): # Make sure the recv identity is not removed by optimization. @@ -745,7 +745,7 @@ class ControlFlowTest(test.TestCase): return control_flow_ops.Assert(False, ["Wrong branch!!!"]) r = control_flow_ops.cond(pred, fn1, fn2) - sess.run(r) + self.evaluate(r) def testCondRecvIdentity(self): # Make sure the switch identity is not removed by optimization. @@ -761,7 +761,7 @@ class ControlFlowTest(test.TestCase): return control_flow_ops.Assert(False, ["Wrong branch!!!"]) r = control_flow_ops.cond(pred, fn1, fn2) - sess.run(r) + self.evaluate(r) def testCondGrad_1(self): with self.cached_session(): @@ -1050,7 +1050,7 @@ class ControlFlowTest(test.TestCase): self.assertEqual(r[0].dtype, dtypes.int32) self.assertEqual(r[1].dtype, dtypes.int32_ref) - value_i, value_x = sess.run(r) + value_i, value_x = self.evaluate(r) self.assertEqual(100, value_i) self.assertEqual(0, value_x) @@ -1642,7 +1642,7 @@ class ControlFlowTest(test.TestCase): with ops.control_dependencies([control_flow_ops.no_op()]): loop = control_flow_ops.while_loop(cond, body, (constant_op.constant(5),)) - self.assertEqual(0, sess.run(loop)) + self.assertEqual(0, self.evaluate(loop)) @test_util.disable_control_flow_v2("b/113324949 (ref vars)") def testWhileCondWithControl_1(self): @@ -2055,7 +2055,7 @@ class ControlFlowTest(test.TestCase): self.assertFalse(gpu_dev_name in dev) with self.session(graph=graph) as sess: - self.assertAllClose(1024.0, sess.run(r)) + self.assertAllClose(1024.0, self.evaluate(r)) @test_util.disable_control_flow_v2("b/116351701 (colocation)") def testWhileGrad_ColocateGradients(self): @@ -2133,7 +2133,7 @@ class ControlFlowTest(test.TestCase): r = control_flow_ops.while_loop(c, b, [v], parallel_iterations=p_iters) grad_a, grad_v = gradients_impl.gradients(r, [a, v]) - grad_a_val, grad_v_val = sess.run([grad_a, grad_v]) + grad_a_val, grad_v_val = self.evaluate([grad_a, grad_v]) self.assertAllClose(216.0, grad_a_val) self.assertAllClose(81.0, grad_v_val) @@ -2264,7 +2264,7 @@ class ControlFlowTest(test.TestCase): i, x = control_flow_ops.while_loop(lambda i, x: i < 3, outer_body, [0, 0.0]) with self.cached_session() as sess: - i_val, x_val = sess.run([i, x]) + i_val, x_val = self.evaluate([i, x]) self.assertEqual(i_val, 3) self.assertAllClose(x_val, 1.0) @@ -2293,7 +2293,7 @@ class ControlFlowTest(test.TestCase): r_flattened = nest.flatten(r) self.assertEqual([100.0, 1.0, 102.0, 3.0, 4.0 + 100 * 2.0], - sess.run(r_flattened)) + self.evaluate(r_flattened)) def testWhile_NestedBadArityFails(self): with self.cached_session(): @@ -2547,8 +2547,8 @@ class ControlFlowTest(test.TestCase): res = outer_loop(inp) optimizer = adam.AdamOptimizer(learning_rate=0.001) train_op = optimizer.minimize(math_ops.reduce_mean(math_ops.square(res))) - sess.run(variables.global_variables_initializer()) - sess.run(train_op) + self.evaluate(variables.global_variables_initializer()) + self.evaluate(train_op) self.assertAllClose(2.999, self.evaluate(var)) def _testWhileCondGrad_Simple(self, use_gpu): @@ -2607,11 +2607,11 @@ class ControlFlowTest(test.TestCase): [i0.get_shape(), tensor_shape.TensorShape([None, 2])]) s = math_ops.reduce_sum(h) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) optimizer = gradient_descent.GradientDescentOptimizer(0.01) op = optimizer.minimize(s) - sess.run(op) - self.assertAllClose([[0.98000002, 1.98000002]], sess.run(x)) + self.evaluate(op) + self.assertAllClose([[0.98000002, 1.98000002]], self.evaluate(x)) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") def testWhileWithRefsWithGradients_1(self): @@ -2705,7 +2705,7 @@ class ControlFlowTest(test.TestCase): output_grad = control_flow_ops.while_loop( c, b, [i0, constant_op.constant(0.0)]) - self.assertAllClose(600.0, sess.run(output_grad)[1]) + self.assertAllClose(600.0, self.evaluate(output_grad)[1]) def testWhileAndTensorArray(self): with self.cached_session() as sess: @@ -2724,7 +2724,7 @@ class ControlFlowTest(test.TestCase): r = control_flow_ops.while_loop(c, b, [n0, y0], parallel_iterations=1) r = gradients_impl.gradients(r, param)[0] - self.assertAllClose(107520.0, sess.run(r)) + self.assertAllClose(107520.0, self.evaluate(r)) def testWhileGrad_StopGrad(self): with self.cached_session(): @@ -2857,8 +2857,8 @@ class ControlFlowTest(test.TestCase): dy_dq, = gradients_impl.gradients(y, q) self.assertIsNotNone(dy_dq) with self.cached_session() as sess: - sess.run(q.initializer) - self.assertAllClose([0., 0.], sess.run(dy_dq)) + self.evaluate(q.initializer) + self.assertAllClose([0., 0.], self.evaluate(dy_dq)) @test_util.disable_control_flow_v2("b/113324949 (RefVariable)") def testWhileGradientWithNontrainablePath2(self): @@ -2875,8 +2875,8 @@ class ControlFlowTest(test.TestCase): dy_dq, = gradients_impl.gradients(y, q) self.assertIsNotNone(dy_dq) with self.cached_session() as sess: - sess.run(q.initializer) - self.assertAllClose([1., 1.], sess.run(dy_dq)) + self.evaluate(q.initializer) + self.assertAllClose([1., 1.], self.evaluate(dy_dq)) @test_util.disable_control_flow_v2("b/115920078 (gradients)") def testIssue16504(self): @@ -3033,19 +3033,19 @@ class ControlFlowTest(test.TestCase): ((x > y, a), (x > y, b)), default=c, exclusive=True) variables.global_variables_initializer().run() - self.assertAllEqual(sess.run([v0, v1, v2]), [-1] * 3) + self.assertAllEqual(self.evaluate([v0, v1, v2]), [-1] * 3) self.assertEqual(2, self.evaluate(r2)) - self.assertAllEqual(sess.run([v0, v1, v2]), [-1, -1, 2]) + self.assertAllEqual(self.evaluate([v0, v1, v2]), [-1, -1, 2]) variables.global_variables_initializer().run() - self.assertAllEqual(sess.run([v0, v1, v2]), [-1] * 3) + self.assertAllEqual(self.evaluate([v0, v1, v2]), [-1] * 3) self.assertEqual(1, self.evaluate(r1)) - self.assertAllEqual(sess.run([v0, v1, v2]), [-1, 1, -1]) + self.assertAllEqual(self.evaluate([v0, v1, v2]), [-1, 1, -1]) variables.global_variables_initializer().run() - self.assertAllEqual(sess.run([v0, v1, v2]), [-1] * 3) + self.assertAllEqual(self.evaluate([v0, v1, v2]), [-1] * 3) self.assertEqual(0, self.evaluate(r0)) - self.assertAllEqual(sess.run([v0, v1, v2]), [0, -1, -1]) + self.assertAllEqual(self.evaluate([v0, v1, v2]), [0, -1, -1]) @test_util.disable_control_flow_v2("b/113324949 (ref vars)") def testOneOpCond(self): @@ -3083,7 +3083,7 @@ class ControlFlowTest(test.TestCase): # Fetching v directly will result in an uninitialized error with self.assertRaisesOpError("Attempting to use uninitialized value"): - sess.run([c, v]) + self.evaluate([c, v]) # Use a control dependency to ensure init_variable is run # while asking for c @@ -3091,7 +3091,7 @@ class ControlFlowTest(test.TestCase): name="real_tensor", output_tensor=v._ref(), # pylint: disable=protected-access dependencies=[v.initializer]) - c_val, real_v_val = sess.run([c, real_v]) + c_val, real_v_val = self.evaluate([c, real_v]) # Ensure the result of 'real_c' is the same as 'c' self.assertAllEqual(10, c_val) @@ -3184,7 +3184,7 @@ class ControlFlowTest(test.TestCase): # Runs "init" before fetching v1 and v2. init.run() - v1_val, v2_val = sess.run([v1, v2]) + v1_val, v2_val = self.evaluate([v1, v2]) # Ensure that v1 and v2 are initialized self.assertAllClose([0.0], v1_val) @@ -3295,7 +3295,7 @@ class ControlFlowTest(test.TestCase): result = control_flow_ops.while_loop(condition, body, [constant_op.constant(4)]) - self.assertEqual(10, sess.run(result)) + self.assertEqual(10, self.evaluate(result)) # Ensure that we cannot run a tensor that escapes the loop body # accidentally. @@ -3345,7 +3345,7 @@ class ControlFlowTest(test.TestCase): cond = constant_op.constant(True, dtypes.bool) v_f, v_t = control_flow_ops.switch(constant_qint, cond) result = control_flow_ops.merge([v_f, v_t]) - sess.run(result) + self.evaluate(result) def testQIntRefSwitchMerge(self): with self.cached_session(use_gpu=test.is_gpu_available()) as sess: @@ -3353,12 +3353,12 @@ class ControlFlowTest(test.TestCase): shape=[1], dtype=dtypes.qint8, name="v", container="", shared_name="") assign_op = state_ops.assign( var_qint, constant_op.constant(np.array([42]), dtypes.qint8)) - sess.run(assign_op) + self.evaluate(assign_op) cond = constant_op.constant(True, dtypes.bool) v_f, v_t = control_flow_ops.ref_switch(var_qint, cond) result = control_flow_ops.ref_merge([v_f, v_t]) - sess.run(result) + self.evaluate(result) def testUInt64SwitchMerge(self): with self.cached_session(force_gpu=test.is_gpu_available()) as sess: @@ -3366,7 +3366,7 @@ class ControlFlowTest(test.TestCase): cond = constant_op.constant(True, dtypes.bool) v_f, v_t = control_flow_ops.switch(constant_uint64, cond) result = control_flow_ops.merge([v_f, v_t]) - sess.run(result) + self.evaluate(result) def testQIntArgAndRet(self): @@ -3377,7 +3377,7 @@ class ControlFlowTest(test.TestCase): with self.cached_session(force_gpu=test.is_gpu_available()) as sess: qint = constant_op.constant(np.array([42]), dtypes.qint8) result = func(qint) - sess.run(result) + self.evaluate(result) class ControlFlowContextCheckTest(test.TestCase): @@ -3682,7 +3682,7 @@ class WhileOpBenchmark(test.Benchmark): with session.Session() as sess, ops.device(default_device): # Get the initial id i, input x, and kernel. i, x, kernel = self._getInitVariables() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) if static_unroll: for _ in xrange(steps): @@ -3701,11 +3701,11 @@ class WhileOpBenchmark(test.Benchmark): for _ in xrange(3): # exclude warm up time - sess.run(r) + self.evaluate(r) start_time = time.time() for _ in xrange(num_iters): - sess.run(r) + self.evaluate(r) return (time.time() - start_time) / num_iters def benchmarkWhileOpCrossDevicePlacement(self): diff --git a/tensorflow/python/kernel_tests/conv_ops_3d_test.py b/tensorflow/python/kernel_tests/conv_ops_3d_test.py index 3924e13575..3ec5c29df7 100644 --- a/tensorflow/python/kernel_tests/conv_ops_3d_test.py +++ b/tensorflow/python/kernel_tests/conv_ops_3d_test.py @@ -109,7 +109,7 @@ class Conv3DTest(test.TestCase): results.append(result) with self.cached_session() as sess: - values = sess.run(results) + values = self.evaluate(results) for value in values: print("expected = ", expected) print("actual = ", value) @@ -184,8 +184,8 @@ class Conv3DTest(test.TestCase): computed_results.append(computed) tolerance = 1e-2 if use_gpu else 1e-5 with self.cached_session() as sess: - expected_values = sess.run(expected_results) - computed_values = sess.run(computed_results) + expected_values = self.evaluate(expected_results) + computed_values = self.evaluate(computed_results) for e_value, c_value in zip(expected_values, computed_values): print("expected = ", e_value) print("actual = ", c_value) @@ -715,8 +715,8 @@ class Conv3DTest(test.TestCase): expected_grad = gradients_impl.gradients(expected, t1 if mode == "input" else t2)[0] # "values" consists of two tensors for two backprops - actual_value = sess.run(actual_grad) - expected_value = sess.run(expected_grad) + actual_value = self.evaluate(actual_grad) + expected_value = self.evaluate(expected_grad) self.assertShapeEqual(actual_value, actual_grad) self.assertShapeEqual(expected_value, expected_grad) print("expected = ", expected_value) diff --git a/tensorflow/python/kernel_tests/conv_ops_test.py b/tensorflow/python/kernel_tests/conv_ops_test.py index 835cc1504d..2f6f3bb383 100644 --- a/tensorflow/python/kernel_tests/conv_ops_test.py +++ b/tensorflow/python/kernel_tests/conv_ops_test.py @@ -908,8 +908,8 @@ class Conv2DTest(test.TestCase): conv = gradients_impl.gradients(conv_forward, t1)[0] conv_2 = gradients_impl.gradients(conv_forward_2, t1)[0] # "values" consists of two tensors for two backprops - value = sess.run(conv) - value_2 = sess.run(conv_2) + value = self.evaluate(conv) + value_2 = self.evaluate(conv_2) self.assertShapeEqual(value, conv) self.assertShapeEqual(value_2, conv_2) tf_logging.info("expected = ", value_2) @@ -961,8 +961,8 @@ class Conv2DTest(test.TestCase): conv_forward_2 = test_util.NCHWToNHWC(conv_forward_2) conv = gradients_impl.gradients(conv_forward, t2)[0] conv_2 = gradients_impl.gradients(conv_forward, t2)[0] - value = sess.run(conv) - value_2 = sess.run(conv_2) + value = self.evaluate(conv) + value_2 = self.evaluate(conv_2) self.assertShapeEqual(value, conv) self.assertShapeEqual(value_2, conv_2) tf_logging.info("expected = ", value_2) @@ -1545,7 +1545,7 @@ class DepthwiseConv2DTest(test.TestCase): t2 = constant_op.constant(x2, shape=filter_in_sizes) conv = nn_impl.depthwise_conv2d( t1, t2, strides=[1, stride, stride, 1], padding=padding) - value = sess.run(conv) + value = self.evaluate(conv) tf_logging.info("value = ", value) self.assertArrayNear(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) @@ -1667,7 +1667,7 @@ class SeparableConv2DTest(test.TestCase): if data_format == "NCHW": conv = array_ops.transpose(conv, [0, 2, 3, 1]) - value = sess.run(conv) + value = self.evaluate(conv) tf_logging.info("value = ", value) self.assertArrayNear(expected, np.ravel(value), 1e-3) self.assertShapeEqual(value, conv) @@ -1774,10 +1774,10 @@ class DeepConv2DTest(test.TestCase): conv = nn_ops.conv2d(t1, t2, strides=strides, padding=padding) os.environ["TF_USE_DEEP_CONV2D"] = "0" - values_expect = sess.run([conv]) + values_expect = self.evaluate([conv]) os.environ["TF_USE_DEEP_CONV2D"] = "1" - values_test = sess.run([conv]) + values_test = self.evaluate([conv]) self.assertAllClose(values_expect, values_test, rtol=1e-5, atol=1e-5) diff --git a/tensorflow/python/kernel_tests/ctc_loss_op_test.py b/tensorflow/python/kernel_tests/ctc_loss_op_test.py index b38776ec5b..36cae2846c 100644 --- a/tensorflow/python/kernel_tests/ctc_loss_op_test.py +++ b/tensorflow/python/kernel_tests/ctc_loss_op_test.py @@ -98,12 +98,12 @@ class CTCLossTest(test.TestCase): self.assertShapeEqual(grad_truth, grad) if expected_err_re is None: - (tf_loss, tf_grad) = sess.run([loss, grad]) + (tf_loss, tf_grad) = self.evaluate([loss, grad]) self.assertAllClose(tf_loss, loss_truth, atol=1e-6) self.assertAllClose(tf_grad, grad_truth, atol=1e-6) else: with self.assertRaisesOpError(expected_err_re): - sess.run([loss, grad]) + self.evaluate([loss, grad]) def testBasic(self): """Test two batch entries.""" @@ -266,7 +266,7 @@ class CTCLossTest(test.TestCase): sequence_length=seq_lens, time_major=False) - (tf_loss, tf_loss_transposed) = sess.run([loss, loss_transposed]) + (tf_loss, tf_loss_transposed) = self.evaluate([loss, loss_transposed]) self.assertAllEqual(tf_loss, tf_loss_transposed) def testInvalidSecondGradient(self): @@ -332,9 +332,10 @@ class CTCLossTestV2(test.TestCase): def assert_same_loss_and_grads(loss): with self.cached_session() as sess: - self.assertAllClose(*sess.run([loss, ref_loss])) + self.assertAllClose(*self.evaluate([loss, ref_loss])) grad = gradients_impl.gradients(loss, [logits]) - self.assertAllClose(*sess.run([grad, ref_grad]), rtol=2e-06, atol=2e-06) + self.assertAllClose( + *self.evaluate([grad, ref_grad]), rtol=2e-06, atol=2e-06) assert_same_loss_and_grads( ctc_ops.ctc_loss_v2( @@ -391,9 +392,11 @@ class CTCLossTestV2(test.TestCase): with self.cached_session() as sess: for _ in range(32): - self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) - self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), - rtol=2e-06, atol=2e-06) + self.assertAllClose(*self.evaluate([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose( + *self.evaluate([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, + atol=2e-06) def testCtcLossDenseUniqueFastPathIsSameAsCtcLoss(self): random_seed.set_random_seed(5) @@ -442,9 +445,11 @@ class CTCLossTestV2(test.TestCase): with self.cached_session() as sess: for _ in range(32): - self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) - self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), - rtol=2e-06, atol=2e-06) + self.assertAllClose(*self.evaluate([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose( + *self.evaluate([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, + atol=2e-06) def testCtcLossDenseWithBlankIndexIsSameAsCtcLoss(self): random_seed.set_random_seed(5) @@ -496,9 +501,11 @@ class CTCLossTestV2(test.TestCase): with self.cached_session() as sess: for _ in range(32): - self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) - self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), - rtol=2e-06, atol=2e-06) + self.assertAllClose(*self.evaluate([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose( + *self.evaluate([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, + atol=2e-06) def testCtcLossDenseWithNegativeBlankIndexIsSameAsCtcLoss(self): with ops.device("/GPU:0" if test.is_gpu_available() else "/CPU:0"): @@ -542,9 +549,11 @@ class CTCLossTestV2(test.TestCase): with self.cached_session() as sess: for _ in range(32): - self.assertAllClose(*sess.run([ctc_loss, tf_nn_ctc_loss])) - self.assertAllClose(*sess.run([ctc_loss_grads, tf_nn_ctc_grads]), - rtol=2e-06, atol=2e-06) + self.assertAllClose(*self.evaluate([ctc_loss, tf_nn_ctc_loss])) + self.assertAllClose( + *self.evaluate([ctc_loss_grads, tf_nn_ctc_grads]), + rtol=2e-06, + atol=2e-06) def testCollapseRepeated(self): collapsed, new_seq_lengths = ctc_ops.collapse_repeated( diff --git a/tensorflow/python/kernel_tests/cwise_ops_binary_test.py b/tensorflow/python/kernel_tests/cwise_ops_binary_test.py index df166b6101..fc7d4572e2 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_binary_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_binary_test.py @@ -83,17 +83,17 @@ class BinaryOpTest(test.TestCase): out = tf_func(inx, iny) tf_cpu = self.evaluate(out) # Test that the op takes precedence over numpy operators. - np_left = tf_func(x, iny).eval() - np_right = tf_func(inx, y).eval() + np_left = self.evaluate(tf_func(x, iny)) + np_right = self.evaluate(tf_func(inx, y)) if also_compare_variables: var_x = variables.Variable(x) var_y = variables.Variable(y) - variables.global_variables_initializer().run() + self.evaluate(variables.global_variables_initializer()) print(type(x), type(y), type(var_x), type(var_y)) print(type(tf_func(x, var_y)), type(tf_func(var_x, y))) - np_var_left = tf_func(x, var_y).eval() - np_var_right = tf_func(var_x, y).eval() + np_var_left = self.evaluate(tf_func(x, var_y)) + np_var_right = self.evaluate(tf_func(var_x, y)) if np_ans.dtype != np.object: self.assertAllClose(np_ans, tf_cpu) @@ -253,7 +253,7 @@ class BinaryOpTest(test.TestCase): var_x = variables.Variable(x) var_y = variables.Variable(y) with self.cached_session() as sess: - sess.run([var_x.initializer, var_y.initializer]) + self.evaluate([var_x.initializer, var_y.initializer]) left_result = (var_x * y).eval() right_result = (x * var_y).eval() np_result = x * y @@ -385,7 +385,7 @@ class BinaryOpTest(test.TestCase): with self.test_session(use_gpu=False) as sess: cmp_eq = math_ops.equal(x, y) cmp_not_eq = math_ops.not_equal(x, y) - values = sess.run([cmp_eq, cmp_not_eq]) + values = self.evaluate([cmp_eq, cmp_not_eq]) self.assertAllEqual([[True, True], [False, False]], values[0]) self.assertAllEqual([[False, False], [True, True]], values[1]) diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index d7dbf5ab9a..ab116c400a 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -572,7 +572,7 @@ class MinMaxOpTest(test.TestCase): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) omin, omax = math_ops.minimum(inx, iny), math_ops.maximum(inx, iny) - tf_min, tf_max = sess.run([omin, omax]) + tf_min, tf_max = self.evaluate([omin, omax]) self.assertAllEqual(np_min, tf_min) self.assertAllEqual(np_max, tf_max) @@ -662,8 +662,8 @@ class MathOpsOverloadTest(test.TestCase): def _compareUnary(self, x, dtype, np_func, tf_func): np_ans = np_func(x).astype(dtype.as_numpy_dtype) with self.test_session(use_gpu=False): - self.assertAllClose(np_ans, - tf_func(ops.convert_to_tensor(x, dtype=dtype)).eval()) + self.assertAllClose( + np_ans, self.evaluate(tf_func(ops.convert_to_tensor(x, dtype=dtype)))) def testOverload(self): dtypes = [ @@ -736,7 +736,7 @@ class IsFiniteInfNanTest(test.TestCase): inx = ops.convert_to_tensor(x) ofinite, oinf, onan = math_ops.is_finite(inx), math_ops.is_inf( inx), math_ops.is_nan(inx) - tf_finite, tf_inf, tf_nan = sess.run([ofinite, oinf, onan]) + tf_finite, tf_inf, tf_nan = self.evaluate([ofinite, oinf, onan]) self.assertAllEqual(np_inf, tf_inf) self.assertAllEqual(np_nan, tf_nan) self.assertAllEqual(np_finite, tf_finite) @@ -788,7 +788,7 @@ class RoundingTest(test.TestCase): y = np.rint(x) if y is None else np.asarray(y) with self.cached_session() as sess: tf_rint = math_ops.rint(x) - np_rint = sess.run(tf_rint) + np_rint = self.evaluate(tf_rint) self.assertAllEqual(y, np_rint) self.assertShapeEqual(y, tf_rint) @@ -797,7 +797,7 @@ class RoundingTest(test.TestCase): with self.cached_session() as sess: inx = ops.convert_to_tensor(x) ofloor, oceil = math_ops.floor(inx), math_ops.ceil(inx) - tf_floor, tf_ceil = sess.run([ofloor, oceil]) + tf_floor, tf_ceil = self.evaluate([ofloor, oceil]) self.assertAllEqual(np_floor, tf_floor) self.assertAllEqual(np_ceil, tf_ceil) self.assertShapeEqual(np_floor, ofloor) @@ -881,7 +881,7 @@ class ComplexMakeRealImagTest(test.TestCase): force_gpu=use_gpu and test_util.is_gpu_available()) as sess: inx = ops.convert_to_tensor(cplx) tf_angle = math_ops.angle(inx) - tf_angle_val = sess.run(tf_angle) + tf_angle_val = self.evaluate(tf_angle) self.assertAllEqual(np_angle, tf_angle_val) self.assertShapeEqual(np_angle, tf_angle) diff --git a/tensorflow/python/kernel_tests/decode_image_op_test.py b/tensorflow/python/kernel_tests/decode_image_op_test.py index 7a8743e11f..267afdeb5e 100644 --- a/tensorflow/python/kernel_tests/decode_image_op_test.py +++ b/tensorflow/python/kernel_tests/decode_image_op_test.py @@ -40,7 +40,7 @@ class DecodeImageOpTest(test.TestCase): bmp0 = io_ops.read_file(path) image0 = image_ops.decode_image(bmp0) image1 = image_ops.decode_bmp(bmp0) - bmp0, image0, image1 = sess.run([bmp0, image0, image1]) + bmp0, image0, image1 = self.evaluate([bmp0, image0, image1]) self.assertEqual(len(bmp0), 4194) self.assertAllEqual(image0, image1) @@ -56,7 +56,7 @@ class DecodeImageOpTest(test.TestCase): gif0 = io_ops.read_file(path) image0 = image_ops.decode_image(gif0) image1 = image_ops.decode_gif(gif0) - gif0, image0, image1 = sess.run([gif0, image0, image1]) + gif0, image0, image1 = self.evaluate([gif0, image0, image1]) self.assertEqual(image0.shape, shape) self.assertAllEqual(image0, image1) @@ -85,7 +85,7 @@ class DecodeImageOpTest(test.TestCase): jpeg0 = io_ops.read_file(path) image0 = image_ops.decode_image(jpeg0) image1 = image_ops.decode_jpeg(jpeg0) - jpeg0, image0, image1 = sess.run([jpeg0, image0, image1]) + jpeg0, image0, image1 = self.evaluate([jpeg0, image0, image1]) self.assertEqual(len(jpeg0), 3771) self.assertEqual(image0.shape, (256, 128, 3)) self.assertAllEqual(image0, image1) @@ -104,7 +104,7 @@ class DecodeImageOpTest(test.TestCase): png0 = io_ops.read_file(path) image0 = image_ops.decode_image(png0, channels=channels) image1 = image_ops.decode_png(png0, channels=channels) - png0, image0, image1 = sess.run([png0, image0, image1]) + png0, image0, image1 = self.evaluate([png0, image0, image1]) self.assertEqual(image0.shape, (26, 51, channels or channels_in)) self.assertAllEqual(image0, image1) diff --git a/tensorflow/python/kernel_tests/decode_jpeg_op_test.py b/tensorflow/python/kernel_tests/decode_jpeg_op_test.py index 66b3e0f22f..f8fc28062f 100644 --- a/tensorflow/python/kernel_tests/decode_jpeg_op_test.py +++ b/tensorflow/python/kernel_tests/decode_jpeg_op_test.py @@ -80,7 +80,7 @@ class DecodeJpegBenchmark(test.Benchmark): initializer=image_ops.encode_jpeg(tiled_image)) with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) images = [] for _ in xrange(parallelism): if crop_window is None: @@ -105,11 +105,11 @@ class DecodeJpegBenchmark(test.Benchmark): for _ in xrange(3): # Skip warm up time. - sess.run(r) + self.evaluate(r) start_time = time.time() for _ in xrange(num_iters): - sess.run(r) + self.evaluate(r) end_time = time.time() return end_time - start_time diff --git a/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py b/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py index 3ed7dba966..0676664685 100644 --- a/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py +++ b/tensorflow/python/kernel_tests/dense_update_ops_no_tsan_test.py @@ -43,7 +43,7 @@ class AssignOpTest(test.TestCase): variables.global_variables_initializer().run() def run_add(add_op): - sess.run(add_op) + self.evaluate(add_op) threads = [ self.checkedThread( @@ -70,7 +70,7 @@ class AssignOpTest(test.TestCase): variables.global_variables_initializer().run() def run_assign(assign_op): - sess.run(assign_op) + self.evaluate(assign_op) threads = [ self.checkedThread( @@ -103,7 +103,7 @@ class AssignOpTest(test.TestCase): p.initializer.run() def run_add(add_op): - sess.run(add_op) + self.evaluate(add_op) threads = [ self.checkedThread( @@ -131,7 +131,7 @@ class AssignOpTest(test.TestCase): p.initializer.run() def run_assign(assign_op): - sess.run(assign_op) + self.evaluate(assign_op) threads = [ self.checkedThread( diff --git a/tensorflow/python/kernel_tests/depthtospace_op_test.py b/tensorflow/python/kernel_tests/depthtospace_op_test.py index c4bed11080..19f145865f 100644 --- a/tensorflow/python/kernel_tests/depthtospace_op_test.py +++ b/tensorflow/python/kernel_tests/depthtospace_op_test.py @@ -277,7 +277,7 @@ class DepthToSpaceTest(test.TestCase): actual = array_ops.depth_to_space(t, block_size, data_format=data_format) with self.session(use_gpu=use_gpu) as sess: - actual_vals, expected_vals = sess.run([actual, expected]) + actual_vals, expected_vals = self.evaluate([actual, expected]) self.assertTrue(np.array_equal(actual_vals, expected_vals)) def testAgainstTranspose(self): diff --git a/tensorflow/python/kernel_tests/depthwise_conv_op_test.py b/tensorflow/python/kernel_tests/depthwise_conv_op_test.py index f65d0be367..f6d834c2f8 100644 --- a/tensorflow/python/kernel_tests/depthwise_conv_op_test.py +++ b/tensorflow/python/kernel_tests/depthwise_conv_op_test.py @@ -162,7 +162,7 @@ class DepthwiseConv2DTest(test.TestCase): conv_native = array_ops.transpose(conv_native, [0, 2, 3, 1]) try: - native_result = sess.run(conv_native) + native_result = self.evaluate(conv_native) except errors.InvalidArgumentError as e: # Grouped convolution kernel is only registered for cuDNN 7. Silently # return when we are running on an earlier version or without GPU. @@ -174,7 +174,7 @@ class DepthwiseConv2DTest(test.TestCase): conv_interface = nn_impl.depthwise_conv2d( t1, t2, strides=[1, stride, stride, 1], padding=padding) - interface_result = sess.run(conv_interface) + interface_result = self.evaluate(conv_interface) tf_logging.info( "data_type: %r, use_gpu: %r, grouped_conv: %r, max diff = %f", @@ -269,7 +269,7 @@ class DepthwiseConv2DTest(test.TestCase): t2 = constant_op.constant(x2, shape=filter_in_sizes) conv = nn_ops.depthwise_conv2d_native( t1, t2, strides=[1, stride, stride, 1], padding=padding) - value = sess.run(conv) + value = self.evaluate(conv) tf_logging.info("value = %r", value) self.assertArrayNear(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) diff --git a/tensorflow/python/kernel_tests/determinant_op_test.py b/tensorflow/python/kernel_tests/determinant_op_test.py index 602ceb6ebd..d6ef9e70b8 100644 --- a/tensorflow/python/kernel_tests/determinant_op_test.py +++ b/tensorflow/python/kernel_tests/determinant_op_test.py @@ -156,7 +156,7 @@ class DeterminantOpTest(test.TestCase): matrix2 = random_ops.random_normal([5, 5], seed=42) det1 = linalg_ops.matrix_determinant(matrix1) det2 = linalg_ops.matrix_determinant(matrix2) - det1_val, det2_val = sess.run([det1, det2]) + det1_val, det2_val = self.evaluate([det1, det2]) self.assertEqual(det1_val, det2_val) diff --git a/tensorflow/python/kernel_tests/distributions/categorical_test.py b/tensorflow/python/kernel_tests/distributions/categorical_test.py index f116c54bd1..9c593d2737 100644 --- a/tensorflow/python/kernel_tests/distributions/categorical_test.py +++ b/tensorflow/python/kernel_tests/distributions/categorical_test.py @@ -287,7 +287,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): } with self.cached_session() as sess: - run_result = sess.run(to_run) + run_result = self.evaluate(to_run) self.assertAllEqual(run_result["cat_prob"].shape, run_result["norm_prob"].shape) @@ -462,7 +462,7 @@ class CategoricalTest(test.TestCase, parameterized.TestCase): b = categorical.Categorical(logits=b_logits) kl = kullback_leibler.kl_divergence(a, b) - kl_val = sess.run(kl) + kl_val = self.evaluate(kl) # Make sure KL(a||a) is 0 kl_same = sess.run(kullback_leibler.kl_divergence(a, a)) diff --git a/tensorflow/python/kernel_tests/distributions/special_math_test.py b/tensorflow/python/kernel_tests/distributions/special_math_test.py index 6b6de8b139..0f800b95fa 100644 --- a/tensorflow/python/kernel_tests/distributions/special_math_test.py +++ b/tensorflow/python/kernel_tests/distributions/special_math_test.py @@ -448,7 +448,7 @@ class LogCDFLaplaceTest(test.TestCase): actual = sm.log_cdf_laplace(grid) grad = gradients_impl.gradients(actual, grid)[0] - actual_, grad_ = sess.run([actual, grad]) + actual_, grad_ = self.evaluate([actual, grad]) # isfinite checks for NaN and Inf. self.assertAllTrue(np.isfinite(actual_)) @@ -467,7 +467,7 @@ class LogCDFLaplaceTest(test.TestCase): actual = sm.log_cdf_laplace(grid) grad = gradients_impl.gradients(actual, grid)[0] - actual_, grad_ = sess.run([actual, grad]) + actual_, grad_ = self.evaluate([actual, grad]) # isfinite checks for NaN and Inf. self.assertAllTrue(np.isfinite(actual_)) diff --git a/tensorflow/python/kernel_tests/distributions/util_test.py b/tensorflow/python/kernel_tests/distributions/util_test.py index f4e651b25b..d3fa513f05 100644 --- a/tensorflow/python/kernel_tests/distributions/util_test.py +++ b/tensorflow/python/kernel_tests/distributions/util_test.py @@ -805,7 +805,7 @@ class ReduceWeightedLogSumExp(test.TestCase): w = constant_op.constant(w_) actual, actual_sgn = du.reduce_weighted_logsumexp( logx, w, axis=-1, return_sign=True) - [actual_, actual_sgn_] = sess.run([actual, actual_sgn]) + [actual_, actual_sgn_] = self.evaluate([actual, actual_sgn]) self.assertAllEqual(expected, actual_) self.assertAllEqual([-1., -1, 1], actual_sgn_) @@ -823,7 +823,7 @@ class ReduceWeightedLogSumExp(test.TestCase): w = constant_op.constant(w_) actual, actual_sgn = du.reduce_weighted_logsumexp( logx, w, axis=-1, return_sign=True, keep_dims=True) - [actual_, actual_sgn_] = sess.run([actual, actual_sgn]) + [actual_, actual_sgn_] = self.evaluate([actual, actual_sgn]) self.assertAllEqual(expected, actual_) self.assertAllEqual([[-1.], [-1], [1]], actual_sgn_) diff --git a/tensorflow/python/kernel_tests/division_future_test.py b/tensorflow/python/kernel_tests/division_future_test.py index e477bdc73b..85c85809d3 100644 --- a/tensorflow/python/kernel_tests/division_future_test.py +++ b/tensorflow/python/kernel_tests/division_future_test.py @@ -65,7 +65,7 @@ class DivisionTestCase(test.TestCase): tf_floordiv = tf_x // tf_y check(floordiv, tf_floordiv) # Do only one sess.run for speed - for f, (x, y) in zip(checks, sess.run(tensors)): + for f, (x, y) in zip(checks, self.evaluate(tensors)): f(x, y) diff --git a/tensorflow/python/kernel_tests/division_past_test.py b/tensorflow/python/kernel_tests/division_past_test.py index 63951b5b38..38bb18631a 100644 --- a/tensorflow/python/kernel_tests/division_past_test.py +++ b/tensorflow/python/kernel_tests/division_past_test.py @@ -64,7 +64,7 @@ class DivisionTestCase(test.TestCase): tf_floordiv = tf_x // tf_y check(floordiv, tf_floordiv) # Do only one sess.run for speed - for f, (x, y) in zip(checks, sess.run(tensors)): + for f, (x, y) in zip(checks, self.evaluate(tensors)): f(x, y) diff --git a/tensorflow/python/kernel_tests/draw_bounding_box_op_test.py b/tensorflow/python/kernel_tests/draw_bounding_box_op_test.py index c655876280..6aa757e293 100644 --- a/tensorflow/python/kernel_tests/draw_bounding_box_op_test.py +++ b/tensorflow/python/kernel_tests/draw_bounding_box_op_test.py @@ -87,7 +87,7 @@ class DrawBoundingBoxOpTest(test.TestCase): image = array_ops.expand_dims(image, 0) image = image_ops.draw_bounding_boxes(image, bboxes) with self.cached_session(use_gpu=False) as sess: - op_drawn_image = np.squeeze(sess.run(image), 0) + op_drawn_image = np.squeeze(self.evaluate(image), 0) self.assertAllEqual(test_drawn_image, op_drawn_image) def testDrawBoundingBoxRGBColorCycling(self): diff --git a/tensorflow/python/kernel_tests/dynamic_partition_op_test.py b/tensorflow/python/kernel_tests/dynamic_partition_op_test.py index 07da855a01..3622fde3f3 100644 --- a/tensorflow/python/kernel_tests/dynamic_partition_op_test.py +++ b/tensorflow/python/kernel_tests/dynamic_partition_op_test.py @@ -40,7 +40,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant([0, 0, 2, 3, 2, 1]) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual([0, 13], partition_vals[0]) @@ -62,7 +62,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant([0, 0, 2, 3, 2, 1]) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual([[0, 1, 2], [3, 4, 5]], partition_vals[0]) @@ -87,7 +87,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual(part1, partition_vals[0]) @@ -109,7 +109,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=num_partitions) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(num_partitions, len(partition_vals)) for i in range(num_partitions): @@ -125,7 +125,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual([3 + 4j, 7 + 8j], partition_vals[0]) @@ -138,7 +138,7 @@ class DynamicPartitionTest(test.TestCase): indices = 3 partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual(np.array([], dtype=np.float64).reshape(-1, 4), @@ -164,7 +164,7 @@ class DynamicPartitionTest(test.TestCase): outputs = data_flow_ops.dynamic_partition( data_t, partitions_t, num_partitions=n) self.assertEqual(n, len(outputs)) - outputs_val = sess.run(outputs) + outputs_val = self.evaluate(outputs) for i, output in enumerate(outputs_val): self.assertAllEqual(output, data[partitions == i]) @@ -183,7 +183,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(4, len(partition_vals)) self.assertAllEqual([], partition_vals[0]) @@ -199,7 +199,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=3) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(3, len(partition_vals)) self.assertAllEqual([[]], partition_vals[0]) @@ -215,7 +215,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual([], partition_vals[0]) @@ -236,7 +236,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=2) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(2, len(partition_vals)) self.assertAllEqual([6], partition_vals[0]) @@ -257,7 +257,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=5) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(5, len(partition_vals)) self.assertAllEqual([5], partition_vals[0]) @@ -281,7 +281,7 @@ class DynamicPartitionTest(test.TestCase): indices = constant_op.constant(indices_list, dtype=dtypes.int32) partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=40) - partition_vals = sess.run(partitions) + partition_vals = self.evaluate(partitions) self.assertEqual(40, len(partition_vals)) for i in range(40): @@ -295,7 +295,7 @@ class DynamicPartitionTest(test.TestCase): partitions = data_flow_ops.dynamic_partition( data, indices, num_partitions=4) with self.assertRaisesOpError(r"partitions\[2\] = 99 is not in \[0, 4\)"): - sess.run(partitions) + self.evaluate(partitions) def testScalarIndexOutOfRange(self): with self.cached_session() as sess: @@ -303,7 +303,7 @@ class DynamicPartitionTest(test.TestCase): data = np.zeros(5) partitions = data_flow_ops.dynamic_partition(data, bad, num_partitions=7) with self.assertRaisesOpError(r"partitions = 17 is not in \[0, 7\)"): - sess.run(partitions) + self.evaluate(partitions) def testHigherRankIndexOutOfRange(self): with self.cached_session() as sess: @@ -335,7 +335,7 @@ class DynamicPartitionTest(test.TestCase): self.assertEqual(len(inds), x.shape[0]) partitioned = data_flow_ops.dynamic_partition(x, inds, 16) with self.cached_session() as sess: - res = sess.run(partitioned) + res = self.evaluate(partitioned) self.assertEqual(res[-1].shape[0], 192) diff --git a/tensorflow/python/kernel_tests/embedding_ops_test.py b/tensorflow/python/kernel_tests/embedding_ops_test.py index dba3409c9e..39c0575cd5 100644 --- a/tensorflow/python/kernel_tests/embedding_ops_test.py +++ b/tensorflow/python/kernel_tests/embedding_ops_test.py @@ -294,7 +294,7 @@ class EmbeddingLookupTest(test.TestCase): variables.global_variables_initializer().run() params_values = [params[p_i.name] for p_i in p] # Test that the PartitionedVariable components equal the list in p - p_var_val = sess.run(list(p_variable)) + p_var_val = self.evaluate(list(p_variable)) # Actual test tf_result = embedding.eval(feed_dict=feed_dict) np_result, _, _ = _EmbeddingResult(params, id_vals, num_shards, vocab_size) @@ -316,7 +316,7 @@ class EmbeddingLookupTest(test.TestCase): variables.global_variables_initializer().run() params_values = [params[p_i.name] for p_i in p] # Test that the PartitionedVariable components equal the list in p - p_var_val = sess.run(list(p_variable)) + p_var_val = self.evaluate(list(p_variable)) # Actual test print(ops.get_default_graph().as_graph_def()) tf_result = self.evaluate(embedding) diff --git a/tensorflow/python/kernel_tests/fifo_queue_test.py b/tensorflow/python/kernel_tests/fifo_queue_test.py index e3742f2e72..9655351a01 100644 --- a/tensorflow/python/kernel_tests/fifo_queue_test.py +++ b/tensorflow/python/kernel_tests/fifo_queue_test.py @@ -159,7 +159,7 @@ class FIFOQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) threads = [ self.checkedThread( @@ -191,7 +191,7 @@ class FIFOQueueTest(test.TestCase): results = [] def dequeue(): - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in enqueue_ops] for thread in threads: @@ -240,13 +240,13 @@ class FIFOQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) for enqueue_op in enqueue_ops: - sess.run(enqueue_op) + self.evaluate(enqueue_op) results = [] def dequeue(): for _ in xrange(len(elems)): - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -269,7 +269,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() for i in xrange(len(elems)): - x_val, y_val = sess.run(dequeued_t) + x_val, y_val = self.evaluate(dequeued_t) x, y = elems[i] self.assertEqual([x], x_val) self.assertEqual([y], y_val) @@ -356,7 +356,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() for i in range(8): - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertEqual(float_elems[i % 4], float_val) self.assertAllEqual(int_elems[i % 4], int_val) @@ -399,17 +399,17 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertEqual(float_val.shape, dequeued_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_t[1].get_shape()) - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) self.assertAllEqual(float_elems[8], float_val) self.assertAllEqual(int_elems[8], int_val) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) @@ -429,13 +429,13 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertEqual([None], dequeued_t[0].get_shape().as_list()) self.assertEqual([None, 2], dequeued_t[1].get_shape().as_list()) - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) @@ -529,7 +529,7 @@ class FIFOQueueTest(test.TestCase): # Enqueue 100 items in parallel on 10 threads. def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) threads = [self.checkedThread(target=enqueue) for _ in range(10)] for thread in threads: @@ -552,7 +552,7 @@ class FIFOQueueTest(test.TestCase): dequeued_elems = [] def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t)) + dequeued_elems.extend(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in range(10)] for thread in threads: @@ -576,7 +576,7 @@ class FIFOQueueTest(test.TestCase): dequeued_elems = [] def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t)) + dequeued_elems.extend(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in range(10)] for thread in threads: @@ -596,11 +596,11 @@ class FIFOQueueTest(test.TestCase): def enqueue(): for _ in xrange(100): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): for _ in xrange(100): - self.assertTrue(sess.run(dequeued_t) in (10.0, 20.0)) + self.assertTrue(self.evaluate(dequeued_t) in (10.0, 20.0)) enqueue_threads = [self.checkedThread(target=enqueue) for _ in range(10)] dequeue_threads = [self.checkedThread(target=dequeue) for _ in range(10)] @@ -632,7 +632,7 @@ class FIFOQueueTest(test.TestCase): def dequeue(): for i in xrange(250): - self.assertEqual(i, sess.run(dequeued_t)) + self.assertEqual(i, self.evaluate(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -663,7 +663,7 @@ class FIFOQueueTest(test.TestCase): dequeuemany_t = q.dequeue_many(count_placeholder) def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -701,10 +701,10 @@ class FIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t).tolist()) + dequeued_elems.extend(self.evaluate(dequeued_t).tolist()) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -728,10 +728,10 @@ class FIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t).tolist()) + dequeued_elems.extend(self.evaluate(dequeued_t).tolist()) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -797,11 +797,11 @@ class FIFOQueueTest(test.TestCase): def dequeue(): for elem in elems: - self.assertEqual([elem], sess.run(dequeued_t)) + self.assertEqual([elem], self.evaluate(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -821,7 +821,7 @@ class FIFOQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -842,11 +842,11 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems, sess.run(dequeued_t)) + self.assertAllEqual(elems, self.evaluate(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -867,11 +867,11 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], sess.run(dequeued_t)) + self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -892,8 +892,8 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], sess.run(dequeued_t)) - self.assertAllEqual(elems[3:], sess.run(dequeued_t)) + self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[3:], self.evaluate(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -913,16 +913,16 @@ class FIFOQueueTest(test.TestCase): cleanup_dequeue_t = q.dequeue() def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - self.assertAllEqual(elems[0:3], sess.run(dequeued_t)) + self.assertAllEqual(elems[0:3], self.evaluate(dequeued_t)) with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(dequeued_t) - self.assertEqual(elems[3], sess.run(cleanup_dequeue_t)) + self.evaluate(dequeued_t) + self.assertEqual(elems[3], self.evaluate(cleanup_dequeue_t)) def close(): - sess.run(close_op) + self.evaluate(close_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -955,7 +955,7 @@ class FIFOQueueTest(test.TestCase): def dequeue(): with self.assertRaises(errors_impl.OutOfRangeError): - sess.run([dequeued_a_t, dequeued_b_t]) + self.evaluate([dequeued_a_t, dequeued_b_t]) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -968,7 +968,7 @@ class FIFOQueueTest(test.TestCase): # Test that the elements in the partially-dequeued batch are # restored in the correct order. for elem_a, elem_b in zip(elems_a, elems_b): - val_a, val_b = sess.run([cleanup_dequeue_a_t, cleanup_dequeue_b_t]) + val_a, val_b = self.evaluate([cleanup_dequeue_a_t, cleanup_dequeue_b_t]) self.assertEqual(elem_a, val_a) self.assertEqual(elem_b, val_b) self.assertEqual(0, q.size().eval()) @@ -983,7 +983,7 @@ class FIFOQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -1003,7 +1003,7 @@ class FIFOQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -1051,7 +1051,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1074,7 +1074,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1103,7 +1103,7 @@ class FIFOQueueTest(test.TestCase): def blocking_enqueue(): # Expect the operation to succeed once the dequeue op runs. - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1113,7 +1113,7 @@ class FIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - sess.run(close_op) + self.evaluate(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1138,7 +1138,7 @@ class FIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1148,7 +1148,7 @@ class FIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - sess.run(close_op) + self.evaluate(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1266,19 +1266,19 @@ class FIFOQueueTest(test.TestCase): def _blockingDequeue(self, sess, dequeue_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_op) + self.evaluate(dequeue_op) def _blockingDequeueMany(self, sess, dequeue_many_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_many_op) + self.evaluate(dequeue_many_op) def _blockingEnqueue(self, sess, enqueue_op): with self.assertRaisesOpError("was cancelled"): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def _blockingEnqueueMany(self, sess, enqueue_many_op): with self.assertRaisesOpError("was cancelled"): - sess.run(enqueue_many_op) + self.evaluate(enqueue_many_op) def testResetOfBlockingOperation(self): with self.cached_session() as sess: @@ -1321,7 +1321,7 @@ class FIFOQueueTest(test.TestCase): def blocking_enqueue(): enq_done.append(False) # This will fill the queue and then block until enough dequeues happen. - sess.run(enq) + self.evaluate(enq) enq_done.append(True) thread = self.checkedThread(target=blocking_enqueue) @@ -1331,14 +1331,14 @@ class FIFOQueueTest(test.TestCase): results = [] results.append(deq.eval()) # Will only complete after the enqueue starts. self.assertEqual(len(enq_done), 1) - self.assertEqual(sess.run(size_op), 5) + self.assertEqual(self.evaluate(size_op), 5) for _ in range(3): results.append(deq.eval()) time.sleep(0.1) self.assertEqual(len(enq_done), 1) - self.assertEqual(sess.run(size_op), 5) + self.assertEqual(self.evaluate(size_op), 5) # This dequeue will unblock the thread. results.append(deq.eval()) @@ -1364,7 +1364,7 @@ class FIFOQueueTest(test.TestCase): def blocking_dequeue(): # Will only complete after 4 enqueues complete. - results.extend(sess.run(deq)) + results.extend(self.evaluate(deq)) thread = self.checkedThread(target=blocking_dequeue) thread.start() @@ -1373,7 +1373,7 @@ class FIFOQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) self.assertEqual(len(results), 0) - sess.run(enq) + self.evaluate(enq) # Enough enqueued to unblock the dequeue thread.join() @@ -1405,7 +1405,7 @@ class FIFOQueueTest(test.TestCase): q.enqueue_many(input_tuple).run() output_tuple_t = q.dequeue_many(32) - output_tuple = sess.run(output_tuple_t) + output_tuple = self.evaluate(output_tuple_t) for (input_elem, output_elem) in zip(input_tuple, output_tuple): self.assertAllEqual(input_elem, output_elem) @@ -1507,10 +1507,10 @@ class FIFOQueueDictTest(test.TestCase): enqueue_op4 = q.enqueue_many({"f": [40.0, 50.0]}) dequeue = q.dequeue() dequeue_2 = q.dequeue_many(2) - sess.run(enqueue_op) - sess.run(enqueue_op2) - sess.run(enqueue_op3) - sess.run(enqueue_op4) + self.evaluate(enqueue_op) + self.evaluate(enqueue_op2) + self.evaluate(enqueue_op3) + self.evaluate(enqueue_op4) f = sess.run(dequeue["f"]) self.assertEqual(10.0, f) f = sess.run(dequeue_2["f"]) @@ -1565,10 +1565,10 @@ class FIFOQueueDictTest(test.TestCase): }) dequeue = q.dequeue() dequeue_2 = q.dequeue_many(2) - sess.run(enqueue_op) - sess.run(enqueue_op2) - sess.run(enqueue_op3) - sess.run(enqueue_op4) + self.evaluate(enqueue_op) + self.evaluate(enqueue_op2) + self.evaluate(enqueue_op3) + self.evaluate(enqueue_op4) i, f, s = sess.run([dequeue["i"], dequeue["f"], dequeue["s"]]) self.assertEqual(123, i) self.assertEqual(10.0, f) @@ -1597,7 +1597,7 @@ class FIFOQueueWithTimeoutTest(test.TestCase): # until operation_timeout_in_ms. with self.assertRaisesRegexp(errors_impl.DeadlineExceededError, "Timed out waiting for notification"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) def testReusableAfterTimeout(self): with self.cached_session() as sess: @@ -1613,8 +1613,8 @@ class FIFOQueueWithTimeoutTest(test.TestCase): "Timed out waiting for notification"): sess.run(dequeued_t, options=config_pb2.RunOptions(timeout_in_ms=10)) - sess.run(enqueue_op) - self.assertEqual(37, sess.run(dequeued_t)) + self.evaluate(enqueue_op) + self.assertEqual(37, self.evaluate(dequeued_t)) class QueueContainerTest(test.TestCase): diff --git a/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py b/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py index cb7659a89a..272adecfb8 100644 --- a/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py +++ b/tensorflow/python/kernel_tests/fractional_avg_pool_op_test.py @@ -133,7 +133,7 @@ class FractionalAvgTest(test.TestCase): pseudo_random, overlapping, seed=self._SEED) - actual, row_seq, col_seq = sess.run([p, r, c]) + actual, row_seq, col_seq = self.evaluate([p, r, c]) expected = self._GetExpectedFractionalAvgPoolResult(input_tensor, row_seq, col_seq, overlapping) self.assertShapeEqual(expected, p) @@ -164,7 +164,7 @@ class FractionalAvgTest(test.TestCase): pseudo_random, overlapping, seed=self._SEED) - tensor_output, row_seq, col_seq = sess.run([p, r, c]) + tensor_output, row_seq, col_seq = self.evaluate([p, r, c]) expected_result = self._GetExpectedFractionalAvgPoolResult( rand_mat.astype(np.float32), row_seq, col_seq, overlapping) print("row sequence:") diff --git a/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py b/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py index 0427e34fc1..9b1e73b318 100644 --- a/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py +++ b/tensorflow/python/kernel_tests/fractional_max_pool_op_test.py @@ -133,7 +133,7 @@ class FractionalMaxPoolTest(test.TestCase): pseudo_random, overlapping, seed=self._SEED) - actual, row_seq, col_seq = sess.run([p, r, c]) + actual, row_seq, col_seq = self.evaluate([p, r, c]) expected = self._GetExpectedFractionalMaxPoolResult(input_tensor, row_seq, col_seq, overlapping) self.assertShapeEqual(expected, p) @@ -164,7 +164,7 @@ class FractionalMaxPoolTest(test.TestCase): pseudo_random, overlapping, seed=self._SEED) - tensor_output, row_seq, col_seq = sess.run([p, r, c]) + tensor_output, row_seq, col_seq = self.evaluate([p, r, c]) expected_result = self._GetExpectedFractionalMaxPoolResult(rand_mat, row_seq, col_seq, diff --git a/tensorflow/python/kernel_tests/functional_ops_test.py b/tensorflow/python/kernel_tests/functional_ops_test.py index 503569f3b1..23b3c7e1cc 100644 --- a/tensorflow/python/kernel_tests/functional_ops_test.py +++ b/tensorflow/python/kernel_tests/functional_ops_test.py @@ -458,7 +458,7 @@ class FunctionalOpsTest(test.TestCase): grad = gradients_impl.gradients(ys=[loss], xs=[a, b]) with self.test_session(use_gpu=True) as sess: variables.global_variables_initializer().run() - sess.run(grad) + self.evaluate(grad) @test_util.run_in_graph_and_eager_modes def testFoldShape(self): @@ -567,8 +567,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:worker/replica:0/task:0/cpu:1") with session.Session(worker[0].target) as sess: - sess.run(variables.global_variables_initializer()) - mul = sess.run(remote_op) + self.evaluate(variables.global_variables_initializer()) + mul = self.evaluate(remote_op) self.assertEqual(mul, [6]) def testRemoteFunctionDirectSession(self): @@ -591,8 +591,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:localhost/replica:0/task:0/cpu:1") with self.test_session(config=worker_config) as sess: - sess.run(variables.global_variables_initializer()) - mul = sess.run(remote_op) + self.evaluate(variables.global_variables_initializer()) + mul = self.evaluate(remote_op) self.assertEqual(mul, [6]) def testRemoteFunctionSameDeviceDirectSession(self): @@ -610,8 +610,8 @@ class FunctionalOpsTest(test.TestCase): args=[a, b], Tout=[dtypes.int32], f=_remote_fn, target="/cpu:0") with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - mul = sess.run(remote_op) + self.evaluate(variables.global_variables_initializer()) + mul = self.evaluate(remote_op) self.assertEqual(mul, [6]) def testRemoteFunctionCPUGPU(self): @@ -634,8 +634,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:localhost/replica:0/task:0/device:GPU:0")[0] + 3.0 with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - mul = sess.run(remote_op) + self.evaluate(variables.global_variables_initializer()) + mul = self.evaluate(remote_op) self.assertEqual(mul, 9.0) def testRemoteFunctionGPUCPU(self): @@ -658,8 +658,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:localhost/replica:0/task:0/cpu:0")[0] + 3.0 with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - mul = sess.run(remote_op) + self.evaluate(variables.global_variables_initializer()) + mul = self.evaluate(remote_op) self.assertEqual(mul, 9.0) def testRemoteFunctionGPUCPUStrings(self): @@ -677,7 +677,7 @@ class FunctionalOpsTest(test.TestCase): args=[a], Tout=[dtypes.string], f=_remote_fn, target="/cpu:0") with self.cached_session() as sess: - ret = sess.run(remote_op) + ret = self.evaluate(remote_op) self.assertAllEqual(ret, [b"a"]) def testRemoteFunctionCrossProcess(self): @@ -699,8 +699,8 @@ class FunctionalOpsTest(test.TestCase): target="/job:worker/replica:0/task:1/cpu:0")[0] + 3.0 with session.Session(workers[0].target) as sess: - sess.run(variables.global_variables_initializer()) - mul = sess.run(remote_op) + self.evaluate(variables.global_variables_initializer()) + mul = self.evaluate(remote_op) self.assertEqual(mul, 9) def testIf(self): @@ -769,7 +769,7 @@ class FunctionalOpsTest(test.TestCase): else: fetch = "my_while:1" with self.session(graph=g, use_gpu=use_gpu) as sess: - return sess.run(fetch) + return self.evaluate(fetch) self.assertAllEqual(Run(20., False), 210.) self.assertAllEqual(Run(20., True), 210.) @@ -857,11 +857,11 @@ class FunctionalOpsTest(test.TestCase): result_binary = functional_ops.While( [1.0, 0., 0.], function.Defun(*[dtypes.float32] * 3)(TestCond), TestBinary) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) assert len(result_unary) == 2 - self.assertEqual([10.0, 54.0], sess.run(result_unary)) + self.assertEqual([10.0, 54.0], self.evaluate(result_unary)) assert len(result_binary) == 3 - self.assertEqual([10.0, 54.0, 9.0], sess.run(result_binary)) + self.assertEqual([10.0, 54.0, 9.0], self.evaluate(result_binary)) def TestCondCapture(n, *args): del args @@ -892,7 +892,7 @@ class FunctionalOpsTest(test.TestCase): 100, 0, -1, [0.], Body, rewrite_with_while=rewrite_with_while) [0], ] - xvals = sess.run(xs) + xvals = self.evaluate(xs) self.assertAllEqual(210, xvals[0]) self.assertAllEqual(5050, xvals[1]) @@ -949,16 +949,16 @@ class FunctionalOpsTest(test.TestCase): result_binary = functional_ops.For( 1, 10, 1, [0., 0.], TestBinary, rewrite_with_while=rewrite_with_while) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) assert not result_nullary # The nullary variant doesn't return anything so we can't easily run it. # As a total hack, fetch the operation by name and run it. sess.run(ops.get_default_graph().get_operation_by_name( "While" if rewrite_with_while else "For")) assert len(result_unary) == 1 - self.assertEqual([54.0], sess.run(result_unary)) + self.assertEqual([54.0], self.evaluate(result_unary)) assert len(result_binary) == 2 - self.assertEqual([54.0, 9.0], sess.run(result_binary)) + self.assertEqual([54.0, 9.0], self.evaluate(result_binary)) def _tfMLP(self, xval, wsval, bsval, rewrite_with_while): # On GPU, don't rewrite using a while loop. @@ -1041,8 +1041,8 @@ class FunctionalOpsTest(test.TestCase): avals = [Poly(a), Grad(a)] b = constant_op.constant(1.) bvals = [Poly(b), Grad(b)] - self.assertAllEqual(sess.run(avals), [8., 4.]) - self.assertAllEqual(sess.run(bvals), [17., 16.]) + self.assertAllEqual(self.evaluate(avals), [8., 4.]) + self.assertAllEqual(self.evaluate(bvals), [17., 16.]) # TODO(akshayka): Replace `function.Defun` with tf.contrib.eager.defun` in the @@ -1193,8 +1193,8 @@ class PartitionedCallTest(test.TestCase): allow_soft_placement=False, log_device_placement=True, device_count={"CPU": 2})) as sess: - sess.run(variables.global_variables_initializer()) - expected = sess.run(sum_gather()) + self.evaluate(variables.global_variables_initializer()) + expected = self.evaluate(sum_gather()) result = sess.run( functional_ops.partitioned_call( args=defined.captured_inputs, f=defined)) diff --git a/tensorflow/python/kernel_tests/gradient_correctness_test.py b/tensorflow/python/kernel_tests/gradient_correctness_test.py index 291a69ebac..12b8a4c8e3 100644 --- a/tensorflow/python/kernel_tests/gradient_correctness_test.py +++ b/tensorflow/python/kernel_tests/gradient_correctness_test.py @@ -35,7 +35,7 @@ class GradientCorrectnessTest(test.TestCase): yexp = math_ops.exp(x) yexplog = math_ops.log(yexp) grads = gradients_impl.gradients([yexp, yexplog], [x]) - grad_vals = sess.run(grads) + grad_vals = self.evaluate(grads) exp1_plus_one = (1.0 + np.exp(1.0)).astype(np.float32) # [dexp(x)/dx + d(log(exp(x)))/dx] @ x=1 == exp(1) + 1 self.assertAllClose(grad_vals[0], exp1_plus_one) @@ -44,13 +44,13 @@ class GradientCorrectnessTest(test.TestCase): x = constant_op.constant(3.) dx_dx, = gradients_impl.gradients(x, x) with self.cached_session() as sess: - self.assertAllClose(1., sess.run(dx_dx)) + self.assertAllClose(1., self.evaluate(dx_dx)) def testIntegerIdentityGradient(self): x = constant_op.constant(3) dx_dx, = gradients_impl.gradients(x, x) with self.cached_session() as sess: - self.assertAllClose(1, sess.run(dx_dx)) + self.assertAllClose(1, self.evaluate(dx_dx)) def testGradientWithIntegerPath(self): x = constant_op.constant([3.9, 4.1]) @@ -58,7 +58,7 @@ class GradientCorrectnessTest(test.TestCase): y = x * k dy_dx, = gradients_impl.gradients(y, x) with self.cached_session() as sess: - self.assertAllClose([3., 4.], sess.run(dy_dx)) + self.assertAllClose([3., 4.], self.evaluate(dy_dx)) def testNoIntegerGradient1(self): x = constant_op.constant([3.9, 4.1]) diff --git a/tensorflow/python/kernel_tests/init_ops_test.py b/tensorflow/python/kernel_tests/init_ops_test.py index a3f2c0ddd7..87c7bbef3c 100644 --- a/tensorflow/python/kernel_tests/init_ops_test.py +++ b/tensorflow/python/kernel_tests/init_ops_test.py @@ -704,12 +704,12 @@ class ConvolutionDeltaOrthogonalInitializerTest(test.TestCase): ratio = outputs_2norm / inputs_2norm my_ops = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(my_ops) + self.evaluate(my_ops) # Check the shape of the outputs t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the delta-orthogonal kernel. - self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) def testNonuniformity(self): value = 0 @@ -842,12 +842,12 @@ class ConvolutionOrthogonal1dInitializerTest(test.TestCase): ratio = outputs_2norm / inputs_2norm my_ops = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(my_ops) + self.evaluate(my_ops) # Check the shape of the outputs t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the orthogonal kernel. - self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) class ConvolutionOrthogonal2dInitializerTest(test.TestCase): @@ -937,12 +937,12 @@ class ConvolutionOrthogonal2dInitializerTest(test.TestCase): ratio = outputs_2norm / inputs_2norm my_ops = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(my_ops) + self.evaluate(my_ops) # Check the shape of the outputs t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the orthogonal kernel. - self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) class ConvolutionOrthogonal3dInitializerTest(test.TestCase): @@ -1062,12 +1062,12 @@ class ConvolutionOrthogonal3dInitializerTest(test.TestCase): ratio = outputs_2norm / inputs_2norm my_ops = variables.global_variables_initializer() with self.cached_session(use_gpu=True) as sess: - sess.run(my_ops) + self.evaluate(my_ops) # Check the shape of the outputs t = self.evaluate(outputs) self.assertAllEqual(t.shape, outputs_shape) # Check isometry of the orthogonal kernel. - self.assertAllClose(sess.run(ratio), gain, rtol=tol, atol=tol) + self.assertAllClose(self.evaluate(ratio), gain, rtol=tol, atol=tol) class IdentityInitializerTest(test.TestCase): diff --git a/tensorflow/python/kernel_tests/inplace_ops_test.py b/tensorflow/python/kernel_tests/inplace_ops_test.py index 51d16861dd..e0c36d3d2e 100644 --- a/tensorflow/python/kernel_tests/inplace_ops_test.py +++ b/tensorflow/python/kernel_tests/inplace_ops_test.py @@ -149,7 +149,7 @@ class InplaceOpsTest(test_util.TensorFlowTestCase): y = inplace_ops.alias_inplace_add(x, [0], [[1, 2, 3]]) with ops.control_dependencies([y]): z = array_ops.identity(x) - _, vy, vz = sess.run([x, y, z]) + _, vy, vz = self.evaluate([x, y, z]) self.assertAllClose(vy, vz) def testError(self): diff --git a/tensorflow/python/kernel_tests/io_ops_test.py b/tensorflow/python/kernel_tests/io_ops_test.py index afa24195cb..a6b477062e 100644 --- a/tensorflow/python/kernel_tests/io_ops_test.py +++ b/tensorflow/python/kernel_tests/io_ops_test.py @@ -53,7 +53,7 @@ class IoOpsTest(test.TestCase): pass with self.cached_session() as sess: w = io_ops.write_file(temp.name, contents) - sess.run(w) + self.evaluate(w) with open(temp.name, 'rb') as f: file_contents = f.read() self.assertEqual(file_contents, contents) @@ -67,7 +67,7 @@ class IoOpsTest(test.TestCase): filepath = os.path.join(subdir, 'subdir2', 'filename') with self.cached_session() as sess: w = io_ops.write_file(filepath, contents) - sess.run(w) + self.evaluate(w) with open(filepath, 'rb') as f: file_contents = f.read() self.assertEqual(file_contents, contents) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py index d5580d0e88..09867435a7 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_circulant_test.py @@ -557,7 +557,7 @@ class LinearOperatorCirculant2DTestNonHermitianSpectrum( self.assertEqual(matrix_tensor.dtype, linear_operator_circulant._DTYPE_COMPLEX) matrix_h = linalg.adjoint(matrix_tensor) - matrix, matrix_h = sess.run([matrix_tensor, matrix_h]) + matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllClose(matrix, matrix_h, atol=0) def test_assert_non_singular_fails_for_singular_operator(self): @@ -631,7 +631,7 @@ class LinearOperatorCirculant3DTest(test.TestCase): linear_operator_circulant._DTYPE_COMPLEX) matrix_h = linalg.adjoint(matrix_tensor) - matrix, matrix_h = sess.run([matrix_tensor, matrix_h]) + matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) self.assertAllClose(matrix, matrix_h) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py index 91f4097438..80889a162f 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_diag_test.py @@ -147,12 +147,12 @@ class LinearOperatorDiagTest( operator_matmul = operator.matmul(x) mat_matmul = math_ops.matmul(mat, x) self.assertAllEqual(operator_matmul.get_shape(), mat_matmul.get_shape()) - self.assertAllClose(*sess.run([operator_matmul, mat_matmul])) + self.assertAllClose(*self.evaluate([operator_matmul, mat_matmul])) operator_solve = operator.solve(x) mat_solve = linalg_ops.matrix_solve(mat, x) self.assertAllEqual(operator_solve.get_shape(), mat_solve.get_shape()) - self.assertAllClose(*sess.run([operator_solve, mat_solve])) + self.assertAllClose(*self.evaluate([operator_solve, mat_solve])) def test_diag_matmul(self): operator1 = linalg_lib.LinearOperatorDiag([2., 3.]) diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py index 522213e26b..e9fd91c6cf 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_identity_test.py @@ -170,7 +170,7 @@ class LinearOperatorIdentityTest( expected = x self.assertAllEqual(operator_matmul.get_shape(), expected.get_shape()) - self.assertAllClose(*sess.run([operator_matmul, expected])) + self.assertAllClose(*self.evaluate([operator_matmul, expected])) def test_default_batch_shape_broadcasts_with_everything_dynamic(self): # These cannot be done in the automated (base test class) tests since they @@ -207,7 +207,7 @@ class LinearOperatorIdentityTest( operator_matmul = operator.matmul(x) self.assertAllEqual(operator_matmul.get_shape(), expected.get_shape()) - self.assertAllClose(*sess.run([operator_matmul, expected])) + self.assertAllClose(*self.evaluate([operator_matmul, expected])) def test_broadcast_matmul_dynamic_shapes(self): # These cannot be done in the automated (base test class) tests since they @@ -403,13 +403,13 @@ class LinearOperatorScaledIdentityTest( expected = x * 2.2 + zeros operator_matmul = operator.matmul(x) self.assertAllEqual(operator_matmul.get_shape(), expected.get_shape()) - self.assertAllClose(*sess.run([operator_matmul, expected])) + self.assertAllClose(*self.evaluate([operator_matmul, expected])) # Test solve expected = x / 2.2 + zeros operator_solve = operator.solve(x) self.assertAllEqual(operator_solve.get_shape(), expected.get_shape()) - self.assertAllClose(*sess.run([operator_solve, expected])) + self.assertAllClose(*self.evaluate([operator_solve, expected])) def test_broadcast_matmul_and_solve_scalar_scale_multiplier(self): # These cannot be done in the automated (base test class) tests since they @@ -429,13 +429,13 @@ class LinearOperatorScaledIdentityTest( expected = x * 2.2 operator_matmul = operator.matmul(x) self.assertAllEqual(operator_matmul.get_shape(), expected.get_shape()) - self.assertAllClose(*sess.run([operator_matmul, expected])) + self.assertAllClose(*self.evaluate([operator_matmul, expected])) # Test solve expected = x / 2.2 operator_solve = operator.solve(x) self.assertAllEqual(operator_solve.get_shape(), expected.get_shape()) - self.assertAllClose(*sess.run([operator_solve, expected])) + self.assertAllClose(*self.evaluate([operator_solve, expected])) def test_is_x_flags(self): operator = linalg_lib.LinearOperatorScaledIdentity( diff --git a/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py b/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py index 5ce2616972..f12714677e 100644 --- a/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py +++ b/tensorflow/python/kernel_tests/linalg/linear_operator_util_test.py @@ -119,7 +119,7 @@ class BroadcastMatrixBatchDimsTest(test.TestCase): with self.cached_session() as sess: self.assertAllEqual(x_bc_expected.shape, x_bc.get_shape()) self.assertAllEqual(y_bc_expected.shape, y_bc.get_shape()) - x_bc_, y_bc_ = sess.run([x_bc, y_bc]) + x_bc_, y_bc_ = self.evaluate([x_bc, y_bc]) self.assertAllClose(x_bc_expected, x_bc_) self.assertAllClose(y_bc_expected, y_bc_) @@ -138,7 +138,7 @@ class BroadcastMatrixBatchDimsTest(test.TestCase): with self.cached_session() as sess: self.assertAllEqual(x_bc_expected.shape, x_bc.get_shape()) self.assertAllEqual(y_bc_expected.shape, y_bc.get_shape()) - x_bc_, y_bc_ = sess.run([x_bc, y_bc]) + x_bc_, y_bc_ = self.evaluate([x_bc, y_bc]) self.assertAllClose(x_bc_expected, x_bc_) self.assertAllClose(y_bc_expected, y_bc_) diff --git a/tensorflow/python/kernel_tests/list_ops_test.py b/tensorflow/python/kernel_tests/list_ops_test.py index 09cb5cf0ba..1d9f4032d1 100644 --- a/tensorflow/python/kernel_tests/list_ops_test.py +++ b/tensorflow/python/kernel_tests/list_ops_test.py @@ -806,7 +806,7 @@ class ListOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): l_read2 = list_ops.tensor_list_get_item(l, 0, element_dtype=dtypes.float32) grad = gradients_impl.gradients([l_read1, l_read2], [x]) with self.cached_session() as sess: - self.assertSequenceEqual(sess.run(grad), [2.]) + self.assertSequenceEqual(self.evaluate(grad), [2.]) def testSkipEagerBuildElementShape(self): fn = list_ops._build_element_shape diff --git a/tensorflow/python/kernel_tests/listdiff_op_test.py b/tensorflow/python/kernel_tests/listdiff_op_test.py index baeb40dd63..2865710798 100644 --- a/tensorflow/python/kernel_tests/listdiff_op_test.py +++ b/tensorflow/python/kernel_tests/listdiff_op_test.py @@ -47,7 +47,7 @@ class ListDiffTest(test.TestCase): y_tensor = ops.convert_to_tensor(y, dtype=dtype) out_tensor, idx_tensor = diff_func(x_tensor, y_tensor, index_dtype=index_dtype) - tf_out, tf_idx = sess.run([out_tensor, idx_tensor]) + tf_out, tf_idx = self.evaluate([out_tensor, idx_tensor]) self.assertAllEqual(tf_out, out) self.assertAllEqual(tf_idx, idx) self.assertEqual(1, out_tensor.get_shape().ndims) diff --git a/tensorflow/python/kernel_tests/lookup_ops_test.py b/tensorflow/python/kernel_tests/lookup_ops_test.py index 3efad4ea11..79961d8dd1 100644 --- a/tensorflow/python/kernel_tests/lookup_ops_test.py +++ b/tensorflow/python/kernel_tests/lookup_ops_test.py @@ -137,7 +137,7 @@ class HashTableOpTest(test.TestCase): output2 = table2.lookup(input_string) output3 = table3.lookup(input_string) - out1, out2, out3 = sess.run([output1, output2, output3]) + out1, out2, out3 = self.evaluate([output1, output2, output3]) self.assertAllEqual([0, 1, -1], out1) self.assertAllEqual([0, 1, -1], out2) self.assertAllEqual([0, 1, -1], out3) @@ -174,7 +174,7 @@ class HashTableOpTest(test.TestCase): constant_op.constant(sp_shape, dtypes.int64)) output = table.lookup(input_tensor) - out_indices, out_values, out_shape = sess.run(output) + out_indices, out_values, out_shape = self.evaluate(output) self.assertAllEqual([0, 1, -1], out_values) self.assertAllEqual(sp_indices, out_indices) @@ -995,7 +995,7 @@ class InitializeTableFromFileOpTest(test.TestCase): output2 = table2.lookup(input_string) output3 = table3.lookup(input_string) - out1, out2, out3 = sess.run([output1, output2, output3]) + out1, out2, out3 = self.evaluate([output1, output2, output3]) self.assertAllEqual([0, 1, -1], out1) self.assertAllEqual([0, 1, -1], out2) self.assertAllEqual([0, 1, -1], out3) @@ -1313,7 +1313,7 @@ class IdTableWithHashBucketsTest(test.TestCase): out1 = table1.lookup(input_string) out2 = table2.lookup(input_string) - out1, out2 = sess.run([out1, out2]) + out1, out2 = self.evaluate([out1, out2]) self.assertAllEqual([5, 0, 1, 2, 5], out1) self.assertAllEqual([5, 0, 1, 2, 3], out2) self.assertEquals(vocab_size + oov_buckets, table1.size().eval()) @@ -1396,7 +1396,7 @@ class IdTableWithHashBucketsTest(test.TestCase): out1 = table1.lookup(input_string_1) out2 = table2.lookup(input_string_2) - out1, out2 = sess.run([out1, out2]) + out1, out2 = self.evaluate([out1, out2]) self.assertAllEqual([0, 1, 2, -1], out1) self.assertAllEqual([-2, 1, -2], out2) self.assertEquals(vocab_size + oov_buckets, table1.size().eval()) diff --git a/tensorflow/python/kernel_tests/losses_test.py b/tensorflow/python/kernel_tests/losses_test.py index d3a907852a..bda63bcaa9 100644 --- a/tensorflow/python/kernel_tests/losses_test.py +++ b/tensorflow/python/kernel_tests/losses_test.py @@ -1046,9 +1046,9 @@ class MeanPairwiseSquaredErrorTest(test.TestCase): init_op = variables.global_variables_initializer() with self.cached_session() as sess: - sess.run(init_op) + self.evaluate(init_op) for grad, _ in gradients_to_variables: - np_grad = sess.run(grad) + np_grad = self.evaluate(grad) self.assertFalse(np.isnan(np_grad).any()) def testNonZeroLossWithPythonScalarWeight(self): diff --git a/tensorflow/python/kernel_tests/matrix_exponential_op_test.py b/tensorflow/python/kernel_tests/matrix_exponential_op_test.py index d41b449a1f..83f4216e4d 100644 --- a/tensorflow/python/kernel_tests/matrix_exponential_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_exponential_op_test.py @@ -151,7 +151,7 @@ class ExponentialOpTest(test.TestCase): matrix2 = random_ops.random_normal([5, 5], seed=42) expm1 = linalg_impl.matrix_exponential(matrix1) expm2 = linalg_impl.matrix_exponential(matrix2) - expm = sess.run([expm1, expm2]) + expm = self.evaluate([expm1, expm2]) self.assertAllEqual(expm[0], expm[1]) diff --git a/tensorflow/python/kernel_tests/matrix_inverse_op_test.py b/tensorflow/python/kernel_tests/matrix_inverse_op_test.py index 434458721c..5cef4b79a3 100644 --- a/tensorflow/python/kernel_tests/matrix_inverse_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_inverse_op_test.py @@ -146,7 +146,7 @@ class InverseOpTest(test.TestCase): inv1 = linalg_ops.matrix_inverse(matrix1, adjoint=adjoint_) inv2 = linalg_ops.matrix_inverse(matrix2, adjoint=adjoint_) all_ops += [inv1, inv2] - inv = sess.run(all_ops) + inv = self.evaluate(all_ops) self.assertAllEqual(inv[0], inv[1]) self.assertAllEqual(inv[2], inv[3]) diff --git a/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py b/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py index 81c0b5a772..b0bce6a1b9 100644 --- a/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_logarithm_op_test.py @@ -129,7 +129,7 @@ class LogarithmOpTest(test.TestCase): random_ops.random_normal([5, 5], seed=42), dtypes.complex64) logm1 = gen_linalg_ops.matrix_logarithm(matrix1) logm2 = gen_linalg_ops.matrix_logarithm(matrix2) - logm = sess.run([logm1, logm2]) + logm = self.evaluate([logm1, logm2]) self.assertAllEqual(logm[0], logm[1]) diff --git a/tensorflow/python/kernel_tests/matrix_solve_op_test.py b/tensorflow/python/kernel_tests/matrix_solve_op_test.py index 1334d0c4ce..80badee896 100644 --- a/tensorflow/python/kernel_tests/matrix_solve_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_solve_op_test.py @@ -126,7 +126,7 @@ class MatrixSolveOpTest(test.TestCase): s1 = linalg_ops.matrix_solve(lhs1, rhs1, adjoint=adjoint_) s2 = linalg_ops.matrix_solve(lhs2, rhs2, adjoint=adjoint_) all_ops += [s1, s2] - val = sess.run(all_ops) + val = self.evaluate(all_ops) self.assertAllEqual(val[0], val[1]) self.assertAllEqual(val[2], val[3]) diff --git a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py index 9212580313..1f2144bdee 100644 --- a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py @@ -108,7 +108,7 @@ class SquareRootOpTest(test.TestCase): sqrt1 = gen_linalg_ops.matrix_square_root(matrix1) sqrt2 = gen_linalg_ops.matrix_square_root(matrix2) all_ops = [sqrt1, sqrt2] - sqrt = sess.run(all_ops) + sqrt = self.evaluate(all_ops) self.assertAllEqual(sqrt[0], sqrt[1]) diff --git a/tensorflow/python/kernel_tests/metrics_test.py b/tensorflow/python/kernel_tests/metrics_test.py index 5dcdb9e420..eb5f99582c 100644 --- a/tensorflow/python/kernel_tests/metrics_test.py +++ b/tensorflow/python/kernel_tests/metrics_test.py @@ -203,10 +203,10 @@ class MeanTest(test.TestCase): mean, update_op = metrics.mean(values) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(4): - sess.run(update_op) - self.assertAlmostEqual(1.65, sess.run(mean), 5) + self.evaluate(update_op) + self.assertAlmostEqual(1.65, self.evaluate(mean), 5) def testUpdateOpsReturnsCurrentValue(self): with self.cached_session() as sess: @@ -220,14 +220,14 @@ class MeanTest(test.TestCase): mean, update_op = metrics.mean(values) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.5, sess.run(update_op), 5) - self.assertAlmostEqual(1.475, sess.run(update_op), 5) - self.assertAlmostEqual(12.4 / 6.0, sess.run(update_op), 5) - self.assertAlmostEqual(1.65, sess.run(update_op), 5) + self.assertAlmostEqual(0.5, self.evaluate(update_op), 5) + self.assertAlmostEqual(1.475, self.evaluate(update_op), 5) + self.assertAlmostEqual(12.4 / 6.0, self.evaluate(update_op), 5) + self.assertAlmostEqual(1.65, self.evaluate(update_op), 5) - self.assertAlmostEqual(1.65, sess.run(mean), 5) + self.assertAlmostEqual(1.65, self.evaluate(mean), 5) def testUnweighted(self): values = _test_values((3, 2, 4, 1)) @@ -370,10 +370,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(4): - sess.run(update_op) - self.assertAllClose([[-0.9 / 4., 3.525]], sess.run(mean)) + self.evaluate(update_op) + self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(mean)) def testMultiDimensional(self): with self.cached_session() as sess: @@ -391,10 +391,11 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(2): - sess.run(update_op) - self.assertAllClose([[[1, 2], [1, 2]], [[2, 3], [5, 6]]], sess.run(mean)) + self.evaluate(update_op) + self.assertAllClose([[[1, 2], [1, 2]], [[2, 3], [5, 6]]], + self.evaluate(mean)) def testUpdateOpsReturnsCurrentValue(self): with self.cached_session() as sess: @@ -408,14 +409,14 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) - self.assertAllClose([[0, 1]], sess.run(update_op), 5) - self.assertAllClose([[-2.1, 5.05]], sess.run(update_op), 5) - self.assertAllClose([[2.3 / 3., 10.1 / 3.]], sess.run(update_op), 5) - self.assertAllClose([[-0.9 / 4., 3.525]], sess.run(update_op), 5) + self.assertAllClose([[0, 1]], self.evaluate(update_op), 5) + self.assertAllClose([[-2.1, 5.05]], self.evaluate(update_op), 5) + self.assertAllClose([[2.3 / 3., 10.1 / 3.]], self.evaluate(update_op), 5) + self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(update_op), 5) - self.assertAllClose([[-0.9 / 4., 3.525]], sess.run(mean), 5) + self.assertAllClose([[-0.9 / 4., 3.525]], self.evaluate(mean), 5) def testBinaryWeighted1d(self): with self.cached_session() as sess: @@ -439,10 +440,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(4): - sess.run(update_op) - self.assertAllClose([[3.25, 0.5]], sess.run(mean), 5) + self.evaluate(update_op) + self.assertAllClose([[3.25, 0.5]], self.evaluate(mean), 5) def testWeighted1d(self): with self.cached_session() as sess: @@ -466,10 +467,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(4): - sess.run(update_op) - self.assertAllClose([[0.8, 3.52]], sess.run(mean), 5) + self.evaluate(update_op) + self.assertAllClose([[0.8, 3.52]], self.evaluate(mean), 5) def testWeighted2d_1(self): with self.cached_session() as sess: @@ -493,10 +494,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(4): - sess.run(update_op) - self.assertAllClose([[-2.1, 0.5]], sess.run(mean), 5) + self.evaluate(update_op) + self.assertAllClose([[-2.1, 0.5]], self.evaluate(mean), 5) def testWeighted2d_2(self): with self.cached_session() as sess: @@ -520,10 +521,10 @@ class MeanTensorTest(test.TestCase): mean, update_op = metrics.mean_tensor(values, weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(4): - sess.run(update_op) - self.assertAllClose([[0, 0.5]], sess.run(mean), 5) + self.evaluate(update_op) + self.assertAllClose([[0, 0.5]], self.evaluate(mean), 5) class AccuracyTest(test.TestCase): @@ -576,11 +577,11 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_accuracy = accuracy.eval() @@ -609,10 +610,10 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in xrange(3): - sess.run(update_op) - self.assertEqual(0.5, sess.run(update_op)) + self.evaluate(update_op) + self.assertEqual(0.5, self.evaluate(update_op)) self.assertEqual(0.5, accuracy.eval()) def testEffectivelyEquivalentSizes(self): @@ -621,7 +622,7 @@ class AccuracyTest(test.TestCase): with self.cached_session() as sess: accuracy, update_op = metrics.accuracy(labels, predictions) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertEqual(1.0, update_op.eval()) self.assertEqual(1.0, accuracy.eval()) @@ -631,7 +632,7 @@ class AccuracyTest(test.TestCase): with self.cached_session() as sess: accuracy, update_op = metrics.accuracy(labels, predictions, weights=2.0) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertEqual(1.0, update_op.eval()) self.assertEqual(1.0, accuracy.eval()) @@ -645,7 +646,7 @@ class AccuracyTest(test.TestCase): with self.cached_session() as sess: accuracy, update_op = metrics.accuracy(labels, predictions, weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # if streaming_accuracy does not flatten the weight, accuracy would be # 0.33333334 due to an intended broadcast of weight. Due to flattening, # it will be higher than .95 @@ -666,7 +667,7 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions, weights_placeholder) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # if streaming_accuracy does not flatten the weight, accuracy would be # 0.33333334 due to an intended broadcast of weight. Due to flattening, # it will be higher than .95 @@ -704,10 +705,10 @@ class AccuracyTest(test.TestCase): accuracy, update_op = metrics.accuracy(labels, predictions, weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in xrange(3): - sess.run(update_op) - self.assertEqual(1.0, sess.run(update_op)) + self.evaluate(update_op) + self.assertEqual(1.0, self.evaluate(update_op)) self.assertEqual(1.0, accuracy.eval()) @@ -747,11 +748,11 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_precision = precision.eval() @@ -766,8 +767,8 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(1, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(1, self.evaluate(update_op)) self.assertAlmostEqual(1, precision.eval()) def testSomeCorrect_multipleInputDtypes(self): @@ -779,7 +780,7 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAlmostEqual(0.5, update_op.eval()) self.assertAlmostEqual(0.5, precision.eval()) @@ -882,8 +883,8 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - sess.run(update_op) + self.evaluate(variables.local_variables_initializer()) + self.evaluate(update_op) self.assertAlmostEqual(0, precision.eval()) def testZeroTrueAndFalsePositivesGivesZeroPrecision(self): @@ -892,8 +893,8 @@ class PrecisionTest(test.TestCase): precision, update_op = metrics.precision(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - sess.run(update_op) + self.evaluate(variables.local_variables_initializer()) + self.evaluate(update_op) self.assertEqual(0.0, precision.eval()) @@ -934,11 +935,11 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_recall = recall.eval() @@ -953,8 +954,8 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - sess.run(update_op) + self.evaluate(variables.local_variables_initializer()) + self.evaluate(update_op) self.assertEqual(1, recall.eval()) def testSomeCorrect_multipleInputDtypes(self): @@ -966,7 +967,7 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAlmostEqual(0.5, update_op.eval()) self.assertAlmostEqual(0.5, recall.eval()) @@ -977,7 +978,7 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) weighted_tp = 2.0 + 5.0 weighted_t = (2.0 + 2.0) + (5.0 + 5.0) expected_precision = weighted_tp / weighted_t @@ -991,7 +992,7 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) weighted_tp = 3.0 + 1.0 weighted_t = (2.0 + 3.0) + (4.0 + 1.0) expected_precision = weighted_tp / weighted_t @@ -1006,8 +1007,8 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - sess.run(update_op) + self.evaluate(variables.local_variables_initializer()) + self.evaluate(update_op) self.assertEqual(0, recall.eval()) def testZeroTruePositivesAndFalseNegativesGivesZeroRecall(self): @@ -1016,8 +1017,8 @@ class RecallTest(test.TestCase): recall, update_op = metrics.recall(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - sess.run(update_op) + self.evaluate(variables.local_variables_initializer()) + self.evaluate(update_op) self.assertEqual(0, recall.eval()) @@ -1056,11 +1057,11 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_auc = auc.eval() @@ -1078,8 +1079,8 @@ class AUCTest(test.TestCase): labels = constant_op.constant(inputs) auc, update_op = metrics.auc(labels, predictions, curve=curve) - sess.run(variables.local_variables_initializer()) - self.assertEqual(1, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(1, self.evaluate(update_op)) self.assertEqual(1, auc.eval()) @@ -1093,8 +1094,8 @@ class AUCTest(test.TestCase): constant_op.constant([0, 1, 1, 0], shape=(1, 4)), dtype=label_dtype) auc, update_op = metrics.auc(labels, predictions) - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.5, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.5, self.evaluate(update_op)) self.assertAlmostEqual(0.5, auc.eval()) @@ -1106,8 +1107,8 @@ class AUCTest(test.TestCase): weights = constant_op.constant([2], shape=(1, 1)) auc, update_op = metrics.auc(labels, predictions, weights=weights) - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.5, sess.run(update_op), 5) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.5, self.evaluate(update_op), 5) self.assertAlmostEqual(0.5, auc.eval(), 5) @@ -1119,8 +1120,8 @@ class AUCTest(test.TestCase): weights = constant_op.constant([1, 2, 3, 4], shape=(1, 4)) auc, update_op = metrics.auc(labels, predictions, weights=weights) - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.7, sess.run(update_op), 5) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.7, self.evaluate(update_op), 5) self.assertAlmostEqual(0.7, auc.eval(), 5) @@ -1134,10 +1135,10 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='careful_interpolation') - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # expected ~= 0.79726744594 expected = 1 - math.log(1.5) / 2 - self.assertAlmostEqual(expected, sess.run(update_op), delta=1e-3) + self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) def testCorrectAnotherAUCPRSpecialCase(self): @@ -1150,10 +1151,10 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='careful_interpolation') - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # expected ~= 0.61350593198 expected = (2.5 - 2 * math.log(4./3) - 0.25 * math.log(7./5)) / 3 - self.assertAlmostEqual(expected, sess.run(update_op), delta=1e-3) + self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) def testThirdCorrectAUCPRSpecialCase(self): @@ -1166,10 +1167,10 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='careful_interpolation') - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # expected ~= 0.90410597584 expected = 1 - math.log(4./3) / 3 - self.assertAlmostEqual(expected, sess.run(update_op), delta=1e-3) + self.assertAlmostEqual(expected, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(expected, auc.eval(), delta=1e-3) def testIncorrectAUCPRSpecialCase(self): @@ -1180,8 +1181,8 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='trapezoidal') - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.79166, sess.run(update_op), delta=1e-3) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.79166, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(0.79166, auc.eval(), delta=1e-3) @@ -1195,8 +1196,8 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='trapezoidal') - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.610317, sess.run(update_op), delta=1e-3) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.610317, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(0.610317, auc.eval(), delta=1e-3) @@ -1210,8 +1211,8 @@ class AUCTest(test.TestCase): auc, update_op = metrics.auc(labels, predictions, curve='PR', summation_method='trapezoidal') - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.90277, sess.run(update_op), delta=1e-3) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.90277, self.evaluate(update_op), delta=1e-3) self.assertAlmostEqual(0.90277, auc.eval(), delta=1e-3) @@ -1223,8 +1224,8 @@ class AUCTest(test.TestCase): labels = constant_op.constant(1 - inputs, dtype=dtypes_lib.float32) auc, update_op = metrics.auc(labels, predictions) - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0, self.evaluate(update_op)) self.assertAlmostEqual(0, auc.eval()) @@ -1234,8 +1235,8 @@ class AUCTest(test.TestCase): labels = array_ops.zeros([4]) auc, update_op = metrics.auc(labels, predictions) - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(1, sess.run(update_op), 6) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(1, self.evaluate(update_op), 6) self.assertAlmostEqual(1, auc.eval(), 6) @@ -1245,8 +1246,8 @@ class AUCTest(test.TestCase): labels = array_ops.ones([4]) auc, update_op = metrics.auc(labels, predictions, curve='PR') - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(1, sess.run(update_op), 6) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(1, self.evaluate(update_op), 6) self.assertAlmostEqual(1, auc.eval(), 6) @@ -1317,9 +1318,9 @@ class AUCTest(test.TestCase): num_thresholds=500, weights=tf_weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for i in range(num_batches): - sess.run(update_op) + self.evaluate(update_op) # Since this is only approximate, we can't expect a 6 digits match. # Although with higher number of samples/thresholds we should see the @@ -1371,11 +1372,11 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.7) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_specificity = specificity.eval() @@ -1391,8 +1392,8 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.7) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(1, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(1, self.evaluate(update_op)) self.assertEqual(1, specificity.eval()) def testSomeCorrectHighSensitivity(self): @@ -1406,8 +1407,8 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.8) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(1.0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(1.0, self.evaluate(update_op)) self.assertAlmostEqual(1.0, specificity.eval()) def testSomeCorrectLowSensitivity(self): @@ -1421,9 +1422,9 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, sensitivity=0.4) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.6, sess.run(update_op)) + self.assertAlmostEqual(0.6, self.evaluate(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) def testWeighted1d_multipleLabelDtypes(self): @@ -1440,9 +1441,9 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, weights=weights, sensitivity=0.4) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(0.6, sess.run(update_op)) + self.assertAlmostEqual(0.6, self.evaluate(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) def testWeighted2d(self): @@ -1458,9 +1459,9 @@ class SpecificityAtSensitivityTest(test.TestCase): labels, predictions, weights=weights, sensitivity=0.4) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) - self.assertAlmostEqual(8.0 / 15.0, sess.run(update_op)) + self.assertAlmostEqual(8.0 / 15.0, self.evaluate(update_op)) self.assertAlmostEqual(8.0 / 15.0, specificity.eval()) @@ -1508,11 +1509,11 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.7) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_sensitivity = sensitivity.eval() @@ -1528,8 +1529,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.7) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(1, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(1, self.evaluate(update_op)) self.assertEqual(1, specificity.eval()) def testSomeCorrectHighSpecificity(self): @@ -1543,8 +1544,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.8) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.8, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.8, self.evaluate(update_op)) self.assertAlmostEqual(0.8, specificity.eval()) def testSomeCorrectLowSpecificity(self): @@ -1558,8 +1559,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, specificity=0.4) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.6, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.6, self.evaluate(update_op)) self.assertAlmostEqual(0.6, specificity.eval()) def testWeighted_multipleLabelDtypes(self): @@ -1577,8 +1578,8 @@ class SensitivityAtSpecificityTest(test.TestCase): labels, predictions, weights=weights, specificity=0.4) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(0.675, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(0.675, self.evaluate(update_op)) self.assertAlmostEqual(0.675, specificity.eval()) @@ -1639,14 +1640,14 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates, then verify idempotency. - sess.run([prec_op, rec_op]) + self.evaluate([prec_op, rec_op]) initial_prec = prec.eval() initial_rec = rec.eval() for _ in range(10): - sess.run([prec_op, rec_op]) + self.evaluate([prec_op, rec_op]) self.assertAllClose(initial_prec, prec.eval()) self.assertAllClose(initial_rec, rec.eval()) @@ -1663,8 +1664,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertEqual(1, prec.eval()) self.assertEqual(1, rec.eval()) @@ -1683,8 +1684,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertAlmostEqual(0.5, prec.eval()) self.assertAlmostEqual(0.5, rec.eval()) @@ -1701,8 +1702,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertAlmostEqual(0, prec.eval()) self.assertAlmostEqual(0, rec.eval()) @@ -1729,8 +1730,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec_low = array_ops.reshape(rec_low, shape=()) rec_high = array_ops.reshape(rec_high, shape=()) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertAlmostEqual(1.0, prec_low.eval(), places=5) self.assertAlmostEqual(0.0, prec_high.eval(), places=5) @@ -1759,8 +1760,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec_low = array_ops.reshape(rec_low, shape=()) rec_high = array_ops.reshape(rec_high, shape=()) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertAlmostEqual(1.0, prec_low.eval(), places=5) self.assertAlmostEqual(0.0, prec_high.eval(), places=5) @@ -1783,8 +1784,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): [rec_low, rec_high] = array_ops.split( value=rec, num_or_size_splits=2, axis=0) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertAlmostEqual(0.75, prec_low.eval()) self.assertAlmostEqual(0.0, prec_high.eval()) @@ -1801,8 +1802,8 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(labels, predictions, thresholds) - sess.run(variables.local_variables_initializer()) - sess.run([prec_op, rec_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([prec_op, rec_op]) self.assertAlmostEqual(0, prec.eval(), 6) self.assertAlmostEqual(0, rec.eval(), 6) @@ -1869,9 +1870,9 @@ class PrecisionRecallThresholdsTest(test.TestCase): rec, rec_op = metrics.recall_at_thresholds(tf_labels, tf_predictions, thresholds) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(int(num_samples / batch_size)): - sess.run([prec_op, rec_op]) + self.evaluate([prec_op, rec_op]) # Since this is only approximate, we can't expect a 6 digits match. # Although with higher number of samples/thresholds we should see the # accuracy improving @@ -2802,11 +2803,11 @@ class MeanAbsoluteErrorTest(test.TestCase): error, update_op = metrics.mean_absolute_error(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_error = error.eval() @@ -2823,8 +2824,8 @@ class MeanAbsoluteErrorTest(test.TestCase): error, update_op = metrics.mean_absolute_error(labels, predictions, weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(3, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(3, self.evaluate(update_op)) self.assertEqual(3, error.eval()) @@ -2867,11 +2868,11 @@ class MeanRelativeErrorTest(test.TestCase): normalizer) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_error = error.eval() @@ -2892,8 +2893,8 @@ class MeanRelativeErrorTest(test.TestCase): labels, predictions, normalizer=labels) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(expected_error, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(expected_error, self.evaluate(update_op)) self.assertEqual(expected_error, error.eval()) def testSingleUpdateNormalizedByZeros(self): @@ -2908,8 +2909,8 @@ class MeanRelativeErrorTest(test.TestCase): labels, predictions, normalizer=array_ops.zeros_like(labels)) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(0.0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(0.0, self.evaluate(update_op)) self.assertEqual(0.0, error.eval()) @@ -2946,11 +2947,11 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_error = error.eval() @@ -2964,8 +2965,8 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, error.eval()) def testSingleUpdateWithError(self): @@ -2977,8 +2978,8 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(6, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(6, self.evaluate(update_op)) self.assertEqual(6, error.eval()) def testSingleUpdateWithErrorAndWeights(self): @@ -2991,8 +2992,8 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions, weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(13, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(13, self.evaluate(update_op)) self.assertEqual(13, error.eval()) def testMultipleBatchesOfSizeOne(self): @@ -3013,9 +3014,9 @@ class MeanSquaredErrorTest(test.TestCase): error, update_op = metrics.mean_squared_error(labels, predictions) - sess.run(variables.local_variables_initializer()) - sess.run(update_op) - self.assertAlmostEqual(208.0 / 6, sess.run(update_op), 5) + self.evaluate(variables.local_variables_initializer()) + self.evaluate(update_op) + self.assertAlmostEqual(208.0 / 6, self.evaluate(update_op), 5) self.assertAlmostEqual(208.0 / 6, error.eval(), 5) @@ -3054,11 +3055,11 @@ class MeanSquaredErrorTest(test.TestCase): mse1, update_op1 = metrics.mean_squared_error( labels1, predictions1, name='msd1') - sess.run(variables.local_variables_initializer()) - sess.run([update_op0, update_op1]) - sess.run([update_op0, update_op1]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([update_op0, update_op1]) + self.evaluate([update_op0, update_op1]) - mse0, mse1 = sess.run([mse0, mse1]) + mse0, mse1 = self.evaluate([mse0, mse1]) self.assertAlmostEqual(208.0 / 6, mse0, 5) self.assertAlmostEqual(79.0 / 6, mse1, 5) @@ -3081,9 +3082,9 @@ class MeanSquaredErrorTest(test.TestCase): mae, ma_update_op = metrics.mean_absolute_error(labels, predictions) mse, ms_update_op = metrics.mean_squared_error(labels, predictions) - sess.run(variables.local_variables_initializer()) - sess.run([ma_update_op, ms_update_op]) - sess.run([ma_update_op, ms_update_op]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([ma_update_op, ms_update_op]) + self.evaluate([ma_update_op, ms_update_op]) self.assertAlmostEqual(32.0 / 6, mae.eval(), 5) self.assertAlmostEqual(208.0 / 6, mse.eval(), 5) @@ -3123,11 +3124,11 @@ class RootMeanSquaredErrorTest(test.TestCase): error, update_op = metrics.root_mean_squared_error(labels, predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_error = error.eval() @@ -3142,8 +3143,8 @@ class RootMeanSquaredErrorTest(test.TestCase): rmse, update_op = metrics.root_mean_squared_error(labels, predictions) - sess.run(variables.local_variables_initializer()) - self.assertEqual(0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, rmse.eval()) @@ -3156,7 +3157,7 @@ class RootMeanSquaredErrorTest(test.TestCase): rmse, update_op = metrics.root_mean_squared_error(labels, predictions) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAlmostEqual(math.sqrt(6), update_op.eval(), 5) self.assertAlmostEqual(math.sqrt(6), rmse.eval(), 5) @@ -3171,8 +3172,8 @@ class RootMeanSquaredErrorTest(test.TestCase): rmse, update_op = metrics.root_mean_squared_error(labels, predictions, weights) - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(math.sqrt(13), sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(math.sqrt(13), self.evaluate(update_op)) self.assertAlmostEqual(math.sqrt(13), rmse.eval(), 5) @@ -3221,11 +3222,11 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=1) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_error = error.eval() @@ -3243,8 +3244,8 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=2) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, error.eval()) def testSingleUpdateWithError1(self): @@ -3259,8 +3260,8 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=2) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(1, sess.run(update_op), 5) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(1, self.evaluate(update_op), 5) self.assertAlmostEqual(1, error.eval(), 5) def testSingleUpdateWithError2(self): @@ -3280,8 +3281,8 @@ class MeanCosineDistanceTest(test.TestCase): error, update_op = metrics.mean_cosine_distance(labels, predictions, dim=2) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertAlmostEqual(1.0, sess.run(update_op), 5) + self.evaluate(variables.local_variables_initializer()) + self.assertAlmostEqual(1.0, self.evaluate(update_op), 5) self.assertAlmostEqual(1.0, error.eval(), 5) def testSingleUpdateWithErrorAndWeights1(self): @@ -3299,8 +3300,8 @@ class MeanCosineDistanceTest(test.TestCase): labels, predictions, dim=2, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) - self.assertEqual(0, sess.run(update_op)) + self.evaluate(variables.local_variables_initializer()) + self.assertEqual(0, self.evaluate(update_op)) self.assertEqual(0, error.eval()) def testSingleUpdateWithErrorAndWeights2(self): @@ -3318,7 +3319,7 @@ class MeanCosineDistanceTest(test.TestCase): labels, predictions, dim=2, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertEqual(1.5, update_op.eval()) self.assertEqual(1.5, error.eval()) @@ -3360,10 +3361,10 @@ class PcntBelowThreshTest(test.TestCase): pcnt1, update_op1 = metrics.percentage_below(values, 7, name='medium') pcnt2, update_op2 = metrics.percentage_below(values, 1, name='low') - sess.run(variables.local_variables_initializer()) - sess.run([update_op0, update_op1, update_op2]) + self.evaluate(variables.local_variables_initializer()) + self.evaluate([update_op0, update_op1, update_op2]) - pcnt0, pcnt1, pcnt2 = sess.run([pcnt0, pcnt1, pcnt2]) + pcnt0, pcnt1, pcnt2 = self.evaluate([pcnt0, pcnt1, pcnt2]) self.assertAlmostEqual(1.0, pcnt0, 5) self.assertAlmostEqual(0.75, pcnt1, 5) self.assertAlmostEqual(0.0, pcnt2, 5) @@ -3382,11 +3383,11 @@ class PcntBelowThreshTest(test.TestCase): pcnt2, update_op2 = metrics.percentage_below( values, 1, weights=weights, name='low') - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertListEqual([1.0, 0.5, 0.0], - sess.run([update_op0, update_op1, update_op2])) + self.evaluate([update_op0, update_op1, update_op2])) - pcnt0, pcnt1, pcnt2 = sess.run([pcnt0, pcnt1, pcnt2]) + pcnt0, pcnt1, pcnt2 = self.evaluate([pcnt0, pcnt1, pcnt2]) self.assertAlmostEqual(1.0, pcnt0, 5) self.assertAlmostEqual(0.5, pcnt1, 5) self.assertAlmostEqual(0.0, pcnt2, 5) @@ -3446,11 +3447,11 @@ class MeanIOUTest(test.TestCase): labels, predictions, num_classes=num_classes) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_mean_iou = mean_iou.eval() @@ -3482,9 +3483,9 @@ class MeanIOUTest(test.TestCase): miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(5): - sess.run(update_op) + self.evaluate(update_op) desired_output = np.mean([1.0 / 2.0, 1.0 / 4.0, 0.]) self.assertEqual(desired_output, miou.eval()) @@ -3529,7 +3530,7 @@ class MeanIOUTest(test.TestCase): variables.local_variables_initializer().run() for _ in range(6): - sess.run(update_op) + self.evaluate(update_op) desired_output = np.mean([2.0 / 3.0, 1.0 / 2.0]) self.assertAlmostEqual(desired_output, mean_iou.eval()) @@ -3563,9 +3564,9 @@ class MeanIOUTest(test.TestCase): miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(5): - sess.run(update_op) + self.evaluate(update_op) desired_output = np.mean([1.0 / 3.0, 2.0 / 4.0]) self.assertAlmostEqual(desired_output, miou.eval()) @@ -3587,7 +3588,7 @@ class MeanIOUTest(test.TestCase): num_classes = 2 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) confusion_matrix = update_op.eval() self.assertAllEqual([[3, 0], [2, 5]], confusion_matrix) desired_miou = np.mean([3. / 5., 5. / 7.]) @@ -3599,7 +3600,7 @@ class MeanIOUTest(test.TestCase): num_classes = 1 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertEqual(40, update_op.eval()[0]) self.assertEqual(1.0, miou.eval()) @@ -3609,7 +3610,7 @@ class MeanIOUTest(test.TestCase): num_classes = 2 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual([[0, 0], [40, 0]], update_op.eval()) self.assertEqual(0., miou.eval()) @@ -3640,7 +3641,7 @@ class MeanIOUTest(test.TestCase): with self.cached_session() as sess: miou, update_op = metrics.mean_iou( labels, predictions, num_classes, weights=weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual([[2, 0], [2, 4]], update_op.eval()) desired_miou = np.mean([2. / 4., 4. / 6.]) self.assertAlmostEqual(desired_miou, miou.eval()) @@ -3659,7 +3660,7 @@ class MeanIOUTest(test.TestCase): num_classes = 3 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual([[7, 4, 3], [3, 5, 2], [0, 0, 0]], update_op.eval()) self.assertAlmostEqual( 1 / 3 * (7 / (7 + 3 + 7) + 5 / (5 + 4 + 5) + 0 / (0 + 5 + 0)), @@ -3671,7 +3672,7 @@ class MeanIOUTest(test.TestCase): num_classes = 2 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual([[1, 0], [0, 0]], update_op.eval()) self.assertAlmostEqual(1, miou.eval()) @@ -3689,7 +3690,7 @@ class MeanIOUTest(test.TestCase): num_classes = 3 with self.cached_session() as sess: miou, update_op = metrics.mean_iou(labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual([[9, 5, 0], [3, 7, 0], [0, 0, 0]], update_op.eval()) self.assertAlmostEqual( 1 / 2 * (9 / (9 + 3 + 5) + 7 / (7 + 5 + 3)), miou.eval()) @@ -3752,11 +3753,11 @@ class MeanPerClassAccuracyTest(test.TestCase): labels, predictions, num_classes=num_classes) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) # Run several updates. for _ in range(10): - sess.run(update_op) + self.evaluate(update_op) # Then verify idempotency. initial_mean_accuracy = mean_accuracy.eval() @@ -3788,9 +3789,9 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(5): - sess.run(update_op) + self.evaluate(update_op) desired_output = np.mean([1.0, 1.0 / 3.0, 0.0]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) @@ -3835,7 +3836,7 @@ class MeanPerClassAccuracyTest(test.TestCase): variables.local_variables_initializer().run() for _ in range(6): - sess.run(update_op) + self.evaluate(update_op) desired_output = np.mean([2.0 / 2.0, 0.5 / 1.5]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) @@ -3870,9 +3871,9 @@ class MeanPerClassAccuracyTest(test.TestCase): mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) for _ in range(5): - sess.run(update_op) + self.evaluate(update_op) desired_output = np.mean([1.0 / 2.0, 2.0 / 3.0, 0.]) self.assertAlmostEqual(desired_output, mean_accuracy.eval()) @@ -3883,7 +3884,7 @@ class MeanPerClassAccuracyTest(test.TestCase): with self.cached_session() as sess: mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertEqual(1.0, update_op.eval()[0]) self.assertEqual(1.0, mean_accuracy.eval()) @@ -3894,7 +3895,7 @@ class MeanPerClassAccuracyTest(test.TestCase): with self.cached_session() as sess: mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual([0.0, 0.0], update_op.eval()) self.assertEqual(0., mean_accuracy.eval()) @@ -3913,7 +3914,7 @@ class MeanPerClassAccuracyTest(test.TestCase): with self.cached_session() as sess: mean_accuracy, update_op = metrics.mean_per_class_accuracy( labels, predictions, num_classes, weights=weights) - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) desired_accuracy = np.array([2. / 2., 4. / 6.], dtype=np.float32) self.assertAllEqual(desired_accuracy, update_op.eval()) desired_mean_accuracy = np.mean(desired_accuracy) @@ -3945,7 +3946,7 @@ class FalseNegativesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(3., tn_update_op.eval()) self.assertAllClose(3., tn.eval()) @@ -3964,7 +3965,7 @@ class FalseNegativesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(5., tn_update_op.eval()) self.assertAllClose(5., tn.eval()) @@ -3994,7 +3995,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), fn.eval()) self.assertAllEqual((0, 2, 3), fn_update_op.eval()) self.assertAllEqual((0, 2, 3), fn.eval()) @@ -4013,7 +4014,7 @@ class FalseNegativesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), fn.eval()) self.assertAllEqual((0.0, 8.0, 11.0), fn_update_op.eval()) self.assertAllEqual((0.0, 8.0, 11.0), fn.eval()) @@ -4044,7 +4045,7 @@ class FalsePositivesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(7., tn_update_op.eval()) self.assertAllClose(7., tn.eval()) @@ -4063,7 +4064,7 @@ class FalsePositivesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(14., tn_update_op.eval()) self.assertAllClose(14., tn.eval()) @@ -4093,7 +4094,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), fp.eval()) self.assertAllEqual((7, 4, 2), fp_update_op.eval()) self.assertAllEqual((7, 4, 2), fp.eval()) @@ -4114,7 +4115,7 @@ class FalsePositivesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), fp.eval()) self.assertAllEqual((125.0, 42.0, 12.0), fp_update_op.eval()) self.assertAllEqual((125.0, 42.0, 12.0), fp.eval()) @@ -4145,7 +4146,7 @@ class TrueNegativesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(3., tn_update_op.eval()) self.assertAllClose(3., tn.eval()) @@ -4164,7 +4165,7 @@ class TrueNegativesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(4., tn_update_op.eval()) self.assertAllClose(4., tn.eval()) @@ -4194,7 +4195,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), tn.eval()) self.assertAllEqual((2, 5, 7), tn_update_op.eval()) self.assertAllEqual((2, 5, 7), tn.eval()) @@ -4213,7 +4214,7 @@ class TrueNegativesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), tn.eval()) self.assertAllEqual((5.0, 15.0, 23.0), tn_update_op.eval()) self.assertAllEqual((5.0, 15.0, 23.0), tn.eval()) @@ -4244,7 +4245,7 @@ class TruePositivesTest(test.TestCase): labels=labels, predictions=predictions) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(7., tn_update_op.eval()) self.assertAllClose(7., tn.eval()) @@ -4263,7 +4264,7 @@ class TruePositivesTest(test.TestCase): labels=labels, predictions=predictions, weights=weights) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllClose(0., tn.eval()) self.assertAllClose(12., tn_update_op.eval()) self.assertAllClose(12., tn.eval()) @@ -4293,7 +4294,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): predictions=predictions, labels=labels, thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0, 0, 0), tp.eval()) self.assertAllEqual((3, 1, 0), tp_update_op.eval()) self.assertAllEqual((3, 1, 0), tp.eval()) @@ -4310,7 +4311,7 @@ class TruePositivesAtThresholdsTest(test.TestCase): thresholds=[0.15, 0.5, 0.85]) with self.cached_session() as sess: - sess.run(variables.local_variables_initializer()) + self.evaluate(variables.local_variables_initializer()) self.assertAllEqual((0.0, 0.0, 0.0), tp.eval()) self.assertAllEqual((111.0, 37.0, 0.0), tp_update_op.eval()) self.assertAllEqual((111.0, 37.0, 0.0), tp.eval()) diff --git a/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py b/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py index 15e3826542..87f1991aa7 100644 --- a/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py +++ b/tensorflow/python/kernel_tests/neon_depthwise_conv_op_test.py @@ -142,8 +142,8 @@ class DepthwiseConv2DTest(test.TestCase): conv_interface = nn_impl.depthwise_conv2d( t1, t2, strides=[1, stride, stride, 1], padding=padding) - native_result = sess.run(conv_native) - interface_result = sess.run(conv_interface) + native_result = self.evaluate(conv_native) + interface_result = self.evaluate(conv_interface) print("depthwise conv_2d: ", tensor_in_sizes, "*", filter_in_sizes, ", stride:", stride, ", padding: ", padding, ", max diff: ", @@ -211,7 +211,7 @@ class DepthwiseConv2DTest(test.TestCase): t2 = constant_op.constant(x2, shape=filter_in_sizes) conv = nn_ops.depthwise_conv2d_native( t1, t2, strides=[1, stride, stride, 1], padding=padding) - value = sess.run(conv) + value = self.evaluate(conv) print("value = ", value) self.assertAllClose(expected, np.ravel(value), 1e-5) self.assertShapeEqual(value, conv) diff --git a/tensorflow/python/kernel_tests/norm_op_test.py b/tensorflow/python/kernel_tests/norm_op_test.py index e202b6e8a4..5ff0c58bf1 100644 --- a/tensorflow/python/kernel_tests/norm_op_test.py +++ b/tensorflow/python/kernel_tests/norm_op_test.py @@ -70,7 +70,7 @@ def _GetNormOpTest(dtype_, shape_, ord_, axis_, keep_dims_, use_static_shape_): tf_matrix = constant_op.constant(matrix) tf_norm = linalg_ops.norm( tf_matrix, ord=ord_, axis=axis_, keepdims=keep_dims_) - tf_norm_val = sess.run(tf_norm) + tf_norm_val = self.evaluate(tf_norm) else: tf_matrix = array_ops.placeholder(dtype_) tf_norm = linalg_ops.norm( diff --git a/tensorflow/python/kernel_tests/nth_element_op_test.py b/tensorflow/python/kernel_tests/nth_element_op_test.py index 338b6cec01..6cd4974671 100644 --- a/tensorflow/python/kernel_tests/nth_element_op_test.py +++ b/tensorflow/python/kernel_tests/nth_element_op_test.py @@ -35,7 +35,7 @@ class NthElementTest(test.TestCase): with self.cached_session(use_gpu=False) as sess: inputs_op = ops.convert_to_tensor(inputs, dtype=dtype) values_op = nn_ops.nth_element(inputs_op, n, reverse=reverse) - values = sess.run(values_op) + values = self.evaluate(values_op) self.assertShapeEqual(np_expected_values, values_op) self.assertAllClose(np_expected_values, values) diff --git a/tensorflow/python/kernel_tests/padding_fifo_queue_test.py b/tensorflow/python/kernel_tests/padding_fifo_queue_test.py index 520b663375..b4818360d5 100644 --- a/tensorflow/python/kernel_tests/padding_fifo_queue_test.py +++ b/tensorflow/python/kernel_tests/padding_fifo_queue_test.py @@ -126,7 +126,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) threads = [ self.checkedThread( @@ -158,7 +158,7 @@ class PaddingFIFOQueueTest(test.TestCase): results = [] def dequeue(): - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in enqueue_ops] for thread in threads: @@ -193,13 +193,13 @@ class PaddingFIFOQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) for enqueue_op in enqueue_ops: - sess.run(enqueue_op) + self.evaluate(enqueue_op) results = [] def dequeue(): for _ in xrange(len(elems)): - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -224,7 +224,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() for i in xrange(len(elems)): - x_val, y_val = sess.run(dequeued_t) + x_val, y_val = self.evaluate(dequeued_t) x, y = elems[i] self.assertEqual([x], x_val) self.assertEqual([y], y_val) @@ -327,7 +327,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() for i in range(8): - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertEqual(float_elems[i % 4], float_val) self.assertAllEqual(int_elems[i % 4], int_val) @@ -344,7 +344,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() for i in range(8): - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertEqual(float_elems[i % 4], float_val) self.assertAllEqual(int_elems[i % 4], int_val) @@ -387,17 +387,17 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertEqual(float_val.shape, dequeued_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_t[1].get_shape()) - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) self.assertAllEqual(float_elems[8], float_val) self.assertAllEqual(int_elems[8], int_val) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) @@ -418,7 +418,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[0:4], float_val) self.assertAllEqual(int_elems[0:4], int_val) self.assertTrue( @@ -428,11 +428,11 @@ class PaddingFIFOQueueTest(test.TestCase): tensor_shape.TensorShape(int_val.shape).is_compatible_with(dequeued_t[ 1].get_shape())) - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual(float_elems[4:8], float_val) self.assertAllEqual(int_elems[4:8], int_val) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) self.assertAllEqual(float_elems[8], float_val) self.assertAllEqual(int_elems[8], int_val) self.assertTrue( @@ -459,7 +459,7 @@ class PaddingFIFOQueueTest(test.TestCase): for enqueue_op in enqueue_ops: enqueue_op.run() - string_val, int_val = sess.run(dequeued_t) + string_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual([[b"a", b"", b""], [b"ab", b"", b""], [b"abc", b"", b""], [b"abc", b"d", b""], @@ -473,7 +473,7 @@ class PaddingFIFOQueueTest(test.TestCase): tensor_shape.TensorShape(int_val.shape).is_compatible_with(dequeued_t[ 1].get_shape())) - string_val, int_val = sess.run(dequeued_single_t) + string_val, int_val = self.evaluate(dequeued_single_t) self.assertAllEqual([b"abc", b"d", b"e", b"f"], string_val) self.assertAllEqual([[1, 2, 3, 4]], int_val) self.assertTrue( @@ -500,7 +500,7 @@ class PaddingFIFOQueueTest(test.TestCase): for enqueue_op in enqueue_ops: enqueue_op.run() - string_val, int_val = sess.run(dequeued_t) + string_val, int_val = self.evaluate(dequeued_t) self.assertAllEqual([[b"a", b"", b""], [b"ab", b"", b""], [b"abc", b"", b""], [b"abc", b"d", b""], @@ -514,7 +514,7 @@ class PaddingFIFOQueueTest(test.TestCase): tensor_shape.TensorShape(int_val.shape).is_compatible_with(dequeued_t[ 1].get_shape())) - string_val, int_val = sess.run(dequeued_single_t) + string_val, int_val = self.evaluate(dequeued_single_t) self.assertAllEqual([b"abc", b"d", b"e", b"f"], string_val) self.assertAllEqual([[1, 2, 3, 4]], int_val) self.assertTrue( @@ -633,7 +633,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Enqueue 100 items in parallel on 10 threads. def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) threads = [self.checkedThread(target=enqueue) for _ in range(10)] for thread in threads: @@ -656,7 +656,7 @@ class PaddingFIFOQueueTest(test.TestCase): dequeued_elems = [] def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t)) + dequeued_elems.extend(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in range(10)] for thread in threads: @@ -680,7 +680,7 @@ class PaddingFIFOQueueTest(test.TestCase): dequeued_elems = [] def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t)) + dequeued_elems.extend(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in range(10)] for thread in threads: @@ -700,11 +700,11 @@ class PaddingFIFOQueueTest(test.TestCase): def enqueue(): for _ in xrange(100): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): for _ in xrange(100): - self.assertTrue(sess.run(dequeued_t) in (10.0, 20.0)) + self.assertTrue(self.evaluate(dequeued_t) in (10.0, 20.0)) enqueue_threads = [self.checkedThread(target=enqueue) for _ in range(10)] dequeue_threads = [self.checkedThread(target=dequeue) for _ in range(10)] @@ -736,7 +736,7 @@ class PaddingFIFOQueueTest(test.TestCase): def dequeue(): for i in xrange(250): - self.assertEqual(i, sess.run(dequeued_t)) + self.assertEqual(i, self.evaluate(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -767,7 +767,7 @@ class PaddingFIFOQueueTest(test.TestCase): dequeuemany_t = q.dequeue_many(count_placeholder) def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -805,10 +805,10 @@ class PaddingFIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t).tolist()) + dequeued_elems.extend(self.evaluate(dequeued_t).tolist()) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -832,10 +832,10 @@ class PaddingFIFOQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t).tolist()) + dequeued_elems.extend(self.evaluate(dequeued_t).tolist()) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -901,11 +901,11 @@ class PaddingFIFOQueueTest(test.TestCase): def dequeue(): for elem in elems: - self.assertEqual([elem], sess.run(dequeued_t)) + self.assertEqual([elem], self.evaluate(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -926,8 +926,8 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], sess.run(dequeued_t)) - self.assertAllEqual(elems[3:], sess.run(dequeued_t)) + self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) + self.assertAllEqual(elems[3:], self.evaluate(dequeued_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -947,7 +947,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -968,11 +968,11 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems, sess.run(dequeued_t)) + self.assertAllEqual(elems, self.evaluate(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -993,11 +993,11 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def dequeue(): - self.assertAllEqual(elems[:3], sess.run(dequeued_t)) + self.assertAllEqual(elems[:3], self.evaluate(dequeued_t)) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -1017,16 +1017,16 @@ class PaddingFIFOQueueTest(test.TestCase): cleanup_dequeue_t = q.dequeue() def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - self.assertAllEqual(elems[0:3], sess.run(dequeued_t)) + self.assertAllEqual(elems[0:3], self.evaluate(dequeued_t)) with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(dequeued_t) - self.assertEqual(elems[3], sess.run(cleanup_dequeue_t)) + self.evaluate(dequeued_t) + self.assertEqual(elems[3], self.evaluate(cleanup_dequeue_t)) def close(): - sess.run(close_op) + self.evaluate(close_op) enqueue_thread = self.checkedThread(target=enqueue) enqueue_thread.start() @@ -1059,7 +1059,7 @@ class PaddingFIFOQueueTest(test.TestCase): def dequeue(): with self.assertRaises(errors_impl.OutOfRangeError): - sess.run([dequeued_a_t, dequeued_b_t]) + self.evaluate([dequeued_a_t, dequeued_b_t]) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -1072,7 +1072,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Test that the elements in the partially-dequeued batch are # restored in the correct order. for elem_a, elem_b in zip(elems_a, elems_b): - val_a, val_b = sess.run([cleanup_dequeue_a_t, cleanup_dequeue_b_t]) + val_a, val_b = self.evaluate([cleanup_dequeue_a_t, cleanup_dequeue_b_t]) self.assertEqual(elem_a, val_a) self.assertEqual(elem_b, val_b) self.assertEqual(0, q.size().eval()) @@ -1087,7 +1087,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -1107,7 +1107,7 @@ class PaddingFIFOQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -1155,7 +1155,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1178,7 +1178,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -1207,7 +1207,7 @@ class PaddingFIFOQueueTest(test.TestCase): def blocking_enqueue(): # Expect the operation to succeed once the dequeue op runs. - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1217,7 +1217,7 @@ class PaddingFIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - sess.run(close_op) + self.evaluate(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1242,7 +1242,7 @@ class PaddingFIFOQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) enqueue_thread = self.checkedThread(target=blocking_enqueue) enqueue_thread.start() @@ -1252,7 +1252,7 @@ class PaddingFIFOQueueTest(test.TestCase): time.sleep(0.1) def close(): - sess.run(close_op) + self.evaluate(close_op) close_thread = self.checkedThread(target=close) close_thread.start() @@ -1379,19 +1379,19 @@ class PaddingFIFOQueueTest(test.TestCase): def _blockingDequeue(self, sess, dequeue_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_op) + self.evaluate(dequeue_op) def _blockingDequeueMany(self, sess, dequeue_many_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_many_op) + self.evaluate(dequeue_many_op) def _blockingEnqueue(self, sess, enqueue_op): with self.assertRaisesOpError("was cancelled"): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def _blockingEnqueueMany(self, sess, enqueue_many_op): with self.assertRaisesOpError("was cancelled"): - sess.run(enqueue_many_op) + self.evaluate(enqueue_many_op) def testResetOfBlockingOperation(self): with self.cached_session() as sess: @@ -1434,7 +1434,7 @@ class PaddingFIFOQueueTest(test.TestCase): def blocking_enqueue(): enq_done.append(False) # This will fill the queue and then block until enough dequeues happen. - sess.run(enq) + self.evaluate(enq) enq_done.append(True) thread = self.checkedThread(target=blocking_enqueue) @@ -1444,14 +1444,14 @@ class PaddingFIFOQueueTest(test.TestCase): results = [] results.append(deq.eval()) # Will only complete after the enqueue starts. self.assertEqual(len(enq_done), 1) - self.assertEqual(sess.run(size_op), 5) + self.assertEqual(self.evaluate(size_op), 5) for _ in range(3): results.append(deq.eval()) time.sleep(0.1) self.assertEqual(len(enq_done), 1) - self.assertEqual(sess.run(size_op), 5) + self.assertEqual(self.evaluate(size_op), 5) # This dequeue will unblock the thread. results.append(deq.eval()) @@ -1477,7 +1477,7 @@ class PaddingFIFOQueueTest(test.TestCase): def blocking_dequeue(): # Will only complete after 4 enqueues complete. - results.extend(sess.run(deq)) + results.extend(self.evaluate(deq)) thread = self.checkedThread(target=blocking_dequeue) thread.start() @@ -1486,7 +1486,7 @@ class PaddingFIFOQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) self.assertEqual(len(results), 0) - sess.run(enq) + self.evaluate(enq) # Enough enqueued to unblock the dequeue thread.join() @@ -1517,7 +1517,7 @@ class PaddingFIFOQueueTest(test.TestCase): q.enqueue_many(input_tuple).run() output_tuple_t = q.dequeue_many(32) - output_tuple = sess.run(output_tuple_t) + output_tuple = self.evaluate(output_tuple_t) for (input_elem, output_elem) in zip(input_tuple, output_tuple): self.assertAllEqual(input_elem, output_elem) diff --git a/tensorflow/python/kernel_tests/parse_single_example_op_test.py b/tensorflow/python/kernel_tests/parse_single_example_op_test.py index a84895a287..3f50087282 100644 --- a/tensorflow/python/kernel_tests/parse_single_example_op_test.py +++ b/tensorflow/python/kernel_tests/parse_single_example_op_test.py @@ -107,7 +107,7 @@ class ParseExampleTest(test.TestCase): for result_dict in [out, out_with_example_name]: result = flatten_values_tensors_or_sparse(result_dict.values()) # Check values. - tf_result = sess.run(result) + tf_result = self.evaluate(result) _compare_output_to_expected(self, result_dict, expected_values, tf_result) diff --git a/tensorflow/python/kernel_tests/parsing_ops_test.py b/tensorflow/python/kernel_tests/parsing_ops_test.py index 8f359bd32c..1f677103dc 100644 --- a/tensorflow/python/kernel_tests/parsing_ops_test.py +++ b/tensorflow/python/kernel_tests/parsing_ops_test.py @@ -101,7 +101,7 @@ class ParseExampleTest(test.TestCase): out = parsing_ops.parse_example(**kwargs) result = flatten_values_tensors_or_sparse(out.values()) # Check values. - tf_result = sess.run(result) + tf_result = self.evaluate(result) _compare_output_to_expected(self, out, expected_values, tf_result) # Check shapes; if serialized is a Tensor we need its size to @@ -1614,7 +1614,7 @@ class DecodeJSONExampleTest(test.TestCase): shape=examples.shape, dtype=dtypes.string) binary_tensor = parsing_ops.decode_json_example(json_tensor) - binary_val = sess.run(binary_tensor) + binary_val = self.evaluate(binary_tensor) if examples.shape: self.assertShapeEqual(binary_val, json_tensor) @@ -1700,7 +1700,7 @@ class DecodeJSONExampleTest(test.TestCase): json_tensor = constant_op.constant(["{]"]) binary_tensor = parsing_ops.decode_json_example(json_tensor) with self.assertRaisesOpError("Error while parsing JSON"): - sess.run(binary_tensor) + self.evaluate(binary_tensor) class ParseTensorOpTest(test.TestCase): diff --git a/tensorflow/python/kernel_tests/pooling_ops_3d_test.py b/tensorflow/python/kernel_tests/pooling_ops_3d_test.py index e393c7a022..a8e962bc3a 100644 --- a/tensorflow/python/kernel_tests/pooling_ops_3d_test.py +++ b/tensorflow/python/kernel_tests/pooling_ops_3d_test.py @@ -81,7 +81,7 @@ class PoolingTest(test.TestCase): data_format=data_format) if data_format == "NCDHW": t = test_util.NCHWToNHWC(t) - vals = sess.run(t) + vals = self.evaluate(t) # Verifies values. actual = vals.flatten() self.assertAllClose(expected, actual) diff --git a/tensorflow/python/kernel_tests/pooling_ops_test.py b/tensorflow/python/kernel_tests/pooling_ops_test.py index 61628c4756..81222719f2 100644 --- a/tensorflow/python/kernel_tests/pooling_ops_test.py +++ b/tensorflow/python/kernel_tests/pooling_ops_test.py @@ -826,7 +826,7 @@ class PoolingTest(test.TestCase): strides=[1, 1, 1, 1], Targmax=dtypes.int64, padding="VALID") - out, argmax = sess.run([out_op, argmax_op]) + out, argmax = self.evaluate([out_op, argmax_op]) self.assertShapeEqual(out, out_op) self.assertShapeEqual(argmax, argmax_op) self.assertAllClose(out.ravel(), [1.0, 1.0, 1.0, 1.0]) diff --git a/tensorflow/python/kernel_tests/priority_queue_test.py b/tensorflow/python/kernel_tests/priority_queue_test.py index 73a9c81638..9be682ea52 100644 --- a/tensorflow/python/kernel_tests/priority_queue_test.py +++ b/tensorflow/python/kernel_tests/priority_queue_test.py @@ -50,7 +50,7 @@ class PriorityQueueTest(test.TestCase): enq.run() deq = q.dequeue_many(100) - deq_elem, deq_value_0, deq_value_1 = sess.run(deq) + deq_elem, deq_value_0, deq_value_1 = self.evaluate(deq) allowed = {} missed = set() @@ -81,7 +81,7 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) dequeue_op = q.dequeue_many(100) @@ -93,7 +93,7 @@ class PriorityQueueTest(test.TestCase): for t in enqueue_threads: t.start() - deq_elem, deq_value_0, deq_value_1 = sess.run(dequeue_op) + deq_elem, deq_value_0, deq_value_1 = self.evaluate(dequeue_op) for t in enqueue_threads: t.join() @@ -132,12 +132,12 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) dequeued = [] def dequeue(dequeue_op): - (dequeue_indices, dequeue_values) = sess.run(dequeue_op) + (dequeue_indices, dequeue_values) = self.evaluate(dequeue_op) self.assertAllEqual(dequeue_indices, dequeue_values) dequeued.extend(dequeue_indices) @@ -184,10 +184,10 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(dequeue_op, dequeued): - (dequeue_indices, dequeue_values) = sess.run(dequeue_op) + (dequeue_indices, dequeue_values) = self.evaluate(dequeue_op) self.assertAllEqual(dequeue_indices, dequeue_values) dequeue_wait.acquire() dequeued.extend(dequeue_indices) @@ -215,7 +215,7 @@ class PriorityQueueTest(test.TestCase): # We can't guarantee full sorting because we can't guarantee # that the dequeued.extend() call runs immediately after the - # sess.run() call. Here we're just happy everything came out. + # self.evaluate() call. Here we're just happy everything came out. self.assertAllEqual(set(dequeued), set(all_enqueued_values)) def testRoundTripInsertManyMultiThreadedReadOnceSorts(self): @@ -236,7 +236,7 @@ class PriorityQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) dequeue_op = q.dequeue_many(100) @@ -248,7 +248,7 @@ class PriorityQueueTest(test.TestCase): for t in enqueue_threads: t.start() - deq_elem, deq_value_0, deq_value_1 = sess.run(dequeue_op) + deq_elem, deq_value_0, deq_value_1 = self.evaluate(dequeue_op) for t in enqueue_threads: t.join() @@ -276,7 +276,7 @@ class PriorityQueueTest(test.TestCase): side_value_1 = np.random.rand(1000).astype(bytes) q.enqueue_many((elem, side_value_0, side_value_1)).run() deq = q.dequeue_many(1000) - deq_elem, deq_value_0, deq_value_1 = sess.run(deq) + deq_elem, deq_value_0, deq_value_1 = self.evaluate(deq) allowed = {} for e, v0, v1 in zip(elem, side_value_0, side_value_1): diff --git a/tensorflow/python/kernel_tests/py_func_test.py b/tensorflow/python/kernel_tests/py_func_test.py index b101da036e..c9cbe44a7f 100644 --- a/tensorflow/python/kernel_tests/py_func_test.py +++ b/tensorflow/python/kernel_tests/py_func_test.py @@ -307,9 +307,9 @@ class PyFuncTest(test.TestCase): with session_lib.Session() as sess: producer = iter(range(3)) x, = script_ops.py_func(lambda: next(producer), [], [dtypes.int64]) - self.assertEqual(sess.run(x), 0) - self.assertEqual(sess.run(x), 1) - self.assertEqual(sess.run(x), 2) + self.assertEqual(self.evaluate(x), 0) + self.assertEqual(self.evaluate(x), 1) + self.assertEqual(self.evaluate(x), 2) def testStateless(self): # Not using self.cached_session(), which disables optimization. @@ -317,9 +317,9 @@ class PyFuncTest(test.TestCase): producer = iter(range(3)) x, = script_ops.py_func( lambda: next(producer), [], [dtypes.int64], stateful=False) - self.assertEqual(sess.run(x), 0) - self.assertEqual(sess.run(x), 0) - self.assertEqual(sess.run(x), 0) + self.assertEqual(self.evaluate(x), 0) + self.assertEqual(self.evaluate(x), 0) + self.assertEqual(self.evaluate(x), 0) def testGradientFunction(self): # Input to tf.py_func is necessary, otherwise get_gradient_function() @@ -390,7 +390,7 @@ class PyFuncTest(test.TestCase): f = script_ops.py_func( do_nothing, [constant_op.constant(3, dtypes.int64)], [], stateful=False) with self.cached_session() as sess: - self.assertEqual(sess.run(f), []) + self.assertEqual(self.evaluate(f), []) def _testExceptionHandling(self, py_exp, tf_exp, eager=False): diff --git a/tensorflow/python/kernel_tests/qr_op_test.py b/tensorflow/python/kernel_tests/qr_op_test.py index 617b724204..305b5aa364 100644 --- a/tensorflow/python/kernel_tests/qr_op_test.py +++ b/tensorflow/python/kernel_tests/qr_op_test.py @@ -60,7 +60,7 @@ class QrOpTest(test.TestCase): q1, r1 = linalg_ops.qr(matrix1, full_matrices=full_matrices_) q2, r2 = linalg_ops.qr(matrix2, full_matrices=full_matrices_) all_ops += [q1, r1, q2, r2] - val = sess.run(all_ops) + val = self.evaluate(all_ops) for i in range(8): q = 4 * i self.assertAllEqual(val[q], val[q + 2]) # q1 == q2 @@ -129,7 +129,7 @@ def _GetQrOpTest(dtype_, shape_, full_matrices_, use_static_shape_): q_tf, r_tf = linalg_ops.qr(x_tf, full_matrices=full_matrices_) if use_static_shape_: - q_tf_val, r_tf_val = sess.run([q_tf, r_tf]) + q_tf_val, r_tf_val = self.evaluate([q_tf, r_tf]) else: q_tf_val, r_tf_val = sess.run([q_tf, r_tf], feed_dict={x_tf: x_np}) diff --git a/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py b/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py index 0023506b77..cab841741e 100644 --- a/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py +++ b/tensorflow/python/kernel_tests/random/multinomial_op_big_test.py @@ -39,7 +39,7 @@ class MultinomialTest(test.TestCase): num_samples=1000000, seed=15) for _ in range(100): - x = sess.run(samples) + x = self.evaluate(samples) indices, counts = np.unique(x, return_counts=True) for index, count in zip(indices, counts): if index in counts_by_indices.keys(): @@ -57,7 +57,7 @@ class MultinomialTest(test.TestCase): num_samples=1000000, seed=15) for _ in range(100): - x = sess.run(samples) + x = self.evaluate(samples) indices, counts = np.unique(x, return_counts=True) for index, count in zip(indices, counts): if index in counts_by_indices.keys(): @@ -79,7 +79,7 @@ class MultinomialTest(test.TestCase): # we'll run out of memory if we try to draw 1e9 samples directly # really should fit in 12GB of memory... for _ in range(100): - x = sess.run(samples) + x = self.evaluate(samples) indices, counts = np.unique(x, return_counts=True) for index, count in zip(indices, counts): if index in counts_by_indices.keys(): diff --git a/tensorflow/python/kernel_tests/random/random_gamma_test.py b/tensorflow/python/kernel_tests/random/random_gamma_test.py index 606e8862c4..d18e3feb04 100644 --- a/tensorflow/python/kernel_tests/random/random_gamma_test.py +++ b/tensorflow/python/kernel_tests/random/random_gamma_test.py @@ -48,7 +48,7 @@ class RandomGammaTest(test.TestCase): [num], alpha, beta=beta, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = sess.run(rng) + ret[i, :] = self.evaluate(rng) return ret return func diff --git a/tensorflow/python/kernel_tests/random/random_ops_test.py b/tensorflow/python/kernel_tests/random/random_ops_test.py index 6de894846b..76618316b2 100644 --- a/tensorflow/python/kernel_tests/random/random_ops_test.py +++ b/tensorflow/python/kernel_tests/random/random_ops_test.py @@ -49,9 +49,9 @@ class RandomOpTestCommon(test.TestCase): random_seed.set_random_seed(graph_seed) x = rng_func([num], min_or_mean, max_or_stddev, dtype=dtype, seed=op_seed) - y = sess.run(x) - z = sess.run(x) - w = sess.run(x) + y = self.evaluate(x) + z = self.evaluate(x) + w = self.evaluate(x) # We use exact equality here. If the random-number generator is producing # the same output, all three outputs will be bitwise identical. @@ -69,7 +69,7 @@ class RandomNormalTest(RandomOpTestCommon): [num], mean=mu, stddev=sigma, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = sess.run(rng) + ret[i, :] = self.evaluate(rng) return ret return func @@ -160,7 +160,7 @@ class TruncatedNormalTest(test.TestCase): [num], mean=mu, stddev=sigma, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = sess.run(rng) + ret[i, :] = self.evaluate(rng) return ret return func @@ -256,7 +256,7 @@ class RandomUniformTest(RandomOpTestCommon): [num], minval=minv, maxval=maxv, dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = sess.run(rng) + ret[i, :] = self.evaluate(rng) return ret return func diff --git a/tensorflow/python/kernel_tests/random/random_poisson_test.py b/tensorflow/python/kernel_tests/random/random_poisson_test.py index 95e48101f6..47c0858db7 100644 --- a/tensorflow/python/kernel_tests/random/random_poisson_test.py +++ b/tensorflow/python/kernel_tests/random/random_poisson_test.py @@ -43,7 +43,7 @@ class RandomPoissonTest(test.TestCase): rng = random_ops.random_poisson(lam, [num], dtype=dtype, seed=seed) ret = np.empty([10, num]) for i in xrange(10): - ret[i, :] = sess.run(rng) + ret[i, :] = self.evaluate(rng) return ret return func diff --git a/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py b/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py index f3fcf1eff7..ed4f5434d9 100644 --- a/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py +++ b/tensorflow/python/kernel_tests/random/random_shuffle_queue_test.py @@ -84,9 +84,9 @@ class RandomShuffleQueueTest(test.TestCase): dequeue_t = q.dequeue() results = [] for _ in range(2): - a, b = sess.run(dequeue_t) + a, b = self.evaluate(dequeue_t) results.append((a, b)) - a, b = sess.run(q.dequeue_many(3)) + a, b = self.evaluate(q.dequeue_many(3)) for i in range(3): results.append((a[i], b[i])) self.assertItemsEqual([(1, [5]), (2, [6]), (3, [7]), (4, [8]), (9, [10])], @@ -101,7 +101,7 @@ class RandomShuffleQueueTest(test.TestCase): # Run one producer thread for each element in elems. def enqueue(enqueue_op): - sess.run(enqueue_op) + self.evaluate(enqueue_op) threads = [ self.checkedThread( @@ -133,7 +133,7 @@ class RandomShuffleQueueTest(test.TestCase): results = [] def dequeue(): - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in enqueue_ops] for thread in threads: @@ -167,13 +167,13 @@ class RandomShuffleQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) for enqueue_op in enqueue_ops: - sess.run(enqueue_op) + self.evaluate(enqueue_op) results = [] def dequeue(): for _ in xrange(len(elems)): - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -197,7 +197,7 @@ class RandomShuffleQueueTest(test.TestCase): results = [] for _ in xrange(len(elems)): - x, y = sess.run(dequeued_t) + x, y = self.evaluate(dequeued_t) results.append((x, y)) self.assertItemsEqual(elems, results) @@ -321,7 +321,7 @@ class RandomShuffleQueueTest(test.TestCase): results = [] for _ in range(8): - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) results.append((float_val, [int_val[0], int_val[1]])) expected = list(zip(float_elems, int_elems)) * 2 self.assertItemsEqual(expected, results) @@ -368,20 +368,20 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() results = [] - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) self.assertEqual(float_val.shape, dequeued_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_t[1].get_shape()) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_single_t[1].get_shape()) results.append((float_val, int_val.tolist())) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) results.append((float_val, int_val.tolist())) self.assertItemsEqual(zip(float_elems, int_elems), results) @@ -402,21 +402,21 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() results = [] - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) # dequeue_up_to has undefined shape. self.assertEqual([None], dequeued_t[0].get_shape().as_list()) self.assertEqual([None, 2], dequeued_t[1].get_shape().as_list()) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = sess.run(dequeued_t) + float_val, int_val = self.evaluate(dequeued_t) results.extend(zip(float_val, int_val.tolist())) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) self.assertEqual(float_val.shape, dequeued_single_t[0].get_shape()) self.assertEqual(int_val.shape, dequeued_single_t[1].get_shape()) results.append((float_val, int_val.tolist())) - float_val, int_val = sess.run(dequeued_single_t) + float_val, int_val = self.evaluate(dequeued_single_t) results.append((float_val, int_val.tolist())) self.assertItemsEqual(zip(float_elems, int_elems), results) @@ -442,7 +442,7 @@ class RandomShuffleQueueTest(test.TestCase): # Enqueue 100 items in parallel on 10 threads. def enqueue(): - sess.run(enqueue_op) + self.evaluate(enqueue_op) threads = [self.checkedThread(target=enqueue) for _ in range(10)] for thread in threads: @@ -466,7 +466,7 @@ class RandomShuffleQueueTest(test.TestCase): dequeued_elems = [] def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t)) + dequeued_elems.extend(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in range(10)] for thread in threads: @@ -489,7 +489,7 @@ class RandomShuffleQueueTest(test.TestCase): dequeued_elems = [] def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t)) + dequeued_elems.extend(self.evaluate(dequeued_t)) threads = [self.checkedThread(target=dequeue) for _ in range(10)] for thread in threads: @@ -515,7 +515,7 @@ class RandomShuffleQueueTest(test.TestCase): dequeued_elems = [] def dequeue(dequeue_op): - dequeued_elems.extend(sess.run(dequeue_op)) + dequeued_elems.extend(self.evaluate(dequeue_op)) threads = [] for dequeue_op in dequeue_ops: @@ -539,10 +539,10 @@ class RandomShuffleQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t).tolist()) + dequeued_elems.extend(self.evaluate(dequeued_t).tolist()) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -566,10 +566,10 @@ class RandomShuffleQueueTest(test.TestCase): # The enqueue_op should run after the dequeue op has blocked. # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) - sess.run(enqueue_op) + self.evaluate(enqueue_op) def dequeue(): - dequeued_elems.extend(sess.run(dequeued_t).tolist()) + dequeued_elems.extend(self.evaluate(dequeued_t).tolist()) enqueue_thread = self.checkedThread(target=enqueue) dequeue_thread = self.checkedThread(target=dequeue) @@ -665,18 +665,18 @@ class RandomShuffleQueueTest(test.TestCase): results = [] # Manually dequeue until we hit min_size. - results.append(sess.run(dequeued_t)) - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) + results.append(self.evaluate(dequeued_t)) def blocking_dequeue(): - results.append(sess.run(dequeued_t)) - results.append(sess.run(dequeued_t)) + results.append(self.evaluate(dequeued_t)) + results.append(self.evaluate(dequeued_t)) self.assertItemsEqual(elems, results) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=blocking_dequeue) dequeue_thread.start() @@ -701,7 +701,7 @@ class RandomShuffleQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) finished.append(True) dequeue_thread = self.checkedThread(target=dequeue) @@ -727,12 +727,12 @@ class RandomShuffleQueueTest(test.TestCase): progress = [] # Must be mutable def dequeue(): - self.assertItemsEqual(elems, sess.run(dequeued_t)) + self.assertItemsEqual(elems, self.evaluate(dequeued_t)) progress.append(1) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) progress.append(2) self.assertEqual(len(progress), 0) @@ -763,9 +763,9 @@ class RandomShuffleQueueTest(test.TestCase): results = [] def dequeue(): - results.extend(sess.run(dequeued_t)) + results.extend(self.evaluate(dequeued_t)) self.assertEquals(3, len(results)) - results.extend(sess.run(dequeued_t)) + results.extend(self.evaluate(dequeued_t)) self.assertEquals(4, len(results)) dequeue_thread = self.checkedThread(target=dequeue) @@ -794,11 +794,11 @@ class RandomShuffleQueueTest(test.TestCase): results = [] def dequeue(): - results.extend(sess.run(dequeued_t)) + results.extend(self.evaluate(dequeued_t)) self.assertEquals(3, len(results)) # min_after_dequeue is 2, we ask for 3 elements, and we end up only # getting the remaining 1. - results.extend(sess.run(dequeued_t)) + results.extend(self.evaluate(dequeued_t)) self.assertEquals(4, len(results)) dequeue_thread = self.checkedThread(target=dequeue) @@ -824,16 +824,16 @@ class RandomShuffleQueueTest(test.TestCase): results = [] def dequeue(): - results.extend(sess.run(dequeued_t)) + results.extend(self.evaluate(dequeued_t)) self.assertEqual(len(results), 3) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) # While the last dequeue failed, we want to insure that it returns # any elements that it potentially reserved to dequeue. Thus the # next cleanup should return a single element. - results.extend(sess.run(cleanup_dequeue_t)) + results.extend(self.evaluate(cleanup_dequeue_t)) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -854,7 +854,7 @@ class RandomShuffleQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -874,7 +874,7 @@ class RandomShuffleQueueTest(test.TestCase): # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.OutOfRangeError, "is closed and has insufficient"): - sess.run(dequeued_t) + self.evaluate(dequeued_t) dequeue_thread = self.checkedThread(target=dequeue) dequeue_thread.start() @@ -922,7 +922,7 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -950,7 +950,7 @@ class RandomShuffleQueueTest(test.TestCase): enqueue_op.run() def blocking_enqueue(): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread = self.checkedThread(target=blocking_enqueue) thread.start() @@ -987,11 +987,11 @@ class RandomShuffleQueueTest(test.TestCase): def blocking_enqueue(): # Expect the operation to succeed since it will complete # before the queue is closed. - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) # Expect the operation to fail due to the queue being closed. with self.assertRaisesRegexp(errors_impl.CancelledError, "closed"): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread1 = self.checkedThread(target=blocking_enqueue) thread1.start() @@ -1001,7 +1001,7 @@ class RandomShuffleQueueTest(test.TestCase): time.sleep(0.1) def blocking_close(): - sess.run(close_op) + self.evaluate(close_op) thread2 = self.checkedThread(target=blocking_close) thread2.start() @@ -1032,7 +1032,7 @@ class RandomShuffleQueueTest(test.TestCase): def blocking_enqueue(): # This will block until the dequeue after the close. - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) thread1 = self.checkedThread(target=blocking_enqueue) thread1.start() @@ -1050,7 +1050,7 @@ class RandomShuffleQueueTest(test.TestCase): time.sleep(0.1) def blocking_close(): - sess.run(close_op) + self.evaluate(close_op) thread2 = self.checkedThread(target=blocking_close) thread2.start() @@ -1064,7 +1064,7 @@ class RandomShuffleQueueTest(test.TestCase): # At this point the close operation will complete, so the next enqueue # will fail. with self.assertRaisesRegexp(errors_impl.CancelledError, "closed"): - sess.run(blocking_enqueue_op) + self.evaluate(blocking_enqueue_op) def testSharedQueueSameSession(self): with self.cached_session(): @@ -1216,23 +1216,23 @@ class RandomShuffleQueueTest(test.TestCase): def _blockingDequeue(self, sess, dequeue_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_op) + self.evaluate(dequeue_op) def _blockingDequeueMany(self, sess, dequeue_many_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_many_op) + self.evaluate(dequeue_many_op) def _blockingDequeueUpTo(self, sess, dequeue_up_to_op): with self.assertRaisesOpError("was cancelled"): - sess.run(dequeue_up_to_op) + self.evaluate(dequeue_up_to_op) def _blockingEnqueue(self, sess, enqueue_op): with self.assertRaisesOpError("was cancelled"): - sess.run(enqueue_op) + self.evaluate(enqueue_op) def _blockingEnqueueMany(self, sess, enqueue_many_op): with self.assertRaisesOpError("was cancelled"): - sess.run(enqueue_many_op) + self.evaluate(enqueue_many_op) def testResetOfBlockingOperation(self): with self.cached_session() as sess: @@ -1383,7 +1383,7 @@ class RandomShuffleQueueTest(test.TestCase): def blocking_enqueue(): enq_done.append(False) # This will fill the queue and then block until enough dequeues happen. - sess.run(enq) + self.evaluate(enq) enq_done.append(True) thread = self.checkedThread(target=blocking_enqueue) @@ -1393,14 +1393,14 @@ class RandomShuffleQueueTest(test.TestCase): results = [] results.append(deq.eval()) # Will only complete after the enqueue starts. self.assertEqual(len(enq_done), 1) - self.assertEqual(sess.run(size_op), 5) + self.assertEqual(self.evaluate(size_op), 5) for _ in range(3): results.append(deq.eval()) time.sleep(0.1) self.assertEqual(len(enq_done), 1) - self.assertEqual(sess.run(size_op), 5) + self.assertEqual(self.evaluate(size_op), 5) # This dequeue will unblock the thread. results.append(deq.eval()) @@ -1426,7 +1426,7 @@ class RandomShuffleQueueTest(test.TestCase): def blocking_dequeue(): # Will only complete after 4 enqueues complete. - results.extend(sess.run(deq)) + results.extend(self.evaluate(deq)) thread = self.checkedThread(target=blocking_dequeue) thread.start() @@ -1435,7 +1435,7 @@ class RandomShuffleQueueTest(test.TestCase): # TODO(mrry): Figure out how to do this without sleeping. time.sleep(0.1) self.assertEqual(len(results), 0) - sess.run(enq) + self.evaluate(enq) # Enough enqueued to unblock the dequeue thread.join() diff --git a/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py b/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py index 13f97a9367..d80bea955e 100644 --- a/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py +++ b/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py @@ -62,7 +62,7 @@ class StatelessOpsTest(test.TestCase): for stateless_op, stateful_op in cases: stateful = stateful_op(seed=seed[1]) pure = stateless_op(seed=preseed) - self.assertAllEqual(stateful.eval(), self.evaluate(pure)) + self.assertAllEqual(self.evaluate(stateful), self.evaluate(pure)) def _test_determinism(self, cases): # Stateless values should be equal iff the seeds are equal (roughly) diff --git a/tensorflow/python/kernel_tests/reader_ops_test.py b/tensorflow/python/kernel_tests/reader_ops_test.py index 18a8a3d547..a4a18c5219 100644 --- a/tensorflow/python/kernel_tests/reader_ops_test.py +++ b/tensorflow/python/kernel_tests/reader_ops_test.py @@ -140,147 +140,143 @@ class TFCompressionTestCase(test.TestCase): class IdentityReaderTest(test.TestCase): - def _ExpectRead(self, sess, key, value, expected): - k, v = sess.run([key, value]) + def _ExpectRead(self, key, value, expected): + k, v = self.evaluate([key, value]) self.assertAllEqual(expected, k) self.assertAllEqual(expected, v) def testOneEpoch(self): - with self.cached_session() as sess: - reader = io_ops.IdentityReader("test_reader") - work_completed = reader.num_work_units_completed() - produced = reader.num_records_produced() - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - queued_length = queue.size() - key, value = reader.read(queue) + reader = io_ops.IdentityReader("test_reader") + work_completed = reader.num_work_units_completed() + produced = reader.num_records_produced() + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + queued_length = queue.size() + key, value = reader.read(queue) - self.assertAllEqual(0, self.evaluate(work_completed)) - self.assertAllEqual(0, self.evaluate(produced)) - self.assertAllEqual(0, self.evaluate(queued_length)) + self.assertAllEqual(0, self.evaluate(work_completed)) + self.assertAllEqual(0, self.evaluate(produced)) + self.assertAllEqual(0, self.evaluate(queued_length)) - queue.enqueue_many([["A", "B", "C"]]).run() - queue.close().run() - self.assertAllEqual(3, self.evaluate(queued_length)) + self.evaluate(queue.enqueue_many([["A", "B", "C"]])) + self.evaluate(queue.close()) + self.assertAllEqual(3, self.evaluate(queued_length)) - self._ExpectRead(sess, key, value, b"A") - self.assertAllEqual(1, self.evaluate(produced)) + self._ExpectRead(key, value, b"A") + self.assertAllEqual(1, self.evaluate(produced)) - self._ExpectRead(sess, key, value, b"B") + self._ExpectRead(key, value, b"B") - self._ExpectRead(sess, key, value, b"C") - self.assertAllEqual(3, self.evaluate(produced)) - self.assertAllEqual(0, self.evaluate(queued_length)) + self._ExpectRead(key, value, b"C") + self.assertAllEqual(3, self.evaluate(produced)) + self.assertAllEqual(0, self.evaluate(queued_length)) - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - sess.run([key, value]) + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + self.evaluate([key, value]) - self.assertAllEqual(3, self.evaluate(work_completed)) - self.assertAllEqual(3, self.evaluate(produced)) - self.assertAllEqual(0, self.evaluate(queued_length)) + self.assertAllEqual(3, self.evaluate(work_completed)) + self.assertAllEqual(3, self.evaluate(produced)) + self.assertAllEqual(0, self.evaluate(queued_length)) def testMultipleEpochs(self): - with self.cached_session() as sess: - reader = io_ops.IdentityReader("test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - enqueue = queue.enqueue_many([["DD", "EE"]]) - key, value = reader.read(queue) - - enqueue.run() - self._ExpectRead(sess, key, value, b"DD") - self._ExpectRead(sess, key, value, b"EE") - enqueue.run() - self._ExpectRead(sess, key, value, b"DD") - self._ExpectRead(sess, key, value, b"EE") - enqueue.run() - self._ExpectRead(sess, key, value, b"DD") - self._ExpectRead(sess, key, value, b"EE") - queue.close().run() - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - sess.run([key, value]) + reader = io_ops.IdentityReader("test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + enqueue = queue.enqueue_many([["DD", "EE"]]) + key, value = reader.read(queue) + + self.evaluate(enqueue) + self._ExpectRead(key, value, b"DD") + self._ExpectRead(key, value, b"EE") + self.evaluate(enqueue) + self._ExpectRead(key, value, b"DD") + self._ExpectRead(key, value, b"EE") + self.evaluate(enqueue) + self._ExpectRead(key, value, b"DD") + self._ExpectRead(key, value, b"EE") + self.evaluate(queue.close()) + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + self.evaluate([key, value]) def testSerializeRestore(self): - with self.cached_session() as sess: - reader = io_ops.IdentityReader("test_reader") - produced = reader.num_records_produced() - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - queue.enqueue_many([["X", "Y", "Z"]]).run() - key, value = reader.read(queue) - - self._ExpectRead(sess, key, value, b"X") - self.assertAllEqual(1, self.evaluate(produced)) - state = reader.serialize_state().eval() - - self._ExpectRead(sess, key, value, b"Y") - self._ExpectRead(sess, key, value, b"Z") - self.assertAllEqual(3, self.evaluate(produced)) - - queue.enqueue_many([["Y", "Z"]]).run() - queue.close().run() - reader.restore_state(state).run() - self.assertAllEqual(1, self.evaluate(produced)) - self._ExpectRead(sess, key, value, b"Y") - self._ExpectRead(sess, key, value, b"Z") - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - sess.run([key, value]) - self.assertAllEqual(3, self.evaluate(produced)) - - self.assertEqual(bytes, type(state)) - - with self.assertRaises(ValueError): - reader.restore_state([]) - - with self.assertRaises(ValueError): - reader.restore_state([state, state]) - - with self.assertRaisesOpError( - "Could not parse state for IdentityReader 'test_reader'"): - reader.restore_state(state[1:]).run() - - with self.assertRaisesOpError( - "Could not parse state for IdentityReader 'test_reader'"): - reader.restore_state(state[:-1]).run() - - with self.assertRaisesOpError( - "Could not parse state for IdentityReader 'test_reader'"): - reader.restore_state(state + b"ExtraJunk").run() - - with self.assertRaisesOpError( - "Could not parse state for IdentityReader 'test_reader'"): - reader.restore_state(b"PREFIX" + state).run() - - with self.assertRaisesOpError( - "Could not parse state for IdentityReader 'test_reader'"): - reader.restore_state(b"BOGUS" + state[5:]).run() + reader = io_ops.IdentityReader("test_reader") + produced = reader.num_records_produced() + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + self.evaluate(queue.enqueue_many([["X", "Y", "Z"]])) + key, value = reader.read(queue) + + self._ExpectRead(key, value, b"X") + self.assertAllEqual(1, self.evaluate(produced)) + state = self.evaluate(reader.serialize_state()) + + self._ExpectRead(key, value, b"Y") + self._ExpectRead(key, value, b"Z") + self.assertAllEqual(3, self.evaluate(produced)) + + self.evaluate(queue.enqueue_many([["Y", "Z"]])) + self.evaluate(queue.close()) + self.evaluate(reader.restore_state(state)) + self.assertAllEqual(1, self.evaluate(produced)) + self._ExpectRead(key, value, b"Y") + self._ExpectRead(key, value, b"Z") + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + self.evaluate([key, value]) + self.assertAllEqual(3, self.evaluate(produced)) + + self.assertEqual(bytes, type(state)) + + with self.assertRaises(ValueError): + reader.restore_state([]) + + with self.assertRaises(ValueError): + reader.restore_state([state, state]) + + with self.assertRaisesOpError( + "Could not parse state for IdentityReader 'test_reader'"): + self.evaluate(reader.restore_state(state[1:])) + + with self.assertRaisesOpError( + "Could not parse state for IdentityReader 'test_reader'"): + self.evaluate(reader.restore_state(state[:-1])) + + with self.assertRaisesOpError( + "Could not parse state for IdentityReader 'test_reader'"): + self.evaluate(reader.restore_state(state + b"ExtraJunk")) + + with self.assertRaisesOpError( + "Could not parse state for IdentityReader 'test_reader'"): + self.evaluate(reader.restore_state(b"PREFIX" + state)) + + with self.assertRaisesOpError( + "Could not parse state for IdentityReader 'test_reader'"): + self.evaluate(reader.restore_state(b"BOGUS" + state[5:])) def testReset(self): - with self.cached_session() as sess: - reader = io_ops.IdentityReader("test_reader") - work_completed = reader.num_work_units_completed() - produced = reader.num_records_produced() - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - queued_length = queue.size() - key, value = reader.read(queue) + reader = io_ops.IdentityReader("test_reader") + work_completed = reader.num_work_units_completed() + produced = reader.num_records_produced() + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + queued_length = queue.size() + key, value = reader.read(queue) - queue.enqueue_many([["X", "Y", "Z"]]).run() - self._ExpectRead(sess, key, value, b"X") - self.assertLess(0, self.evaluate(queued_length)) - self.assertAllEqual(1, self.evaluate(produced)) + self.evaluate(queue.enqueue_many([["X", "Y", "Z"]])) + self._ExpectRead(key, value, b"X") + self.assertLess(0, self.evaluate(queued_length)) + self.assertAllEqual(1, self.evaluate(produced)) - self._ExpectRead(sess, key, value, b"Y") - self.assertLess(0, self.evaluate(work_completed)) - self.assertAllEqual(2, self.evaluate(produced)) + self._ExpectRead(key, value, b"Y") + self.assertLess(0, self.evaluate(work_completed)) + self.assertAllEqual(2, self.evaluate(produced)) - reader.reset().run() - self.assertAllEqual(0, self.evaluate(work_completed)) - self.assertAllEqual(0, self.evaluate(produced)) - self.assertAllEqual(1, self.evaluate(queued_length)) - self._ExpectRead(sess, key, value, b"Z") + self.evaluate(reader.reset()) + self.assertAllEqual(0, self.evaluate(work_completed)) + self.assertAllEqual(0, self.evaluate(produced)) + self.assertAllEqual(1, self.evaluate(queued_length)) + self._ExpectRead(key, value, b"Z") - queue.enqueue_many([["K", "L"]]).run() - self._ExpectRead(sess, key, value, b"K") + self.evaluate(queue.enqueue_many([["K", "L"]])) + self._ExpectRead(key, value, b"K") class WholeFileReaderTest(test.TestCase): @@ -301,44 +297,42 @@ class WholeFileReaderTest(test.TestCase): os.remove(fn) super(WholeFileReaderTest, self).tearDown() - def _ExpectRead(self, sess, key, value, index): - k, v = sess.run([key, value]) + def _ExpectRead(self, key, value, index): + k, v = self.evaluate([key, value]) self.assertAllEqual(compat.as_bytes(self._filenames[index]), k) self.assertAllEqual(self._content[index], v) def testOneEpoch(self): - with self.cached_session() as sess: - reader = io_ops.WholeFileReader("test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - queue.enqueue_many([self._filenames]).run() - queue.close().run() - key, value = reader.read(queue) + reader = io_ops.WholeFileReader("test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + self.evaluate(queue.enqueue_many([self._filenames])) + self.evaluate(queue.close()) + key, value = reader.read(queue) - self._ExpectRead(sess, key, value, 0) - self._ExpectRead(sess, key, value, 1) - self._ExpectRead(sess, key, value, 2) + self._ExpectRead(key, value, 0) + self._ExpectRead(key, value, 1) + self._ExpectRead(key, value, 2) - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - sess.run([key, value]) + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + self.evaluate([key, value]) def testInfiniteEpochs(self): - with self.cached_session() as sess: - reader = io_ops.WholeFileReader("test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - enqueue = queue.enqueue_many([self._filenames]) - key, value = reader.read(queue) - - enqueue.run() - self._ExpectRead(sess, key, value, 0) - self._ExpectRead(sess, key, value, 1) - enqueue.run() - self._ExpectRead(sess, key, value, 2) - self._ExpectRead(sess, key, value, 0) - self._ExpectRead(sess, key, value, 1) - enqueue.run() - self._ExpectRead(sess, key, value, 2) - self._ExpectRead(sess, key, value, 0) + reader = io_ops.WholeFileReader("test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + enqueue = queue.enqueue_many([self._filenames]) + key, value = reader.read(queue) + + self.evaluate(enqueue) + self._ExpectRead(key, value, 0) + self._ExpectRead(key, value, 1) + self.evaluate(enqueue) + self._ExpectRead(key, value, 2) + self._ExpectRead(key, value, 0) + self._ExpectRead(key, value, 1) + self.evaluate(enqueue) + self._ExpectRead(key, value, 2) + self._ExpectRead(key, value, 0) class TextLineReaderTest(test.TestCase): @@ -366,22 +360,21 @@ class TextLineReaderTest(test.TestCase): return filenames def _testOneEpoch(self, files): - with self.cached_session() as sess: - reader = io_ops.TextLineReader(name="test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) + reader = io_ops.TextLineReader(name="test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(self._num_lines): - k, v = sess.run([key, value]) - self.assertAllEqual("%s:%d" % (files[i], j + 1), compat.as_text(k)) - self.assertAllEqual(self._LineText(i, j), v) + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(self._num_lines): + k, v = self.evaluate([key, value]) + self.assertAllEqual("%s:%d" % (files[i], j + 1), compat.as_text(k)) + self.assertAllEqual(self._LineText(i, j), v) - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) def testOneEpochLF(self): self._testOneEpoch(self._CreateFiles(crlf=False)) @@ -391,22 +384,21 @@ class TextLineReaderTest(test.TestCase): def testSkipHeaderLines(self): files = self._CreateFiles() - with self.cached_session() as sess: - reader = io_ops.TextLineReader(skip_header_lines=1, name="test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) + reader = io_ops.TextLineReader(skip_header_lines=1, name="test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(self._num_lines - 1): - k, v = sess.run([key, value]) - self.assertAllEqual("%s:%d" % (files[i], j + 2), compat.as_text(k)) - self.assertAllEqual(self._LineText(i, j + 1), v) + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(self._num_lines - 1): + k, v = self.evaluate([key, value]) + self.assertAllEqual("%s:%d" % (files[i], j + 2), compat.as_text(k)) + self.assertAllEqual(self._LineText(i, j + 1), v) - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) class FixedLengthRecordReaderTest(TFCompressionTestCase): @@ -522,55 +514,53 @@ class FixedLengthRecordReaderTest(TFCompressionTestCase): # gap_bytes=hop_bytes-record_bytes def _TestOneEpoch(self, files, num_records, gap_bytes, encoding=None): hop_bytes = 0 if gap_bytes == 0 else self._record_bytes + gap_bytes - with self.cached_session() as sess: - reader = io_ops.FixedLengthRecordReader( - header_bytes=self._header_bytes, - record_bytes=self._record_bytes, - footer_bytes=self._footer_bytes, - hop_bytes=hop_bytes, - encoding=encoding, - name="test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) - - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(num_records): - k, v = sess.run([key, value]) - self.assertAllEqual("%s:%d" % (files[i], j), compat.as_text(k)) - self.assertAllEqual(self._Record(i, j), v) - - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + reader = io_ops.FixedLengthRecordReader( + header_bytes=self._header_bytes, + record_bytes=self._record_bytes, + footer_bytes=self._footer_bytes, + hop_bytes=hop_bytes, + encoding=encoding, + name="test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) + + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(num_records): + k, v = self.evaluate([key, value]) + self.assertAllEqual("%s:%d" % (files[i], j), compat.as_text(k)) + self.assertAllEqual(self._Record(i, j), v) + + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) def _TestOneEpochWithHopBytes(self, files, num_overlapped_records, encoding=None): - with self.cached_session() as sess: - reader = io_ops.FixedLengthRecordReader( - header_bytes=self._header_bytes, - record_bytes=self._record_bytes, - footer_bytes=self._footer_bytes, - hop_bytes=self._hop_bytes, - encoding=encoding, - name="test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) - - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(num_overlapped_records): - k, v = sess.run([key, value]) - self.assertAllEqual("%s:%d" % (files[i], j), compat.as_text(k)) - self.assertAllEqual(self._OverlappedRecord(i, j), v) - - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + reader = io_ops.FixedLengthRecordReader( + header_bytes=self._header_bytes, + record_bytes=self._record_bytes, + footer_bytes=self._footer_bytes, + hop_bytes=self._hop_bytes, + encoding=encoding, + name="test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) + + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(num_overlapped_records): + k, v = self.evaluate([key, value]) + self.assertAllEqual("%s:%d" % (files[i], j), compat.as_text(k)) + self.assertAllEqual(self._OverlappedRecord(i, j), v) + + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) def testOneEpoch(self): for num_records in [0, 7]: @@ -621,84 +611,80 @@ class TFRecordReaderTest(TFCompressionTestCase): def testOneEpoch(self): files = self._CreateFiles() - with self.cached_session() as sess: - reader = io_ops.TFRecordReader(name="test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) - - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(self._num_records): - k, v = sess.run([key, value]) - self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) - self.assertAllEqual(self._Record(i, j), v) - - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + reader = io_ops.TFRecordReader(name="test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) + + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(self._num_records): + k, v = self.evaluate([key, value]) + self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) + self.assertAllEqual(self._Record(i, j), v) + + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) def testReadUpTo(self): files = self._CreateFiles() - with self.cached_session() as sess: - reader = io_ops.TFRecordReader(name="test_reader") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - batch_size = 3 - key, value = reader.read_up_to(queue, batch_size) - - queue.enqueue_many([files]).run() - queue.close().run() - num_k = 0 - num_v = 0 - - while True: - try: - k, v = sess.run([key, value]) - # Test reading *up to* batch_size records - self.assertLessEqual(len(k), batch_size) - self.assertLessEqual(len(v), batch_size) - num_k += len(k) - num_v += len(v) - except errors_impl.OutOfRangeError: - break - - # Test that we have read everything - self.assertEqual(self._num_files * self._num_records, num_k) - self.assertEqual(self._num_files * self._num_records, num_v) + reader = io_ops.TFRecordReader(name="test_reader") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + batch_size = 3 + key, value = reader.read_up_to(queue, batch_size) + + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + num_k = 0 + num_v = 0 + + while True: + try: + k, v = self.evaluate([key, value]) + # Test reading *up to* batch_size records + self.assertLessEqual(len(k), batch_size) + self.assertLessEqual(len(v), batch_size) + num_k += len(k) + num_v += len(v) + except errors_impl.OutOfRangeError: + break + + # Test that we have read everything + self.assertEqual(self._num_files * self._num_records, num_k) + self.assertEqual(self._num_files * self._num_records, num_v) def testReadZlibFiles(self): options = tf_record.TFRecordOptions(TFRecordCompressionType.ZLIB) files = self._CreateFiles(options) - with self.cached_session() as sess: - reader = io_ops.TFRecordReader(name="test_reader", options=options) - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) - - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(self._num_records): - k, v = sess.run([key, value]) - self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) - self.assertAllEqual(self._Record(i, j), v) + reader = io_ops.TFRecordReader(name="test_reader", options=options) + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) + + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(self._num_records): + k, v = self.evaluate([key, value]) + self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) + self.assertAllEqual(self._Record(i, j), v) def testReadGzipFiles(self): options = tf_record.TFRecordOptions(TFRecordCompressionType.GZIP) files = self._CreateFiles(options) - with self.cached_session() as sess: - reader = io_ops.TFRecordReader(name="test_reader", options=options) - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) + reader = io_ops.TFRecordReader(name="test_reader", options=options) + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) - queue.enqueue_many([files]).run() - queue.close().run() - for i in range(self._num_files): - for j in range(self._num_records): - k, v = sess.run([key, value]) - self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) - self.assertAllEqual(self._Record(i, j), v) + self.evaluate(queue.enqueue_many([files])) + self.evaluate(queue.close()) + for i in range(self._num_files): + for j in range(self._num_records): + k, v = self.evaluate([key, value]) + self.assertTrue(compat.as_text(k).startswith("%s:" % files[i])) + self.assertAllEqual(self._Record(i, j), v) class AsyncReaderTest(test.TestCase): @@ -724,7 +710,7 @@ class AsyncReaderTest(test.TestCase): thread_data.append(thread_data_t(t, queue, output)) # Start all readers. They are all blocked waiting for queue entries. - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for d in thread_data: d.thread.start() @@ -733,7 +719,7 @@ class AsyncReaderTest(test.TestCase): fname = os.path.join(self.get_temp_dir(), "deadlock.%s.txt" % i) with open(fname, "wb") as f: f.write(("file-%s" % i).encode()) - d.queue.enqueue_many([[fname]]).run() + self.evaluate(d.queue.enqueue_many([[fname]])) d.thread.join() self.assertEqual([[("file-%s" % i).encode()]], d.output) @@ -752,22 +738,21 @@ class LMDBReaderTest(test.TestCase): shutil.copy(path, self.db_path) def testReadFromFile(self): - with self.cached_session() as sess: - reader = io_ops.LMDBReader(name="test_read_from_file") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) - - queue.enqueue([self.db_path]).run() - queue.close().run() - for i in range(10): - k, v = sess.run([key, value]) - self.assertAllEqual(compat.as_bytes(k), compat.as_bytes(str(i))) - self.assertAllEqual( - compat.as_bytes(v), compat.as_bytes(str(chr(ord("a") + i)))) - - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + reader = io_ops.LMDBReader(name="test_read_from_file") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) + + self.evaluate(queue.enqueue([self.db_path])) + self.evaluate(queue.close()) + for i in range(10): + k, v = self.evaluate([key, value]) + self.assertAllEqual(compat.as_bytes(k), compat.as_bytes(str(i))) + self.assertAllEqual( + compat.as_bytes(v), compat.as_bytes(str(chr(ord("a") + i)))) + + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) def testReadFromSameFile(self): with self.cached_session() as sess: @@ -782,29 +767,28 @@ class LMDBReaderTest(test.TestCase): threads = queue_runner_impl.start_queue_runners(sess, coord=coord) for _ in range(3): for _ in range(10): - k1, v1, k2, v2 = sess.run([key1, value1, key2, value2]) + k1, v1, k2, v2 = self.evaluate([key1, value1, key2, value2]) self.assertAllEqual(compat.as_bytes(k1), compat.as_bytes(k2)) self.assertAllEqual(compat.as_bytes(v1), compat.as_bytes(v2)) coord.request_stop() coord.join(threads) def testReadFromFolder(self): - with self.cached_session() as sess: - reader = io_ops.LMDBReader(name="test_read_from_folder") - queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) - key, value = reader.read(queue) - - queue.enqueue([self.db_path]).run() - queue.close().run() - for i in range(10): - k, v = sess.run([key, value]) - self.assertAllEqual(compat.as_bytes(k), compat.as_bytes(str(i))) - self.assertAllEqual( - compat.as_bytes(v), compat.as_bytes(str(chr(ord("a") + i)))) - - with self.assertRaisesOpError("is closed and has insufficient elements " - "\\(requested 1, current size 0\\)"): - k, v = sess.run([key, value]) + reader = io_ops.LMDBReader(name="test_read_from_folder") + queue = data_flow_ops.FIFOQueue(99, [dtypes.string], shapes=()) + key, value = reader.read(queue) + + self.evaluate(queue.enqueue([self.db_path])) + self.evaluate(queue.close()) + for i in range(10): + k, v = self.evaluate([key, value]) + self.assertAllEqual(compat.as_bytes(k), compat.as_bytes(str(i))) + self.assertAllEqual( + compat.as_bytes(v), compat.as_bytes(str(chr(ord("a") + i)))) + + with self.assertRaisesOpError("is closed and has insufficient elements " + "\\(requested 1, current size 0\\)"): + k, v = self.evaluate([key, value]) def testReadFromFileRepeatedly(self): with self.cached_session() as sess: @@ -819,7 +803,7 @@ class LMDBReaderTest(test.TestCase): for _ in range(3): # Go over all 10 records each time. for j in range(10): - k, v = sess.run([key, value]) + k, v = self.evaluate([key, value]) self.assertAllEqual(compat.as_bytes(k), compat.as_bytes(str(j))) self.assertAllEqual( compat.as_bytes(v), compat.as_bytes(str(chr(ord("a") + j)))) diff --git a/tensorflow/python/kernel_tests/record_input_test.py b/tensorflow/python/kernel_tests/record_input_test.py index ebb9872f22..74020667d9 100644 --- a/tensorflow/python/kernel_tests/record_input_test.py +++ b/tensorflow/python/kernel_tests/record_input_test.py @@ -54,7 +54,7 @@ class RecordInputOpTest(test.TestCase): batch_size=1, name="record_input").get_yield_op() - self.assertEqual(sess.run(yield_op), b"0000000000") + self.assertEqual(self.evaluate(yield_op), b"0000000000") def testRecordInputSimpleGzip(self): with self.cached_session() as sess: @@ -73,7 +73,7 @@ class RecordInputOpTest(test.TestCase): compression_type=tf_record.TFRecordCompressionType.GZIP).get_yield_op( ) - self.assertEqual(sess.run(yield_op), b"0000000000") + self.assertEqual(self.evaluate(yield_op), b"0000000000") def testRecordInputSimpleZlib(self): with self.cached_session() as sess: @@ -92,7 +92,7 @@ class RecordInputOpTest(test.TestCase): compression_type=tf_record.TFRecordCompressionType.ZLIB).get_yield_op( ) - self.assertEqual(sess.run(yield_op), b"0000000000") + self.assertEqual(self.evaluate(yield_op), b"0000000000") def testRecordInputEpochs(self): files = 100 @@ -117,7 +117,7 @@ class RecordInputOpTest(test.TestCase): for _ in range(3): epoch_set = set() for _ in range(int(files * records_per_file / batches)): - op_list = sess.run(yield_op) + op_list = self.evaluate(yield_op) self.assertTrue(len(op_list) is batches) for r in op_list: self.assertTrue(r[0] not in epoch_set) @@ -138,15 +138,15 @@ class RecordInputOpTest(test.TestCase): yield_op = records.get_yield_op() for _ in range(50): - sess.run(yield_op) + self.evaluate(yield_op) def testEmptyGlob(self): with self.cached_session() as sess: record_input = data_flow_ops.RecordInput(file_pattern="foo") yield_op = record_input.get_yield_op() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) with self.assertRaises(NotFoundError): - sess.run(yield_op) + self.evaluate(yield_op) def testBufferTooSmall(self): files = 10 @@ -171,7 +171,7 @@ class RecordInputOpTest(test.TestCase): for _ in range(3): epoch_set = set() for _ in range(int(files * records_per_file / batches)): - op_list = sess.run(yield_op) + op_list = self.evaluate(yield_op) self.assertTrue(len(op_list) is batches) for r in op_list: self.assertTrue(r[0] not in epoch_set) diff --git a/tensorflow/python/kernel_tests/reduce_benchmark_test.py b/tensorflow/python/kernel_tests/reduce_benchmark_test.py index 3a2fb81157..ef9c4c350f 100644 --- a/tensorflow/python/kernel_tests/reduce_benchmark_test.py +++ b/tensorflow/python/kernel_tests/reduce_benchmark_test.py @@ -81,7 +81,7 @@ class ReduceBenchmarks(test.Benchmark): grad, = gradients_impl.gradients(reduction, tensor) def fn(): - sess.run(grad.op) + self.evaluate(grad.op) self._run(fn, 10000) @@ -98,7 +98,7 @@ class ReduceBenchmarks(test.Benchmark): grad, = gradients_impl.gradients(reduction, tensor) def fn(): - sess.run(grad.op) + self.evaluate(grad.op) self._run(fn, 10000) diff --git a/tensorflow/python/kernel_tests/reduction_ops_test.py b/tensorflow/python/kernel_tests/reduction_ops_test.py index d1a295f42b..4eb329796e 100644 --- a/tensorflow/python/kernel_tests/reduction_ops_test.py +++ b/tensorflow/python/kernel_tests/reduction_ops_test.py @@ -185,7 +185,7 @@ class SumReductionTest(BaseReductionTest): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_sum([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -216,7 +216,7 @@ class SumReductionTest(BaseReductionTest): tf_arr = variables.Variable(arr) variables.global_variables_initializer().run() tf_mean = math_ops.reduce_mean(tf_arr, 0, False) - tf_out_mean = sess.run(tf_mean) + tf_out_mean = self.evaluate(tf_mean) self.assertAllClose(tf_out_mean, 1.) def testFloat32(self): @@ -238,7 +238,7 @@ class SumReductionTest(BaseReductionTest): with self.session(graph=ops.Graph(), use_gpu=True) as sess: tf_row_sum = self._tf_reduce(arr, 1, False) tf_col_sum = self._tf_reduce(arr, 0, False) - tf_out_row, tf_out_col = sess.run([tf_row_sum, tf_col_sum]) + tf_out_row, tf_out_col = self.evaluate([tf_row_sum, tf_col_sum]) self.assertAllClose(col_sum, tf_out_col) self.assertAllClose(row_sum, tf_out_row) @@ -252,7 +252,7 @@ class SumReductionTest(BaseReductionTest): with self.session(graph=ops.Graph(), use_gpu=True) as sess: tf_sum_xz = self._tf_reduce(arr, [0, 2], False) tf_sum_y = self._tf_reduce(arr, 1, False) - tf_out_sum_xz, tf_out_sum_y = sess.run([tf_sum_xz, tf_sum_y]) + tf_out_sum_xz, tf_out_sum_y = self.evaluate([tf_sum_xz, tf_sum_y]) self.assertAllClose(sum_y, tf_out_sum_y) self.assertAllClose(sum_xz, tf_out_sum_xz) @@ -400,7 +400,7 @@ class MeanReductionTest(BaseReductionTest): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_mean([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -473,7 +473,7 @@ class ProdReductionTest(BaseReductionTest): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_prod([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -576,7 +576,7 @@ class MinReductionTest(test.TestCase): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_min([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -689,7 +689,7 @@ class MaxReductionTest(test.TestCase): for dtype in [dtypes.int64, dtypes.int32]: with self.cached_session(use_gpu=True) as sess: v = math_ops.reduce_max([0, 0], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, 0) def testInfinity(self): @@ -817,7 +817,7 @@ class AllReductionTest(test.TestCase): with self.session(use_gpu=True) as sess: v = math_ops.reduce_all([True, True], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, True) def testAll3D(self): @@ -866,7 +866,7 @@ class AnyReductionTest(test.TestCase): with self.session(use_gpu=True) as sess: v = math_ops.reduce_any([True, True], constant_op.constant(0, dtype=dtype)) - tf_v = sess.run(v) + tf_v = self.evaluate(v) self.assertAllEqual(tf_v, True) def testAll3D(self): @@ -962,7 +962,7 @@ class CountNonzeroReductionTest(test.TestCase): # Test case for GitHub issue 18712 with self.cached_session() as sess: v = math_ops.count_nonzero(constant_op.constant(["test"])) - self.assertAllClose(sess.run(v), 1) + self.assertAllClose(self.evaluate(v), 1) def testStringReduce1D(self): # Create a 1D array of strings diff --git a/tensorflow/python/kernel_tests/relu_op_test.py b/tensorflow/python/kernel_tests/relu_op_test.py index 68243f27c0..30cef90885 100644 --- a/tensorflow/python/kernel_tests/relu_op_test.py +++ b/tensorflow/python/kernel_tests/relu_op_test.py @@ -147,7 +147,7 @@ class ReluTest(test.TestCase): # Repeat the experiment for 100 times. All tensor shapes and its tensor # values are randomly generated for each run. for _ in xrange(100): - dx_f32_v, dx_f16_v = sess.run([dx_f32, dx_f16]) + dx_f32_v, dx_f16_v = self.evaluate([dx_f32, dx_f16]) self.assertAllClose(dx_f32_v, dx_f16_v, atol=3e-4) def testGradientFloat64(self): diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index e85b04469b..13b39926ec 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -153,7 +153,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): def testCachedValueReadBeforeWrite(self): with self.cached_session() as sess: v = resource_variable_ops.ResourceVariable(0.0, caching_device="cpu:0") - sess.run(v.initializer) + self.evaluate(v.initializer) value, _ = sess.run([v, v.assign_add(1.0)]) self.assertAllEqual(value, 0.0) @@ -590,11 +590,11 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): with ops.Graph().as_default(), self.cached_session() as sess: # v describes a VariableDef-based variable without an initial value. v = resource_variable_ops.ResourceVariable(variable_def=v_def) - self.assertEqual(3.0, sess.run(v.initialized_value())) + self.assertEqual(3.0, self.evaluate(v.initialized_value())) # initialized_value should not rerun the initializer_op if the variable # has already been initialized elsewhere. - sess.run(v.assign(1.0)) + self.evaluate(v.assign(1.0)) self.assertEqual(1.0, v.initialized_value().eval()) v_def.ClearField("initial_value_name") @@ -606,7 +606,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.assertProtoEquals(v_def, v.to_proto()) # But attempts to use initialized_value will result in errors. with self.assertRaises(ValueError): - sess.run(v.initialized_value()) + self.evaluate(v.initialized_value()) def testTrainableInProto(self): with ops.Graph().as_default(): diff --git a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py index 952ef34456..c388121982 100644 --- a/tensorflow/python/kernel_tests/scatter_nd_ops_test.py +++ b/tensorflow/python/kernel_tests/scatter_nd_ops_test.py @@ -161,8 +161,8 @@ class StatefulScatterNdTest(test.TestCase): init = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(init) - result = sess.run(scatter) + self.evaluate(init) + result = self.evaluate(scatter) self.assertAllClose(result, expected) def testSimpleResource(self): @@ -175,8 +175,8 @@ class StatefulScatterNdTest(test.TestCase): init = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(init) - sess.run(scatter) + self.evaluate(init) + self.evaluate(scatter) self.assertAllClose(ref.eval(), expected) def testSimple2(self): @@ -189,8 +189,8 @@ class StatefulScatterNdTest(test.TestCase): init = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(init) - result = sess.run(scatter) + self.evaluate(init) + result = self.evaluate(scatter) self.assertAllClose(result, expected) def testSimple3(self): @@ -203,8 +203,8 @@ class StatefulScatterNdTest(test.TestCase): init = variables.global_variables_initializer() with self.session(use_gpu=True) as sess: - sess.run(init) - result = sess.run(scatter) + self.evaluate(init) + result = self.evaluate(scatter) self.assertAllClose(result, expected) def testVariableRankUpdate(self): @@ -341,8 +341,8 @@ class StatefulScatterNdTest(test.TestCase): init = variables.global_variables_initializer() with session.Session() as sess: - sess.run(init) - result = sess.run(scatter) + self.evaluate(init) + result = self.evaluate(scatter) assert np.allclose(result, expected_result) # TODO(fpmc): Re-enable this test when gpu_pip test actually runs on a GPU. @@ -421,7 +421,7 @@ class ScatterNdTest(test.TestCase): b"", b"", b"seven"]) scatter = self.scatter_nd(indices, updates, shape=(8,)) with self.cached_session() as sess: - result = sess.run(scatter) + result = self.evaluate(scatter) self.assertAllEqual(expected, result) # Same indice is updated twice by same value. @@ -432,7 +432,7 @@ class ScatterNdTest(test.TestCase): expected = np.array([b"", b"", b"", b"bb", b"a", b"", b"", b"c"]) scatter = self.scatter_nd(indices, updates, shape=(8,)) with self.cached_session() as sess: - result = sess.run(scatter) + result = self.evaluate(scatter) self.assertAllEqual(expected, result) # Same indice is updated twice by different value. @@ -444,7 +444,7 @@ class ScatterNdTest(test.TestCase): np.array([b"", b"", b"", b"cb", b"a", b"", b"", b"d"])] scatter = self.scatter_nd(indices, updates, shape=(8,)) with self.cached_session() as sess: - result = sess.run(scatter) + result = self.evaluate(scatter) self.assertTrue(np.array_equal(result, expected[0]) or np.array_equal(result, expected[1])) diff --git a/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py b/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py index 85756b769d..42577f7e42 100644 --- a/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py +++ b/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py @@ -63,7 +63,7 @@ class SelfAdjointEigTest(test.TestCase): e1 = linalg_ops.self_adjoint_eigvals(matrix1) e2 = linalg_ops.self_adjoint_eigvals(matrix2) all_ops += [e1, e2] - val = sess.run(all_ops) + val = self.evaluate(all_ops) self.assertAllEqual(val[0], val[2]) # The algorithm is slightly different for compute_v being True and False, # so require approximate equality only here. @@ -81,7 +81,7 @@ class SelfAdjointEigTest(test.TestCase): self.assertEqual(matrix.shape, (32, 32)) matrix_tensor = constant_op.constant(matrix) with self.session(use_gpu=True) as sess: - (e, v) = sess.run(linalg_ops.self_adjoint_eig(matrix_tensor)) + (e, v) = self.evaluate(linalg_ops.self_adjoint_eig(matrix_tensor)) self.assertEqual(e.size, 32) self.assertAllClose( np.matmul(v, v.transpose()), np.eye(32, dtype=np.float32), atol=2e-3) diff --git a/tensorflow/python/kernel_tests/session_ops_test.py b/tensorflow/python/kernel_tests/session_ops_test.py index 03e1ae852f..dc663cb091 100644 --- a/tensorflow/python/kernel_tests/session_ops_test.py +++ b/tensorflow/python/kernel_tests/session_ops_test.py @@ -37,7 +37,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = sess.run(h) + h = self.evaluate(h) # Feed a tensor handle. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -51,7 +51,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = sess.run(h) + h = self.evaluate(h) # Get the tensor from its handle. self.assertEqual(50, h.eval()) @@ -64,7 +64,7 @@ class SessionOpsTest(test.TestCase): c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) v = math_ops.multiply(a, c) - h, v = sess.run([h, v]) + h, v = self.evaluate([h, v]) self.assertEqual(50, h.eval()) self.assertEqual(500, v) @@ -77,7 +77,7 @@ class SessionOpsTest(test.TestCase): p = math_ops.less(a, b) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - p, h = sess.run([p, h]) + p, h = self.evaluate([p, h]) # Run by feeding a tensor handle. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -94,7 +94,7 @@ class SessionOpsTest(test.TestCase): # Initialize a handle. a = constant_op.constant(0) h = session_ops.get_session_handle(a) - h = sess.run(h) + h = self.evaluate(h) # Do some computation. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -111,7 +111,7 @@ class SessionOpsTest(test.TestCase): # Initialize a handle. a = constant_op.constant(0) h = session_ops.get_session_handle(a) - h = sess.run(h) + h = self.evaluate(h) # Do some computation. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -133,7 +133,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = sess.run(h) + h = self.evaluate(h) # Feed a tensor handle. f, x = session_ops.get_session_tensor(h.handle, dtypes.int32) @@ -144,7 +144,7 @@ class SessionOpsTest(test.TestCase): with ops.device(test.gpu_device_name()): a = constant_op.constant(10) h = session_ops.get_session_handle(a) - h = sess.run(h) + h = self.evaluate(h) self.assertEqual(100, sess.run(y, feed_dict={f: h.handle})) def testHandleDelete(self): @@ -154,7 +154,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - sess.run(h).delete() + self.evaluate(h).delete() def testHandleDeleteRaw(self): with self.cached_session() as sess: @@ -163,7 +163,7 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(5) c = math_ops.multiply(a, b) h = session_ops.get_session_handle(c) - h = sess.run(h) + h = self.evaluate(h) # Delete using a raw tensor handle. raw_h = h.get_raw_handle() @@ -174,10 +174,10 @@ class SessionOpsTest(test.TestCase): with self.cached_session() as sess: with ops.device(test.gpu_device_name()): a = constant_op.constant(1.0) - a_handle = sess.run(session_ops.get_session_handle(a)) + a_handle = self.evaluate(session_ops.get_session_handle(a)) with ops.device("/cpu:0"): b = constant_op.constant(2.0) - b_handle = sess.run(session_ops.get_session_handle(b)) + b_handle = self.evaluate(session_ops.get_session_handle(b)) a_p, a_t = session_ops.get_session_tensor(a_handle.handle, dtypes.float32) b_p, b_t = session_ops.get_session_tensor(b_handle.handle, dtypes.float32) @@ -193,8 +193,8 @@ class SessionOpsTest(test.TestCase): # initial values live on CPU with ops.device("/cpu:0"): one = constant_op.constant(1, dtype=dtypes.float32) - one_handle = sess.run(session_ops.get_session_handle(one)) - x_handle = sess.run(session_ops.get_session_handle(one)) + one_handle = self.evaluate(session_ops.get_session_handle(one)) + x_handle = self.evaluate(session_ops.get_session_handle(one)) # addition lives on GPU with ops.device(test.gpu_device_name()): @@ -219,8 +219,8 @@ class SessionOpsTest(test.TestCase): b = constant_op.constant(2.0) b_handle_op = session_ops.get_session_handle(b) - a_handle = sess.run(a_handle_op) - b_handle = sess.run(b_handle_op) + a_handle = self.evaluate(a_handle_op) + b_handle = self.evaluate(b_handle_op) a_p, a_t = session_ops.get_session_tensor(a_handle.handle, dtypes.float32) b_p, b_t = session_ops.get_session_tensor(b_handle.handle, dtypes.float32) @@ -239,7 +239,7 @@ class SessionOpsTest(test.TestCase): c = math_ops.multiply(a, b) d = math_ops.multiply(c, c) - h_c = sess.run(session_ops.get_session_handle(c)) + h_c = self.evaluate(session_ops.get_session_handle(c)) self.assertAllClose(2500.0, sess.run(d, feed_dict={c: h_c})) @@ -248,7 +248,7 @@ class SessionOpsTest(test.TestCase): a = constant_op.constant(10.0) b = constant_op.constant(5.0) c = math_ops.multiply(a, b) - h_c = sess.run(session_ops.get_session_handle(c)) + h_c = self.evaluate(session_ops.get_session_handle(c)) d = array_ops.identity(c) c_val = sess.run(c, feed_dict={c: h_c}) @@ -277,8 +277,8 @@ class SessionOpsTest(test.TestCase): d = math_ops.div(a, b) e = math_ops.subtract(c, d) - h_c = sess.run(session_ops.get_session_handle(c)) - h_d = sess.run(session_ops.get_session_handle(d)) + h_c = self.evaluate(session_ops.get_session_handle(c)) + h_d = self.evaluate(session_ops.get_session_handle(d)) self.assertAllClose(48.0, sess.run(e, feed_dict={c: h_c, d: h_d})) self.assertAllClose(-48.0, sess.run(e, feed_dict={c: h_d, d: h_c})) @@ -288,13 +288,13 @@ class SessionOpsTest(test.TestCase): a = variables.Variable(12.0) inc_a = state_ops.assign_add(a, 2.0) b = math_ops.add(a, 5.0) - sess.run(a.initializer) + self.evaluate(a.initializer) h_a_read = sess.run(session_ops.get_session_handle(a.read_value())) - self.assertAllClose(12.0, sess.run(a)) + self.assertAllClose(12.0, self.evaluate(a)) self.assertAllClose(17.0, sess.run(b, feed_dict={a: h_a_read})) - sess.run(inc_a) + self.evaluate(inc_a) self.assertAllClose(19.0, sess.run(b, feed_dict={a: h_a_read})) diff --git a/tensorflow/python/kernel_tests/sets_test.py b/tensorflow/python/kernel_tests/sets_test.py index 8335e9c139..ba3d32b192 100644 --- a/tensorflow/python/kernel_tests/sets_test.py +++ b/tensorflow/python/kernel_tests/sets_test.py @@ -159,7 +159,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): self.assertEqual(None, op.get_shape().dims) self.assertEqual(dtypes.int32, op.dtype) with self.cached_session() as sess: - results = sess.run(ops) + results = self.evaluate(ops) self.assertAllEqual(results[0], results[1]) return results[0] @@ -534,7 +534,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): def _set_intersection_count(self, a, b): op = sets.set_size(sets.set_intersection(a, b)) with self.cached_session() as sess: - return sess.run(op) + return self.evaluate(op) def test_set_difference_multirow_2d(self): for dtype in _DTYPES: @@ -972,7 +972,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): def _set_difference_count(self, a, b, aminusb=True): op = sets.set_size(sets.set_difference(a, b, aminusb)) with self.cached_session() as sess: - return sess.run(op) + return self.evaluate(op) def test_set_union_multirow_2d(self): for dtype in _DTYPES: @@ -1221,7 +1221,7 @@ class SetOpsTest(test_util.TensorFlowTestCase): def _set_union_count(self, a, b): op = sets.set_size(sets.set_union(a, b)) with self.cached_session() as sess: - return sess.run(op) + return self.evaluate(op) def _assert_set_operation(self, expected_indices, expected_values, expected_shape, sparse_tensor_value, dtype): diff --git a/tensorflow/python/kernel_tests/shape_ops_test.py b/tensorflow/python/kernel_tests/shape_ops_test.py index 3e0eae326b..a0506fbfc5 100644 --- a/tensorflow/python/kernel_tests/shape_ops_test.py +++ b/tensorflow/python/kernel_tests/shape_ops_test.py @@ -73,8 +73,8 @@ class ShapeOpsTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: tf_ans = array_ops.shape_n([x, x, x]) tf_ans_64 = array_ops.shape_n([x, x, x], out_type=dtypes.int64) - result = sess.run(tf_ans) - result_64 = sess.run(tf_ans_64) + result = self.evaluate(tf_ans) + result_64 = self.evaluate(tf_ans_64) for i in range(3): self.assertAllEqual(np_ans, result[i]) self.assertAllEqual(np_ans, result_64[i]) diff --git a/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py b/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py index c4e5b6f674..de3351e543 100644 --- a/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/reconstruction_ops_test.py @@ -56,7 +56,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, 2) with self.session(use_gpu=True) as sess: - output = sess.run(reconstruction) + output = self.evaluate(reconstruction) expected_output = np.array([1, 1, 2, 2, 3, 2, 2, 1, 1]) @@ -99,7 +99,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, self.frame_hop) with self.session(use_gpu=True) as sess: - output = sess.run(reconstruction) + output = self.evaluate(reconstruction) string_output = [np.base_repr(x, self.bases[0]) for x in output] self.assertEqual(string_output, self.expected_string) @@ -109,7 +109,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, self.frame_hop) with self.session(use_gpu=True) as sess: - output = sess.run(reconstruction) + output = self.evaluate(reconstruction) accumulator = True for i in range(self.batch_size): @@ -125,7 +125,7 @@ class ReconstructionOpsTest(test.TestCase): reconstruction = reconstruction_ops.overlap_and_add(signal, self.frame_hop) with self.session(use_gpu=True) as sess: - output = sess.run(reconstruction) + output = self.evaluate(reconstruction) string_output = [np.base_repr(int(x), self.bases[0]) for x in np.squeeze(output)] diff --git a/tensorflow/python/kernel_tests/signal/spectral_ops_test.py b/tensorflow/python/kernel_tests/signal/spectral_ops_test.py index 7583c4d8fc..7b9748c7f2 100644 --- a/tensorflow/python/kernel_tests/signal/spectral_ops_test.py +++ b/tensorflow/python/kernel_tests/signal/spectral_ops_test.py @@ -235,7 +235,8 @@ class SpectralOpsTest(test.TestCase): inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) with self.cached_session(use_gpu=True) as sess: - hann_window, inverse_window = sess.run([hann_window, inverse_window]) + hann_window, inverse_window = self.evaluate( + [hann_window, inverse_window]) # Expect unit gain at each phase of the window. product_window = hann_window * inverse_window @@ -263,7 +264,8 @@ class SpectralOpsTest(test.TestCase): inverse_window = inverse_window_fn(frame_length, dtype=dtypes.float32) with self.cached_session(use_gpu=True) as sess: - hann_window, inverse_window = sess.run([hann_window, inverse_window]) + hann_window, inverse_window = self.evaluate( + [hann_window, inverse_window]) self.assertAllClose(hann_window, inverse_window * 1.5) @@ -293,7 +295,7 @@ class SpectralOpsTest(test.TestCase): # the sum of the magnitude STFT. sinusoid = math_ops.sin( 2 * np.pi * math_ops.linspace(0.0, 1.0, signal_length)) - sinusoid_gradient = sess.run(self._compute_stft_gradient(sinusoid)) + sinusoid_gradient = self.evaluate(self._compute_stft_gradient(sinusoid)) self.assertFalse((sinusoid_gradient == 0.0).all()) def test_gradients_numerical(self): diff --git a/tensorflow/python/kernel_tests/slice_op_test.py b/tensorflow/python/kernel_tests/slice_op_test.py index 5bb34a632d..ee48c6eb0e 100644 --- a/tensorflow/python/kernel_tests/slice_op_test.py +++ b/tensorflow/python/kernel_tests/slice_op_test.py @@ -207,7 +207,7 @@ class SliceTest(test.TestCase): dtype=dtypes.float32) slice_t = array_ops.slice(a, [0, 0], [2, 2]) slice2_t = a[:2, :2] - slice_val, slice2_val = sess.run([slice_t, slice2_t]) + slice_val, slice2_val = self.evaluate([slice_t, slice2_t]) self.assertAllEqual(slice_val, inp[:2, :2]) self.assertAllEqual(slice2_val, inp[:2, :2]) self.assertEqual(slice_val.shape, slice_t.get_shape()) @@ -247,7 +247,7 @@ class SliceTest(test.TestCase): + sizes[3], indices[4]:indices[4] + sizes[4], indices[5]: indices[5] + sizes[5]] - slice_val, slice2_val = sess.run([slice_t, slice2_t]) + slice_val, slice2_val = self.evaluate([slice_t, slice2_t]) expected_val = inp[indices[0]:indices[0] + sizes[0], indices[1]:indices[ 1] + sizes[1], indices[2]:indices[2] + sizes[2], indices[3]:indices[ @@ -313,7 +313,7 @@ class SliceTest(test.TestCase): g1 = gradients_impl.gradients(loss1, x)[0] g2 = gradients_impl.gradients(loss2, x)[0] - g1_val, g2_val = sess.run([g1, g2]) + g1_val, g2_val = self.evaluate([g1, g2]) self.assertAllEqual(g1_val, g2_val) def testGradientsAll(self): diff --git a/tensorflow/python/kernel_tests/spacetodepth_op_test.py b/tensorflow/python/kernel_tests/spacetodepth_op_test.py index 8ac98a198c..c9aaa68971 100644 --- a/tensorflow/python/kernel_tests/spacetodepth_op_test.py +++ b/tensorflow/python/kernel_tests/spacetodepth_op_test.py @@ -273,7 +273,7 @@ class SpaceToDepthTest(test.TestCase): actual = array_ops.space_to_depth(t, block_size, data_format=data_format) with self.cached_session(use_gpu=use_gpu) as sess: - actual_vals, expected_vals = sess.run([actual, expected]) + actual_vals, expected_vals = self.evaluate([actual, expected]) self.assertTrue(np.array_equal(actual_vals, expected_vals)) def testAgainstTranspose(self): diff --git a/tensorflow/python/kernel_tests/sparse_add_op_test.py b/tensorflow/python/kernel_tests/sparse_add_op_test.py index a746830afb..c61f863355 100644 --- a/tensorflow/python/kernel_tests/sparse_add_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_add_op_test.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import math_ops from tensorflow.python.ops import sparse_ops @@ -85,13 +86,13 @@ class SparseAddTest(test.TestCase): constant_op.constant(shape, dtypes.int64)) def testAddSelf(self): - with self.session(use_gpu=False) as sess: + with test_util.force_cpu(): for sp_a in (self._SparseTensorValue_3x3(), self._SparseTensor_3x3()): for sp_b in (self._SparseTensorValue_3x3(), self._SparseTensor_3x3()): sp_sum = sparse_ops.sparse_add(sp_a, sp_b) self.assertAllEqual((3, 3), sp_sum.get_shape()) - sum_out = sess.run(sp_sum) + sum_out = self.evaluate(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, [[0, 1], [1, 0], [2, 0], [2, 1]]) @@ -99,12 +100,12 @@ class SparseAddTest(test.TestCase): self.assertAllEqual(sum_out.dense_shape, [3, 3]) def testAddSelfAndNegation(self): - with self.session(use_gpu=False) as sess: + with test_util.force_cpu(): sp_a = self._SparseTensor_3x3() sp_b = self._SparseTensor_3x3(negate=True) sp_sum = sparse_ops.sparse_add(sp_a, sp_b, 0.1) - sum_out = sess.run(sp_sum) + sum_out = self.evaluate(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, np.empty([0, 2])) @@ -112,7 +113,7 @@ class SparseAddTest(test.TestCase): self.assertAllEqual(sum_out.dense_shape, [3, 3]) def testSmallValuesShouldVanish(self): - with self.session(use_gpu=False) as sess: + with test_util.force_cpu(): sp_a = self._SparseTensor_3x3() sp_b = self._SparseTensor_3x3_v2() @@ -123,7 +124,7 @@ class SparseAddTest(test.TestCase): # two values should vanish: |.1| < .21, and |-.2| < .21 sp_sum = sparse_ops.sparse_add(sp_a, sp_b, thresh=0.21) - sum_out = sess.run(sp_sum) + sum_out = self.evaluate(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, [[0, 1], [2, 0]]) @@ -132,7 +133,7 @@ class SparseAddTest(test.TestCase): # only .1 vanishes sp_sum = sparse_ops.sparse_add(sp_a, sp_b, thresh=0.11) - sum_out = sess.run(sp_sum) + sum_out = self.evaluate(sp_sum) self.assertEqual(sp_sum.dense_shape.get_shape(), [2]) self.assertAllEqual(sum_out.indices, [[0, 1], [2, 0], [2, 1]]) @@ -147,7 +148,7 @@ class SparseAddTest(test.TestCase): sp_a, nnz_a = self._randomTensor([n, m], np.float32) sp_b, nnz_b = self._randomTensor([n, m], np.float32) sp_sum = sparse_ops.sparse_add(sp_a, sp_b) - nnz_sum = len(sp_sum.values.eval()) + nnz_sum = len(self.evaluate(sp_sum.values)) err = gradient_checker.compute_gradient_error( [sp_a.values, sp_b.values], [(nnz_a,), (nnz_b,)], sp_sum.values, @@ -162,16 +163,16 @@ class SparseAddTest(test.TestCase): rand_vals_np = np.random.randn(n, m).astype(dtype) dense_np = np.random.randn(n, m).astype(dtype) - with self.cached_session(use_gpu=False): + with test_util.force_cpu(): sparse, unused_nnz = _sparsify(rand_vals_np, index_dtype=index_dtype) - s = sparse_ops.sparse_add(sparse, - constant_op.constant(dense_np)).eval() + s = self.evaluate( + sparse_ops.sparse_add(sparse, constant_op.constant(dense_np))) self.assertAllEqual(dense_np + rand_vals_np, s) self.assertTrue(s.dtype == dtype) # check commutativity - s = sparse_ops.sparse_add(constant_op.constant(dense_np), - sparse).eval() + s = self.evaluate( + sparse_ops.sparse_add(constant_op.constant(dense_np), sparse)) self.assertAllEqual(dense_np + rand_vals_np, s) self.assertTrue(s.dtype == dtype) @@ -191,7 +192,7 @@ class SparseAddTest(test.TestCase): self.assertLess(err, 1e-3) def testInvalidSparseTensor(self): - with self.session(use_gpu=False) as sess: + with test_util.force_cpu(): shape = [2, 2] val = [0] dense = constant_op.constant(np.zeros(shape, dtype=np.int32)) @@ -205,7 +206,7 @@ class SparseAddTest(test.TestCase): with self.assertRaisesRegexp(errors_impl.InvalidArgumentError, "invalid index"): - sess.run(s) + self.evaluate(s) ######################## Benchmarking code diff --git a/tensorflow/python/kernel_tests/sparse_concat_op_test.py b/tensorflow/python/kernel_tests/sparse_concat_op_test.py index 402c5eb4ea..368a533e56 100644 --- a/tensorflow/python/kernel_tests/sparse_concat_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_concat_op_test.py @@ -147,7 +147,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [4]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = sess.run(sp_concat) + concat_out = self.evaluate(sp_concat) self.assertAllEqual(concat_out.indices, [[0, 2], [1, 0], [2, 0], [2, 2]]) @@ -169,7 +169,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [8]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = sess.run(sp_concat) + concat_out = self.evaluate(sp_concat) self.assertAllEqual(concat_out.indices, [[0, 2], [1, 0], [1, 4], [2, 0], [2, 2], [2, 3], @@ -195,7 +195,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [7]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = sess.run(sp_concat) + concat_out = self.evaluate(sp_concat) self.assertAllEqual( concat_out.indices, @@ -220,7 +220,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [10]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = sess.run(sp_concat) + concat_out = self.evaluate(sp_concat) self.assertAllEqual(concat_out.indices, [[0, 2], [1, 0], [1, 4], [1, 8], [2, 0], [2, 2], [2, 3], [2, 6], @@ -244,7 +244,7 @@ class SparseConcatTest(test.TestCase): self.assertEqual(sp_concat.values.get_shape(), [8]) self.assertEqual(sp_concat.dense_shape.get_shape(), [2]) - concat_out = sess.run(sp_concat) + concat_out = self.evaluate(sp_concat) self.assertAllEqual( concat_out.indices, @@ -287,7 +287,7 @@ class SparseConcatTest(test.TestCase): # Shape mismatches can only be caught when the op is run with self.assertRaisesOpError("Input shapes must match"): - sess.run(sp_concat) + self.evaluate(sp_concat) def testMismatchedShapesExpandNonconcatDim(self): with self.session(use_gpu=False) as sess: @@ -302,8 +302,8 @@ class SparseConcatTest(test.TestCase): sp_concat_dim1 = sparse_ops.sparse_concat( concat_dim1, [sp_a, sp_b, sp_c, sp_d], expand_nonconcat_dim=True) - sp_concat_dim0_out = sess.run(sp_concat_dim0) - sp_concat_dim1_out = sess.run(sp_concat_dim1) + sp_concat_dim0_out = self.evaluate(sp_concat_dim0) + sp_concat_dim1_out = self.evaluate(sp_concat_dim1) self.assertAllEqual(sp_concat_dim0_out.indices, [[0, 2], [1, 0], [2, 0], [2, 2], [4, 1], [5, 0], diff --git a/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py b/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py index a824d5c826..66589fa315 100644 --- a/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py +++ b/tensorflow/python/kernel_tests/sparse_conditional_accumulator_test.py @@ -140,7 +140,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): t = _indexedslice(mat_to_add) q.apply_indexed_slices_grad(t).run() - result = sess.run(q.take_indexed_slices_grad(1)) + result = self.evaluate(q.take_indexed_slices_grad(1)) self._assertEqual_nparray(sum_elems / len(elems), result, sess) @@ -189,7 +189,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = sess.run(takeg_t) + val = self.evaluate(takeg_t) self.assertAllEqual([0, 1, 2], val.indices) self.assertAllEqual([[0.5, 0.5], [0, 2], [3, 0]], val.values) self.assertAllEqual([-1, 2], val.dense_shape) @@ -209,7 +209,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = sess.run(takeg_t) + val = self.evaluate(takeg_t) self.assertAllEqual([0, 1, 2], val.indices) self.assertAllEqual([[1, 1], [0, 2], [3, 0]], val.values) self.assertAllEqual([-1, 2], val.dense_shape) @@ -235,7 +235,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = sess.run(takeg_t) + val = self.evaluate(takeg_t) self.assertAllEqual(val.indices, [0, 1, 2]) self.assertAllEqual(val.values, [[0.5, 0.5], [0, 2], [3, 0]]) self.assertAllEqual(val.dense_shape, [-1, 2]) @@ -252,7 +252,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() takeg_t = q.take_indexed_slices_grad(1) - val = sess.run(takeg_t) + val = self.evaluate(takeg_t) self.assertAllEqual(val.indices, [0, 1, 2]) self.assertAllEqual(val.values, [[5, 5], [0, 20], [30, 0]]) self.assertAllEqual(val.dense_shape, [-1, 2]) @@ -269,7 +269,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): takeg_t = q.take_indexed_slices_grad(1) def apply_indexed_slices_grad(accum_op): - sess.run(accum_op) + self.evaluate(accum_op) threads = [ self.checkedThread( @@ -281,7 +281,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): for thread in threads: thread.join() - val = sess.run(takeg_t) + val = self.evaluate(takeg_t) expected_val = sum(elems) / len(elems) self._assertEqual_nparray( @@ -303,7 +303,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): takeg_t = q.take_indexed_slices_grad(1) def apply_indexed_slices_grad(accum_op): - sess.run(accum_op) + self.evaluate(accum_op) threads = [ self.checkedThread(target=apply_indexed_slices_grad, args=(o,)) @@ -315,7 +315,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): for thread in threads: thread.join() - val = sess.run(takeg_t) + val = self.evaluate(takeg_t) expected_val = 550.0 self._assertEqual_nparray( @@ -338,13 +338,13 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): def apply_indexed_slices_grad(): for accum_op in accum_ops: time.sleep(1.0) - sess.run(accum_op) + self.evaluate(accum_op) apply_indexed_slices_grad_thread = self.checkedThread( target=apply_indexed_slices_grad) def take_grad(): - t = sess.run(takeg_t) + t = self.evaluate(takeg_t) results.append(t) threads = [self.checkedThread(target=take_grad) for _ in range(10)] @@ -378,10 +378,10 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): def apply_indexed_slices_grad(): for accum_op in accum_ops: - sess.run(accum_op) + self.evaluate(accum_op) def take_grad(): - results.append(sess.run(takeg_t)) + results.append(self.evaluate(takeg_t)) accum_thread = self.checkedThread(target=apply_indexed_slices_grad) takeg_thread = self.checkedThread(target=take_grad) @@ -394,7 +394,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): def _blocking_takeg(self, sess, takeg_op): with self.assertRaisesOpError("was cancelled"): - sess.run(takeg_op) + self.evaluate(takeg_op) def testAccumulatorCancel(self): with self.cached_session() as sess: @@ -585,7 +585,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): np.float32)).run() # After take grad, constraints on accumulated gradient are removed - sess.run(q.take_grad(1)) + self.evaluate(q.take_grad(1)) # First successful gradient imposes new constraints. # Hereafter, shape will additionally constrained to [None,2,2,3] @@ -615,7 +615,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): grad_values=np.array( [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]]).astype(np.float32)).run() - val = sess.run(q.take_indexed_slices_grad(1)) + val = self.evaluate(q.take_indexed_slices_grad(1)) self.assertAllEqual(val.dense_shape, [2, 2, 2, 2]) q = data_flow_ops.SparseConditionalAccumulator( @@ -627,7 +627,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): [[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]]).astype( np.float32)).run() - val = sess.run(q.take_indexed_slices_grad(1)) + val = self.evaluate(q.take_indexed_slices_grad(1)) self.assertAllEqual(val.dense_shape, [-1, 2, 2, 3]) def testApplyGradtInt32IndicesAndShape(self): @@ -653,7 +653,7 @@ class IndexedSlicesConditionalAccumulatorTest(test.TestCase): accum_op.run() self.assertEqual(q.num_accumulated().eval(), 2) - val = sess.run(q.take_indexed_slices_grad(1)) + val = self.evaluate(q.take_indexed_slices_grad(1)) self.assertAllEqual(val.indices, [0, 2]) self.assertAllEqual(val.values, [[0, 0, 1], [3, 0, 4]]) self.assertAllEqual(val.dense_shape, [3, 3]) diff --git a/tensorflow/python/kernel_tests/sparse_cross_op_test.py b/tensorflow/python/kernel_tests/sparse_cross_op_test.py index 17e867439a..8451b96c56 100644 --- a/tensorflow/python/kernel_tests/sparse_cross_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_cross_op_test.py @@ -43,7 +43,7 @@ class SparseCrossOpTest(test.TestCase): 'batch2-FC1-F2_X_batch2-FC2-F1', 'batch2-FC1-F2_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_dense(self): """Tests only dense inputs.""" @@ -63,7 +63,7 @@ class SparseCrossOpTest(test.TestCase): 'batch2-FC1-F2_X_batch2-FC2-F1', 'batch2-FC1-F2_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_integer_mixed_string_sparse(self): """Tests mixed type.""" @@ -77,7 +77,7 @@ class SparseCrossOpTest(test.TestCase): '55555_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_integer_mixed_string_dense(self): """Tests mixed dense inputs.""" @@ -95,7 +95,7 @@ class SparseCrossOpTest(test.TestCase): '999999_X_batch2-FC2-F1', '999999_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_sparse_cross_dense(self): """Tests sparse and dense inputs.""" @@ -112,7 +112,7 @@ class SparseCrossOpTest(test.TestCase): 'batch2-FC1-F2_X_batch2-FC2-F1', 'batch2-FC1-F2_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_integer_sparse_input(self): """Tests mixed type sparse and dense inputs.""" @@ -128,7 +128,7 @@ class SparseCrossOpTest(test.TestCase): '5555_X_batch2-FC2-F1', '5555_X_batch2-FC2-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_permutation_3x3x3(self): """Tests 3x3x3 permutation.""" @@ -170,7 +170,7 @@ class SparseCrossOpTest(test.TestCase): 'batch1-FC1-F3_X_batch1-FC2-F3_X_batch1-FC3-F3' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_permutation_3x1x2(self): """Tests 3x1x2 permutation.""" @@ -189,7 +189,7 @@ class SparseCrossOpTest(test.TestCase): 'batch1-FC1-F3_X_batch1-FC2-F1_X_batch1-FC3-F2' ]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_large_batch(self): """Tests with large batch size to force multithreading.""" @@ -222,7 +222,7 @@ class SparseCrossOpTest(test.TestCase): expected_out = self._sparse_tensor(col_out) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_one_column_empty(self): """Tests when one column is empty. @@ -235,7 +235,7 @@ class SparseCrossOpTest(test.TestCase): self._sparse_tensor([['batch1-FC3-F1', 'batch1-FC3-F2']]) ]) with self.cached_session() as sess: - self._assert_sparse_tensor_empty(sess.run(op)) + self._assert_sparse_tensor_empty(self.evaluate(op)) def test_some_columns_empty(self): """Tests when more than one columns are empty. @@ -254,7 +254,7 @@ class SparseCrossOpTest(test.TestCase): 'batch1-FC1-F2_X_batch1-FC2-F1_X_batch1-FC3-F2' ]], 2) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_all_columns_empty(self): """Tests when all columns are empty. @@ -267,7 +267,7 @@ class SparseCrossOpTest(test.TestCase): self._sparse_tensor([]) ]) with self.cached_session() as sess: - self._assert_sparse_tensor_empty(sess.run(op)) + self._assert_sparse_tensor_empty(self.evaluate(op)) def test_hashed_zero_bucket_no_hash_key(self): op = sparse_ops.sparse_cross_hashed([ @@ -278,7 +278,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[1971693436396284976]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_hashed_zero_bucket(self): op = sparse_ops.sparse_cross_hashed( @@ -291,7 +291,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[4847552627144134031]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) # TODO(sibyl-Aix6ihai): Add benchmark to compare Hashed vs Non-hashed. def test_hashed_no_hash_key(self): @@ -305,7 +305,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[83]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_hashed_output(self): op = sparse_ops.sparse_cross_hashed( @@ -319,7 +319,7 @@ class SparseCrossOpTest(test.TestCase): # Check actual hashed output to prevent unintentional hashing changes. expected_out = self._sparse_tensor([[31]]) with self.cached_session() as sess: - self._assert_sparse_tensor_equals(expected_out, sess.run(op)) + self._assert_sparse_tensor_equals(expected_out, self.evaluate(op)) def test_hashed__has_no_collision(self): """Tests that fingerprint concatenation has no collisions.""" @@ -345,7 +345,7 @@ class SparseCrossOpTest(test.TestCase): ], num_buckets=1000) with self.cached_session() as sess: - out = sess.run(op) + out = self.evaluate(op) self.assertEqual(6, len(out.values)) self.assertAllEqual([[0, i] for i in range(6)], out.indices) self.assertTrue(all(x < 1000 and x >= 0 for x in out.values)) diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index db3f6c44e2..ad253595d2 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -154,7 +154,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sparse_tensor.SparseTensor.from_value(values_v)): sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat32(self): @@ -163,7 +163,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float32) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat64(self): @@ -172,7 +172,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float64) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt32AndFloat32NonCanonicalOrder(self): @@ -182,7 +182,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_merge( indices, values, vocab_size, already_sorted=True) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsNotSorted(output, vocab_size) def testInt64AndFloat32NonCanonicalOrder(self): @@ -192,7 +192,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_merge( indices, values, vocab_size, already_sorted=True) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsNotSorted(output, vocab_size) def testInt64AndFloat64NonCanonicalOrder(self): @@ -203,7 +203,7 @@ class SparseMergeTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_merge( indices, values, vocab_size_tensor, already_sorted=True) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsNotSorted(output, vocab_size) def testShouldSetLastDimensionInDynamicShape(self): @@ -261,7 +261,7 @@ class SparseMergeHighDimTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float32) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat64(self): @@ -270,7 +270,7 @@ class SparseMergeHighDimTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float64) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsSorted(output, vocab_size) def testInt64AndFloat64Shape(self): @@ -279,7 +279,7 @@ class SparseMergeHighDimTest(test_util.TensorFlowTestCase): indices, values = self._SparseTensor_3x50(np.int64, np.float64) sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self._AssertResultsSorted(output, vocab_size) @@ -302,7 +302,7 @@ class SparseRetainTest(test_util.TensorFlowTestCase): to_retain = np.array([1, 0, 0, 1, 1, 0], dtype=np.bool) sp_output = sparse_ops.sparse_retain(sp_input, to_retain) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self.assertAllEqual(output.indices, [[0, 0], [1, 4], [3, 2]]) self.assertAllEqual(output.values, [0, 14, 32]) @@ -314,7 +314,7 @@ class SparseRetainTest(test_util.TensorFlowTestCase): to_retain = np.zeros((6,), dtype=np.bool) sp_output = sparse_ops.sparse_retain(sp_input, to_retain) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self.assertAllEqual(output.indices, np.array([]).reshape((0, 2))) self.assertAllEqual(output.values, []) @@ -365,7 +365,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): new_shape = np.array([3, 6, 7], dtype=np.int64) sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]]) @@ -378,7 +378,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): new_shape = np.array([3, 6, 7], dtype=np.int64) sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]]) @@ -404,7 +404,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): sp_input = self._SparseTensor_2x5x6() sp_output = sparse_ops.sparse_reset_shape(sp_input) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]]) @@ -416,7 +416,7 @@ class SparseResetShapeTest(test_util.TensorFlowTestCase): sp_input = self._SparseTensor_2x5x6_Empty() sp_output = sparse_ops.sparse_reset_shape(sp_input) - output = sess.run(sp_output) + output = self.evaluate(sp_output) self.assertAllEqual(output.indices.shape, [0, 3]) self.assertAllEqual(output.values.shape, [0]) @@ -591,8 +591,8 @@ class SparseAddTest(test_util.TensorFlowTestCase): sp_output = sparse_ops.sparse_add(sp_input, sp_input) with self.session(use_gpu=False) as sess: - sess.run(variables.global_variables_initializer()) - output = sess.run(sp_output) + self.evaluate(variables.global_variables_initializer()) + output = self.evaluate(sp_output) self.assertAllEqual(output.values, [2]) diff --git a/tensorflow/python/kernel_tests/sparse_reorder_op_test.py b/tensorflow/python/kernel_tests/sparse_reorder_op_test.py index 7b83ae5177..bbf2f39202 100644 --- a/tensorflow/python/kernel_tests/sparse_reorder_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_reorder_op_test.py @@ -60,7 +60,7 @@ class SparseReorderTest(test.TestCase): input_val = self._SparseTensorValue_5x6(np.arange(6)) sp_output = sparse_ops.sparse_reorder(input_val) - output_val = sess.run(sp_output) + output_val = self.evaluate(sp_output) self.assertAllEqual(output_val.indices, input_val.indices) self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) @@ -83,7 +83,7 @@ class SparseReorderTest(test.TestCase): input_val = self._SparseTensorValue_5x6(np.random.permutation(6)) sp_output = sparse_ops.sparse_reorder(input_val) - output_val = sess.run(sp_output) + output_val = self.evaluate(sp_output) self.assertAllEqual(output_val.indices, expected_output_val.indices) self.assertAllEqual(output_val.values, expected_output_val.values) self.assertAllEqual(output_val.dense_shape, diff --git a/tensorflow/python/kernel_tests/sparse_reshape_op_test.py b/tensorflow/python/kernel_tests/sparse_reshape_op_test.py index f7be397c33..918af27091 100644 --- a/tensorflow/python/kernel_tests/sparse_reshape_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_reshape_op_test.py @@ -81,7 +81,7 @@ class SparseReshapeTest(test.TestCase): input_val = self._SparseTensorValue_5x6() sp_output = sparse_ops.sparse_reshape(input_val, [5, 6]) - output_val = sess.run(sp_output) + output_val = self.evaluate(sp_output) self.assertAllEqual(output_val.indices, input_val.indices) self.assertAllEqual(output_val.values, input_val.values) self.assertAllEqual(output_val.dense_shape, input_val.dense_shape) @@ -151,7 +151,7 @@ class SparseReshapeTest(test.TestCase): input_val = self._SparseTensorValue_5x6() sp_output = sparse_ops.sparse_reshape(input_val, [2, 3, 5]) - output_val = sess.run(sp_output) + output_val = self.evaluate(sp_output) self.assertAllEqual(output_val.indices, np.array([[0, 0, 0], [0, 1, 1], [0, 1, 4], [0, 2, 0], [1, 1, 0], [1, 1, 1]])) diff --git a/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py b/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py index b24a086969..39a9ab9b49 100644 --- a/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_serialization_ops_test.py @@ -73,7 +73,7 @@ class SerializeSparseTest(test.TestCase): serialized = serialize_fn(sp_input, out_type=out_type) sp_deserialized = deserialize_fn(serialized, dtype=dtypes.int32) - indices, values, shape = sess.run(sp_deserialized) + indices, values, shape = self.evaluate(sp_deserialized) self.assertAllEqual(indices, sp_input[0]) self.assertAllEqual(values, sp_input[1]) diff --git a/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py b/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py index e08464a701..538e7c69b5 100644 --- a/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_tensors_map_ops_test.py @@ -88,7 +88,7 @@ class SparseTensorsMapTest(test.TestCase): sp_out = take_many_sparse_from_tensors_map( sparse_map_op=handle0.op, sparse_handles=handles_concat) - combined_indices, combined_values, combined_shape = sess.run(sp_out) + combined_indices, combined_values, combined_shape = self.evaluate(sp_out) self.assertAllEqual(combined_indices[:6, 0], [0] * 6) # minibatch 0 self.assertAllEqual(combined_indices[:6, 1:], sp_input0[0]) @@ -114,7 +114,8 @@ class SparseTensorsMapTest(test.TestCase): sp_roundtrip = take_many_sparse_from_tensors_map( sparse_map_op=handle.op, sparse_handles=sparse_handles) - combined_indices, combined_values, combined_shape = sess.run(sp_roundtrip) + combined_indices, combined_values, combined_shape = self.evaluate( + sp_roundtrip) self.assertAllEqual(combined_indices[:6, 0], [0] * 6) # minibatch 0 self.assertAllEqual(combined_indices[:6, 1:], input0_val[0]) @@ -165,19 +166,19 @@ class SparseTensorsMapTest(test.TestCase): with self.assertRaisesOpError( r"Inconsistent rank across SparseTensors: rank prior to " r"SparseTensor\[1\] was: 3 but rank of SparseTensor\[1\] is: 4"): - sess.run(sp_roundtrip) + self.evaluate(sp_roundtrip) def testTakeManyFailsWrongInputOp(self): with self.session(use_gpu=False) as sess: input_val = self._SparseTensorValue_5x6(np.arange(6)) handle = add_sparse_to_tensors_map(input_val) - handle_value = sess.run(handle) + handle_value = self.evaluate(handle) bad_handle = handle_value + 10 sp_roundtrip = take_many_sparse_from_tensors_map( sparse_map_op=handle.op, sparse_handles=[handle_value, bad_handle]) with self.assertRaisesOpError(r"Unable to find SparseTensor: 10"): - sess.run(sp_roundtrip) + self.evaluate(sp_roundtrip) class BenchmarkSparseTensorsMapVsSerialization(test.Benchmark): @@ -212,8 +213,8 @@ class BenchmarkSparseTensorsMapVsSerialization(test.Benchmark): variables.global_variables_initializer().run() - st_roundtrip_values = sess.run(st_roundtrip) - st_deserialized_values = sess.run(st_deserialized) + st_roundtrip_values = self.evaluate(st_roundtrip) + st_deserialized_values = self.evaluate(st_deserialized) np.testing.assert_equal(st_roundtrip_values.values, st_deserialized_values.values) np.testing.assert_equal(st_roundtrip_values.indices, diff --git a/tensorflow/python/kernel_tests/sparse_xent_op_test.py b/tensorflow/python/kernel_tests/sparse_xent_op_test.py index 3f91131dab..cc8c7c238f 100644 --- a/tensorflow/python/kernel_tests/sparse_xent_op_test.py +++ b/tensorflow/python/kernel_tests/sparse_xent_op_test.py @@ -66,7 +66,7 @@ class SparseXentTest(test.TestCase): with self.cached_session(use_gpu=True) as sess: loss, backprop = gen_nn_ops.sparse_softmax_cross_entropy_with_logits( np_features, np_labels) - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllCloseAccordingToType(np_loss, tf_loss) self.assertAllCloseAccordingToType(np_backprop, tf_backprop) @@ -76,7 +76,7 @@ class SparseXentTest(test.TestCase): loss, backprop = gen_nn_ops.sparse_softmax_cross_entropy_with_logits( np.array([[1.], [-1.], [0.]]).astype(np.float32), np.array([0, 0, 0]).astype(label_dtype)) - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllClose([0.0, 0.0, 0.0], tf_loss) self.assertAllClose([[0.0], [0.0], [0.0]], tf_backprop) @@ -90,7 +90,7 @@ class SparseXentTest(test.TestCase): loss, backprop = ( gen_nn_ops.sparse_softmax_cross_entropy_with_logits( features, labels)) - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllClose( [[np.nan] * 4, [0.25, 0.25, 0.25, -0.75], [-0.968, 0.087, 0.237, 0.6439], [np.nan] * 4], @@ -104,7 +104,7 @@ class SparseXentTest(test.TestCase): loss, backprop = ( gen_nn_ops.sparse_softmax_cross_entropy_with_logits(features, labels)) with self.assertRaisesOpError("Received a label value of"): - sess.run([loss, backprop]) + self.evaluate([loss, backprop]) def testNpXent(self): # We create 2 batches of logits for testing. @@ -226,7 +226,7 @@ class SparseXentTest(test.TestCase): loss = nn_ops.sparse_softmax_cross_entropy_with_logits( labels=labels, logits=features) backprop = loss.op.inputs[0].op.outputs[1] - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllCloseAccordingToType(np_loss, tf_loss) self.assertAllCloseAccordingToType(np_backprop, tf_backprop) diff --git a/tensorflow/python/kernel_tests/stack_ops_test.py b/tensorflow/python/kernel_tests/stack_ops_test.py index 6c6fe8aba4..dffb260b5f 100644 --- a/tensorflow/python/kernel_tests/stack_ops_test.py +++ b/tensorflow/python/kernel_tests/stack_ops_test.py @@ -131,7 +131,7 @@ class StackOpTest(test.TestCase): pop1 = gen_data_flow_ops.stack_pop_v2(h1, dtypes.float32) pop2 = gen_data_flow_ops.stack_pop_v2(h2, dtypes.float32) - out1, out2 = sess.run([pop1, pop2]) + out1, out2 = self.evaluate([pop1, pop2]) self.assertAllClose(out1, 4.0) self.assertAllClose(out2, 5.0) @@ -144,7 +144,7 @@ class StackOpTest(test.TestCase): h = gen_data_flow_ops.stack_v2( -1, elem_type=dtypes.float32, stack_name="foo") c1 = gen_data_flow_ops.stack_close_v2(h) - sess.run(c1) + self.evaluate(c1) def testCloseStack(self): self._testCloseStack(use_gpu=False) @@ -157,7 +157,7 @@ class StackOpTest(test.TestCase): c = gen_data_flow_ops.stack_push_v2(h, [[4.0, 5.0]]) with ops.control_dependencies([c]): c1 = gen_data_flow_ops.stack_close_v2(h) - sess.run(c1) + self.evaluate(c1) def testPushCloseStack(self): self._testPushCloseStack(use_gpu=False) @@ -263,7 +263,7 @@ class StackOpRefTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: h = gen_data_flow_ops._stack(dtypes.float32, stack_name="foo") c1 = gen_data_flow_ops.stack_close(h) - sess.run(c1) + self.evaluate(c1) def testCloseStack(self): self._testCloseStack(use_gpu=False) @@ -275,7 +275,7 @@ class StackOpRefTest(test.TestCase): c = gen_data_flow_ops.stack_push(h, [[4.0, 5.0]]) with ops.control_dependencies([c]): c1 = gen_data_flow_ops.stack_close(h) - sess.run(c1) + self.evaluate(c1) def testPushCloseStack(self): self._testPushCloseStack(use_gpu=False) diff --git a/tensorflow/python/kernel_tests/string_length_op_test.py b/tensorflow/python/kernel_tests/string_length_op_test.py index 57db7302b1..06bf28ebce 100644 --- a/tensorflow/python/kernel_tests/string_length_op_test.py +++ b/tensorflow/python/kernel_tests/string_length_op_test.py @@ -29,7 +29,7 @@ class StringLengthOpTest(test.TestCase): with self.cached_session() as sess: lengths = string_ops.string_length(strings) - values = sess.run(lengths) + values = self.evaluate(lengths) self.assertAllEqual(values, [[[1, 2], [3, 4], [5, 6]]]) def testUnit(self): @@ -43,9 +43,9 @@ class StringLengthOpTest(test.TestCase): utf8_char_lengths = string_ops.string_length( utf8_strings, unit="UTF8_CHAR") self.assertAllEqual( - sess.run(utf8_byte_lengths), expected_utf8_byte_lengths) + self.evaluate(utf8_byte_lengths), expected_utf8_byte_lengths) self.assertAllEqual( - sess.run(utf8_char_lengths), expected_utf8_char_lengths) + self.evaluate(utf8_char_lengths), expected_utf8_char_lengths) with self.assertRaisesRegexp( ValueError, "Attr 'unit' of 'StringLength' Op passed string 'XYZ' " 'not in: "BYTE", "UTF8_CHAR"'): diff --git a/tensorflow/python/kernel_tests/string_split_op_test.py b/tensorflow/python/kernel_tests/string_split_op_test.py index b968e885ed..92e13db0f7 100644 --- a/tensorflow/python/kernel_tests/string_split_op_test.py +++ b/tensorflow/python/kernel_tests/string_split_op_test.py @@ -34,7 +34,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [0, 3], [1, 0]]) self.assertAllEqual(values, [b"pigs", b"on", b"the", b"wing", b"animals"]) self.assertAllEqual(shape, [2, 4]) @@ -44,7 +44,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, delimiter="") - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]) @@ -62,7 +62,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual( indices, [[1, 0], [2, 0], [3, 0], [5, 0], [6, 0], [7, 0], [8, 0]]) @@ -74,7 +74,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, delimiter=" .") - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual( indices, [[1, 0], [2, 0], [3, 0], [5, 0], [6, 0], [7, 0], [8, 0]]) @@ -92,13 +92,13 @@ class StringSplitOpTest(test.TestCase): ValueError, string_ops.string_split, strings, delimiter=["a"]) tokens = string_ops.string_split(strings, delimiter="|") - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0]]) self.assertAllEqual(values, [b"hello", b"world", b"hello world"]) self.assertAllEqual(shape, [2, 2]) tokens = string_ops.string_split(strings, delimiter="| ") - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertAllEqual(values, [b"hello", b"world", b"hello", b"world"]) self.assertAllEqual(shape, [2, 2]) @@ -145,7 +145,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, "#", skip_empty=False) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1], [2, 2]]) @@ -154,7 +154,7 @@ class StringSplitOpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split(strings, "#") - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(values, [b"a", b"b", b"c"]) self.assertAllEqual(indices, [[0, 0], [1, 0], [2, 0]]) self.assertAllEqual(shape, [3, 1]) @@ -167,7 +167,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [0, 3], [1, 0]]) self.assertAllEqual(values, [b"pigs", b"on", b"the", b"wing", b"animals"]) self.assertAllEqual(shape, [2, 4]) @@ -182,7 +182,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, sep="<>") - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual( indices, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]]) @@ -200,7 +200,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, sep=',') - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]]) self.assertAllEqual(values, [b"1", b"2", b"3", @@ -217,7 +217,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]) self.assertAllEqual(values, [b"1", b"2", b"3", b"4", b"5", b"6"]) @@ -233,7 +233,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, sep=',', maxsplit=1) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertAllEqual(values, [b"1", b"2,3", b"4", b"5,,6,"]) @@ -249,7 +249,7 @@ class StringSplitV2OpTest(test.TestCase): with self.cached_session() as sess: tokens = string_ops.string_split_v2(strings, maxsplit=1) - indices, values, shape = sess.run(tokens) + indices, values, shape = self.evaluate(tokens) self.assertAllEqual(indices, [[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertAllEqual(values, [b"1", b"2 3", b"4", b"5 6 "]) diff --git a/tensorflow/python/kernel_tests/string_strip_op_test.py b/tensorflow/python/kernel_tests/string_strip_op_test.py index 1e404b7146..edff3862ff 100644 --- a/tensorflow/python/kernel_tests/string_strip_op_test.py +++ b/tensorflow/python/kernel_tests/string_strip_op_test.py @@ -30,7 +30,7 @@ class StringStripOpTest(test.TestCase): with self.cached_session() as sess: output = string_ops.string_strip(strings) - output = sess.run(output) + output = self.evaluate(output) self.assertAllEqual(output, [b"pigs on the wing", b"animals"]) def test_string_strip_2d(self): @@ -39,7 +39,7 @@ class StringStripOpTest(test.TestCase): with self.cached_session() as sess: output = string_ops.string_strip(strings) - output = sess.run(output) + output = self.evaluate(output) self.assertAllEqual(output, [[b"pigs on the wing", b"animals"], [b"hello", b"world"]]) @@ -48,7 +48,7 @@ class StringStripOpTest(test.TestCase): with self.cached_session() as sess: output = string_ops.string_strip(strings) - output = sess.run(output) + output = self.evaluate(output) self.assertAllEqual(output, [b"hello", b"", b"world", b""]) diff --git a/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py b/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py index 63ce77b9d5..1547c55f8b 100644 --- a/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_audio_op_test.py @@ -60,7 +60,7 @@ class SummaryV1AudioOpTest(test.TestCase): sample_rate = 8000 summ = summary.audio( "snd", const, max_outputs=3, sample_rate=sample_rate) - value = sess.run(summ) + value = self.evaluate(summ) self.assertEqual([], summ.get_shape()) audio_summ = self._AsSummary(value) diff --git a/tensorflow/python/kernel_tests/summary_v1_image_op_test.py b/tensorflow/python/kernel_tests/summary_v1_image_op_test.py index 094606944f..e1b24756f3 100644 --- a/tensorflow/python/kernel_tests/summary_v1_image_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_image_op_test.py @@ -70,7 +70,7 @@ class SummaryV1ImageOpTest(test.TestCase): # Summarize summ = summary.image("img", const) - value = sess.run(summ) + value = self.evaluate(summ) self.assertEqual([], summ.get_shape()) image_summ = self._AsSummary(value) @@ -97,7 +97,7 @@ class SummaryV1ImageOpTest(test.TestCase): # Summarize summ = summary.image("img", tf_images) - value = sess.run(summ) + value = self.evaluate(summ) self.assertEqual([], summ.get_shape()) image_summ = self._AsSummary(value) diff --git a/tensorflow/python/kernel_tests/summary_v1_ops_test.py b/tensorflow/python/kernel_tests/summary_v1_ops_test.py index 6c4e106b11..1206cb7013 100644 --- a/tensorflow/python/kernel_tests/summary_v1_ops_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_ops_test.py @@ -42,7 +42,7 @@ class SummaryV1OpsTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant([10.0, 20.0]) summ = logging_ops.scalar_summary(["c1", "c2"], const, name="mysumm") - value = sess.run(summ) + value = self.evaluate(summ) self.assertEqual([], summ.get_shape()) self.assertProtoEquals(""" value { tag: "c1" simple_value: 10.0 } @@ -53,7 +53,7 @@ class SummaryV1OpsTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant([10.0, 20.0]) summ = logging_ops.scalar_summary(["c1", "c2"], const) - value = sess.run(summ) + value = self.evaluate(summ) self.assertEqual([], summ.get_shape()) self.assertProtoEquals(""" value { tag: "c1" simple_value: 10.0 } @@ -66,7 +66,7 @@ class SummaryV1OpsTest(test.TestCase): summ1 = summary.histogram("h", const) summ2 = logging_ops.scalar_summary("c", const) merge = summary.merge([summ1, summ2]) - value = sess.run(merge) + value = self.evaluate(merge) self.assertEqual([], merge.get_shape()) self.assertProtoEquals(""" value { diff --git a/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py b/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py index 34f771679a..b8e5b5b882 100644 --- a/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py +++ b/tensorflow/python/kernel_tests/summary_v1_tensor_op_test.py @@ -50,7 +50,7 @@ class SummaryV1TensorOpTest(test.TestCase): with ops.name_scope("zod"): s3 = summary_lib.tensor_summary("s3", c) s4 = summary_lib.tensor_summary("TensorSummary", c) - summ1, summ2, summ3, summ4 = sess.run([s1, s2, s3, s4]) + summ1, summ2, summ3, summ4 = self.evaluate([s1, s2, s3, s4]) v1 = self._SummarySingleValue(summ1) self.assertEqual(v1.tag, "s1") @@ -68,7 +68,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(10.0) summ = summary_lib.tensor_summary("foo", const) - result = sess.run(summ) + result = self.evaluate(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) @@ -79,7 +79,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(s) summ = summary_lib.tensor_summary("foo", const) - result = sess.run(summ) + result = self.evaluate(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) @@ -89,7 +89,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = array_ops.ones([5, 5, 5]) summ = summary_lib.tensor_summary("foo", const) - result = sess.run(summ) + result = self.evaluate(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) self._AssertNumpyEq(n, np.ones([5, 5, 5])) @@ -99,7 +99,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(strings) summ = summary_lib.tensor_summary("foo", const) - result = sess.run(summ) + result = self.evaluate(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) self._AssertNumpyEq(n, strings) @@ -109,7 +109,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: const = constant_op.constant(bools) summ = summary_lib.tensor_summary("foo", const) - result = sess.run(summ) + result = self.evaluate(summ) value = self._SummarySingleValue(result) n = tensor_util.MakeNdarray(value.tensor) @@ -119,7 +119,7 @@ class SummaryV1TensorOpTest(test.TestCase): with self.cached_session() as sess: def get_description(summary_op): - summ_str = sess.run(summary_op) + summ_str = self.evaluate(summary_op) summ = summary_pb2.Summary() summ.ParseFromString(summ_str) return summ.value[0].metadata diff --git a/tensorflow/python/kernel_tests/svd_op_test.py b/tensorflow/python/kernel_tests/svd_op_test.py index 32c97a7b19..97a280ef51 100644 --- a/tensorflow/python/kernel_tests/svd_op_test.py +++ b/tensorflow/python/kernel_tests/svd_op_test.py @@ -68,7 +68,7 @@ class SvdOpTest(test.TestCase): s2 = linalg_ops.svd( matrix2, compute_uv=compute_uv_, full_matrices=full_matrices_) all_ops += [s1, s2] - val = sess.run(all_ops) + val = self.evaluate(all_ops) for i in range(2): s = 6 * i self.assertAllEqual(val[s], val[s + 3]) # s1 == s2 @@ -150,7 +150,7 @@ def _GetSvdOpTest(dtype_, shape_, use_static_shape_, compute_uv_, s_tf, u_tf, v_tf = linalg_ops.svd( x_tf, compute_uv=compute_uv_, full_matrices=full_matrices_) if use_static_shape_: - s_tf_val, u_tf_val, v_tf_val = sess.run([s_tf, u_tf, v_tf]) + s_tf_val, u_tf_val, v_tf_val = self.evaluate([s_tf, u_tf, v_tf]) else: s_tf_val, u_tf_val, v_tf_val = sess.run( [s_tf, u_tf, v_tf], feed_dict={x_tf: x_np}) @@ -158,7 +158,7 @@ def _GetSvdOpTest(dtype_, shape_, use_static_shape_, compute_uv_, s_tf = linalg_ops.svd( x_tf, compute_uv=compute_uv_, full_matrices=full_matrices_) if use_static_shape_: - s_tf_val = sess.run(s_tf) + s_tf_val = self.evaluate(s_tf) else: s_tf_val = sess.run(s_tf, feed_dict={x_tf: x_np}) diff --git a/tensorflow/python/kernel_tests/template_test.py b/tensorflow/python/kernel_tests/template_test.py index 9dcdaa61ed..a187fa115c 100644 --- a/tensorflow/python/kernel_tests/template_test.py +++ b/tensorflow/python/kernel_tests/template_test.py @@ -104,10 +104,10 @@ class TemplateTest(test.TestCase): train_op = optimizer.minimize(train_loss) with session.Session() as sess: - sess.run(variables.global_variables_initializer()) - initial_test_loss = sess.run(test_loss) - sess.run(train_op) - final_test_loss = sess.run(test_loss) + self.evaluate(variables.global_variables_initializer()) + initial_test_loss = self.evaluate(test_loss) + self.evaluate(train_op) + final_test_loss = self.evaluate(test_loss) # Parameters are tied, so the loss should have gone down when we trained it. self.assertLess(final_test_loss, initial_test_loss) diff --git a/tensorflow/python/kernel_tests/tensor_array_ops_test.py b/tensorflow/python/kernel_tests/tensor_array_ops_test.py index 7e8db8947b..bb8645e2d5 100644 --- a/tensorflow/python/kernel_tests/tensor_array_ops_test.py +++ b/tensorflow/python/kernel_tests/tensor_array_ops_test.py @@ -751,7 +751,7 @@ class TensorArrayTest(test.TestCase): [-0.5, 1.5], # read(0) gradient [20.0, 30.0, 40.0, 50.0] ]) # concat gradient - grad_vals = sess.run(grad_r) # 2 + 2 entries + grad_vals = self.evaluate(grad_r) # 2 + 2 entries self.assertAllClose([2.0 - 0.5 + 20.0, 3.0 + 1.5 + 30.0], grad_vals[0]) self.assertAllEqual([4.0 + 40.0, 5.0 + 50.0], grad_vals[1]) @@ -1286,7 +1286,7 @@ class TensorArrayTest(test.TestCase): r = w1.stack() self.assertAllEqual(np.array([1.0, 2.0, 3.0, 4.0]), self.evaluate(r)) grad = gradients_impl.gradients(ys=[r], xs=[x]) - self.assertAllEqual(np.array([1.0, 1.0, 1.0]), sess.run(grad)[0]) + self.assertAllEqual(np.array([1.0, 1.0, 1.0]), self.evaluate(grad)[0]) @test_util.disable_control_flow_v2("b/117943489") def testSkipEagerTensorArrayUnpackDynamic(self): @@ -1303,7 +1303,7 @@ class TensorArrayTest(test.TestCase): r = w1.concat() self.assertAllEqual(np.array([1.0, 2.0, 3.0, 4.0]), self.evaluate(r)) grad = gradients_impl.gradients(ys=[r], xs=[x]) - self.assertAllEqual(np.array([1.0, 1.0, 1.0]), sess.run(grad)[0]) + self.assertAllEqual(np.array([1.0, 1.0, 1.0]), self.evaluate(grad)[0]) def _testTensorArrayEvalEmpty(self): with self.cached_session(use_gpu=True): @@ -1583,7 +1583,7 @@ class TensorArrayTest(test.TestCase): # wrap it in the correct name scope. dx, = gradients_impl.gradients(ys=[y], xs=[x], grad_ys=[dy]) with self.cached_session(use_gpu=True) as sess: - vdx, vdy = sess.run([dx, dy]) + vdx, vdy = self.evaluate([dx, dy]) self.assertAllClose(vdx, vdy) def testSkipEagerTensorArrayInt64GPU(self): diff --git a/tensorflow/python/kernel_tests/topk_op_test.py b/tensorflow/python/kernel_tests/topk_op_test.py index d9f340de6b..a72888c256 100644 --- a/tensorflow/python/kernel_tests/topk_op_test.py +++ b/tensorflow/python/kernel_tests/topk_op_test.py @@ -48,7 +48,7 @@ class TopKTest(test.TestCase): np_expected_indices = np.array(expected_indices) with self.cached_session(use_gpu=True) as sess: values_op, indices_op = nn_ops.top_k(inputs, k, sorted=sorted) - values, indices = sess.run([values_op, indices_op]) + values, indices = self.evaluate([values_op, indices_op]) self.assertShapeEqual(np_expected_values, values_op) self.assertShapeEqual(np_expected_indices, indices_op) diff --git a/tensorflow/python/kernel_tests/unicode_transcode_op_test.py b/tensorflow/python/kernel_tests/unicode_transcode_op_test.py index 4ad5ee4103..037ecd104b 100644 --- a/tensorflow/python/kernel_tests/unicode_transcode_op_test.py +++ b/tensorflow/python/kernel_tests/unicode_transcode_op_test.py @@ -42,7 +42,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, strings) outputs = string_ops.unicode_transcode( @@ -52,7 +52,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, strings) outputs = string_ops.unicode_transcode( @@ -62,7 +62,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, strings) def test_transcode_utf16_to_utf8(self): @@ -77,7 +77,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, expected) def test_transcode_bad_utf8(self): @@ -90,7 +90,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=True) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b" ") outputs = string_ops.unicode_transcode( @@ -100,7 +100,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"\x00 ") def test_transcode_bad_utf8_with_some_good(self): @@ -113,7 +113,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"abc abcdefg") def test_transcode_bad_utf8_with_defaults(self): @@ -121,7 +121,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bad_string, input_encoding="UTF-8", output_encoding="UTF-8") - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"\x00\xef\xbf\xbd") def test_transcode_bad_utf8_with_space_replacement(self): @@ -130,7 +130,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): outputs = string_ops.unicode_transcode( bad_string, input_encoding="UTF-8", output_encoding="UTF-8", replacement_char=ord(" ")) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"\x00 ") def test_transcode_bad_utf8_with_strict_errors(self): @@ -143,7 +143,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="strict") with self.assertRaisesOpError( "Invalid formatting on input string"): - sess.run(outputs) + self.evaluate(outputs) def test_transcode_bad_utf8_start_with_strict_errors(self): bad_string = b"\xffabcd" @@ -155,7 +155,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="strict") with self.assertRaisesOpError( "Invalid formatting on input string"): - sess.run(outputs) + self.evaluate(outputs) def test_transcode_bad_utf8_with_elision_of_malformatting(self): bad_string = b"\x00\xff" @@ -165,7 +165,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): input_encoding="UTF-8", output_encoding="UTF-8", errors="ignore") - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"\x00") def test_transcode_bad_utf8_with_elision_including_control_chars(self): @@ -177,7 +177,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-8", errors="ignore", replace_control_characters=True) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"") def test_transcode_bad_utf8_termination_with_defaults(self): @@ -185,7 +185,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bad_string, input_encoding="UTF-8", output_encoding="UTF-8") - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"a\xef\xbf\xbd") # 0xFFFD def test_transcode_utf8_with_replacement_char(self): @@ -194,13 +194,13 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): outputs = string_ops.unicode_transcode( strings, input_encoding="UTF-8", output_encoding="UTF-8", errors="strict") - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, [b"a\xef\xbf\xbd"]) outputs = string_ops.unicode_transcode( strings, input_encoding="UTF-8", output_encoding="UTF-8", errors="replace", replacement_char=ord("?")) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, [b"a\xef\xbf\xbd"]) def test_transcode_utf8_to_utf16(self): @@ -214,7 +214,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-16-BE", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) print("values=", values) self.assertAllEqual(values, expected) @@ -230,7 +230,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-8", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, expected) def test_transcode_utf8_to_utf32(self): @@ -243,7 +243,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-32-BE", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, expected) # Documentation in ICU suggests that getNextUChar may produce a different @@ -258,7 +258,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): output_encoding="UTF-8", replacement_char=ord(" "), replace_control_characters=False) - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, strings) def test_transcode_utf8_with_bom(self): @@ -266,12 +266,12 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-8", output_encoding="UTF-8") - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"\xef\xbb\xbfabcdefg") # BOM preserved outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-8", output_encoding="UTF-16-BE") - values = sess.run(outputs) + values = self.evaluate(outputs) utf16expected = bom_string.decode("UTF-8").encode("UTF-16-BE") self.assertAllEqual(values, utf16expected) @@ -280,20 +280,20 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): with self.cached_session() as sess: outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-16-BE", output_encoding="UTF-8") - values = sess.run(outputs) + values = self.evaluate(outputs) # BOM is preserved in output self.assertAllEqual(values, b"\xef\xbb\xbfa") outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-16-LE", output_encoding="UTF-8") - values = sess.run(outputs) + values = self.evaluate(outputs) # mangled BOM and value from (incorrect) LE encoding self.assertAllEqual(values, b"\xef\xbf\xbe\xe6\x84\x80") bom_string = b"\xff\xfe\x61\x00" # Little-endian BOM with 'a' encoded outputs = string_ops.unicode_transcode( bom_string, input_encoding="UTF-16-LE", output_encoding="UTF-8") - values = sess.run(outputs) + values = self.evaluate(outputs) self.assertAllEqual(values, b"\xef\xbb\xbfa") @parameterized.parameters( @@ -336,7 +336,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): replace_control_characters=False) with self.assertRaisesOpError( "Could not create converter for input encoding: invalid"): - sess.run(outputs) + self.evaluate(outputs) with self.assertRaisesRegexp(ValueError, "Op passed string 'invalid'"): with self.cached_session() as sess: @@ -347,7 +347,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="replace", replacement_char=ord(" "), replace_control_characters=False) - sess.run(outputs) + self.evaluate(outputs) def test_invalid_error_policy_causes_errors(self): strings = [[b"a", b"abc"], [b"ABC", b"DEF"]] @@ -362,7 +362,7 @@ class UnicodeTranscodeOpTest(test.TestCase, parameterized.TestCase): errors="invalid", replacement_char=ord(" "), replace_control_characters=False) - sess.run(outputs) + self.evaluate(outputs) def test_forwarding(self): with self.cached_session(): diff --git a/tensorflow/python/kernel_tests/unique_op_test.py b/tensorflow/python/kernel_tests/unique_op_test.py index 316570e13e..f203263e0c 100644 --- a/tensorflow/python/kernel_tests/unique_op_test.py +++ b/tensorflow/python/kernel_tests/unique_op_test.py @@ -32,7 +32,7 @@ class UniqueTest(test.TestCase): x = np.random.randint(2, high=10, size=7000) with self.cached_session() as sess: y, idx = array_ops.unique(x) - tf_y, tf_idx = sess.run([y, idx]) + tf_y, tf_idx = self.evaluate([y, idx]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -43,7 +43,7 @@ class UniqueTest(test.TestCase): x = np.random.randint(2, high=10, size=7000) with self.cached_session() as sess: y, idx = array_ops.unique(x, out_idx=dtypes.int64) - tf_y, tf_idx = sess.run([y, idx]) + tf_y, tf_idx = self.evaluate([y, idx]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -55,7 +55,7 @@ class UniqueTest(test.TestCase): x = [chr(i) for i in indx] with self.cached_session() as sess: y, idx = array_ops.unique(x) - tf_y, tf_idx = sess.run([y, idx]) + tf_y, tf_idx = self.evaluate([y, idx]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -67,9 +67,9 @@ class UniqueTest(test.TestCase): x = np.array([[1, 0, 0], [1, 0, 0], [2, 0, 0]]) with self.cached_session() as sess: y0, idx0 = gen_array_ops.unique_v2(x, axis=np.array([0], dtype)) - tf_y0, tf_idx0 = sess.run([y0, idx0]) + tf_y0, tf_idx0 = self.evaluate([y0, idx0]) y1, idx1 = gen_array_ops.unique_v2(x, axis=np.array([1], dtype)) - tf_y1, tf_idx1 = sess.run([y1, idx1]) + tf_y1, tf_idx1 = self.evaluate([y1, idx1]) self.assertAllEqual(tf_y0, np.array([[1, 0, 0], [2, 0, 0]])) self.assertAllEqual(tf_idx0, np.array([0, 0, 1])) self.assertAllEqual(tf_y1, np.array([[1, 0], [1, 0], [2, 0]])) @@ -81,7 +81,7 @@ class UniqueTest(test.TestCase): x = np.random.randint(2, high=10, size=7000) with self.cached_session() as sess: y, idx = gen_array_ops.unique_v2(x, axis=np.array([], np.int32)) - tf_y, tf_idx = sess.run([y, idx]) + tf_y, tf_idx = self.evaluate([y, idx]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -95,7 +95,7 @@ class UniqueWithCountsTest(test.TestCase): x = np.random.randint(2, high=10, size=7000) with self.cached_session() as sess: y, idx, count = array_ops.unique_with_counts(x) - tf_y, tf_idx, tf_count = sess.run([y, idx, count]) + tf_y, tf_idx, tf_count = self.evaluate([y, idx, count]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -108,7 +108,7 @@ class UniqueWithCountsTest(test.TestCase): x = np.random.randint(2, high=10, size=7000) with self.cached_session() as sess: y, idx, count = array_ops.unique_with_counts(x, out_idx=dtypes.int64) - tf_y, tf_idx, tf_count = sess.run([y, idx, count]) + tf_y, tf_idx, tf_count = self.evaluate([y, idx, count]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -123,7 +123,7 @@ class UniqueWithCountsTest(test.TestCase): with self.cached_session() as sess: y, idx, count = array_ops.unique_with_counts(x) - tf_y, tf_idx, tf_count = sess.run([y, idx, count]) + tf_y, tf_idx, tf_count = self.evaluate([y, idx, count]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) @@ -139,10 +139,10 @@ class UniqueWithCountsTest(test.TestCase): with self.cached_session() as sess: y0, idx0, count0 = gen_array_ops.unique_with_counts_v2( x, axis=np.array([0], dtype)) - tf_y0, tf_idx0, tf_count0 = sess.run([y0, idx0, count0]) + tf_y0, tf_idx0, tf_count0 = self.evaluate([y0, idx0, count0]) y1, idx1, count1 = gen_array_ops.unique_with_counts_v2( x, axis=np.array([1], dtype)) - tf_y1, tf_idx1, tf_count1 = sess.run([y1, idx1, count1]) + tf_y1, tf_idx1, tf_count1 = self.evaluate([y1, idx1, count1]) self.assertAllEqual(tf_y0, np.array([[1, 0, 0], [2, 0, 0]])) self.assertAllEqual(tf_idx0, np.array([0, 0, 1])) self.assertAllEqual(tf_count0, np.array([2, 1])) @@ -157,7 +157,7 @@ class UniqueWithCountsTest(test.TestCase): with self.cached_session() as sess: y, idx, count = gen_array_ops.unique_with_counts_v2( x, axis=np.array([], np.int32)) - tf_y, tf_idx, tf_count = sess.run([y, idx, count]) + tf_y, tf_idx, tf_count = self.evaluate([y, idx, count]) self.assertEqual(len(x), len(tf_idx)) self.assertEqual(len(tf_y), len(np.unique(x))) diff --git a/tensorflow/python/kernel_tests/variable_ops_test.py b/tensorflow/python/kernel_tests/variable_ops_test.py index 769bbba47b..cdfd805a93 100644 --- a/tensorflow/python/kernel_tests/variable_ops_test.py +++ b/tensorflow/python/kernel_tests/variable_ops_test.py @@ -220,7 +220,7 @@ class VariableOpTest(test.TestCase): with self.test_session(use_gpu=True): # The variable and an op to increment it are on the GPU. var = state_ops.variable_op([1], dtypes.float32) - state_ops.assign(var, [1.0]).eval() + self.evaluate(state_ops.assign(var, [1.0])) increment = state_ops.assign_add(var, [1.0]) with ops.control_dependencies([increment]): with ops.device("/cpu:0"): diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index 6267b01a29..37012af299 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -434,19 +434,19 @@ class VariableScopeTest(test.TestCase): add = v1 + v0 # v0 should be uninitialized. with self.assertRaisesRegexp(errors.OpError, "uninitialized"): - sess.run(v0) + self.evaluate(v0) # We should be able to initialize and run v1 without initializing # v0, even if the variable was created with a control dep on v0. - sess.run(v1.initializer) - self.assertEqual(1, sess.run(v1)) + self.evaluate(v1.initializer) + self.assertEqual(1, self.evaluate(v1)) # v0 should still be uninitialized. with self.assertRaisesRegexp(errors.OpError, "uninitialized"): - sess.run(v0) + self.evaluate(v0) with self.assertRaisesRegexp(errors.OpError, "uninitialized"): - sess.run(add) + self.evaluate(add) # If we initialize v0 we should be able to run 'add'. - sess.run(v0.initializer) - sess.run(add) + self.evaluate(v0.initializer) + self.evaluate(add) # TODO(mihaimaruseac): Not converted to use wrap_function because of # AssertionError: True is not false (last assertFalse) @@ -489,19 +489,19 @@ class VariableScopeTest(test.TestCase): v2 = var_dict["v2"] # We should be able to initialize and run v1 and v2 without initializing # v0, even if the variable was created with a control dep on v0. - sess.run(v1.initializer) - self.assertEqual([1], sess.run(v1)) - sess.run(v2.initializer) - self.assertEqual([2], sess.run(v2)) + self.evaluate(v1.initializer) + self.assertEqual([1], self.evaluate(v1)) + self.evaluate(v2.initializer) + self.assertEqual([2], self.evaluate(v2)) # v0 should still be uninitialized. with self.assertRaisesRegexp(errors.OpError, "uninitialized"): - sess.run(v0) + self.evaluate(v0) # We should not be able to run 'add' yet. with self.assertRaisesRegexp(errors.OpError, "uninitialized"): - sess.run(add) + self.evaluate(add) # If we initialize v0 we should be able to run 'add'. - sess.run(v0.initializer) - sess.run(add) + self.evaluate(v0.initializer) + self.evaluate(add) # TODO(mihaimaruseac): Not converted to use wrap_function because of # TypeError: Expected tf.group() expected Tensor arguments not 'None' with @@ -1580,7 +1580,7 @@ class VariableScopeWithCustomGetterTest(test.TestCase): self.assertEqual("custom_getter/add:0", v.name) with self.cached_session() as sess: variables_lib.global_variables_initializer().run() - np_vars, np_v = sess.run([true_vars, v]) + np_vars, np_v = self.evaluate([true_vars, v]) self.assertAllClose(np_v, sum(np_vars)) # TODO(mihaimaruseac): Not converted to use wrap_function because of @@ -1625,7 +1625,7 @@ class VariableScopeWithCustomGetterTest(test.TestCase): with self.cached_session() as sess: variables_lib.global_variables_initializer().run() - np_vars, np_v = sess.run([true_vars, v]) + np_vars, np_v = self.evaluate([true_vars, v]) # take products of sums of products self.assertAllClose( np_v, (((np_vars[0] * np_vars[1]) + (np_vars[2] * np_vars[3])) + ( diff --git a/tensorflow/python/kernel_tests/variables_test.py b/tensorflow/python/kernel_tests/variables_test.py index faa9f82067..14ec46dcb2 100644 --- a/tensorflow/python/kernel_tests/variables_test.py +++ b/tensorflow/python/kernel_tests/variables_test.py @@ -228,13 +228,13 @@ class VariablesTestCase(test.TestCase): self.assertEqual([2], self.evaluate(v2)) # v0 should still be uninitialized. with self.assertRaisesRegexp(errors_impl.OpError, "uninitialized"): - sess.run(v0) + self.evaluate(v0) # We should not be able to run 'add' yet. with self.assertRaisesRegexp(errors_impl.OpError, "uninitialized"): - sess.run(add) + self.evaluate(add) # If we initialize v0 we should be able to run 'add'. self.evaluate(v0.initializer) - sess.run(add) + self.evaluate(add) def testControlFlowInitialization(self): """Expects an error if an initializer is in a control-flow scope.""" @@ -476,11 +476,11 @@ class VariablesTestCase(test.TestCase): with ops.Graph().as_default(), self.cached_session() as sess: # v describes a VariableDef-based variable without an initial value. v = variables.Variable(variable_def=v_def) - self.assertEqual(3.0, sess.run(v.initialized_value())) + self.assertEqual(3.0, self.evaluate(v.initialized_value())) # initialized_value should not rerun the initializer_op if the variable # has already been initialized elsewhere. - sess.run(v.assign(1.0)) + self.evaluate(v.assign(1.0)) self.assertEqual(1.0, v.initialized_value().eval()) v_def.ClearField("initial_value_name") @@ -492,7 +492,7 @@ class VariablesTestCase(test.TestCase): self.assertProtoEquals(v_def, v.to_proto()) # But attempts to use initialized_value will result in errors. with self.assertRaises(ValueError): - sess.run(v.initialized_value()) + self.evaluate(v.initialized_value()) def testTrainableInProto(self): with ops.Graph().as_default(): @@ -579,7 +579,7 @@ class IsInitializedTest(test.TestCase): variables.global_variables_initializer().run() do_opt = gradient_descent.GradientDescentOptimizer(0.1).minimize( objective) - sess.run([do_opt]) + self.evaluate([do_opt]) self.assertAllClose([[0.9, 0.9], [0.9, 0.9]], self.evaluate(b)) @@ -596,9 +596,9 @@ class ObsoleteIsInitializedTest(test.TestCase): _ = v, w inited = variables.assert_variables_initialized() with self.assertRaisesOpError("Attempting to use uninitialized value"): - sess.run(inited) + self.evaluate(inited) variables.global_variables_initializer().run() - sess.run(inited) + self.evaluate(inited) def testVariableList(self): with ops.Graph().as_default(), self.cached_session() as sess: diff --git a/tensorflow/python/kernel_tests/while_v2_test.py b/tensorflow/python/kernel_tests/while_v2_test.py index 0634dfa2d8..48b32f06aa 100644 --- a/tensorflow/python/kernel_tests/while_v2_test.py +++ b/tensorflow/python/kernel_tests/while_v2_test.py @@ -48,8 +48,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v < 8., lambda v: v * v, [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(sess.run(ret), 16.) - self.assertSequenceEqual(sess.run(grad), [32.]) + self.assertEqual(self.evaluate(ret), 16.) + self.assertSequenceEqual(self.evaluate(grad), [32.]) def testMultipleLoopVarsBasic(self): x = constant_op.constant(5.) @@ -65,8 +65,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): # Note: This is simply d_ret[0]/d_x since d_ret[1]/d_x is 0. grad = gradients_impl.gradients(ret, [x]) # [2*x*y] with self.cached_session() as sess: - self.assertSequenceEqual(sess.run(ret), [45., 3.]) - self.assertSequenceEqual(sess.run(grad), [9.]) + self.assertSequenceEqual(self.evaluate(ret), [45., 3.]) + self.assertSequenceEqual(self.evaluate(grad), [9.]) def testMultipleLoopVars(self): x = constant_op.constant(5.) @@ -88,13 +88,13 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grady_1 = gradients_impl.gradients(ret[1], [y]) # [x + 1] grady_2 = gradients_impl.gradients(ret, [y]) # [2*x*y + x**2 + x + 1] with self.cached_session() as sess: - self.assertSequenceEqual(sess.run(ret), [120., 23.]) - self.assertSequenceEqual(sess.run(gradx_0), [39.]) - self.assertSequenceEqual(sess.run(gradx_1), [4.]) - self.assertSequenceEqual(sess.run(gradx_2), [43.]) - self.assertSequenceEqual(sess.run(grady_0), [55.]) - self.assertSequenceEqual(sess.run(grady_1), [6.]) - self.assertSequenceEqual(sess.run(grady_2), [61.]) + self.assertSequenceEqual(self.evaluate(ret), [120., 23.]) + self.assertSequenceEqual(self.evaluate(gradx_0), [39.]) + self.assertSequenceEqual(self.evaluate(gradx_1), [4.]) + self.assertSequenceEqual(self.evaluate(gradx_2), [43.]) + self.assertSequenceEqual(self.evaluate(grady_0), [55.]) + self.assertSequenceEqual(self.evaluate(grady_1), [6.]) + self.assertSequenceEqual(self.evaluate(grady_2), [61.]) def testMultipleWhileLoops(self): x = constant_op.constant(2.) @@ -103,8 +103,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret2, [x]) # 4x**3 grad_grad = gradients_impl.gradients(grad, [x]) # 12x**2 with self.cached_session() as sess: - self.assertSequenceEqual(sess.run(grad), [32.]) - self.assertSequenceEqual(sess.run(grad_grad), [48.]) + self.assertSequenceEqual(self.evaluate(grad), [32.]) + self.assertSequenceEqual(self.evaluate(grad_grad), [48.]) def testDoubleDerivative(self): x = constant_op.constant(2.) @@ -112,9 +112,9 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret, [x]) # 4x**3 grad_grad = gradients_impl.gradients(grad, [x]) # 12x**2 with self.cached_session() as sess: - self.assertEqual(sess.run(ret), 16.) - self.assertSequenceEqual(sess.run(grad), [32.]) - self.assertSequenceEqual(sess.run(grad_grad), [48.]) + self.assertEqual(self.evaluate(ret), 16.) + self.assertSequenceEqual(self.evaluate(grad), [32.]) + self.assertSequenceEqual(self.evaluate(grad_grad), [48.]) def testPruning(self): x = constant_op.constant(1) @@ -157,8 +157,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v + y < 9., lambda v: v * 3., [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(sess.run(ret), 18.) - self.assertSequenceEqual(sess.run(grad), [9.]) + self.assertEqual(self.evaluate(ret), 18.) + self.assertSequenceEqual(self.evaluate(grad), [9.]) def testCaptureExternalTensorInBody(self): x = constant_op.constant(2.) @@ -166,8 +166,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v < 8., lambda v: v * y, [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(sess.run(ret), 18.) - self.assertSequenceEqual(sess.run(grad), [9.]) + self.assertEqual(self.evaluate(ret), 18.) + self.assertSequenceEqual(self.evaluate(grad), [9.]) def testLoopWithTensorListPushBack(self): x = constant_op.constant(2.) @@ -188,7 +188,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret[0], x) with self.cached_session() as sess: self.assertEqual(sess.run(ret[0]), 16.) - self.assertSequenceEqual(sess.run(grad), [32.]) + self.assertSequenceEqual(self.evaluate(grad), [32.]) def testDuplicateAccumulator(self): x = constant_op.constant(2.) @@ -222,7 +222,7 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): grad = gradients_impl.gradients(ret[0], x) with self.cached_session() as sess: self.assertEqual(sess.run(ret[0]), 16.) - self.assertSequenceEqual(sess.run(grad), [32.]) + self.assertSequenceEqual(self.evaluate(grad), [32.]) @parameterized.named_parameters( ("UnknownShape", None), @@ -315,9 +315,9 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): y0 = constant_op.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], name="elems") # map_fn uses TensorArray internally. r = functional_ops.map_fn(lambda x: math_ops.multiply(x, param), y0) - self.assertAllClose([2.0, 4.0, 6.0, 8.0, 10.0, 12.0], sess.run(r)) + self.assertAllClose([2.0, 4.0, 6.0, 8.0, 10.0, 12.0], self.evaluate(r)) r = gradients_impl.gradients(r, param)[0] - self.assertAllClose(21.0, sess.run(r)) + self.assertAllClose(21.0, self.evaluate(r)) def testNestedWhile(self): # Compute sum of geometric progression: n^0 + n^1 + ... + n^m @@ -334,8 +334,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): result = while_loop_v2(lambda i, _: i >= 0, Body, [m, sum_of_powers])[1] grad = gradients_impl.gradients(result, [n]) with self.cached_session() as sess: - self.assertEqual(sess.run(result), 364.) - self.assertSequenceEqual(sess.run(grad), [547.]) + self.assertEqual(self.evaluate(result), 364.) + self.assertSequenceEqual(self.evaluate(grad), [547.]) def testIdentityNodeInBody(self): @@ -348,8 +348,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): ret = while_loop_v2(lambda v: v < 8., Body, [x]) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: - self.assertEqual(sess.run(ret), 16.) - self.assertSequenceEqual(sess.run(grad), [32.]) + self.assertEqual(self.evaluate(ret), 16.) + self.assertSequenceEqual(self.evaluate(grad), [32.]) def testNestedWhileAndTensorArray(self): n = constant_op.constant(3.0) diff --git a/tensorflow/python/kernel_tests/xent_op_test.py b/tensorflow/python/kernel_tests/xent_op_test.py index c3c7f867a1..77669f08cc 100644 --- a/tensorflow/python/kernel_tests/xent_op_test.py +++ b/tensorflow/python/kernel_tests/xent_op_test.py @@ -56,7 +56,7 @@ class XentTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: loss, backprop = gen_nn_ops.softmax_cross_entropy_with_logits( np_features, np_labels) - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllCloseAccordingToType(np_loss, tf_loss) self.assertAllCloseAccordingToType(np_backprop, tf_backprop) @@ -65,7 +65,7 @@ class XentTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: loss = nn_ops.softmax_cross_entropy_with_logits( labels=np_labels, logits=np_features, dim=dim) - tf_loss = sess.run(loss) + tf_loss = self.evaluate(loss) print("np_loss:", np_loss) print("tf_loss:", tf_loss) self.assertAllCloseAccordingToType(np_loss, tf_loss) @@ -80,7 +80,7 @@ class XentTest(test.TestCase): loss, backprop = gen_nn_ops.softmax_cross_entropy_with_logits( np.array([[1.], [-1.], [0.]]).astype(dtype), np.array([[-1.], [0.], [1.]]).astype(dtype)) - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllClose([0.0, 0.0, 0.0], tf_loss) self.assertAllClose([[2.0], [1.0], [0.0]], tf_backprop) @@ -148,7 +148,7 @@ class XentTest(test.TestCase): with self.cached_session(use_gpu=use_gpu) as sess: loss, backprop = gen_nn_ops.softmax_cross_entropy_with_logits( tf_f, tf_l) - tf_loss, tf_backprop = sess.run([loss, backprop]) + tf_loss, tf_backprop = self.evaluate([loss, backprop]) self.assertAllCloseAccordingToType(np_loss, tf_loss) self.assertAllCloseAccordingToType(np_backprop, tf_backprop) @@ -280,7 +280,7 @@ class XentTest(test.TestCase): with self.session(use_gpu=True) as sess: loss = nn_ops.softmax_cross_entropy_with_logits( labels=labels, logits=features) - tf_loss = sess.run(loss) + tf_loss = self.evaluate(loss) self.assertAllEqual(np_loss, tf_loss) diff --git a/tensorflow/python/layers/convolutional_test.py b/tensorflow/python/layers/convolutional_test.py index 257fa27156..d3200fa5b5 100644 --- a/tensorflow/python/layers/convolutional_test.py +++ b/tensorflow/python/layers/convolutional_test.py @@ -276,8 +276,8 @@ class ConvTest(test.TestCase): # Check the names of weights in order. self.assertTrue('kernel' in weights[0].name) self.assertTrue('bias' in weights[1].name) - sess.run(variables.global_variables_initializer()) - weights = sess.run(weights) + self.evaluate(variables.global_variables_initializer()) + weights = self.evaluate(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 3, 32))) # Check that the bias still got initialized to zeros. @@ -663,8 +663,8 @@ class SeparableConv2DTest(test.TestCase): self.assertTrue('depthwise_kernel' in weights[0].name) self.assertTrue('pointwise_kernel' in weights[1].name) self.assertTrue('bias' in weights[2].name) - sess.run(variables.global_variables_initializer()) - weights = sess.run(weights) + self.evaluate(variables.global_variables_initializer()) + weights = self.evaluate(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 3, 1))) self.assertAllClose(weights[1], np.ones((1, 1, 3, 32))) @@ -902,8 +902,8 @@ class Conv2DTransposeTest(test.TestCase): # Check the names of weights in order. self.assertTrue('kernel' in weights[0].name) self.assertTrue('bias' in weights[1].name) - sess.run(variables.global_variables_initializer()) - weights = sess.run(weights) + self.evaluate(variables.global_variables_initializer()) + weights = self.evaluate(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 32, 3))) # Check that the bias still got initialized to zeros. @@ -1084,8 +1084,8 @@ class Conv3DTransposeTest(test.TestCase): # Check the names of weights in order. self.assertTrue('kernel' in weights[0].name) self.assertTrue('bias' in weights[1].name) - sess.run(variables.global_variables_initializer()) - weights = sess.run(weights) + self.evaluate(variables.global_variables_initializer()) + weights = self.evaluate(weights) # Check that the kernel weights got initialized to ones (from scope) self.assertAllClose(weights[0], np.ones((3, 3, 3, 4, 32))) # Check that the bias still got initialized to zeros. diff --git a/tensorflow/python/layers/core_test.py b/tensorflow/python/layers/core_test.py index 0343bfa8bd..a61639b2db 100644 --- a/tensorflow/python/layers/core_test.py +++ b/tensorflow/python/layers/core_test.py @@ -443,7 +443,7 @@ class DropoutTest(test.TestCase): dp = core_layers.Dropout(rate, name='dropout') inputs = array_ops.ones((5, 5)) dropped = dp.apply(inputs, training=True) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) np_output = sess.run(dropped, feed_dict={rate: 0.5}) self.assertAlmostEqual(0., np_output.min()) np_output = sess.run(dropped, feed_dict={rate: 0.0}) diff --git a/tensorflow/python/layers/normalization_test.py b/tensorflow/python/layers/normalization_test.py index ba2bf10cf3..cc3badbde1 100644 --- a/tensorflow/python/layers/normalization_test.py +++ b/tensorflow/python/layers/normalization_test.py @@ -78,7 +78,7 @@ class BNTest(test.TestCase): if restore: saver.restore(sess, checkpoint_path) else: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) np.random.seed(0) for _ in range(2): image_val = np.random.rand(*shape).astype(dtype.as_numpy_dtype) @@ -321,9 +321,9 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 4, 1)) np_beta = np.reshape(np_beta, (1, 4, 1)) @@ -336,8 +336,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 2)) std = np.std(np_inputs, axis=(0, 2)) variance = np.square(std) @@ -363,8 +364,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 3)) np_beta = np.reshape(np_beta, (1, 1, 3)) for _ in range(100): @@ -376,8 +377,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 1)) std = np.std(np_inputs, axis=(0, 1)) variance = np.square(std) @@ -404,8 +406,8 @@ class BNTest(test.TestCase): with self.session(use_gpu=True) as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 4, 1, 1)) np_beta = np.reshape(np_beta, (1, 4, 1, 1)) for _ in range(100): @@ -417,8 +419,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 2, 3)) std = np.std(np_inputs, axis=(0, 2, 3)) variance = np.square(std) @@ -444,8 +447,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 3, 1)) np_beta = np.reshape(np_beta, (1, 1, 3, 1)) for _ in range(100): @@ -457,8 +460,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 1, 3)) std = np.std(np_inputs, axis=(0, 1, 3)) variance = np.square(std) @@ -484,8 +488,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) for _ in range(100): @@ -497,8 +501,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -524,8 +529,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) for _ in range(100): @@ -537,8 +542,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -565,8 +571,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 4, 1, 1)) np_beta = np.reshape(np_beta, (1, 4, 1, 1)) for _ in range(100): @@ -578,8 +584,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 2, 3)) std = np.std(np_inputs, axis=(0, 2, 3)) variance = np.square(std) @@ -605,8 +612,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) for _ in range(100): @@ -619,8 +626,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -646,8 +654,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) for _ in range(100): @@ -658,8 +666,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 1, 2)) std = np.std(np_inputs, axis=(0, 1, 2)) variance = np.square(std) @@ -667,7 +676,7 @@ class BNTest(test.TestCase): self.assertAllClose(variance, moving_var, atol=1e-2) # Test inference with placeholder learning phase. - np_output = sess.run(outputs_infer) + np_output = self.evaluate(outputs_infer) # Verify that the axis is normalized during inference. normed_np_output = ((np_output - epsilon) * np_gamma) + np_beta @@ -696,8 +705,8 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([gamma, beta]) + self.evaluate(variables.global_variables_initializer()) + np_gamma, np_beta = self.evaluate([gamma, beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) for _ in range(100): @@ -709,8 +718,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - np_moving_mean, np_moving_var = sess.run([moving_mean, moving_variance]) - np_inputs = sess.run(inputs) + np_moving_mean, np_moving_var = self.evaluate( + [moving_mean, moving_variance]) + np_inputs = self.evaluate(inputs) np_mean = np.mean(np_inputs, axis=(0, 1, 2)) np_std = np.std(np_inputs, axis=(0, 1, 2)) np_variance = np.square(np_std) @@ -758,14 +768,15 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(100): np_output, _, _ = sess.run([outputs2] + updates, feed_dict={training: True}) # Verify that the statistics are updated during training. - np_moving_mean, np_moving_var = sess.run([moving_mean, moving_variance]) - np_inputs = sess.run(inputs2) + np_moving_mean, np_moving_var = self.evaluate( + [moving_mean, moving_variance]) + np_inputs = self.evaluate(inputs2) np_mean = np.mean(np_inputs, axis=(0, 1, 2)) np_std = np.std(np_inputs, axis=(0, 1, 2)) np_variance = np.square(np_std) @@ -773,7 +784,7 @@ class BNTest(test.TestCase): self.assertAllClose(np_variance, np_moving_var, atol=1e-2) # Verify that the axis is normalized during training. - np_gamma, np_beta = sess.run([gamma, beta]) + np_gamma, np_beta = self.evaluate([gamma, beta]) np_gamma = np.reshape(np_gamma, (1, 1, 1, 6)) np_beta = np.reshape(np_beta, (1, 1, 1, 6)) normed_np_output = ((np_output - epsilon) * np_gamma) + np_beta @@ -885,7 +896,7 @@ class BNTest(test.TestCase): renorm_mean = renorm_stddev = 0. renorm_weight = 0. with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -937,7 +948,7 @@ class BNTest(test.TestCase): moving_mean = 0. moving_variance = 1. with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) yt_val_train, adj_scale_val, adj_bias_val = sess.run( @@ -990,7 +1001,7 @@ class BNTest(test.TestCase): renorm_mean = renorm_stddev = 0. renorm_weight = 0. with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) yt_val_train, adj_scale_val, adj_bias_val = sess.run( @@ -1040,7 +1051,7 @@ class BNTest(test.TestCase): out1.shape.as_list(), out2.shape.as_list()) with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) x = np.random.random(shape) y1, y2 = sess.run([out1, out2], feed_dict={inp: x}) @@ -1062,7 +1073,7 @@ class BNTest(test.TestCase): inp, virtual_batch_size=2) with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) x = np.random.random(np_shape) y = sess.run(out, feed_dict={inp: x}) @@ -1093,7 +1104,7 @@ class BNTest(test.TestCase): shape[1]]) with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -1146,7 +1157,7 @@ class BNTest(test.TestCase): shape[1:]) with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -1200,7 +1211,7 @@ class BNTest(test.TestCase): shape[1:]) with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) @@ -1256,9 +1267,9 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) for _ in range(100): np_output, _, _ = sess.run([outputs] + bn.updates, @@ -1269,8 +1280,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=0, keepdims=True) std = np.std(np_inputs, axis=0, keepdims=True) variance = np.square(std) @@ -1296,9 +1308,9 @@ class BNTest(test.TestCase): with self.cached_session() as sess: # Test training with placeholder learning phase. - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) - np_gamma, np_beta = sess.run([bn.gamma, bn.beta]) + np_gamma, np_beta = self.evaluate([bn.gamma, bn.beta]) for _ in range(100): np_output, _, _ = sess.run([outputs] + bn.updates, @@ -1309,8 +1321,9 @@ class BNTest(test.TestCase): self.assertAlmostEqual(np.std(normed_np_output), 1., places=1) # Verify that the statistics are updated during training. - moving_mean, moving_var = sess.run([bn.moving_mean, bn.moving_variance]) - np_inputs = sess.run(inputs) + moving_mean, moving_var = self.evaluate( + [bn.moving_mean, bn.moving_variance]) + np_inputs = self.evaluate(inputs) mean = np.mean(np_inputs, axis=(0, 4), keepdims=True) std = np.std(np_inputs, axis=(0, 4), keepdims=True) variance = np.square(std) @@ -1350,7 +1363,7 @@ class BNTest(test.TestCase): shape[1:]) with self.session(use_gpu=True) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(5): x = np.random.random(shape) diff --git a/tensorflow/python/ops/bitwise_ops_test.py b/tensorflow/python/ops/bitwise_ops_test.py index f6f35374c0..739278273b 100644 --- a/tensorflow/python/ops/bitwise_ops_test.py +++ b/tensorflow/python/ops/bitwise_ops_test.py @@ -66,7 +66,8 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): inputs = np.array(raw_inputs, dtype=dtype.as_numpy_dtype) truth = [count_bits(x) for x in inputs] input_tensor = constant_op.constant(inputs, dtype=dtype) - popcnt_result = sess.run(gen_bitwise_ops.population_count(input_tensor)) + popcnt_result = self.evaluate( + gen_bitwise_ops.population_count(input_tensor)) self.assertAllEqual(truth, popcnt_result) def testInvertOp(self): @@ -89,7 +90,7 @@ class BitwiseOpTest(test_util.TensorFlowTestCase): self.assertAllEqual(not_a_or_a, [not_0] * 4) # For unsigned dtypes let's also check the result directly. if dtype.is_unsigned: - inverted = sess.run(bitwise_ops.invert(input_tensor)) + inverted = self.evaluate(bitwise_ops.invert(input_tensor)) expected = [dtype.max - x for x in inputs] self.assertAllEqual(inverted, expected) diff --git a/tensorflow/python/ops/clip_ops_test.py b/tensorflow/python/ops/clip_ops_test.py index 8aa9c4ffb3..e9f7941b42 100644 --- a/tensorflow/python/ops/clip_ops_test.py +++ b/tensorflow/python/ops/clip_ops_test.py @@ -35,7 +35,7 @@ class ClipOpsTest(test.TestCase): input_op = constant_op.constant(inputs) clipped = clip_ops.clip_by_norm(input_op, max_norm) check_op = numerics.add_check_numerics_ops() - result, _ = sess.run([clipped, check_op]) + result, _ = self.evaluate([clipped, check_op]) self.assertAllClose(result, expected) def _testClipIndexedSlicesByNorm(self, values, indices, shape, max_norm, @@ -54,7 +54,7 @@ class ClipOpsTest(test.TestCase): # Tensor mode dense_tensor = ops.convert_to_tensor(indixed_slices) dense_clipped = clip_ops.clip_by_norm(dense_tensor, max_norm, axes) - result, expected = sess.run([clipped, dense_clipped]) + result, expected = self.evaluate([clipped, dense_clipped]) self.assertAllClose(result, expected) def testClipTensorByNorm(self): diff --git a/tensorflow/python/ops/control_flow_ops_test.py b/tensorflow/python/ops/control_flow_ops_test.py index 47675d3f34..c020189ad6 100644 --- a/tensorflow/python/ops/control_flow_ops_test.py +++ b/tensorflow/python/ops/control_flow_ops_test.py @@ -209,9 +209,9 @@ class SwitchTestCase(test_util.TensorFlowTestCase): optimizer = momentum.MomentumOptimizer(0.1, 0.9) train_op = optimizer.minimize(cost) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(10): - sess.run([train_op]) + self.evaluate([train_op]) def testResourceReadInLoop(self): with ops.Graph().as_default(): @@ -232,7 +232,7 @@ class SwitchTestCase(test_util.TensorFlowTestCase): cond, body, [constant_op.constant(0), constant_op.constant(0.0)]) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllEqual(10.0, self.evaluate(cost)) def doTestIndexedSlicesGradientInCondInWhileLoop(self, use_resource=False): @@ -269,8 +269,8 @@ class SwitchTestCase(test_util.TensorFlowTestCase): static_grads.indices) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - self.assertAllEqual(*sess.run([static_grads, dynamic_grads])) + self.evaluate(variables.global_variables_initializer()) + self.assertAllEqual(*self.evaluate([static_grads, dynamic_grads])) def testIndexedSlicesGradientInCondInWhileLoop(self): self.doTestIndexedSlicesGradientInCondInWhileLoop(use_resource=False) @@ -398,9 +398,9 @@ class CondTest(test_util.TensorFlowTestCase): pred=bool_var, true_fn=lambda: state_ops.assign(bool_var, False), false_fn=lambda: True) - sess.run(bool_var.initializer) - self.assertEquals(sess.run(cond_on_bool_var), False) - self.assertEquals(sess.run(cond_on_bool_var), True) + self.evaluate(bool_var.initializer) + self.assertEquals(self.evaluate(cond_on_bool_var), False) + self.assertEquals(self.evaluate(cond_on_bool_var), True) def testCondMissingArg1(self): with ops.Graph().as_default(): diff --git a/tensorflow/python/ops/gradients_test.py b/tensorflow/python/ops/gradients_test.py index 262b62e013..a9058c4a34 100644 --- a/tensorflow/python/ops/gradients_test.py +++ b/tensorflow/python/ops/gradients_test.py @@ -365,7 +365,7 @@ class GradientsTest(test_util.TensorFlowTestCase): grads = gradients.gradients( [y], [x], unconnected_gradients="zero") with self.cached_session() as sess: - self.assertAllEqual([[0.0, 0.0], [0.0, 0.0]], sess.run(grads)[0]) + self.assertAllEqual([[0.0, 0.0], [0.0, 0.0]], self.evaluate(grads)[0]) def testUnconnectedGradientsZeroConnectedGradients(self): with ops.Graph().as_default(): @@ -374,7 +374,7 @@ class GradientsTest(test_util.TensorFlowTestCase): grad = gradients.gradients( [y], [x], unconnected_gradients="zero") with self.cached_session() as sess: - self.assertEquals(3.0, sess.run(grad)[0]) + self.assertEquals(3.0, self.evaluate(grad)[0]) def testUnknownUnconnectedGradientsValueGiven(self): with ops.Graph().as_default(): @@ -438,8 +438,8 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): grads = gradients.gradients(y, [x, b1]) with self.cached_session() as sess: - self.assertAllEqual([40.0], sess.run(grads)[0]) - self.assertAllEqual([10.0], sess.run(grads)[1]) + self.assertAllEqual([40.0], self.evaluate(grads)[0]) + self.assertAllEqual([10.0], self.evaluate(grads)[1]) def testFunctionGradientsWithGradFunc(self): g = ops.Graph() @@ -487,7 +487,7 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): f = Foo() with self.cached_session() as sess: - self.assertEqual(sess.run(f), 2.0) + self.assertEqual(self.evaluate(f), 2.0) def testGradientOfCaptured(self): with ops.Graph().as_default(): @@ -501,7 +501,7 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): f = Foo() with self.cached_session() as sess: - self.assertEqual(sess.run(f), 2.0) + self.assertEqual(self.evaluate(f), 2.0) def testCapturedResourceVariable(self): with ops.Graph().as_default(): @@ -515,8 +515,8 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): f = Foo() with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) - self.assertEqual(sess.run(f), 2.0) + self.evaluate(variables.global_variables_initializer()) + self.assertEqual(self.evaluate(f), 2.0) def testCapturedNested(self): with ops.Graph().as_default(): @@ -541,9 +541,9 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): x1_grad, x2_grad = Outer() with self.cached_session() as sess: # 1.0 + None + 2.0 + 1.0 = 4.0 - self.assertEqual(sess.run(x1_grad), 4.0) + self.assertEqual(self.evaluate(x1_grad), 4.0) # None + 1.0 + 1.0 + None = 2.0 - self.assertEqual(sess.run(x2_grad), 2.0) + self.assertEqual(self.evaluate(x2_grad), 2.0) def testCapturedFromFunction(self): with ops.Graph().as_default(): @@ -563,7 +563,7 @@ class FunctionGradientsTest(test_util.TensorFlowTestCase): z_grad = Outer() with self.cached_session() as sess: - self.assertEqual(sess.run(z_grad), 3.0) + self.assertEqual(self.evaluate(z_grad), 3.0) def testCapturedEagerTensors(self): # Test that we can handle captured eager tensors unrelated to the gradient @@ -873,7 +873,7 @@ class CustomGradientTest(test_util.TensorFlowTestCase): y = MyMultiply(x1, x2) dy = gradients.gradients(y, [x1, x2]) with session.Session() as sess: - self.assertAllEqual([3., 5.], sess.run(dy)) + self.assertAllEqual([3., 5.], self.evaluate(dy)) def testCustomGradientErrors(self): @@ -914,7 +914,7 @@ class CustomGradientTest(test_util.TensorFlowTestCase): for g in grads: self.assertTrue(g is not None) with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) dw = sess.run(math_ops.reduce_sum(grads[1])) self.assertEqual(12., dw) @@ -1074,7 +1074,7 @@ class TensorListGradientsTest(test_util.TensorFlowTestCase): grad = gradients.gradients(tl, a, grad_ys=grad_tl)[0] with self.cached_session() as sess: - self.assertEquals(sess.run(grad), 5.) + self.assertEquals(self.evaluate(grad), 5.) if __name__ == "__main__": diff --git a/tensorflow/python/ops/image_grad_test.py b/tensorflow/python/ops/image_grad_test.py index 32c2f37c0b..0ea15b0d23 100644 --- a/tensorflow/python/ops/image_grad_test.py +++ b/tensorflow/python/ops/image_grad_test.py @@ -44,7 +44,7 @@ class ResizeNearestNeighborOpTest(test.TestCase): out_shape[1:3]) self.assertEqual(out_shape, list(resize_out.get_shape())) - resize_out = sess.run(resize_out) + resize_out = self.evaluate(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) def testGradFromResizeToLargerInBothDims(self): @@ -113,7 +113,7 @@ class ResizeBilinearOpTest(test.TestCase): resize_out = image_ops.resize_bilinear(input_tensor, out_shape[1:3]) self.assertEqual(out_shape, list(resize_out.get_shape())) - resize_out = sess.run(resize_out) + resize_out = self.evaluate(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) def testGradFromResizeToLargerInBothDims(self): @@ -196,7 +196,7 @@ class ResizeBicubicOpTest(test.TestCase): align_corners=align_corners) self.assertEqual(out_shape, list(resize_out.get_shape())) - resize_out = sess.run(resize_out) + resize_out = self.evaluate(resize_out) self.assertEqual(out_shape, list(resize_out.shape)) def testGradFromResizeToLargerInBothDims(self): @@ -273,7 +273,7 @@ class CropAndResizeOpTest(test.TestCase): constant_op.constant( crop_size, shape=[2])) self.assertEqual(crops_shape, list(crops.get_shape())) - crops = sess.run(crops) + crops = self.evaluate(crops) self.assertEqual(crops_shape, list(crops.shape)) def _randomUniformAvoidAnchors(self, low, high, anchors, radius, num_samples): diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index ac2d2698b6..71a574e0a0 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -70,7 +70,8 @@ class RGBToHSVTest(test_util.TensorFlowTestCase): split2 = list(map(image_ops.hsv_to_rgb, split1)) join1 = array_ops.stack(split1) join2 = array_ops.stack(split2) - batch1, batch2, join1, join2 = sess.run([batch1, batch2, join1, join2]) + batch1, batch2, join1, join2 = self.evaluate( + [batch1, batch2, join1, join2]) # Verify that processing batch elements together is the same as separate self.assertAllClose(batch1, join1) @@ -109,7 +110,8 @@ class RGBToYIQTest(test_util.TensorFlowTestCase): split2 = list(map(image_ops.yiq_to_rgb, split1)) join1 = array_ops.stack(split1) join2 = array_ops.stack(split2) - batch1, batch2, join1, join2 = sess.run([batch1, batch2, join1, join2]) + batch1, batch2, join1, join2 = self.evaluate( + [batch1, batch2, join1, join2]) # Verify that processing batch elements together is the same as separate self.assertAllClose(batch1, join1, rtol=1e-4, atol=1e-4) @@ -138,7 +140,8 @@ class RGBToYUVTest(test_util.TensorFlowTestCase): split2 = list(map(image_ops.yuv_to_rgb, split1)) join1 = array_ops.stack(split1) join2 = array_ops.stack(split2) - batch1, batch2, join1, join2 = sess.run([batch1, batch2, join1, join2]) + batch1, batch2, join1, join2 = self.evaluate( + [batch1, batch2, join1, join2]) # Verify that processing batch elements together is the same as separate self.assertAllClose(batch1, join1, rtol=1e-4, atol=1e-4) @@ -488,11 +491,11 @@ class FlipImageBenchmark(test.Benchmark): trainable=False, dtype=dtypes.float32) run_op = image_ops.flip_left_right(inputs) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - sess.run(run_op) + self.evaluate(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -518,11 +521,11 @@ class FlipImageBenchmark(test.Benchmark): trainable=False, dtype=dtypes.float32) run_op = image_ops.random_flip_left_right(inputs) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - sess.run(run_op) + self.evaluate(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -548,11 +551,11 @@ class FlipImageBenchmark(test.Benchmark): trainable=False, dtype=dtypes.float32) run_op = image_ops.random_flip_left_right(inputs) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - sess.run(run_op) + self.evaluate(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -610,11 +613,11 @@ class AdjustHueBenchmark(test.Benchmark): delta = constant_op.constant(0.1, dtype=dtypes.float32) outputs = image_ops.adjust_hue(inputs, delta) run_op = control_flow_ops.group(outputs) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for i in xrange(warmup_rounds + benchmark_rounds): if i == warmup_rounds: start = time.time() - sess.run(run_op) + self.evaluate(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -653,12 +656,12 @@ class AdjustSaturationBenchmark(test.Benchmark): delta = constant_op.constant(0.1, dtype=dtypes.float32) outputs = image_ops.adjust_saturation(inputs, delta) run_op = control_flow_ops.group(outputs) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in xrange(warmup_rounds): - sess.run(run_op) + self.evaluate(run_op) start = time.time() for _ in xrange(benchmark_rounds): - sess.run(run_op) + self.evaluate(run_op) end = time.time() step_time = (end - start) / benchmark_rounds tag = device + "_%s" % (cpu_count if cpu_count is not None else "_all") @@ -698,7 +701,7 @@ class ResizeBilinearBenchmark(test.Benchmark): benchmark_op = control_flow_ops.group(*deps) with self.benchmark_session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) results = self.run_op_benchmark( sess, benchmark_op, @@ -746,7 +749,7 @@ class ResizeBicubicBenchmark(test.Benchmark): benchmark_op = control_flow_ops.group(*deps) with self.benchmark_session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) results = self.run_op_benchmark( sess, benchmark_op, @@ -803,7 +806,7 @@ class ResizeAreaBenchmark(test.Benchmark): benchmark_op = control_flow_ops.group(*deps) with self.benchmark_session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) results = self.run_op_benchmark( sess, benchmark_op, @@ -2265,7 +2268,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): image = constant_op.constant(img_np, shape=img_shape) y = image_ops.resize_images(image, [target_height, target_width], opt) yshape = array_ops.shape(y) - resized, newshape = sess.run([y, yshape]) + resized, newshape = self.evaluate([y, yshape]) self.assertAllEqual(img_shape, newshape) self.assertAllClose(resized, img_np, atol=1e-5) @@ -2379,7 +2382,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): image = constant_op.constant(img_np, shape=img_shape) y = image_ops.resize_images(image, [height, width], opt) yshape = array_ops.shape(y) - resized, newshape = sess.run([y, yshape]) + resized, newshape = self.evaluate([y, yshape]) self.assertAllEqual(img_shape, newshape) self.assertAllClose(resized, img_np, atol=1e-5) @@ -3066,7 +3069,7 @@ class JpegTest(test_util.TensorFlowTestCase): jpeg0 = io_ops.read_file(path) image0 = image_ops.decode_jpeg(jpeg0) image1 = image_ops.decode_jpeg(image_ops.encode_jpeg(image0)) - jpeg0, image0, image1 = sess.run([jpeg0, image0, image1]) + jpeg0, image0, image1 = self.evaluate([jpeg0, image0, image1]) self.assertEqual(len(jpeg0), 3771) self.assertEqual(image0.shape, (256, 128, 3)) self.assertLess(self.averageError(image0, image1), 1.4) @@ -3083,7 +3086,7 @@ class JpegTest(test_util.TensorFlowTestCase): io_ops.read_file(rgb_path), channels=channels) cmyk = image_ops.decode_jpeg( io_ops.read_file(cmyk_path), channels=channels) - rgb, cmyk = sess.run([rgb, cmyk]) + rgb, cmyk = self.evaluate([rgb, cmyk]) self.assertEqual(rgb.shape, shape) self.assertEqual(cmyk.shape, shape) error = self.averageError(rgb, cmyk) @@ -3112,7 +3115,7 @@ class JpegTest(test_util.TensorFlowTestCase): image2.get_shape().as_list()) # CropAndDecode should be equal to DecodeJpeg+Crop. - image1_crop, image2 = sess.run([image1_crop, image2]) + image1_crop, image2 = self.evaluate([image1_crop, image2]) self.assertAllEqual(image1_crop, image2) def testCropAndDecodeJpegWithInvalidCropWindow(self): @@ -3131,7 +3134,7 @@ class JpegTest(test_util.TensorFlowTestCase): with self.assertRaisesWithPredicateMatch( errors.InvalidArgumentError, lambda e: "Invalid JPEG data or crop window" in str(e)): - sess.run(result) + self.evaluate(result) def testSynthetic(self): with self.test_session(use_gpu=True) as sess: @@ -3141,7 +3144,8 @@ class JpegTest(test_util.TensorFlowTestCase): image1 = image_ops.decode_jpeg(jpeg0, dct_method="INTEGER_ACCURATE") image2 = image_ops.decode_jpeg( image_ops.encode_jpeg(image1), dct_method="INTEGER_ACCURATE") - jpeg0, image0, image1, image2 = sess.run([jpeg0, image0, image1, image2]) + jpeg0, image0, image1, image2 = self.evaluate( + [jpeg0, image0, image1, image2]) # The decoded-encoded image should be similar to the input self.assertLess(self.averageError(image0, image1), 0.6) @@ -3161,7 +3165,8 @@ class JpegTest(test_util.TensorFlowTestCase): image1 = image_ops.decode_jpeg(jpeg0, dct_method="INTEGER_FAST") image2 = image_ops.decode_jpeg( image_ops.encode_jpeg(image1), dct_method="INTEGER_FAST") - jpeg0, image0, image1, image2 = sess.run([jpeg0, image0, image1, image2]) + jpeg0, image0, image1, image2 = self.evaluate( + [jpeg0, image0, image1, image2]) # The decoded-encoded image should be similar to the input, but # note this is worse than the slower algorithm because it is @@ -3184,7 +3189,7 @@ class JpegTest(test_util.TensorFlowTestCase): jpeg0 = image_ops.encode_jpeg(image0) image1 = image_ops.decode_jpeg(jpeg0, dct_method="INTEGER_FAST") image2 = image_ops.decode_jpeg(jpeg0) - image1, image2 = sess.run([image1, image2]) + image1, image2 = self.evaluate([image1, image2]) # The images should be the same. self.assertAllClose(image1, image2) @@ -3230,7 +3235,7 @@ class PngTest(test_util.TensorFlowTestCase): with self.test_session(use_gpu=True) as sess: png0 = io_ops.read_file(prefix + filename) image0 = image_ops.decode_png(png0, channels=channels) - png0, image0 = sess.run([png0, image0]) + png0, image0 = self.evaluate([png0, image0]) self.assertEqual(image0.shape, (26, 51, channels or channels_in)) if channels == channels_in: image1 = image_ops.decode_png(image_ops.encode_png(image0)) @@ -3242,7 +3247,7 @@ class PngTest(test_util.TensorFlowTestCase): image0 = constant_op.constant(_SimpleColorRamp()) png0 = image_ops.encode_png(image0, compression=7) image1 = image_ops.decode_png(png0) - png0, image0, image1 = sess.run([png0, image0, image1]) + png0, image0, image1 = self.evaluate([png0, image0, image1]) # PNG is lossless self.assertAllEqual(image0, image1) @@ -3257,7 +3262,7 @@ class PngTest(test_util.TensorFlowTestCase): image0 = constant_op.constant(_SimpleColorRamp(), dtype=dtypes.uint16) png0 = image_ops.encode_png(image0, compression=7) image1 = image_ops.decode_png(png0, dtype=dtypes.uint16) - png0, image0, image1 = sess.run([png0, image0, image1]) + png0, image0, image1 = self.evaluate([png0, image0, image1]) # PNG is lossless self.assertAllEqual(image0, image1) @@ -3273,7 +3278,7 @@ class PngTest(test_util.TensorFlowTestCase): image0 = constant_op.constant(gray_alpha) png0 = image_ops.encode_png(image0, compression=7) image1 = image_ops.decode_png(png0) - png0, image0, image1 = sess.run([png0, image0, image1]) + png0, image0, image1 = self.evaluate([png0, image0, image1]) self.assertEqual(2, image0.shape[-1]) self.assertAllEqual(image0, image1) @@ -3284,7 +3289,7 @@ class PngTest(test_util.TensorFlowTestCase): image0 = constant_op.constant(gray_alpha, dtype=dtypes.uint16) png0 = image_ops.encode_png(image0, compression=7) image1 = image_ops.decode_png(png0, dtype=dtypes.uint16) - png0, image0, image1 = sess.run([png0, image0, image1]) + png0, image0, image1 = self.evaluate([png0, image0, image1]) self.assertEqual(2, image0.shape[-1]) self.assertAllEqual(image0, image1) @@ -3310,7 +3315,7 @@ class GifTest(test_util.TensorFlowTestCase): with self.test_session(use_gpu=True) as sess: gif0 = io_ops.read_file(prefix + filename) image0 = image_ops.decode_gif(gif0) - gif0, image0 = sess.run([gif0, image0]) + gif0, image0 = self.evaluate([gif0, image0]) self.assertEqual(image0.shape, shape) @@ -3829,7 +3834,7 @@ class PSNRTest(test_util.TensorFlowTestCase): "tensorflow/core/lib/psnr/testdata", filename)) im = image_ops.decode_jpeg(content, dct_method="INTEGER_ACCURATE") im = image_ops.convert_image_dtype(im, dtypes.float32) - im, = sess.run([im]) + im, = self.evaluate([im]) return np.expand_dims(im, axis=0) def _LoadTestImages(self): @@ -3936,7 +3941,7 @@ class SSIMTest(test_util.TensorFlowTestCase): "tensorflow/core/lib/ssim/testdata", filename)) im = image_ops.decode_png(content) im = image_ops.convert_image_dtype(im, dtypes.float32) - im, = sess.run([im]) + im, = self.evaluate([im]) return np.expand_dims(im, axis=0) def _LoadTestImages(self): @@ -4028,7 +4033,7 @@ class MultiscaleSSIMTest(test_util.TensorFlowTestCase): "tensorflow/core/lib/ssim/testdata", filename)) im = image_ops.decode_png(content) im = image_ops.convert_image_dtype(im, dtypes.float32) - im, = sess.run([im]) + im, = self.evaluate([im]) return np.expand_dims(im, axis=0) def _LoadTestImages(self): @@ -4110,7 +4115,7 @@ class MultiscaleSSIMTest(test_util.TensorFlowTestCase): images = [ops.convert_to_tensor(x, dtype=dtypes.float32) for x in images] msssim_ops = [image_ops.ssim_multiscale(x, y, 1.0) for x, y in itertools.combinations(images, 2)] - msssim = sess.run(msssim_ops) + msssim = self.evaluate(msssim_ops) msssim = np.squeeze(msssim) self.assertTrue(np.all(msssim >= 0.0)) @@ -4223,7 +4228,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(jpeg0, dtype=dtypes.uint16) image1 = image_ops.convert_image_dtype(image_ops.decode_jpeg(jpeg0), dtypes.uint16) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testPngUint16(self): @@ -4233,7 +4238,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(png0, dtype=dtypes.uint16) image1 = image_ops.convert_image_dtype( image_ops.decode_png(png0, dtype=dtypes.uint16), dtypes.uint16) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testGifUint16(self): @@ -4243,7 +4248,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(gif0, dtype=dtypes.uint16) image1 = image_ops.convert_image_dtype(image_ops.decode_gif(gif0), dtypes.uint16) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testBmpUint16(self): @@ -4253,7 +4258,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(bmp0, dtype=dtypes.uint16) image1 = image_ops.convert_image_dtype(image_ops.decode_bmp(bmp0), dtypes.uint16) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testJpegFloat32(self): @@ -4263,7 +4268,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(jpeg0, dtype=dtypes.float32) image1 = image_ops.convert_image_dtype(image_ops.decode_jpeg(jpeg0), dtypes.float32) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testPngFloat32(self): @@ -4273,7 +4278,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(png0, dtype=dtypes.float32) image1 = image_ops.convert_image_dtype( image_ops.decode_png(png0, dtype=dtypes.uint16), dtypes.float32) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testGifFloat32(self): @@ -4283,7 +4288,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(gif0, dtype=dtypes.float32) image1 = image_ops.convert_image_dtype(image_ops.decode_gif(gif0), dtypes.float32) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) def testBmpFloat32(self): @@ -4293,7 +4298,7 @@ class DecodeImageTest(test_util.TensorFlowTestCase): image0 = image_ops.decode_image(bmp0, dtype=dtypes.float32) image1 = image_ops.convert_image_dtype(image_ops.decode_bmp(bmp0), dtypes.float32) - image0, image1 = sess.run([image0, image1]) + image0, image1 = self.evaluate([image0, image1]) self.assertAllEqual(image0, image1) diff --git a/tensorflow/python/ops/init_ops_test.py b/tensorflow/python/ops/init_ops_test.py index 5693c3caaf..1f22248004 100644 --- a/tensorflow/python/ops/init_ops_test.py +++ b/tensorflow/python/ops/init_ops_test.py @@ -45,8 +45,8 @@ class InitializersTest(test.TestCase): output = variable.numpy() else: sess = ops.get_default_session() - sess.run(variable.initializer) - output = sess.run(variable) + self.evaluate(variable.initializer) + output = self.evaluate(variable) lim = 3e-2 if target_std is not None: self.assertGreater(lim, abs(output.std() - target_std)) diff --git a/tensorflow/python/ops/math_ops_test.py b/tensorflow/python/ops/math_ops_test.py index adcaa7abff..cd45b6f136 100644 --- a/tensorflow/python/ops/math_ops_test.py +++ b/tensorflow/python/ops/math_ops_test.py @@ -373,7 +373,7 @@ class AddNTest(test_util.TensorFlowTestCase): for i in range(0, num_inputs) ] addn = math_ops.add_n(input_vars) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) add_n_grad = gradients.gradients(addn, input_vars) self.assertAllEqual(np.repeat(1.0, num_inputs), # d/dx (x + y + ...) = 1 [g.eval() for g in add_n_grad]) @@ -461,7 +461,7 @@ class DivAndModTest(test_util.TensorFlowTestCase): a = variables.Variable(2.) b = variables.Variable(4.) with self.cached_session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) c_grad = gradients.gradients(math_ops.divide(a, b), [a, b]) self.assertAllEqual([x.eval() for x in c_grad], [.25, -.125]) c_grad = gradients.gradients(math_ops.div(a, b), [a, b]) diff --git a/tensorflow/python/ops/nccl_ops_test.py b/tensorflow/python/ops/nccl_ops_test.py index 1b496fec47..3b2e2b0175 100644 --- a/tensorflow/python/ops/nccl_ops_test.py +++ b/tensorflow/python/ops/nccl_ops_test.py @@ -102,7 +102,7 @@ class NcclTestCase(test.TestCase): continue # Test execution and results. - for t in sess.run(result_tensors): + for t in self.evaluate(result_tensors): self.assertAllClose(t, np_ans) def _TestGradient(self, nccl_reduce, numpy_fn): diff --git a/tensorflow/python/ops/nn_batchnorm_test.py b/tensorflow/python/ops/nn_batchnorm_test.py index b50bccfde2..31b2790f2b 100644 --- a/tensorflow/python/ops/nn_batchnorm_test.py +++ b/tensorflow/python/ops/nn_batchnorm_test.py @@ -235,10 +235,11 @@ class BatchNormalizationTest(test.TestCase): odx, odm, odv, odb, odg = gradients_impl.gradients( [on], [x, m, v, beta, gamma], [backprop]) if scale_after_normalization: - all_grads = sess.run([dx, dm, dv, db, dg, odx, odm, odv, odb, odg]) + all_grads = self.evaluate( + [dx, dm, dv, db, dg, odx, odm, odv, odb, odg]) to_check = ["dx", "dm", "dv", "db", "dg"] else: - all_grads = sess.run([dx, dm, dv, db, odx, odm, odv, odb]) + all_grads = self.evaluate([dx, dm, dv, db, odx, odm, odv, odb]) to_check = ["dx", "dm", "dv", "db"] for i, _ in enumerate(to_check): self.assertAllClose( @@ -318,7 +319,7 @@ class BatchNormalizationTest(test.TestCase): gamma_val, epsilon, scale_after_normalization, shift_after_normalization) - [tf_batch_norm] = sess.run([bn]) + [tf_batch_norm] = self.evaluate([bn]) self.assertEquals(x_shape, np_batch_norm.shape) self.assertEquals(x_shape, tf_batch_norm.shape) self.assertAllClose(np_batch_norm, tf_batch_norm, atol=atol) @@ -371,9 +372,9 @@ class SufficientStatisticsTest(test.TestCase): x.set_shape(x_shape) op_c, op_m, op_v, op_s = self._opSuffStats(x, axes, shift, keep_dims) if shift: - tf_c, tf_m, tf_v, tf_s = sess.run([op_c, op_m, op_v, op_s]) + tf_c, tf_m, tf_v, tf_s = self.evaluate([op_c, op_m, op_v, op_s]) else: - tf_c, tf_m, tf_v = sess.run([op_c, op_m, op_v]) + tf_c, tf_m, tf_v = self.evaluate([op_c, op_m, op_v]) else: x = array_ops.placeholder( dtype=dtypes.float32, shape=[None] * len(x_shape), name="x") @@ -432,7 +433,7 @@ class NormalizeMomentsTest(test.TestCase): tf_shift_v = None opm, opv = self._opNormalizeMoments(tf_counts, tf_mean_ss, tf_variance_ss, tf_shift_v) - tfm, tfv = sess.run([opm, opv]) + tfm, tfv = self.evaluate([opm, opv]) self.assertAllClose(npm, tfm, atol=0.000001) self.assertAllClose(npv, tfv, atol=0.000001) diff --git a/tensorflow/python/ops/nn_fused_batchnorm_test.py b/tensorflow/python/ops/nn_fused_batchnorm_test.py index a6c582fcac..4bc33ff8bd 100644 --- a/tensorflow/python/ops/nn_fused_batchnorm_test.py +++ b/tensorflow/python/ops/nn_fused_batchnorm_test.py @@ -82,7 +82,7 @@ class BatchNormalizationTest(test.TestCase): epsilon=epsilon, data_format=data_format, is_training=False) - y_val = sess.run(y) + y_val = self.evaluate(y) y_ref = self._inference_ref(x, scale, offset, mean, var, epsilon, data_format) # An atol value of 1e-3 is too small for float16's, because some adjacent @@ -127,7 +127,7 @@ class BatchNormalizationTest(test.TestCase): epsilon=epsilon, data_format=data_format, is_training=True) - y_val, mean_val, var_val = sess.run([y, mean, var]) + y_val, mean_val, var_val = self.evaluate([y, mean, var]) y_ref, mean_ref, var_ref = self._training_ref(x, scale, offset, epsilon, data_format) y_atol = 2e-3 if x_dtype == np.float16 else 1e-3 @@ -277,10 +277,10 @@ class BatchNormalizationTest(test.TestCase): if is_training: epsilon = y.op.get_attr('epsilon') data_format = y.op.get_attr('data_format') - grad_vals = sess.run([grad_x, grad_scale, grad_offset]) + grad_vals = self.evaluate([grad_x, grad_scale, grad_offset]) grad_internal = nn_grad._BatchNormGrad(grad_y, x, scale, pop_mean, pop_var, epsilon, data_format) - grad_internal_vals = sess.run(list(grad_internal)) + grad_internal_vals = self.evaluate(list(grad_internal)) for grad_val, grad_internal_val in zip(grad_vals, grad_internal_vals): self.assertAllClose(grad_val, grad_internal_val, atol=err_tolerance) diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py index 72db0952b4..017bc9dae5 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py @@ -1090,7 +1090,7 @@ class TensorArrayTest(PForTest): # y = x * x. Hence dy/dx = 2 * x. actual_grad = 2.0 * x with session.Session() as sess: - actual_grad, computed_grad = sess.run([t1, actual_grad]) + actual_grad, computed_grad = self.evaluate([t1, actual_grad]) self.assertAllClose(actual_grad, computed_grad) @@ -1244,7 +1244,7 @@ class ControlFlowTest(PForTest): expected_output = array_ops.transpose(expected_output, [1, 0]) with session.Session() as sess: - out, expected = sess.run([out, expected_output]) + out, expected = self.evaluate([out, expected_output]) self.assertAllClose(expected, out) def test_tensor_array_as_loop_variable(self): @@ -1432,7 +1432,7 @@ class Benchmarks(test.Benchmark): sess = session.Session() with sess: init = variables.global_variables_initializer() - sess.run(init) + self.evaluate(init) run_fn = sess.make_callable(targets) run_fn() # Warm up begin = time.time() diff --git a/tensorflow/python/ops/parallel_for/gradients_test.py b/tensorflow/python/ops/parallel_for/gradients_test.py index bbb46539ea..4342833e3e 100644 --- a/tensorflow/python/ops/parallel_for/gradients_test.py +++ b/tensorflow/python/ops/parallel_for/gradients_test.py @@ -484,8 +484,8 @@ class GradientsTest(test.TestCase): pfor_jacobian, while_gradients = create_dynamic_lstm_batch_jacobian(8, 4, 3) with session.Session() as sess: init = variables.global_variables_initializer() - sess.run(init) - pfor = sess.run(pfor_jacobian) + self.evaluate(init) + pfor = self.evaluate(pfor_jacobian) for i in range(4): while_i = sess.run(while_gradients[i]) self.assertAllClose(while_i, pfor[:, i, ...]) @@ -560,11 +560,11 @@ class GradientsBenchmarks(test.Benchmark): sess = session.Session() with sess: init = variables.global_variables_initializer() - sess.run(init) - sess.run(targets) + self.evaluate(init) + self.evaluate(targets) begin = time.time() for _ in range(iters): - sess.run(targets) + self.evaluate(targets) end = time.time() avg_time_ms = 1000 * (end - begin) / iters self.report_benchmark(iters=iters, wall_time=avg_time_ms, name=name) diff --git a/tensorflow/python/ops/quantized_conv_ops_test.py b/tensorflow/python/ops/quantized_conv_ops_test.py index f7fa264461..6b469a954f 100644 --- a/tensorflow/python/ops/quantized_conv_ops_test.py +++ b/tensorflow/python/ops/quantized_conv_ops_test.py @@ -73,7 +73,7 @@ class Conv2DTest(test.TestCase): max_input=x1_max, min_filter=x2_min, max_filter=x2_max) - value = sess.run(conv) + value = self.evaluate(conv) quantized_output = value[0] output_min = value[1] output_max = value[2] diff --git a/tensorflow/python/ops/quantized_ops_test.py b/tensorflow/python/ops/quantized_ops_test.py index 0f3b04e4ad..b81843d174 100644 --- a/tensorflow/python/ops/quantized_ops_test.py +++ b/tensorflow/python/ops/quantized_ops_test.py @@ -41,7 +41,7 @@ class QuantizedOpsTest(test.TestCase): x_min = 0.0 x_max = 255.0 op = array_ops.quantize(x, x_min, x_max, dtypes.quint8, mode="MIN_FIRST") - value = sess.run(op) + value = self.evaluate(op) self.assertArrayNear(expected_output, value.output, 0.1) def testDequantizeOp(self): @@ -52,7 +52,7 @@ class QuantizedOpsTest(test.TestCase): x_min = 0.0 x_max = 255.0 op = array_ops.dequantize(x, x_min, x_max, mode="MIN_FIRST") - value = sess.run(op) + value = self.evaluate(op) self.assertArrayNear(expected_output, value, 0.1) diff --git a/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py b/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py index dcf1feaa69..c52db9e2a1 100644 --- a/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_gather_nd_op_test.py @@ -190,7 +190,7 @@ class RaggedGatherNdOpTest(test_util.TensorFlowTestCase, with self.test_session() as sess: if hasattr(expected, 'tolist'): expected = expected.tolist() - self.assertEqual(sess.run(result).tolist(), expected) + self.assertEqual(self.evaluate(result).tolist(), expected) def testRaggedGatherNdUnknownRankError(self): params = ragged.constant([['a', 'b'], ['c', 'd']]) diff --git a/tensorflow/python/ops/ragged/ragged_segment_op_test.py b/tensorflow/python/ops/ragged/ragged_segment_op_test.py index 373a332f13..228c9bc5e4 100644 --- a/tensorflow/python/ops/ragged/ragged_segment_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_segment_op_test.py @@ -119,7 +119,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, segmented = segment_op(rt, segment_ids, num_segments) with self.test_session(): - self.assertListEqual(segmented.eval().tolist(), expected) + self.assertListEqual(self.evaluate(segmented).tolist(), expected) @parameterized.parameters( (ragged.segment_sum, sum, [0, 0, 1, 1, 2, 2]), @@ -173,7 +173,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, [[411, 412], [321, 322], [331]] # row 2 ] # pyformat: disable with self.test_session(): - self.assertEqual(segmented1.eval().tolist(), expected1) + self.assertEqual(self.evaluate(segmented1).tolist(), expected1) segment_ids2 = [1, 2, 1, 1] segmented2 = ragged.segment_sum(rt, segment_ids2, 3) @@ -181,7 +181,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, [[111+411, 112+412, 113, 114], [121+321, 322], [331]], []] # pyformat: disable with self.test_session(): - self.assertEqual(segmented2.eval().tolist(), expected2) + self.assertEqual(self.evaluate(segmented2).tolist(), expected2) def testRaggedSegmentIds(self): rt = ragged.constant([ @@ -196,7 +196,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, [111+321, 112+322, 113, 114], [121+331+411, 412]] # pyformat: disable with self.test_session(): - self.assertEqual(segmented.eval().tolist(), expected) + self.assertEqual(self.evaluate(segmented).tolist(), expected) def testShapeMismatchError1(self): dt = constant_op.constant([1, 2, 3, 4, 5, 6]) diff --git a/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py b/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py index a1c10aff9d..cd382fe0b8 100644 --- a/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py @@ -29,7 +29,8 @@ class RaggedTensorBoundingShapeOp(test_util.TensorFlowTestCase): # This is the example from ragged.bounding_shape.__doc__. rt = ragged.constant([[1, 2, 3, 4], [5], [], [6, 7, 8, 9], [10]]) with self.test_session(): - self.assertEqual(ragged.bounding_shape(rt).eval().tolist(), [5, 4]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt)).tolist(), [5, 4]) def test2DRaggedTensorWithOneRaggedDimension(self): values = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] @@ -37,9 +38,12 @@ class RaggedTensorBoundingShapeOp(test_util.TensorFlowTestCase): rt2 = ragged.from_row_splits(values, [0, 7]) rt3 = ragged.from_row_splits(values, [0, 0, 7, 7]) with self.test_session(): - self.assertEqual(ragged.bounding_shape(rt1).eval().tolist(), [5, 3]) - self.assertEqual(ragged.bounding_shape(rt2).eval().tolist(), [1, 7]) - self.assertEqual(ragged.bounding_shape(rt3).eval().tolist(), [3, 7]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt1)).tolist(), [5, 3]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt2)).tolist(), [1, 7]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt3)).tolist(), [3, 7]) def test3DRaggedTensorWithOneRaggedDimension(self): values = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]] @@ -47,22 +51,26 @@ class RaggedTensorBoundingShapeOp(test_util.TensorFlowTestCase): rt2 = ragged.from_row_splits(values, [0, 7]) rt3 = ragged.from_row_splits(values, [0, 0, 7, 7]) with self.test_session(): - self.assertEqual(ragged.bounding_shape(rt1).eval().tolist(), [5, 3, 2]) - self.assertEqual(ragged.bounding_shape(rt2).eval().tolist(), [1, 7, 2]) - self.assertEqual(ragged.bounding_shape(rt3).eval().tolist(), [3, 7, 2]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt1)).tolist(), [5, 3, 2]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt2)).tolist(), [1, 7, 2]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt3)).tolist(), [3, 7, 2]) def testNonRaggedTensor(self): dt = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] with self.test_session(): - self.assertEqual(ragged.bounding_shape(dt).eval().tolist(), [4, 3]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(dt)).tolist(), [4, 3]) def testExplicitAxisOptimizations(self): rt = ragged.from_row_splits(b'a b c d e f g'.split(), [0, 2, 5, 6, 6, 7]) with self.test_session(): - self.assertEqual(ragged.bounding_shape(rt, 0).eval().tolist(), 5) - self.assertEqual(ragged.bounding_shape(rt, 1).eval().tolist(), 3) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt, 0)).tolist(), 5) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt, 1)).tolist(), 3) self.assertEqual( - ragged.bounding_shape(rt, [1, 0]).eval().tolist(), [3, 5]) + self.evaluate(ragged.bounding_shape(rt, [1, 0])).tolist(), [3, 5]) if __name__ == '__main__': diff --git a/tensorflow/python/ops/ragged/ragged_tensor_test.py b/tensorflow/python/ops/ragged/ragged_tensor_test.py index f66ca102ef..66b15d9bcc 100644 --- a/tensorflow/python/ops/ragged/ragged_tensor_test.py +++ b/tensorflow/python/ops/ragged/ragged_tensor_test.py @@ -264,7 +264,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_value_rowids, value_rowids) # cached_value_rowids with self.test_session(): self.assertAllEqual(rt_value_rowids, value_rowids) - self.assertEqual(rt_nrows.eval(), 5) + self.assertEqual(self.evaluate(rt_nrows), 5) self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) @@ -287,7 +287,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_value_rowids, value_rowids) # cached_value_rowids with self.test_session(): self.assertAllEqual(rt_value_rowids, value_rowids) - self.assertEqual(rt_nrows.eval(), 5) + self.assertEqual(self.evaluate(rt_nrows), 5) self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) @@ -345,7 +345,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertEqual(rt.values.shape.as_list(), [0]) self.assertEqual(ragged.value_rowids(rt).shape.as_list(), [0]) with self.test_session(): - self.assertEqual(rt_nrows.eval().tolist(), 0) + self.assertEqual(self.evaluate(rt_nrows).tolist(), 0) self.assertEqual(rt.tolist(), []) def testFromRowSplits(self): @@ -364,7 +364,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_row_splits, row_splits) with self.test_session(): - self.assertEqual(rt_nrows.eval(), 5) + self.assertEqual(self.evaluate(rt_nrows), 5) self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) @@ -388,7 +388,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) with self.test_session(): - self.assertEqual(rt_nrows.eval(), 5) + self.assertEqual(self.evaluate(rt_nrows), 5) self.assertAllEqual(rt_row_starts, row_starts) self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) @@ -408,7 +408,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) with self.test_session(): - self.assertEqual(rt_nrows.eval(), 5) + self.assertEqual(self.evaluate(rt_nrows), 5) self.assertAllEqual(rt_row_limits, row_limits) self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) @@ -429,7 +429,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_row_lengths, row_lengths) # cached_nrows with self.test_session(): - self.assertEqual(rt_nrows.eval(), 5) + self.assertEqual(self.evaluate(rt_nrows), 5) self.assertAllEqual(rt_row_lengths, row_lengths) self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) @@ -606,21 +606,28 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.test_session(): self.assertEqual(rt.tolist(), [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) - self.assertEqual(rt.values.eval().tolist(), - [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) + self.assertEqual( + self.evaluate(rt.values).tolist(), + [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) self.assertEqual(rt.values.shape.dims[0].value, 7) self.assertEqual( - ragged.value_rowids(rt).eval().tolist(), [0, 0, 2, 2, 2, 3, 4]) - self.assertEqual(ragged.nrows(rt).eval().tolist(), 5) - self.assertEqual(rt.row_splits.eval().tolist(), [0, 2, 2, 5, 6, 7]) - self.assertEqual(ragged.row_starts(rt).eval().tolist(), [0, 2, 2, 5, 6]) - self.assertEqual(ragged.row_limits(rt).eval().tolist(), [2, 2, 5, 6, 7]) + self.evaluate(ragged.value_rowids(rt)).tolist(), + [0, 0, 2, 2, 2, 3, 4]) + self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 5) + self.assertEqual( + self.evaluate(rt.row_splits).tolist(), [0, 2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 2, 5, 6]) + self.assertEqual( + self.evaluate(ragged.row_limits(rt)).tolist(), [2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 0, 3, 1, 1]) self.assertEqual( - ragged.row_lengths(rt).eval().tolist(), [2, 0, 3, 1, 1]) - self.assertEqual(rt.inner_values.eval().tolist(), - [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) - self.assertEqual([s.eval().tolist() for s in rt.nested_row_splits], - [[0, 2, 2, 5, 6, 7]]) + self.evaluate(rt.inner_values).tolist(), + [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) + self.assertEqual( + [self.evaluate(s).tolist() for s in rt.nested_row_splits], + [[0, 2, 2, 5, 6, 7]]) def testRaggedTensorAccessors_3d_with_ragged_rank_1(self): values = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]] @@ -635,22 +642,27 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): [[[0, 1], [2, 3]], [], [[4, 5], [6, 7], [8, 9]], [[10, 11]], [[12, 13]]]) self.assertEqual( - rt.values.eval().tolist(), + self.evaluate(rt.values).tolist(), [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]]) self.assertEqual(rt.values.shape.dims[0].value, 7) self.assertEqual( - ragged.value_rowids(rt).eval().tolist(), [0, 0, 2, 2, 2, 3, 4]) - self.assertEqual(ragged.nrows(rt).eval().tolist(), 5) - self.assertEqual(rt.row_splits.eval().tolist(), [0, 2, 2, 5, 6, 7]) - self.assertEqual(ragged.row_starts(rt).eval().tolist(), [0, 2, 2, 5, 6]) - self.assertEqual(ragged.row_limits(rt).eval().tolist(), [2, 2, 5, 6, 7]) + self.evaluate(ragged.value_rowids(rt)).tolist(), + [0, 0, 2, 2, 2, 3, 4]) + self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 5) + self.assertEqual( + self.evaluate(rt.row_splits).tolist(), [0, 2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 2, 5, 6]) + self.assertEqual( + self.evaluate(ragged.row_limits(rt)).tolist(), [2, 2, 5, 6, 7]) self.assertEqual( - ragged.row_lengths(rt).eval().tolist(), [2, 0, 3, 1, 1]) + self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 0, 3, 1, 1]) self.assertEqual( - rt.inner_values.eval().tolist(), + self.evaluate(rt.inner_values).tolist(), [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]]) - self.assertEqual([s.eval().tolist() for s in rt.nested_row_splits], - [[0, 2, 2, 5, 6, 7]]) + self.assertEqual( + [self.evaluate(s).tolist() for s in rt.nested_row_splits], + [[0, 2, 2, 5, 6, 7]]) def testRaggedTensorAccessors_3d_with_ragged_rank_2(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -670,32 +682,38 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertEqual( rt.tolist(), [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) - self.assertEqual(rt.values.eval().tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual( + self.evaluate(rt.values).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) self.assertEqual(rt.values.shape.dims[0].value, 5) self.assertEqual( - ragged.value_rowids(rt).eval().tolist(), [0, 0, 1, 3, 3]) - self.assertEqual(ragged.nrows(rt).eval().tolist(), 4) - self.assertEqual(rt.row_splits.eval().tolist(), [0, 2, 3, 3, 5]) - self.assertEqual(ragged.row_starts(rt).eval().tolist(), [0, 2, 3, 3]) - self.assertEqual(ragged.row_limits(rt).eval().tolist(), [2, 3, 3, 5]) - self.assertEqual(ragged.row_lengths(rt).eval().tolist(), [2, 1, 0, 2]) - self.assertEqual(rt.inner_values.eval().tolist(), - [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) - self.assertEqual([s.eval().tolist() for s in rt.nested_row_splits], - [[0, 2, 3, 3, 5], [0, 2, 2, 5, 6, 7]]) + self.evaluate(ragged.value_rowids(rt)).tolist(), [0, 0, 1, 3, 3]) + self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 4) + self.assertEqual(self.evaluate(rt.row_splits).tolist(), [0, 2, 3, 3, 5]) + self.assertEqual( + self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 3, 3]) + self.assertEqual( + self.evaluate(ragged.row_limits(rt)).tolist(), [2, 3, 3, 5]) + self.assertEqual( + self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 1, 0, 2]) + self.assertEqual( + self.evaluate(rt.inner_values).tolist(), + [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) + self.assertEqual( + [self.evaluate(s).tolist() for s in rt.nested_row_splits], + [[0, 2, 3, 3, 5], [0, 2, 2, 5, 6, 7]]) def testNRowsWithTensorInput(self): dt = constant_op.constant([[1, 2, 3], [4, 5, 6]]) nrows = ragged.nrows(dt) with self.test_session(): - self.assertEqual(nrows.eval(), 2) + self.assertEqual(self.evaluate(nrows), 2) def testRowLengthsWithTensorInput(self): dt = constant_op.constant([[1, 2, 3], [4, 5, 6]]) row_lengths = ragged.row_lengths(dt) with self.test_session(): - self.assertEqual(row_lengths.eval().tolist(), [3, 3]) + self.assertEqual(self.evaluate(row_lengths).tolist(), [3, 3]) #============================================================================= # RaggedTensor.shape @@ -751,9 +769,9 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): with self.test_session(): tensor_slice_spec1 = _make_tensor_slice_spec(slice_spec, True) tensor_slice_spec2 = _make_tensor_slice_spec(slice_spec, False) - value1 = rt.__getitem__(slice_spec).eval() - value2 = rt.__getitem__(tensor_slice_spec1).eval() - value3 = rt.__getitem__(tensor_slice_spec2).eval() + value1 = self.evaluate(rt.__getitem__(slice_spec)) + value2 = self.evaluate(rt.__getitem__(tensor_slice_spec1)) + value3 = self.evaluate(rt.__getitem__(tensor_slice_spec2)) if hasattr(value1, 'tolist'): value1 = value1.tolist() if hasattr(value2, 'tolist'): diff --git a/tensorflow/python/profiler/model_analyzer_test.py b/tensorflow/python/profiler/model_analyzer_test.py index 94c685274a..8648f0b514 100644 --- a/tensorflow/python/profiler/model_analyzer_test.py +++ b/tensorflow/python/profiler/model_analyzer_test.py @@ -93,10 +93,10 @@ class PrintModelAnalysisTest(test.TestCase): config=self._no_rewrite_session_config()) as sess, ops.device(dev): x = lib.BuildSmallModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) pctx.trace_next_step() pctx.dump_next_step() - _ = sess.run(x) + _ = self.evaluate(x) pctx.profiler.profile_name_scope(options=opts) @@ -160,7 +160,7 @@ class PrintModelAnalysisTest(test.TestCase): ) as sess, ops.device('/device:CPU:0'): x = lib.BuildSmallModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -186,7 +186,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -220,9 +220,9 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) pctx.trace_next_step() - _ = sess.run(x) + _ = self.evaluate(x) tfprof_node = pctx.profiler.profile_python(options=opts) # pylint: disable=line-too-long @@ -281,7 +281,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -309,7 +309,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run( x, @@ -345,7 +345,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -391,7 +391,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run( x, @@ -424,7 +424,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildFullModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run( x, @@ -490,7 +490,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -555,7 +555,7 @@ class PrintModelAnalysisTest(test.TestCase): with session.Session(config=self._no_rewrite_session_config()) as sess: x = lib.BuildSmallModel() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) run_meta = config_pb2.RunMetadata() _ = sess.run(x, options=config_pb2.RunOptions( @@ -587,10 +587,10 @@ class PrintModelAnalysisTest(test.TestCase): def _trainLoop(self, train_op, train_steps, time_dir, time_step, memory_dir, memory_step, profile_dir, dump_step): with session.Session(config=self._no_rewrite_session_config()) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # start from 1 because variable_initializer took one step. for i in range(1, train_steps + 1): - _ = sess.run(train_op) + _ = self.evaluate(train_op) if i in time_step: ret = gfile.ListDirectory(time_dir) self.assertEqual(len(ret), 1) diff --git a/tensorflow/python/profiler/profile_context_test.py b/tensorflow/python/profiler/profile_context_test.py index 107ad443c3..680cd71d1f 100644 --- a/tensorflow/python/profiler/profile_context_test.py +++ b/tensorflow/python/profiler/profile_context_test.py @@ -48,10 +48,10 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir()) as pctx: pctx.add_auto_profiling("op", options=opts, profile_steps=[15, 50, 100]) with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) total_steps = 101 for i in range(total_steps): - sess.run(x) + self.evaluate(x) if i == 14 or i == 49: self.assertTrue(gfile.Exists(outfile)) gfile.Remove(outfile) @@ -75,18 +75,18 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir(), debug=True): with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(10): - sess.run(x) + self.evaluate(x) for f in gfile.ListDirectory(test.get_temp_dir()): # Warm up, no tracing. self.assertFalse("run_meta" in f) - sess.run(x) + self.evaluate(x) self.assertTrue( gfile.Exists(os.path.join(test.get_temp_dir(), "run_meta_11"))) gfile.Remove(os.path.join(test.get_temp_dir(), "run_meta_11")) # fetched already. - sess.run(x) + self.evaluate(x) for f in gfile.ListDirectory(test.get_temp_dir()): self.assertFalse("run_meta" in f) @@ -96,18 +96,18 @@ class ProfilerContextTest(test.TestCase): with profile_context.ProfileContext(test.get_temp_dir(), enabled=False) as pctx: with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(10): - sess.run(x) + self.evaluate(x) self.assertTrue(pctx.profiler is None) self.assertTrue( getattr(session.BaseSession, "profile_context", None) is None) with profile_context.ProfileContext(test.get_temp_dir()) as pctx: with session.Session() as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for _ in range(10): - sess.run(x) + self.evaluate(x) self.assertFalse(pctx.profiler is None) self.assertFalse( getattr(session.BaseSession, "profile_context", None) is None) diff --git a/tensorflow/python/saved_model/loader_test.py b/tensorflow/python/saved_model/loader_test.py index 648c1c5928..3678e505bd 100644 --- a/tensorflow/python/saved_model/loader_test.py +++ b/tensorflow/python/saved_model/loader_test.py @@ -50,7 +50,7 @@ class SavedModelLoaderTest(test.TestCase): x = variables.VariableV1(5, name="x") y = variables.VariableV1(11, name="y") z = x + y - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) foo_sig_def = signature_def_utils.build_signature_def( {"foo_input": utils.build_tensor_info(x)}, @@ -104,9 +104,9 @@ class SavedModelLoaderTest(test.TestCase): with self.session(graph=graph) as sess: # Check that x and y are not initialized with self.assertRaises(errors.FailedPreconditionError): - sess.run(x) + self.evaluate(x) with self.assertRaises(errors.FailedPreconditionError): - sess.run(y) + self.evaluate(y) def test_load_with_import_scope(self): loader = loader_impl.SavedModelLoader(SAVED_MODEL_WITH_MAIN_OP) @@ -138,7 +138,7 @@ class SavedModelLoaderTest(test.TestCase): y = variables.VariableV1(0, name="y") z = x * y - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # There are variables to restore, so a saver must be created. with self.assertRaises(ValueError): diff --git a/tensorflow/python/saved_model/saved_model_test.py b/tensorflow/python/saved_model/saved_model_test.py index a40ea7687f..e722b6ceae 100644 --- a/tensorflow/python/saved_model/saved_model_test.py +++ b/tensorflow/python/saved_model/saved_model_test.py @@ -61,7 +61,7 @@ class SavedModelTestBase(test.TestCase): def _init_and_validate_variable(self, sess, variable_name, variable_value): v = variables.VariableV1(variable_value, name=variable_name) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(variable_value, self.evaluate(v)) def _build_asset_collection(self, asset_file_name, asset_file_contents, @@ -389,7 +389,7 @@ class SavedModelTest(SavedModelTestBase): a = ops.get_default_graph().get_tensor_by_name(constant_5_name) b = constant_op.constant(6.0) c = a * b - self.assertEqual(30.0, sess.run(c)) + self.assertEqual(30.0, self.evaluate(c)) # Restore the graph with tag "bar". with self.session(graph=ops.Graph()) as sess: @@ -398,7 +398,7 @@ class SavedModelTest(SavedModelTestBase): a = ops.get_default_graph().get_tensor_by_name(constant_6_name) b = constant_op.constant(5.0) c = a * b - self.assertEqual(30.0, sess.run(c)) + self.assertEqual(30.0, self.evaluate(c)) def testNoOverwrite(self): export_dir = self._get_export_dir("test_no_overwrite") @@ -464,7 +464,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: v = variables.VariableV1(42, name="v") ops.add_to_collection("foo_vars", v) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(42, self.evaluate(v)) builder.add_meta_graph_and_variables(sess, ["foo"]) @@ -474,7 +474,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: v = variables.VariableV1(43, name="v") ops.add_to_collection("bar_vars", v) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(43, self.evaluate(v)) builder.add_meta_graph(["bar"]) @@ -802,7 +802,7 @@ class SavedModelTest(SavedModelTestBase): add_v1_v2 = math_ops.add(v1._ref(), v2._ref()) custom_main_op = control_flow_ops.group(state_ops.assign(v3, add_v1_v2)) - sess.run(custom_main_op) + self.evaluate(custom_main_op) builder.add_meta_graph_and_variables( sess, ["foo"], main_op=custom_main_op) @@ -836,7 +836,7 @@ class SavedModelTest(SavedModelTestBase): assign_v3 = state_ops.assign(v3, math_ops.add(v1, v2)) legacy_init_op = control_flow_ops.group(assign_v3, name="legacy_init_op") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) builder.add_meta_graph_and_variables( sess, ["foo"], legacy_init_op=legacy_init_op) @@ -879,7 +879,7 @@ class SavedModelTest(SavedModelTestBase): assign_v2 = state_ops.assign(v2, v1) init_op = control_flow_ops.group(assign_v2, name="init_op") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) ops.add_to_collection(key, control_flow_ops.no_op()) # ValueError should be raised since the LEGACY_INIT_OP_KEY collection @@ -902,10 +902,10 @@ class SavedModelTest(SavedModelTestBase): v2 = variables.VariableV1(2, name="v2") ops.add_to_collection("v", v2) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) train_op = state_ops.assign_add(v1, v2) - sess.run(train_op) + self.evaluate(train_op) # TODO(karmel): remove explicit call when in the public method. builder._add_train_op(train_op) builder.add_meta_graph_and_variables(sess, ["foo"]) @@ -931,10 +931,10 @@ class SavedModelTest(SavedModelTestBase): v2 = variables.VariableV1(2, name="v2") ops.add_to_collection("v", v2) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) train_op = control_flow_ops.group() - sess.run(train_op) + self.evaluate(train_op) # TODO(karmel): remove explicit call when in the public method. builder._add_train_op(train_op) builder.add_meta_graph_and_variables(sess, ["foo"]) @@ -960,11 +960,11 @@ class SavedModelTest(SavedModelTestBase): v2 = variables.VariableV1(2, name="v2") ops.add_to_collection("v", v2) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) builder.add_meta_graph_and_variables(sess, ["pre_foo"]) train_op = state_ops.assign_add(v1, v2) - sess.run(train_op) + self.evaluate(train_op) # TODO(karmel): remove explicit call when in the public method. builder._add_train_op(train_op) builder.add_meta_graph(["foo"]) @@ -1090,7 +1090,7 @@ class SavedModelTest(SavedModelTestBase): ops.add_to_collection("v", v3) ops.add_to_collection("init_op", init_op) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(1, ops.get_collection("v")[0].eval()) self.assertEqual(2, ops.get_collection("v")[1].eval()) @@ -1145,7 +1145,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: variables.VariableV1(1, name="v1") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) custom_saver = training.Saver(name="my_saver") builder.add_meta_graph_and_variables(sess, ["tag"], saver=custom_saver) @@ -1167,7 +1167,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: variables.VariableV1(1, name="v1") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) training.Saver(name="my_saver") builder.add_meta_graph_and_variables(sess, ["tag"]) @@ -1189,7 +1189,7 @@ class SavedModelTest(SavedModelTestBase): with self.session(graph=ops.Graph()) as sess: variables.VariableV1(1, name="v1") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) builder.add_meta_graph_and_variables(sess, ["tag_0"]) saver_1 = training.Saver() @@ -1298,7 +1298,7 @@ class SavedModelTest(SavedModelTestBase): real_num = variables.VariableV1(1.0, dtype=dtypes.float32, name="real") imag_num = variables.VariableV1(2.0, dtype=dtypes.float32, name="imag") math_ops.complex(real_num, imag_num, name="complex") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) builder.add_meta_graph_and_variables( sess, ["foo"], strip_default_attrs=True) @@ -1308,7 +1308,7 @@ class SavedModelTest(SavedModelTestBase): real_num = variables.VariableV1(1.0, dtype=dtypes.float32, name="real") imag_num = variables.VariableV1(2.0, dtype=dtypes.float32, name="imag") math_ops.complex(real_num, imag_num, name="complex") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) builder.add_meta_graph(["bar"], strip_default_attrs=False) # Save the SavedModel to disk in text format. @@ -1370,7 +1370,7 @@ class SavedModelTest(SavedModelTestBase): with session.Session(graph=ops.Graph()) as sess: variables.VariableV1(1.0, dtype=dtypes.float64, name="var") test_ops.test_attr(T=dtypes.float32, name="test_attr") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) builder.add_meta_graph_and_variables(sess, ["foo"]) # Save the SavedModel to disk in text format. diff --git a/tensorflow/python/saved_model/simple_save_test.py b/tensorflow/python/saved_model/simple_save_test.py index 2d404dcea4..0d0665072a 100644 --- a/tensorflow/python/saved_model/simple_save_test.py +++ b/tensorflow/python/saved_model/simple_save_test.py @@ -33,7 +33,7 @@ class SimpleSaveTest(test.TestCase): def _init_and_validate_variable(self, sess, variable_name, variable_value): v = variables.Variable(variable_value, name=variable_name) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(variable_value, self.evaluate(v)) return v diff --git a/tensorflow/python/tools/strip_unused_test.py b/tensorflow/python/tools/strip_unused_test.py index 7cf0c3e3ed..e906ff94ba 100644 --- a/tensorflow/python/tools/strip_unused_test.py +++ b/tensorflow/python/tools/strip_unused_test.py @@ -50,7 +50,7 @@ class StripUnusedTest(test_util.TensorFlowTestCase): wanted_input_node, 2.0, name="output_node") math_ops.add(output_node, 2.0, name="later_node") sess = session.Session() - output = sess.run(output_node) + output = self.evaluate(output_node) self.assertNear(-4.0, output, 0.00001) graph_io.write_graph(sess.graph, self.get_temp_dir(), input_graph_name) @@ -113,7 +113,7 @@ class StripUnusedTest(test_util.TensorFlowTestCase): input_node1, input_node2, name="output_node") math_ops.add(output_node, 2.0, name="later_node") sess = session.Session() - output = sess.run(output_node) + output = self.evaluate(output_node) self.assertNear(6.0, output, 0.00001) graph_io.write_graph(sess.graph, self.get_temp_dir(), input_graph_name) diff --git a/tensorflow/python/training/adagrad_da_test.py b/tensorflow/python/training/adagrad_da_test.py index 761f703cb5..c7c47206a9 100644 --- a/tensorflow/python/training/adagrad_da_test.py +++ b/tensorflow/python/training/adagrad_da_test.py @@ -54,14 +54,14 @@ class AdagradDAOptimizerTest(test.TestCase): zip([grads0, grads1], [var0, var1]), global_step=global_step) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([0.0, 0.0], v0_val) self.assertAllClose([0.0, 0.0], v1_val) # Run a step of AdagradDA update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) # Let g to be gradient accumulator, gg to be gradient squared # accumulator, T be the global step, lr is the learning rate, and k the # initial gradient squared accumulator value. @@ -119,14 +119,14 @@ class AdagradDAOptimizerTest(test.TestCase): zip([grads0, grads1], [var0, var1]), global_step=global_step) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run a step of AdagradDA update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.904534, -1.603567]), v0_val) self.assertAllCloseAccordingToType( @@ -151,14 +151,14 @@ class AdagradDAOptimizerTest(test.TestCase): zip([grads0, grads1], [var0, var1]), global_step=global_step) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run a step of AdagradDA update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.895489, -1.59555]), v0_val) self.assertAllCloseAccordingToType( @@ -183,14 +183,14 @@ class AdagradDAOptimizerTest(test.TestCase): zip([grads0, grads1], [var0, var1]), global_step=global_step) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run a step of AdagradDA update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.046907, -0.093659]), v0_val) self.assertAllCloseAccordingToType( diff --git a/tensorflow/python/training/basic_session_run_hooks_test.py b/tensorflow/python/training/basic_session_run_hooks_test.py index 3fabb3e086..03810b57e3 100644 --- a/tensorflow/python/training/basic_session_run_hooks_test.py +++ b/tensorflow/python/training/basic_session_run_hooks_test.py @@ -249,7 +249,7 @@ class LoggingTensorHookTest(test.TestCase): tensors=[t.name], at_end=True) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) self.logged_message = '' for _ in range(3): mon_sess.run(train_op) @@ -267,7 +267,7 @@ class LoggingTensorHookTest(test.TestCase): tensors=[t.name], every_n_iter=10, at_end=at_end) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertRegexpMatches(str(self.logged_message), t.name) for _ in range(3): @@ -314,7 +314,7 @@ class LoggingTensorHookTest(test.TestCase): tensors={'foo': t}, every_n_iter=1) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertRegexpMatches(str(self.logged_message), 'foo') # in first run, elapsed time is None. @@ -328,7 +328,7 @@ class LoggingTensorHookTest(test.TestCase): tensors=[t.name], every_n_secs=1.0, at_end=at_end) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertRegexpMatches(str(self.logged_message), t.name) @@ -376,7 +376,7 @@ class LoggingTensorHookTest(test.TestCase): formatter=lambda items: 'qqq=%s' % items[t.name]) hook.begin() mon_sess = monitored_session._HookedSession(sess, [hook]) - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess.run(train_op) self.assertEqual(self.logged_message[0], 'qqq=42.0') @@ -927,7 +927,7 @@ class StepCounterHookTest(test.TestCase): hook = basic_session_run_hooks.StepCounterHook( summary_writer=summary_writer, every_n_steps=10) hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) with test.mock.patch.object(tf_logging, 'warning') as mock_log: for _ in range(30): @@ -958,7 +958,7 @@ class StepCounterHookTest(test.TestCase): summary_writer=summary_writer, every_n_steps=None, every_n_secs=0.1) hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) mon_sess.run(train_op) mock_time.return_value += 0.2 @@ -995,7 +995,7 @@ class StepCounterHookTest(test.TestCase): summary_writer=summary_writer, every_n_steps=1, every_n_secs=None) hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) mon_sess.run(train_op) mon_sess.run(train_op) @@ -1015,7 +1015,7 @@ class StepCounterHookTest(test.TestCase): with ops.Graph().as_default(), session_lib.Session() as sess: variables.get_or_create_global_step() train_op = training_util._increment_global_step(0) # keep same. - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) hook = basic_session_run_hooks.StepCounterHook( every_n_steps=1, every_n_secs=None) hook.begin() @@ -1042,7 +1042,7 @@ class StepCounterHookTest(test.TestCase): summary_writer=self.summary_writer, every_n_steps=every_n_steps) self.hook._set_steps_per_run(steps_per_run) self.hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) self.mon_sess = monitored_session._HookedSession(sess, [self.hook]) @test.mock.patch.object(time, 'time') @@ -1161,7 +1161,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(30): mon_sess.run(self.train_op) @@ -1193,7 +1193,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(10): mon_sess.run(self.train_op) @@ -1223,7 +1223,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(4): mon_sess.run(self.train_op) @@ -1258,7 +1258,7 @@ class SummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(8): mon_sess.run(self.train_op) @@ -1327,7 +1327,7 @@ class GlobalStepWaiterHookTest(test.TestCase): mock_sleep.side_effect = mock_sleep_side_effect # Run the mocked-out interaction with the hook. - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) run_context = session_run_hook.SessionRunContext( original_args=None, session=sess) hook.before_run(run_context) @@ -1422,7 +1422,7 @@ class ResourceSummarySaverHookTest(test.TestCase): with self.cached_session() as sess: hook.begin() - sess.run(variables_lib.global_variables_initializer()) + self.evaluate(variables_lib.global_variables_initializer()) mon_sess = monitored_session._HookedSession(sess, [hook]) for _ in range(30): mon_sess.run(self.train_op) diff --git a/tensorflow/python/training/checkpoint_ops_test.py b/tensorflow/python/training/checkpoint_ops_test.py index 38d4acf85f..21ad3df1c8 100644 --- a/tensorflow/python/training/checkpoint_ops_test.py +++ b/tensorflow/python/training/checkpoint_ops_test.py @@ -47,7 +47,7 @@ class LoadAndRemapWrappersTest(test.TestCase): with variable_scope.variable_scope('some_scope'): variable_scope.get_variable(name='embeddings', shape=[5, 16], initializer=initializer) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) saver = saver_lib.Saver() saver.save(sess, checkpoint_prefix, global_step=5) self.checkpoint_file = '{}-5'.format(checkpoint_prefix) diff --git a/tensorflow/python/training/ftrl_test.py b/tensorflow/python/training/ftrl_test.py index a61132a966..70b5db31f8 100644 --- a/tensorflow/python/training/ftrl_test.py +++ b/tensorflow/python/training/ftrl_test.py @@ -54,7 +54,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([0.0, 0.0], v0_val) self.assertAllClose([0.0, 0.0], v1_val) @@ -62,7 +62,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-2.60260963, -4.29698515]), v0_val) self.assertAllCloseAccordingToType( @@ -90,14 +90,14 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run 3 steps FTRL for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-2.55607247, -3.98729396]), v0_val) self.assertAllCloseAccordingToType( @@ -137,14 +137,14 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) # Run 10 steps FTRL for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-7.66718769, -10.91273689]), v0_val) self.assertAllCloseAccordingToType( @@ -166,7 +166,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) @@ -174,7 +174,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.24059935, -0.46829352]), v0_val) self.assertAllCloseAccordingToType( @@ -203,7 +203,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([4.0, 3.0], v1_val) @@ -211,7 +211,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType( np.array([-0.22578995, -0.44345796]), v0_val) self.assertAllCloseAccordingToType( @@ -239,7 +239,7 @@ class FtrlOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([[1.0], [2.0]], v0_val) self.assertAllCloseAccordingToType([[4.0], [3.0]], v1_val) @@ -247,7 +247,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([[-0.22578995], [2.]], v0_val) self.assertAllCloseAccordingToType([[4.], [-0.13229476]], v1_val) @@ -275,7 +275,7 @@ class FtrlOptimizerTest(test.TestCase): update1 = opt1.apply_gradients([(grads1, var1)]) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllCloseAccordingToType([1.0, 2.0], v0_val) self.assertAllCloseAccordingToType([1.0, 2.0], v1_val) @@ -284,12 +284,12 @@ class FtrlOptimizerTest(test.TestCase): update0.run() update1.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) # var0 is experiencing L2 shrinkage so it should be smaller than var1 # in magnitude. self.assertTrue((v0_val**2 < v1_val**2).all()) - accum0 = list(sess.run(opt0._slots)["accum"].values())[0] - accum1 = list(sess.run(opt1._slots)["accum"].values())[0] + accum0 = list(self.evaluate(opt0._slots)["accum"].values())[0] + accum1 = list(self.evaluate(opt1._slots)["accum"].values())[0] # L2 shrinkage should not change how we update grad accumulator. self.assertAllCloseAccordingToType(accum0, accum1) @@ -313,7 +313,7 @@ class FtrlOptimizerTest(test.TestCase): variables.global_variables_initializer().run() sess = ops.get_default_session() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) if is_sparse: self.assertAllCloseAccordingToType([[0.0], [0.0]], v0_val) self.assertAllCloseAccordingToType([[0.0], [0.0]], v1_val) @@ -325,7 +325,7 @@ class FtrlOptimizerTest(test.TestCase): for _ in range(steps): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) return v0_val, v1_val # When variables are initialized with Zero, FTRL-Proximal has two properties: diff --git a/tensorflow/python/training/input_test.py b/tensorflow/python/training/input_test.py index e5aac5da18..327f087138 100644 --- a/tensorflow/python/training/input_test.py +++ b/tensorflow/python/training/input_test.py @@ -256,7 +256,7 @@ class StringInputProducerTest(test_lib.TestCase): # writing of the `tf.Graph` object. However, many users # write code this way, so we include this test to ensure # that we can support it. - self.assertEquals(string, sess.run(queue.dequeue())) + self.assertEquals(string, self.evaluate(queue.dequeue())) coord.request_stop() coord.join(threads) @@ -348,14 +348,14 @@ class SliceInputProducerTest(test_lib.TestCase): # No randomness, so just see repeated copies of the input. num_items = len(source_strings) * num_epochs - output = [sess.run(slices) for _ in range(num_items)] + output = [self.evaluate(slices) for _ in range(num_items)] out_strings, out_ints = zip(*output) self.assertAllEqual(source_strings * num_epochs, out_strings) self.assertAllEqual(source_ints * num_epochs, out_ints) # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(slices) + self.evaluate(slices) for thread in threads: thread.join() @@ -383,7 +383,7 @@ class SliceInputProducerTest(test_lib.TestCase): for e in expected: frequency[e] = 0 for _ in range(num_epochs): - output = [sess.run(slices) for _ in range(len(source_strings))] + output = [self.evaluate(slices) for _ in range(len(source_strings))] key = b",".join([s + compat.as_bytes(str(i)) for s, i in output]) self.assertIn(key, expected) frequency[key] += 1 @@ -399,7 +399,7 @@ class SliceInputProducerTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(slices) + self.evaluate(slices) for thread in threads: thread.join() @@ -474,7 +474,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = sess.run(batched_fetch) + results = self.evaluate(batched_fetch) self.assertAllEqual(results[0], np.arange(i * batch_size, (i + 1) * batch_size)) self.assertAllEqual( @@ -491,7 +491,7 @@ class BatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched_fetch) + self.evaluate(batched_fetch) for thread in threads: thread.join() @@ -507,7 +507,7 @@ class BatchTest(test_lib.TestCase): with self.cached_session() as sess: coord = coordinator.Coordinator() threads = queue_runner_impl.start_queue_runners(sess=sess, coord=coord) - sess.run(batched) + self.evaluate(batched) coord.request_stop() for thread in threads: thread.join() @@ -518,7 +518,7 @@ class BatchTest(test_lib.TestCase): with self.cached_session() as sess: coord = coordinator.Coordinator() threads = queue_runner_impl.start_queue_runners(sess=sess, coord=coord) - sess.run(batched) + self.evaluate(batched) coord.request_stop() for thread in threads: thread.join() @@ -539,7 +539,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) expected_results = np.arange(i * batch_size, (i + 1) * batch_size) max_len = expected_results[-1] self.assertAllEqual(results[0], expected_results) @@ -549,7 +549,7 @@ class BatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -571,7 +571,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual(results[0], np.arange(i * batch_size, (i + 1) * batch_size)) self.assertAllEqual( @@ -584,7 +584,7 @@ class BatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -610,7 +610,7 @@ class BatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertAllEqual(results[0], results[1].values) @@ -624,7 +624,7 @@ class BatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -651,7 +651,7 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual(results[0], np.arange(i * batch_size, (i + 1) * batch_size)) self.assertAllEqual( @@ -667,7 +667,7 @@ class BatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra_elements. - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual(results[0], np.arange(num_batches * batch_size, num_batches * batch_size + extra_elements)) @@ -681,7 +681,7 @@ class BatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -709,7 +709,7 @@ class BatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertAllEqual(results[0], results[1].values) @@ -721,7 +721,7 @@ class BatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra_elements. - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Last Batch: %s", results[0]) self.assertEqual(len(results[0]), extra_elements) self.assertAllEqual(results[0], results[1].values) @@ -736,7 +736,7 @@ class BatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -827,14 +827,14 @@ class BatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual([0] * batch_size, np.mod(results[0], 2)) self.assertAllEqual([0] * batch_size, np.mod(results[1].values, 2)) self.assertAllEqual([b"string"] * batch_size, results[2]) # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1020,7 +1020,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = sess.run(batched_fetch) + results = self.evaluate(batched_fetch) self.assertEqual(3, len(results)) self.assertEqual(batch_size, len(results[0])) self.assertEqual(batch_size, len(results[2])) @@ -1051,7 +1051,7 @@ class BatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched_fetch) + self.evaluate(batched_fetch) for thread in threads: thread.join() @@ -1116,7 +1116,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertEqual(2, len(results)) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[1]), batch_size) @@ -1148,7 +1148,7 @@ class BatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1201,7 +1201,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[2]), batch_size) @@ -1221,7 +1221,7 @@ class BatchJoinTest(test_lib.TestCase): [results[0][i] for i in which_b]) # Reached the final batch with 2 * extra_elements. - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Last Batch: %s", results[0]) self.assertEqual(len(results[0]), 2 * extra_elements) self.assertEqual(len(results[2]), 2 * extra_elements) @@ -1249,7 +1249,7 @@ class BatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1296,7 +1296,7 @@ class BatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[1]), batch_size) @@ -1316,7 +1316,7 @@ class BatchJoinTest(test_lib.TestCase): [results[0][i] for i in which_b]) # Reached the final batch with 2 * extra_elements. - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Last Batch: %s", results[0]) self.assertEqual(len(results[0]), 2 * extra_elements) self.assertEqual(len(results[1]), 2 * extra_elements) @@ -1347,7 +1347,7 @@ class BatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1410,7 +1410,7 @@ class BatchJoinTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual( [0] * batch_size, np.mod(results[0], 2),) @@ -1421,7 +1421,7 @@ class BatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1579,7 +1579,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = sess.run(batched_fetch) + results = self.evaluate(batched_fetch) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) self.assertAllEqual( @@ -1597,7 +1597,7 @@ class ShuffleBatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched_fetch) + self.evaluate(batched_fetch) for thread in threads: thread.join() @@ -1634,7 +1634,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for _ in range(num_batches): - results = sess.run(batched_fetch) + results = self.evaluate(batched_fetch) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) self.assertAllEqual( @@ -1645,7 +1645,7 @@ class ShuffleBatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra elements. - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual(results[1].dense_shape, [extra_elements, 1]) self.assertAllEqual(results[2], [b"string"] * extra_elements) all_counts.extend(results[0]) @@ -1659,7 +1659,7 @@ class ShuffleBatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched_fetch) + self.evaluate(batched_fetch) for thread in threads: thread.join() @@ -1687,7 +1687,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) @@ -1706,7 +1706,7 @@ class ShuffleBatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1737,7 +1737,7 @@ class ShuffleBatchTest(test_lib.TestCase): all_counts = [] for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) all_counts.extend(results[0]) @@ -1749,7 +1749,7 @@ class ShuffleBatchTest(test_lib.TestCase): self.assertAllEqual(results[2], [b"string"] * batch_size) # Reached the final batch with extra elements. - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual(results[0].shape, [extra_elements]) self.assertAllEqual(results[1].dense_shape, [extra_elements, 1]) self.assertAllEqual(results[2], [b"string"] * extra_elements) @@ -1764,7 +1764,7 @@ class ShuffleBatchTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1817,14 +1817,14 @@ class ShuffleBatchTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual([0] * batch_size, np.mod(results[0], 2)) self.assertAllEqual([0] * batch_size, np.mod(results[1].values, 2)) self.assertAllEqual([b"string"] * batch_size, results[2]) # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -1990,7 +1990,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = sess.run(batched_fetch) + results = self.evaluate(batched_fetch) self.assertEqual(3, len(results)) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[2]), batch_size) @@ -2020,7 +2020,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched_fetch) + self.evaluate(batched_fetch) for thread in threads: thread.join() @@ -2082,7 +2082,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): saw_both = 0 num_batches = (num_a + num_b) // batch_size for i in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) tf_logging.info("Batch %d: %s", i, results[0]) self.assertEqual(len(results[0]), batch_size) self.assertEqual(len(results[2]), batch_size) @@ -2102,7 +2102,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): [results[0][i] for i in which_b]) # Reached end with 2 * extra_elements left - results = sess.run(batched) + results = self.evaluate(batched) self.assertEqual(len(results[0]), 2 * extra_elements) self.assertAllEqual(results[1].dense_shape, [2 * extra_elements, 1]) self.assertEqual(len(results[2]), 2 * extra_elements) @@ -2129,7 +2129,7 @@ class ShuffleBatchJoinTest(test_lib.TestCase): # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() @@ -2203,14 +2203,14 @@ class ShuffleBatchJoinTest(test_lib.TestCase): threads = queue_runner_impl.start_queue_runners() for _ in range(num_batches): - results = sess.run(batched) + results = self.evaluate(batched) self.assertAllEqual([0] * batch_size, np.mod(results[0], 2)) self.assertAllEqual([0] * batch_size, np.mod(results[1].values, 2)) self.assertAllEqual([b"string"] * batch_size, results[2]) # Reached the limit. with self.assertRaises(errors_impl.OutOfRangeError): - sess.run(batched) + self.evaluate(batched) for thread in threads: thread.join() diff --git a/tensorflow/python/training/learning_rate_decay_test.py b/tensorflow/python/training/learning_rate_decay_test.py index 03a32f6ca0..9c31c0924f 100644 --- a/tensorflow/python/training/learning_rate_decay_test.py +++ b/tensorflow/python/training/learning_rate_decay_test.py @@ -62,23 +62,22 @@ class LRDecayTest(test_util.TensorFlowTestCase): self.assertAllClose(self.evaluate(decayed_lr), expected, 1e-6) def testVariables(self): - with self.cached_session(): - step = variables.VariableV1(1) - assign_1 = step.assign(1) - assign_2 = step.assign(2) - assign_100 = step.assign(100) - decayed_lr = learning_rate_decay.exponential_decay(.1, step, 3, 0.96, - staircase=True) - variables.global_variables_initializer().run() - # No change to learning rate - assign_1.op.run() - self.assertAllClose(decayed_lr.eval(), .1, 1e-6) - assign_2.op.run() - self.assertAllClose(decayed_lr.eval(), .1, 1e-6) - # Decayed learning rate - assign_100.op.run() - expected = .1 * 0.96 ** (100 // 3) - self.assertAllClose(decayed_lr.eval(), expected, 1e-6) + step = variables.VariableV1(1) + assign_1 = step.assign(1) + assign_2 = step.assign(2) + assign_100 = step.assign(100) + decayed_lr = learning_rate_decay.exponential_decay( + .1, step, 3, 0.96, staircase=True) + self.evaluate(variables.global_variables_initializer()) + # No change to learning rate + self.evaluate(assign_1.op) + self.assertAllClose(self.evaluate(decayed_lr), .1, 1e-6) + self.evaluate(assign_2.op) + self.assertAllClose(self.evaluate(decayed_lr), .1, 1e-6) + # Decayed learning rate + self.evaluate(assign_100.op) + expected = .1 * 0.96**(100 // 3) + self.assertAllClose(self.evaluate(decayed_lr), expected, 1e-6) @test_util.run_in_graph_and_eager_modes def testPiecewiseConstant(self): diff --git a/tensorflow/python/training/learning_rate_decay_v2_test.py b/tensorflow/python/training/learning_rate_decay_v2_test.py index b2ac93f06f..354ddb25be 100644 --- a/tensorflow/python/training/learning_rate_decay_v2_test.py +++ b/tensorflow/python/training/learning_rate_decay_v2_test.py @@ -62,23 +62,22 @@ class LRDecayTestV2(test_util.TensorFlowTestCase): self.assertAllClose(self.evaluate(decayed_lr()), expected, 1e-6) def testVariables(self): - with self.cached_session(): - step = variables.Variable(1) - assign_1 = step.assign(1) - assign_2 = step.assign(2) - assign_100 = step.assign(100) - decayed_lr = learning_rate_decay_v2.exponential_decay(.1, step, 3, 0.96, - staircase=True) - variables.global_variables_initializer().run() - # No change to learning rate - assign_1.op.run() - self.assertAllClose(decayed_lr().eval(), .1, 1e-6) - assign_2.op.run() - self.assertAllClose(decayed_lr().eval(), .1, 1e-6) - # Decayed learning rate - assign_100.op.run() - expected = .1 * 0.96 ** (100 // 3) - self.assertAllClose(decayed_lr().eval(), expected, 1e-6) + step = variables.Variable(1) + assign_1 = step.assign(1) + assign_2 = step.assign(2) + assign_100 = step.assign(100) + decayed_lr = learning_rate_decay_v2.exponential_decay( + .1, step, 3, 0.96, staircase=True) + self.evaluate(variables.global_variables_initializer()) + # No change to learning rate + self.evaluate(assign_1.op) + self.assertAllClose(self.evaluate(decayed_lr()), .1, 1e-6) + self.evaluate(assign_2.op) + self.assertAllClose(self.evaluate(decayed_lr()), .1, 1e-6) + # Decayed learning rate + self.evaluate(assign_100.op) + expected = .1 * 0.96**(100 // 3) + self.assertAllClose(self.evaluate(decayed_lr()), expected, 1e-6) @test_util.run_in_graph_and_eager_modes def testPiecewiseConstant(self): diff --git a/tensorflow/python/training/monitored_session_test.py b/tensorflow/python/training/monitored_session_test.py index b828be4499..2ceb387ec3 100644 --- a/tensorflow/python/training/monitored_session_test.py +++ b/tensorflow/python/training/monitored_session_test.py @@ -1170,7 +1170,7 @@ class HookedSessionTest(test.TestCase): mock_run = FakeSession(sess) mon_sess = monitored_session._HookedSession(sess=mock_run, hooks=[]) a_tensor = constant_op.constant([0], name='a_tensor') - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) output = mon_sess.run(fetches=a_tensor, feed_dict='a_feed', options='an_option', @@ -1189,7 +1189,7 @@ class HookedSessionTest(test.TestCase): mon_sess = monitored_session._HookedSession( sess=sess, hooks=[mock_hook, mock_hook2]) a_tensor = constant_op.constant([0], name='a_tensor') - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) mon_sess.run(a_tensor) for hook in [mock_hook, mock_hook2]: @@ -1214,7 +1214,7 @@ class HookedSessionTest(test.TestCase): mon_sess = monitored_session._HookedSession( sess=sess, hooks=[mock_hook, mock_hook2]) constant_op.constant([0], name='a_tensor') - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) mon_sess.run(fetches='a_tensor') self.assertFalse(mon_sess.should_stop()) @@ -1234,7 +1234,7 @@ class HookedSessionTest(test.TestCase): third_tensor = constant_op.constant([10], name='third_tensor') mock_hook.request = session_run_hook.SessionRunArgs([another_tensor]) mock_hook2.request = session_run_hook.SessionRunArgs([third_tensor]) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) output = mon_sess.run(fetches=a_tensor) self.assertEqual(output, [0]) @@ -1254,7 +1254,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={b_tensor: [10]}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertEqual(mon_sess.run(fetches=add_tensor), [15]) @@ -1272,7 +1272,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={b_tensor: [10]}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) feed_dict = {c_tensor: [20]} self.assertEqual( @@ -1293,7 +1293,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={a_tensor: [10]}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) with self.assertRaisesRegexp(RuntimeError, 'Same tensor is fed'): mon_sess.run(fetches=add_tensor) @@ -1311,7 +1311,7 @@ class HookedSessionTest(test.TestCase): None, feed_dict={a_tensor: [5]}) mock_hook2.request = session_run_hook.SessionRunArgs( None, feed_dict={b_tensor: [10]}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) with self.assertRaisesRegexp(RuntimeError, 'Same tensor is fed'): mon_sess.run(fetches=add_tensor, feed_dict={b_tensor: [10]}) diff --git a/tensorflow/python/training/moving_averages_test.py b/tensorflow/python/training/moving_averages_test.py index 8009e3c24e..6ce5de6663 100644 --- a/tensorflow/python/training/moving_averages_test.py +++ b/tensorflow/python/training/moving_averages_test.py @@ -274,14 +274,14 @@ class ExponentialMovingAverageTest(test.TestCase): self.assertEqual([], v1_avg.value().op.control_inputs) self.assertEqual([], v1_avg.value().op.control_inputs) # We should be able to initialize v1_avg before v0. - sess.run(v1_avg.initializer) - sess.run(v0.initializer) - self.assertEqual([10.0], sess.run(v1_avg)) + self.evaluate(v1_avg.initializer) + self.evaluate(v0.initializer) + self.assertEqual([10.0], self.evaluate(v1_avg)) # running ema_op should add to v0 (in addition to updating v1_avg) - sess.run(assign_to_v1) - sess.run(ema_op) - self.assertEqual(1, sess.run(v0)) - self.assertEqual([17.5], sess.run(v1_avg)) + self.evaluate(assign_to_v1) + self.evaluate(ema_op) + self.assertEqual(1, self.evaluate(v0)) + self.assertEqual([17.5], self.evaluate(v1_avg)) @test_util.run_in_graph_and_eager_modes def testBasicEager(self): diff --git a/tensorflow/python/training/proximal_adagrad_test.py b/tensorflow/python/training/proximal_adagrad_test.py index 272f9019e7..9d46a6682d 100644 --- a/tensorflow/python/training/proximal_adagrad_test.py +++ b/tensorflow/python/training/proximal_adagrad_test.py @@ -48,7 +48,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([0.0, 0.0], v0_val) self.assertAllClose([0.0, 0.0], v1_val) @@ -56,7 +56,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([-2.60260963, -4.29698515]), v0_val) self.assertAllClose(np.array([-0.28432083, -0.56694895]), v1_val) opt_vars = opt.variables() @@ -85,14 +85,14 @@ class ProximalAdagradOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([1.0, 2.0], v0_val) self.assertAllClose([4.0, 3.0], v1_val) # Run 3 steps Proximal Adagrad. for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([-1.60261, -2.296985]), v0_val) self.assertAllClose(np.array([3.715679, 2.433051]), v1_val) @@ -129,14 +129,14 @@ class ProximalAdagradOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([1.0, 2.0], v0_val) self.assertAllClose([4.0, 3.0], v1_val) # Run 10 steps Proximal Adagrad for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([-6.663634, -9.190331]), v0_val) self.assertAllClose(np.array([2.959304, 1.029232]), v1_val) @@ -155,7 +155,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([1.0, 2.0], v0_val) self.assertAllClose([4.0, 3.0], v1_val) @@ -163,7 +163,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([-0.0495, -0.0995]), v0_val) self.assertAllClose(np.array([-0.0045, -0.0095]), v1_val) @@ -191,7 +191,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): variables.global_variables_initializer().run() sess = ops.get_default_session() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) if is_sparse: self.assertAllClose([[1.0], [2.0]], v0_val) self.assertAllClose([[3.0], [4.0]], v1_val) @@ -203,7 +203,7 @@ class ProximalAdagradOptimizerTest(test.TestCase): for _ in range(steps): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) return v0_val, v1_val def testEquivAdagradwithoutRegularization(self): diff --git a/tensorflow/python/training/proximal_gradient_descent_test.py b/tensorflow/python/training/proximal_gradient_descent_test.py index a9355f4824..8797b308eb 100644 --- a/tensorflow/python/training/proximal_gradient_descent_test.py +++ b/tensorflow/python/training/proximal_gradient_descent_test.py @@ -50,7 +50,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([0.0, 0.0], v0_val) self.assertAllClose([0.0, 0.0], v1_val) @@ -58,7 +58,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([-0.9, -1.8]), v0_val) self.assertAllClose(np.array([-0.09, -0.18]), v1_val) @@ -80,7 +80,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([1.0, 2.0], v0_val) self.assertAllClose([4.0, 3.0], v1_val) @@ -88,7 +88,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): for _ in range(3): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([0.1, 0.2]), v0_val) self.assertAllClose(np.array([3.91, 2.82]), v1_val) @@ -123,7 +123,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): update = opt.apply_gradients(zip([grads0, grads1], [var0, var1])) variables.global_variables_initializer().run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose([1.0, 2.0], v0_val) self.assertAllClose([4.0, 3.0], v1_val) @@ -131,7 +131,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): for _ in range(10): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) self.assertAllClose(np.array([-0.0495, -0.0995]), v0_val) self.assertAllClose(np.array([-0.0045, -0.0095]), v1_val) @@ -159,7 +159,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): variables.global_variables_initializer().run() sess = ops.get_default_session() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) if is_sparse: self.assertAllClose([[1.0], [2.0]], v0_val) self.assertAllClose([[3.0], [4.0]], v1_val) @@ -171,7 +171,7 @@ class ProximalGradientDescentOptimizerTest(test.TestCase): for _ in range(steps): update.run() - v0_val, v1_val = sess.run([var0, var1]) + v0_val, v1_val = self.evaluate([var0, var1]) return v0_val, v1_val def testEquivSparseGradientDescentwithoutRegularization(self): diff --git a/tensorflow/python/training/quantize_training_test.py b/tensorflow/python/training/quantize_training_test.py index 6edbf7665f..07fd488563 100644 --- a/tensorflow/python/training/quantize_training_test.py +++ b/tensorflow/python/training/quantize_training_test.py @@ -73,11 +73,11 @@ class PywrapQuantizeTrainingTest(test.TestCase): _ = importer.import_graph_def(result, name='') # Initialize the variable. - sess.run(g.get_operation_by_name(init_op.name)) + self.evaluate(g.get_operation_by_name(init_op.name)) # Run the graph for one step to assign values to the quantization min/max # variables. - sess.run(g.get_tensor_by_name(c.name)) + self.evaluate(g.get_tensor_by_name(c.name)) saver.save(sess, save_path) diff --git a/tensorflow/python/training/saver_test.py b/tensorflow/python/training/saver_test.py index be49e6e715..6b2177b0bb 100644 --- a/tensorflow/python/training/saver_test.py +++ b/tensorflow/python/training/saver_test.py @@ -227,7 +227,7 @@ class SaverTest(test.TestCase): w1 = resource_variable_ops.ResourceVariable(1.0, name="w1") w2 = resource_variable_ops.ResourceVariable(2.0, name="w2") graph_saver = saver_module.Saver([w1, w2]) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) graph_saver.save(sess, graph_ckpt_prefix) with context.eager_mode(): @@ -260,7 +260,7 @@ class SaverTest(test.TestCase): w3 = resource_variable_ops.ResourceVariable(0.0, name="w3") w4 = resource_variable_ops.ResourceVariable(0.0, name="w4") graph_saver = saver_module.Saver([w3, w4]) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) graph_saver.restore(sess, eager_ckpt_prefix) self.assertAllEqual(w3.eval(), 3.0) self.assertAllEqual(w4.eval(), 4.0) @@ -326,7 +326,7 @@ class SaverTest(test.TestCase): with self.cached_session() as sess: # Initialize all variables - sess.run(init_all_op) + self.evaluate(init_all_op) # Check that the parameter nodes have been initialized. self.assertEqual(10.0, v0.eval()) @@ -376,7 +376,7 @@ class SaverTest(test.TestCase): with self.cached_session() as sess: tensor = sess.graph.get_tensor_by_name( save.saver_def.filename_tensor_name) - self.assertEqual(sess.run(tensor), filename) + self.assertEqual(self.evaluate(tensor), filename) def testInvalidPath(self): v0 = variables.VariableV1(0, name="v0") @@ -407,7 +407,7 @@ class SaverTest(test.TestCase): with self.assertRaisesWithPredicateMatch( errors_impl.OpError, lambda e: "uninitialized value v" in e.message): - sess.run(v) + self.evaluate(v) # Restore the saved values in the parameter nodes. save.restore(sess, save_path) @@ -497,10 +497,10 @@ class SaverTest(test.TestCase): with self.assertRaisesWithPredicateMatch( errors_impl.OpError, lambda e: "uninitialized value v0" in e.message): - sess.run(v0) + self.evaluate(v0) with self.assertRaisesWithPredicateMatch( errors_impl.OpError, lambda e: "uninitialized value v1" in e.message): - sess.run(v1) + self.evaluate(v1) self.assertEqual(0, len(v2.keys().eval())) self.assertEqual(0, len(v2.values().eval())) @@ -742,7 +742,7 @@ class SaverTest(test.TestCase): try: with self.cached_session() as sess: # Initialize all variables - sess.run(init_all_op) + self.evaluate(init_all_op) # Check that the parameter nodes have been initialized. self.assertEqual(10.0, v0.eval()) @@ -777,7 +777,7 @@ class SaverTest(test.TestCase): with self.cached_session() as sess: # Initialize all variables - sess.run(init_all_op) + self.evaluate(init_all_op) # Check that the parameter nodes have been initialized. self.assertEqual(10.0, v0.eval()) @@ -824,11 +824,11 @@ class SaverTest(test.TestCase): save_graph = ops_lib.Graph() with save_graph.as_default(), self.session(graph=save_graph) as sess: orig_vars = _model() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) save = saver_module.Saver(max_to_keep=1) variables.global_variables_initializer().run() save.save(sess, save_dir) - orig_vals = sess.run(orig_vars) + orig_vals = self.evaluate(orig_vars) restore_graph = ops_lib.Graph() with restore_graph.as_default(), self.session( @@ -836,7 +836,7 @@ class SaverTest(test.TestCase): restored_vars = _model() save = saver_module.Saver(max_to_keep=1) save.restore(sess, save_dir) - restored_vals = sess.run(restored_vars) + restored_vals = self.evaluate(restored_vars) for orig, restored in zip(orig_vals, restored_vals): self.assertAllEqual(orig, restored) @@ -1747,7 +1747,7 @@ class MetaGraphTest(test.TestCase): self.assertEqual([], v1.get_shape()) with self.assertRaisesWithPredicateMatch( errors_impl.OpError, lambda e: "uninitialized value v1" in e.message): - sess.run(v1) + self.evaluate(v1) # Retrieves saver1. Verifies that new_saver1 can restore v1. new_saver1 = savers[1] new_saver1.restore(sess, saver1_ckpt) @@ -1927,9 +1927,9 @@ class MetaGraphTest(test.TestCase): with self.cached_session() as sess: # Initializes all the variables. - sess.run(init_all_op) + self.evaluate(init_all_op) # Runs to logit. - sess.run(logits) + self.evaluate(logits) # Creates a saver. saver0 = saver_module.Saver() saver0.save(sess, saver0_ckpt) @@ -1969,7 +1969,7 @@ class MetaGraphTest(test.TestCase): ops_lib.add_to_collection("train_op", train_op) # Runs train_op. - sess.run(train_op) + self.evaluate(train_op) # Generates MetaGraphDef. saver_module.export_meta_graph(train_filename) @@ -1983,7 +1983,7 @@ class MetaGraphTest(test.TestCase): # Restores from checkpoint. new_saver.restore(sess, saver0_ckpt) train_op = ops_lib.get_collection("train_op")[0] - sess.run(train_op) + self.evaluate(train_op) def testGraphExtension(self): test_dir = self._get_test_dir("graph_extension") @@ -2015,8 +2015,8 @@ class MetaGraphTest(test.TestCase): # Generate a MetaGraphDef containing the while loop. with session.Session() as sess: - sess.run(init_op) - sess.run(output) + self.evaluate(init_op) + self.evaluate(output) saver = saver_module.Saver() saver.save(sess, saver_ckpt) saver.export_meta_graph(filename) @@ -2031,8 +2031,8 @@ class MetaGraphTest(test.TestCase): no_constfold_config.graph_options.rewrite_options.constant_folding = ( rewriter_config_pb2.RewriterConfig.OFF) with session.Session(config=no_constfold_config) as sess: - sess.run(init_op) - expected_grad_value = sess.run(grad) + self.evaluate(init_op) + expected_grad_value = self.evaluate(grad) # Restore the MetaGraphDef into a new Graph. with ops_lib.Graph().as_default(): @@ -2048,8 +2048,8 @@ class MetaGraphTest(test.TestCase): init_op = variables.global_variables_initializer() with session.Session(config=no_constfold_config) as sess: - sess.run(init_op) - actual_grad_value = sess.run(grad) + self.evaluate(init_op) + actual_grad_value = self.evaluate(grad) self.assertEqual(expected_grad_value, actual_grad_value) def _testWhileLoopAndGradientSerDes(self, outer_body_fn): @@ -2187,7 +2187,7 @@ class MetaGraphTest(test.TestCase): logits=logit, name="cost") adam.AdamOptimizer().minimize(cost, name="optimize") saver = saver_module.Saver() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) saver.save(sess, filename) graph = ops_lib.Graph() @@ -2224,7 +2224,7 @@ class MetaGraphTest(test.TestCase): # Create a variable in graph_2 under scope "my_scope". variables.VariableV1(array_ops.zeros([10]), name="my_scope/my_var") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Restore the checkpoint into a different scope "subgraph_2". new_saver_2 = saver_module.import_meta_graph( filename + ".meta", graph=graph_2, import_scope="subgraph_2") @@ -2257,7 +2257,7 @@ class MetaGraphTest(test.TestCase): logits=logit, name="cost") adam.AdamOptimizer().minimize(cost, name="optimize") saver = saver_module.Saver() - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) saver.save(sess, filename) graph = ops_lib.Graph() @@ -2294,12 +2294,12 @@ class MetaGraphTest(test.TestCase): meta_graph_def, clear_devices=False, import_scope="new_model") # Device refers to GPU, which is not available here. with self.assertRaises(errors_impl.InvalidArgumentError): - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) with session.Session(graph=ops_lib.Graph()) as sess: saver_module.import_meta_graph( meta_graph_def, clear_devices=True, import_scope="new_model") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) sess.run(["new_model/optimize"], { "new_model/image:0": np.random.random([1, 784]), "new_model/label:0": np.random.randint( @@ -2326,7 +2326,7 @@ class MetaGraphTest(test.TestCase): with session.Session(graph=ops_lib.Graph()) as sess: saver_module.import_meta_graph(meta_graph_def, import_scope="new_model") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) sess.run(["new_model/optimize"], { "new_model/image:0": np.random.random([1, 784]), "new_model/label:0": np.random.randint( @@ -2352,7 +2352,7 @@ class MetaGraphTest(test.TestCase): meta_graph_def_from_graph_def]: with session.Session(graph=ops_lib.Graph()) as sess: saver_module.import_meta_graph(meta_graph_def, import_scope="new_model") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) for i in range(10): self.assertEqual(i * i, sess.run("new_model/output:0")) with self.assertRaises(errors.OutOfRangeError): @@ -2378,7 +2378,7 @@ class CheckpointReaderTest(test.TestCase): save_path = os.path.join(self.get_temp_dir(), "ckpt_for_debug_string" + str(self._WRITE_VERSION)) with self.cached_session() as sess: - sess.run(init_all_op) + self.evaluate(init_all_op) # Saves a checkpoint. save.save(sess, save_path) @@ -2524,7 +2524,7 @@ class ScopedGraphTest(test.TestCase): self.assertEqual(["biases:0", "weights:0"], sorted(var_list.keys())) with self.session(graph=graph) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) saver = saver_module.Saver(var_list=var_list, max_to_keep=1) saver.save(sess, os.path.join(test_dir, ckpt_filename), write_state=False) @@ -2587,10 +2587,10 @@ class ScopedGraphTest(test.TestCase): saver = saver_module.Saver(var_list=var_list, max_to_keep=1) saver.restore(sess, os.path.join(test_dir, ckpt_filename)) # Verify that we have restored weights1 and biases1. - sess.run([weights1, biases1]) + self.evaluate([weights1, biases1]) # Initialize the rest of the variables and run logits. - sess.run(init_rest_op) - sess.run(logits) + self.evaluate(init_rest_op) + self.evaluate(logits) # Verifies that we can save the subgraph under "hidden1" and restore it # into "new_hidden1" in the new graph. @@ -2618,7 +2618,7 @@ class ScopedGraphTest(test.TestCase): # Run the graph and save scoped checkpoint. with self.session(graph=graph1) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) _, var_list_1 = meta_graph.export_scoped_meta_graph( export_scope="hidden1") saver = saver_module.Saver(var_list=var_list_1, max_to_keep=1) @@ -2674,7 +2674,7 @@ class ScopedGraphTest(test.TestCase): # Run the graph and save scoped checkpoint. with self.session(graph=graph1) as sess: - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) _, var_list_1 = meta_graph.export_scoped_meta_graph( graph_def=graph1.as_graph_def(), export_scope="hidden1") saver = saver_module.Saver(var_list=var_list_1, max_to_keep=1) @@ -2942,7 +2942,7 @@ class CheckpointableCompatibilityTests(test.TestCase): a_saver = saver_module.Saver([a]) b_saver = saver_module.Saver([b]) with self.cached_session() as sess: - sess.run(a.initializer) + self.evaluate(a.initializer) save_path = a_saver.save(sess=sess, save_path=checkpoint_prefix) with self.assertRaisesRegexp( errors.NotFoundError, "Key b not found in checkpoint"): @@ -2964,7 +2964,7 @@ class CheckpointableCompatibilityTests(test.TestCase): a_saver = saver_module.Saver([a]) with self.session(graph=g) as sess: - sess.run(a.initializer) + self.evaluate(a.initializer) save_path = a_saver.save(sess=sess, save_path=checkpoint_prefix) with ops_lib.Graph().as_default() as g: diff --git a/tensorflow/python/training/server_lib_same_variables_clear_container_test.py b/tensorflow/python/training/server_lib_same_variables_clear_container_test.py index 11e6f28ab0..3a5eb712c6 100644 --- a/tensorflow/python/training/server_lib_same_variables_clear_container_test.py +++ b/tensorflow/python/training/server_lib_same_variables_clear_container_test.py @@ -60,9 +60,9 @@ class SameVariablesClearContainerTest(test.TestCase): session.Session.reset(server0.target, ["local0"]) sess = session.Session(server0.target) with self.assertRaises(errors_impl.FailedPreconditionError): - sess.run(v0) + self.evaluate(v0) # Reinitializes v0 for the following test. - sess.run(v0.initializer) + self.evaluate(v0.initializer) # Verifies that v1 is still valid. self.assertAllEqual(2.0, sess_1.run(v1)) @@ -71,10 +71,10 @@ class SameVariablesClearContainerTest(test.TestCase): session.Session.reset(server1.target, ["local1"]) sess = session.Session(server1.target) with self.assertRaises(errors_impl.FailedPreconditionError): - sess.run(v1) + self.evaluate(v1) # Verifies that v0 is still valid. sess = session.Session(server0.target) - self.assertAllEqual(1.0, sess.run(v0)) + self.assertAllEqual(1.0, self.evaluate(v0)) if __name__ == "__main__": diff --git a/tensorflow/python/training/server_lib_sparse_job_test.py b/tensorflow/python/training/server_lib_sparse_job_test.py index 1a6b44b90e..8c2745b51a 100644 --- a/tensorflow/python/training/server_lib_sparse_job_test.py +++ b/tensorflow/python/training/server_lib_sparse_job_test.py @@ -36,7 +36,7 @@ class SparseJobTest(test.TestCase): a = constant_op.constant(1.0) with session.Session(server.target) as sess: - self.assertEqual(1.0, sess.run(a)) + self.assertEqual(1.0, self.evaluate(a)) if __name__ == "__main__": diff --git a/tensorflow/python/training/supervisor_test.py b/tensorflow/python/training/supervisor_test.py index b734e9653e..9dc88d78cc 100644 --- a/tensorflow/python/training/supervisor_test.py +++ b/tensorflow/python/training/supervisor_test.py @@ -100,7 +100,7 @@ class SupervisorTest(test.TestCase): sv = supervisor.Supervisor(logdir=logdir) sess = sv.prepare_or_wait_for_session("") for _ in xrange(10): - sess.run(my_op) + self.evaluate(my_op) sess.close() sv.stop() @@ -111,7 +111,7 @@ class SupervisorTest(test.TestCase): sv = supervisor.Supervisor(logdir=logdir) with sv.managed_session("") as sess: for _ in xrange(10): - sess.run(my_op) + self.evaluate(my_op) # Supervisor has been stopped. self.assertTrue(sv.should_stop()) @@ -128,7 +128,7 @@ class SupervisorTest(test.TestCase): if step == 1: raise RuntimeError("failing here") else: - sess.run(my_op) + self.evaluate(my_op) # Supervisor has been stopped. self.assertTrue(sv.should_stop()) self.assertEqual(1, last_step) @@ -146,7 +146,7 @@ class SupervisorTest(test.TestCase): raise errors_impl.OutOfRangeError(my_op.op.node_def, my_op.op, "all done") else: - sess.run(my_op) + self.evaluate(my_op) # Supervisor has been stopped. OutOfRangeError was not thrown. self.assertTrue(sv.should_stop()) self.assertEqual(3, last_step) @@ -335,7 +335,7 @@ class SupervisorTest(test.TestCase): sess = sv.prepare_or_wait_for_session( "", config=config_pb2.ConfigProto(device_count={"CPU": 2})) for _ in xrange(10): - sess.run(my_op) + self.evaluate(my_op) sess.close() sv.stop() diff --git a/tensorflow/python/training/warm_starting_util_test.py b/tensorflow/python/training/warm_starting_util_test.py index b575b8d364..fa1f370f41 100644 --- a/tensorflow/python/training/warm_starting_util_test.py +++ b/tensorflow/python/training/warm_starting_util_test.py @@ -49,7 +49,7 @@ class WarmStartingUtilTest(test.TestCase): return vocab_file def _write_checkpoint(self, sess): - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) saver = saver_lib.Saver() ckpt_prefix = os.path.join(self.get_temp_dir(), "model") saver.save(sess, ckpt_prefix, global_step=0) @@ -70,7 +70,7 @@ class WarmStartingUtilTest(test.TestCase): if partitioner: self.assertTrue(isinstance(var, variables.PartitionedVariable)) var = var._get_variable_list() - return var, sess.run(var) + return var, self.evaluate(var) def _create_prev_run_vars(self, var_names, @@ -86,7 +86,7 @@ class WarmStartingUtilTest(test.TestCase): shape=shape, initializer=initializer)) self._write_checkpoint(sess) - return [sess.run(var) for var in all_vars] + return [self.evaluate(var) for var in all_vars] def _create_dummy_inputs(self): return { @@ -125,7 +125,7 @@ class WarmStartingUtilTest(test.TestCase): prev_tensor_name, var = ws_util._get_var_info(fruit_weights) checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllClose(prev_val, fruit_weights.eval(sess)) def testWarmStartVarPrevVarPartitioned(self): @@ -143,7 +143,7 @@ class WarmStartingUtilTest(test.TestCase): prev_tensor_name, var = ws_util._get_var_info(fruit_weights) checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllClose(prev_val, fruit_weights.eval(sess)) def testWarmStartVarCurrentVarPartitioned(self): @@ -162,7 +162,7 @@ class WarmStartingUtilTest(test.TestCase): prev_tensor_name, var = ws_util._get_var_info(fruit_weights) checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) fruit_weights = fruit_weights._get_variable_list() new_val = np.concatenate( [fruit_weights[0].eval(sess), fruit_weights[1].eval(sess)], axis=0) @@ -189,7 +189,7 @@ class WarmStartingUtilTest(test.TestCase): fruit_weights, prev_tensor_name="old_scope/fruit_weights") checkpoint_utils.init_from_checkpoint(self.get_temp_dir(), {prev_tensor_name: var}) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) fruit_weights = fruit_weights._get_variable_list() new_val = np.concatenate( [fruit_weights[0].eval(sess), fruit_weights[1].eval(sess)], axis=0) @@ -211,7 +211,7 @@ class WarmStartingUtilTest(test.TestCase): "fruit_weights", initializer=[[0.], [0.], [0.], [0.], [0.]]) ws_util._warm_start_var_with_vocab(fruit_weights, new_vocab_path, 5, self.get_temp_dir(), prev_vocab_path) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllClose([[2.], [1.5], [1.], [0.5], [0.]], fruit_weights.eval(sess)) @@ -236,7 +236,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllClose([[0.3, 0.5, 0.], [0.8, 1.0, 0.], [1.2, 1.5, 0.], [2.3, 2., 0.]], fruit_output_layer.eval(sess)) @@ -261,7 +261,7 @@ class WarmStartingUtilTest(test.TestCase): self.get_temp_dir(), prev_vocab_path, previous_vocab_size=2) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Old vocabulary limited to ['apple', 'banana']. self.assertAllClose([[0.], [0.], [1.], [0.5], [0.]], fruit_weights.eval(sess)) @@ -285,7 +285,7 @@ class WarmStartingUtilTest(test.TestCase): "fruit_weights", initializer=[[0.], [0.], [0.], [0.], [0.]]) ws_util._warm_start_var_with_vocab(fruit_weights, new_vocab_path, 5, self.get_temp_dir(), prev_vocab_path) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllClose([[2.], [1.5], [1.], [0.5], [0.]], fruit_weights.eval(sess)) @@ -312,7 +312,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertAllClose([[0.3, 0.5, 0.], [0.8, 1.0, 0.], [1.2, 1.5, 0.], [2.3, 2., 0.]], fruit_output_layer.eval(sess)) @@ -340,7 +340,7 @@ class WarmStartingUtilTest(test.TestCase): self.get_temp_dir(), prev_vocab_path, current_oov_buckets=1) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_weights, variables.PartitionedVariable)) fruit_weights_vars = fruit_weights._get_variable_list() @@ -372,7 +372,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_output_layer, variables.PartitionedVariable)) fruit_output_layer_vars = fruit_output_layer._get_variable_list() @@ -404,7 +404,7 @@ class WarmStartingUtilTest(test.TestCase): partitioner=lambda shape, dtype: [2, 1]) ws_util._warm_start_var_with_vocab(fruit_weights, new_vocab_path, 6, self.get_temp_dir(), prev_vocab_path) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_weights, variables.PartitionedVariable)) fruit_weights_vars = fruit_weights._get_variable_list() @@ -438,7 +438,7 @@ class WarmStartingUtilTest(test.TestCase): prev_ckpt=self.get_temp_dir(), prev_vocab_path=prev_vocab_path, axis=1) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) self.assertTrue( isinstance(fruit_output_layer, variables.PartitionedVariable)) fruit_output_layer_vars = fruit_output_layer._get_variable_list() @@ -463,7 +463,7 @@ class WarmStartingUtilTest(test.TestCase): shape=[10, 1], initializer=zeros()) ws_util.warm_start(self.get_temp_dir(), vars_to_warm_start=[var]) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started (init overridden to ones). self.assertAllEqual(var.eval(), prev_int_val) @@ -483,7 +483,7 @@ class WarmStartingUtilTest(test.TestCase): shape=[10, 1], initializer=zeros()) ws_util.warm_start(self.get_temp_dir(), vars_to_warm_start=["v1"]) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started (init overridden to ones). self.assertAllEqual(var.eval(), prev_int_val) @@ -519,7 +519,7 @@ class WarmStartingUtilTest(test.TestCase): # This warm-starts both v1 and v1/Momentum, but only # v2 (and not v2/Momentum). vars_to_warm_start=["v1", "v2[^/]"]) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify the selection of weights were correctly warm-started (init # overridden to ones). self.assertAllEqual(v1.eval(), prev_v1_val) @@ -542,7 +542,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_int], partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_int: [np.zeros([10, 1])]}, @@ -553,7 +553,7 @@ class WarmStartingUtilTest(test.TestCase): with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_int], partitioner) ws_util.warm_start(self.get_temp_dir(), vars_to_warm_start=".*sc_int.*") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_int: [prev_int_val]}, sess) @@ -571,7 +571,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_hash], partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_hash: [np.zeros([15, 1])]}, @@ -583,7 +583,7 @@ class WarmStartingUtilTest(test.TestCase): cols_to_vars = self._create_linear_model([sc_hash], partitioner) ws_util.warm_start( self.get_temp_dir(), vars_to_warm_start=".*sc_hash.*") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_hash: [prev_hash_val]}, sess) @@ -605,7 +605,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_vocab], partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [np.zeros([4, 1])]}, @@ -619,7 +619,7 @@ class WarmStartingUtilTest(test.TestCase): # vocab is assumed to be same as new vocab. ws_util.warm_start( self.get_temp_dir(), vars_to_warm_start=".*sc_vocab.*") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [prev_vocab_val]}, sess) @@ -641,7 +641,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_vocab], partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [np.zeros([4, 1])]}, @@ -657,7 +657,7 @@ class WarmStartingUtilTest(test.TestCase): # Explicitly provide the file prefix instead of just the dir. os.path.join(self.get_temp_dir(), "model-0"), vars_to_warm_start=".*sc_vocab.*") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [prev_vocab_val]}, sess) @@ -686,7 +686,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([sc_vocab], partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [np.zeros([2, 1])]}, @@ -708,7 +708,7 @@ class WarmStartingUtilTest(test.TestCase): var_name_to_vocab_info={ "linear_model/sc_vocab/weights": vocab_info }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. 'banana' isn't in the # first two entries of the old vocabulary, so it's newly initialized. self._assert_cols_to_vars(cols_to_vars, {sc_vocab: [[[1], [0]]]}, sess) @@ -729,7 +729,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model([real_bucket], partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, the weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, @@ -741,7 +741,7 @@ class WarmStartingUtilTest(test.TestCase): cols_to_vars = self._create_linear_model([real_bucket], partitioner) ws_util.warm_start( self.get_temp_dir(), vars_to_warm_start=".*real_bucketized.*") - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, {real_bucket: [prev_bucket_val]}, sess) @@ -800,7 +800,7 @@ class WarmStartingUtilTest(test.TestCase): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: cols_to_vars = self._create_linear_model(all_linear_cols, partitioner) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Without warm-starting, all weights should be initialized using default # initializer (which is init_ops.zeros_initializer). self._assert_cols_to_vars(cols_to_vars, { @@ -826,7 +826,7 @@ class WarmStartingUtilTest(test.TestCase): var_name_to_vocab_info={ "linear_model/sc_vocab/weights": vocab_info }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. self._assert_cols_to_vars(cols_to_vars, { sc_int: [prev_int_val], @@ -865,7 +865,7 @@ class WarmStartingUtilTest(test.TestCase): "linear_model/sc_vocab/weights", initializer=[[0.5], [1.], [2.], [3.]]) self._write_checkpoint(sess) - prev_keys_val = sess.run(sc_keys_weights) + prev_keys_val = self.evaluate(sc_keys_weights) def _partitioner(shape, dtype): # pylint:disable=unused-argument # Partition each var into 2 equal slices. @@ -892,7 +892,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[sc_keys]): "some_other_name" }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # sc_hash should not be warm-started. Var corresponding to sc_vocab # should be correctly warm-started after vocab remapping. @@ -933,7 +933,7 @@ class WarmStartingUtilTest(test.TestCase): "linear_model/sc_vocab/weights", initializer=[[0.5], [1.], [2.], [3.]]) self._write_checkpoint(sess) - prev_keys_val = sess.run(sc_keys_weights) + prev_keys_val = self.evaluate(sc_keys_weights) # New graph, new session with warm-starting. with ops.Graph().as_default() as g: @@ -955,7 +955,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[sc_keys]): "some_other_name" }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # sc_hash should not be warm-started. Var corresponding to sc_vocab # should be correctly warm-started after vocab remapping. @@ -1024,7 +1024,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[sc_keys]): "some_other_name" }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # sc_vocab should be correctly warm-started after vocab remapping, # and neither of the other two should be warm-started.. @@ -1091,7 +1091,7 @@ class WarmStartingUtilTest(test.TestCase): ws_util._infer_var_name(cols_to_vars[emb_vocab_column]): vocab_info }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # emb_vocab_column should be correctly warm-started after vocab # remapping. Missing values are filled in with the EmbeddingColumn's @@ -1163,7 +1163,7 @@ class WarmStartingUtilTest(test.TestCase): var_name_to_vocab_info={ "linear_model/sc_vocab_embedding/embedding_weights": vocab_info }) - sess.run(variables.global_variables_initializer()) + self.evaluate(variables.global_variables_initializer()) # Verify weights were correctly warm-started. Var corresponding to # emb_vocab should be correctly warm-started after vocab remapping. # Missing values are filled in with the EmbeddingColumn's initializer. -- GitLab From e12ae7b521b47c9c33bcbf5e76dc99d4b309b9df Mon Sep 17 00:00:00 2001 From: Blake Hechtman Date: Tue, 27 Nov 2018 10:06:35 -0800 Subject: [PATCH 395/672] [XLA] Remove interior padding from padded dimensions with one-sized operand dimnesions. PiperOrigin-RevId: 223010061 --- .../xla/service/algebraic_simplifier.cc | 21 ++++++++++++ .../xla/service/algebraic_simplifier_test.cc | 34 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier.cc b/tensorflow/compiler/xla/service/algebraic_simplifier.cc index 0b0502b4ff..a9099d9e31 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier.cc @@ -1671,6 +1671,27 @@ Status AlgebraicSimplifierVisitor::HandlePad(HloInstruction* pad) { pad, HloInstruction::CreateBroadcast(pad->shape(), pad->mutable_operand(1), {})); } + + // Interior padding on one sized dimensions have no effect. As a result it + // makes other simplifications possible if there is no interior padding. + if (HasInteriorPadding(pad->padding_config())) { + PaddingConfig padding_config = pad->padding_config(); + bool cleared_interior_padding = false; + for (int64 i = 0; i < ShapeUtil::Rank(pad->shape()); ++i) { + if (padding_config.dimensions(i).interior_padding() > 0 && + pad->operand(0)->shape().dimensions(i) == 1) { + cleared_interior_padding = true; + padding_config.mutable_dimensions(i)->set_interior_padding(0); + } + } + if (cleared_interior_padding) { + TF_ASSIGN_OR_RETURN(HloInstruction * pad_without_interior_pad, + MakePadHlo(pad->mutable_operand(0), + pad->mutable_operand(1), padding_config)); + return ReplaceInstruction(pad, pad_without_interior_pad); + } + } + // Eliminate nop pads (padding all zero), and replace a pad with negative // padding with a pad with non-negative padding followed by a slice. bool all_zero = true; diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc b/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc index 24c35464ad..48f689c96a 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier_test.cc @@ -2189,6 +2189,40 @@ TEST_F(AlgebraicSimplifierTest, NegativePadding) { has_negative_padding(computation->root_instruction()->operand(0))); } +TEST_F(AlgebraicSimplifierTest, TrivialInteriorPadding) { + // Verify that a pad instruction with interior padding on one-sized + // dimensions, removes the interior padding. + HloComputation::Builder builder(TestName()); + HloInstruction* param = + builder.AddInstruction(HloInstruction::CreateParameter( + 0, ShapeUtil::MakeShape(F32, {2, 1}), "param")); + HloInstruction* zero = builder.AddInstruction( + HloInstruction::CreateConstant(LiteralUtil::CreateR0(0.0f))); + PaddingConfig padding; + for (int i = 0; i < 2; ++i) { + auto dimension = padding.add_dimensions(); + dimension->set_edge_padding_low(3); + dimension->set_edge_padding_high(3); + dimension->set_interior_padding(i * 3); + } + HloInstruction* pad = builder.AddInstruction(HloInstruction::CreatePad( + ShapeUtil::MakeShape(F32, {8, 7}), param, zero, padding)); + + auto module = CreateNewVerifiedModule(); + HloComputation* computation = module->AddEntryComputation(builder.Build()); + + AlgebraicSimplifier simplifier(default_options_); + + ASSERT_THAT(computation->root_instruction(), op::Pad(param, zero)); + ASSERT_TRUE(HasInteriorPadding(pad->padding_config())); + + EXPECT_TRUE(simplifier.Run(module.get()).ValueOrDie()); + + EXPECT_THAT(computation->root_instruction(), op::Pad(param, zero)); + EXPECT_FALSE( + HasInteriorPadding(computation->root_instruction()->padding_config())); +} + TEST_F(AlgebraicSimplifierTest, RemoveNoopReshape) { HloComputation::Builder builder(TestName()); HloInstruction* param = -- GitLab From 1dab0d879218f36c44e88b2d6bf71e819da0ef05 Mon Sep 17 00:00:00 2001 From: Brennan Saeta Date: Tue, 27 Nov 2018 10:14:36 -0800 Subject: [PATCH 396/672] Automated rollback of commit 50e5b015be1ead47f170013a640bf3028bb0560f PiperOrigin-RevId: 223011511 --- tensorflow/c/eager/BUILD | 1 + tensorflow/c/eager/c_api.cc | 11 +++--- .../compiler/jit/build_xla_ops_pass_test.cc | 8 +--- .../compiler/jit/create_xla_launch_op_test.cc | 6 +-- .../mark_for_compilation_pass_test_helper.cc | 8 +--- .../jit/partially_decluster_pass_test.cc | 6 +-- tensorflow/compiler/jit/xla_cpu_device.cc | 11 +++--- tensorflow/compiler/jit/xla_gpu_device.cc | 10 ++--- .../compiler/jit/xla_interpreter_device.cc | 7 ++-- tensorflow/compiler/tf2xla/xla_compiler.cc | 2 +- tensorflow/core/BUILD | 4 ++ .../collective_executor_mgr_test.cc | 6 +-- .../collective_param_resolver_local_test.cc | 6 +-- .../collective_rma_local_test.cc | 6 +-- .../core/common_runtime/device_factory.cc | 17 +++++---- .../core/common_runtime/device_factory.h | 13 ++++--- tensorflow/core/common_runtime/device_mgr.cc | 37 +++++++++++-------- tensorflow/core/common_runtime/device_mgr.h | 15 ++++---- .../device_resolver_local_test.cc | 6 +-- .../core/common_runtime/device_set_test.cc | 2 +- .../core/common_runtime/direct_session.cc | 4 +- tensorflow/core/common_runtime/eager/BUILD | 1 + .../eager/kernel_and_device_test.cc | 14 ++++--- .../core/common_runtime/executor_test.cc | 8 ++-- .../core/common_runtime/function_test.cc | 7 ++-- .../function_threadpool_test.cc | 6 +-- .../core/common_runtime/gpu/gpu_device.cc | 20 +++++----- .../core/common_runtime/gpu/gpu_device.h | 18 ++++----- .../common_runtime/gpu/gpu_device_factory.cc | 21 +++++------ .../gpu/gpu_device_on_non_gpu_machine_test.cc | 2 +- .../common_runtime/gpu/gpu_device_test.cc | 32 +++++++--------- .../hierarchical_tree_broadcaster_test.cc | 11 +++--- .../kernel_benchmark_testlib.cc | 8 ++-- .../common_runtime/kernel_benchmark_testlib.h | 2 +- tensorflow/core/common_runtime/placer_test.cc | 2 +- .../process_function_library_runtime_test.cc | 18 +++++---- .../core/common_runtime/renamed_device.cc | 14 +++---- .../core/common_runtime/renamed_device.h | 7 ++-- .../core/common_runtime/ring_reducer_test.cc | 11 +++--- .../threadpool_device_factory.cc | 17 +++++---- tensorflow/core/distributed_runtime/BUILD | 1 + ...lective_param_resolver_distributed_test.cc | 11 +++--- .../collective_rma_distributed_test.cc | 11 +++--- .../device_resolver_distributed_test.cc | 13 ++++--- .../eager/eager_service_impl.cc | 6 +-- .../eager/eager_service_impl_test.cc | 9 ++--- .../rpc/grpc_server_lib.cc | 11 ++++-- .../rpc_collective_executor_mgr_test.cc | 6 +-- .../core/distributed_runtime/session_mgr.cc | 4 +- .../distributed_runtime/session_mgr_test.cc | 8 ++-- .../core/grappler/grappler_item_builder.cc | 9 +++-- tensorflow/core/grappler/optimizers/BUILD | 2 +- .../grappler/optimizers/function_optimizer.cc | 9 +++-- tensorflow/core/kernels/data/BUILD | 1 + tensorflow/core/kernels/data/iterator_ops.cc | 6 +-- .../data/single_threaded_executor_test.cc | 8 ++-- tensorflow/lite/delegates/flex/BUILD | 1 + .../lite/delegates/flex/delegate_data.cc | 7 ++-- tensorflow/lite/toco/import_tensorflow.cc | 4 +- tensorflow/python/client/device_lib.i | 7 +--- tensorflow/python/grappler/tf_optimizer.i | 5 +-- 61 files changed, 273 insertions(+), 271 deletions(-) diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD index ba3d8533db..5a0988ed31 100644 --- a/tensorflow/c/eager/BUILD +++ b/tensorflow/c/eager/BUILD @@ -50,6 +50,7 @@ tf_cuda_library( ], "//conditions:default": [], }) + [ + "@com_google_absl//absl/memory", "//tensorflow/core/common_runtime/eager:eager_operation", "//tensorflow/core/distributed_runtime/eager:eager_client", "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client", diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index 192044915f..c9e730ef41 100755 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -21,6 +21,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "tensorflow/c/c_api.h" #include "tensorflow/c/c_api_internal.h" #include "tensorflow/c/eager/c_api_internal.h" @@ -80,7 +81,7 @@ tensorflow::Status GetAllRemoteDevices( const std::vector& remote_workers, tensorflow::WorkerCacheInterface* worker_cache, std::unique_ptr* device_mgr) { - std::vector remote_devices; + std::vector> remote_devices; tensorflow::Status status; // TODO(nareshmodi) do this in parallel instead of serially. for (const string& remote_worker : remote_workers) { @@ -93,7 +94,7 @@ tensorflow::Status GetAllRemoteDevices( status = s; if (s.ok()) { for (tensorflow::Device* d : *devices) { - remote_devices.push_back(d); + remote_devices.emplace_back(d); } } n.Notify(); @@ -101,7 +102,7 @@ tensorflow::Status GetAllRemoteDevices( n.WaitForNotification(); } std::unique_ptr remote_device_mgr( - new tensorflow::DeviceMgr(remote_devices)); + new tensorflow::DeviceMgr(std::move(remote_devices))); TF_RETURN_IF_ERROR(status); @@ -262,13 +263,13 @@ TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx, void TFE_DeleteContextOptions(TFE_ContextOptions* options) { delete options; } TFE_Context* TFE_NewContext(const TFE_ContextOptions* opts, TF_Status* status) { - std::vector devices; + std::vector> devices; status->status = tensorflow::DeviceFactory::AddDevices( opts->session_options.options, "/job:localhost/replica:0/task:0", &devices); if (!status->status.ok()) return nullptr; std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(devices)); + new tensorflow::DeviceMgr(std::move(devices))); tensorflow::Rendezvous* r = new tensorflow::IntraProcessRendezvous(device_mgr.get()); diff --git a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc index 11df946cc1..48a23a4c17 100644 --- a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc +++ b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc @@ -42,14 +42,8 @@ class BuildXlaOpsTest : public ::testing::Test { .ok()); } - void TearDown() override { - for (Device* device : devices_) { - delete device; - } - } - private: - std::vector devices_; + std::vector> devices_; }; using ::tensorflow::testing::FindNodeByName; diff --git a/tensorflow/compiler/jit/create_xla_launch_op_test.cc b/tensorflow/compiler/jit/create_xla_launch_op_test.cc index 7386660762..0f872a480f 100644 --- a/tensorflow/compiler/jit/create_xla_launch_op_test.cc +++ b/tensorflow/compiler/jit/create_xla_launch_op_test.cc @@ -59,8 +59,9 @@ class CreateXlaLaunchOpTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 1}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices_)); + options, "/job:localhost/replica:0/task:0", &devices)); FunctionDefLibrary proto; for (const auto& fdef : flib) { @@ -69,7 +70,7 @@ class CreateXlaLaunchOpTest : public ::testing::Test { lib_def_ = absl::make_unique( OpRegistry::Global(), proto); OptimizerOptions opts; - device_mgr_ = absl::make_unique(devices_); + device_mgr_ = absl::make_unique(std::move(devices)); pflr_ = absl::make_unique( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, /*default_thread_pool=*/nullptr, /*cluster_flr=*/nullptr); @@ -77,7 +78,6 @@ class CreateXlaLaunchOpTest : public ::testing::Test { } FunctionLibraryRuntime* flr_; - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc index d56d0f8ccf..64a3301745 100644 --- a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc +++ b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc @@ -34,15 +34,9 @@ namespace tensorflow { // // It may be worth refactoring out XlaOpRegistry::RegisterCompilationDevice to // make this more direct, but probably not worth it solely for this test. - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(*session_options, "", &devices)); - auto delete_devices = gtl::MakeCleanup([&] { - for (Device* d : devices) { - delete d; - } - }); - GraphOptimizationPassOptions opt_options; opt_options.graph = graph; opt_options.session_options = session_options; diff --git a/tensorflow/compiler/jit/partially_decluster_pass_test.cc b/tensorflow/compiler/jit/partially_decluster_pass_test.cc index 1fc5da5071..38a54cc5ef 100644 --- a/tensorflow/compiler/jit/partially_decluster_pass_test.cc +++ b/tensorflow/compiler/jit/partially_decluster_pass_test.cc @@ -386,7 +386,7 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) { TF_ASSERT_OK(s.ToGraph(graph.get())); // This is needed to register the XLA_GPU device. - std::vector devices; + std::vector> devices; TF_ASSERT_OK(DeviceFactory::AddDevices( SessionOptions(), "/job:localhost/replica:0/task:0", &devices)); @@ -400,10 +400,6 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) { TF_ASSERT_OK(PartiallyDecluster(&graph)); EXPECT_EQ(GetXlaClusterForNode(*n), "cluster_0"); - - for (Device* d : devices) { - delete d; - } } TEST(PartiallyDeclusterPassTest, DontDeclusterNonTensorFlowOps) { diff --git a/tensorflow/compiler/jit/xla_cpu_device.cc b/tensorflow/compiler/jit/xla_cpu_device.cc index 9006dd514b..7df898ad12 100644 --- a/tensorflow/compiler/jit/xla_cpu_device.cc +++ b/tensorflow/compiler/jit/xla_cpu_device.cc @@ -31,12 +31,12 @@ namespace tensorflow { class XlaCpuDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; }; -Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options, - const string& name_prefix, - std::vector* devices) { +Status XlaCpuDeviceFactory::CreateDevices( + const SessionOptions& session_options, const string& name_prefix, + std::vector>* devices) { XlaDeviceFlags* flags = GetXlaDeviceFlags(); bool compile_on_demand = flags->tf_xla_compile_on_demand; @@ -63,8 +63,7 @@ Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options, options.device_ordinal = 0; options.compilation_device_name = DEVICE_CPU_XLA_JIT; options.use_multiple_streams = false; - auto device = absl::make_unique(session_options, options); - devices->push_back(device.release()); + devices->push_back(absl::make_unique(session_options, options)); return Status::OK(); } diff --git a/tensorflow/compiler/jit/xla_gpu_device.cc b/tensorflow/compiler/jit/xla_gpu_device.cc index 4419701695..944f732b99 100644 --- a/tensorflow/compiler/jit/xla_gpu_device.cc +++ b/tensorflow/compiler/jit/xla_gpu_device.cc @@ -29,12 +29,12 @@ namespace tensorflow { class XlaGpuDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; }; -Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options, - const string& name_prefix, - std::vector* devices) { +Status XlaGpuDeviceFactory::CreateDevices( + const SessionOptions& session_options, const string& name_prefix, + std::vector>* devices) { XlaOpRegistry::DeviceRegistration registration; registration.compilation_device_name = DEVICE_GPU_XLA_JIT; registration.autoclustering_policy = @@ -70,7 +70,7 @@ Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options, return status; } - devices->push_back(device.release()); + devices->push_back(std::move(device)); } return Status::OK(); } diff --git a/tensorflow/compiler/jit/xla_interpreter_device.cc b/tensorflow/compiler/jit/xla_interpreter_device.cc index e828bae865..4007309ed1 100644 --- a/tensorflow/compiler/jit/xla_interpreter_device.cc +++ b/tensorflow/compiler/jit/xla_interpreter_device.cc @@ -33,12 +33,12 @@ constexpr std::array kExecAllTypes = { class XlaInterpreterDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; }; Status XlaInterpreterDeviceFactory::CreateDevices( const SessionOptions& session_options, const string& name_prefix, - std::vector* devices) { + std::vector>* devices) { static XlaDeviceOpRegistrations* registrations = RegisterXlaDeviceKernels( DEVICE_XLA_INTERPRETER, DEVICE_INTERPRETER_XLA_JIT); (void)registrations; @@ -61,8 +61,7 @@ Status XlaInterpreterDeviceFactory::CreateDevices( options.device_ordinal = 0; options.compilation_device_name = DEVICE_INTERPRETER_XLA_JIT; options.use_multiple_streams = false; - auto device = absl::make_unique(session_options, options); - devices->push_back(device.release()); + devices->push_back(absl::make_unique(session_options, options)); return Status::OK(); } diff --git a/tensorflow/compiler/tf2xla/xla_compiler.cc b/tensorflow/compiler/tf2xla/xla_compiler.cc index 7fdd60145f..ee461a3c07 100644 --- a/tensorflow/compiler/tf2xla/xla_compiler.cc +++ b/tensorflow/compiler/tf2xla/xla_compiler.cc @@ -380,7 +380,7 @@ XlaCompiler::XlaCompiler(XlaCompiler::Options options) initialization_status_(Status::OK()), next_step_id_(1), device_(new XlaCompilationDevice(SessionOptions(), options_.device_type)), - device_mgr_({device_}) { + device_mgr_(absl::WrapUnique(device_)) { CHECK(!options_.device_type.type_string().empty()); if (options_.populate_resource_manager) { initialization_status_ = diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 6821ac7eb7..20b1916e7d 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -2980,6 +2980,7 @@ tf_cuda_library( ":lib_internal", ":proto_text", ":protos_all_cc", + "@com_google_absl//absl/memory", "//third_party/eigen3", "//tensorflow/core/grappler:grappler_item", ] + mkl_deps(), @@ -3858,6 +3859,7 @@ tf_cc_tests_gpu( ":test", ":test_main", ":testlib", + "@com_google_absl//absl/memory", ], ) @@ -3886,6 +3888,7 @@ tf_cc_tests_gpu( ":test", ":test_main", ":testlib", + "@com_google_absl//absl/memory", ], ) @@ -4453,6 +4456,7 @@ tf_cc_test( "//tensorflow/core/kernels:random_ops", "//tensorflow/core/kernels:shape_ops", "//third_party/eigen3", + "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/core/common_runtime/collective_executor_mgr_test.cc b/tensorflow/core/common_runtime/collective_executor_mgr_test.cc index 91994c5731..f3d86aa633 100644 --- a/tensorflow/core/common_runtime/collective_executor_mgr_test.cc +++ b/tensorflow/core/common_runtime/collective_executor_mgr_test.cc @@ -38,8 +38,9 @@ class CollectiveExecutorMgrTest : public ::testing::Test { auto* device_count = options.config.mutable_device_count(); string task_name = "/job:localhost/replica:0/task:0"; device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); std::unique_ptr drl( new DeviceResolverLocal(device_mgr_.get())); std::unique_ptr prl( @@ -50,7 +51,6 @@ class CollectiveExecutorMgrTest : public ::testing::Test { } std::unique_ptr cme_; - std::vector devices_; std::unique_ptr device_mgr_; }; diff --git a/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc b/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc index 9a501b3298..94d889c40d 100644 --- a/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc +++ b/tensorflow/core/common_runtime/collective_param_resolver_local_test.cc @@ -37,8 +37,9 @@ class CollectiveParamResolverLocalTest : public ::testing::Test { string task_name = "/job:localhost/replica:0/task:0"; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); prl_.reset(new CollectiveParamResolverLocal(device_mgr_.get(), drl_.get(), task_name)); @@ -73,7 +74,6 @@ class CollectiveParamResolverLocalTest : public ::testing::Test { } } - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; std::unique_ptr prl_; diff --git a/tensorflow/core/common_runtime/collective_rma_local_test.cc b/tensorflow/core/common_runtime/collective_rma_local_test.cc index a931fe64bd..4263f3a4ad 100644 --- a/tensorflow/core/common_runtime/collective_rma_local_test.cc +++ b/tensorflow/core/common_runtime/collective_rma_local_test.cc @@ -42,8 +42,9 @@ class CollectiveRemoteAccessLocalTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, kTaskName, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, kTaskName, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); prl_.reset(new CollectiveParamResolverLocal(device_mgr_.get(), drl_.get(), kTaskName)); @@ -51,7 +52,6 @@ class CollectiveRemoteAccessLocalTest : public ::testing::Test { kStepId)); } - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; std::unique_ptr prl_; diff --git a/tensorflow/core/common_runtime/device_factory.cc b/tensorflow/core/common_runtime/device_factory.cc index b94900114c..0fad13fe1e 100644 --- a/tensorflow/core/common_runtime/device_factory.cc +++ b/tensorflow/core/common_runtime/device_factory.cc @@ -20,6 +20,7 @@ limitations under the License. #include #include +#include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/logging.h" @@ -89,9 +90,9 @@ DeviceFactory* DeviceFactory::GetFactory(const string& device_type) { return it->second.factory.get(); } -Status DeviceFactory::AddDevices(const SessionOptions& options, - const string& name_prefix, - std::vector* devices) { +Status DeviceFactory::AddDevices( + const SessionOptions& options, const string& name_prefix, + std::vector>* devices) { // CPU first. A CPU device is required. auto cpu_factory = GetFactory("CPU"); if (!cpu_factory) { @@ -116,16 +117,16 @@ Status DeviceFactory::AddDevices(const SessionOptions& options, return Status::OK(); } -Device* DeviceFactory::NewDevice(const string& type, - const SessionOptions& options, - const string& name_prefix) { +std::unique_ptr DeviceFactory::NewDevice(const string& type, + const SessionOptions& options, + const string& name_prefix) { auto device_factory = GetFactory(type); if (!device_factory) { return nullptr; } SessionOptions opt = options; (*opt.config.mutable_device_count())[type] = 1; - std::vector devices; + std::vector> devices; TF_CHECK_OK(device_factory->CreateDevices(opt, name_prefix, &devices)); int expected_num_devices = 1; auto iter = options.config.device_count().find(type); @@ -133,7 +134,7 @@ Device* DeviceFactory::NewDevice(const string& type, expected_num_devices = iter->second; } DCHECK_EQ(devices.size(), static_cast(expected_num_devices)); - return devices[0]; + return std::move(devices[0]); } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/device_factory.h b/tensorflow/core/common_runtime/device_factory.h index db50226fe8..b3cd7adca9 100644 --- a/tensorflow/core/common_runtime/device_factory.h +++ b/tensorflow/core/common_runtime/device_factory.h @@ -40,18 +40,19 @@ class DeviceFactory { // CPU devices are added first. static Status AddDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices); + std::vector>* devices); // Helper for tests. Create a single device of type "type". The // returned device is always numbered zero, so if creating multiple // devices of the same type, supply distinct name_prefix arguments. - static Device* NewDevice(const string& type, const SessionOptions& options, - const string& name_prefix); + static std::unique_ptr NewDevice(const string& type, + const SessionOptions& options, + const string& name_prefix); // Most clients should call AddDevices() instead. - virtual Status CreateDevices(const SessionOptions& options, - const string& name_prefix, - std::vector* devices) = 0; + virtual Status CreateDevices( + const SessionOptions& options, const string& name_prefix, + std::vector>* devices) = 0; // Return the device priority number for a "device_type" string. // diff --git a/tensorflow/core/common_runtime/device_mgr.cc b/tensorflow/core/common_runtime/device_mgr.cc index 470abc1431..1f7d7c4699 100644 --- a/tensorflow/core/common_runtime/device_mgr.cc +++ b/tensorflow/core/common_runtime/device_mgr.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/device_mgr.h" +#include #include #include "tensorflow/core/common_runtime/local_device.h" #include "tensorflow/core/framework/device_attributes.pb.h" @@ -24,32 +25,32 @@ limitations under the License. namespace tensorflow { -DeviceMgr::DeviceMgr(const std::vector& devices) - : name_backing_store_(128) { - for (Device* d : devices) { +DeviceMgr::DeviceMgr(std::vector> devices) + : devices_(std::move(devices)), name_backing_store_(128) { + for (auto& d : devices_) { CHECK(d->device_mgr_ == nullptr); d->device_mgr_ = this; - devices_.push_back(d); - // Register under the (1) full name and (2) canonical name. for (const string& name : DeviceNameUtils::GetNamesForDeviceMappings(d->parsed_name())) { - device_map_[CopyToBackingStore(name)] = d; + device_map_[CopyToBackingStore(name)] = d.get(); } // Register under the (3) local name and (4) legacy local name. for (const string& name : DeviceNameUtils::GetLocalNamesForDeviceMappings(d->parsed_name())) { - device_map_[CopyToBackingStore(name)] = d; + device_map_[CopyToBackingStore(name)] = d.get(); } device_type_counts_[d->device_type()]++; } } -DeviceMgr::~DeviceMgr() { - // TODO(b/37437134): Remove destructor after converting to std::unique_ptr. - for (Device* p : devices_) delete p; -} +DeviceMgr::DeviceMgr(std::unique_ptr device) + : DeviceMgr([&device] { + std::vector> vector; + vector.push_back(std::move(device)); + return vector; + }()) {} StringPiece DeviceMgr::CopyToBackingStore(StringPiece s) { size_t n = s.size(); @@ -61,18 +62,22 @@ StringPiece DeviceMgr::CopyToBackingStore(StringPiece s) { void DeviceMgr::ListDeviceAttributes( std::vector* devices) const { devices->reserve(devices_.size()); - for (Device* dev : devices_) { + for (const auto& dev : devices_) { devices->emplace_back(dev->attributes()); } } std::vector DeviceMgr::ListDevices() const { - return std::vector(devices_.begin(), devices_.end()); + std::vector devices(devices_.size()); + for (size_t i = 0; i < devices_.size(); ++i) { + devices[i] = devices_[i].get(); + } + return devices; } string DeviceMgr::DebugString() const { string out; - for (Device* dev : devices_) { + for (const auto& dev : devices_) { strings::StrAppend(&out, dev->name(), "\n"); } return out; @@ -80,7 +85,7 @@ string DeviceMgr::DebugString() const { string DeviceMgr::DeviceMappingString() const { string out; - for (Device* dev : devices_) { + for (const auto& dev : devices_) { if (!dev->attributes().physical_device_desc().empty()) { strings::StrAppend(&out, dev->name(), " -> ", dev->attributes().physical_device_desc(), "\n"); @@ -107,7 +112,7 @@ Status DeviceMgr::LookupDevice(StringPiece name, Device** device) const { void DeviceMgr::ClearContainers(gtl::ArraySlice containers) const { Status s; - for (Device* dev : devices_) { + for (const auto& dev : devices_) { if (containers.empty()) { s.Update(dev->resource_manager()->Cleanup( dev->resource_manager()->default_container())); diff --git a/tensorflow/core/common_runtime/device_mgr.h b/tensorflow/core/common_runtime/device_mgr.h index c1ff10d9b5..bf8694655a 100644 --- a/tensorflow/core/common_runtime/device_mgr.h +++ b/tensorflow/core/common_runtime/device_mgr.h @@ -16,6 +16,7 @@ limitations under the License. #ifndef TENSORFLOW_CORE_COMMON_RUNTIME_DEVICE_MGR_H_ #define TENSORFLOW_CORE_COMMON_RUNTIME_DEVICE_MGR_H_ +#include #include #include #include @@ -34,15 +35,17 @@ class DeviceAttributes; class DeviceMgr { public: - // Takes ownership of each device in 'devices'. + // Constructs a DeviceMgr from a list of devices. // TODO(zhifengc): Other initialization information. - // TODO(b/37437134): Use std::unique_ptr's to track ownership. - explicit DeviceMgr(const std::vector& devices); - ~DeviceMgr(); + explicit DeviceMgr(std::vector> devices); + + // Constructs a DeviceMgr managing a single device. + explicit DeviceMgr(std::unique_ptr device); // Returns attributes of all devices. void ListDeviceAttributes(std::vector* devices) const; + // Returns raw pointers to the underlying devices. std::vector ListDevices() const; // Returns a string listing all devices. @@ -62,9 +65,7 @@ class DeviceMgr { int NumDeviceType(const string& type) const; private: - // TODO(b/37437134): Use std::unique_ptr's to track ownership. - typedef gtl::InlinedVector DeviceVec; - DeviceVec devices_; + const std::vector> devices_; StringPiece CopyToBackingStore(StringPiece s); diff --git a/tensorflow/core/common_runtime/device_resolver_local_test.cc b/tensorflow/core/common_runtime/device_resolver_local_test.cc index f5a6471ff7..54f1119e13 100644 --- a/tensorflow/core/common_runtime/device_resolver_local_test.cc +++ b/tensorflow/core/common_runtime/device_resolver_local_test.cc @@ -36,12 +36,12 @@ class DeviceResolverLocalTest : public ::testing::Test { string task_name = "/job:localhost/replica:0/task:0"; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); drl_.reset(new DeviceResolverLocal(device_mgr_.get())); } - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr drl_; }; diff --git a/tensorflow/core/common_runtime/device_set_test.cc b/tensorflow/core/common_runtime/device_set_test.cc index fd9c4222a7..6a8c3d14e5 100644 --- a/tensorflow/core/common_runtime/device_set_test.cc +++ b/tensorflow/core/common_runtime/device_set_test.cc @@ -57,7 +57,7 @@ class DeviceSetTest : public ::testing::Test { class DummyFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { return Status::OK(); } }; diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index 178469db51..0434ca47b6 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -156,12 +156,12 @@ class DirectSessionFactory : public SessionFactory { if (options.config.graph_options().build_cost_model() > 0) { EnableCPUAllocatorFullStats(true); } - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); DirectSession* session = - new DirectSession(options, new DeviceMgr(devices), this); + new DirectSession(options, new DeviceMgr(std::move(devices)), this); { mutex_lock l(sessions_lock_); sessions_.push_back(session); diff --git a/tensorflow/core/common_runtime/eager/BUILD b/tensorflow/core/common_runtime/eager/BUILD index a7b618c18b..86890ba07d 100644 --- a/tensorflow/core/common_runtime/eager/BUILD +++ b/tensorflow/core/common_runtime/eager/BUILD @@ -181,6 +181,7 @@ tf_cc_test( "//tensorflow/core:lib", "//tensorflow/core:test", "//tensorflow/core:test_main", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc b/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc index 948bdbcaf5..3ffed3ce32 100644 --- a/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc +++ b/tensorflow/core/common_runtime/eager/kernel_and_device_test.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "tensorflow/cc/client/client_session.h" #include "tensorflow/cc/framework/ops.h" #include "tensorflow/cc/framework/scope.h" @@ -37,12 +38,13 @@ namespace { class TestEnv { public: TestEnv() : flib_def_(OpRegistry::Global(), {}) { - Device* device = - DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0"); - device_mgr_.reset(new DeviceMgr({device})); - flib_runtime_ = NewFunctionLibraryRuntime(device_mgr_.get(), Env::Default(), - device, TF_GRAPH_DEF_VERSION, - &flib_def_, nullptr, {}, nullptr); + std::vector> devices; + devices.push_back( + DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0")); + device_mgr_ = absl::make_unique(std::move(devices)); + flib_runtime_ = NewFunctionLibraryRuntime( + device_mgr_.get(), Env::Default(), device_mgr_->ListDevices()[0], + TF_GRAPH_DEF_VERSION, &flib_def_, nullptr, {}, nullptr); } FunctionLibraryRuntime* function_library_runtime() const { diff --git a/tensorflow/core/common_runtime/executor_test.cc b/tensorflow/core/common_runtime/executor_test.cc index 7697103faf..c311b2533e 100644 --- a/tensorflow/core/common_runtime/executor_test.cc +++ b/tensorflow/core/common_runtime/executor_test.cc @@ -53,17 +53,17 @@ class ExecutorTest : public ::testing::Test { // when the test completes. CHECK(rendez_->Unref()); delete exec_; - delete device_; } // Resets executor_ with a new executor based on a graph 'gdef'. void Create(std::unique_ptr graph) { const int version = graph->versions().producer(); LocalExecutorParams params; - params.device = device_; + params.device = device_.get(); params.create_kernel = [this, version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_, nullptr, ndef, version, kernel); + return CreateNonCachedKernel(device_.get(), nullptr, ndef, version, + kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -83,7 +83,7 @@ class ExecutorTest : public ::testing::Test { } thread::ThreadPool* thread_pool_ = nullptr; - Device* device_ = nullptr; + std::unique_ptr device_; Executor* exec_ = nullptr; StepStatsCollector step_stats_collector_; StepStats step_stats_; diff --git a/tensorflow/core/common_runtime/function_test.cc b/tensorflow/core/common_runtime/function_test.cc index 13c189fb87..3b4c976685 100644 --- a/tensorflow/core/common_runtime/function_test.cc +++ b/tensorflow/core/common_runtime/function_test.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include +#include "absl/memory/memory.h" #include "absl/strings/numbers.h" #include "absl/strings/str_split.h" #include "tensorflow/cc/ops/array_ops_internal.h" @@ -147,14 +148,15 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 3}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices_)); + options, "/job:localhost/replica:0/task:0", &devices)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); OptimizerOptions opts; - device_mgr_.reset(new DeviceMgr(devices_)); + device_mgr_ = absl::make_unique(std::move(devices)); pflr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); @@ -358,7 +360,6 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { FunctionLibraryRuntime* flr0_; FunctionLibraryRuntime* flr1_; FunctionLibraryRuntime* flr2_; - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/core/common_runtime/function_threadpool_test.cc b/tensorflow/core/common_runtime/function_threadpool_test.cc index 655a68cfc9..bdbe24a70d 100644 --- a/tensorflow/core/common_runtime/function_threadpool_test.cc +++ b/tensorflow/core/common_runtime/function_threadpool_test.cc @@ -54,14 +54,15 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 3}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices( - options, "/job:localhost/replica:0/task:0", &devices_)); + options, "/job:localhost/replica:0/task:0", &devices)); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); OptimizerOptions opts; - device_mgr_.reset(new DeviceMgr(devices_)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); pflr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); @@ -194,7 +195,6 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { FunctionLibraryRuntime* flr0_; FunctionLibraryRuntime* flr1_; FunctionLibraryRuntime* flr2_; - std::vector devices_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.cc b/tensorflow/core/common_runtime/gpu/gpu_device.cc index 81fea311e1..5152d97fde 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device.cc @@ -907,9 +907,9 @@ Allocator* BaseGPUDevice::GetScopedAllocator(AllocatorAttributes attr, const int BaseGPUDeviceFactory::InterconnectMap::kSameDeviceStrength = 1000; const int BaseGPUDeviceFactory::InterconnectMap::kStreamExecutorStrength = 1; -Status BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, - const string& name_prefix, - std::vector* devices) { +Status BaseGPUDeviceFactory::CreateDevices( + const SessionOptions& options, const string& name_prefix, + std::vector>* devices) { TF_RETURN_IF_ERROR(ValidateGPUMachineManager()); se::Platform* gpu_manager = GPUMachineManager(); if (gpu_manager == nullptr) { @@ -1073,12 +1073,10 @@ static string GetShortDeviceDescription(PlatformGpuId platform_gpu_id, // LINT.ThenChange(//tensorflow/python/platform/test.py) } -Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, - const string& name_prefix, - TfGpuId tf_gpu_id, - int64 memory_limit, - const DeviceLocality& dev_locality, - std::vector* devices) { +Status BaseGPUDeviceFactory::CreateGPUDevice( + const SessionOptions& options, const string& name_prefix, TfGpuId tf_gpu_id, + int64 memory_limit, const DeviceLocality& dev_locality, + std::vector>* devices) { CHECK_GE(tf_gpu_id.value(), 0); const string device_name = strings::StrCat(name_prefix, "/device:GPU:", tf_gpu_id.value()); @@ -1108,7 +1106,7 @@ Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, // different (which should be an error). // // TODO(laigd): report error if memory_limit doesn't match stats.bytes_limit. - BaseGPUDevice* gpu_device = CreateGPUDevice( + std::unique_ptr gpu_device = CreateGPUDevice( options, device_name, static_cast(stats.bytes_limit), dev_locality, tf_gpu_id, GetShortDeviceDescription(platform_gpu_id, desc), gpu_allocator, ProcessState::singleton()->GetCPUAllocator(numa_node)); @@ -1116,7 +1114,7 @@ Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, << (stats.bytes_limit >> 20) << " MB memory) -> physical GPU (" << GetShortDeviceDescription(platform_gpu_id, desc) << ")"; TF_RETURN_IF_ERROR(gpu_device->Init(options)); - devices->push_back(gpu_device); + devices->push_back(std::move(gpu_device)); return Status::OK(); } diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.h b/tensorflow/core/common_runtime/gpu/gpu_device.h index 674e8384d5..d002d02c51 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.h +++ b/tensorflow/core/common_runtime/gpu/gpu_device.h @@ -166,7 +166,7 @@ class BaseGPUDevice : public LocalDevice { class BaseGPUDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override; + std::vector>* devices) override; struct InterconnectMap { // Name of interconnect technology, if known. @@ -207,15 +207,13 @@ class BaseGPUDeviceFactory : public DeviceFactory { Status CreateGPUDevice(const SessionOptions& options, const string& name_prefix, TfGpuId tf_gpu_id, int64 memory_limit, const DeviceLocality& dev_locality, - std::vector* devices); - - virtual BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, Bytes memory_limit, - const DeviceLocality& dev_locality, - TfGpuId tf_gpu_id, - const string& physical_device_desc, - Allocator* gpu_allocator, - Allocator* cpu_allocator) = 0; + std::vector>* devices); + + virtual std::unique_ptr CreateGPUDevice( + const SessionOptions& options, const string& name, Bytes memory_limit, + const DeviceLocality& dev_locality, TfGpuId tf_gpu_id, + const string& physical_device_desc, Allocator* gpu_allocator, + Allocator* cpu_allocator) = 0; // Returns into 'ids' the list of valid platform GPU ids, in the order that // they should map to TF GPU ids "/device:GPU:0", "/device:GPU:1", etc, diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc index e1aaf95df6..8dc7197329 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc @@ -59,15 +59,14 @@ class GPUDevice : public BaseGPUDevice { class GPUDeviceFactory : public BaseGPUDeviceFactory { private: - BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, Bytes memory_limit, - const DeviceLocality& locality, - TfGpuId tf_gpu_id, - const string& physical_device_desc, - Allocator* gpu_allocator, - Allocator* cpu_allocator) override { - return new GPUDevice(options, name, memory_limit, locality, tf_gpu_id, - physical_device_desc, gpu_allocator, cpu_allocator); + std::unique_ptr CreateGPUDevice( + const SessionOptions& options, const string& name, Bytes memory_limit, + const DeviceLocality& locality, TfGpuId tf_gpu_id, + const string& physical_device_desc, Allocator* gpu_allocator, + Allocator* cpu_allocator) override { + return absl::make_unique(options, name, memory_limit, locality, + tf_gpu_id, physical_device_desc, + gpu_allocator, cpu_allocator); } }; @@ -108,7 +107,7 @@ class GPUCompatibleCPUDevice : public ThreadPoolDevice { class GPUCompatibleCPUDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { int n = 1; auto iter = options.config.device_count().find("CPU"); if (iter != options.config.device_count().end()) { @@ -116,7 +115,7 @@ class GPUCompatibleCPUDeviceFactory : public DeviceFactory { } for (int i = 0; i < n; i++) { string name = strings::StrCat(name_prefix, "/device:CPU:", i); - devices->push_back(new GPUCompatibleCPUDevice( + devices->push_back(absl::make_unique( options, name, Bytes(256 << 20), DeviceLocality(), cpu_allocator())); } diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc b/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc index 75be6d60b8..58656ec757 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_on_non_gpu_machine_test.cc @@ -33,7 +33,7 @@ namespace { TEST(GPUDeviceOnNonGPUMachineTest, CreateGPUDevicesOnNonGPUMachine) { SessionOptions opts; - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, "/job:localhost/replica:0/task:0", &devices)); EXPECT_TRUE(devices.empty()); diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_test.cc b/tensorflow/core/common_runtime/gpu/gpu_device_test.cc index 36294094e9..ae623b2adb 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_test.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_test.cc @@ -88,7 +88,7 @@ class GPUDeviceTest : public ::testing::Test { TEST_F(GPUDeviceTest, FailedToParseVisibleDeviceList) { SessionOptions opts = MakeSessionOptions("0,abc"); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -97,7 +97,7 @@ TEST_F(GPUDeviceTest, FailedToParseVisibleDeviceList) { TEST_F(GPUDeviceTest, InvalidGpuId) { SessionOptions opts = MakeSessionOptions("100"); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -107,7 +107,7 @@ TEST_F(GPUDeviceTest, InvalidGpuId) { TEST_F(GPUDeviceTest, DuplicateEntryInVisibleDeviceList) { SessionOptions opts = MakeSessionOptions("0,0"); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -117,7 +117,7 @@ TEST_F(GPUDeviceTest, DuplicateEntryInVisibleDeviceList) { TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithMemoryFractionSettings) { SessionOptions opts = MakeSessionOptions("0", 0.1, 1, {{}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -129,7 +129,7 @@ TEST_F(GPUDeviceTest, GpuDeviceCountTooSmall) { // device_count is 0, but with one entry in visible_device_list and one // (empty) VirtualDevices messages. SessionOptions opts = MakeSessionOptions("0", 0, 0, {{}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::UNKNOWN); @@ -141,7 +141,7 @@ TEST_F(GPUDeviceTest, NotEnoughGpuInVisibleDeviceList) { // Single entry in visible_device_list with two (empty) VirtualDevices // messages. SessionOptions opts = MakeSessionOptions("0", 0, 8, {{}, {}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::UNKNOWN); @@ -155,7 +155,7 @@ TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithVisibleDeviceList) { // Three entries in visible_device_list with two (empty) VirtualDevices // messages. SessionOptions opts = MakeSessionOptions("0,1", 0, 8, {{}}); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INVALID_ARGUMENT); @@ -169,39 +169,36 @@ TEST_F(GPUDeviceTest, VirtualDeviceConfigConflictsWithVisibleDeviceList) { TEST_F(GPUDeviceTest, EmptyVirtualDeviceConfig) { // It'll create single virtual device when the virtual device config is empty. SessionOptions opts = MakeSessionOptions("0"); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_GE(devices[0]->attributes().memory_limit(), 0); - gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, SingleVirtualDeviceWithNoMemoryLimit) { // It'll create single virtual device for the gpu in question when // memory_limit_mb is unset. SessionOptions opts = MakeSessionOptions("0", 0, 1, {{}}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_GE(devices[0]->attributes().memory_limit(), 0); - gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, SingleVirtualDeviceWithMemoryLimit) { SessionOptions opts = MakeSessionOptions("0", 0, 1, {{123}}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(1, devices.size()); EXPECT_EQ(123 << 20, devices[0]->attributes().memory_limit()); - gtl::STLDeleteElements(&devices); } TEST_F(GPUDeviceTest, MultipleVirtualDevices) { SessionOptions opts = MakeSessionOptions("0", 0, 1, {{123, 456}}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); EXPECT_EQ(2, devices.size()); @@ -219,7 +216,6 @@ TEST_F(GPUDeviceTest, MultipleVirtualDevices) { devices[1]->attributes().locality().links().link(0).type()); EXPECT_EQ(BaseGPUDeviceFactory::InterconnectMap::kSameDeviceStrength, devices[1]->attributes().locality().links().link(0).strength()); - gtl::STLDeleteElements(&devices); } // Enabling unified memory on pre-Pascal GPUs results in an initialization @@ -236,7 +232,7 @@ TEST_F(GPUDeviceTest, UnifiedMemoryUnavailableOnPrePascalGpus) { opts.config.mutable_gpu_options() ->mutable_experimental() ->set_use_unified_memory(true); - std::vector devices; + std::vector> devices; Status status = DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices); EXPECT_EQ(status.code(), error::INTERNAL); @@ -259,7 +255,7 @@ TEST_F(GPUDeviceTest, UnifiedMemoryAllocation) { } SessionOptions opts = MakeSessionOptions("0", kGpuMemoryFraction); - std::vector devices; + std::vector> devices; TF_ASSERT_OK(DeviceFactory::GetFactory("GPU")->CreateDevices( opts, kDeviceNamePrefix, &devices)); ASSERT_EQ(1, devices.size()); @@ -278,8 +274,6 @@ TEST_F(GPUDeviceTest, UnifiedMemoryAllocation) { (memory_limit >> 20) << 20); EXPECT_NE(ptr, nullptr); allocator->DeallocateRaw(ptr); - - gtl::STLDeleteElements(&devices); } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc b/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc index 2144eea84f..f0656ff533 100644 --- a/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc +++ b/tensorflow/core/common_runtime/hierarchical_tree_broadcaster_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/hierarchical_tree_broadcaster.h" #include +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/base_collective_executor.h" #include "tensorflow/core/common_runtime/collective_rma_local.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -217,7 +218,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { << " num_devices_per_worker=" << num_devices_per_worker; int total_num_devices = num_workers * num_devices_per_worker; device_type_ = device_type; - std::vector local_devices; + std::vector> local_devices; SessionOptions sess_opts; sess_opts.env = Env::Default(); Bytes mem_limit(4 << 20); @@ -227,7 +228,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { if (device_type == DEVICE_CPU) { string dev_name = strings::StrCat("/job:worker/replica:0/task:", wi, "/device:CPU:", di); - local_devices.push_back(new ThreadPoolDevice( + local_devices.push_back(absl::make_unique( sess_opts, dev_name, mem_limit, dev_locality, cpu_allocator())); } else if (device_type == DEVICE_GPU && !gpu_devices_.empty()) { int dev_idx = (wi * num_devices_per_worker) + di; @@ -235,7 +236,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { LOG(INFO) << "dev_mgr has access to limited GPUs, reusing for more " "than one ring node."; } else { - local_devices.push_back(gpu_devices_[dev_idx]); + local_devices.push_back(std::move(gpu_devices_[dev_idx])); } } else { LOG(FATAL) << "Unsupported device_type " << device_type; @@ -243,7 +244,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { } } if (!dev_mgr_ || device_type == DEVICE_CPU) { - dev_mgr_.reset(new DeviceMgr(local_devices)); + dev_mgr_.reset(new DeviceMgr(std::move(local_devices))); } if (!gpu_ring_order_) gpu_ring_order_.reset(new string()); dev_resolver_.reset(new DeviceResolverLocal(dev_mgr_.get())); @@ -714,7 +715,7 @@ class HierarchicalTreeBroadcasterTest : public ::testing::Test { std::unique_ptr dev_resolver_; std::vector instances_; CollectiveParams col_params_; - std::vector gpu_devices_; + std::vector> gpu_devices_; std::unique_ptr dev_mgr_; std::unique_ptr gpu_ring_order_; mutex mu_; diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc index 1f585a8c24..bdd6c0e87d 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc @@ -75,12 +75,12 @@ Benchmark::Benchmark(const string& device, Graph* g, const int graph_def_version = g->versions().producer(); LocalExecutorParams params; - params.device = device_; + params.device = device_.get(); params.function_library = nullptr; params.create_kernel = [this, graph_def_version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_, nullptr, ndef, graph_def_version, - kernel); + return CreateNonCachedKernel(device_.get(), nullptr, ndef, + graph_def_version, kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -107,7 +107,7 @@ Benchmark::~Benchmark() { // run kernel destructors that may attempt to access state borrowed from // `device_`, such as the resource manager. exec_.reset(); - delete device_; + device_.reset(); delete pool_; } } diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.h b/tensorflow/core/common_runtime/kernel_benchmark_testlib.h index 555b43f655..b1557c50b0 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.h +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.h @@ -55,7 +55,7 @@ class Benchmark { private: thread::ThreadPool* pool_ = nullptr; - Device* device_ = nullptr; + std::unique_ptr device_ = nullptr; Rendezvous* rendez_ = nullptr; std::unique_ptr exec_; diff --git a/tensorflow/core/common_runtime/placer_test.cc b/tensorflow/core/common_runtime/placer_test.cc index 009f905f10..04e77e55f6 100644 --- a/tensorflow/core/common_runtime/placer_test.cc +++ b/tensorflow/core/common_runtime/placer_test.cc @@ -92,7 +92,7 @@ class FakeDevice : public Device { class DummyFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { return Status::OK(); } }; diff --git a/tensorflow/core/common_runtime/process_function_library_runtime_test.cc b/tensorflow/core/common_runtime/process_function_library_runtime_test.cc index cce2308011..21cb62118a 100644 --- a/tensorflow/core/common_runtime/process_function_library_runtime_test.cc +++ b/tensorflow/core/common_runtime/process_function_library_runtime_test.cc @@ -62,9 +62,12 @@ class ProcessFunctionLibraryRuntimeTest : public ::testing::Test { SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 2}); + std::vector> devices; TF_CHECK_OK(DeviceFactory::AddDevices(options, "/job:a/replica:0/task:0", - &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + &devices)); + device0_ = devices[0].get(); + device1_ = devices[1].get(); + device_mgr_.reset(new DeviceMgr(std::move(devices))); FunctionDefLibrary proto; for (const auto& fdef : flib) *(proto.add_function()) = fdef; lib_def_.reset(new FunctionLibraryDefinition(OpRegistry::Global(), proto)); @@ -138,8 +141,9 @@ class ProcessFunctionLibraryRuntimeTest : public ::testing::Test { return Status::OK(); } - std::vector devices_; std::unique_ptr device_mgr_; + Device* device0_ = nullptr; // Not owned. (Owned by device_mgr_.) + Device* device1_ = nullptr; // Not owned. (Owned by device_mgr_.) std::unique_ptr lib_def_; std::unique_ptr cluster_flr_; std::unique_ptr proc_flr_; @@ -165,16 +169,16 @@ TEST_F(ProcessFunctionLibraryRuntimeTest, Basic) { FunctionLibraryRuntime* flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/cpu:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[0]); + EXPECT_EQ(flr->device(), device0_); flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/device:CPU:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[0]); + EXPECT_EQ(flr->device(), device0_); flr = proc_flr_->GetFLR("/device:CPU:0"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[0]); + EXPECT_EQ(flr->device(), device0_); flr = proc_flr_->GetFLR("/job:a/replica:0/task:0/cpu:1"); EXPECT_NE(flr, nullptr); - EXPECT_EQ(flr->device(), devices_[1]); + EXPECT_EQ(flr->device(), device1_); flr = proc_flr_->GetFLR("abc"); EXPECT_EQ(flr, nullptr); rendezvous_->Unref(); diff --git a/tensorflow/core/common_runtime/renamed_device.cc b/tensorflow/core/common_runtime/renamed_device.cc index 56766a8df4..45541c35fe 100644 --- a/tensorflow/core/common_runtime/renamed_device.cc +++ b/tensorflow/core/common_runtime/renamed_device.cc @@ -14,15 +14,14 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/common_runtime/renamed_device.h" +#include "absl/memory/memory.h" namespace tensorflow { -// TODO(saeta): Convert to returning a std::unique_ptr? /* static */ -Device* RenamedDevice::NewRenamedDevice(const string& new_base, - Device* underlying, - bool owns_underlying, - bool isolate_session_state) { +std::unique_ptr RenamedDevice::NewRenamedDevice( + const string& new_base, Device* underlying, bool owns_underlying, + bool isolate_session_state) { DeviceNameUtils::ParsedName parsed_name; CHECK(DeviceNameUtils::ParseFullName(new_base, &parsed_name)); DeviceNameUtils::ParsedName underlying_parsed_name = @@ -36,8 +35,9 @@ Device* RenamedDevice::NewRenamedDevice(const string& new_base, parsed_name.id); DeviceAttributes attributes(underlying->attributes()); attributes.set_name(name); - return new RenamedDevice(underlying, attributes, owns_underlying, - isolate_session_state); + // Call absl::WrapUnique to access private constructor. + return absl::WrapUnique(new RenamedDevice( + underlying, attributes, owns_underlying, isolate_session_state)); } RenamedDevice::RenamedDevice(Device* underlying, diff --git a/tensorflow/core/common_runtime/renamed_device.h b/tensorflow/core/common_runtime/renamed_device.h index c00789a556..6d24f496ff 100644 --- a/tensorflow/core/common_runtime/renamed_device.h +++ b/tensorflow/core/common_runtime/renamed_device.h @@ -28,9 +28,10 @@ namespace tensorflow { // session. class RenamedDevice : public Device { public: - static Device* NewRenamedDevice(const string& new_base, Device* underlying, - bool owns_underlying, - bool isolate_session_state); + static std::unique_ptr NewRenamedDevice(const string& new_base, + Device* underlying, + bool owns_underlying, + bool isolate_session_state); ~RenamedDevice() override; diff --git a/tensorflow/core/common_runtime/ring_reducer_test.cc b/tensorflow/core/common_runtime/ring_reducer_test.cc index a271bf7b74..7feb29a6db 100644 --- a/tensorflow/core/common_runtime/ring_reducer_test.cc +++ b/tensorflow/core/common_runtime/ring_reducer_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/ring_reducer.h" #include +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/base_collective_executor.h" #include "tensorflow/core/common_runtime/collective_rma_local.h" #include "tensorflow/core/common_runtime/device.h" @@ -157,7 +158,7 @@ class RingReducerTest : public ::testing::Test { InitGPUDevices(); #endif device_type_ = device_type; - std::vector local_devices; + std::vector> local_devices; SessionOptions sess_opts; sess_opts.env = Env::Default(); Bytes mem_limit(4 << 20); @@ -167,7 +168,7 @@ class RingReducerTest : public ::testing::Test { if (device_type == DEVICE_CPU) { string dev_name = strings::StrCat("/job:worker/replica:0/task:", wi, "/cpu:", di); - local_devices.push_back(new ThreadPoolDevice( + local_devices.push_back(absl::make_unique( sess_opts, dev_name, mem_limit, dev_locality, cpu_allocator())); } else if (device_type == DEVICE_GPU && !gpu_devices_.empty()) { int dev_idx = (wi * num_devices) + di; @@ -175,7 +176,7 @@ class RingReducerTest : public ::testing::Test { LOG(INFO) << "dev_mgr has access to limited GPUs, reusing for more " "than one ring node."; } else { - local_devices.push_back(gpu_devices_[dev_idx]); + local_devices.push_back(std::move(gpu_devices_[dev_idx])); } } else { LOG(FATAL) << "Unsupported device_type " << device_type; @@ -185,7 +186,7 @@ class RingReducerTest : public ::testing::Test { if (!dev_mgr_ || device_type == DEVICE_CPU) { LOG(ERROR) << "resetting dev_mgr for " << local_devices.size() << " devices: "; - dev_mgr_.reset(new DeviceMgr(local_devices)); + dev_mgr_.reset(new DeviceMgr(std::move(local_devices))); } if (!gpu_ring_order_) gpu_ring_order_.reset(new string()); dev_resolver_.reset(new DeviceResolverLocal(dev_mgr_.get())); @@ -544,7 +545,7 @@ class RingReducerTest : public ::testing::Test { std::unique_ptr dev_resolver_; std::vector instances_; CollectiveParams col_params_; - std::vector gpu_devices_; + std::vector> gpu_devices_; std::unique_ptr dev_mgr_; std::unique_ptr gpu_ring_order_; mutex mu_; diff --git a/tensorflow/core/common_runtime/threadpool_device_factory.cc b/tensorflow/core/common_runtime/threadpool_device_factory.cc index c06a4035a7..f9cbb81749 100644 --- a/tensorflow/core/common_runtime/threadpool_device_factory.cc +++ b/tensorflow/core/common_runtime/threadpool_device_factory.cc @@ -13,12 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -// Register a factory that provides CPU devices. -#include "tensorflow/core/common_runtime/threadpool_device.h" - #include + +// Register a factory that provides CPU devices. +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/common_runtime/process_state.h" +#include "tensorflow/core/common_runtime/threadpool_device.h" #include "tensorflow/core/framework/allocator.h" #include "tensorflow/core/platform/numa.h" #include "tensorflow/core/public/session_options.h" @@ -29,7 +30,7 @@ namespace tensorflow { class ThreadPoolDeviceFactory : public DeviceFactory { public: Status CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector* devices) override { + std::vector>* devices) override { int num_numa_nodes = port::NUMANumNodes(); int n = 1; auto iter = options.config.device_count().find("CPU"); @@ -38,7 +39,7 @@ class ThreadPoolDeviceFactory : public DeviceFactory { } for (int i = 0; i < n; i++) { string name = strings::StrCat(name_prefix, "/device:CPU:", i); - ThreadPoolDevice* tpd = nullptr; + std::unique_ptr tpd; if (options.config.experimental().use_numa_affinity()) { int numa_node = i % num_numa_nodes; if (numa_node != i) { @@ -49,15 +50,15 @@ class ThreadPoolDeviceFactory : public DeviceFactory { } DeviceLocality dev_locality; dev_locality.set_numa_node(numa_node); - tpd = new ThreadPoolDevice( + tpd = absl::make_unique( options, name, Bytes(256 << 20), dev_locality, ProcessState::singleton()->GetCPUAllocator(numa_node)); } else { - tpd = new ThreadPoolDevice( + tpd = absl::make_unique( options, name, Bytes(256 << 20), DeviceLocality(), ProcessState::singleton()->GetCPUAllocator(port::kNUMANoAffinity)); } - devices->push_back(tpd); + devices->push_back(std::move(tpd)); } return Status::OK(); diff --git a/tensorflow/core/distributed_runtime/BUILD b/tensorflow/core/distributed_runtime/BUILD index cd9e58ac39..e388d3e6f0 100644 --- a/tensorflow/core/distributed_runtime/BUILD +++ b/tensorflow/core/distributed_runtime/BUILD @@ -625,6 +625,7 @@ tf_cc_test( "//tensorflow/core:test", "//tensorflow/core:test_main", "//tensorflow/core:testlib", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc b/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc index 4eed856759..40b18d321a 100644 --- a/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/collective_param_resolver_distributed_test.cc @@ -29,7 +29,8 @@ limitations under the License. namespace tensorflow { namespace { -static Device* NewDevice(const string& type, const string& name) { +static std::unique_ptr NewDevice(const string& type, + const string& name) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -40,7 +41,7 @@ static Device* NewDevice(const string& type, const string& name) { attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(3); // a non-default value - return new FakeDevice(attr); + return absl::make_unique(attr); } class FakeWorker : public TestWorkerInterface { @@ -156,16 +157,16 @@ class DeviceResDistTest : public ::testing::Test { void DefineWorker(const ConfigProto& config, const string& worker_name, const string& device_type, int num_devices) { - std::vector devices; + std::vector> devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i))); } - DeviceMgr* dev_mgr = new DeviceMgr(devices); + DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : devices) { + for (auto* d : dev_mgr->ListDevices()) { dv->push_back(d->name()); } DeviceResolverDistributed* dev_res = diff --git a/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc b/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc index 33e1c8f2c3..26f722a6bd 100644 --- a/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/collective_rma_distributed_test.cc @@ -41,7 +41,8 @@ limitations under the License. namespace tensorflow { namespace { -static Device* NewDevice(const string& type, const string& name) { +static std::unique_ptr NewDevice(const string& type, + const string& name) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -52,7 +53,7 @@ static Device* NewDevice(const string& type, const string& name) { attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(3); // a non-default value - return new FakeDevice(attr); + return absl::make_unique(attr); } static int64 kStepId = 123; @@ -211,16 +212,16 @@ class CollRMADistTest : public ::testing::Test { void DefineWorker(const ConfigProto& config, const string& worker_name, const string& device_type, int num_devices) { - std::vector devices; + std::vector> devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i))); } - DeviceMgr* dev_mgr = new DeviceMgr(devices); + DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : devices) { + for (auto d : dev_mgr->ListDevices()) { dv->push_back(d->name()); } DeviceResolverDistributed* dev_res = diff --git a/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc b/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc index ae44b98bd5..842a2b3b05 100644 --- a/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc +++ b/tensorflow/core/distributed_runtime/device_resolver_distributed_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/distributed_runtime/device_resolver_distributed.h" +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_mgr.h" #include "tensorflow/core/distributed_runtime/test_utils.h" #include "tensorflow/core/lib/core/notification.h" @@ -41,8 +42,8 @@ class TestableDeviceResolverDistributed : public DeviceResolverDistributed { // Create a fake 'Device' whose only interesting attribute is a non-default // DeviceLocality. -static Device* NewDevice(const string& type, const string& name, - int numa_node) { +static std::unique_ptr NewDevice(const string& type, const string& name, + int numa_node) { class FakeDevice : public Device { public: explicit FakeDevice(const DeviceAttributes& attr) : Device(nullptr, attr) {} @@ -53,7 +54,7 @@ static Device* NewDevice(const string& type, const string& name, attr.set_name(name); attr.set_device_type(type); attr.mutable_locality()->set_numa_node(numa_node); - return new FakeDevice(attr); + return absl::make_unique(attr); } // Create a fake WorkerInterface that responds to requests without RPCs, @@ -151,19 +152,19 @@ class DeviceResDistTest : public ::testing::Test { void DefineWorker(const string& worker_name, const string& device_type, int num_devices) { - std::vector devices; + std::vector> devices; for (int i = 0; i < num_devices; ++i) { devices.push_back(NewDevice( device_type, strings::StrCat(worker_name, "/device:", device_type, ":", i), i)); } - DeviceMgr* dev_mgr = new DeviceMgr(devices); + DeviceMgr* dev_mgr = new DeviceMgr(std::move(devices)); TestableDeviceResolverDistributed* dev_res = new TestableDeviceResolverDistributed(dev_mgr, &wc_, worker_name); resolvers_[worker_name] = dev_res; device_mgrs_.push_back(dev_mgr); std::vector* dv = &dev_by_task_[worker_name]; - for (auto d : devices) { + for (auto* d : dev_mgr->ListDevices()) { dv->push_back(d->name()); } FakeWorker* fw = new FakeWorker(worker_name, dev_mgr, dev_res); diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc index 5b0a420fad..c66466c0a6 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc @@ -87,7 +87,7 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, return tensorflow::errors::Internal( "invalid eager env_ or env_->rendezvous_mgr."); } - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(tensorflow::DeviceFactory::AddDevices( // TODO(nareshmodi): Correctly set the SessionOptions. @@ -97,12 +97,12 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, request->server_def().task_index()), &devices)); response->mutable_device_attributes()->Reserve(devices.size()); - for (auto& d : devices) { + for (const auto& d : devices) { *response->add_device_attributes() = d->attributes(); } std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(devices)); + new tensorflow::DeviceMgr(std::move(devices))); auto* r = env_->rendezvous_mgr->Find(request->rendezvous_id()); auto session_name = strings::StrCat("eager_", request->rendezvous_id()); diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc index 5ba522c2a2..7a1463e8f0 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl_test.cc @@ -68,12 +68,9 @@ class EagerServiceImplTest : public ::testing::Test { worker_env_.rendezvous_mgr = &rendezvous_mgr_; worker_env_.session_mgr = session_mgr_.get(); - Device* device = DeviceFactory::NewDevice( - "CPU", {}, "/job:localhost/replica:0/task:0/device:CPU:0"); - - worker_env_.local_devices = {device}; - - device_mgr_.reset(new DeviceMgr(worker_env_.local_devices)); + device_mgr_ = absl::make_unique(DeviceFactory::NewDevice( + "CPU", {}, "/job:localhost/replica:0/task:0/device:CPU:0")); + worker_env_.local_devices = device_mgr_->ListDevices(); worker_env_.device_mgr = device_mgr_.get(); } diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc index ae722fdfe9..cbd5cd927e 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include #include +#include #include "grpc/support/alloc.h" #include "grpcpp/grpcpp.h" @@ -156,10 +157,12 @@ Status GrpcServer::Init( string name_prefix = strings::StrCat("/job:", server_def_.job_name(), "/replica:0", "/task:", server_def_.task_index()); - TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(sess_opts, name_prefix, - &master_env_.local_devices)); - worker_env_.local_devices = master_env_.local_devices; - worker_env_.device_mgr = new DeviceMgr(worker_env_.local_devices); + std::vector> devices; + TF_RETURN_IF_ERROR( + DeviceFactory::AddDevices(sess_opts, name_prefix, &devices)); + worker_env_.device_mgr = new DeviceMgr(std::move(devices)); + master_env_.local_devices = worker_env_.device_mgr->ListDevices(); + worker_env_.local_devices = worker_env_.device_mgr->ListDevices(); worker_env_.rendezvous_mgr = rendezvous_mgr_func == nullptr ? new RpcRendezvousMgr(&worker_env_) : rendezvous_mgr_func(&worker_env_); diff --git a/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc b/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc index 0323300fdd..1c87fe9d92 100644 --- a/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc +++ b/tensorflow/core/distributed_runtime/rpc_collective_executor_mgr_test.cc @@ -42,8 +42,9 @@ class RpcCollectiveExecutorMgrTest : public ::testing::Test { WorkerCacheInterface* worker_cache = nullptr; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", NUM_DEVS}); - TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices_)); - device_mgr_.reset(new DeviceMgr(devices_)); + std::vector> devices; + TF_CHECK_OK(DeviceFactory::AddDevices(options, task_name, &devices)); + device_mgr_.reset(new DeviceMgr(std::move(devices))); std::unique_ptr dr(new DeviceResolverDistributed( device_mgr_.get(), worker_cache, task_name)); std::unique_ptr cpr( @@ -57,7 +58,6 @@ class RpcCollectiveExecutorMgrTest : public ::testing::Test { } std::unique_ptr cme_; - std::vector devices_; std::unique_ptr device_mgr_; }; diff --git a/tensorflow/core/distributed_runtime/session_mgr.cc b/tensorflow/core/distributed_runtime/session_mgr.cc index 38833bd202..29fe767e42 100644 --- a/tensorflow/core/distributed_runtime/session_mgr.cc +++ b/tensorflow/core/distributed_runtime/session_mgr.cc @@ -78,13 +78,13 @@ Status SessionMgr::CreateSession(const string& session, if (isolate_session_state) { // Create a private copy of the DeviceMgr for the WorkerSession. - std::vector renamed_devices; + std::vector> renamed_devices; for (Device* d : worker_env_->local_devices) { renamed_devices.push_back(RenamedDevice::NewRenamedDevice( worker_name, d, false, isolate_session_state)); } - auto device_mgr = MakeUnique(renamed_devices); + auto device_mgr = MakeUnique(std::move(renamed_devices)); auto graph_mgr = MakeUnique(worker_env_, device_mgr.get()); worker_session.reset( new WorkerSession(session, worker_name, diff --git a/tensorflow/core/distributed_runtime/session_mgr_test.cc b/tensorflow/core/distributed_runtime/session_mgr_test.cc index 99192119a6..1ab0d20f0b 100644 --- a/tensorflow/core/distributed_runtime/session_mgr_test.cc +++ b/tensorflow/core/distributed_runtime/session_mgr_test.cc @@ -46,11 +46,9 @@ class SessionMgrTest : public ::testing::Test { SessionMgrTest() : mgr_(&env_, "/job:mnist/replica:0/task:0", std::unique_ptr(), factory_) { - Device* device = - FakeDevice::MakeCPU("/job:mnist/replica:0/task:0/device:fakecpu:0") - .release(); - env_.local_devices = {device}; - device_mgr_.reset(new DeviceMgr(env_.local_devices)); + device_mgr_ = absl::make_unique( + FakeDevice::MakeCPU("/job:mnist/replica:0/task:0/device:fakecpu:0")); + env_.local_devices = device_mgr_->ListDevices(); env_.device_mgr = device_mgr_.get(); } diff --git a/tensorflow/core/grappler/grappler_item_builder.cc b/tensorflow/core/grappler/grappler_item_builder.cc index cf99f4908b..e69dfa79d1 100644 --- a/tensorflow/core/grappler/grappler_item_builder.cc +++ b/tensorflow/core/grappler/grappler_item_builder.cc @@ -102,10 +102,11 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, } // Instantiate all variables for function library runtime creation. - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); - std::unique_ptr dvc_mgr(new DeviceMgr(devices)); + Device* cpu_device = devices[0].get(); + std::unique_ptr dvc_mgr(new DeviceMgr(std::move(devices))); FunctionLibraryDefinition function_library(OpRegistry::Global(), graph_def.library()); Env* env = Env::Default(); @@ -124,7 +125,7 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, new ProcessFunctionLibraryRuntime(dvc_mgr.get(), env, graph_def.versions().producer(), &function_library, *optimizer_opts)); - FunctionLibraryRuntime* flr = pflr->GetFLR(devices[0]->name()); + FunctionLibraryRuntime* flr = pflr->GetFLR(cpu_device->name()); // Create the GraphOptimizer to optimize the graph def. GraphConstructorOptions graph_ctor_opts; @@ -137,7 +138,7 @@ Status OptimizeGraph(const GraphDef& graph_def_arg, GraphDef* output_graph_def, // Optimize the graph. ::tensorflow::GraphOptimizer optimizer(*optimizer_opts); - optimizer.Optimize(flr, env, devices[0], &graphptr, /*shape_map=*/nullptr); + optimizer.Optimize(flr, env, cpu_device, &graphptr, /*shape_map=*/nullptr); graphptr->ToGraphDef(output_graph_def); // The default values of attributes might have been stripped by the optimizer. diff --git a/tensorflow/core/grappler/optimizers/BUILD b/tensorflow/core/grappler/optimizers/BUILD index b6f989f2c9..8e6629565a 100644 --- a/tensorflow/core/grappler/optimizers/BUILD +++ b/tensorflow/core/grappler/optimizers/BUILD @@ -142,7 +142,6 @@ cc_library( ":graph_optimizer", "//tensorflow/core:core_cpu_base", "//tensorflow/core:framework", - "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler:grappler_item", @@ -150,6 +149,7 @@ cc_library( "//tensorflow/core/grappler:op_types", "//tensorflow/core/grappler:utils", "//tensorflow/core/grappler/utils:functions", + "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/core/grappler/optimizers/function_optimizer.cc b/tensorflow/core/grappler/optimizers/function_optimizer.cc index f99826ddca..f8ddbeb659 100644 --- a/tensorflow/core/grappler/optimizers/function_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/function_optimizer.cc @@ -16,7 +16,9 @@ limitations under the License. #include "tensorflow/core/grappler/optimizers/function_optimizer.h" #include +#include +#include "absl/memory/memory.h" #include "absl/strings/str_replace.h" #include "absl/strings/substitute.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -343,14 +345,15 @@ class FunctionOptimizerContext { DeviceAttributes attr; attr.set_name("/device:CPU:0"); attr.set_device_type("CPU"); - Device* device = new FakeCPUDevice(env, attr); - device_mgr_.reset(new DeviceMgr({device})); + std::vector> devices; + devices.push_back(absl::make_unique(env, attr)); + device_mgr_ = absl::make_unique(std::move(devices)); OptimizerOptions optimizer_opts; optimizer_opts.set_do_function_inlining(true); process_flr_.reset(new ProcessFunctionLibraryRuntime( device_mgr_.get(), env, graph_version_, &function_library_, optimizer_opts)); - flr_ = process_flr_->GetFLR(device->name()); + flr_ = process_flr_->GetFLR(device_mgr_->ListDevices()[0]->name()); } } diff --git a/tensorflow/core/kernels/data/BUILD b/tensorflow/core/kernels/data/BUILD index 7192684e2d..dcb6975669 100644 --- a/tensorflow/core/kernels/data/BUILD +++ b/tensorflow/core/kernels/data/BUILD @@ -600,6 +600,7 @@ tf_kernel_library( "//tensorflow/core:protos_all_cc", "//tensorflow/core:session_options", "//tensorflow/core/kernels:ops_util", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/kernels/data/iterator_ops.cc b/tensorflow/core/kernels/data/iterator_ops.cc index 93999dc095..98b67454d5 100644 --- a/tensorflow/core/kernels/data/iterator_ops.cc +++ b/tensorflow/core/kernels/data/iterator_ops.cc @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/kernels/data/iterator_ops.h" +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/graph_runner.h" #include "tensorflow/core/common_runtime/renamed_device.h" #include "tensorflow/core/common_runtime/threadpool_device.h" @@ -545,10 +546,9 @@ FunctionLibraryRuntime* IteratorHandleOp::CreatePrivateFLR( // in its resource manager. The existing device will outlive the // IteratorResource, because we are storing the IteratorResource // in that device's resource manager. - Device* wrapped_device = RenamedDevice::NewRenamedDevice( + *device_mgr = absl::make_unique(RenamedDevice::NewRenamedDevice( ctx->device()->name(), down_cast(ctx->device()), - false /* owns_underlying */, false /* isolate_session_state */); - device_mgr->reset(new DeviceMgr({wrapped_device})); + false /* owns_underlying */, false /* isolate_session_state */)); flib_def->reset(new FunctionLibraryDefinition( *ctx->function_library()->GetFunctionLibraryDefinition())); pflr->reset(new ProcessFunctionLibraryRuntime( diff --git a/tensorflow/core/kernels/data/single_threaded_executor_test.cc b/tensorflow/core/kernels/data/single_threaded_executor_test.cc index 6244e287bb..7bb51fb8b5 100644 --- a/tensorflow/core/kernels/data/single_threaded_executor_test.cc +++ b/tensorflow/core/kernels/data/single_threaded_executor_test.cc @@ -51,17 +51,17 @@ class ExecutorTest : public ::testing::Test { // when the test completes. CHECK(rendez_->Unref()); delete exec_; - delete device_; } // Resets executor_ with a new executor based on a graph 'gdef'. void Create(std::unique_ptr graph) { const int version = graph->versions().producer(); LocalExecutorParams params; - params.device = device_; + params.device = device_.get(); params.create_kernel = [this, version](const NodeDef& ndef, OpKernel** kernel) { - return CreateNonCachedKernel(device_, nullptr, ndef, version, kernel); + return CreateNonCachedKernel(device_.get(), nullptr, ndef, version, + kernel); }; params.delete_kernel = [](OpKernel* kernel) { DeleteNonCachedKernel(kernel); @@ -86,7 +86,7 @@ class ExecutorTest : public ::testing::Test { return exec_->Run(args); } - Device* device_ = nullptr; + std::unique_ptr device_; Executor* exec_ = nullptr; Executor::Args::Runner runner_; Rendezvous* rendez_ = nullptr; diff --git a/tensorflow/lite/delegates/flex/BUILD b/tensorflow/lite/delegates/flex/BUILD index 222a043a88..63e86899da 100644 --- a/tensorflow/lite/delegates/flex/BUILD +++ b/tensorflow/lite/delegates/flex/BUILD @@ -116,6 +116,7 @@ cc_library( hdrs = ["delegate_data.h"], deps = [ ":buffer_map", + "@com_google_absl//absl/memory", "//tensorflow/core/common_runtime/eager:context", ] + select({ "//tensorflow:android": [ diff --git a/tensorflow/lite/delegates/flex/delegate_data.cc b/tensorflow/lite/delegates/flex/delegate_data.cc index b62479a448..1483a53038 100644 --- a/tensorflow/lite/delegates/flex/delegate_data.cc +++ b/tensorflow/lite/delegates/flex/delegate_data.cc @@ -14,20 +14,21 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/lite/delegates/flex/delegate_data.h" +#include "absl/memory/memory.h" #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/lib/core/status.h" namespace tflite { namespace flex { tensorflow::Status DelegateData::Create(std::unique_ptr* data) { - std::vector devices; + std::vector> devices; TF_RETURN_IF_ERROR(tensorflow::DeviceFactory::AddDevices( tensorflow::SessionOptions(), "/job:localhost/replica:0/task:0", &devices)); - std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(devices)); + std::unique_ptr device_mgr = + absl::make_unique(std::move(devices)); // Note that Rendezvous is ref-counted so it will be automatically deleted. tensorflow::Rendezvous* rendezvous = new tensorflow::IntraProcessRendezvous(device_mgr.get()); diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index c8d1e1bdc5..b51f80c1a7 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -2012,13 +2012,13 @@ bool InlineAllFunctions(GraphDef* graphdef) { tensorflow::SessionOptions options; auto* device_count = options.config.mutable_device_count(); device_count->insert({"CPU", 1}); - std::vector devices; + std::vector> devices; TF_CHECK_OK(tensorflow::DeviceFactory::AddDevices( options, "/job:localhost/replica:0/task:0", &devices)); tensorflow::FunctionLibraryDefinition fld(tensorflow::OpRegistry::Global(), graphdef_copy.library()); - tensorflow::DeviceMgr device_mgr(devices); + tensorflow::DeviceMgr device_mgr(std::move(devices)); tensorflow::OptimizerOptions o_opts; tensorflow::ProcessFunctionLibraryRuntime pflr( &device_mgr, tensorflow::Env::Default(), TF_GRAPH_DEF_VERSION, &fld, diff --git a/tensorflow/python/client/device_lib.i b/tensorflow/python/client/device_lib.i index 944e855cee..3e579152d5 100644 --- a/tensorflow/python/client/device_lib.i +++ b/tensorflow/python/client/device_lib.i @@ -48,17 +48,14 @@ static std::vector ListDevicesWithSessionConfig( std::vector output; SessionOptions options; options.config = config; - std::vector devices; + std::vector> devices; Status status = DeviceFactory::AddDevices( options, "" /* name_prefix */, &devices); if (!status.ok()) { Set_TF_Status_from_Status(out_status, status); } - std::vector> device_holder(devices.begin(), - devices.end()); - - for (const Device* device : devices) { + for (const std::unique_ptr& device : devices) { const DeviceAttributes& attr = device->attributes(); string attr_serialized; if (!attr.SerializeToString(&attr_serialized)) { diff --git a/tensorflow/python/grappler/tf_optimizer.i b/tensorflow/python/grappler/tf_optimizer.i index daa5bc9444..b746c3ec26 100644 --- a/tensorflow/python/grappler/tf_optimizer.i +++ b/tensorflow/python/grappler/tf_optimizer.i @@ -74,13 +74,13 @@ limitations under the License. void DetectDevices(std::unordered_map* device_map) { tensorflow::SessionOptions options; - std::vector devices; + std::vector> devices; tensorflow::Status status = tensorflow::DeviceFactory::AddDevices(options, "", &devices); if (!status.ok()) { return; } - for (const tensorflow::Device* device : devices) { + for (const std::unique_ptr& device : devices) { tensorflow::DeviceProperties& prop = (*device_map)[device->name()]; prop = tensorflow::grappler::GetDeviceInfo(device->parsed_name()); @@ -88,7 +88,6 @@ void DetectDevices(std::unordered_map* dev // available device memory. const tensorflow::DeviceAttributes& attr = device->attributes(); prop.set_memory_size(attr.memory_limit()); - delete device; } } -- GitLab From dd9642c39d1468e0d8d0db66e3664414f1b510be Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 27 Nov 2018 10:27:27 -0800 Subject: [PATCH 397/672] Ensure all fuzzers fuzz the op they have to fuzz. PiperOrigin-RevId: 223013893 --- tensorflow/core/kernels/fuzzing/encode_base64_fuzz.cc | 2 +- tensorflow/core/kernels/fuzzing/fuzz_session.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tensorflow/core/kernels/fuzzing/encode_base64_fuzz.cc b/tensorflow/core/kernels/fuzzing/encode_base64_fuzz.cc index a8f07f4bad..b8d779fb13 100644 --- a/tensorflow/core/kernels/fuzzing/encode_base64_fuzz.cc +++ b/tensorflow/core/kernels/fuzzing/encode_base64_fuzz.cc @@ -19,7 +19,7 @@ limitations under the License. namespace tensorflow { namespace fuzzing { -class FuzzEncodeBase64 : public FuzzSession { +class FuzzEncodeBase64 : public FuzzStringInputOp { SINGLE_INPUT_OP_BUILDER(DT_STRING, EncodeBase64); }; diff --git a/tensorflow/core/kernels/fuzzing/fuzz_session.h b/tensorflow/core/kernels/fuzzing/fuzz_session.h index 9777be1ae8..57d562ddf4 100644 --- a/tensorflow/core/kernels/fuzzing/fuzz_session.h +++ b/tensorflow/core/kernels/fuzzing/fuzz_session.h @@ -72,11 +72,11 @@ class FuzzSession { // By convention, the graph should have inputs named "input1", ... // "inputN", and one output node, named "output". // Users of FuzzSession should override this method to create their graph. - virtual void BuildGraph(const Scope& scope) {} + virtual void BuildGraph(const Scope& scope) = 0; // Implements the logic that converts an opaque byte buffer // from the fuzzer to Tensor inputs to the graph. Users must override. - virtual void FuzzImpl(const uint8_t* data, size_t size) {} + virtual void FuzzImpl(const uint8_t* data, size_t size) = 0; // Initializes the FuzzSession. Not safe for multithreading. // Separate init function because the call to virtual BuildGraphDef -- GitLab From 411cc508e1a63d648855014f0912663e780a0ff9 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Tue, 27 Nov 2018 10:48:57 -0800 Subject: [PATCH 398/672] Optimize accesses to the "begin" and "end" tensors in `ValidateStridedSliceOp()`. 1. Hoist the call to `Tensor::flat()` on the begin and end tensors out of the loop over dimensions. This avoids revalidating the tensor type, shape, and alignment once per dimension. 2. Use `Tensor::vec()` instead of `Tensor::flat()` because we have already checked that the corresponding input tensors are vectors, and the vector codepath is more efficient. PiperOrigin-RevId: 223017951 --- tensorflow/core/util/strided_slice_op.cc | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tensorflow/core/util/strided_slice_op.cc b/tensorflow/core/util/strided_slice_op.cc index ad8a44a518..55688e5808 100644 --- a/tensorflow/core/util/strided_slice_op.cc +++ b/tensorflow/core/util/strided_slice_op.cc @@ -83,10 +83,17 @@ static Status TF_MUST_USE_RESULT BuildDenseSpec( { int full_index = 0; - const auto& strides_flat = sparse.strides_tensor.flat(); + const T* const strides_flat = sparse.strides_tensor.vec().data(); dense->begin_valid = sparse.begin_tensor != nullptr; dense->end_valid = sparse.end_tensor != nullptr; + const T* const begin_flat = sparse.begin_tensor != nullptr + ? sparse.begin_tensor->vec().data() + : nullptr; + const T* const end_flat = sparse.end_tensor != nullptr + ? sparse.end_tensor->vec().data() + : nullptr; + for (int i = 0; i < sparse.dims; i++) { if ((1 << i) & sparse.ellipsis_mask) { // Expand the ellipsis into the appropriate indices @@ -112,16 +119,14 @@ static Status TF_MUST_USE_RESULT BuildDenseSpec( } // Gather slicing spec into appropriate index - if (sparse.begin_tensor != nullptr) { - const auto& begin_flat = sparse.begin_tensor->flat(); - dense->begin[full_index] = internal::SubtleMustCopy(begin_flat(i)); + if (begin_flat != nullptr) { + dense->begin[full_index] = internal::SubtleMustCopy(begin_flat[i]); } - if (sparse.end_tensor != nullptr) { - const auto& end_flat = sparse.end_tensor->flat(); - dense->end[full_index] = internal::SubtleMustCopy(end_flat(i)); + if (end_flat != nullptr) { + dense->end[full_index] = internal::SubtleMustCopy(end_flat[i]); } dense->strides[full_index] = - internal::SubtleMustCopy(strides_flat(i)); + internal::SubtleMustCopy(strides_flat[i]); if (sparse.begin_mask & (1 << i)) { dense->begin_mask |= (1 << full_index); } -- GitLab From 06f3fdb6f14732ef9d4a5c50d2cb10ab605373ce Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 11:09:45 -0800 Subject: [PATCH 399/672] Add min-duration flags to benchmark_model: --min_secs, --warmup_min_secs. The existing flags --num_runs, --warmup_runs become only minima. Thus the old behavior is restored by passing 0.0 for both --min_secs, --warmup_min_secs. The default values --min_secs=1.0, --warmup_min_secs=0.5 reflect what it typically takes to get stable benchmark results on an Android device. The operating system won't ramp up to max clock speed in less than (order of magnitude) 100 ms, so warming up for less than a few hundreds ms results in inconsistent timings. PiperOrigin-RevId: 223021882 --- .../lite/tools/benchmark/benchmark_model.cc | 49 ++++++++++++++----- .../lite/tools/benchmark/benchmark_model.h | 3 +- .../lite/tools/benchmark/benchmark_test.cc | 2 + 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/tensorflow/lite/tools/benchmark/benchmark_model.cc b/tensorflow/lite/tools/benchmark/benchmark_model.cc index 05148aea65..e9b485efca 100644 --- a/tensorflow/lite/tools/benchmark/benchmark_model.cc +++ b/tensorflow/lite/tools/benchmark/benchmark_model.cc @@ -51,11 +51,13 @@ using tensorflow::Stat; BenchmarkParams BenchmarkModel::DefaultParams() { BenchmarkParams params; params.AddParam("num_runs", BenchmarkParam::Create(50)); + params.AddParam("min_secs", BenchmarkParam::Create(1.0f)); params.AddParam("run_delay", BenchmarkParam::Create(-1.0f)); params.AddParam("num_threads", BenchmarkParam::Create(1)); params.AddParam("benchmark_name", BenchmarkParam::Create("")); params.AddParam("output_prefix", BenchmarkParam::Create("")); params.AddParam("warmup_runs", BenchmarkParam::Create(1)); + params.AddParam("warmup_min_secs", BenchmarkParam::Create(0.5f)); return params; } @@ -73,19 +75,34 @@ void BenchmarkLoggingListener::OnBenchmarkEnd(const BenchmarkResults &results) { std::vector BenchmarkModel::GetFlags() { return { - CreateFlag("num_runs", ¶ms_, "number of runs"), + CreateFlag("num_runs", ¶ms_, + "minimum number of runs, see also min_secs"), + CreateFlag( + "min_secs", ¶ms_, + "minimum number of seconds to rerun for, potentially making the " + "actual number of runs to be greater than num_runs"), CreateFlag("run_delay", ¶ms_, "delay between runs in seconds"), CreateFlag("num_threads", ¶ms_, "number of threads"), CreateFlag("benchmark_name", ¶ms_, "benchmark name"), CreateFlag("output_prefix", ¶ms_, "benchmark output prefix"), - CreateFlag("warmup_runs", ¶ms_, - "how many runs to initialize model"), + CreateFlag( + "warmup_runs", ¶ms_, + "minimum number of runs performed on initialization, to " + "allow performance characteristics to settle, see also " + "warmup_min_secs"), + CreateFlag( + "warmup_min_secs", ¶ms_, + "minimum number of seconds to rerun for, potentially making the " + "actual number of warm-up runs to be greater than warmup_runs"), }; } void BenchmarkModel::LogParams() { - TFLITE_LOG(INFO) << "Num runs: [" << params_.Get("num_runs") << "]"; + TFLITE_LOG(INFO) << "Min num runs: [" << params_.Get("num_runs") + << "]"; + TFLITE_LOG(INFO) << "Min runs duration (seconds): [" + << params_.Get("min_secs") << "]"; TFLITE_LOG(INFO) << "Inter-run delay (seconds): [" << params_.Get("run_delay") << "]"; TFLITE_LOG(INFO) << "Num threads: [" << params_.Get("num_threads") @@ -94,16 +111,24 @@ void BenchmarkModel::LogParams() { << params_.Get("benchmark_name") << "]"; TFLITE_LOG(INFO) << "Output prefix: [" << params_.Get("output_prefix") << "]"; - TFLITE_LOG(INFO) << "Warmup runs: [" << params_.Get("warmup_runs") - << "]"; + TFLITE_LOG(INFO) << "Min warmup runs: [" + << params_.Get("warmup_runs") << "]"; + TFLITE_LOG(INFO) << "Min warmup runs duration (seconds): [" + << params_.Get("warmup_min_secs") << "]"; } void BenchmarkModel::PrepareInputsAndOutputs() {} -Stat BenchmarkModel::Run(int num_times, RunType run_type) { +Stat BenchmarkModel::Run(int min_num_times, float min_secs, + RunType run_type) { Stat run_stats; - TFLITE_LOG(INFO) << "Running benchmark for " << num_times << " iterations "; - for (int run = 0; run < num_times; run++) { + TFLITE_LOG(INFO) << "Running benchmark for at least " << min_num_times + << " iterations and at least " << min_secs << " seconds"; + int64_t min_finish_us = + profiling::time::NowMicros() + static_cast(min_secs * 1.e6f); + for (int run = 0; + run < min_num_times || profiling::time::NowMicros() < min_finish_us; + run++) { PrepareInputsAndOutputs(); listeners_.OnSingleRunStart(run_type); int64_t start_us = profiling::time::NowMicros(); @@ -145,9 +170,11 @@ void BenchmarkModel::Run() { uint64_t input_bytes = ComputeInputBytes(); Stat warmup_time_us = - Run(params_.Get("warmup_runs"), WARMUP); + Run(params_.Get("warmup_runs"), + params_.Get("warmup_min_secs"), WARMUP); Stat inference_time_us = - Run(params_.Get("num_runs"), REGULAR); + Run(params_.Get("num_runs"), params_.Get("min_secs"), + REGULAR); listeners_.OnBenchmarkEnd( {startup_latency_us, input_bytes, warmup_time_us, inference_time_us}); } diff --git a/tensorflow/lite/tools/benchmark/benchmark_model.h b/tensorflow/lite/tools/benchmark/benchmark_model.h index d8a9b05010..31ee5c92aa 100644 --- a/tensorflow/lite/tools/benchmark/benchmark_model.h +++ b/tensorflow/lite/tools/benchmark/benchmark_model.h @@ -150,7 +150,8 @@ class BenchmarkModel { bool ParseFlags(int argc, char** argv); virtual std::vector GetFlags(); virtual uint64_t ComputeInputBytes() = 0; - virtual tensorflow::Stat Run(int num_times, RunType run_type); + virtual tensorflow::Stat Run(int min_num_times, float min_secs, + RunType run_type); virtual void PrepareInputsAndOutputs(); virtual void RunImpl() = 0; BenchmarkParams params_; diff --git a/tensorflow/lite/tools/benchmark/benchmark_test.cc b/tensorflow/lite/tools/benchmark/benchmark_test.cc index 59d23d9008..8191fbcd73 100644 --- a/tensorflow/lite/tools/benchmark/benchmark_test.cc +++ b/tensorflow/lite/tools/benchmark/benchmark_test.cc @@ -33,6 +33,7 @@ namespace { BenchmarkParams CreateParams() { BenchmarkParams params; params.AddParam("num_runs", BenchmarkParam::Create(2)); + params.AddParam("min_secs", BenchmarkParam::Create(1.0f)); params.AddParam("run_delay", BenchmarkParam::Create(-1.0f)); params.AddParam("num_threads", BenchmarkParam::Create(1)); params.AddParam("benchmark_name", BenchmarkParam::Create("")); @@ -42,6 +43,7 @@ BenchmarkParams CreateParams() { params.AddParam("input_layer", BenchmarkParam::Create("")); params.AddParam("input_layer_shape", BenchmarkParam::Create("")); params.AddParam("use_nnapi", BenchmarkParam::Create(false)); + params.AddParam("warmup_min_secs", BenchmarkParam::Create(0.5f)); return params; } -- GitLab From 7ac49ea7f13fd02b1e8be036ff5b42641ff5c627 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 27 Nov 2018 11:15:06 -0800 Subject: [PATCH 400/672] [TF:XLA] Make DynamicStitch work for index tensors with zero elements PiperOrigin-RevId: 223022861 --- .../compiler/tests/dynamic_stitch_test.py | 9 +++++++ .../tf2xla/kernels/dynamic_stitch_op.cc | 25 +++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/tensorflow/compiler/tests/dynamic_stitch_test.py b/tensorflow/compiler/tests/dynamic_stitch_test.py index 50b04daa6b..e89cf975f5 100644 --- a/tensorflow/compiler/tests/dynamic_stitch_test.py +++ b/tensorflow/compiler/tests/dynamic_stitch_test.py @@ -58,6 +58,15 @@ class DynamicStitchTest(xla_test.XLATestCase): [idx1, idx2], [val1, val2], expected=np.array([[], [], [], []], np.int32)) + def testEmptyIndex(self): + idx1 = np.array([], dtype=np.int32) + idx2 = np.array([[], []], dtype=np.int32) + val1 = np.ndarray(shape=(0, 9), dtype=np.int32) + val2 = np.ndarray(shape=(2, 0, 9), dtype=np.int32) + self._AssertDynamicStitchResultIs([idx1, idx2], [val1, val2], + expected=np.ndarray( + shape=(0, 9), dtype=np.int32)) + def testSimple1D(self): val1 = np.array([0, 4, 7], dtype=np.int32) val2 = np.array([1, 6, 2, 3, 5], dtype=np.int32) diff --git a/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc b/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc index b2f6ef43fa..6e6ba21daf 100644 --- a/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc @@ -113,8 +113,20 @@ class DynamicStitchOp : public XlaOpKernel { } } int number_of_indices = max_index + 1; - OP_REQUIRES(ctx, number_of_indices > 0, - errors::InvalidArgument("no indices supplied")); + int64 result_rank = 1 + data0_shape.dims() - indices0_shape.dims(); + if (number_of_indices == 0) { + std::vector result_shape(result_rank); + for (int d = indices0_shape.dims(); d < data0_shape.dims(); d++) { + result_shape[d - indices0_shape.dims() + 1] = data0_shape.dim_size(d); + } + xla::PrimitiveType element_type = + ctx->input_xla_type(ctx->num_inputs() - 1); + xla::Literal empty_literal = xla::Literal::CreateFromShape( + xla::ShapeUtil::MakeShape(element_type, result_shape)); + ctx->SetOutput(0, xla::ConstantLiteral(ctx->builder(), empty_literal)); + return; + } + // Construct the reverse mapping, for each index, of which slice of which // input it comes from. std::vector src_input_vector(number_of_indices); @@ -157,12 +169,9 @@ class DynamicStitchOp : public XlaOpKernel { // Set up the vectors for slicing: the first dimension will vary // slice by slice, and the rest take the full common extra shape. - std::vector slice_start(1 + data0_shape.dims() - - indices0_shape.dims()); - std::vector slice_limit(1 + data0_shape.dims() - - indices0_shape.dims()); - std::vector stride(1 + data0_shape.dims() - indices0_shape.dims(), - 1); + std::vector slice_start(result_rank); + std::vector slice_limit(result_rank); + std::vector stride(result_rank, 1); for (int d = indices0_shape.dims(); d < data0_shape.dims(); d++) { slice_limit[1 + d - indices0_shape.dims()] = data0_shape.dim_size(d); } -- GitLab From 5bb914349a484f25845a2e77fb1b989760a5f64f Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 27 Nov 2018 11:46:28 -0800 Subject: [PATCH 401/672] Ensure default args of some functions are similar in TF 1.0 and TF 2.0. PiperOrigin-RevId: 223029699 --- tensorflow/python/ops/math_ops.py | 12 ++++++------ tensorflow/python/ops/nn_ops.py | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index d6b2423c1b..c3feb1870d 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -82,8 +82,6 @@ def argmax(input, output_type=dtypes.int64): axis = deprecation.deprecated_argument_lookup( "axis", axis, "dimension", dimension) - if axis is None: - axis = 0 return argmax_v2(input, axis, output_type, name) @@ -111,6 +109,8 @@ def argmax_v2(input, Returns: A `Tensor` of type `output_type`. """ + if axis is None: + axis = 0 return gen_math_ops.arg_max(input, axis, name=name, output_type=output_type) @@ -127,8 +127,6 @@ def argmin(input, output_type=dtypes.int64): axis = deprecation.deprecated_argument_lookup( "axis", axis, "dimension", dimension) - if axis is None: - axis = 0 return argmin_v2(input, axis, output_type, name) @@ -156,6 +154,8 @@ def argmin_v2(input, Returns: A `Tensor` of type `output_type`. """ + if axis is None: + axis = 0 return gen_math_ops.arg_min(input, axis, name=name, output_type=output_type) @@ -1521,8 +1521,6 @@ def count_nonzero(input_tensor, "axis", axis, "reduction_indices", reduction_indices ) - if keepdims is None: - keepdims = False return count_nonzero_v2(input_tensor, axis, keepdims, dtype, name) @@ -1580,6 +1578,8 @@ def count_nonzero_v2(input, # pylint: disable=redefined-builtin Returns: The reduced tensor (number of nonzero values). """ + if keepdims is None: + keepdims = False with ops.name_scope(name, "count_nonzero", [input]): input = ops.convert_to_tensor(input, name="input") # A scalar of 'zero' is enough as `not_equal` will broadcast. diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 2596f8e9bc..2ffe381216 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -2237,6 +2237,8 @@ def softmax_v2(logits, axis=None, name=None): InvalidArgumentError: if `logits` is empty or `axis` is beyond the last dimension of `logits`. """ + if axis is None: + axis = -1 return _softmax(logits, gen_nn_ops.softmax, axis, name) @@ -2292,6 +2294,8 @@ def log_softmax_v2(logits, axis=None, name=None): InvalidArgumentError: if `logits` is empty or `axis` is beyond the last dimension of `logits`. """ + if axis is None: + axis = -1 return _softmax(logits, gen_nn_ops.log_softmax, axis, name) -- GitLab From b186f4dc0da5c437a767e128e788b5ffc595583f Mon Sep 17 00:00:00 2001 From: Michael Kuperstein Date: Tue, 27 Nov 2018 11:49:18 -0800 Subject: [PATCH 402/672] [XLA] Make no_duplicate literal generation better supported for half/bfloat16 PiperOrigin-RevId: 223030267 --- tensorflow/compiler/xla/tests/BUILD | 1 + tensorflow/compiler/xla/tests/test_utils.cc | 146 ++++++++++++------ .../compiler/xla/tests/test_utils_test.cc | 23 +++ 3 files changed, 119 insertions(+), 51 deletions(-) diff --git a/tensorflow/compiler/xla/tests/BUILD b/tensorflow/compiler/xla/tests/BUILD index d92255dc48..2c18e2fd10 100644 --- a/tensorflow/compiler/xla/tests/BUILD +++ b/tensorflow/compiler/xla/tests/BUILD @@ -79,6 +79,7 @@ cc_library( "//tensorflow/compiler/xla/service:hlo_verifier", "//tensorflow/compiler/xla/service:transfer_manager", "//tensorflow/core:lib", + "@com_google_absl//absl/base", "@com_google_absl//absl/memory", "@com_google_absl//absl/types:span", ], diff --git a/tensorflow/compiler/xla/tests/test_utils.cc b/tensorflow/compiler/xla/tests/test_utils.cc index 2f18036ff4..8b4be6607f 100644 --- a/tensorflow/compiler/xla/tests/test_utils.cc +++ b/tensorflow/compiler/xla/tests/test_utils.cc @@ -15,6 +15,7 @@ limitations under the License. #include +#include "absl/base/casts.h" #include "absl/memory/memory.h" #include "tensorflow/compiler/xla/literal_util.h" #include "tensorflow/compiler/xla/primitive_util.h" @@ -28,65 +29,112 @@ namespace xla { namespace { template -void PopulateWithRandomFloatingPointDataImpl(Literal* literal, - std::minstd_rand0* engine, - bool no_duplicates) { +void PopulateWithRandomFloatingPointData(Literal* literal, + std::minstd_rand0* engine) { + std::uniform_real_distribution generator(-0.1f, 0.2f); + for (FloatT& value : literal->data()) { + value = static_cast(generator(*engine)); + } +} + +template +void PopulateWithIntNext(Literal* literal); + +template <> +void PopulateWithIntNext(Literal* literal) { + // Duplicates may be generated if we don't have enough bits. + uint16 next_value = 0; + for (half& value : literal->data()) { + // Zero-out the MSB of the exponent to avoid Infs and NaNs, and put it into + // the sign bit. We could be less wasteful, but this is best-effort anyway. + uint16 exponent_msb = next_value & 0x4000; + value.x = (next_value & 0xBFFF) | (exponent_msb << 1); + next_value++; + } +} + +template <> +void PopulateWithIntNext(Literal* literal) { + // Duplicates may be generated if we don't have enough bits. + uint16 next_value = 0; + for (bfloat16& value : literal->data()) { + // Zero-out the MSB of the exponent to avoid Infs and NaNs, and put it into + // the sign bit. We could be less wasteful, but this is best-effort anyway. + uint16 exponent_msb = next_value & 0x4000; + value.value = (next_value & 0xBFFF) | (exponent_msb << 1); + next_value++; + } +} + +template +void PopulateWithNextAfter(Literal* literal) { + // Duplicates may be generated if the number of elements in the literal + // exceeds the number of positive values supported by the type. + float next_value = std::numeric_limits::min(); + for (float& value : literal->data()) { + value = next_value; + next_value = std::nextafter(next_value, std::numeric_limits::max()); + } +} + +template ::value || + std::is_same::value, + int>::type = 0> +void PopulateWithNoDuplicateData(Literal* literal, std::minstd_rand0* engine) { + PopulateWithIntNext(literal); + std::shuffle(literal->data().begin(), literal->data().end(), + *engine); +} + +template ::value && + !std::is_same::value, + int>::type = 0> +void PopulateWithNoDuplicateData(Literal* literal, std::minstd_rand0* engine) { + PopulateWithNextAfter(literal); + std::shuffle(literal->data().begin(), literal->data().end(), + *engine); +} + +template +void PopulateWithFloatingPointData(Literal* literal, std::minstd_rand0* engine, + bool no_duplicates) { CHECK(engine != nullptr); CHECK_EQ(literal->shape().element_type(), primitive_util::NativeToPrimitiveType()); if (no_duplicates) { - // Duplicates may be generated if the number of elements in the literal - // exceeds the number of positive values supported by the type. - FloatT next_value = std::numeric_limits::min(); - for (FloatT& value : literal->data()) { - value = next_value; - next_value = - std::nextafter(next_value, std::numeric_limits::max()); - } - std::shuffle(literal->data().begin(), literal->data().end(), - *engine); + PopulateWithNoDuplicateData(literal, engine); } else { - std::uniform_real_distribution generator(-0.1f, 0.2f); - for (FloatT& value : literal->data()) { - value = static_cast(generator(*engine)); - } + PopulateWithRandomFloatingPointData(literal, engine); } } -template -void PopulateWithRandomFloatingPointData(Literal* literal, +template <> +void PopulateWithFloatingPointData(Literal* literal, std::minstd_rand0* engine, bool no_duplicates) { CHECK(engine != nullptr); - PopulateWithRandomFloatingPointDataImpl(literal, engine, - no_duplicates); -} - -template <> -void PopulateWithRandomFloatingPointData(Literal* literal, - std::minstd_rand0* engine, - bool no_duplicates) { - // no_duplicates is ignored for half types. Unique values can only be - // generated for arrays with fewer than ~2**16 elements and no_duplicates is - // best-effort anyway. - CHECK(engine != nullptr); - std::uniform_real_distribution generator(-0.1f, 0.2f); - for (half& value : literal->data()) { - value = static_cast(generator(*engine)); + CHECK_EQ(literal->shape().element_type(), + primitive_util::NativeToPrimitiveType()); + if (no_duplicates) { + PopulateWithNoDuplicateData(literal, engine); + } else { + PopulateWithRandomFloatingPointData(literal, engine); } } template <> -void PopulateWithRandomFloatingPointData(Literal* literal, - std::minstd_rand0* engine, - bool no_duplicates) { - // no_duplicates is ignored for bfloat types. Unique values can only be - // generated for arrays with fewer than ~2**16 elements and no_duplicates is - // best-effort anyway. +void PopulateWithFloatingPointData(Literal* literal, + std::minstd_rand0* engine, + bool no_duplicates) { CHECK(engine != nullptr); - std::uniform_real_distribution generator(-0.1f, 0.2f); - for (bfloat16& value : literal->data()) { - value = static_cast(generator(*engine)); + CHECK_EQ(literal->shape().element_type(), + primitive_util::NativeToPrimitiveType()); + if (no_duplicates) { + PopulateWithNoDuplicateData(literal, engine); + } else { + PopulateWithRandomFloatingPointData(literal, engine); } } @@ -135,20 +183,16 @@ StatusOr MakeFakeLiteralInternal(const Shape& shape, Literal literal(shape); switch (shape.element_type()) { case BF16: - PopulateWithRandomFloatingPointData(&literal, engine, - no_duplicates); + PopulateWithFloatingPointData(&literal, engine, no_duplicates); break; case F16: - PopulateWithRandomFloatingPointData(&literal, engine, - no_duplicates); + PopulateWithFloatingPointData(&literal, engine, no_duplicates); break; case F32: - PopulateWithRandomFloatingPointData(&literal, engine, - no_duplicates); + PopulateWithFloatingPointData(&literal, engine, no_duplicates); break; case F64: - PopulateWithRandomFloatingPointData(&literal, engine, - no_duplicates); + PopulateWithFloatingPointData(&literal, engine, no_duplicates); break; case S8: PopulateWithRandomIntegralData(&literal, engine, no_duplicates); diff --git a/tensorflow/compiler/xla/tests/test_utils_test.cc b/tensorflow/compiler/xla/tests/test_utils_test.cc index e066b3f4f2..e8f5d7a9a7 100644 --- a/tensorflow/compiler/xla/tests/test_utils_test.cc +++ b/tensorflow/compiler/xla/tests/test_utils_test.cc @@ -175,5 +175,28 @@ ENTRY %sort.148.1589 (parameter.0: s32[1048576], parameter.1: s32[1048576]) -> ( } } +XLA_TEST_F(TestUtilsTest, NoDuplicatesBfloat16) { + // Inputs which are sort keys in key/value sorts should have no duplicates. + auto module = ParseHloString(R"( +HloModule sort, is_scheduled=true + +ENTRY %sort. (parameter.0: bf16[2,1452], parameter.1: s32[2,1452]) -> (bf16[2,1452], s32[2,1452]) { + %parameter.0 = bf16[2,1452]{1,0} parameter(0) + %parameter.1 = s32[2,1452]{1,0} parameter(1) + ROOT %sort = (bf16[2,1452]{1,0}, s32[2,1452]{1,0}) sort(bf16[2,1452]{1,0} %parameter.0, s32[2,1452]{1,0} %parameter.1), dimensions={1} +} +)") + .ValueOrDie(); + TF_ASSERT_OK_AND_ASSIGN(std::vector args, + MakeFakeArguments(module.get())); + ASSERT_EQ(args.size(), 2); + const Literal& key_arg = args[0]; + + absl::flat_hash_set key_set; + for (const bfloat16& value : key_arg.data()) { + EXPECT_TRUE(key_set.insert(absl::bit_cast(value)).second); + } +} + } // namespace } // namespace xla -- GitLab From 6cef228475b10d655eabecfcdb365eaeb6383cf0 Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Tue, 27 Nov 2018 12:00:28 -0800 Subject: [PATCH 403/672] [XLA:CPU] Fix symbol resolution problem on Mac OS X. Mac OS X prefixes symbols with a leading underscore (e.g. "_expf") but the names used in the XLA call registry are unprefixed (e.g., "expf"). The SimpleOrcJit symbol resolver class seems to receive the prefixed version from LLVM. To work around the problem, in the event of a failed lookup retry lookups with the leading underscore stripped. PiperOrigin-RevId: 223032111 --- .../compiler/xla/service/cpu/simple_orc_jit.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc b/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc index f77641eb7d..efccadedf2 100644 --- a/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc +++ b/tensorflow/compiler/xla/service/cpu/simple_orc_jit.cc @@ -128,8 +128,18 @@ SimpleOrcJIT::SimpleOrcJIT(const llvm::TargetOptions& target_options, } llvm::JITSymbol SimpleOrcJIT::ResolveRuntimeSymbol(const std::string& name) { - void* func_addr = CustomCallTargetRegistry::Global()->Lookup(name); + void* func_addr = nullptr; + if (name.size() > 1 && name.front() == data_layout_.getGlobalPrefix()) { + // On Mac OS X, 'name' may have a leading underscore prefix, even though the + // registered name may not. + std::string stripped_name(name.begin() + 1, name.end()); + func_addr = CustomCallTargetRegistry::Global()->Lookup(stripped_name); + } else { + func_addr = CustomCallTargetRegistry::Global()->Lookup(name); + } + if (func_addr == nullptr) { + VLOG(2) << "Unable to resolve runtime symbol: " << name; return nullptr; } llvm::JITEvaluatedSymbol symbol_info(reinterpret_cast(func_addr), -- GitLab From e165762a36738570b224f4bd84e593093264cf56 Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Tue, 27 Nov 2018 12:15:23 -0800 Subject: [PATCH 404/672] Updated `thresholds` argument in confusion matrix metrics to accept scalar input and set the default value to be a scalar instead of a list. This way the metric result will be a scalar if input thresholds is a scalar and a list otherwise. PiperOrigin-RevId: 223035043 --- tensorflow/python/keras/metrics.py | 116 +++++++++++++----------- tensorflow/python/keras/metrics_test.py | 44 +++------ 2 files changed, 74 insertions(+), 86 deletions(-) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 60632e5a25..90babf38fd 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -48,6 +48,7 @@ from tensorflow.python.keras.losses import sparse_categorical_crossentropy from tensorflow.python.keras.losses import squared_hinge from tensorflow.python.keras.utils.generic_utils import deserialize_keras_object from tensorflow.python.keras.utils.generic_utils import serialize_keras_object +from tensorflow.python.keras.utils.generic_utils import to_list from tensorflow.python.keras.utils.losses_utils import squeeze_or_expand_dimensions from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops @@ -215,7 +216,8 @@ def _update_confusion_matrix_variables(variables_to_update, y_true: A `Tensor` whose shape matches `y_pred`. Will be cast to `bool`. y_pred: A floating point `Tensor` of arbitrary shape and whose values are in the range `[0, 1]`. - thresholds: A python list or tuple of float thresholds in `[0, 1]`. + thresholds: A float value or a python list or tuple of float thresholds in + `[0, 1]`. sample_weight: Optional `Tensor` whose rank is either 0, or the same rank as `y_true`, and must be broadcastable to `y_true` (i.e., all dimensions must be either `1`, or the same as the corresponding `y_true` dimension). @@ -264,6 +266,7 @@ def _update_confusion_matrix_variables(variables_to_update, math_ops.cast(y_pred, dtype=dtypes.float32), math_ops.cast(y_true, dtype=dtypes.bool), sample_weight) + thresholds = to_list(thresholds) num_thresholds = len(thresholds) num_predictions = array_ops.size(y_pred) @@ -868,21 +871,22 @@ class _ConfusionMatrixConditionCount(Metric): Args: confusion_matrix_cond: One of `_ConfusionMatrix` conditions. - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ super(_ConfusionMatrixConditionCount, self).__init__(name=name, dtype=dtype) self._confusion_matrix_cond = confusion_matrix_cond - self.thresholds = [0.5] if thresholds is None else thresholds - _assert_thresholds_range(self.thresholds) + self.thresholds = 0.5 if thresholds is None else thresholds + thresholds = to_list(thresholds) + _assert_thresholds_range(thresholds) self.accumulator = self.add_weight( 'accumulator', - shape=(len(self.thresholds),), + shape=(len(thresholds),), initializer=init_ops.zeros_initializer) def update_state(self, y_true, y_pred, sample_weight=None): @@ -903,7 +907,11 @@ class _ConfusionMatrixConditionCount(Metric): }, y_true, y_pred, self.thresholds, sample_weight) def result(self): - return ops.convert_to_tensor(self.accumulator) + if isinstance(self.thresholds, (list, tuple)): + result = self.accumulator + else: + result = self.accumulator[0] + return ops.convert_to_tensor(result) @tf_export('metrics.FalsePositives', 'keras.metrics.FalsePositives') @@ -941,11 +949,11 @@ class FalsePositives(_ConfusionMatrixConditionCount): """Creates a `FalsePositives` instance. Args: - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ @@ -991,11 +999,11 @@ class FalseNegatives(_ConfusionMatrixConditionCount): """Creates a `FalseNegatives` instance. Args: - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ @@ -1041,11 +1049,11 @@ class TrueNegatives(_ConfusionMatrixConditionCount): """Creates a `TrueNegatives` instance. Args: - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ @@ -1091,11 +1099,11 @@ class TruePositives(_ConfusionMatrixConditionCount): """Creates a `TruePositives` instance. Args: - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ @@ -1142,23 +1150,25 @@ class Precision(Metric): """Creates a `Precision` instance. Args: - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ super(Precision, self).__init__(name=name, dtype=dtype) - self.thresholds = [0.5] if thresholds is None else thresholds + self.thresholds = 0.5 if thresholds is None else thresholds + thresholds = to_list(thresholds) + _assert_thresholds_range(thresholds) self.tp = self.add_weight( 'true_positives', - shape=(len(self.thresholds),), + shape=(len(thresholds),), initializer=init_ops.zeros_initializer) self.fp = self.add_weight( 'false_positives', - shape=(len(self.thresholds),), + shape=(len(thresholds),), initializer=init_ops.zeros_initializer) def update_state(self, y_true, y_pred, sample_weight=None): @@ -1180,10 +1190,8 @@ class Precision(Metric): }, y_true, y_pred, self.thresholds, sample_weight) def result(self): - return array_ops.where( - math_ops.greater(self.tp + self.fp, 0), - math_ops.div(self.tp, self.tp + self.fp), - array_ops.zeros_like(self.thresholds)) + result = math_ops.div_no_nan(self.tp, self.tp + self.fp) + return result if isinstance(self.thresholds, (list, tuple)) else result[0] @tf_export('metrics.Recall', 'keras.metrics.Recall') @@ -1222,23 +1230,25 @@ class Recall(Metric): """Creates a `Recall` instance. Args: - thresholds: (Optional) Defaults to [0.5]. A python list/tuple of float - threshold values in [0, 1]. A threshold is compared with prediction - values to determine the truth value of predictions (i.e., above the - threshold is `true`, below is `false`). One metric value is generated - for each threshold value. + thresholds: (Optional) Defaults to 0.5. A float value or a python + list/tuple of float threshold values in [0, 1]. A threshold is compared + with prediction values to determine the truth value of predictions + (i.e., above the threshold is `true`, below is `false`). One metric + value is generated for each threshold value. name: (Optional) string name of the metric instance. dtype: (Optional) data type of the metric result. """ super(Recall, self).__init__(name=name, dtype=dtype) - self.thresholds = [0.5] if thresholds is None else thresholds + self.thresholds = 0.5 if thresholds is None else thresholds + thresholds = to_list(thresholds) + _assert_thresholds_range(thresholds) self.tp = self.add_weight( 'true_positives', - shape=(len(self.thresholds),), + shape=(len(thresholds),), initializer=init_ops.zeros_initializer) self.fn = self.add_weight( 'false_negatives', - shape=(len(self.thresholds),), + shape=(len(thresholds),), initializer=init_ops.zeros_initializer) def update_state(self, y_true, y_pred, sample_weight=None): @@ -1260,10 +1270,8 @@ class Recall(Metric): }, y_true, y_pred, self.thresholds, sample_weight) def result(self): - return array_ops.where( - math_ops.greater(self.tp + self.fn, 0), - math_ops.div(self.tp, self.tp + self.fn), - array_ops.zeros_like(self.thresholds)) + result = math_ops.div_no_nan(self.tp, self.tp + self.fn) + return result if isinstance(self.thresholds, (list, tuple)) else result[0] @six.add_metaclass(abc.ABCMeta) diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index f049b10721..eda434391e 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -548,7 +548,7 @@ class FalsePositivesTest(test.TestCase): update_op = fp_obj.update_state(y_true, y_pred) self.evaluate(update_op) result = fp_obj.result() - self.assertAllClose([7.], result) + self.assertAllClose(7., result) def test_weighted(self): fp_obj = metrics.FalsePositives() @@ -559,7 +559,7 @@ class FalsePositivesTest(test.TestCase): (0, 1, 0, 1, 0), (1, 1, 1, 1, 1))) sample_weight = constant_op.constant((1., 1.5, 2., 2.5)) result = fp_obj(y_true, y_pred, sample_weight=sample_weight) - self.assertAllClose([14.], self.evaluate(result)) + self.assertAllClose(14., self.evaluate(result)) def test_unweighted_with_thresholds(self): fp_obj = metrics.FalsePositives(thresholds=[0.15, 0.5, 0.85]) @@ -617,7 +617,7 @@ class FalseNegativesTest(test.TestCase): update_op = fn_obj.update_state(y_true, y_pred) self.evaluate(update_op) result = fn_obj.result() - self.assertAllClose([3.], result) + self.assertAllClose(3., result) def test_weighted(self): fn_obj = metrics.FalseNegatives() @@ -628,7 +628,7 @@ class FalseNegativesTest(test.TestCase): (0, 1, 0, 1, 0), (1, 1, 1, 1, 1))) sample_weight = constant_op.constant((1., 1.5, 2., 2.5)) result = fn_obj(y_true, y_pred, sample_weight=sample_weight) - self.assertAllClose([5.], self.evaluate(result)) + self.assertAllClose(5., self.evaluate(result)) def test_unweighted_with_thresholds(self): fn_obj = metrics.FalseNegatives(thresholds=[0.15, 0.5, 0.85]) @@ -679,7 +679,7 @@ class TrueNegativesTest(test.TestCase): update_op = tn_obj.update_state(y_true, y_pred) self.evaluate(update_op) result = tn_obj.result() - self.assertAllClose([3.], result) + self.assertAllClose(3., result) def test_weighted(self): tn_obj = metrics.TrueNegatives() @@ -690,7 +690,7 @@ class TrueNegativesTest(test.TestCase): (0, 1, 0, 1, 0), (1, 1, 1, 1, 1))) sample_weight = constant_op.constant((1., 1.5, 2., 2.5)) result = tn_obj(y_true, y_pred, sample_weight=sample_weight) - self.assertAllClose([4.], self.evaluate(result)) + self.assertAllClose(4., self.evaluate(result)) def test_unweighted_with_thresholds(self): tn_obj = metrics.TrueNegatives(thresholds=[0.15, 0.5, 0.85]) @@ -741,7 +741,7 @@ class TruePositivesTest(test.TestCase): update_op = tp_obj.update_state(y_true, y_pred) self.evaluate(update_op) result = tp_obj.result() - self.assertAllClose([7.], result) + self.assertAllClose(7., result) def test_weighted(self): tp_obj = metrics.TruePositives() @@ -752,7 +752,7 @@ class TruePositivesTest(test.TestCase): (0, 1, 0, 1, 0), (1, 1, 1, 1, 1))) sample_weight = constant_op.constant((1., 1.5, 2., 2.5)) result = tp_obj(y_true, y_pred, sample_weight=sample_weight) - self.assertAllClose([12.], self.evaluate(result)) + self.assertAllClose(12., self.evaluate(result)) def test_unweighted_with_thresholds(self): tp_obj = metrics.TruePositives(thresholds=[0.15, 0.5, 0.85]) @@ -857,7 +857,7 @@ class PrecisionTest(test.TestCase): self.assertArrayNear([0.5, 0.], self.evaluate(result), 0) def test_weighted_with_threshold(self): - p_obj = metrics.Precision(thresholds=[0.5, 1.1]) + p_obj = metrics.Precision(thresholds=[0.5, 1.]) y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) y_pred = constant_op.constant([[1, 0], [0.6, 0]], shape=(2, 2), @@ -872,18 +872,8 @@ class PrecisionTest(test.TestCase): expected_precision = weighted_tp / weighted_positives self.assertArrayNear([expected_precision, 0], self.evaluate(result), 1e-3) - def test_extreme_thresholds(self): - p_obj = metrics.Precision(thresholds=[-1.0, 2.0]) # beyond values range - y_pred = math_ops.cast( - constant_op.constant([1, 0, 1, 0], shape=(1, 4)), dtype=dtypes.float32) - y_true = math_ops.cast( - constant_op.constant([0, 1, 1, 1], shape=(1, 4)), dtype=dtypes.float32) - self.evaluate(variables.variables_initializer(p_obj.variables)) - result = p_obj(y_true, y_pred) - self.assertArrayNear([0.75, 0.], self.evaluate(result), 0) - def test_multiple_updates(self): - p_obj = metrics.Precision(thresholds=[0.5, 1.1]) + p_obj = metrics.Precision(thresholds=[0.5, 1.]) y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) y_pred = constant_op.constant([[1, 0], [0.6, 0]], shape=(2, 2), @@ -978,7 +968,7 @@ class RecallTest(test.TestCase): self.assertArrayNear([0.5, 0.], self.evaluate(result), 0) def test_weighted_with_threshold(self): - r_obj = metrics.Recall(thresholds=[0.5, 1.1]) + r_obj = metrics.Recall(thresholds=[0.5, 1.]) y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) y_pred = constant_op.constant([[1, 0], [0.6, 0]], shape=(2, 2), @@ -993,18 +983,8 @@ class RecallTest(test.TestCase): expected_recall = weighted_tp / weighted_positives self.assertArrayNear([expected_recall, 0], self.evaluate(result), 1e-3) - def test_extreme_thresholds(self): - r_obj = metrics.Recall(thresholds=[-1.0, 2.0]) # beyond values range - y_pred = math_ops.cast( - constant_op.constant([1, 0, 1, 0], shape=(1, 4)), dtype=dtypes.float32) - y_true = math_ops.cast( - constant_op.constant([0, 1, 1, 1], shape=(1, 4)), dtype=dtypes.float32) - self.evaluate(variables.variables_initializer(r_obj.variables)) - result = r_obj(y_true, y_pred) - self.assertArrayNear([1.0, 0.], self.evaluate(result), 0) - def test_multiple_updates(self): - r_obj = metrics.Recall(thresholds=[0.5, 1.1]) + r_obj = metrics.Recall(thresholds=[0.5, 1.]) y_true = constant_op.constant([[0, 1], [1, 0]], shape=(2, 2)) y_pred = constant_op.constant([[1, 0], [0.6, 0]], shape=(2, 2), -- GitLab From c1e50881f3f687fe8ffb7a9cb6d2d905bb70ec71 Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Tue, 27 Nov 2018 12:19:07 -0800 Subject: [PATCH 405/672] [XLA] Avoid undefined behavior in absl::bit_cast with Eigen::half. [XLA] [TF] Fix more compile warnings in Mac OS OSS build. PiperOrigin-RevId: 223035708 --- tensorflow/compiler/xla/literal.cc | 28 +++++++++++++++++-- tensorflow/compiler/xla/protobuf_util.cc | 10 ------- .../common_runtime/accumulate_n_optimizer.cc | 5 ++-- .../core/common_runtime/ring_reducer.cc | 2 +- tensorflow/core/graph/graph.h | 2 +- .../core/kernels/eigen_spatial_convolutions.h | 12 ++++---- .../stream_executor/device_description.cc | 12 +------- 7 files changed, 37 insertions(+), 34 deletions(-) diff --git a/tensorflow/compiler/xla/literal.cc b/tensorflow/compiler/xla/literal.cc index 36ad7c6486..f2fcb93717 100644 --- a/tensorflow/compiler/xla/literal.cc +++ b/tensorflow/compiler/xla/literal.cc @@ -63,6 +63,14 @@ void ConvertEndianShort(char* bytes, int64 size) { } } +// Since Eigen::half doesn't satisfy the absl::bit_cast contract, we need to be +// able to transparently access the raw 16-bit value contained within. +template +T GetRawValue(T val) { + return val; +} +uint16 GetRawValue(Eigen::half val) { return val.x; } + } // namespace LiteralBase::~LiteralBase() {} @@ -1206,16 +1214,32 @@ Literal ConvertBetweenNativeTypes(const LiteralBase& src_literal) { } template -typename std::enable_if<(sizeof(NativeSrcT) == sizeof(NativeDestT)), +typename std::enable_if<(sizeof(NativeSrcT) == sizeof(NativeDestT) && + !std::is_same::value), Literal>::type BitcastBetweenNativeTypes(const LiteralBase& src_literal) { auto converter = [](NativeSrcT src) { - return absl::bit_cast(src); + return absl::bit_cast(GetRawValue(src)); }; return ConvertBetweenNativeTypesWithConverter( src_literal, converter); } +template +typename std::enable_if<(sizeof(NativeSrcT) == sizeof(Eigen::half) && + std::is_same::value), + Literal>::type +BitcastBetweenNativeTypes(const LiteralBase& src_literal) { + // Eigen::half doesn't satisfy the absl::bit_cast contract, so explicitly + // cast to unsigned short and then use raw_uint16_to_half. + auto converter = [](NativeSrcT src) { + return Eigen::half_impl::raw_uint16_to_half( + absl::bit_cast(GetRawValue(src))); + }; + return ConvertBetweenNativeTypesWithConverter( + src_literal, converter); +} + // This template specialization is here to make the compiler happy. bit_cast has // a static check that the types are the same size. This specialization should // never be used because the source and destination types are checked for diff --git a/tensorflow/compiler/xla/protobuf_util.cc b/tensorflow/compiler/xla/protobuf_util.cc index b507a2ef79..ac342bf40f 100644 --- a/tensorflow/compiler/xla/protobuf_util.cc +++ b/tensorflow/compiler/xla/protobuf_util.cc @@ -40,16 +40,6 @@ bool ProtobufEquals(const tensorflow::protobuf::Message& m1, namespace { -string SanitizeFilename(const string& file_name) { - string safe_file_name = file_name; - for (char& c : safe_file_name) { - if (c == '/' || c == '\\') { - c = '_'; - } - } - return safe_file_name; -} - std::pair>*> GetDirectoryExpanders() { static auto* mutex = new tensorflow::mutex; diff --git a/tensorflow/core/common_runtime/accumulate_n_optimizer.cc b/tensorflow/core/common_runtime/accumulate_n_optimizer.cc index 822d0065b6..c4bc1a684c 100644 --- a/tensorflow/core/common_runtime/accumulate_n_optimizer.cc +++ b/tensorflow/core/common_runtime/accumulate_n_optimizer.cc @@ -74,8 +74,7 @@ class AccumulateNV2RemovePass : public GraphOptimizationPass { Status rewriteNode(Node* n, Graph* g) { AttrSlice n_attrs = n->attrs(); - auto base_make_node = [n, g, &n_attrs](const string& op, - const string& name) { + auto base_make_node = [n, &n_attrs](const string& op, const string& name) { NodeBuilder node_builder(name, op); // The pieces of AccumulateNV2 should all be on the same node. @@ -86,7 +85,7 @@ class AccumulateNV2RemovePass : public GraphOptimizationPass { } return node_builder; }; - auto make_node = [n, g, &n_attrs, &base_make_node](string op) { + auto make_node = [n, g, &base_make_node](string op) { return base_make_node( op, g->NewName(strings::StrCat(n->name(), "/Internal"))); }; diff --git a/tensorflow/core/common_runtime/ring_reducer.cc b/tensorflow/core/common_runtime/ring_reducer.cc index b1fe928ba7..092f15e49e 100644 --- a/tensorflow/core/common_runtime/ring_reducer.cc +++ b/tensorflow/core/common_runtime/ring_reducer.cc @@ -290,7 +290,7 @@ void RingReducer::Run(StatusCallback done) { col_ctx_->device, col_ctx_->op_ctx->input_alloc_attr(0), col_ctx_->op_ctx->output_alloc_attr(0), col_ctx_->input, col_ctx_->output, 0 /*dev_to_dev_stream_index*/, - [this, ¬e, &status](const Status& s) { + [¬e, &status](const Status& s) { status.Update(s); note.Notify(); }); diff --git a/tensorflow/core/graph/graph.h b/tensorflow/core/graph/graph.h index 6c6d98b5aa..af0b123706 100644 --- a/tensorflow/core/graph/graph.h +++ b/tensorflow/core/graph/graph.h @@ -65,7 +65,7 @@ class WhileContext; class NeighborIter; // Declared below class NodeIter; // Declared below -class NodeProperties; // Defined in .cc +struct NodeProperties; // Defined in .cc class Node { public: diff --git a/tensorflow/core/kernels/eigen_spatial_convolutions.h b/tensorflow/core/kernels/eigen_spatial_convolutions.h index e8dea4763e..25c735d080 100644 --- a/tensorflow/core/kernels/eigen_spatial_convolutions.h +++ b/tensorflow/core/kernels/eigen_spatial_convolutions.h @@ -552,17 +552,17 @@ class TensorContractionSubMapper< EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorContractionSubMapper( const ParentMapper& base_mapper, Index vert_offset, Index horiz_offset) - : m_base_mapper(base_mapper), - m_depth_offset(vert_offset), - m_col_offset(horiz_offset) { + : m_depth_offset(vert_offset), + m_col_offset(horiz_offset), + m_base_mapper(base_mapper) { m_base_mapper.computeBaseIndices(m_col_offset, m_rowIndex, m_colIndex, m_otherIndex); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorContractionSubMapper( const Self& base_mapper, Index vert_offset, Index horiz_offset) - : m_base_mapper(base_mapper.m_base_mapper), - m_depth_offset(vert_offset + base_mapper.m_depth_offset), - m_col_offset(horiz_offset + base_mapper.m_col_offset) { + : m_depth_offset(vert_offset + base_mapper.m_depth_offset), + m_col_offset(horiz_offset + base_mapper.m_col_offset), + m_base_mapper(base_mapper.m_base_mapper) { m_base_mapper.computeBaseIndices(m_col_offset, m_rowIndex, m_colIndex, m_otherIndex); } diff --git a/tensorflow/stream_executor/device_description.cc b/tensorflow/stream_executor/device_description.cc index 4120e230db..0b991b7ba8 100644 --- a/tensorflow/stream_executor/device_description.cc +++ b/tensorflow/stream_executor/device_description.cc @@ -140,21 +140,11 @@ void CalculateDimensionality(const DeviceDescription &device_description, uint64 element_count, uint64 *threads_per_block, uint64 *block_count) { *threads_per_block = device_description.threads_per_block_limit(); - *block_count = DivideCeil(element_count, *threads_per_block); + *block_count = port::MathUtil::CeilOfRatio(element_count, *threads_per_block); if (*block_count == 1) { CHECK_LE(element_count, *threads_per_block); *threads_per_block = element_count; } } -// Round value up to a multiple of n. -static uint64 RoundUp(uint64 value, uint64 n) { - return port::MathUtil::CeilOfRatio(value, n) * n; -} - -// Round value down to a multiple of n. -static uint64 RoundDown(uint64 value, uint64 n) { - return port::MathUtil::FloorOfRatio(value, n) * n; -} - } // namespace stream_executor -- GitLab From 0b6ed4887ab1a65d2a0500ec8ebb03e221d8681b Mon Sep 17 00:00:00 2001 From: Igor Ganichev Date: Tue, 27 Nov 2018 12:27:16 -0800 Subject: [PATCH 406/672] Add EagerTensor.backing_device property For reasons of compatibility with graph execution, EagerTensor.device returns the device of that ran the operation that produced this tensor. This is not always the device that holds the tensor's memory. The latter is useful information for troubleshooting now. It will be even more so once we have native multi-device functions. PiperOrigin-RevId: 223036943 --- tensorflow/c/eager/BUILD | 1 + tensorflow/c/eager/c_api.cc | 12 +++++ tensorflow/c/eager/c_api.h | 23 +++++++++ tensorflow/c/eager/c_api_test.cc | 65 ++++++++++++++++++++++++ tensorflow/c/eager/c_api_test_util.cc | 13 +++++ tensorflow/c/eager/c_api_test_util.h | 3 ++ tensorflow/python/eager/pywrap_tensor.cc | 18 +++++++ tensorflow/python/framework/ops.py | 12 +++++ tensorflow/python/framework/ops_test.py | 7 +++ 9 files changed, 154 insertions(+) diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD index 5a0988ed31..c34a84fcfe 100644 --- a/tensorflow/c/eager/BUILD +++ b/tensorflow/c/eager/BUILD @@ -144,6 +144,7 @@ tf_cuda_cc_test( "//tensorflow/core:test", "//tensorflow/core:test_main", "//tensorflow/core/distributed_runtime/rpc:grpc_server_lib", + "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc index c9e730ef41..027d752f42 100755 --- a/tensorflow/c/eager/c_api.cc +++ b/tensorflow/c/eager/c_api.cc @@ -411,6 +411,18 @@ const char* TFE_TensorHandleDeviceName(TFE_TensorHandle* h, TF_Status* status) { : d->name().c_str(); } +const char* TFE_TensorHandleBackingDeviceName(TFE_TensorHandle* h, + TF_Status* status) { + if (h == nullptr || h->handle == nullptr) { + status->status = tensorflow::errors::InvalidArgument( + "The passed in handle is a nullptr"); + return nullptr; + } + tensorflow::Device* d = h->handle->device(); + return (d == nullptr) ? "/job:localhost/replica:0/task:0/device:CPU:0" + : d->name().c_str(); +} + TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_TensorHandleCopySharingTensor( TFE_TensorHandle* h, TF_Status* status) { if (h == nullptr || h->handle == nullptr) { diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h index b2454d8722..8d6c8d958d 100755 --- a/tensorflow/c/eager/c_api.h +++ b/tensorflow/c/eager/c_api.h @@ -169,10 +169,33 @@ TF_CAPI_EXPORT extern int64_t TFE_TensorHandleNumElements(TFE_TensorHandle* h, TF_CAPI_EXPORT extern int64_t TFE_TensorHandleDim(TFE_TensorHandle* h, int dim_index, TF_Status* status); + +// Returns the device of the operation that produced `h`. +// If `h` was produced by a copy, returns the destination device of +// the copy. Note that returned device name is not always the device +// holding the tensor handle's memory. If you want the latter, use +// TFE_TensorHandleBackingDeviceName. +// This function will block till the operation that produces `h` has completed. +// +// Device on which the kernel of the operation that produced `h` ran. +// +// If `h` was produced by a copy, returns the destination device of +// the copy. +// +// Note that returned device name is not always the device that owns the memory +// that backs the tensor handle. For the latter see +// TFE_TensorHandleBackingDeviceName. +// // This function will block till the operation that produces `h` has completed. TF_CAPI_EXPORT extern const char* TFE_TensorHandleDeviceName( TFE_TensorHandle* h, TF_Status* status); +// Returns the name of the device in whose memory `h` resides. +// +// This function will block till the operation that produces `h` has completed. +TF_CAPI_EXPORT extern const char* TFE_TensorHandleBackingDeviceName( + TFE_TensorHandle* h, TF_Status* status); + // Return a pointer to a new TFE_TensorHandle that shares the underlying tensor // with `h`. On success, `status` is set to OK. On failure, `status` reflects // the error and a nullptr is returned. diff --git a/tensorflow/c/eager/c_api_test.cc b/tensorflow/c/eager/c_api_test.cc index 0045bb5622..6b39b79ee8 100644 --- a/tensorflow/c/eager/c_api_test.cc +++ b/tensorflow/c/eager/c_api_test.cc @@ -16,6 +16,7 @@ limitations under the License. #include "tensorflow/c/eager/c_api.h" #include +#include "absl/strings/match.h" #include "tensorflow/c/eager/c_api_test_util.h" #include "tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h" #include "tensorflow/core/framework/function.pb.h" @@ -794,6 +795,14 @@ TEST(CAPI, TensorHandleNullptr) { TF_SetStatus(status.get(), TF_OK, ""); + device_name = TFE_TensorHandleBackingDeviceName(h, status.get()); + ASSERT_EQ(TF_INVALID_ARGUMENT, TF_GetCode(status.get())); + ASSERT_EQ(device_name, nullptr); + ASSERT_EQ("The passed in handle is a nullptr", + string(TF_Message(status.get()))); + + TF_SetStatus(status.get(), TF_OK, ""); + int num_dims = TFE_TensorHandleNumDims(h, status.get()); ASSERT_EQ(TF_INVALID_ARGUMENT, TF_GetCode(status.get())); ASSERT_EQ(num_dims, -1); @@ -809,6 +818,62 @@ TEST(CAPI, TensorHandleNullptr) { string(TF_Message(status.get()))); } +TEST(CAPI, TensorHandleDevices) { + std::unique_ptr status( + TF_NewStatus(), TF_DeleteStatus); + TFE_ContextOptions* opts = TFE_NewContextOptions(); + TFE_Context* ctx = TFE_NewContext(opts, status.get()); + TFE_DeleteContextOptions(opts); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + + TFE_TensorHandle* hcpu = TestMatrixTensorHandle(); + const char* device_name = TFE_TensorHandleDeviceName(hcpu, status.get()); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + ASSERT_TRUE(absl::StrContains(device_name, "CPU:0")) << device_name; + const char* backing_device_name = + TFE_TensorHandleBackingDeviceName(hcpu, status.get()); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + ASSERT_TRUE(absl::StrContains(backing_device_name, "CPU:0")) + << backing_device_name; + + // Disable the test if no GPU is present. + string gpu_device_name; + if (GetDeviceName(ctx, &gpu_device_name, "GPU")) { + TFE_TensorHandle* hgpu = TFE_TensorHandleCopyToDevice( + hcpu, ctx, gpu_device_name.c_str(), status.get()); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + + TFE_Op* shape_op = ShapeOp(ctx, hgpu); + TFE_OpSetDevice(shape_op, gpu_device_name.c_str(), status.get()); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + TFE_TensorHandle* retvals[1]; + int num_retvals = 1; + TFE_Execute(shape_op, &retvals[0], &num_retvals, status.get()); + ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get()); + + // .device of shape is GPU since the op is executed on GPU + device_name = TFE_TensorHandleDeviceName(retvals[0], status.get()); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + ASSERT_TRUE(absl::StrContains(device_name, "GPU:0")) << device_name; + + // .backing_device of shape is CPU since the tensor is backed by CPU + backing_device_name = + TFE_TensorHandleBackingDeviceName(retvals[0], status.get()); + ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + ASSERT_TRUE(absl::StrContains(backing_device_name, "CPU:0")) + << backing_device_name; + + TFE_DeleteOp(shape_op); + TFE_DeleteTensorHandle(retvals[0]); + TFE_DeleteTensorHandle(hgpu); + } + + TFE_DeleteTensorHandle(hcpu); + TFE_ContextAsyncWait(ctx, status.get()); + EXPECT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get()); + TFE_DeleteContext(ctx); +} + void Execute_MatMul_CPU(bool async) { TF_Status* status = TF_NewStatus(); TFE_ContextOptions* opts = TFE_NewContextOptions(); diff --git a/tensorflow/c/eager/c_api_test_util.cc b/tensorflow/c/eager/c_api_test_util.cc index 008f088c2d..bd38127d50 100644 --- a/tensorflow/c/eager/c_api_test_util.cc +++ b/tensorflow/c/eager/c_api_test_util.cc @@ -104,6 +104,19 @@ TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b) { return op; } +TFE_Op* ShapeOp(TFE_Context* ctx, TFE_TensorHandle* a) { + TF_Status* status = TF_NewStatus(); + + TFE_Op* op = TFE_NewOp(ctx, "Shape", status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_OpAddInput(op, a, status); + CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TF_DeleteStatus(status); + TFE_OpSetAttrType(op, "T", TFE_TensorHandleDataType(a)); + + return op; +} + TFE_TensorHandle* TestAxisTensorHandle() { int64_t dims[] = {1}; int data[] = {1}; diff --git a/tensorflow/c/eager/c_api_test_util.h b/tensorflow/c/eager/c_api_test_util.h index 474cae67c8..75ef9459e9 100644 --- a/tensorflow/c/eager/c_api_test_util.h +++ b/tensorflow/c/eager/c_api_test_util.h @@ -37,6 +37,9 @@ TFE_TensorHandle* TestMatrixTensorHandle3X2(); // Return a matmul op multiplying `a` by `b`. TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b); +// Return a shape op fetching the shape of `a`. +TFE_Op* ShapeOp(TFE_Context* ctx, TFE_TensorHandle* a); + // Return an 1-D INT32 tensor containing a single value 1. TFE_TensorHandle* TestAxisTensorHandle(); diff --git a/tensorflow/python/eager/pywrap_tensor.cc b/tensorflow/python/eager/pywrap_tensor.cc index ed19047f09..0d0f70d543 100644 --- a/tensorflow/python/eager/pywrap_tensor.cc +++ b/tensorflow/python/eager/pywrap_tensor.cc @@ -672,11 +672,29 @@ static PyObject* EagerTensor_device(EagerTensor* self) { #endif } +// Getter `backing_device`. +static PyObject* EagerTensor_backing_device(EagerTensor* self) { + const char* device = + TFE_TensorHandleBackingDeviceName(self->handle, self->status); + if (MaybeRaiseExceptionFromTFStatus(self->status, PyExc_ValueError)) { + // Cleanup self->status before returning. + TF_SetStatus(self->status, TF_OK, ""); + return nullptr; + } +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromString(device); +#else + return PyBytes_FromString(device); +#endif +} + static PyGetSetDef EagerTensor_getseters[] = { {const_cast("_id"), (getter)EagerTensor_getid, nullptr, const_cast("_id"), nullptr}, {const_cast("device"), (getter)EagerTensor_device, nullptr, const_cast("device"), nullptr}, + {const_cast("backing_device"), (getter)EagerTensor_backing_device, + nullptr, const_cast("backing_device"), nullptr}, {const_cast("_handle_data"), (getter)EagerTensor_tensor_handle, (setter)EagerTensor_settensor_handle, const_cast("_tensor_handle"), nullptr}, diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index ec00778347..31fa111b3f 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -748,6 +748,18 @@ class _EagerTensorBase(Tensor): def _numpy(self): raise NotImplementedError() + @property + def backing_device(self): + """Returns the name of the device holding this tensor's memory. + + `.backing_device` is usually the same as `.device`, which returns + the device on which the kernel of the operation that produced this tensor + ran. However, some operations can produce tensors on a different device + (e.g., an operation that executes on the GPU but produces output tensors + in host memory). + """ + raise NotImplementedError() + def __copy__(self): # Eager Tensors are immutable so it's safe to return themselves as a copy. return self diff --git a/tensorflow/python/framework/ops_test.py b/tensorflow/python/framework/ops_test.py index 32a24521ad..9c9ef799f7 100644 --- a/tensorflow/python/framework/ops_test.py +++ b/tensorflow/python/framework/ops_test.py @@ -1075,6 +1075,13 @@ class DeviceTest(test_util.TensorFlowTestCase): node { name: "FloatOutput" op: "FloatOutput" } """, gd) + def testEagerBackingDevice(self): + with context.eager_mode(): + with ops.device("/device:CPU:0"): + t = constant_op.constant(1.0) + self.assertRegexpMatches(t.device, "/device:CPU:0") + self.assertRegexpMatches(t.backing_device, "/device:CPU:0") + def testDevicePartialString(self): g = ops.Graph() with g.device("/job:worker/replica:2"): -- GitLab From 55fed8c55147aa5e2c35b3b1f3bac34224bac916 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 12:39:19 -0800 Subject: [PATCH 407/672] Automated rollback of commit f56925c38e4fe67fba3e4da7ee8bbb72b1e69d38 PiperOrigin-RevId: 223038945 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 0725bd0e8a..d9d40874a4 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -134,11 +134,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "eigen_archive", build_file = clean_dep("//third_party:eigen.BUILD"), - sha256 = "fc0f871496cdaec892245afc9890e8267f73b0fcec5a7f75be0dc914e2972023", - strip_prefix = "eigen-eigen-efda481cbd7a", + sha256 = "8fa7ba1af23f0320be05f4658061138d6eb8dd1f320669cbf305b3a034f9d1c2", + strip_prefix = "eigen-eigen-ea671884cc96", urls = [ - "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/efda481cbd7a.tar.gz", - "https://bitbucket.org/eigen/eigen/get/efda481cbd7a.tar.gz", + "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/ea671884cc96.tar.gz", + "https://bitbucket.org/eigen/eigen/get/ea671884cc96.tar.gz", ], ) -- GitLab From 6fb83aa0e3a194dcbcf8054cdd576a8d4f1d484b Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Tue, 27 Nov 2018 12:47:30 -0800 Subject: [PATCH 408/672] Minor update to tflite_convert documentation. PiperOrigin-RevId: 223040385 --- tensorflow/lite/g3doc/devguide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/lite/g3doc/devguide.md b/tensorflow/lite/g3doc/devguide.md index d42729c7ea..fdd02638f9 100644 --- a/tensorflow/lite/g3doc/devguide.md +++ b/tensorflow/lite/g3doc/devguide.md @@ -77,8 +77,8 @@ formats: SavedModels using [Python](convert/python_api.md#basic_savedmodel) or using the [command line](convert/cmdline_examples.md#savedmodel). * `tf.keras` - A HDF5 file containing a model with weights and input and - output arguments generated by `tf.Keras`. See [here] for converting HDF5 - models. See the documentation for converting HDF5 models using + output arguments generated by `tf.Keras`. See the documentation for + converting HDF5 models using [Python](convert/python_api.md#basic_keras_file) or using the [command line](convert/cmdline_examples.md#keras). * `frozen tf.GraphDef` — A subclass of `tf.GraphDef` that does not contain -- GitLab From 6efff588f689ee0e3a05784ca6bf249092a7a380 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 12:56:54 -0800 Subject: [PATCH 409/672] Switch callers to the new location of distribute_lib. PiperOrigin-RevId: 223042010 --- tensorflow/contrib/optimizer_v2/BUILD | 2 +- tensorflow/contrib/optimizer_v2/optimizer_v2.py | 2 +- tensorflow/python/keras/BUILD | 2 +- tensorflow/python/keras/engine/distributed_training_utils.py | 2 +- tensorflow/python/keras/engine/training_distributed.py | 2 +- tensorflow/python/training/optimizer.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tensorflow/contrib/optimizer_v2/BUILD b/tensorflow/contrib/optimizer_v2/BUILD index 835fb4aec4..6e40140630 100644 --- a/tensorflow/contrib/optimizer_v2/BUILD +++ b/tensorflow/contrib/optimizer_v2/BUILD @@ -48,7 +48,6 @@ py_library( srcs_version = "PY2AND3", deps = [ "//tensorflow/python:control_flow_ops", - "//tensorflow/python:distribute", "//tensorflow/python:framework", "//tensorflow/python:math_ops", "//tensorflow/python:resource_variable_ops", @@ -56,6 +55,7 @@ py_library( "//tensorflow/python:training", "//tensorflow/python:variable_scope", "//tensorflow/python:variables", + "//tensorflow/python/distribute:distribute_lib", "//tensorflow/python/distribute:reduce_util", ], ) diff --git a/tensorflow/contrib/optimizer_v2/optimizer_v2.py b/tensorflow/contrib/optimizer_v2/optimizer_v2.py index 747f5b9b8b..73a556f0b2 100644 --- a/tensorflow/contrib/optimizer_v2/optimizer_v2.py +++ b/tensorflow/contrib/optimizer_v2/optimizer_v2.py @@ -24,6 +24,7 @@ import abc import six +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import reduce_util as ds_reduce_util from tensorflow.python.eager import backprop from tensorflow.python.eager import context @@ -35,7 +36,6 @@ from tensorflow.python.ops import math_ops from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.training import distribution_strategy_context as distribute_ctx from tensorflow.python.training import optimizer as optimizer_v1 from tensorflow.python.training import slot_creator diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD index a7f01817fb..69e18ea55f 100755 --- a/tensorflow/python/keras/BUILD +++ b/tensorflow/python/keras/BUILD @@ -185,7 +185,6 @@ py_library( ":engine", "//tensorflow/python:array_ops", "//tensorflow/python:cudnn_rnn_ops_gen", - "//tensorflow/python:distribute", "//tensorflow/python:dtypes", "//tensorflow/python:embedding_ops", "//tensorflow/python:framework_ops", @@ -199,6 +198,7 @@ py_library( "//tensorflow/python:tensor_array_ops", "//tensorflow/python:tensor_shape", "//tensorflow/python:util", + "//tensorflow/python/distribute:distribute_lib", ], ) diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index bb8174e26a..8b0076163e 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -23,6 +23,7 @@ from tensorflow.python.client import session as session_module from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import iterator_ops from tensorflow.python.distribute import distribute_coordinator_context as dc_context +from tensorflow.python.distribute import distribute_lib from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util @@ -32,7 +33,6 @@ from tensorflow.python.keras.optimizer_v2 import optimizer_v2 from tensorflow.python.ops import array_ops from tensorflow.python.ops import variables from tensorflow.python.platform import tf_logging as logging -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.util import nest diff --git a/tensorflow/python/keras/engine/training_distributed.py b/tensorflow/python/keras/engine/training_distributed.py index 53261fdd26..d16832318c 100644 --- a/tensorflow/python/keras/engine/training_distributed.py +++ b/tensorflow/python/keras/engine/training_distributed.py @@ -36,7 +36,7 @@ from tensorflow.python.keras.utils.generic_utils import Progbar from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging -from tensorflow.python.training import distribute as distribute_lib +from tensorflow.python.distribute import distribute_lib from tensorflow.python.util import nest diff --git a/tensorflow/python/training/optimizer.py b/tensorflow/python/training/optimizer.py index 8cd5311b31..2556e6274a 100644 --- a/tensorflow/python/training/optimizer.py +++ b/tensorflow/python/training/optimizer.py @@ -24,6 +24,7 @@ import abc import six +from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import reduce_util as ds_reduce_util from tensorflow.python.eager import backprop from tensorflow.python.eager import context @@ -37,7 +38,6 @@ from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables -from tensorflow.python.training import distribute as distribute_lib from tensorflow.python.training import distribution_strategy_context as distribute_ctx from tensorflow.python.training import slot_creator from tensorflow.python.training.checkpointable import base as checkpointable -- GitLab From f1e25462e9c96e7f4dda213afc91751f65342711 Mon Sep 17 00:00:00 2001 From: Michael Case Date: Tue, 27 Nov 2018 13:29:47 -0800 Subject: [PATCH 410/672] Add build configs for TF integration builder. This builder will check out TF from Piper and Estimator from GitHub. It will then build Estimator pip from a pinned revision, and install the pip package. It will then run TF tests that depend on Estimator code. PiperOrigin-RevId: 223047585 --- tensorflow/contrib/distribute/python/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tensorflow/contrib/distribute/python/BUILD b/tensorflow/contrib/distribute/python/BUILD index b068ef029f..38ce0b2b8e 100644 --- a/tensorflow/contrib/distribute/python/BUILD +++ b/tensorflow/contrib/distribute/python/BUILD @@ -416,6 +416,7 @@ cuda_py_test( "multi_and_single_gpu", "no_oss", # http://b/119349471 "no_pip", + "tf_integration_test", ], ) @@ -429,6 +430,7 @@ cuda_py_test( "multi_and_single_gpu", "no_oss", # http://b/119349471 "no_pip", + "tf_integration_test", ], ) -- GitLab From 891e56199d35d067efb50303e6714253df6d1c83 Mon Sep 17 00:00:00 2001 From: Katherine Wu Date: Tue, 27 Nov 2018 13:31:04 -0800 Subject: [PATCH 411/672] Add warning for the renamed tf.estimator.Estimator.export_savedmodel function. PiperOrigin-RevId: 223047837 --- tensorflow/tools/compatibility/ast_edits.py | 28 +++++++++++++++++++ .../tools/compatibility/ast_edits_test.py | 24 ++++++++++++++++ .../tools/compatibility/tf_upgrade_v2.py | 16 +++++++++++ .../tools/compatibility/tf_upgrade_v2_test.py | 7 +++++ 4 files changed, 75 insertions(+) diff --git a/tensorflow/tools/compatibility/ast_edits.py b/tensorflow/tools/compatibility/ast_edits.py index 5edb4d4759..90bfab3507 100644 --- a/tensorflow/tools/compatibility/ast_edits.py +++ b/tensorflow/tools/compatibility/ast_edits.py @@ -40,6 +40,10 @@ class APIChangeSpec(object): * `function_reorders`: maps functions whose argument order has changed to the list of arguments in the new order * `function_handle`: maps function names to custom handlers for the function + * `function_warnings`: maps full names of functions to warnings that will be + printed out if the function is used. (e.g. tf.nn.convolution()) + * `unrestricted_function_warnings`: maps names of functions to warnings that + will be printed out when the function is used (e.g. foo.convolution()). For an example, see `TFAPIChangeSpec`. """ @@ -195,6 +199,29 @@ class _ASTCallVisitor(ast.NodeVisitor): except KeyError: pass + def _print_warning_for_function_unrestricted(self, node): + """Print a warning when specific functions are called. + + The function _print_warning_for_function matches the full name of the called + function, e.g., tf.foo.bar(). This function matches the function name that + is called, as long as the function is an attribute. For example, + `tf.foo.bar()` and `foo.bar()` are matched, but not `bar()`. + + Args: + node: ast.Call object + """ + function_warnings = getattr( + self._api_change_spec, "unrestricted_function_warnings", {}) + if isinstance(node.func, ast.Attribute): + function_name = node.func.attr + try: + warning_message = function_warnings[function_name] + self._file_edit.add(warning_message, + node.lineno, node.col_offset, "", "", + error="%s requires manual check." % function_name) + except KeyError: + pass + def _get_attribute_full_path(self, node): """Traverse an attribute to generate a full name e.g. tf.foo.bar. @@ -276,6 +303,7 @@ class _ASTCallVisitor(ast.NodeVisitor): Args: node: Current Node """ + self._print_warning_for_function_unrestricted(node) # Find a simple attribute name path e.g. "tf.foo.bar" full_name, name = self._get_attribute_full_path(node.func) diff --git a/tensorflow/tools/compatibility/ast_edits_test.py b/tensorflow/tools/compatibility/ast_edits_test.py index 08f4ae3fcc..99f20a026f 100644 --- a/tensorflow/tools/compatibility/ast_edits_test.py +++ b/tensorflow/tools/compatibility/ast_edits_test.py @@ -52,6 +52,10 @@ class NoUpdateSpec(ast_edits.APIChangeSpec): self.function_handle = {} self.function_reorders = {} self.function_keyword_renames = {} + self.symbol_renames = {} + self.function_warnings = {} + self.unrestricted_function_warnings = {} + self.change_to_function = {} class RenameKeywordSpec(NoUpdateSpec): @@ -391,6 +395,26 @@ class TestAstEdits(test_util.TensorFlowTestCase): _, new_text = self._upgrade(RemoveMultipleKeywordArguments(), text) self.assertIn(new_text, acceptable_outputs) + def testUnrestrictedFunctionWarnings(self): + class FooWarningSpec(NoUpdateSpec): + """Usages of function attribute foo() prints out a warning.""" + + def __init__(self): + NoUpdateSpec.__init__(self) + self.unrestricted_function_warnings = {"foo": "not good"} + texts = ["object.foo()", "get_object().foo()", + "get_object().foo()", "object.foo().bar()"] + for text in texts: + (_, report, _), _ = self._upgrade(FooWarningSpec(), text) + self.assertIn("not good", report) + + # Note that foo() won't result in a warning, because in this case foo is + # not an attribute, but a name. + false_alarms = ["foo", "foo()", "foo.bar()", "obj.run_foo()", "obj.foo"] + for text in false_alarms: + (_, report, _), _ = self._upgrade(FooWarningSpec(), text) + self.assertNotIn("not good", report) + if __name__ == "__main__": test_lib.main() diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 7433e0ecbf..f9cc20c9cd 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -677,6 +677,22 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): if name not in self.function_warnings and name not in excluded_renames } + export_saved_model_renamed = ( + "(Manual edit required) Please rename the function export_savedmodel() " + "to export_saved_model(). Two things to note:\n\t(1) The argument " + "strip_default_attributes has been removed. The function will always " + "strip the default attributes from ops. If this breaks your code, " + "please switch to tf.compat.v1.estimator.Estimator.\n\t(2) This change " + "only effects core estimator. If you are using " + "tf.contrib.learn.Estimator, please switch to using core estimator.") + + # Specify warnings for functions that aren't restricted to the tf.x.y.z + # format. This should only be used for methods with unique names, e.g. + # export_savedmodel, which is only defined in Estimator objects. + self.unrestricted_function_warnings = { + "export_savedmodel": export_saved_model_renamed, + } + @staticmethod def _dropout_handler(file_edit_recorder, node): if len(node.args) < 2: diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index bda748f274..553010d4fc 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -212,6 +212,13 @@ class TestUpgrade(test_util.TensorFlowTestCase): ["test.py:1: Optimizer.compute_gradients " "requires manual check."]) + def testExportSavedModelRename(self): + text = "self.est.export_savedmodel(path)" + _, report, unused_errors, unused_new_text = self._upgrade(text) + self.assertIn( + "rename the function export_savedmodel() to export_saved_model()", + report) + class TestUpgradeFiles(test_util.TensorFlowTestCase): -- GitLab From 654efdeacca7b84bd4245cffe95ae27eb1bd1c75 Mon Sep 17 00:00:00 2001 From: Yanan Cao Date: Tue, 27 Nov 2018 13:40:54 -0800 Subject: [PATCH 412/672] Add gradient function for XlaClusterOutput PiperOrigin-RevId: 223049594 --- tensorflow/compiler/jit/BUILD | 5 +++- .../jit/encapsulate_xla_computations_pass.cc | 7 +++-- tensorflow/compiler/jit/ops/BUILD | 6 ++++ tensorflow/compiler/jit/ops/xla_ops_grad.py | 29 +++++++++++++++++++ tensorflow/compiler/tf2xla/BUILD | 1 + tensorflow/contrib/compiler/BUILD | 1 + tensorflow/contrib/compiler/xla.py | 1 + 7 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 tensorflow/compiler/jit/ops/xla_ops_grad.py diff --git a/tensorflow/compiler/jit/BUILD b/tensorflow/compiler/jit/BUILD index 1f6dadf1ac..a3c7dd22de 100644 --- a/tensorflow/compiler/jit/BUILD +++ b/tensorflow/compiler/jit/BUILD @@ -736,7 +736,10 @@ tf_custom_op_py_library( visibility = [ ":friends", ], - deps = ["//tensorflow/compiler/jit/ops:xla_ops_wrapper_py"], + deps = [ + "//tensorflow/compiler/jit/ops:xla_ops_grad", + "//tensorflow/compiler/jit/ops:xla_ops_wrapper_py", + ], ) # This target can be used by XLA device plugins to prevent circular dependencies, and provides access to all of the required headers for building a device library. diff --git a/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc b/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc index 2ce6fa73fc..d334100aa4 100644 --- a/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc +++ b/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc @@ -195,8 +195,11 @@ Status RewriteSubgraph(const std::vector& arg_source_tensors, e->dst()->attrs().Find(kXlaClusterAttr) == nullptr && e->dst()->type_string() != kXlaClusterOutput) { return errors::InvalidArgument( - "Undeclared output of XLA computation. A common cause of this error " - "is variable initializers that depend on the XLA computation. Edge: ", + "Undeclared output of XLA computation. Some common causes of this " + "error are: 1) variable initializers that depend on the XLA " + "computation; 2) gradient computations that depend on the XLA " + "computation, which can be mitigated by moving gradient computations " + "inside XLA computation. Offending edge: ", e->src()->name(), ":", e->src_output(), " -> ", e->dst()->name(), ":", e->dst_input()); } diff --git a/tensorflow/compiler/jit/ops/BUILD b/tensorflow/compiler/jit/ops/BUILD index f72224545b..64409d9334 100644 --- a/tensorflow/compiler/jit/ops/BUILD +++ b/tensorflow/compiler/jit/ops/BUILD @@ -18,3 +18,9 @@ tf_gen_op_wrapper_py( out = "xla_ops.py", deps = ["//tensorflow/compiler/jit/ops:xla_ops"], ) + +py_library( + name = "xla_ops_grad", + srcs = ["xla_ops_grad.py"], + deps = ["//tensorflow/python:framework_ops"], +) diff --git a/tensorflow/compiler/jit/ops/xla_ops_grad.py b/tensorflow/compiler/jit/ops/xla_ops_grad.py new file mode 100644 index 0000000000..2d31d8dc71 --- /dev/null +++ b/tensorflow/compiler/jit/ops/xla_ops_grad.py @@ -0,0 +1,29 @@ +"""Gradients for XLA ops.""" +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops + + +@ops.RegisterGradient("XlaClusterOutput") +def _XlaClusterOutputGrad(_, grad): + del grad # unused + raise RuntimeError("Gradient computation of graph in xla.compile() is " + "prohibited because it can cause performance degradation." + "Please move gradient computation inside xla.compile().") diff --git a/tensorflow/compiler/tf2xla/BUILD b/tensorflow/compiler/tf2xla/BUILD index 3458c7f1c4..25a84fb1b6 100644 --- a/tensorflow/compiler/tf2xla/BUILD +++ b/tensorflow/compiler/tf2xla/BUILD @@ -9,6 +9,7 @@ package_group( "//tensorflow/compiler/jit/...", "//tensorflow/compiler/tests/...", "//tensorflow/compiler/tf2xla/...", + "//tensorflow/contrib/compiler/...", ], ) diff --git a/tensorflow/contrib/compiler/BUILD b/tensorflow/contrib/compiler/BUILD index 1630f010ab..e4566437c6 100644 --- a/tensorflow/contrib/compiler/BUILD +++ b/tensorflow/contrib/compiler/BUILD @@ -58,6 +58,7 @@ py_library( srcs_version = "PY2AND3", deps = [ "//tensorflow/compiler/jit:xla_ops_py", + "//tensorflow/compiler/jit/ops:xla_ops_grad", "//tensorflow/python:array_ops", "//tensorflow/python:control_flow_ops", "//tensorflow/python:framework_ops", diff --git a/tensorflow/contrib/compiler/xla.py b/tensorflow/contrib/compiler/xla.py index 335ac79464..f867cd15b6 100644 --- a/tensorflow/contrib/compiler/xla.py +++ b/tensorflow/contrib/compiler/xla.py @@ -23,6 +23,7 @@ import contextlib from six.moves import xrange # pylint: disable=redefined-builtin from tensorflow.compiler.jit.ops import xla_ops +from tensorflow.compiler.jit.ops import xla_ops_grad # pylint: disable=unused-import from tensorflow.core.framework import attr_value_pb2 from tensorflow.python.estimator import model_fn as model_fn_lib from tensorflow.python.framework import ops -- GitLab From 3409380f7ca5adc4d381e581a8838fd8aa6d8572 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Tue, 27 Nov 2018 14:27:52 -0800 Subject: [PATCH 413/672] Fix unnecessarily opaque test. PiperOrigin-RevId: 223058199 --- tensorflow/python/ops/variable_scope.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index cf33c61b82..87ef046100 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -907,7 +907,7 @@ class _VariableStore(object): variable_dtype = None else: # Instantiate initializer if provided initializer is a type object. - if isinstance(initializer, type(init_ops.Initializer)): + if tf_inspect.isclass(initializer): initializer = initializer(dtype=dtype) spec = tf_inspect.getargspec(initializer) if shape is not None and shape.is_fully_defined(): -- GitLab From a69210ede18ca9401e72916a3d0f96e6aead80c4 Mon Sep 17 00:00:00 2001 From: Mingxing Tan Date: Tue, 27 Nov 2018 14:41:24 -0800 Subject: [PATCH 414/672] Internal changes. PiperOrigin-RevId: 223060752 --- tensorflow/python/keras/layers/normalization.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/keras/layers/normalization.py b/tensorflow/python/keras/layers/normalization.py index aa8598d731..2b360d2114 100644 --- a/tensorflow/python/keras/layers/normalization.py +++ b/tensorflow/python/keras/layers/normalization.py @@ -491,6 +491,9 @@ class BatchNormalization(Layer): return (r, d, new_mean, new_variance) + def _moments(self, inputs, reduction_axes, keep_dims): + return nn.moments(inputs, reduction_axes, keep_dims=keep_dims) + def call(self, inputs, training=None): if training is None: training = K.learning_phase() @@ -562,7 +565,8 @@ class BatchNormalization(Layer): # Some of the computations here are not necessary when training==False # but not a constant. However, this makes the code simpler. keep_dims = self.virtual_batch_size is not None or len(self.axis) > 1 - mean, variance = nn.moments(inputs, reduction_axes, keep_dims=keep_dims) + mean, variance = self._moments( + inputs, reduction_axes, keep_dims=keep_dims) moving_mean = self.moving_mean moving_variance = self.moving_variance -- GitLab From 891bf2d9fa5773c9588d363faa5efd63f2134a75 Mon Sep 17 00:00:00 2001 From: Anna R Date: Tue, 27 Nov 2018 14:47:43 -0800 Subject: [PATCH 415/672] Add a few tests for upgrade script, fix tf.argmin/tf.argmax to rename dimension to axis. PiperOrigin-RevId: 223061849 --- tensorflow/tools/compatibility/BUILD | 10 +++++ .../compatibility/testdata/test_file_v1_10.py | 41 ++++++++++++++++++- .../tools/compatibility/tf_upgrade_v2.py | 10 ++++- .../tools/compatibility/tf_upgrade_v2_test.py | 22 ++++++++++ 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/tensorflow/tools/compatibility/BUILD b/tensorflow/tools/compatibility/BUILD index f46e36bf32..a6574dac53 100644 --- a/tensorflow/tools/compatibility/BUILD +++ b/tensorflow/tools/compatibility/BUILD @@ -124,6 +124,16 @@ genrule( tools = [":tf_upgrade_v2"], ) +py_test( + name = "test_file_v1_10", + size = "small", + srcs = ["testdata/test_file_v1_10.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow:tensorflow_py", + ], +) + py_test( name = "test_file_v2_0", size = "small", diff --git a/tensorflow/tools/compatibility/testdata/test_file_v1_10.py b/tensorflow/tools/compatibility/testdata/test_file_v1_10.py index e5ca8d3e2e..fd688781b0 100644 --- a/tensorflow/tools/compatibility/testdata/test_file_v1_10.py +++ b/tensorflow/tools/compatibility/testdata/test_file_v1_10.py @@ -25,10 +25,47 @@ from tensorflow.python.platform import test as test_lib class TestUpgrade(test_util.TensorFlowTestCase): """Test various APIs that have been changed in 2.0.""" + def setUp(self): + tf.enable_eager_execution() + def testRenames(self): with self.cached_session(): - self.assertAllClose(1.04719755, tf.acos(0.5).eval()) - self.assertAllClose(0.5, tf.rsqrt(4.0).eval()) + self.assertAllClose(1.04719755, tf.acos(0.5)) + self.assertAllClose(0.5, tf.rsqrt(4.0)) + + def testSerializeSparseTensor(self): + sp_input = tf.SparseTensor( + indices=tf.constant([[1]], dtype=tf.int64), + values=tf.constant([2], dtype=tf.int64), + dense_shape=[2]) + + with self.cached_session(): + serialized_sp = tf.serialize_sparse(sp_input, 'serialize_name', tf.string) + self.assertEqual((3,), serialized_sp.shape) + self.assertTrue(serialized_sp[0].numpy()) # check non-empty + + def testSerializeManySparse(self): + sp_input = tf.SparseTensor( + indices=tf.constant([[0, 1]], dtype=tf.int64), + values=tf.constant([2], dtype=tf.int64), + dense_shape=[1, 2]) + + with self.cached_session(): + serialized_sp = tf.serialize_many_sparse( + sp_input, 'serialize_name', tf.string) + self.assertEqual((1, 3), serialized_sp.shape) + + def testArgMaxMin(self): + self.assertAllClose( + [1], + tf.argmax([[1, 3, 2]], name='abc', dimension=1)) + self.assertAllClose( + [0, 0, 0], + tf.argmax([[1, 3, 2]], dimension=0)) + self.assertAllClose( + [0], + tf.argmin([[1, 3, 2]], name='abc', dimension=1)) + if __name__ == "__main__": test_lib.main() diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index f9cc20c9cd..059d2ef4de 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -31,6 +31,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): # Maps from a function name to a dictionary that describes how to # map from an old argument keyword to the new argument keyword. self.function_keyword_renames = { + "tf.argmin": { + "dimension": "axis", + }, + "tf.argmax": { + "dimension": "axis", + }, "tf.image.crop_and_resize": { "box_ind": "box_indices", }, @@ -408,8 +414,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): self.function_reorders = { "tf.io.serialize_sparse": ["sp_input", "name", "out_type"], "tf.io.serialize_many_sparse": ["sp_input", "name", "out_type"], - "tf.argmax": ["input", "axis", "name", "dimension", "output_type"], - "tf.argmin": ["input", "axis", "name", "dimension", "output_type"], + "tf.argmax": ["input", "axis", "name", "axis", "output_type"], + "tf.argmin": ["input", "axis", "name", "axis", "output_type"], "tf.batch_to_space": ["input", "crops", "block_size", "name"], "tf.boolean_mask": ["tensor", "mask", "name", "axis"], "tf.convert_to_tensor": ["value", "dtype", "name", "preferred_dtype"], diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index 553010d4fc..0414becc70 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -219,6 +219,28 @@ class TestUpgrade(test_util.TensorFlowTestCase): "rename the function export_savedmodel() to export_saved_model()", report) + def testArgmin(self): + text = "tf.argmin(input, name=n, dimension=1, output_type=type)" + expected_text = "tf.argmin(input=input, name=n, axis=1, output_type=type)" + _, unused_report, unused_errors, new_text = self._upgrade(text) + self.assertEqual(new_text, expected_text) + + text = "tf.argmin(input, 0)" + expected_text = "tf.argmin(input=input, axis=0)" + _, unused_report, unused_errors, new_text = self._upgrade(text) + self.assertEqual(new_text, expected_text) + + def testArgmax(self): + text = "tf.argmax(input, name=n, dimension=1, output_type=type)" + expected_text = "tf.argmax(input=input, name=n, axis=1, output_type=type)" + _, unused_report, unused_errors, new_text = self._upgrade(text) + self.assertEqual(new_text, expected_text) + + text = "tf.argmax(input, 0)" + expected_text = "tf.argmax(input=input, axis=0)" + _, unused_report, unused_errors, new_text = self._upgrade(text) + self.assertEqual(new_text, expected_text) + class TestUpgradeFiles(test_util.TensorFlowTestCase): -- GitLab From f670244e49b6c644bb27d448b116ae1f2cf8164c Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 14:58:29 -0800 Subject: [PATCH 416/672] Make Stream prefer host callbacks with return status PiperOrigin-RevId: 223063676 --- .../xla/service/interpreter/executor.cc | 11 ++++++++--- .../xla/service/interpreter/executor.h | 3 ++- .../stream_executor/cuda/cuda_gpu_executor.cc | 9 +++++++-- .../stream_executor/cuda/cuda_gpu_executor.h | 3 ++- .../stream_executor/host/host_gpu_executor.cc | 9 +++++++-- .../stream_executor/host/host_gpu_executor.h | 3 ++- tensorflow/stream_executor/stream.h | 16 +++++++++++----- .../stream_executor_internal.cc | 19 +++++++++---------- .../stream_executor_internal.h | 4 ++-- 9 files changed, 50 insertions(+), 27 deletions(-) diff --git a/tensorflow/compiler/xla/service/interpreter/executor.cc b/tensorflow/compiler/xla/service/interpreter/executor.cc index 4fb67bd0b7..e3e5fa7154 100644 --- a/tensorflow/compiler/xla/service/interpreter/executor.cc +++ b/tensorflow/compiler/xla/service/interpreter/executor.cc @@ -78,9 +78,14 @@ port::Status XlaInterpreterExecutor::SynchronousMemcpy( return port::Status::OK(); } -bool XlaInterpreterExecutor::HostCallback(Stream *stream, - std::function callback) { - AsExecutorStream(stream)->EnqueueTask(callback); +bool XlaInterpreterExecutor::HostCallback( + Stream *stream, std::function callback) { + AsExecutorStream(stream)->EnqueueTask([callback]() { + port::Status s = callback(); + if (!s.ok()) { + LOG(WARNING) << "Host callback failed: " << s; + } + }); return true; } diff --git a/tensorflow/compiler/xla/service/interpreter/executor.h b/tensorflow/compiler/xla/service/interpreter/executor.h index fbb9945784..400c305154 100644 --- a/tensorflow/compiler/xla/service/interpreter/executor.h +++ b/tensorflow/compiler/xla/service/interpreter/executor.h @@ -125,7 +125,8 @@ class XlaInterpreterExecutor : public internal::StreamExecutorInterface { return port::Status{port::error::UNIMPLEMENTED, ""}; } - bool HostCallback(Stream *stream, std::function callback) override; + bool HostCallback(Stream *stream, + std::function callback) override; port::Status AllocateEvent(Event *event) override { return port::Status{port::error::UNIMPLEMENTED, ""}; diff --git a/tensorflow/stream_executor/cuda/cuda_gpu_executor.cc b/tensorflow/stream_executor/cuda/cuda_gpu_executor.cc index ad9154226c..4874d096ad 100644 --- a/tensorflow/stream_executor/cuda/cuda_gpu_executor.cc +++ b/tensorflow/stream_executor/cuda/cuda_gpu_executor.cc @@ -662,8 +662,13 @@ bool CUDAExecutor::MemcpyDeviceToDevice(Stream *stream, } bool CUDAExecutor::HostCallback(Stream *stream, - std::function callback) { - auto callback_ptr = new std::function(callback); + std::function callback) { + auto callback_ptr = new std::function([callback]() { + port::Status s = callback(); + if (!s.ok()) { + LOG(WARNING) << "Host callback failed: " << s; + } + }); return CUDADriver::AddStreamCallback(context_, AsCUDAStreamValue(stream), InternalHostCallback, callback_ptr); } diff --git a/tensorflow/stream_executor/cuda/cuda_gpu_executor.h b/tensorflow/stream_executor/cuda/cuda_gpu_executor.h index 90bf1c0242..ae8e4abf92 100644 --- a/tensorflow/stream_executor/cuda/cuda_gpu_executor.h +++ b/tensorflow/stream_executor/cuda/cuda_gpu_executor.h @@ -148,7 +148,8 @@ class CUDAExecutor : public internal::StreamExecutorInterface { const DeviceMemoryBase &gpu_src, uint64 size) override; - bool HostCallback(Stream *stream, std::function callback) override; + bool HostCallback(Stream *stream, + std::function callback) override; bool AllocateStream(Stream *stream) override; diff --git a/tensorflow/stream_executor/host/host_gpu_executor.cc b/tensorflow/stream_executor/host/host_gpu_executor.cc index 8adf739b17..1396a83dfb 100644 --- a/tensorflow/stream_executor/host/host_gpu_executor.cc +++ b/tensorflow/stream_executor/host/host_gpu_executor.cc @@ -148,8 +148,13 @@ port::Status HostExecutor::SynchronousMemcpyDeviceToDevice( } bool HostExecutor::HostCallback(Stream *stream, - std::function callback) { - AsHostStream(stream)->EnqueueTask(callback); + std::function callback) { + AsHostStream(stream)->EnqueueTask([callback]() { + port::Status s = callback(); + if (!s.ok()) { + LOG(WARNING) << "Host callback failed: " << s; + } + }); return true; } diff --git a/tensorflow/stream_executor/host/host_gpu_executor.h b/tensorflow/stream_executor/host/host_gpu_executor.h index 7ba1f18101..56e3c2aa6a 100644 --- a/tensorflow/stream_executor/host/host_gpu_executor.h +++ b/tensorflow/stream_executor/host/host_gpu_executor.h @@ -103,7 +103,8 @@ class HostExecutor : public internal::StreamExecutorInterface { const DeviceMemoryBase &gpu_src, uint64 size) override; - bool HostCallback(Stream *stream, std::function callback) override; + bool HostCallback(Stream *stream, + std::function callback) override; port::Status AllocateEvent(Event *event) override { return port::Status(port::error::UNIMPLEMENTED, ""); diff --git a/tensorflow/stream_executor/stream.h b/tensorflow/stream_executor/stream.h index e1629b5b30..0fc90cf83d 100644 --- a/tensorflow/stream_executor/stream.h +++ b/tensorflow/stream_executor/stream.h @@ -2033,9 +2033,20 @@ class Stream { // transferred to the caller. internal::StreamInterface *implementation() { return implementation_.get(); } + // Entrains onto the stream a callback to the host (from the device). + // Behaves as ThenDoHostCallbackWithStatus below, but the callback should + // never fail or its failure is inconsequential. + // + // This is kept for backward compatibility. Future code should use + // ThenDoHostCallbackWithStatus and explicitly return a success status. + // TODO(b/112125301): Eventually remove this method. + Stream &ThenDoHostCallback(std::function callback); + // Entrains onto the stream a callback to the host (from the device). // Host callbacks block/occupy the stream just as device functions // (execute one at a time, block later stream operations). + // Whether the callback return status affects the result of BlockHostUntilDone + // is platform-dependent. // // Behavior is undefined when synchronizing using OpenCL user events. // Behavior is undefined if host callbacks call device routines or insert @@ -2043,11 +2054,6 @@ class Stream { // // On certain platforms, ThenDoHostCallback is expected to have significant // negative effects on performance. - Stream &ThenDoHostCallback(std::function callback); - - // Entrains onto the stream a callback to the host (from the device). - // Behaves as ThenDoHostCallback above, but returns a Status instead of void. - // This overload should be preferred if the callback could fail. Stream &ThenDoHostCallbackWithStatus(std::function callback); // Returns the StreamExecutor (parent object) associated with this stream. diff --git a/tensorflow/stream_executor/stream_executor_internal.cc b/tensorflow/stream_executor/stream_executor_internal.cc index 7df6a361c6..341c6edccd 100644 --- a/tensorflow/stream_executor/stream_executor_internal.cc +++ b/tensorflow/stream_executor/stream_executor_internal.cc @@ -36,16 +36,15 @@ StreamExecutorFactory* MakeOpenCLExecutorImplementation() { StreamExecutorFactory MakeHostExecutorImplementation; -// TODO(b/112125301): Consolodate this down to one implementation of -// HostCallback, taking a callback that returns a Status. -bool StreamExecutorInterface::HostCallback( - Stream* stream, std::function callback) { - return HostCallback(stream, [callback]() { - port::Status s = callback(); - if (!s.ok()) { - LOG(WARNING) << "HostCallback failed: " << s; - } - }); +// The default implementation just calls the other HostCallback method. +// It should make all existing code that uses a void() callback still work. +bool StreamExecutorInterface::HostCallback(Stream* stream, + std::function callback) { + return HostCallback( + stream, std::function([callback]() -> port::Status { + callback(); + return port::Status::OK(); + })); } } // namespace internal diff --git a/tensorflow/stream_executor/stream_executor_internal.h b/tensorflow/stream_executor/stream_executor_internal.h index 32f75fd1bc..0c2c33cfca 100644 --- a/tensorflow/stream_executor/stream_executor_internal.h +++ b/tensorflow/stream_executor/stream_executor_internal.h @@ -237,9 +237,9 @@ class StreamExecutorInterface { virtual bool MemcpyDeviceToDevice(Stream *stream, DeviceMemoryBase *gpu_dst, const DeviceMemoryBase &gpu_src, uint64 size) = 0; - virtual bool HostCallback(Stream *stream, std::function callback) = 0; + virtual bool HostCallback(Stream *stream, std::function callback); virtual bool HostCallback(Stream *stream, - std::function callback); + std::function callback) = 0; virtual port::Status AllocateEvent(Event *event) = 0; virtual port::Status DeallocateEvent(Event *event) = 0; virtual port::Status RecordEvent(Stream *stream, Event *event) = 0; -- GitLab From 71ec2bbdb2f762692c44159057c8a0c63dbbb5f0 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 27 Nov 2018 15:08:17 -0800 Subject: [PATCH 417/672] [TF:XLA] Unbreak test build after DeviceMgr API change PiperOrigin-RevId: 223065543 --- tensorflow/compiler/tests/randomized_tests.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/tests/randomized_tests.cc b/tensorflow/compiler/tests/randomized_tests.cc index a6b5802012..d23fd12516 100644 --- a/tensorflow/compiler/tests/randomized_tests.cc +++ b/tensorflow/compiler/tests/randomized_tests.cc @@ -3382,10 +3382,10 @@ int main(int argc, char** argv) { } // XLA devices register kernels at construction time; create all known devices // to make sure the kernels are registered. - std::vector devices; + std::vector> devices; TF_CHECK_OK(tensorflow::DeviceFactory::AddDevices( tensorflow::SessionOptions(), "", &devices)); - tensorflow::DeviceMgr device_mgr(devices); + tensorflow::DeviceMgr device_mgr(std::move(devices)); tensorflow::Device* ignored; TF_QCHECK_OK( -- GitLab From d9c76a8e85af52ae39ad36345827c34676068df1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 15:27:25 -0800 Subject: [PATCH 418/672] Emit layout info in error message otherwise it's pretty hard to debug. PiperOrigin-RevId: 223068849 --- tensorflow/compiler/xla/service/hlo_verifier.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_verifier.cc b/tensorflow/compiler/xla/service/hlo_verifier.cc index 017549ce1b..77db7b098a 100644 --- a/tensorflow/compiler/xla/service/hlo_verifier.cc +++ b/tensorflow/compiler/xla/service/hlo_verifier.cc @@ -1379,9 +1379,8 @@ class InstructionVerifier : public DfsHloVisitorWithDefault { const Layout& operand_layout = operand_shape.layout(); TF_RET_CHECK(LayoutUtil::Equal(result_layout, operand_layout)) << "Instruction shouldn't change layouts " - << instruction->ToString() << " From " - << ShapeUtil::HumanString(result_shape) << " To " - << ShapeUtil::HumanString(operand_shape); + << instruction->ToString() << " From " << result_shape << " To " + << operand_shape; } } } -- GitLab From b326178f3d478fab34c247b7f072204284085f85 Mon Sep 17 00:00:00 2001 From: Reed Wanderman-Milne Date: Tue, 27 Nov 2018 15:31:44 -0800 Subject: [PATCH 419/672] Slightly change behavior of fused parameter to tf.keras.layers.BatchNormalization in 2.0. The original behavior is that if True or None is passed to the fused parameter, the layer sets self.fused to True if fused is supported, and False otherwise. No distinction is made between passing fused=True and fused=None to the constructor. The new behavior is that if True is passed to the fused parameter and fused is not supported, an error is thrown. If None is passed, self.fused is set to True if it is supported, and False otherwise. We do most the checks in the constructor, but we must wait until build() to do the final check, as we do not have the input size information in the constructor. PiperOrigin-RevId: 223069621 --- .../python/keras/layers/normalization.py | 117 +++++++++++++++--- .../python/keras/layers/normalization_test.py | 113 ++++++++++++++--- ...ow.keras.layers.-batch-normalization.pbtxt | 3 +- ...nsorflow.layers.-batch-normalization.pbtxt | 3 +- ...ow.keras.layers.-batch-normalization.pbtxt | 2 +- 5 files changed, 196 insertions(+), 42 deletions(-) diff --git a/tensorflow/python/keras/layers/normalization.py b/tensorflow/python/keras/layers/normalization.py index 2b360d2114..d958497655 100644 --- a/tensorflow/python/keras/layers/normalization.py +++ b/tensorflow/python/keras/layers/normalization.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python import tf2 from tensorflow.python.eager import context from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -40,8 +41,8 @@ from tensorflow.python.training import distribution_strategy_context from tensorflow.python.util.tf_export import tf_export -@tf_export('keras.layers.BatchNormalization') -class BatchNormalization(Layer): +@tf_export('keras.layers.BatchNormalization', v1=[]) +class BatchNormalizationV2(Layer): """Batch normalization layer (Ioffe and Szegedy, 2014). Normalize the activations of the previous layer at each batch, @@ -84,8 +85,10 @@ class BatchNormalization(Layer): and should be neither too small (which would add noise) nor too large (which would give stale estimates). Note that `momentum` is still applied to get the means and variances for inference. - fused: if `None` or `True`, use a faster, fused implementation if possible. - If `False`, use the system recommended implementation. + fused: if `True`, use a faster, fused implementation, or raise a ValueError + if the fused implementation cannot be used. If `None`, use the faster + implementation if possible. If False, do not used the fused + implementation. trainable: Boolean, if `True` also add variables to the graph collection `GraphKeys.TRAINABLE_VARIABLES` (see tf.Variable). virtual_batch_size: An `int`. By default, `virtual_batch_size` is `None`, @@ -120,6 +123,9 @@ class BatchNormalization(Layer): Internal Covariate Shift](https://arxiv.org/abs/1502.03167) """ + # The BatchNormalizationV1 subclass sets this to False to use the V1 behavior. + _USE_V2_BEHAVIOR = True + def __init__(self, axis=-1, momentum=0.99, @@ -143,12 +149,15 @@ class BatchNormalization(Layer): adjustment=None, name=None, **kwargs): - super(BatchNormalization, self).__init__( + super(BatchNormalizationV2, self).__init__( name=name, trainable=trainable, **kwargs) if isinstance(axis, list): self.axis = axis[:] - else: + elif isinstance(axis, int): self.axis = axis + else: + raise TypeError('axis must be int or list, type given: %s' + % type(self.axis)) self.momentum = momentum self.epsilon = epsilon self.center = center @@ -165,7 +174,14 @@ class BatchNormalization(Layer): self.renorm = renorm self.virtual_batch_size = virtual_batch_size self.adjustment = adjustment - if fused is None: + if self._USE_V2_BEHAVIOR: + if fused: + self._raise_if_fused_cannot_be_used() + # We leave fused as None if self._fused_can_be_used()==True, since we + # still may set it to False in self.build() if the input rank is not 4. + elif fused is None and not self._fused_can_be_used(): + fused = False + elif fused is None: fused = True self.supports_masking = True @@ -181,6 +197,38 @@ class BatchNormalization(Layer): self.renorm_clipping = renorm_clipping self.renorm_momentum = renorm_momentum + def _raise_if_fused_cannot_be_used(self): + """Raises a ValueError if fused implementation cannot be used. + + In addition to the checks done in this function, the input tensors rank must + be 4. The input rank check can only be done once the input shape is known. + """ + # Currently fused batch norm doesn't support renorm. It also only supports a + # channel dimension on axis 1 or 3, when no virtual batch size or adjustment + # is used. + if self.renorm: + raise ValueError('Passing both fused=True and renorm=True is ' + 'unsupported') + axis = [self.axis] if isinstance(self.axis, int) else self.axis + # Axis -3 is equivalent to 1, and axis -1 is equivalent to 3, because the + # input rank is required to be 4 (which is checked later). + if len(axis) > 1 or axis[0] not in (-3, -1, 1, 3): + raise ValueError('Passing fused=True is only supported when axis is 1 ' + 'or 3') + if self.virtual_batch_size is not None: + raise ValueError('Passing fused=True is unsupported when ' + 'virtual_batch_size is specified.') + if self.adjustment is not None: + raise ValueError('Passing fused=True is unsupported when ' + 'adjustment is specified.') + + def _fused_can_be_used(self): + try: + self._raise_if_fused_cannot_be_used() + return True + except ValueError: + return False + def build(self, input_shape): input_shape = tensor_shape.TensorShape(input_shape) if not input_shape.ndims: @@ -191,10 +239,6 @@ class BatchNormalization(Layer): if isinstance(self.axis, int): self.axis = [self.axis] - if not isinstance(self.axis, list): - raise TypeError('axis must be int or list, type given: %s' - % type(self.axis)) - for idx, x in enumerate(self.axis): if x < 0: self.axis[idx] = ndims + x @@ -219,16 +263,18 @@ class BatchNormalization(Layer): raise ValueError('When using virtual_batch_size, adjustment cannot ' 'be specified') - if self.fused: - # Currently fused batch norm doesn't support renorm. It also only supports - # an input tensor of rank 4 and a channel dimension on axis 1 or 3. + if self.fused in (None, True): # TODO(yaozhang): if input is not 4D, reshape it to 4D and reshape the # output back to its original shape accordingly. - self.fused = (not self.renorm and - ndims == 4 and - self.axis in [[1], [3]] and - self.virtual_batch_size is None and - self.adjustment is None) + if self._USE_V2_BEHAVIOR: + if self.fused is None: + self.fused = (ndims == 4) + elif self.fused and ndims != 4: + raise ValueError('Batch normalization layers with fused=True only ' + 'support 4D input tensors.') + else: + assert self.fused is not None + self.fused = (ndims == 4 and self._fused_can_be_used()) # TODO(chrisying): fused batch norm is currently not supported for # multi-axis batch norm and by extension virtual batches. In some cases, # it might be possible to use fused batch norm but would require reshaping @@ -672,5 +718,36 @@ class BatchNormalization(Layer): 'layer cannot be serialized and has been omitted from ' 'the layer config. It will not be included when ' 're-creating the layer from the saved config.') - base_config = super(BatchNormalization, self).get_config() + base_config = super(BatchNormalizationV2, self).get_config() return dict(list(base_config.items()) + list(config.items())) + + +def _replace_in_v2_docstring(old, new): + string = BatchNormalizationV2.__doc__ + if old not in string: + raise ValueError('Could not find following string in BatchNormalizationV2 ' + 'docstring: "{}"'.format(old)) + return string.replace(old, new) + + +@tf_export(v1=['keras.layers.BatchNormalization']) # pylint: disable=missing-docstring +class BatchNormalizationV1(BatchNormalizationV2): + + __doc__ = _replace_in_v2_docstring( + ''' + fused: if `True`, use a faster, fused implementation, or raise a ValueError + if the fused implementation cannot be used. If `None`, use the faster + implementation if possible. If False, do not used the fused + implementation.''', + + ''' + fused: if `None` or `True`, use a faster, fused implementation if possible. + If `False`, use the system recommended implementation.''') + + _USE_V2_BEHAVIOR = False + + +if tf2.enabled(): + BatchNormalization = BatchNormalizationV2 +else: + BatchNormalization = BatchNormalizationV1 diff --git a/tensorflow/python/keras/layers/normalization_test.py b/tensorflow/python/keras/layers/normalization_test.py index 92e4128707..2f7f042b7f 100644 --- a/tensorflow/python/keras/layers/normalization_test.py +++ b/tensorflow/python/keras/layers/normalization_test.py @@ -23,6 +23,7 @@ import numpy as np from tensorflow.python import keras from tensorflow.python.framework import test_util as tf_test_util from tensorflow.python.keras import testing_utils +from tensorflow.python.keras.layers import normalization from tensorflow.python.platform import test from tensorflow.python.training import gradient_descent @@ -54,6 +55,14 @@ class NormalizationLayersTest(test.TestCase): kwargs={'scale': False, 'center': False}, input_shape=(3, 3)) + testing_utils.layer_test( + normalization.BatchNormalizationV2, + kwargs={'fused': True}, + input_shape=(3, 3, 3, 3)) + testing_utils.layer_test( + normalization.BatchNormalizationV2, + kwargs={'fused': None}, + input_shape=(3, 3, 3)) def test_batchnorm_weights(self): layer = keras.layers.BatchNormalization(scale=False, center=False) @@ -78,15 +87,18 @@ class NormalizationLayersTest(test.TestCase): self.assertEqual(layer.gamma.constraint, max_norm) self.assertEqual(layer.beta.constraint, max_norm) - def test_batchnorm_correctness(self): + def _test_batchnorm_correctness(self, dtype, use_v2=True, fused=False): model = keras.models.Sequential() - norm = keras.layers.BatchNormalization(input_shape=(10,), momentum=0.8) + layer_ctor = (normalization.BatchNormalizationV2 if use_v2 + else normalization.BatchNormalizationV1) + norm = layer_ctor(input_shape=(2, 2, 2), momentum=0.8, fused=fused) model.add(norm) model.compile(loss='mse', optimizer=gradient_descent.GradientDescentOptimizer(0.01)) # centered on 5.0, variance 10.0 - x = np.random.normal(loc=5.0, scale=10.0, size=(1000, 10)) + x = (np.random.normal(loc=5.0, scale=10.0, size=(1000, 2, 2, 2)) + .astype(dtype)) model.fit(x, x, epochs=4, verbose=0) out = model.predict(x) out -= keras.backend.eval(norm.beta) @@ -95,23 +107,15 @@ class NormalizationLayersTest(test.TestCase): np.testing.assert_allclose(out.mean(), 0.0, atol=1e-1) np.testing.assert_allclose(out.std(), 1.0, atol=1e-1) - def test_batchnorm_mixed_precision(self): - model = keras.models.Sequential() - norm = keras.layers.BatchNormalization(input_shape=(10,), momentum=0.8) - model.add(norm) - model.compile(loss='mse', - optimizer=gradient_descent.GradientDescentOptimizer(0.01)) - - # centered on 5.0, variance 10.0 - x = np.random.normal( - loc=5.0, scale=10.0, size=(1000, 10)).astype(np.float16) - model.fit(x, x, epochs=4, verbose=0) - out = model.predict(x) - out -= keras.backend.eval(norm.beta) - out /= keras.backend.eval(norm.gamma) + def test_batchnorm_correctness(self): + self._test_batchnorm_correctness(np.float32) + self._test_batchnorm_correctness(np.float32, fused=True) + self._test_batchnorm_correctness(np.float32, use_v2=False) - np.testing.assert_allclose(out.mean(), 0.0, atol=1e-1) - np.testing.assert_allclose(out.std(), 1.0, atol=1e-1) + def test_batchnorm_mixed_precision(self): + self._test_batchnorm_correctness(np.float16) + self._test_batchnorm_correctness(np.float16, fused=True) + self._test_batchnorm_correctness(np.float16, use_v2=False) def test_batchnorm_convnet(self): if test.is_gpu_available(cuda_only=True): @@ -151,6 +155,77 @@ class NormalizationLayersTest(test.TestCase): np.testing.assert_allclose(np.mean(out, axis=(0, 1, 2)), 0.0, atol=1e-1) np.testing.assert_allclose(np.std(out, axis=(0, 1, 2)), 1.0, atol=1e-1) + def test_v1_fused_attribute(self): + norm = normalization.BatchNormalizationV1() + inp = keras.layers.Input((4, 4, 4)) + norm(inp) + self.assertEqual(norm.fused, True) + + norm = normalization.BatchNormalizationV1(fused=False) + self.assertEqual(norm.fused, False) + inp = keras.layers.Input(shape=(4, 4, 4)) + norm(inp) + self.assertEqual(norm.fused, False) + + norm = normalization.BatchNormalizationV1(virtual_batch_size=2) + self.assertEqual(norm.fused, True) + inp = keras.layers.Input(shape=(2, 2, 2)) + norm(inp) + self.assertEqual(norm.fused, False) + + def test_v2_fused_attribute(self): + norm = normalization.BatchNormalizationV2() + self.assertEqual(norm.fused, None) + inp = keras.layers.Input(shape=(4, 4, 4)) + norm(inp) + self.assertEqual(norm.fused, True) + + norm = normalization.BatchNormalizationV2() + self.assertEqual(norm.fused, None) + inp = keras.layers.Input(shape=(4, 4)) + norm(inp) + self.assertEqual(norm.fused, False) + + norm = normalization.BatchNormalizationV2(virtual_batch_size=2) + self.assertEqual(norm.fused, False) + inp = keras.layers.Input(shape=(4, 4, 4)) + norm(inp) + self.assertEqual(norm.fused, False) + + norm = normalization.BatchNormalizationV2(fused=False) + self.assertEqual(norm.fused, False) + inp = keras.layers.Input(shape=(4, 4, 4)) + norm(inp) + self.assertEqual(norm.fused, False) + + norm = normalization.BatchNormalizationV2(fused=True, axis=[3]) + self.assertEqual(norm.fused, True) + inp = keras.layers.Input(shape=(4, 4, 4)) + norm(inp) + self.assertEqual(norm.fused, True) + + with self.assertRaisesRegexp(ValueError, 'fused.*renorm'): + normalization.BatchNormalizationV2(fused=True, renorm=True) + + with self.assertRaisesRegexp(ValueError, 'fused.*when axis is 1 or 3'): + normalization.BatchNormalizationV2(fused=True, axis=2) + + with self.assertRaisesRegexp(ValueError, 'fused.*when axis is 1 or 3'): + normalization.BatchNormalizationV2(fused=True, axis=[1, 3]) + + with self.assertRaisesRegexp(ValueError, 'fused.*virtual_batch_size'): + normalization.BatchNormalizationV2(fused=True, virtual_batch_size=2) + + with self.assertRaisesRegexp(ValueError, 'fused.*adjustment'): + normalization.BatchNormalizationV2(fused=True, + adjustment=lambda _: (1, 0)) + + norm = normalization.BatchNormalizationV2(fused=True) + self.assertEqual(norm.fused, True) + inp = keras.layers.Input(shape=(4, 4)) + with self.assertRaisesRegexp(ValueError, '4D input tensors'): + norm(inp) + class NormalizationLayersGraphModeOnlyTest(test.TestCase): diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-batch-normalization.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-batch-normalization.pbtxt index 820034564f..b3d3c84f92 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-batch-normalization.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.layers.-batch-normalization.pbtxt @@ -1,6 +1,7 @@ path: "tensorflow.keras.layers.BatchNormalization" tf_class { - is_instance: "" + is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.layers.-batch-normalization.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.layers.-batch-normalization.pbtxt index b132bd43c4..16d9ecce10 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.layers.-batch-normalization.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.layers.-batch-normalization.pbtxt @@ -1,7 +1,8 @@ path: "tensorflow.layers.BatchNormalization" tf_class { is_instance: "" - is_instance: "" + is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-batch-normalization.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-batch-normalization.pbtxt index 820034564f..5da7926812 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-batch-normalization.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.layers.-batch-normalization.pbtxt @@ -1,6 +1,6 @@ path: "tensorflow.keras.layers.BatchNormalization" tf_class { - is_instance: "" + is_instance: "" is_instance: "" is_instance: "" is_instance: "" -- GitLab From f36a16d6f111ee5e7875ef28e1b3026e1ed939ab Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 27 Nov 2018 15:49:17 -0800 Subject: [PATCH 420/672] Update BUILD file to include matrix_square_root_op_test PR #20611 missed updating the BUILD file to include the python tests. Also fixed python test to no longer use test_session. PiperOrigin-RevId: 223072629 --- tensorflow/python/kernel_tests/BUILD | 12 ++++++++++++ .../kernel_tests/matrix_square_root_op_test.py | 14 ++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index 19facca5a6..3839928434 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -661,6 +661,18 @@ cuda_py_test( ], ) +cuda_py_test( + name = "matrix_square_root_op_test", + size = "medium", + srcs = ["matrix_square_root_op_test.py"], + additional_deps = [ + "//third_party/py/numpy", + "//tensorflow/python:client_testlib", + "//tensorflow/python:framework_for_generated_wrappers", + "//tensorflow/python:linalg_ops", + ], +) + cuda_py_test( name = "matrix_solve_op_test", size = "medium", diff --git a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py index 1f2144bdee..0bf822a692 100644 --- a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py @@ -21,6 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_linalg_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops @@ -31,7 +32,7 @@ class SquareRootOpTest(test.TestCase): def _verifySquareRoot(self, matrix, np_type): matrix = matrix.astype(np_type) - with self.test_session(use_gpu=True): + with test_util.use_gpu(): # Verify that matmul(sqrtm(A), sqrtm(A)) = A sqrt = gen_linalg_ops.matrix_square_root(matrix) square = math_ops.matmul(sqrt, sqrt) @@ -96,13 +97,14 @@ class SquareRootOpTest(test.TestCase): gen_linalg_ops.matrix_square_root(tensor) def testNotSquare(self): - with self.test_session(): - with self.assertRaises(ValueError): - tensor = constant_op.constant([[1., 0., -1.], [-1., 1., 0.]]) - gen_linalg_ops.matrix_square_root(tensor).eval() + with self.assertRaises(ValueError): + tensor = constant_op.constant([[1., 0., -1.], [-1., 1., 0.]]) + self.evaluate(gen_linalg_ops.matrix_square_root(tensor)) def testConcurrentExecutesWithoutError(self): - with self.test_session(use_gpu=True) as sess: + self.skipTest("Triggers assert in matrix_sqrt_quasi_triangular_diagonal") + + with test_util.use_gpu(): matrix1 = random_ops.random_normal([5, 5], seed=42) matrix2 = random_ops.random_normal([5, 5], seed=42) sqrt1 = gen_linalg_ops.matrix_square_root(matrix1) -- GitLab From a31118cf96c515238c2bbc2b27e887e40d308f6a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 16:07:41 -0800 Subject: [PATCH 421/672] Allow XRTCompile to take an XLA DebugOptions to configure compilation and aid debugging. PiperOrigin-RevId: 223075680 --- tensorflow/compiler/jit/BUILD | 1 + tensorflow/compiler/xla/client/BUILD | 3 +- .../xla/client/executable_build_options.cc | 68 +++-------------- .../xla/client/executable_build_options.h | 49 ++---------- .../xla/python/local_computation_builder.i | 10 +-- .../compiler/xla/service/local_service.cc | 30 +------- .../xla/tests/xla_hlo_profile_test.cc | 6 +- tensorflow/compiler/xrt/BUILD | 6 ++ .../compiler/xrt/kernels/xrt_compile_ops.cc | 5 ++ tensorflow/compiler/xrt/xrt.proto | 3 + tensorflow/compiler/xrt/xrt_util.cc | 76 +++++++++++++++++++ tensorflow/compiler/xrt/xrt_util.h | 34 +++++++++ 12 files changed, 155 insertions(+), 136 deletions(-) create mode 100644 tensorflow/compiler/xrt/xrt_util.cc create mode 100644 tensorflow/compiler/xrt/xrt_util.h diff --git a/tensorflow/compiler/jit/BUILD b/tensorflow/compiler/jit/BUILD index a3c7dd22de..be91ed4f43 100644 --- a/tensorflow/compiler/jit/BUILD +++ b/tensorflow/compiler/jit/BUILD @@ -268,6 +268,7 @@ cc_library( "//tensorflow/compiler/tf2xla:common", "//tensorflow/compiler/tf2xla:dump_graph", "//tensorflow/compiler/tf2xla:xla_compiler", + "//tensorflow/compiler/xla:debug_options_flags", "//tensorflow/compiler/xla:statusor", "//tensorflow/compiler/xla/client:client_library", "//tensorflow/compiler/xla/client:local_client", diff --git a/tensorflow/compiler/xla/client/BUILD b/tensorflow/compiler/xla/client/BUILD index e1f3674c4f..ad2e525efd 100644 --- a/tensorflow/compiler/xla/client/BUILD +++ b/tensorflow/compiler/xla/client/BUILD @@ -90,11 +90,12 @@ cc_library( srcs = ["executable_build_options.cc"], hdrs = ["executable_build_options.h"], deps = [ + "//tensorflow/compiler/xla:debug_options_flags", "//tensorflow/compiler/xla:shape_util", "//tensorflow/compiler/xla:util", "//tensorflow/compiler/xla:xla_data_proto", + "//tensorflow/compiler/xla:xla_proto", "//tensorflow/compiler/xla/service:device_memory_allocator", - "//tensorflow/core:lib", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/types:optional", diff --git a/tensorflow/compiler/xla/client/executable_build_options.cc b/tensorflow/compiler/xla/client/executable_build_options.cc index 0f1745366b..1f594e551a 100644 --- a/tensorflow/compiler/xla/client/executable_build_options.cc +++ b/tensorflow/compiler/xla/client/executable_build_options.cc @@ -16,6 +16,7 @@ limitations under the License. #include "tensorflow/compiler/xla/client/executable_build_options.h" #include "absl/strings/str_format.h" +#include "tensorflow/compiler/xla/debug_options_flags.h" #include "tensorflow/compiler/xla/shape_util.h" namespace xla { @@ -39,6 +40,13 @@ ExecutableBuildOptions& ExecutableBuildOptions::set_device_ordinal( int ExecutableBuildOptions::device_ordinal() const { return device_ordinal_; } +DebugOptions* ExecutableBuildOptions::mutable_debug_options() { + if (!has_debug_options()) { + debug_options_ = GetDebugOptionsFromFlags(); + } + return &debug_options_.value(); +} + ExecutableBuildOptions& ExecutableBuildOptions::set_result_layout( const Shape& shape_with_layout) { result_layout_set_ = true; @@ -55,68 +63,10 @@ string ExecutableBuildOptions::ToString() const { if (result_layout_set_) { result_layout = ShapeUtil::HumanStringWithLayout(result_layout_); } - string generate_hlo_graph = "nullopt"; - if (generate_hlo_graph_.has_value()) { - generate_hlo_graph = generate_hlo_graph_.value(); - } return absl::StrFormat( "ExecutableBuildOptions{device_ordinal=%d, result_layout=%s, " "generate_hlo_graph=%s}", - device_ordinal_, result_layout, generate_hlo_graph); -} - -ExecutableBuildOptions& ExecutableBuildOptions::set_generate_hlo_graph( - string regex) { - generate_hlo_graph_ = std::move(regex); - return *this; -} - -const absl::optional& ExecutableBuildOptions::generate_hlo_graph() - const { - return generate_hlo_graph_; -} - -ExecutableBuildOptions& ExecutableBuildOptions::set_dump_optimized_hlo_proto_to( - absl::string_view dirpath) { - dump_optimized_hlo_proto_to_ = string(dirpath); - return *this; -} - -const absl::optional& -ExecutableBuildOptions::dump_optimized_hlo_proto_to() const { - return dump_optimized_hlo_proto_to_; -} - -ExecutableBuildOptions& -ExecutableBuildOptions::set_dump_unoptimized_hlo_proto_to( - absl::string_view dirpath) { - dump_unoptimized_hlo_proto_to_ = string(dirpath); - return *this; -} - -const absl::optional& -ExecutableBuildOptions::dump_unoptimized_hlo_proto_to() const { - return dump_unoptimized_hlo_proto_to_; -} - -ExecutableBuildOptions& ExecutableBuildOptions::set_dump_per_pass_hlo_proto_to( - absl::string_view dirpath) { - dump_per_pass_hlo_proto_to_ = string(dirpath); - return *this; -} - -const absl::optional& -ExecutableBuildOptions::dump_per_pass_hlo_proto_to() const { - return dump_per_pass_hlo_proto_to_; -} - -ExecutableBuildOptions& ExecutableBuildOptions::set_hlo_profile(bool enabled) { - hlo_profile_ = enabled; - return *this; -} - -absl::optional ExecutableBuildOptions::hlo_profile() const { - return hlo_profile_; + device_ordinal_, result_layout, debug_options().xla_generate_hlo_graph()); } } // namespace xla diff --git a/tensorflow/compiler/xla/client/executable_build_options.h b/tensorflow/compiler/xla/client/executable_build_options.h index 93334db88b..dd8cb5598a 100644 --- a/tensorflow/compiler/xla/client/executable_build_options.h +++ b/tensorflow/compiler/xla/client/executable_build_options.h @@ -20,6 +20,7 @@ limitations under the License. #include "absl/types/optional.h" #include "tensorflow/compiler/xla/service/device_memory_allocator.h" #include "tensorflow/compiler/xla/util.h" +#include "tensorflow/compiler/xla/xla.pb.h" #include "tensorflow/compiler/xla/xla_data.pb.h" namespace xla { @@ -44,6 +45,12 @@ class ExecutableBuildOptions { ExecutableBuildOptions& set_result_layout(const Shape& shape_with_layout); const Shape* result_layout() const; + // Expose access to the XLA debug options which will be passed to the + // compilation process. + bool has_debug_options() const { return debug_options_.has_value(); } + const DebugOptions& debug_options() const { return *debug_options_; } + DebugOptions* mutable_debug_options(); + // If set, this specifies an allocator that can be used to allocate temporary // space on the device during compilation. For example, the compiler might // want to run various algorithms on the device and pick the fastest one -- it @@ -55,56 +62,16 @@ class ExecutableBuildOptions { DeviceMemoryAllocator* allocator); DeviceMemoryAllocator* device_allocator() const; - // If set, specifies a regexp of HLO graphs to dump (as in DebugOptions). - ExecutableBuildOptions& set_generate_hlo_graph(string regex); - const absl::optional& generate_hlo_graph() const; - - // If set, specifies a dirpath to dump the end-of-optimization-pipeline HLO - // protobuf to (as in DebugOptions). - ExecutableBuildOptions& set_dump_optimized_hlo_proto_to( - absl::string_view dirpath); - const absl::optional& dump_optimized_hlo_proto_to() const; - - // If set, specifies a dirpath to dump the start-of-optimization-pipeline HLO - // protobuf to (as in DebugOptions). - ExecutableBuildOptions& set_dump_unoptimized_hlo_proto_to( - absl::string_view dirpath); - const absl::optional& dump_unoptimized_hlo_proto_to() const; - - // If set, specifies a dirpath to dump the per-pass-in-pipeline HLO protobufs - // to (as in DebugOptions). - ExecutableBuildOptions& set_dump_per_pass_hlo_proto_to( - absl::string_view dirpath); - const absl::optional& dump_per_pass_hlo_proto_to() const; - - // If true, specifies that we should record an HLO profile during execution - // and log it after execution (as in DebugOptions). If nullopt the default is - // used. - ExecutableBuildOptions& set_hlo_profile(bool enabled); - absl::optional hlo_profile() const; - - void add_disabled_hlo_pass(absl::string_view pass_name) { - disabled_hlo_passes_.push_back(std::string(pass_name)); - } - const absl::Span disabled_hlo_passes() const { - return disabled_hlo_passes_; - } - // Returns a string representation of the build options, suitable for // debugging. string ToString() const; private: - absl::optional hlo_profile_; int device_ordinal_ = -1; Shape result_layout_; bool result_layout_set_ = false; - absl::optional generate_hlo_graph_; - absl::optional dump_optimized_hlo_proto_to_; - absl::optional dump_unoptimized_hlo_proto_to_; - absl::optional dump_per_pass_hlo_proto_to_; + absl::optional debug_options_; DeviceMemoryAllocator* device_allocator_ = nullptr; - std::vector disabled_hlo_passes_; }; } // namespace xla diff --git a/tensorflow/compiler/xla/python/local_computation_builder.i b/tensorflow/compiler/xla/python/local_computation_builder.i index 03698d9ce8..5c2538dcc3 100644 --- a/tensorflow/compiler/xla/python/local_computation_builder.i +++ b/tensorflow/compiler/xla/python/local_computation_builder.i @@ -921,22 +921,22 @@ tensorflow::ImportNumpy(); $1 = NULL; } else { if (!HandleStringAttribute($input, "generate_hlo_graph", [&](string s) { - build_options.set_generate_hlo_graph(std::move(s)); + build_options.mutable_debug_options()->set_xla_generate_hlo_graph(std::move(s)); })) { return nullptr; } if (!HandleStringAttribute($input, "dump_optimized_hlo_proto_to", [&](string s) { - build_options.set_dump_optimized_hlo_proto_to(std::move(s)); + build_options.mutable_debug_options()->set_xla_dump_optimized_hlo_proto_to(std::move(s)); })) { return nullptr; } if (!HandleStringAttribute($input, "dump_unoptimized_hlo_proto_to", [&](string s) { - build_options.set_dump_unoptimized_hlo_proto_to(std::move(s)); + build_options.mutable_debug_options()->set_xla_dump_unoptimized_hlo_proto_to(std::move(s)); })) { return nullptr; } if (!HandleStringAttribute($input, "dump_per_pass_hlo_proto_to", [&](string s) { - build_options.set_dump_per_pass_hlo_proto_to(std::move(s)); + build_options.mutable_debug_options()->set_xla_dump_per_pass_hlo_proto_to(std::move(s)); })) { return nullptr; } @@ -950,7 +950,7 @@ tensorflow::ImportNumpy(); PyErr_SetString(PyExc_TypeError, "ExecutableBuildOptions.hlo_profile must be a bool or None."); SWIG_fail; } - build_options.set_hlo_profile(o == Py_True); + build_options.mutable_debug_options()->set_xla_hlo_profile(o == Py_True); } Py_DECREF(o); diff --git a/tensorflow/compiler/xla/service/local_service.cc b/tensorflow/compiler/xla/service/local_service.cc index 5c105908f3..ddc8691e77 100644 --- a/tensorflow/compiler/xla/service/local_service.cc +++ b/tensorflow/compiler/xla/service/local_service.cc @@ -96,28 +96,8 @@ ExecutionOptions CreateExecutionOptions( const ExecutableBuildOptions& build_options, const ProgramShape* program_shape) { ExecutionOptions execution_options = CreateDefaultExecutionOptions(); - if (build_options.hlo_profile().has_value()) { - execution_options.mutable_debug_options()->set_xla_hlo_profile( - *build_options.hlo_profile()); - } - if (build_options.generate_hlo_graph().has_value()) { - execution_options.mutable_debug_options()->set_xla_generate_hlo_graph( - build_options.generate_hlo_graph().value()); - } - if (build_options.dump_optimized_hlo_proto_to().has_value()) { - execution_options.mutable_debug_options() - ->set_xla_dump_optimized_hlo_proto_to( - build_options.dump_optimized_hlo_proto_to().value()); - } - if (build_options.dump_unoptimized_hlo_proto_to().has_value()) { - execution_options.mutable_debug_options() - ->set_xla_dump_unoptimized_hlo_proto_to( - build_options.dump_unoptimized_hlo_proto_to().value()); - } - if (build_options.dump_per_pass_hlo_proto_to().has_value()) { - execution_options.mutable_debug_options() - ->set_xla_dump_per_pass_hlo_proto_to( - build_options.dump_per_pass_hlo_proto_to().value()); + if (build_options.has_debug_options()) { + *execution_options.mutable_debug_options() = build_options.debug_options(); } if (build_options.result_layout() != nullptr) { *execution_options.mutable_shape_with_output_layout() = @@ -128,12 +108,6 @@ ExecutionOptions CreateExecutionOptions( LayoutUtil::SetToDefaultLayout( execution_options.mutable_shape_with_output_layout()); } - - for (const std::string& disabled_pass : build_options.disabled_hlo_passes()) { - execution_options.mutable_debug_options()->add_xla_disable_hlo_passes( - disabled_pass); - } - return execution_options; } diff --git a/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc b/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc index ca036f1ae0..e57d072a06 100644 --- a/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc +++ b/tensorflow/compiler/xla/tests/xla_hlo_profile_test.cc @@ -157,10 +157,12 @@ void ExecuteAndFetchProfile(string* profile_output, LocalClient* client, TF_ASSERT_OK(transfer_manager->TransferLiteralToDevice( stream_ptr.get(), Literal::CreateFromShape(rhs_arg_shape), rhs_arg)); + ExecutableBuildOptions build_options; + build_options.mutable_debug_options()->set_xla_hlo_profile(true); TF_ASSERT_OK_AND_ASSIGN( std::unique_ptr local_executable, client->Compile(computation, {&lhs_arg_shape, &rhs_arg_shape}, - ExecutableBuildOptions().set_hlo_profile(true))); + build_options)); Executable* executable = local_executable->executable(); HloExecutionProfile hlo_execution_profile( @@ -208,7 +210,7 @@ XLA_TEST_F(HloProfileTest, ProfileSingleComputation) { string profile_output; ExecuteAndFetchProfile(&profile_output, client, computation, lhs_shape, rhs_shape); - + VLOG(4) << "Profile Output:\n" << profile_output; std::vector profile_output_lines = absl::StrSplit(profile_output, '\n'); diff --git a/tensorflow/compiler/xrt/BUILD b/tensorflow/compiler/xrt/BUILD index 2ff97914f8..2dae746d03 100644 --- a/tensorflow/compiler/xrt/BUILD +++ b/tensorflow/compiler/xrt/BUILD @@ -22,6 +22,7 @@ xla_proto_library( deps = [ "//tensorflow/compiler/tf2xla:host_compute_metadata_proto", "//tensorflow/compiler/xla:xla_data_proto", + "//tensorflow/compiler/xla:xla_proto", "//tensorflow/compiler/xla/service:hlo_proto", ], ) @@ -32,20 +33,25 @@ cc_library( "xrt_compilation_cache.cc", "xrt_device.cc", "xrt_state.cc", + "xrt_util.cc", ], hdrs = [ "xrt_compilation_cache.h", "xrt_device.h", "xrt_state.h", + "xrt_util.h", ], deps = [ "//tensorflow/compiler/jit:xla_device", "//tensorflow/compiler/tf2xla:xla_compiler", + "//tensorflow/compiler/xla:debug_options_flags", "//tensorflow/compiler/xla:literal", "//tensorflow/compiler/xla:shape_util", "//tensorflow/compiler/xla:status_macros", "//tensorflow/compiler/xla:statusor", + "//tensorflow/compiler/xla:types", "//tensorflow/compiler/xla:xla_data_proto", + "//tensorflow/compiler/xla:xla_proto", "//tensorflow/compiler/xla/client:local_client", "//tensorflow/compiler/xla/service:backend", "//tensorflow/compiler/xla/service:device_memory_allocator", diff --git a/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc b/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc index db43aeaafe..1603b45ff6 100644 --- a/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc +++ b/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc @@ -33,6 +33,7 @@ limitations under the License. #include "tensorflow/compiler/xrt/xrt.pb.h" #include "tensorflow/compiler/xrt/xrt_compilation_cache.h" #include "tensorflow/compiler/xrt/xrt_device.h" +#include "tensorflow/compiler/xrt/xrt_util.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/resource_mgr.h" #include "tensorflow/core/framework/tensor.h" @@ -117,6 +118,10 @@ Status XRTCompileOp::Compile(OpKernelContext* ctx, build_options.set_device_ordinal(client->default_device_ordinal()); build_options.set_result_layout(config.program_shape().result()); build_options.set_device_allocator(device_ref.backend()->memory_allocator()); + if (config.has_debug_options()) { + *build_options.mutable_debug_options() = + BuildXlaDebugOptions(config.debug_options()); + } VLOG(1) << "Building executable"; auto compile_result = diff --git a/tensorflow/compiler/xrt/xrt.proto b/tensorflow/compiler/xrt/xrt.proto index ae44f71740..e149f2f435 100644 --- a/tensorflow/compiler/xrt/xrt.proto +++ b/tensorflow/compiler/xrt/xrt.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package xrt; import "tensorflow/compiler/tf2xla/host_compute_metadata.proto"; +import "tensorflow/compiler/xla/xla.proto"; import "tensorflow/compiler/xla/xla_data.proto"; import "tensorflow/compiler/xla/service/hlo.proto"; @@ -46,6 +47,8 @@ message XLAComputationConfig { // sent and executed to the set of replica device numbers described in the // DeviceAssignment proto. DeviceAssignment device_assignment = 6; + // The debugging options to be passed to the XLA compilation process. + xla.DebugOptions debug_options = 7; } // Options and XLA computation for a compilation. diff --git a/tensorflow/compiler/xrt/xrt_util.cc b/tensorflow/compiler/xrt/xrt_util.cc new file mode 100644 index 0000000000..3ef8bedc73 --- /dev/null +++ b/tensorflow/compiler/xrt/xrt_util.cc @@ -0,0 +1,76 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/compiler/xrt/xrt_util.h" + +#include +#include + +#include "tensorflow/compiler/xla/debug_options_flags.h" +#include "tensorflow/compiler/xla/types.h" +#include "tensorflow/core/platform/logging.h" + +namespace tensorflow { +namespace { + +bool DebugOptionsPassThroughEnabled() { + const char* env = getenv("TF_XLA_DEBUG_OPTIONS_PASSTHROUGH"); + bool enabled = + env != nullptr && (strcmp(env, "1") == 0 || strcmp(env, "true") == 0); + if (enabled) { + LOG(WARNING) << "Passing through XLA debug options!"; + } else { + LOG(WARNING) << "TF_XLA_DEBUG_OPTIONS_PASSTHROUGH not set, not all options " + "will be retained"; + } + return enabled; +} + +string SafeDebugPath(const string& path) { + if (path.empty() || path.compare(0, 5, "gs://") == 0 || + path.compare(0, 11, "bigstore://") == 0) { + return path; + } + LOG(WARNING) << "Invalid config path (will be dropped): " << path; + return string(); +} + +} // namespace + +xla::DebugOptions BuildXlaDebugOptions(const xla::DebugOptions& ref_options) { + static const bool options_passthrough = DebugOptionsPassThroughEnabled(); + if (options_passthrough) { + return ref_options; + } + xla::DebugOptions options = xla::GetDebugOptionsFromFlags(); + options.set_xla_generate_hlo_text_to( + SafeDebugPath(ref_options.xla_generate_hlo_text_to())); + options.set_xla_dump_optimized_hlo_proto_to( + SafeDebugPath(ref_options.xla_dump_optimized_hlo_proto_to())); + options.set_xla_dump_computations_to( + SafeDebugPath(ref_options.xla_dump_computations_to())); + options.set_xla_dump_executions_to( + SafeDebugPath(ref_options.xla_dump_executions_to())); + for (auto& pass : ref_options.xla_disable_hlo_passes()) { + options.add_xla_disable_hlo_passes(pass); + } + options.set_xla_dump_unoptimized_hlo_proto_to( + SafeDebugPath(ref_options.xla_dump_unoptimized_hlo_proto_to())); + options.set_xla_dump_per_pass_hlo_proto_to( + SafeDebugPath(ref_options.xla_dump_per_pass_hlo_proto_to())); + return options; +} + +} // namespace tensorflow diff --git a/tensorflow/compiler/xrt/xrt_util.h b/tensorflow/compiler/xrt/xrt_util.h new file mode 100644 index 0000000000..d9c05a7f34 --- /dev/null +++ b/tensorflow/compiler/xrt/xrt_util.h @@ -0,0 +1,34 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +// Utility functions in support of the XRT API. + +#ifndef TENSORFLOW_COMPILER_XRT_XRT_UTIL_H_ +#define TENSORFLOW_COMPILER_XRT_XRT_UTIL_H_ + +#include "tensorflow/compiler/xla/xla.pb.h" + +namespace tensorflow { + +// Filters the debug options provided as argument according to the value of the +// TF_XLA_DEBUG_OPTIONS_PASSTHROUGH environment variable. If such variable is +// set to "1" or "true", the debug options will be returned as is. Otherwise +// only a subset of them will be set in the returned ones, and all the paths +// contained in it, will be limited to gs:// and bigstore:// ones. +xla::DebugOptions BuildXlaDebugOptions(const xla::DebugOptions& ref_options); + +} // namespace tensorflow + +#endif // TENSORFLOW_COMPILER_XRT_XRT_UTIL_H_ -- GitLab From 06d4711e8cf98165e16d125db88edac461764f9c Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 16:14:42 -0800 Subject: [PATCH 422/672] Add batch_jacobian to GradientTape. PiperOrigin-RevId: 223076782 --- tensorflow/python/eager/backprop.py | 128 +++++++++++++++++- tensorflow/python/eager/backprop_test.py | 94 +++++++++++++ .../golden/v1/tensorflow.-gradient-tape.pbtxt | 4 + .../golden/v2/tensorflow.-gradient-tape.pbtxt | 4 + 4 files changed, 223 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/eager/backprop.py b/tensorflow/python/eager/backprop.py index 99da422781..beed1d5de3 100644 --- a/tensorflow/python/eager/backprop.py +++ b/tensorflow/python/eager/backprop.py @@ -20,6 +20,7 @@ from __future__ import print_function import functools import operator +import sys import six @@ -33,6 +34,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape from tensorflow.python.ops import array_ops +from tensorflow.python.ops import check_ops from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import gen_math_ops from tensorflow.python.ops import math_ops @@ -1004,9 +1006,8 @@ class GradientTape(object): self._push_tape() y = array_ops.gather(target, i) self._pop_tape() - grad = self.gradient(y, flat_sources, + return self.gradient(y, flat_sources, unconnected_gradients=unconnected_gradients) - return grad try: target_size = int(target.shape[0]) @@ -1021,11 +1022,13 @@ class GradientTape(object): try: output = f() except ValueError as err: - # TODO(agarwal): Fold this error message into err. - logging.error("Encountered an exception while vectorizing the jacobian " - "computation. Vectorization can be disabled by setting " - "experimental_use_pfor to False.") - raise err + six.reraise( + ValueError, + ValueError( + str(err) + "\nEncountered an exception while vectorizing the " + "jacobian computation. Vectorization can be disabled by setting" + " experimental_use_pfor to False."), + sys.exc_info()[2]) else: if context.executing_eagerly(): if not self._persistent: @@ -1046,3 +1049,114 @@ class GradientTape(object): output[i] = out return nest.pack_sequence_as(sources, output) + + def batch_jacobian(self, + target, + source, + unconnected_gradients=UnconnectedGradients.NONE, + experimental_use_pfor=True): + """Computes and stacks per-example jacobians. + + See http://en.wikipedia.org/wiki/jacobian_matrix_and_determinant for the + definition of a Jacobian. This function is essentially an efficient + implementation of the following: + `tf.stack([self.jacobian(y[i], x[i]) for i in range(x.shape[0])])`. + + Note that compared to `GradientTape.jacobian` which computes gradient of + each output value w.r.t each input value, this function is useful when + `target[i,...] is independent of `source[j,...]` for `j != i`. This + independence assumption allows more efficient computation as compared to + `GradientTape.jacobian`. The output, as well as intermediate activations, + are lower dimensional and avoid a bunch of redundant zeros which would + result in the jacobian computation given the independence assumption. + + Example usage: + with tf.GradientTape() as g: + x = tf.constant([[1, 2], [3, 4]], dtype=tf.float32) + g.watch(x) + y = x * x + batch_jacobian = g.batch_jacobian(y, x) + # batch_jacobian is [[[2, 0], [0, 4]], [[6, 0], [0, 8]]] + + Args: + target: A tensor with rank 2 or higher and with shape [b, y1, ..., y_n]. + `target[i,...]` should only depend on `source[i,...]`. + source: A tensor with rank 2 or higher and with shape [b, x1, ..., x_m]. + unconnected_gradients: a value which can either hold 'none' or 'zero' and + alters the value which will be returned if the target and sources are + unconnected. The possible values and effects are detailed in + 'UnconnectedGradients' and it defaults to 'none'. + experimental_use_pfor: If true, uses pfor for computing the Jacobian. Else + uses a tf.while_loop. + + Returns: + A tensor `t` with shape [b, y_1, ..., y_n, x1, ..., x_m] where `t[i, ...]` + is the jacobian of `target[i, ...]` w.r.t. `source[i, ...]`, i.e. stacked + per-example jacobians. + + Raises: + RuntimeError: If called on a non-persistent tape with eager execution + enabled and without enabling experimental_use_pfor. + ValueError: If vectorization of jacobian computation fails or if first + dimension of `target` and `source` do not match. + """ + target_shape = target.shape + if not target_shape.with_rank_at_least(2)[0].is_compatible_with( + source.shape.with_rank_at_least(2)[0]): + raise ValueError( + "Need first dimension of target shape (%s) and " + "source shape (%s) to match." % (target.shape, source.shape)) + if target_shape.is_fully_defined(): + batch_size = int(target_shape[0]) + target_row_size = target_shape.num_elements() // batch_size + else: + target_shape = array_ops.shape(target) + batch_size = target_shape[0] + target_row_size = array_ops.size(target) // batch_size + source_shape = array_ops.shape(source) + # Flatten target to 2-D. + # Note that we push and pop the tape here and below. This is needed since we + # need gradients through the enclosed operations. + self._push_tape() + with ops.control_dependencies( + [check_ops.assert_equal(batch_size, source_shape[0])]): + target = array_ops.reshape(target, [batch_size, target_row_size]) + self._pop_tape() + + def loop_fn(i): + self._push_tape() + y = array_ops.gather(target, i, axis=1) + self._pop_tape() + return self.gradient(y, source, + unconnected_gradients=unconnected_gradients) + + if experimental_use_pfor: + def f(): + return pfor_ops.pfor(loop_fn, target_row_size) + if context.executing_eagerly(): + f = function.defun(f) + try: + output = f() + except ValueError as err: + six.reraise( + ValueError, + ValueError( + str(err) + "\nEncountered an exception while vectorizing the " + "batch_jacobian computation. Vectorization can be disabled by " + "setting experimental_use_pfor to False."), + sys.exc_info()[2]) + else: + if context.executing_eagerly(): + if not self._persistent: + raise RuntimeError( + "GradientTape must be created with persistent=True" + " to compute the batch_jacobian with eager execution enabled and " + " with experimental_use_pfor set to False.") + output = pfor_ops.for_loop(loop_fn, target.dtype, target_row_size) + if output is None: + return None + output = array_ops.reshape(output, + [target_row_size, batch_size, -1]) + output = array_ops.transpose(output, [1, 0, 2]) + new_shape = array_ops.concat([target_shape, source_shape[1:]], axis=0) + return array_ops.reshape(output, new_shape) diff --git a/tensorflow/python/eager/backprop_test.py b/tensorflow/python/eager/backprop_test.py index 8b85548e5c..08553b9f27 100644 --- a/tensorflow/python/eager/backprop_test.py +++ b/tensorflow/python/eager/backprop_test.py @@ -1303,5 +1303,99 @@ class JacobianTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'No converter'): g.jacobian(y, x, experimental_use_pfor=True) + +@test_util.run_all_in_graph_and_eager_modes +class BatchJacobianTest(test.TestCase): + + def _batch_jacobian(self, experimental_use_pfor): + persistent = context.executing_eagerly and not experimental_use_pfor + with backprop.GradientTape(persistent=persistent) as g: + x = constant_op.constant([[1., 2.], [3., 4.]]) + y = constant_op.constant([[3., 4.], [5., 6.]]) + g.watch(x) + z = x * x * y + batch_jacobian = g.batch_jacobian( + z, x, experimental_use_pfor=experimental_use_pfor) + answer = array_ops.stack([array_ops.diag(2 * x[0] * y[0]), + array_ops.diag(2 * x[1] * y[1])]) + return batch_jacobian, answer + + def testPfor(self): + batch_jacobian, answer = self._batch_jacobian(experimental_use_pfor=True) + self.assertAllEqual(answer, batch_jacobian) + + def testWhileLoop(self): + batch_jacobian, answer = self._batch_jacobian(experimental_use_pfor=False) + self.assertAllEqual(answer, batch_jacobian) + + def testPforDefun(self): + + @function.defun + def _f(): + return self._batch_jacobian(experimental_use_pfor=True) + + batch_jacobian, answer = _f() + self.assertAllEqual(answer, batch_jacobian) + + def testWhileLoopDefun(self): + + @function.defun + def _f(): + return self._batch_jacobian(experimental_use_pfor=False) + + batch_jacobian, answer = _f() + self.assertAllEqual(answer, batch_jacobian) + + def testPersistentTape(self): + if not context.executing_eagerly(): + return + with backprop.GradientTape() as g: + x = constant_op.constant([[1.0, 2.0]]) + g.watch(x) + y = x * x + with self.assertRaisesRegexp(RuntimeError, 'persistent'): + g.batch_jacobian(y, x, experimental_use_pfor=False) + + def testBadShape(self): + x = random_ops.random_uniform([2, 3]) + with backprop.GradientTape() as g: + y = array_ops.concat([x, x], axis=0) + with self.assertRaisesRegexp(ValueError, 'Need first dimension'): + g.batch_jacobian(y, x) + + def testBadInputRank(self): + x = random_ops.random_uniform([2]) + with backprop.GradientTape() as g: + y = random_ops.random_uniform([2, 2]) + with self.assertRaisesRegexp(ValueError, 'must have rank at least 2'): + g.batch_jacobian(y, x) + + def testBadOutputRank(self): + x = random_ops.random_uniform([2, 2]) + with backprop.GradientTape() as g: + y = random_ops.random_uniform([2]) + with self.assertRaisesRegexp(ValueError, 'must have rank at least 2'): + g.batch_jacobian(y, x) + + def testPforException(self): + var = variables.Variable([1.]) + + @custom_gradient.custom_gradient + def op(x): + def grad(_): + # Note that we perform a stateful operation here that will not be + # compatible with parallel for construct. + with ops.control_dependencies( + [var.assign(random_ops.random_uniform([1]))]): + return constant_op.constant(1.) + return x, grad + + with backprop.GradientTape() as g: + x = constant_op.constant([[1.], [2.]]) + g.watch(x) + y = op(x) + with self.assertRaisesRegexp(ValueError, 'No converter'): + g.batch_jacobian(y, x, experimental_use_pfor=True) + if __name__ == '__main__': test.main() diff --git a/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt index 50af42f4fc..e37d29995a 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt @@ -6,6 +6,10 @@ tf_class { name: "__init__" argspec: "args=[\'self\', \'persistent\', \'watch_accessed_variables\'], varargs=None, keywords=None, defaults=[\'False\', \'True\'], " } + member_method { + name: "batch_jacobian" + argspec: "args=[\'self\', \'target\', \'source\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + } member_method { name: "gradient" argspec: "args=[\'self\', \'target\', \'sources\', \'output_gradients\', \'unconnected_gradients\'], varargs=None, keywords=None, defaults=[\'None\', \'UnconnectedGradients.NONE\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt index 50af42f4fc..e37d29995a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt @@ -6,6 +6,10 @@ tf_class { name: "__init__" argspec: "args=[\'self\', \'persistent\', \'watch_accessed_variables\'], varargs=None, keywords=None, defaults=[\'False\', \'True\'], " } + member_method { + name: "batch_jacobian" + argspec: "args=[\'self\', \'target\', \'source\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + } member_method { name: "gradient" argspec: "args=[\'self\', \'target\', \'sources\', \'output_gradients\', \'unconnected_gradients\'], varargs=None, keywords=None, defaults=[\'None\', \'UnconnectedGradients.NONE\'], " -- GitLab From 0ae47a7f3a3cbfb47a432741d525bafc50c6b68a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 16:22:30 -0800 Subject: [PATCH 423/672] Fix unit test for matrix square root: Don't try to take the matrix square root of a matrix for which the square root may not exist. PiperOrigin-RevId: 223078107 --- .../python/kernel_tests/matrix_square_root_op_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py index 0bf822a692..1e2109b8c4 100644 --- a/tensorflow/python/kernel_tests/matrix_square_root_op_test.py +++ b/tensorflow/python/kernel_tests/matrix_square_root_op_test.py @@ -102,13 +102,13 @@ class SquareRootOpTest(test.TestCase): self.evaluate(gen_linalg_ops.matrix_square_root(tensor)) def testConcurrentExecutesWithoutError(self): - self.skipTest("Triggers assert in matrix_sqrt_quasi_triangular_diagonal") - with test_util.use_gpu(): matrix1 = random_ops.random_normal([5, 5], seed=42) matrix2 = random_ops.random_normal([5, 5], seed=42) - sqrt1 = gen_linalg_ops.matrix_square_root(matrix1) - sqrt2 = gen_linalg_ops.matrix_square_root(matrix2) + square1 = math_ops.matmul(matrix1, matrix1) + square2 = math_ops.matmul(matrix2, matrix2) + sqrt1 = gen_linalg_ops.matrix_square_root(square1) + sqrt2 = gen_linalg_ops.matrix_square_root(square2) all_ops = [sqrt1, sqrt2] sqrt = self.evaluate(all_ops) self.assertAllEqual(sqrt[0], sqrt[1]) -- GitLab From cdea9d0c8a559f7e387b5d2510b6986516e5495d Mon Sep 17 00:00:00 2001 From: Shivani Agrawal Date: Tue, 27 Nov 2018 16:22:39 -0800 Subject: [PATCH 424/672] Small addition for test method name consistency. PiperOrigin-RevId: 223078123 --- tensorflow/python/framework/test_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/framework/test_util.py b/tensorflow/python/framework/test_util.py index a034032e39..fc97a2275c 100644 --- a/tensorflow/python/framework/test_util.py +++ b/tensorflow/python/framework/test_util.py @@ -892,8 +892,8 @@ def run_all_in_graph_and_eager_modes(cls): """Execute all test methods in the given class with and without eager.""" base_decorator = run_in_graph_and_eager_modes for name, value in cls.__dict__.copy().items(): - if callable(value) and name.startswith( - "test") and not name.startswith("testSkipEager"): + if callable(value) and name.startswith("test") and not ( + name.startswith("testSkipEager") or name.startswith("test_skip_eager")): setattr(cls, name, base_decorator(value)) return cls -- GitLab From f4f859072f7168190dea6b3f6a1a50bfde728eb1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 16:27:43 -0800 Subject: [PATCH 425/672] Tests for placeholder_with_default PiperOrigin-RevId: 223078802 --- tensorflow/lite/build_def.bzl | 1 + tensorflow/lite/testing/generate_examples.py | 27 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tensorflow/lite/build_def.bzl b/tensorflow/lite/build_def.bzl index fcd7255910..5d615f0c5a 100644 --- a/tensorflow/lite/build_def.bzl +++ b/tensorflow/lite/build_def.bzl @@ -269,6 +269,7 @@ def generated_test_models(): "pack", "pad", "padv2", + "placeholder_with_default", "prelu", "pow", "range", diff --git a/tensorflow/lite/testing/generate_examples.py b/tensorflow/lite/testing/generate_examples.py index 5218844299..b143f45b32 100644 --- a/tensorflow/lite/testing/generate_examples.py +++ b/tensorflow/lite/testing/generate_examples.py @@ -3528,6 +3528,33 @@ def make_unroll_batch_matmul_tests(zip_path): make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) +def make_placeholder_with_default_tests(zip_path): + """Make a set of tests to test placeholder_with_default.""" + + test_parameters = [{ + "dtype": [tf.float32, tf.int32, tf.int64], + }] + + def build_graph(parameters): + """Build the placeholder_with_default testing graph.""" + const_node = tf.constant( + [1, 2, 2, 0], shape=[2, 2], dtype=parameters["dtype"]) + input_tensor = tf.placeholder_with_default( + const_node, shape=[2, 2], name="input") + out = tf.equal(input_tensor, const_node, name="output") + + return [input_tensor], [out] + + def build_inputs(parameters, sess, inputs, outputs): + numpy_type = _TF_TYPE_INFO[parameters["dtype"]][0] + input_value = np.array([[1, 0], [2, 1]], numpy_type) + return [input_value], sess.run( + outputs, feed_dict=dict(zip(inputs, [input_value]))) + + make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs, + expected_tf_success=3) + + # Toco binary path provided by the generate rule. bin_path = None -- GitLab From f1d0c84f699624382c8d66e2ea10205ac0207868 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 16:29:56 -0800 Subject: [PATCH 426/672] Skip overflow testing when running with address sanitizer. PiperOrigin-RevId: 223079147 --- .../experimental/micro/examples/micro_speech/timer_test.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc index 83a2dfcc65..0487a12b25 100644 --- a/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc +++ b/tensorflow/lite/experimental/micro/examples/micro_speech/timer_test.cc @@ -26,10 +26,13 @@ TF_LITE_MICRO_TESTS_BEGIN TF_LITE_MICRO_TEST(TestTimer) { // Make sure that the technically-undefined overflow behavior we rely on below // works on this platform. It's still not guaranteed, but at least this is a - // sanity check. + // sanity check. Turn off when running with ASan, as it will complain about + // the following undefined behavior. +#ifndef ADDRESS_SANITIZER int32_t overflow_value = std::numeric_limits::max(); overflow_value += 1; TF_LITE_MICRO_EXPECT_EQ(std::numeric_limits::min(), overflow_value); +#endif const int32_t first_time = TimeInMilliseconds(); const int32_t second_time = TimeInMilliseconds(); -- GitLab From 6f09a093d1e5e6947204db1b5fc1d85032e6a78d Mon Sep 17 00:00:00 2001 From: Asim Shankar Date: Tue, 27 Nov 2018 16:29:56 -0800 Subject: [PATCH 427/672] [Go]: Fix #23257 By temporarily disabling the features introduced in PR #20412 Will re-enable after the C libraries for TensorFlow 1.13 or later have been released. PiperOrigin-RevId: 223079148 --- tensorflow/go/graph.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go index 702ce85228..6ff41ca916 100644 --- a/tensorflow/go/graph.go +++ b/tensorflow/go/graph.go @@ -112,9 +112,17 @@ func (g *Graph) ImportWithOptions(def []byte, options GraphImportOptions) error C.TF_ImportGraphDefOptionsSetPrefix(opts, cprefix) if len(options.Device) != 0 { - cdev := C.CString(options.Device) - defer C.free(unsafe.Pointer(cdev)) - C.TF_ImportGraphDefOptionsSetDefaultDevice(opts, cdev) + // TODO(ashankar): Remove this error and uncomment below + // when a release of the C library which includes + // https://github.com/tensorflow/tensorflow/commit/e0af5ac53e5a8ad9b07cdd5738c0a8e12f938c4e + // has been made. + // See https://github.com/tensorflow/tensorflow/issues/23257 + return fmt.Errorf("GraphImportOptions.Device is only supported with the TensorFlow C library versions after 1.12 (or built from master). See https://github.com/tensorflow/tensorflow/issues/23257") + /* + cdev := C.CString(options.Device) + defer C.free(unsafe.Pointer(cdev)) + C.TF_ImportGraphDefOptionsSetDefaultDevice(opts, cdev) + */ } buf := C.TF_NewBuffer() -- GitLab From 8bf4052fc3123cb141bccd67b007fb084d319d12 Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Tue, 27 Nov 2018 16:39:09 -0800 Subject: [PATCH 428/672] Fix binary accuracy test. Remove the old stateful metrics test. PiperOrigin-RevId: 223080473 --- tensorflow/python/keras/metrics_test.py | 118 ------------------------ 1 file changed, 118 deletions(-) diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index eda434391e..536f717517 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -28,13 +28,10 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.keras import backend as K -from tensorflow.python.keras import layers from tensorflow.python.keras import metrics -from tensorflow.python.keras.engine.training import Model from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops -from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.training.checkpointable import util as checkpointable_utils @@ -131,116 +128,6 @@ class KerasMetricsTest(test.TestCase): result = K.eval(metrics.top_k_categorical_accuracy(y_true, y_pred, k=1)) self.assertEqual(result, 0.) - def test_stateful_metrics(self): - with self.cached_session(): - np.random.seed(1334) - - class BinaryTruePositives(layers.Layer): - """Stateful Metric to count the total true positives over all batches. - - Assumes predictions and targets of shape `(samples, 1)`. - - Arguments: - threshold: Float, lower limit on prediction value that counts as a - positive class prediction. - name: String, name for the metric. - """ - - def __init__(self, name='true_positives', **kwargs): - super(BinaryTruePositives, self).__init__(name=name, **kwargs) - self.true_positives = K.variable(value=0, dtype='int32') - self.stateful = True - - def reset_states(self): - K.set_value(self.true_positives, 0) - - def __call__(self, y_true, y_pred): - """Computes the number of true positives in a batch. - - Args: - y_true: Tensor, batch_wise labels - y_pred: Tensor, batch_wise predictions - - Returns: - The total number of true positives seen this epoch at the - completion of the batch. - """ - y_true = math_ops.cast(y_true, 'int32') - y_pred = math_ops.cast(math_ops.round(y_pred), 'int32') - correct_preds = math_ops.cast(math_ops.equal(y_pred, y_true), 'int32') - true_pos = math_ops.cast( - math_ops.reduce_sum(correct_preds * y_true), 'int32') - current_true_pos = self.true_positives * 1 - self.add_update( - state_ops.assign_add(self.true_positives, true_pos), - inputs=[y_true, y_pred]) - return current_true_pos + true_pos - - metric_fn = BinaryTruePositives() - config = metrics.serialize(metric_fn) - metric_fn = metrics.deserialize( - config, custom_objects={'BinaryTruePositives': BinaryTruePositives}) - - # Test on simple model - inputs = layers.Input(shape=(2,)) - outputs = layers.Dense(1, activation='sigmoid')(inputs) - model = Model(inputs, outputs) - model.compile(optimizer='sgd', - loss='binary_crossentropy', - metrics=['acc', metric_fn]) - - # Test fit, evaluate - samples = 100 - x = np.random.random((samples, 2)) - y = np.random.randint(2, size=(samples, 1)) - val_samples = 10 - val_x = np.random.random((val_samples, 2)) - val_y = np.random.randint(2, size=(val_samples, 1)) - - history = model.fit(x, y, - epochs=1, - batch_size=10, - validation_data=(val_x, val_y)) - outs = model.evaluate(x, y, batch_size=10) - preds = model.predict(x) - - def ref_true_pos(y_true, y_pred): - return np.sum(np.logical_and(y_pred > 0.5, y_true == 1)) - - # Test correctness (e.g. updates should have been run) - self.assertAllClose(outs[2], ref_true_pos(y, preds), atol=1e-5) - - # Test correctness of the validation metric computation - val_preds = model.predict(val_x) - val_outs = model.evaluate(val_x, val_y, batch_size=10) - self.assertAllClose( - val_outs[2], ref_true_pos(val_y, val_preds), atol=1e-5) - self.assertAllClose( - val_outs[2], history.history['val_true_positives'][-1], atol=1e-5) - - # Test with generators - gen = [(np.array([x0]), np.array([y0])) for x0, y0 in zip(x, y)] - val_gen = [(np.array([x0]), np.array([y0])) - for x0, y0 in zip(val_x, val_y)] - history = model.fit_generator(iter(gen), - epochs=1, - steps_per_epoch=samples, - validation_data=iter(val_gen), - validation_steps=val_samples) - outs = model.evaluate_generator(iter(gen), steps=samples) - preds = model.predict_generator(iter(gen), steps=samples) - - # Test correctness of the metric results - self.assertAllClose(outs[2], ref_true_pos(y, preds), atol=1e-5) - - # Test correctness of the validation metric computation - val_preds = model.predict_generator(iter(val_gen), steps=val_samples) - val_outs = model.evaluate_generator(iter(val_gen), steps=val_samples) - self.assertAllClose( - val_outs[2], ref_true_pos(val_y, val_preds), atol=1e-5) - self.assertAllClose( - val_outs[2], history.history['val_true_positives'][-1], atol=1e-5) - @test_util.run_in_graph_and_eager_modes(assert_no_eager_garbage=True) def test_mean(self): m = metrics.Mean(name='my_mean') @@ -423,11 +310,6 @@ class KerasMetricsTest(test.TestCase): result = self.evaluate(result_t) self.assertAlmostEqual(result, 0.67, 2) # 4.5/6.7 - # check incompatible shapes - with self.assertRaisesRegexp(ValueError, - r'Shapes \(1,\) and \(2,\) are incompatible'): - acc_obj.update_state([1, 1], [1]) - @test_util.run_in_graph_and_eager_modes def test_binary_accuracy_threshold(self): acc_obj = metrics.BinaryAccuracy(threshold=0.7) -- GitLab From a461299229410d886aaf31e9998ffc7b53f70708 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Tue, 27 Nov 2018 16:44:18 -0800 Subject: [PATCH 429/672] [tf.data] Remove `tf.data.Iterator` from the V2 API. In TensorFlow 2.0, iterating over a `tf.data.Dataset` is possible using a standard Python for loop: ```python dataset = tf.data.Dataset.from_tensor_slices((features, labels)).batch(bs) for feature_batch, label_batch in dataset: # Train on one minibatch. ``` Since eager execution allows iterators to be created and bound to computation dynamically, there is no need for the concepts of "one-shot", "initializable", "feedable", and "reinitializable" iterators. This change is a step towards simplifying the `tf.data` API. PiperOrigin-RevId: 223081239 --- tensorflow/python/data/ops/iterator_ops.py | 2 +- .../golden/v2/tensorflow.data.-iterator.pbtxt | 46 ------------------- .../tools/api/golden/v2/tensorflow.data.pbtxt | 4 -- 3 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.data.-iterator.pbtxt diff --git a/tensorflow/python/data/ops/iterator_ops.py b/tensorflow/python/data/ops/iterator_ops.py index 68b03ba93b..e2ca64c802 100644 --- a/tensorflow/python/data/ops/iterator_ops.py +++ b/tensorflow/python/data/ops/iterator_ops.py @@ -68,7 +68,7 @@ def _device_stack_is_empty(): return not bool(device_stack) -@tf_export("data.Iterator") +@tf_export(v1=["data.Iterator"]) class Iterator(checkpointable.CheckpointableBase): """Represents the state of iterating through a `Dataset`.""" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.-iterator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.-iterator.pbtxt deleted file mode 100644 index 4f0147a523..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.-iterator.pbtxt +++ /dev/null @@ -1,46 +0,0 @@ -path: "tensorflow.data.Iterator" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "initializer" - mtype: "" - } - member { - name: "output_classes" - mtype: "" - } - member { - name: "output_shapes" - mtype: "" - } - member { - name: "output_types" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'iterator_resource\', \'initializer\', \'output_types\', \'output_shapes\', \'output_classes\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "from_string_handle" - argspec: "args=[\'string_handle\', \'output_types\', \'output_shapes\', \'output_classes\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "from_structure" - argspec: "args=[\'output_types\', \'output_shapes\', \'shared_name\', \'output_classes\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " - } - member_method { - name: "get_next" - argspec: "args=[\'self\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "make_initializer" - argspec: "args=[\'self\', \'dataset\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "string_handle" - argspec: "args=[\'self\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.pbtxt index 509bbae833..4c3d6ddd85 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.pbtxt @@ -8,10 +8,6 @@ tf_module { name: "FixedLengthRecordDataset" mtype: "" } - member { - name: "Iterator" - mtype: "" - } member { name: "Options" mtype: "" -- GitLab From a50880247b9faf245b3c5ea77729e3a4edcb0be1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 17:15:16 -0800 Subject: [PATCH 430/672] Make pfor compatible with Eager execution. PiperOrigin-RevId: 223085811 --- tensorflow/python/eager/backprop.py | 34 +-- .../ops/parallel_for/control_flow_ops.py | 11 + .../ops/parallel_for/control_flow_ops_test.py | 227 +++++++++++------- 3 files changed, 158 insertions(+), 114 deletions(-) diff --git a/tensorflow/python/eager/backprop.py b/tensorflow/python/eager/backprop.py index beed1d5de3..69d444a90e 100644 --- a/tensorflow/python/eager/backprop.py +++ b/tensorflow/python/eager/backprop.py @@ -1015,12 +1015,8 @@ class GradientTape(object): target_size = array_ops.shape(target)[0] if experimental_use_pfor: - def f(): - return pfor_ops.pfor(loop_fn, target_size) - if context.executing_eagerly(): - f = function.defun(f) try: - output = f() + output = pfor_ops.pfor(loop_fn, target_size) except ValueError as err: six.reraise( ValueError, @@ -1030,12 +1026,11 @@ class GradientTape(object): " experimental_use_pfor to False."), sys.exc_info()[2]) else: - if context.executing_eagerly(): - if not self._persistent: - raise RuntimeError( - "GradientTape must be created with persistent=True" - " to compute the jacobian with eager execution enabled and with " - " experimental_use_pfor set to False.") + if context.executing_eagerly() and not self._persistent: + raise RuntimeError( + "GradientTape must be created with persistent=True" + " to compute the jacobian with eager execution enabled and with " + " experimental_use_pfor set to False.") output = pfor_ops.for_loop( loop_fn, [target.dtype] * len(flat_sources), target_size) @@ -1131,12 +1126,8 @@ class GradientTape(object): unconnected_gradients=unconnected_gradients) if experimental_use_pfor: - def f(): - return pfor_ops.pfor(loop_fn, target_row_size) - if context.executing_eagerly(): - f = function.defun(f) try: - output = f() + output = pfor_ops.pfor(loop_fn, target_row_size) except ValueError as err: six.reraise( ValueError, @@ -1146,12 +1137,11 @@ class GradientTape(object): "setting experimental_use_pfor to False."), sys.exc_info()[2]) else: - if context.executing_eagerly(): - if not self._persistent: - raise RuntimeError( - "GradientTape must be created with persistent=True" - " to compute the batch_jacobian with eager execution enabled and " - " with experimental_use_pfor set to False.") + if context.executing_eagerly() and not self._persistent: + raise RuntimeError( + "GradientTape must be created with persistent=True" + " to compute the batch_jacobian with eager execution enabled and " + " with experimental_use_pfor set to False.") output = pfor_ops.for_loop(loop_fn, target.dtype, target_row_size) if output is None: return None diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops.py b/tensorflow/python/ops/parallel_for/control_flow_ops.py index 3c818f3d6c..8f652e9c50 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops.py @@ -17,6 +17,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.eager import context +from tensorflow.python.eager import function from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_util @@ -142,6 +144,15 @@ def pfor(loop_fn, iters, parallel_iterations=None): Raises: ValueError: If parallel_iterations is not None and not an integer > 1. """ + def f(): + return _pfor_impl(loop_fn, iters, parallel_iterations=parallel_iterations) + if context.executing_eagerly(): + f = function.defun(f) + return f() + + +def _pfor_impl(loop_fn, iters, parallel_iterations=None): + """Implementation of pfor.""" existing_ops = set(ops.get_default_graph().get_operations()) with ops.name_scope("loop_body"): loop_var = array_ops.placeholder(dtypes.int32, shape=[]) diff --git a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py index 017bc9dae5..c2484766aa 100644 --- a/tensorflow/python/ops/parallel_for/control_flow_ops_test.py +++ b/tensorflow/python/ops/parallel_for/control_flow_ops_test.py @@ -26,10 +26,12 @@ import numpy as np from tensorflow.core.example import example_pb2 from tensorflow.core.example import feature_pb2 from tensorflow.python.client import session +from tensorflow.python.eager import backprop from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import bitwise_ops from tensorflow.python.ops import clip_ops @@ -52,6 +54,7 @@ from tensorflow.python.platform import test from tensorflow.python.util import nest +@test_util.run_all_in_graph_and_eager_modes class PForTest(test.TestCase): def _run_targets(self, targets1, targets2=None, run_init=True): @@ -125,6 +128,7 @@ class PForTest(test.TestCase): pfor_control_flow_ops.pfor(lambda i: 1, 8, parallel_iterations=1) +@test_util.run_all_in_graph_and_eager_modes class ArrayTest(PForTest): def test_gather(self): @@ -316,14 +320,17 @@ class ArrayTest(PForTest): def test_unary_cwise_ops(self): for op in [array_ops.identity, array_ops.stop_gradient]: - x = random_ops.random_uniform([3, 5]) + with backprop.GradientTape(persistent=True) as g: + x = random_ops.random_uniform([3, 5]) + g.watch(x) # pylint: disable=cell-var-from-loop def loop_fn(i): - x1 = array_ops.gather(x, i) - y = op(x1) + x1 - loss = nn.l2_loss(y) - return op(x), y, gradient_ops.gradients(loss, x1) + with g: + x1 = array_ops.gather(x, i) + y = op(x1) + x1 + loss = nn.l2_loss(y) + return op(x), y, g.gradient(loss, x1) # pylint: enable=cell-var-from-loop @@ -346,17 +353,21 @@ class ArrayTest(PForTest): self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32]) def test_strided_slice(self): - x = random_ops.random_uniform([3, 3, 4, 4, 2, 2, 2]) + with backprop.GradientTape(persistent=True) as g: + x = random_ops.random_uniform([3, 3, 4, 4, 2, 2, 2]) + g.watch(x) def loop_fn(i): - x_i = array_ops.gather(x, i) - y = x_i[:2, ::2, 1::3, ..., array_ops.newaxis, 1] - loss = nn.l2_loss(y) - return y, gradient_ops.gradients(loss, x_i) + with g: + x_i = array_ops.gather(x, i) + y = x_i[:2, ::2, 1::3, ..., array_ops.newaxis, 1] + loss = nn.l2_loss(y) + return y, g.gradient(loss, x_i) self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 2) +@test_util.run_all_in_graph_and_eager_modes class BitwiseTest(PForTest): def test_unary_cwise(self): @@ -396,6 +407,7 @@ class BitwiseTest(PForTest): self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=output_dtypes) +@test_util.run_all_in_graph_and_eager_modes class MathTest(PForTest): def test_unary_cwise_ops(self): @@ -452,22 +464,29 @@ class MathTest(PForTest): nn.softsign, ] for op in complex_ops + real_ops: - x = random_ops.random_uniform([3, 5]) - if op in complex_ops: - y = random_ops.random_uniform([3, 5]) - x = math_ops.complex(x, y) + with backprop.GradientTape(persistent=True) as g: + x = random_ops.random_uniform([3, 5]) + g.watch(x) + if op in complex_ops: + y = random_ops.random_uniform([3, 5]) + g.watch(y) + x = math_ops.complex(x, y) # pylint: disable=cell-var-from-loop output_dtypes = [] def loop_fn(i): - x1 = array_ops.gather(x, i) - y1 = op(x1) - outputs = [op(x), y1] - if y1.dtype == dtypes.float32: - loss = math_ops.reduce_sum(y1 * y1) - grad = gradient_ops.gradients(loss, x1) - if grad and grad[0] is not None: - outputs.extend(grad) + with g: + x1 = array_ops.gather(x, i) + y1 = op(x1) + outputs = [op(x), y1] + if y1.dtype == dtypes.float32: + loss = math_ops.reduce_sum(y1 * y1) + else: + loss = None + if loss is not None: + grad = g.gradient(loss, x1) + if grad is not None: + outputs.append(grad) del output_dtypes[:] output_dtypes.extend([t.dtype for t in outputs]) return outputs @@ -684,17 +703,19 @@ class MathTest(PForTest): x_shape = [2, 3, 4, 5, 6] x = random_ops.random_uniform(x_shape) for data_format in ("NCHW", "NHWC"): - bias_dim = 2 if data_format == "NCHW" else -1 - bias_shape = x_shape[bias_dim] - bias = random_ops.random_uniform([bias_shape]) + with backprop.GradientTape(persistent=True) as g: + bias_dim = 2 if data_format == "NCHW" else -1 + bias_shape = x_shape[bias_dim] + bias = random_ops.random_uniform([bias_shape]) + g.watch(bias) # pylint: disable=cell-var-from-loop def loop_fn(i): - a = array_ops.gather(x, i) - y = nn.bias_add(a, bias, data_format=data_format) - loss = math_ops.reduce_sum(y * y) - return y, gradient_ops.gradients(loss, bias) - + with g: + a = array_ops.gather(x, i) + y = nn.bias_add(a, bias, data_format=data_format) + loss = math_ops.reduce_sum(y * y) + return y, g.gradient(loss, bias) # pylint: enable=cell-var-from-loop self._test_loop_fn( @@ -755,6 +776,7 @@ class MathTest(PForTest): self._test_loop_fn(loop_fn, 2) +@test_util.run_all_in_graph_and_eager_modes class NNTest(PForTest): def test_conv2d(self): @@ -807,48 +829,60 @@ class NNTest(PForTest): self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 2) def test_avg_pool(self): - x = random_ops.random_uniform([3, 2, 12, 12, 3]) - ksize = [1, 3, 3, 1] + with backprop.GradientTape(persistent=True) as g: + x = random_ops.random_uniform([3, 2, 12, 12, 3]) + g.watch(x) + ksize = [1, 3, 3, 1] def loop_fn(i): - x1 = array_ops.gather(x, i) - output = nn.avg_pool( - x1, ksize, strides=[1, 2, 2, 1], padding="VALID", data_format="NHWC") - loss = nn.l2_loss(output) - return output, gradient_ops.gradients(loss, x1) + with g: + x1 = array_ops.gather(x, i) + output = nn.avg_pool( + x1, ksize, strides=[1, 2, 2, 1], padding="VALID", + data_format="NHWC") + loss = nn.l2_loss(output) + return output, g.gradient(loss, x1) self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 2) def test_max_pool(self): - x = random_ops.random_uniform([3, 2, 12, 12, 3]) - ksize = [1, 3, 3, 1] - strides = [1, 2, 2, 1] + with backprop.GradientTape(persistent=True) as g: + x = random_ops.random_uniform([3, 2, 12, 12, 3]) + g.watch(x) + ksize = [1, 3, 3, 1] + strides = [1, 2, 2, 1] def loop_fn(i): - x1 = array_ops.gather(x, i) - output = nn.max_pool( - x1, ksize, strides=strides, padding="VALID", data_format="NHWC") - loss = nn.l2_loss(output) - ones = array_ops.ones_like(output) - grad = gradient_ops.gradients(loss, x1, grad_ys=ones) - grad_grad = gradient_ops.gradients(grad, ones) + with g: + x1 = array_ops.gather(x, i) + output = nn.max_pool( + x1, ksize, strides=strides, padding="VALID", data_format="NHWC") + loss = nn.l2_loss(output) + ones = array_ops.ones_like(output) + g.watch(ones) + grad = g.gradient(loss, x1, output_gradients=ones) + grad_grad = g.gradient(grad, ones) return output, grad, grad_grad self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 3) def test_max_pool3d(self): - x = random_ops.random_uniform([3, 3, 2, 12, 12, 3]) - ksize = [1, 1, 3, 3, 1] - strides = [1, 1, 2, 2, 1] + with backprop.GradientTape(persistent=True) as g: + x = random_ops.random_uniform([3, 3, 2, 12, 12, 3]) + g.watch(x) + ksize = [1, 1, 3, 3, 1] + strides = [1, 1, 2, 2, 1] def loop_fn(i): - x1 = array_ops.gather(x, i) - output = nn.max_pool3d( - x1, ksize, strides=strides, padding="VALID", data_format="NDHWC") - loss = nn.l2_loss(output) - ones = array_ops.ones_like(output) - grad = gradient_ops.gradients(loss, x1, grad_ys=ones) - grad_grad = gradient_ops.gradients(grad, ones) + with g: + x1 = array_ops.gather(x, i) + output = nn.max_pool3d( + x1, ksize, strides=strides, padding="VALID", data_format="NDHWC") + loss = nn.l2_loss(output) + ones = array_ops.ones_like(output) + g.watch(ones) + grad = g.gradient(loss, x1, output_gradients=ones) + grad_grad = g.gradient(grad, ones) return output, grad, grad_grad self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 3) @@ -859,36 +893,41 @@ class NNTest(PForTest): data_formats.append("NCHW") for is_training in (True, False): for data_format in data_formats: - if data_format == "NCHW": - x = random_ops.random_uniform([3, 1, 2, 5, 5]) - else: - x = random_ops.random_uniform([3, 1, 5, 5, 2]) - scale = random_ops.random_uniform([2]) - offset = random_ops.random_uniform([2]) - mean = None if is_training else random_ops.random_uniform([2]) - variance = None if is_training else random_ops.random_uniform([2]) + with backprop.GradientTape(persistent=True) as g: + if data_format == "NCHW": + x = random_ops.random_uniform([3, 1, 2, 5, 5]) + else: + x = random_ops.random_uniform([3, 1, 5, 5, 2]) + g.watch(x) + scale = random_ops.random_uniform([2]) + g.watch(scale) + offset = random_ops.random_uniform([2]) + g.watch(offset) + mean = None if is_training else random_ops.random_uniform([2]) + variance = None if is_training else random_ops.random_uniform([2]) # pylint: disable=cell-var-from-loop def loop_fn(i): - x1 = array_ops.gather(x, i) - outputs = nn.fused_batch_norm( - x1, - scale, - offset, - mean=mean, - variance=variance, - epsilon=0.01, - data_format=data_format, - is_training=is_training) - outputs = list(outputs) - # We only test the first value of outputs when is_training is False. - # It looks like CPU and GPU have different outputs for batch_mean and - # batch_variance for this case. - if not is_training: - outputs[1] = constant_op.constant(0.) - outputs[2] = constant_op.constant(0.) - loss = nn.l2_loss(outputs[0]) - gradients = gradient_ops.gradients(loss, [x1, scale, offset]) + with g: + x1 = array_ops.gather(x, i) + outputs = nn.fused_batch_norm( + x1, + scale, + offset, + mean=mean, + variance=variance, + epsilon=0.01, + data_format=data_format, + is_training=is_training) + outputs = list(outputs) + # We only test the first value of outputs when is_training is False. + # It looks like CPU and GPU have different outputs for batch_mean + # and batch_variance for this case. + if not is_training: + outputs[1] = constant_op.constant(0.) + outputs[2] = constant_op.constant(0.) + loss = nn.l2_loss(outputs[0]) + gradients = g.gradient(loss, [x1, scale, offset]) return outputs + gradients # pylint: enable=cell-var-from-loop @@ -896,16 +935,20 @@ class NNTest(PForTest): self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 6) def test_softmax_cross_entropy_with_logits(self): - logits = random_ops.random_uniform([3, 2, 4]) - labels = random_ops.random_uniform([3, 2, 4]) - labels /= math_ops.reduce_sum(labels, axis=[2], keepdims=True) + with backprop.GradientTape(persistent=True) as g: + logits = random_ops.random_uniform([3, 2, 4]) + g.watch(logits) + labels = random_ops.random_uniform([3, 2, 4]) + labels /= math_ops.reduce_sum(labels, axis=[2], keepdims=True) def loop_fn(i): - logits_i = array_ops.gather(logits, i) - labels_i = array_ops.gather(labels, i) - loss = nn.softmax_cross_entropy_with_logits( - labels=labels_i, logits=logits_i) - return loss, gradient_ops.gradients(math_ops.reduce_sum(loss), logits_i) + with g: + logits_i = array_ops.gather(logits, i) + labels_i = array_ops.gather(labels, i) + loss = nn.softmax_cross_entropy_with_logits( + labels=labels_i, logits=logits_i) + total_loss = math_ops.reduce_sum(loss) + return loss, g.gradient(total_loss, logits_i) self._test_loop_fn(loop_fn, 3, loop_fn_dtypes=[dtypes.float32] * 2) -- GitLab From 34b397c662adda53da5186b7a95267bed60b1b17 Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Tue, 27 Nov 2018 17:26:55 -0800 Subject: [PATCH 431/672] Remove duplicated code from function optimizer and prepare for indirect function calls inlining (PartitionedCallOp). PiperOrigin-RevId: 223087215 --- tensorflow/core/grappler/op_types.cc | 9 +- tensorflow/core/grappler/op_types.h | 5 +- .../grappler/optimizers/function_optimizer.cc | 199 +++++++++--------- 3 files changed, 115 insertions(+), 98 deletions(-) diff --git a/tensorflow/core/grappler/op_types.cc b/tensorflow/core/grappler/op_types.cc index 06248393ba..38fc1fff32 100644 --- a/tensorflow/core/grappler/op_types.cc +++ b/tensorflow/core/grappler/op_types.cc @@ -551,14 +551,15 @@ bool MaybeHasRefInput(const NodeDef& node) { return false; } -bool IsFreeOfSideEffect(const NodeDef& node) { +bool IsFreeOfSideEffect(const NodeDef& node, + const OpRegistryInterface* op_registry) { // Placeholders must be preserved to keep the graph feedable. if (IsPlaceholder(node)) { return false; } const OpDef* op_def = nullptr; const string& op_name = node.op(); - Status status = OpRegistry::Global()->LookUpOpDef(op_name, &op_def); + Status status = op_registry->LookUpOpDef(op_name, &op_def); if (!status.ok()) { return false; } @@ -582,6 +583,10 @@ bool IsFreeOfSideEffect(const NodeDef& node) { return !ModifiesInputsInPlace(node); } +bool IsFreeOfSideEffect(const NodeDef& node) { + return IsFreeOfSideEffect(node, OpRegistry::Global()); +} + bool ModifiesInputsInPlace(const NodeDef& node) { // Some nodes do in-place updates on regular tensor inputs. string op_name = node.op(); diff --git a/tensorflow/core/grappler/op_types.h b/tensorflow/core/grappler/op_types.h index bd286f2c72..67897e8512 100644 --- a/tensorflow/core/grappler/op_types.h +++ b/tensorflow/core/grappler/op_types.h @@ -17,6 +17,7 @@ limitations under the License. #define TENSORFLOW_CORE_GRAPPLER_OP_TYPES_H_ #include "tensorflow/core/framework/node_def.pb.h" +#include "tensorflow/core/framework/op.h" #include "tensorflow/core/lib/core/status.h" namespace tensorflow { @@ -180,7 +181,9 @@ bool IsCommutative(const NodeDef& node); // value. bool IsPersistent(const NodeDef& node); -bool IsFreeOfSideEffect(const NodeDef& node); +bool IsFreeOfSideEffect(const NodeDef& node, + const OpRegistryInterface* op_registry); +bool IsFreeOfSideEffect(const NodeDef& node); // use OpRegistry::Global() // Returns true if the takes a tensor reference as input, or if looking up its // OpDef failed. diff --git a/tensorflow/core/grappler/optimizers/function_optimizer.cc b/tensorflow/core/grappler/optimizers/function_optimizer.cc index f8ddbeb659..22013ea2db 100644 --- a/tensorflow/core/grappler/optimizers/function_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/function_optimizer.cc @@ -220,13 +220,15 @@ class FunctionOptimizerContext { const GrapplerItem& item) : grappler_item_id_(item.id), graph_version_(item.graph.versions().producer()), + opt_level_(opt_level), function_library_(OpRegistry::Global(), item.graph.library()), graph_view_(&item.graph) { InitializeTrulyConstNodes(item); - InitializeInlinedFunctions(opt_level, item); InitializeFetchNodes(item); } + const RewriterConfig::Toggle opt_level() const { return opt_level_; } + const FunctionLibraryDefinition& function_library() const { return function_library_; } @@ -255,10 +257,6 @@ class FunctionOptimizerContext { return fetch_nodes_.find(node_name) != fetch_nodes_.end(); } - bool IsInlinedFunction(const string& name) const { - return inlined_functions_.count(name) > 0; - } - bool IsTrulyConst(const string& name) const { return TrulyConstNode(name) != nullptr; } @@ -267,11 +265,6 @@ class FunctionOptimizerContext { return gtl::FindWithDefault(truly_const_nodes_, name, nullptr); } - // Find inlining candidate by name. Return nullptr if not found. - const FunctionDef* FindInlinedFunction(const string& name) const { - return gtl::FindWithDefault(inlined_functions_, name, nullptr); - } - const FunctionSpecialization* FindFunctionSpecialization( const FunctionSpecializationSignature& sig) const { return gtl::FindOrNull(specialized_functions_, sig); @@ -312,26 +305,6 @@ class FunctionOptimizerContext { } } - void InitializeInlinedFunctions(RewriterConfig::Toggle opt_level, - const GrapplerItem& item) { - bool aggressive = opt_level == RewriterConfig::AGGRESSIVE; - - for (const FunctionDef& func : item.graph.library().function()) { - // Can't create IdentityN nodes with no input or output: skip these - // functions for now. - if (func.signature().input_arg_size() == 0 || - func.signature().output_arg_size() == 0) { - continue; - } - bool marked_noinline = MarkedNoInline(func); - bool marked_specialized = MarkedSpecialized(func); - - if (!marked_specialized && (!marked_noinline || aggressive)) { - inlined_functions_[func.signature().name()] = &func; - } - } - } - void InitializeFetchNodes(const GrapplerItem& item) { for (const string& fetch : item.fetch) { fetch_tensors_.insert(fetch); @@ -359,6 +332,7 @@ class FunctionOptimizerContext { const string grappler_item_id_; const int graph_version_; + const RewriterConfig::Toggle opt_level_; FunctionLibraryDefinition function_library_; // These fields initialized lazily only if needed. @@ -366,8 +340,6 @@ class FunctionOptimizerContext { std::unique_ptr process_flr_; FunctionLibraryRuntime* flr_ = nullptr; - // Functions that can be inlined into optimized graph. - std::unordered_map inlined_functions_; // Nodes that are Const and not in feed. std::unordered_map truly_const_nodes_; // Specialized functions. @@ -390,6 +362,65 @@ class FunctionOptimizerContext { TF_DISALLOW_COPY_AND_ASSIGN(FunctionOptimizerContext); }; +// Returns a pointer to the called function definition iff the given node is +// indeed a function call. Otherwise returns nullptr. +const FunctionDef* FindFunctionCall(const FunctionOptimizerContext& ctx, + const NodeDef& node) { + // Check if a node does indirect function call via PartitionedCallOp. + if (IsPartitionedCall(node) || IsStatefulPartitionedCall(node)) { + const AttrValue* func_attr = AttrSlice(node).Find("f"); + return (func_attr != nullptr && func_attr->has_func()) + ? ctx.function_library().Find(func_attr->func().name()) + : nullptr; + } + + // Check if the function op itself is a function name. + return ctx.function_library().Find(node.op()); +} + +// Returns true iff `node` is a direct function call of `func`, and we know how +// to inline it into the main graph. +bool IsInlinableDirectFunctionCall(const FunctionOptimizerContext& ctx, + const FunctionDef& func, + const NodeDef& node) { + // Indirect function calls (PartitionedCallOp) have automatic control + // dependencies and inlined separately from direct function calls. + bool is_direct_function_call = IsDirectFunctionCall(func, node); + + // For direct function calls we insert IdentityN nodes before/after inlined + // function body to preserve function call semantics (all inputs evaluated + // before function evaluation starts, and all function body nodes finished + // before output consumed by other nodes). + bool has_inputs = func.signature().input_arg_size() > 0; + // TODO(ezhulenev): Relax constraint on output args? + bool has_outputs = func.signature().output_arg_size() > 0; + + // Function must execute all the nodes in a function body that might have side + // effects. After inlining these nodes into the main graph, we can no longer + // guarantee that. For now we disable inlining functions with side effects. + // + // Attaching control dependency to the output IdentityN node is not safe, + // because it might be split or pruned in a later optimization pass. + // + // Indirect function calls (via PartitionedCallOp) have automatic dependency + // tracking, and allow us to safely inline functions with side effects. + bool free_of_side_effects = + std::all_of(func.node_def().begin(), func.node_def().end(), + [&ctx](const NodeDef& node) { + return IsFreeOfSideEffect(node, &ctx.function_library()); + }); + + bool marked_noinline = MarkedNoInline(func); + bool marked_specialized = MarkedSpecialized(func); + + // We ignore `_noinline` marker in aggressive mode. + bool aggressive = ctx.opt_level() == RewriterConfig::AGGRESSIVE; + + return is_direct_function_call && has_inputs && has_outputs && + free_of_side_effects && !marked_specialized && + (!marked_noinline || aggressive); +} + gtl::FlatSet GetActiveOutputs(const NodeDef& node, const FunctionOptimizerContext& ctx, int size_hint = 0) { @@ -608,6 +639,9 @@ Status UpdateSpecializedFunctionNode( // 2. Remove inputs corresponding to the pushed down consts. RemovePushedDownConstInputs(specialization, specialized_func_node); + // NOTE: PartitionedCallOp has `Tin` and `Tout` attributes for input/output + // types, that must be in sync with updated function signature. + // 3. Update input types for the indirect function calls. if (is_indirect_call) { RemovePushedDownConstInputTypes(specialization, func_node, @@ -805,13 +839,16 @@ NodeDef InlinedFunctionOutputsNode(const NodeDef& func_node, return outputs; } -Status InlineFunction(const NodeDef& func_node, const FunctionDef& func, - const FunctionOptimizerContext& ctx, - const int graph_def_version, GraphDef* optimized_graph) { - VLOG(2) << "Inline function instantiation: " << SummarizeNodeDef(func_node); +Status InlineDirectFunctionCall(const NodeDef& func_node, + const FunctionDef& func, + const FunctionOptimizerContext& ctx, + const int graph_def_version, + GraphDef* optimized_graph) { + VLOG(2) << "Inline direct function call: " << SummarizeNodeDef(func_node); - // Specialized function call kernels might have behavior that is not - // representable in a graph (e.g. runtime ops device placing). + // Indirect function calls (via PartitionedCallOp) have automatic control + // dependencies, and doesn't need IdentityN nodes before/after inlined + // function body, and we inline them separately. if (!IsDirectFunctionCall(func, func_node)) { return errors::InvalidArgument("Can't inline indirect function call"); } @@ -877,14 +914,16 @@ Status InlineFunction(const NodeDef& func_node, const FunctionDef& func, // Make sure the node is placed. func_body_node.set_device(func_node.device()); - // Check if a body node is itself a function. + // Check if a body node is itself a function call and can be inlined. const FunctionDef* func_body_node_func = - ctx.FindInlinedFunction(func_body_node.op()); - if (func_body_node_func != nullptr) { + FindFunctionCall(ctx, func_body_node); + if (func_body_node_func != nullptr && + IsInlinableDirectFunctionCall(ctx, *func_body_node_func, + func_body_node)) { // Recursively inline function calls. - TF_RETURN_IF_ERROR(InlineFunction(func_body_node, *func_body_node_func, - ctx, graph_def_version, - optimized_graph)); + TF_RETURN_IF_ERROR( + InlineDirectFunctionCall(func_body_node, *func_body_node_func, ctx, + graph_def_version, optimized_graph)); } else { // Annotate the node with the function attributes. for (const auto& attr : func.attr()) { @@ -1015,8 +1054,6 @@ Status FunctionOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, bool specialize_func = options_.enable_function_specialization; for (const NodeDef& node : item.graph.node()) { - const string op_name = node.op(); - // Each node optimization can modify optimized graph only by adding new // nodes, we can check node size to make sure that graph was not modified. const int num_nodes_before = optimized_graph->node_size(); @@ -1045,11 +1082,13 @@ Status FunctionOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, // 1. Inline symbolic gradients into the optimized graph. // // ---------------------------------------------------------------------- // - if (op_name == "SymbolicGradient" && inline_gradients) { - // Inline symbolic gradients only if the corresponding function is inlined + if (IsSymbolicGradient(node) && inline_gradients) { + // Inline symbolic gradients only if the corresponding function is not + // marked as `_noinline`. const auto* f_attr = gtl::FindOrNull(node.attr(), "f"); - string f_name = f_attr != nullptr ? f_attr->func().name() : ""; - if (ctx.IsInlinedFunction(f_name)) { + const string f_name = f_attr != nullptr ? f_attr->func().name() : ""; + const FunctionDef* func = ctx.function_library().Find(f_name); + if (func && !MarkedNoInline(*func)) { TF_SKIP_ERROR_IF_GRAPH_UNMODIFIED( InlineSymbolicGradient(node, &ctx, optimized_graph)); continue; @@ -1057,28 +1096,33 @@ Status FunctionOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, } // ---------------------------------------------------------------------- // - // 2. Inline or specialize direct function calls. // + // 2. Inline or specialize function calls. // // ---------------------------------------------------------------------- // - const FunctionDef* func = ctx.function_library().Find(op_name); + // Find if a node is a function call (direct or indirect). + const FunctionDef* func = FindFunctionCall(ctx, node); + if (func != nullptr) { - // 2a. Inline it if it's allowed to do so. - if (inline_func && ctx.IsInlinedFunction(op_name)) { + const string& func_name = func->signature().name(); + + // 2a. Inline direct function call if it's inlinable. + if (inline_func && IsInlinableDirectFunctionCall(ctx, *func, node)) { // Inline function body into the optimized graph} - TF_SKIP_ERROR_IF_GRAPH_UNMODIFIED( - InlineFunction(node, *func, ctx, item.graph.versions().producer(), - optimized_graph)); + TF_SKIP_ERROR_IF_GRAPH_UNMODIFIED(InlineDirectFunctionCall( + node, *func, ctx, item.graph.versions().producer(), + optimized_graph)); continue; } - // Do not specialize if function has custom gradient. - const string grad_func = ctx.function_library().FindGradient(op_name); - // 2b. Specialize it to it's instantiation context if can't be inlined, // and it has something worth specializing. bool specialization_worthy = IsParametrized(*func) || HasTrulyConstInputs(node, ctx) || HasUnusedOutputs(node, *func, ctx); + + // Do not specialize if function has custom gradient. + const string grad_func = ctx.function_library().FindGradient(func_name); + if (specialize_func && grad_func.empty() && specialization_worthy) { // TODO(ezhulenev): Specialize function call if input has a known shape. // Specialize function body for its instantiation attributes and inputs. @@ -1089,41 +1133,6 @@ Status FunctionOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, } } - // ---------------------------------------------------------------------- // - // 3. Specialize indirect function calls through the PartitionedCallOp. // - // ---------------------------------------------------------------------- // - - bool is_partitioned_call = - IsPartitionedCall(node) || IsStatefulPartitionedCall(node); - - // We can only specialize PartitionedCall ops. Inlining is not supported. - if (is_partitioned_call && specialize_func) { - const AttrValue* func_attr = AttrSlice(node).Find("f"); - string indirect_func_name = - (func_attr != nullptr && func_attr->has_func()) - ? func_attr->func().name() - : ""; - const FunctionDef* indirect_func = - ctx.function_library().Find(indirect_func_name); - - if (indirect_func != nullptr) { - // Do not specialize if function has custom gradient. - const string grad_func = - ctx.function_library().FindGradient(indirect_func_name); - - // Specialize it to it's instantiation context. - bool specialization_worthy = - IsParametrized(*indirect_func) || HasTrulyConstInputs(node, ctx) || - HasUnusedOutputs(node, *indirect_func, ctx); - if (grad_func.empty() && specialization_worthy) { - TF_SKIP_ERROR_IF_GRAPH_UNMODIFIED(SpecializeFunction( - node, *indirect_func, item.graph.versions().producer(), &ctx, - optimized_graph)); - continue; - } - } - } - // ---------------------------------------------------------------------- // // If we reached this point, node was not handled by any of the stages // (inline, specialize), simply add a copy to the graph. -- GitLab From caad5b172e4c9900ea302b6680cbf0d9caba48a7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 17:58:30 -0800 Subject: [PATCH 432/672] Add a warning against calling _tf_sess() in user code. PiperOrigin-RevId: 223090908 --- tensorflow/python/training/monitored_session.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tensorflow/python/training/monitored_session.py b/tensorflow/python/training/monitored_session.py index 162fef971d..ccd9014648 100644 --- a/tensorflow/python/training/monitored_session.py +++ b/tensorflow/python/training/monitored_session.py @@ -840,6 +840,14 @@ class _MonitoredSession(object): return self._coordinated_creator.tf_sess is None def _tf_sess(self): + """Return underlying tf.Session object. + + Warning: accessing the returned object in user code is likely to cause races + or "flaky tests". + + Returns: + A tf.Session object. + """ return self._coordinated_creator.tf_sess -- GitLab From fbd5472f477c277aa1e4044d4f7e29b4ae958542 Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Tue, 27 Nov 2018 18:02:07 -0800 Subject: [PATCH 433/672] Remove metric value and update op return type check. Fixes tensorflow#23731 PiperOrigin-RevId: 223091282 --- tensorflow/python/keras/metrics.py | 17 ++-------- tensorflow/python/keras/metrics_test.py | 42 ------------------------- 2 files changed, 2 insertions(+), 57 deletions(-) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index 90babf38fd..b74b6ccf5e 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -65,13 +65,6 @@ from tensorflow.python.util.tf_export import tf_export from tensorflow.tools.docs import doc_controls -def check_is_tensor_or_operation(x, name): - """Raises type error if the given input is not a tensor or operation.""" - if not (isinstance(x, ops.Tensor) or isinstance(x, ops.Operation)): - raise TypeError('{0} must be a Tensor or Operation, given: {1}'.format( - name, x)) - - def clone_metric(metric): """Returns a clone of the metric if stateful, otherwise returns it as is.""" if isinstance(metric, Metric): @@ -104,8 +97,6 @@ def update_state_wrapper(update_state_fn): update_op = update_state_fn(*args, **kwargs) if update_op is not None: # update_op will be None in eager execution. metric_obj.add_update(update_op, inputs=True) - check_is_tensor_or_operation( - update_op, 'Metric {0}\'s update'.format(metric_obj.name)) return update_op return tf_decorator.make_decorator(update_state_fn, decorated) @@ -130,7 +121,7 @@ def result_wrapper(result_fn): `merge_call()`. """ - def decorated(metric_obj, *args): + def decorated(_, *args): """Decorated function with merge_call.""" replica_context = distribution_strategy_context.get_replica_context() if replica_context is None: # if in cross replica context already @@ -151,8 +142,6 @@ def result_wrapper(result_fn): # replica mode and compute a value in cross replica mode. result_t = replica_context.merge_call( merge_fn_wrapper, args=(result_fn,) + args) - check_is_tensor_or_operation(result_t, - 'Metric {0}\'s result'.format(metric_obj.name)) return result_t return tf_decorator.make_decorator(result_fn, decorated) @@ -607,9 +596,7 @@ class Mean(Metric): # updated. update_total_op = state_ops.assign_add(self.total, values) with ops.control_dependencies([update_total_op]): - update_count_op = state_ops.assign_add(self.count, num_values) - with ops.control_dependencies([update_count_op]): - return control_flow_ops.no_op() + return state_ops.assign_add(self.count, num_values) def result(self): return math_ops.div_no_nan(self.total, self.count) diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index 536f717517..40611a5d75 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -366,48 +366,6 @@ class KerasMetricsTest(test.TestCase): result = self.evaluate(result_t) self.assertAlmostEqual(result, 0.93, 2) # 2.5/2.7 - @test_util.run_in_graph_and_eager_modes - def test_invalid_result(self): - - class InvalidResult(metrics.Metric): - - def __init__(self, name='invalid-result', dtype=dtypes.float64): - super(InvalidResult, self).__init__(name=name, dtype=dtype) - - def update_state(self, *args, **kwargs): - pass - - def result(self): - return 1 - - invalid_result_obj = InvalidResult() - with self.assertRaisesRegexp( - TypeError, - 'Metric invalid-result\'s result must be a Tensor or Operation, given:' - ): - invalid_result_obj.result() - - @test_util.run_in_graph_and_eager_modes - def test_invalid_update(self): - - class InvalidUpdate(metrics.Metric): - - def __init__(self, name='invalid-update', dtype=dtypes.float64): - super(InvalidUpdate, self).__init__(name=name, dtype=dtype) - - def update_state(self, *args, **kwargs): - return [1] - - def result(self): - pass - - invalid_update_obj = InvalidUpdate() - with self.assertRaisesRegexp( - TypeError, - 'Metric invalid-update\'s update must be a Tensor or Operation, given:' - ): - invalid_update_obj.update_state() - @test_util.run_all_in_graph_and_eager_modes class FalsePositivesTest(test.TestCase): -- GitLab From 3831f175ce88b90a1eb7caf3a1f72b9c8bab7c76 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 18:47:35 -0800 Subject: [PATCH 434/672] Bug fix for tf.ragged.tile RELNOTES: N/A PiperOrigin-RevId: 223096139 --- tensorflow/python/ops/ragged/ragged_array_ops.py | 13 ++++++++++++- tensorflow/python/ops/ragged/ragged_tile_op_test.py | 9 +++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/ops/ragged/ragged_array_ops.py b/tensorflow/python/ops/ragged/ragged_array_ops.py index 425f3957c3..815f48a4b1 100644 --- a/tensorflow/python/ops/ragged/ragged_array_ops.py +++ b/tensorflow/python/ops/ragged/ragged_array_ops.py @@ -1172,6 +1172,17 @@ def _tile_ragged_splits(rt_input, multiples, const_multiples=None): ragged_rank = rt_input.ragged_rank nested_splits = rt_input.nested_row_splits + # projected_splits[src_axis, dst_axis] contains the split points that divide + # the rows from src_axis in the list of dst_axis values. E.g., + # projected_splits[i, i] = nested_splits[i], and + # projected_splits[i, i+1] = gather(nested_splits[i+1], nested_splits[i]). + projected_splits = [{i: nested_splits[i]} for i in range(ragged_rank)] + for src_axis in range(ragged_rank): + for dst_axis in range(src_axis + 1, ragged_rank - 1): + projected_splits[src_axis][dst_axis] = array_ops.gather( + nested_splits[dst_axis], + projected_splits[src_axis][dst_axis - 1]) + # For each ragged dimension: nested_splits[axis] -> result_splits[axis]. result_splits = [] for axis in range(ragged_rank): @@ -1188,7 +1199,7 @@ def _tile_ragged_splits(rt_input, multiples, const_multiples=None): repeats = 1 for d in range(axis - 1, -1, -1): if const_multiples is None or const_multiples[d + 1] != 1: - splits = nested_splits[d] * repeats + splits = projected_splits[d][axis - 1] * repeats output_lengths = _repeat_ranges(output_lengths, splits, multiples[d + 1]) repeats *= multiples[d + 1] diff --git a/tensorflow/python/ops/ragged/ragged_tile_op_test.py b/tensorflow/python/ops/ragged/ragged_tile_op_test.py index bf62d96e7a..672d212114 100644 --- a/tensorflow/python/ops/ragged/ragged_tile_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_tile_op_test.py @@ -170,6 +170,15 @@ class RaggedTileOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt_input=[[[[1], [2]], [[3]]], [[]], [[[4, 5]]]], multiples=[1, 1, 1, 0], expected=[[[[], []], [[]]], [[]], [[[]]]]), + #========================================================================= + # multiple=1 + #========================================================================= + dict( + descr='rank=4, multiples=1 (no repeats)', + rt_input=[[[[1], [2]], [[3], [4]]], [[[5], [6]]]], + multiples=[1, 1, 1, 1], + expected=[[[[1], [2]], [[3], [4]]], + [[[5], [6]]]]), ]) # pyformat: disable def testRaggedTile(self, -- GitLab From 7d5ef9170bfe69c31cd57b18c6491fdd16ee93d3 Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Tue, 27 Nov 2018 19:43:49 -0800 Subject: [PATCH 435/672] For cuDNN >= 7.4, undo the work-around for NHWC with >2 strides for conv backward data. In cuDNN 7.4 release notes, they fixed the performance issue that we work-arounded, and it improves resnet50 a lot. PiperOrigin-RevId: 223100593 --- .../xla/service/gpu/gpu_layout_assignment.cc | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/gpu_layout_assignment.cc b/tensorflow/compiler/xla/service/gpu/gpu_layout_assignment.cc index 1c0a23fa3e..f59da2caa1 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_layout_assignment.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_layout_assignment.cc @@ -65,8 +65,8 @@ HeuristicLayoutAssignment(const HloInstruction* instr, VLOG(2) << "Using heuristic to figure out layouts for " << instr->ToString(); - // Empirically we've found with Volta and cudnn 7 that backward-input convs - // with stride are significantly faster with NCHW layouts. + // Empirically we've found with Volta and cudnn <= 7.3 that backward-input + // convs with stride are significantly faster with NCHW layouts. // // We could have used a mixed layout combination, e.g. (NHWC, NCHW, NCHW), // which on paper gives good performance. However, there are two observations: @@ -75,11 +75,17 @@ HeuristicLayoutAssignment(const HloInstruction* instr, // * we've also observed that for mixed layouts, cuDNN transposes data back // and forth from a different layout combination. If we end up with // transposes anyway, we prefer to have them in XLA, as they can be fused. - // TODO(timshen): Figure out the exact condition. This may be achieved by - // auto-tuning layouts offline. - if (instr->custom_call_target() == kCudnnConvBackwardInputCallTarget && - window_util::HasStride(instr->window())) { - return kAllNCHW; + if (auto* dnn = stream_executor->AsDnn()) { + auto version_status = dnn->GetVersion(); + if (version_status.ok()) { + auto version = version_status.ConsumeValueOrDie(); + if (std::make_tuple(version.major_version(), version.minor_version()) <= + std::make_tuple(7, 3) && + instr->custom_call_target() == kCudnnConvBackwardInputCallTarget && + window_util::HasStride(instr->window())) { + return kAllNCHW; + } + } } // For other Volta f16 convolutions, use NHWC. -- GitLab From c68b4003f88450455ab2fdfc62bde9e97929b085 Mon Sep 17 00:00:00 2001 From: Brennan Saeta Date: Tue, 27 Nov 2018 20:47:45 -0800 Subject: [PATCH 436/672] [Function Library]: Remove unused test variables This is a cleanup following up the DeviceMgr refactor. PiperOrigin-RevId: 223105410 --- tensorflow/core/common_runtime/function_threadpool_test.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tensorflow/core/common_runtime/function_threadpool_test.cc b/tensorflow/core/common_runtime/function_threadpool_test.cc index bdbe24a70d..1b803736fb 100644 --- a/tensorflow/core/common_runtime/function_threadpool_test.cc +++ b/tensorflow/core/common_runtime/function_threadpool_test.cc @@ -67,9 +67,6 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(), opts, default_thread_pool, nullptr /* cluster_flr */)); flr0_ = pflr_->GetFLR("/job:localhost/replica:0/task:0/cpu:0"); - flr1_ = pflr_->GetFLR("/job:localhost/replica:0/task:0/cpu:1"); - flr2_ = pflr_->GetFLR("/job:localhost/replica:0/task:0/cpu:2"); - fdef_lib_ = lib_def_->ToProto(); } Status Run(FunctionLibraryRuntime* flr, FunctionLibraryRuntime::Handle handle, @@ -193,12 +190,9 @@ class FunctionLibraryRuntimeTest : public ::testing::Test { } FunctionLibraryRuntime* flr0_; - FunctionLibraryRuntime* flr1_; - FunctionLibraryRuntime* flr2_; std::unique_ptr device_mgr_; std::unique_ptr lib_def_; std::unique_ptr pflr_; - FunctionDefLibrary fdef_lib_; }; TEST_F(FunctionLibraryRuntimeTest, DefaultThreadpool) { -- GitLab From 5f111d5a6c78f7afcd3ccbabf6e272800caceb9d Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 27 Nov 2018 20:49:05 -0800 Subject: [PATCH 437/672] Remove calls to test_session() or use test_util helpers PiperOrigin-RevId: 223105516 --- .../keras/layers/cudnn_recurrent_test.py | 686 +++++++++--------- .../kernel_tests/cwise_ops_binary_test.py | 28 +- .../python/kernel_tests/cwise_ops_test.py | 66 +- .../kernel_tests/cwise_ops_unary_test.py | 18 +- .../random/multinomial_op_test.py | 35 +- .../random/stateless_random_ops_test.py | 3 +- .../resource_variable_ops_test.py | 2 +- .../python/kernel_tests/variable_ops_test.py | 17 +- .../ops/ragged/ragged_segment_op_test.py | 19 +- .../ragged_tensor_bounding_shape_op_test.py | 40 +- .../python/ops/ragged/ragged_tensor_test.py | 449 ++++++------ 11 files changed, 674 insertions(+), 689 deletions(-) diff --git a/tensorflow/python/keras/layers/cudnn_recurrent_test.py b/tensorflow/python/keras/layers/cudnn_recurrent_test.py index cc93364aae..1f195f3119 100644 --- a/tensorflow/python/keras/layers/cudnn_recurrent_test.py +++ b/tensorflow/python/keras/layers/cudnn_recurrent_test.py @@ -31,64 +31,76 @@ from tensorflow.python.platform import test from tensorflow.python.training.rmsprop import RMSPropOptimizer +@test_util.run_all_in_graph_and_eager_modes class CuDNNTest(test.TestCase, parameterized.TestCase): - @test_util.run_in_graph_and_eager_modes def test_cudnn_rnn_basics(self): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: - for return_sequences in [True, False]: - with keras.utils.CustomObjectScope( - {'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, - 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM}): - testing_utils.layer_test( - layer_class, - kwargs={'units': units, - 'return_sequences': return_sequences}, - input_shape=(num_samples, timesteps, input_size)) - for go_backwards in [True, False]: - with keras.utils.CustomObjectScope( - {'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, - 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM}): - testing_utils.layer_test( - layer_class, - kwargs={'units': units, - 'go_backwards': go_backwards}, - input_shape=(num_samples, timesteps, input_size)) - - @test_util.run_in_graph_and_eager_modes + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: + for return_sequences in [True, False]: + with keras.utils.CustomObjectScope({ + 'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, + 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM + }): + testing_utils.layer_test( + layer_class, + kwargs={ + 'units': units, + 'return_sequences': return_sequences + }, + input_shape=(num_samples, timesteps, input_size)) + for go_backwards in [True, False]: + with keras.utils.CustomObjectScope({ + 'keras.layers.CuDNNGRU': keras.layers.CuDNNGRU, + 'keras.layers.CuDNNLSTM': keras.layers.CuDNNLSTM + }): + testing_utils.layer_test( + layer_class, + kwargs={ + 'units': units, + 'go_backwards': go_backwards + }, + input_shape=(num_samples, timesteps, input_size)) + def test_trainability(self): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - units = 2 - for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: - layer = layer_class(units) - layer.build((None, None, input_size)) - self.assertEqual(len(layer.weights), 3) - self.assertEqual(len(layer.trainable_weights), 3) - self.assertEqual(len(layer.non_trainable_weights), 0) - layer.trainable = False - self.assertEqual(len(layer.weights), 3) - self.assertEqual(len(layer.non_trainable_weights), 3) - self.assertEqual(len(layer.trainable_weights), 0) - layer.trainable = True - self.assertEqual(len(layer.weights), 3) - self.assertEqual(len(layer.trainable_weights), 3) - self.assertEqual(len(layer.non_trainable_weights), 0) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + units = 2 + for layer_class in [keras.layers.CuDNNGRU, keras.layers.CuDNNLSTM]: + layer = layer_class(units) + layer.build((None, None, input_size)) + self.assertEqual(len(layer.weights), 3) + self.assertEqual(len(layer.trainable_weights), 3) + self.assertEqual(len(layer.non_trainable_weights), 0) + layer.trainable = False + self.assertEqual(len(layer.weights), 3) + self.assertEqual(len(layer.non_trainable_weights), 3) + self.assertEqual(len(layer.trainable_weights), 0) + layer.trainable = True + self.assertEqual(len(layer.weights), 3) + self.assertEqual(len(layer.trainable_weights), 3) + self.assertEqual(len(layer.non_trainable_weights), 0) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_regularizer(self, layer_class): + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): + with test_util.use_gpu(): input_size = 10 timesteps = 6 units = 2 @@ -119,132 +131,140 @@ class CuDNNTest(test.TestCase, parameterized.TestCase): ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_return_state(self, layer_class): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 - - inputs = keras.Input(batch_shape=(num_samples, timesteps, input_size)) - layer = layer_class(units, return_state=True, stateful=True) - outputs = layer(inputs) - _, state = outputs[0], outputs[1:] - self.assertEqual(len(state), num_states) - model = keras.models.Model(inputs, state[0]) - - inputs = np.random.random((num_samples, timesteps, input_size)) - state = model.predict(inputs) - np.testing.assert_allclose( - keras.backend.eval(layer.states[0]), state, atol=1e-4) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 + + inputs = keras.Input(batch_shape=(num_samples, timesteps, input_size)) + layer = layer_class(units, return_state=True, stateful=True) + outputs = layer(inputs) + _, state = outputs[0], outputs[1:] + self.assertEqual(len(state), num_states) + model = keras.models.Model(inputs, state[0]) + + inputs = np.random.random((num_samples, timesteps, input_size)) + state = model.predict(inputs) + np.testing.assert_allclose( + keras.backend.eval(layer.states[0]), state, atol=1e-4) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_time_major_input(self, layer_class): - if test.is_gpu_available(cuda_only=True): - with self.test_session(use_gpu=True): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - - model = keras.models.Sequential() - model.add( - keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) - layer = layer_class(units, time_major=True, return_sequences=True) - model.add(layer) - model.add( - keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) - model.compile(loss='categorical_crossentropy', optimizer='adam') - model.fit( - np.ones((num_samples, timesteps, input_size)), - np.ones((num_samples, timesteps, units))) - out = model.predict(np.ones((num_samples, timesteps, input_size))) - self.assertEqual(out.shape, (num_samples, timesteps, units)) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + + model = keras.models.Sequential() + model.add( + keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) + layer = layer_class(units, time_major=True, return_sequences=True) + model.add(layer) + model.add( + keras.layers.Lambda(lambda t: array_ops.transpose(t, [1, 0, 2]))) + model.compile(loss='categorical_crossentropy', optimizer='adam') + model.fit( + np.ones((num_samples, timesteps, input_size)), + np.ones((num_samples, timesteps, units))) + out = model.predict(np.ones((num_samples, timesteps, input_size))) + self.assertEqual(out.shape, (num_samples, timesteps, units)) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_specify_initial_state_keras_tensor(self, layer_class): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 - - inputs = keras.Input((timesteps, input_size)) - initial_state = [keras.Input((units,)) for _ in range(num_states)] - layer = layer_class(units) - if len(initial_state) == 1: - output = layer(inputs, initial_state=initial_state[0]) - else: - output = layer(inputs, initial_state=initial_state) - self.assertIn(initial_state[0], layer._inbound_nodes[0].input_tensors) - - model = keras.models.Model([inputs] + initial_state, output) - model.compile(loss='categorical_crossentropy', optimizer='adam') - - inputs = np.random.random((num_samples, timesteps, input_size)) - initial_state = [ - np.random.random((num_samples, units)) for _ in range(num_states) - ] - targets = np.random.random((num_samples, units)) - model.fit([inputs] + initial_state, targets) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + num_states = 2 if layer_class is keras.layers.CuDNNLSTM else 1 + + inputs = keras.Input((timesteps, input_size)) + initial_state = [keras.Input((units,)) for _ in range(num_states)] + layer = layer_class(units) + if len(initial_state) == 1: + output = layer(inputs, initial_state=initial_state[0]) + else: + output = layer(inputs, initial_state=initial_state) + self.assertIn(initial_state[0], layer._inbound_nodes[0].input_tensors) + + model = keras.models.Model([inputs] + initial_state, output) + model.compile(loss='categorical_crossentropy', optimizer='adam') + + inputs = np.random.random((num_samples, timesteps, input_size)) + initial_state = [ + np.random.random((num_samples, units)) for _ in range(num_states) + ] + targets = np.random.random((num_samples, units)) + model.fit([inputs] + initial_state, targets) @parameterized.named_parameters( ('cudnngru', keras.layers.CuDNNGRU), ('cudnnlstm', keras.layers.CuDNNLSTM), ) def test_statefulness(self, layer_class): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - timesteps = 6 - units = 2 - num_samples = 32 - - model = keras.models.Sequential() - model.add( - keras.layers.Embedding( - 10, - input_size, - input_length=timesteps, - batch_input_shape=(num_samples, timesteps))) - layer = layer_class( - units, return_sequences=False, stateful=True, weights=None) - model.add(layer) - model.compile(optimizer='sgd', loss='mse') - out1 = model.predict(np.ones((num_samples, timesteps))) - self.assertEqual(out1.shape, (num_samples, units)) - - # train once so that the states change - model.train_on_batch( - np.ones((num_samples, timesteps)), np.ones((num_samples, units))) - out2 = model.predict(np.ones((num_samples, timesteps))) - - # if the state is not reset, output should be different - self.assertNotEqual(out1.max(), out2.max()) - - # check that output changes after states are reset - # (even though the model itself didn't change) - layer.reset_states() - out3 = model.predict(np.ones((num_samples, timesteps))) - self.assertNotEqual(out2.max(), out3.max()) - - # check that container-level reset_states() works - model.reset_states() - out4 = model.predict(np.ones((num_samples, timesteps))) - self.assertAllClose(out3, out4, atol=1e-5) - - # check that the call to `predict` updated the states - out5 = model.predict(np.ones((num_samples, timesteps))) - self.assertNotEqual(out4.max(), out5.max()) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + timesteps = 6 + units = 2 + num_samples = 32 + + model = keras.models.Sequential() + model.add( + keras.layers.Embedding( + 10, + input_size, + input_length=timesteps, + batch_input_shape=(num_samples, timesteps))) + layer = layer_class( + units, return_sequences=False, stateful=True, weights=None) + model.add(layer) + model.compile(optimizer='sgd', loss='mse') + out1 = model.predict(np.ones((num_samples, timesteps))) + self.assertEqual(out1.shape, (num_samples, units)) + + # train once so that the states change + model.train_on_batch( + np.ones((num_samples, timesteps)), np.ones((num_samples, units))) + out2 = model.predict(np.ones((num_samples, timesteps))) + + # if the state is not reset, output should be different + self.assertNotEqual(out1.max(), out2.max()) + + # check that output changes after states are reset + # (even though the model itself didn't change) + layer.reset_states() + out3 = model.predict(np.ones((num_samples, timesteps))) + self.assertNotEqual(out2.max(), out3.max()) + + # check that container-level reset_states() works + model.reset_states() + out4 = model.predict(np.ones((num_samples, timesteps))) + self.assertAllClose(out3, out4, atol=1e-5) + + # check that the call to `predict` updated the states + out5 = model.predict(np.ones((num_samples, timesteps))) + self.assertNotEqual(out4.max(), out5.max()) @parameterized.named_parameters( *test_util.generate_combinations_with_testcase_name( @@ -254,49 +274,51 @@ class CuDNNTest(test.TestCase, parameterized.TestCase): def test_load_weights_between_noncudnn_rnn(self, rnn_type, to_cudnn, bidirectional, implementation, model_nest_level, model_type): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - timesteps = 6 - input_shape = (timesteps, input_size) - units = 2 - num_samples = 32 - inputs = np.random.random((num_samples, timesteps, input_size)) - - rnn_layer_kwargs = { - 'recurrent_activation': 'sigmoid', - # ensure biases are non-zero and properly converted - 'bias_initializer': 'random_uniform', - 'implementation': implementation - } - if rnn_type == 'LSTM': - rnn_layer_class = keras.layers.LSTM - cudnn_rnn_layer_class = keras.layers.CuDNNLSTM - else: - rnn_layer_class = keras.layers.GRU - cudnn_rnn_layer_class = keras.layers.CuDNNGRU - rnn_layer_kwargs['reset_after'] = True - - layer = rnn_layer_class(units, **rnn_layer_kwargs) - if bidirectional: - layer = keras.layers.Bidirectional(layer) - - cudnn_layer = cudnn_rnn_layer_class(units) - if bidirectional: - cudnn_layer = keras.layers.Bidirectional(cudnn_layer) - - model = self._make_nested_model(input_shape, layer, model_nest_level, - model_type) - cudnn_model = self._make_nested_model(input_shape, cudnn_layer, - model_nest_level, model_type) - - if to_cudnn: - self._convert_model_weights(model, cudnn_model) - else: - self._convert_model_weights(cudnn_model, model) - - self.assertAllClose(model.predict(inputs), cudnn_model.predict(inputs), - atol=1e-4) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + timesteps = 6 + input_shape = (timesteps, input_size) + units = 2 + num_samples = 32 + inputs = np.random.random((num_samples, timesteps, input_size)) + + rnn_layer_kwargs = { + 'recurrent_activation': 'sigmoid', + # ensure biases are non-zero and properly converted + 'bias_initializer': 'random_uniform', + 'implementation': implementation + } + if rnn_type == 'LSTM': + rnn_layer_class = keras.layers.LSTM + cudnn_rnn_layer_class = keras.layers.CuDNNLSTM + else: + rnn_layer_class = keras.layers.GRU + cudnn_rnn_layer_class = keras.layers.CuDNNGRU + rnn_layer_kwargs['reset_after'] = True + + layer = rnn_layer_class(units, **rnn_layer_kwargs) + if bidirectional: + layer = keras.layers.Bidirectional(layer) + + cudnn_layer = cudnn_rnn_layer_class(units) + if bidirectional: + cudnn_layer = keras.layers.Bidirectional(cudnn_layer) + + model = self._make_nested_model(input_shape, layer, model_nest_level, + model_type) + cudnn_model = self._make_nested_model(input_shape, cudnn_layer, + model_nest_level, model_type) + + if to_cudnn: + self._convert_model_weights(model, cudnn_model) + else: + self._convert_model_weights(cudnn_model, model) + + self.assertAllClose( + model.predict(inputs), cudnn_model.predict(inputs), atol=1e-4) def _make_nested_model(self, input_shape, layer, level=1, model_type='func'): # example: make_nested_seq_model((1,), Dense(10), level=2).summary() @@ -334,149 +356,145 @@ class CuDNNTest(test.TestCase, parameterized.TestCase): to_cudnn): # Similar test as test_load_weights_between_noncudnn_rnn() but has different # rank of input due to usage of TimeDistributed. Issue: #10356. - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_size = 10 - steps = 6 - timesteps = 6 - input_shape = (timesteps, steps, input_size) - units = 2 - num_samples = 32 - inputs = np.random.random((num_samples, timesteps, steps, input_size)) - - rnn_layer_kwargs = { - 'recurrent_activation': 'sigmoid', - # ensure biases are non-zero and properly converted - 'bias_initializer': 'random_uniform', - } - if rnn_type == 'LSTM': - rnn_layer_class = keras.layers.LSTM - cudnn_rnn_layer_class = keras.layers.CuDNNLSTM - else: - rnn_layer_class = keras.layers.GRU - cudnn_rnn_layer_class = keras.layers.CuDNNGRU - rnn_layer_kwargs['reset_after'] = True - - layer = rnn_layer_class(units, **rnn_layer_kwargs) - layer = keras.layers.TimeDistributed(layer) - - cudnn_layer = cudnn_rnn_layer_class(units) - cudnn_layer = keras.layers.TimeDistributed(cudnn_layer) - - model = self._make_nested_model(input_shape, layer) - cudnn_model = self._make_nested_model(input_shape, cudnn_layer) - - if to_cudnn: - self._convert_model_weights(model, cudnn_model) - else: - self._convert_model_weights(cudnn_model, model) - - self.assertAllClose(model.predict(inputs), cudnn_model.predict(inputs), - atol=1e-4) - - @test_util.run_in_graph_and_eager_modes + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_size = 10 + steps = 6 + timesteps = 6 + input_shape = (timesteps, steps, input_size) + units = 2 + num_samples = 32 + inputs = np.random.random((num_samples, timesteps, steps, input_size)) + + rnn_layer_kwargs = { + 'recurrent_activation': 'sigmoid', + # ensure biases are non-zero and properly converted + 'bias_initializer': 'random_uniform', + } + if rnn_type == 'LSTM': + rnn_layer_class = keras.layers.LSTM + cudnn_rnn_layer_class = keras.layers.CuDNNLSTM + else: + rnn_layer_class = keras.layers.GRU + cudnn_rnn_layer_class = keras.layers.CuDNNGRU + rnn_layer_kwargs['reset_after'] = True + + layer = rnn_layer_class(units, **rnn_layer_kwargs) + layer = keras.layers.TimeDistributed(layer) + + cudnn_layer = cudnn_rnn_layer_class(units) + cudnn_layer = keras.layers.TimeDistributed(cudnn_layer) + + model = self._make_nested_model(input_shape, layer) + cudnn_model = self._make_nested_model(input_shape, cudnn_layer) + + if to_cudnn: + self._convert_model_weights(model, cudnn_model) + else: + self._convert_model_weights(cudnn_model, model) + + self.assertAllClose( + model.predict(inputs), cudnn_model.predict(inputs), atol=1e-4) + def test_cudnnrnn_bidirectional(self): - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - rnn = keras.layers.CuDNNGRU - samples = 2 - dim = 2 - timesteps = 2 - output_dim = 2 - mode = 'concat' - - x = np.random.random((samples, timesteps, dim)) - target_dim = 2 * output_dim if mode == 'concat' else output_dim - y = np.random.random((samples, target_dim)) - - # test with Sequential model - model = keras.Sequential() - model.add( - keras.layers.Bidirectional( - rnn(output_dim), merge_mode=mode, input_shape=(None, dim))) - model.compile( - loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) - - # test config - model.get_config() - model = keras.models.model_from_json(model.to_json()) - model.summary() - - # test stacked bidirectional layers - model = keras.Sequential() - model.add( - keras.layers.Bidirectional( - rnn(output_dim, return_sequences=True), - merge_mode=mode, - input_shape=(None, dim))) - model.add(keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode)) - model.compile( - loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) - - # test with functional API - inputs = keras.Input((timesteps, dim)) - outputs = keras.layers.Bidirectional( - rnn(output_dim), merge_mode=mode)( - inputs) - model = keras.Model(inputs, outputs) - model.compile( - loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) - - # Bidirectional and stateful - inputs = keras.Input(batch_shape=(1, timesteps, dim)) - outputs = keras.layers.Bidirectional( - rnn(output_dim, stateful=True), merge_mode=mode)( - inputs) - model = keras.Model(inputs, outputs) - model.compile( - loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) - model.fit(x, y, epochs=1, batch_size=1) + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + rnn = keras.layers.CuDNNGRU + samples = 2 + dim = 2 + timesteps = 2 + output_dim = 2 + mode = 'concat' + + x = np.random.random((samples, timesteps, dim)) + target_dim = 2 * output_dim if mode == 'concat' else output_dim + y = np.random.random((samples, target_dim)) + + # test with Sequential model + model = keras.Sequential() + model.add( + keras.layers.Bidirectional( + rnn(output_dim), merge_mode=mode, input_shape=(None, dim))) + model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) + + # test config + model.get_config() + model = keras.models.model_from_json(model.to_json()) + model.summary() + + # test stacked bidirectional layers + model = keras.Sequential() + model.add( + keras.layers.Bidirectional( + rnn(output_dim, return_sequences=True), + merge_mode=mode, + input_shape=(None, dim))) + model.add(keras.layers.Bidirectional(rnn(output_dim), merge_mode=mode)) + model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) + + # test with functional API + inputs = keras.Input((timesteps, dim)) + outputs = keras.layers.Bidirectional( + rnn(output_dim), merge_mode=mode)( + inputs) + model = keras.Model(inputs, outputs) + model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) + + # Bidirectional and stateful + inputs = keras.Input(batch_shape=(1, timesteps, dim)) + outputs = keras.layers.Bidirectional( + rnn(output_dim, stateful=True), merge_mode=mode)( + inputs) + model = keras.Model(inputs, outputs) + model.compile(loss='mse', optimizer=RMSPropOptimizer(learning_rate=0.001)) + model.fit(x, y, epochs=1, batch_size=1) def test_preprocess_weights_for_loading_gru_incompatible(self): """Test loading weights between incompatible layers. Should fail fast with an exception. """ - if test.is_gpu_available(cuda_only=True): - with self.session(use_gpu=True): - input_shape = (3, 5) - - def gru(cudnn=False, **kwargs): - layer_class = keras.layers.CuDNNGRU if cudnn else keras.layers.GRU - return layer_class(2, input_shape=input_shape, **kwargs) - - def get_layer_weights(layer): - layer.build(input_shape=input_shape) - return layer.get_weights() - - def assert_not_compatible(src, dest, message): - with self.assertRaises(ValueError) as ex: - keras.engine.saving.preprocess_weights_for_loading( - dest, - get_layer_weights(src)) - self.assertIn(message, str(ex.exception)) - - assert_not_compatible( - gru(), - gru(cudnn=True), - 'GRU(reset_after=False) is not compatible with CuDNNGRU') - assert_not_compatible( - gru(cudnn=True), - gru(), - 'CuDNNGRU is not compatible with GRU(reset_after=False)') - assert_not_compatible( - gru(), - gru(reset_after=True), - 'GRU(reset_after=False) is not compatible with ' - 'GRU(reset_after=True)') - assert_not_compatible( - gru(reset_after=True), - gru(), - 'GRU(reset_after=True) is not compatible with ' - 'GRU(reset_after=False)') + if not test.is_gpu_available(cuda_only=True): + self.skipTest('No CUDA GPU available') + + with test_util.use_gpu(): + input_shape = (3, 5) + + def gru(cudnn=False, **kwargs): + layer_class = keras.layers.CuDNNGRU if cudnn else keras.layers.GRU + return layer_class(2, input_shape=input_shape, **kwargs) + + def get_layer_weights(layer): + layer.build(input_shape=input_shape) + return layer.get_weights() + + def assert_not_compatible(src, dest, message): + with self.assertRaises(ValueError) as ex: + keras.engine.saving.preprocess_weights_for_loading( + dest, get_layer_weights(src)) + self.assertIn(message, str(ex.exception)) + + assert_not_compatible( + gru(), gru(cudnn=True), + 'GRU(reset_after=False) is not compatible with CuDNNGRU') + assert_not_compatible( + gru(cudnn=True), gru(), + 'CuDNNGRU is not compatible with GRU(reset_after=False)') + assert_not_compatible( + gru(), gru(reset_after=True), + 'GRU(reset_after=False) is not compatible with ' + 'GRU(reset_after=True)') + assert_not_compatible( + gru(reset_after=True), gru(), + 'GRU(reset_after=True) is not compatible with ' + 'GRU(reset_after=False)') if __name__ == '__main__': diff --git a/tensorflow/python/kernel_tests/cwise_ops_binary_test.py b/tensorflow/python/kernel_tests/cwise_ops_binary_test.py index fc7d4572e2..272c2b1dac 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_binary_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_binary_test.py @@ -77,7 +77,7 @@ class BinaryOpTest(test.TestCase): def _compareCpu(self, x, y, np_func, tf_func, also_compare_variables=False): np_ans = np_func(x, y) - with self.test_session(use_gpu=False): + with test_util.force_cpu(): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) @@ -174,7 +174,7 @@ class BinaryOpTest(test.TestCase): def _compareGpu(self, x, y, np_func, tf_func): np_ans = np_func(x, y) - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) @@ -252,10 +252,12 @@ class BinaryOpTest(test.TestCase): y = np.array([1, 2]).reshape(2, 1).astype(np.int32) var_x = variables.Variable(x) var_y = variables.Variable(y) + with self.cached_session() as sess: self.evaluate([var_x.initializer, var_y.initializer]) - left_result = (var_x * y).eval() - right_result = (x * var_y).eval() + left_result = self.evaluate(var_x * y) + right_result = self.evaluate(x * var_y) + np_result = x * y self.assertAllEqual(np_result, left_result) self.assertAllEqual(np_result, right_result) @@ -382,7 +384,7 @@ class BinaryOpTest(test.TestCase): def testStringComparison(self): x = np.array([["abc", "bh"], ["c", ""]]) y = np.array([["abc", "bh"], ["def", "hi"]]) - with self.test_session(use_gpu=False) as sess: + with test_util.force_cpu(): cmp_eq = math_ops.equal(x, y) cmp_not_eq = math_ops.not_equal(x, y) values = self.evaluate([cmp_eq, cmp_not_eq]) @@ -716,35 +718,35 @@ class BinaryOpTest(test.TestCase): def testPowNegativeExponent(self): for dtype in [np.int32, np.int64]: - with self.test_session(use_gpu=False) as sess: + with test_util.force_cpu(): with self.assertRaisesRegexp( errors_impl.InvalidArgumentError, "Integers to negative integer powers are not allowed"): x = np.array([5, 2]).astype(dtype) y = np.array([-2, 3]).astype(dtype) - sess.run(math_ops.pow(x, y)) + self.evaluate(math_ops.pow(x, y)) - with self.test_session(use_gpu=False) as sess: + with test_util.force_cpu(): with self.assertRaisesRegexp( errors_impl.InvalidArgumentError, "Integers to negative integer powers are not allowed"): x = np.array([5, 2]).astype(dtype) y = np.array([2, -3]).astype(dtype) - sess.run(math_ops.pow(x, y)) + self.evaluate(math_ops.pow(x, y)) - with self.test_session(use_gpu=False) as sess: + with test_util.force_cpu(): with self.assertRaisesRegexp( errors_impl.InvalidArgumentError, "Integers to negative integer powers are not allowed"): x = np.array([5, 2]).astype(dtype) y = -3 - sess.run(math_ops.pow(x, y)) + self.evaluate(math_ops.pow(x, y)) class ComparisonOpTest(test.TestCase): def _compareScalar(self, func, x, y, dtype): - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): out = func( ops.convert_to_tensor(np.array([x]).astype(dtype)), ops.convert_to_tensor(np.array([y]).astype(dtype))) @@ -777,7 +779,7 @@ class ComparisonOpTest(test.TestCase): def _compare(self, x, y, np_func, tf_func): np_ans = np_func(x, y) - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): out = tf_func(ops.convert_to_tensor(x), ops.convert_to_tensor(y)) tf_ans = self.evaluate(out) self.assertAllEqual(np_ans, tf_ans) diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index ab116c400a..7e14f95be4 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -84,7 +84,7 @@ def _default_tolerance(dtype): class ComparisonOpTest(test.TestCase): def _compareScalar(self, func, x, y, dtype): - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): out = func( ops.convert_to_tensor(np.array([x]).astype(dtype)), ops.convert_to_tensor(np.array([y]).astype(dtype))) @@ -117,7 +117,7 @@ class ComparisonOpTest(test.TestCase): def _compare(self, x, y, np_func, tf_func): np_ans = np_func(x, y) - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): out = tf_func(ops.convert_to_tensor(x), ops.convert_to_tensor(y)) tf_ans = self.evaluate(out) self.assertAllEqual(np_ans, tf_ans) @@ -218,8 +218,7 @@ class LogicalOpTest(test.TestCase): def _compareBinary(self, x, y, np_func, tf_func, use_gpu=False): np_ans = np_func(x, y) - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + with test_util.device(use_gpu=use_gpu): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) out = tf_func(inx, iny) @@ -230,8 +229,7 @@ class LogicalOpTest(test.TestCase): def _not(self, x, use_gpu=False): np_ans = np.logical_not(x) - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + with test_util.device(use_gpu=use_gpu): out = math_ops.logical_not(ops.convert_to_tensor(x)) tf_val = self.evaluate(out) self.assertEqual(out.dtype, dtypes_lib.bool) @@ -316,8 +314,7 @@ class SelectOpTest(test.TestCase): def _compare(self, c, x, y, use_gpu): np_ans = np.where(c, x, y) - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + with test_util.device(use_gpu=use_gpu): out = array_ops.where(c, x, y) tf_ans = self.evaluate(out) self.assertAllEqual(np_ans, tf_ans) @@ -460,8 +457,7 @@ class BatchSelectOpTest(test.TestCase): np_ans = np.dstack( [x_i if c_i else y_i for c_i, x_i, y_i in zip(c, x, y)]).transpose( [2, 0, 1]) - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + with test_util.device(use_gpu=use_gpu): out = array_ops.where(c, x, y) tf_ans = self.evaluate(out) self.assertAllEqual(np_ans, tf_ans) @@ -566,9 +562,7 @@ class MinMaxOpTest(test.TestCase): def _compare(self, x, y, use_gpu): np_min, np_max = np.minimum(x, y), np.maximum(x, y) - with self.test_session( - use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()) as sess: + with test_util.device(use_gpu=use_gpu): inx = ops.convert_to_tensor(x) iny = ops.convert_to_tensor(y) omin, omax = math_ops.minimum(inx, iny), math_ops.maximum(inx, iny) @@ -641,13 +635,13 @@ class MinMaxOpTest(test.TestCase): class MathOpsOverloadTest(test.TestCase): def _computeTensorAndLiteral(self, x, y, dtype, func): - with self.test_session(use_gpu=False): + with test_util.force_cpu(): inx = ops.convert_to_tensor(x, dtype=dtype) z = func(inx, y) # Should use __add__, __sub__, etc. return self.evaluate(z) def _computeLiteralAndTensor(self, x, y, dtype, func): - with self.test_session(use_gpu=False): + with test_util.force_cpu(): iny = ops.convert_to_tensor(y, dtype=dtype) z = func(x, iny) # Should use __radd__, __rsub__, etc. return self.evaluate(z) @@ -661,7 +655,7 @@ class MathOpsOverloadTest(test.TestCase): def _compareUnary(self, x, dtype, np_func, tf_func): np_ans = np_func(x).astype(dtype.as_numpy_dtype) - with self.test_session(use_gpu=False): + with test_util.force_cpu(): self.assertAllClose( np_ans, self.evaluate(tf_func(ops.convert_to_tensor(x, dtype=dtype)))) @@ -730,9 +724,7 @@ class IsFiniteInfNanTest(test.TestCase): def _compare(self, x, use_gpu): np_finite, np_inf, np_nan = np.isfinite(x), np.isinf(x), np.isnan(x) - with self.test_session( - use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()) as sess: + with test_util.device(use_gpu=use_gpu): inx = ops.convert_to_tensor(x) ofinite, oinf, onan = math_ops.is_finite(inx), math_ops.is_inf( inx), math_ops.is_nan(inx) @@ -773,7 +765,7 @@ class IsFiniteInfNanTest(test.TestCase): x = np.full((size,), value, dtype=dtype) np_y = np.sqrt(x) np_nan = np.isnan(np_y) - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): tf_y = math_ops.sqrt(x) tf_nan = math_ops.is_nan(tf_y) if value < 0: @@ -786,18 +778,20 @@ class RoundingTest(test.TestCase): def _compare_values(self, x, y=None): y = np.rint(x) if y is None else np.asarray(y) - with self.cached_session() as sess: - tf_rint = math_ops.rint(x) - np_rint = self.evaluate(tf_rint) + + tf_rint = math_ops.rint(x) + np_rint = self.evaluate(tf_rint) + self.assertAllEqual(y, np_rint) self.assertShapeEqual(y, tf_rint) def _compare(self, x): np_floor, np_ceil = np.floor(x), np.ceil(x) - with self.cached_session() as sess: - inx = ops.convert_to_tensor(x) - ofloor, oceil = math_ops.floor(inx), math_ops.ceil(inx) - tf_floor, tf_ceil = self.evaluate([ofloor, oceil]) + + inx = ops.convert_to_tensor(x) + ofloor, oceil = math_ops.floor(inx), math_ops.ceil(inx) + tf_floor, tf_ceil = self.evaluate([ofloor, oceil]) + self.assertAllEqual(np_floor, tf_floor) self.assertAllEqual(np_ceil, tf_ceil) self.assertShapeEqual(np_floor, ofloor) @@ -828,12 +822,13 @@ class ComplexMakeRealImagTest(test.TestCase): def _compareMake(self, real, imag, use_gpu): np_ans = real + (1j) * imag - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + + with test_util.device(use_gpu=use_gpu): real = ops.convert_to_tensor(real) imag = ops.convert_to_tensor(imag) tf_ans = math_ops.complex(real, imag) out = self.evaluate(tf_ans) + self.assertAllEqual(np_ans, out) self.assertShapeEqual(np_ans, tf_ans) @@ -848,8 +843,8 @@ class ComplexMakeRealImagTest(test.TestCase): def _compareRealImag(self, cplx, use_gpu): np_real, np_imag = np.real(cplx), np.imag(cplx) np_zeros = np_real * 0 - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + + with test_util.device(use_gpu=use_gpu): inx = ops.convert_to_tensor(cplx) tf_real = math_ops.real(inx) tf_imag = math_ops.imag(inx) @@ -876,12 +871,12 @@ class ComplexMakeRealImagTest(test.TestCase): def _compareAngle(self, cplx, use_gpu): np_angle = np.angle(cplx) - with self.test_session( - use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()) as sess: + + with test_util.device(use_gpu=use_gpu): inx = ops.convert_to_tensor(cplx) tf_angle = math_ops.angle(inx) tf_angle_val = self.evaluate(tf_angle) + self.assertAllEqual(np_angle, tf_angle_val) self.assertShapeEqual(np_angle, tf_angle) @@ -912,8 +907,7 @@ class ComplexMakeRealImagTest(test.TestCase): def _compareConj(self, cplx, use_gpu): np_ans = np.conj(cplx) - with self.test_session(use_gpu=use_gpu, - force_gpu=use_gpu and test_util.is_gpu_available()): + with test_util.device(use_gpu=use_gpu): inx = ops.convert_to_tensor(cplx) tf_conj = math_ops.conj(inx) tf_ans = self.evaluate(tf_conj) diff --git a/tensorflow/python/kernel_tests/cwise_ops_unary_test.py b/tensorflow/python/kernel_tests/cwise_ops_unary_test.py index 7096083a1f..3e8294f34b 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_unary_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_unary_test.py @@ -76,7 +76,7 @@ class UnaryOpTest(test.TestCase): if grad_atol is None: grad_atol = _default_tolerance(x.dtype) np_ans = np_func(x) - with self.test_session(use_gpu=False): + with self.cached_session(use_gpu=False): inx = ops.convert_to_tensor(x) if x.dtype in (np.float32, np.float64, dtypes_lib.bfloat16.as_numpy_dtype): @@ -121,24 +121,22 @@ class UnaryOpTest(test.TestCase): def _check(self, result_tensor, result_np, input_sp_t, tol): self.assertTrue(isinstance(result_tensor, sparse_tensor.SparseTensor)) self.assertTrue(isinstance(input_sp_t, sparse_tensor.SparseTensor)) - self.assertAllEqual(input_sp_t.indices.eval(), result_tensor.indices.eval()) - self.assertAllEqual(input_sp_t.dense_shape.eval(), - result_tensor.dense_shape.eval()) + self.assertAllEqual(input_sp_t.indices, result_tensor.indices) + self.assertAllEqual(input_sp_t.dense_shape, result_tensor.dense_shape) if tol is None: - self.assertAllClose(result_np, result_tensor.values.eval()) + self.assertAllClose(result_np, result_tensor.values) else: - self.assertAllClose( - result_np, result_tensor.values.eval(), rtol=tol, atol=tol) + self.assertAllClose(result_np, result_tensor.values, rtol=tol, atol=tol) def _compareSparseCpu(self, x, np_func, tf_func, tol): x_sp, x_sp_vals = _sparsify(x) res_np = np_func(x_sp_vals) - with self.test_session(use_gpu=False): + with test_util.force_cpu(): self._check(tf_func(x_sp), res_np, x_sp, tol) def _compareGpu(self, x, np_func, tf_func): np_ans = np_func(x) - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): result = tf_func(ops.convert_to_tensor(x)) tf_gpu = self.evaluate(result) if x.dtype == np.float16: @@ -150,7 +148,7 @@ class UnaryOpTest(test.TestCase): def _compareSparseGpu(self, x, np_func, tf_func, tol): x_sp, x_sp_vals = _sparsify(x) res_np = np_func(x_sp_vals) - with self.test_session(force_gpu=test_util.is_gpu_available()): + with test_util.use_gpu(): self._check(tf_func(x_sp), res_np, x_sp, tol) def _compareBoth(self, x, np_func, tf_func): diff --git a/tensorflow/python/kernel_tests/random/multinomial_op_test.py b/tensorflow/python/kernel_tests/random/multinomial_op_test.py index cfec4d08fb..031a1c281c 100644 --- a/tensorflow/python/kernel_tests/random/multinomial_op_test.py +++ b/tensorflow/python/kernel_tests/random/multinomial_op_test.py @@ -67,11 +67,11 @@ class MultinomialTest(test.TestCase): self.assertAllEqual([[1] * num_samples, [2] * num_samples], samples) def testOneOpMultipleStepsIndependent(self): - with self.test_session(use_gpu=True) as sess: + with test_util.use_gpu(): sample_op1, _ = self._make_ops(10) # Consecutive runs shouldn't yield identical output. - sample1a = sess.run(sample_op1) - sample1b = sess.run(sample_op1) + sample1a = self.evaluate(sample_op1) + sample1b = self.evaluate(sample_op1) self.assertFalse(np.equal(sample1a, sample1b).all()) def testEagerOneOpMultipleStepsIndependent(self): @@ -81,26 +81,26 @@ class MultinomialTest(test.TestCase): self.assertFalse(np.equal(sample1.numpy(), sample2.numpy()).all()) def testTwoOpsIndependent(self): - with self.test_session(use_gpu=True) as sess: + with test_util.use_gpu(): sample_op1, sample_op2 = self._make_ops(32) - sample1, sample2 = sess.run([sample_op1, sample_op2]) + sample1, sample2 = self.evaluate([sample_op1, sample_op2]) # We expect sample1 and sample2 to be independent. # 1 in 2^32 chance of this assertion failing. self.assertFalse(np.equal(sample1, sample2).all()) def testTwoOpsSameSeedDrawSameSequences(self): - with self.test_session(use_gpu=True) as sess: + with test_util.use_gpu(): sample_op1, sample_op2 = self._make_ops(1000, seed=1) - sample1, sample2 = sess.run([sample_op1, sample_op2]) + sample1, sample2 = self.evaluate([sample_op1, sample_op2]) self.assertAllEqual(sample1, sample2) def testLargeLogits(self): for neg in [True, False]: - with self.test_session(use_gpu=True): + with test_util.use_gpu(): logits = np.array([[1000.] * 5]) if neg: logits *= -1 - samples = random_ops.multinomial(logits, 10).eval() + samples = self.evaluate(random_ops.multinomial(logits, 10)) # Sampled classes should be in-range. self.assertTrue((samples >= 0).all()) self.assertTrue((samples < 5).all()) @@ -157,10 +157,10 @@ class MultinomialTest(test.TestCase): Returns: Frequencies from sampled classes; shape [batch_size, num_classes]. """ - with self.test_session(use_gpu=True) as sess: + with test_util.use_gpu(): random_seed.set_random_seed(1618) op = sampler(constant_op.constant(logits), num_samples) - d = sess.run(op) + d = self.evaluate(op) batch_size, num_classes = logits.shape freqs_mat = [] @@ -186,25 +186,26 @@ class MultinomialTest(test.TestCase): def testEmpty(self): classes = 5 - with self.test_session(use_gpu=True): + with test_util.use_gpu(): for batch in 0, 3: for samples in 0, 7: - x = random_ops.multinomial( - array_ops.zeros([batch, classes]), samples).eval() + x = self.evaluate( + random_ops.multinomial( + array_ops.zeros([batch, classes]), samples)) self.assertEqual(x.shape, (batch, samples)) def testEmptyClasses(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): x = random_ops.multinomial(array_ops.zeros([5, 0]), 7) with self.assertRaisesOpError("num_classes should be positive"): self.evaluate(x) def testNegativeMinLogits(self): random_seed.set_random_seed(78844) - with self.test_session(use_gpu=True): + with test_util.use_gpu(): logits = constant_op.constant([[np.finfo(np.float32).min] * 1023 + [0]]) num_samples = 1000 - samples = random_ops.multinomial(logits, num_samples).eval() + samples = self.evaluate(random_ops.multinomial(logits, num_samples)) self.assertAllEqual([[1023] * num_samples], samples) diff --git a/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py b/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py index d80bea955e..071d6c2998 100644 --- a/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py +++ b/tensorflow/python/kernel_tests/random/stateless_random_ops_test.py @@ -24,6 +24,7 @@ import numpy as np from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import random_seed +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import stateless_random_ops as stateless @@ -58,7 +59,7 @@ class StatelessOpsTest(test.TestCase): preseed = invert_philox(key, (seed[0], 0, seed[1], 0)).astype(np.uint64) preseed = preseed[::2] | preseed[1::2] << 32 random_seed.set_random_seed(seed[0]) - with self.test_session(use_gpu=True): + with test_util.use_gpu(): for stateless_op, stateful_op in cases: stateful = stateful_op(seed=seed[1]) pure = stateless_op(seed=preseed) diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index 13b39926ec..30563092c8 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -456,7 +456,7 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): # TODO(alive): get this to work in Eager mode. def testGPU(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): abc = variable_scope.get_variable( "abc", shape=[1], diff --git a/tensorflow/python/kernel_tests/variable_ops_test.py b/tensorflow/python/kernel_tests/variable_ops_test.py index cdfd805a93..c63d7f89c7 100644 --- a/tensorflow/python/kernel_tests/variable_ops_test.py +++ b/tensorflow/python/kernel_tests/variable_ops_test.py @@ -24,6 +24,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_state_ops from tensorflow.python.ops import math_ops @@ -164,7 +165,7 @@ class VariableOpTest(test.TestCase): self.assertEqual(tensor_shape.unknown_shape(), subbed.get_shape()) def testTemporaryVariable(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): var = gen_state_ops.temporary_variable( [1, 2], dtypes.float32, var_name="foo") var = state_ops.assign(var, [[4.0, 5.0]]) @@ -173,14 +174,14 @@ class VariableOpTest(test.TestCase): self.assertAllClose([[10.0, 12.0]], self.evaluate(final)) def testDestroyNonexistentTemporaryVariable(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): var = gen_state_ops.temporary_variable([1, 2], dtypes.float32) final = gen_state_ops.destroy_temporary_variable(var, var_name="bad") with self.assertRaises(errors.NotFoundError): self.evaluate(final) def testDuplicateTemporaryVariable(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): var1 = gen_state_ops.temporary_variable( [1, 2], dtypes.float32, var_name="dup") var1 = state_ops.assign(var1, [[1.0, 2.0]]) @@ -192,7 +193,7 @@ class VariableOpTest(test.TestCase): self.evaluate(final) def testDestroyTemporaryVariableTwice(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): var = gen_state_ops.temporary_variable([1, 2], dtypes.float32) val1 = gen_state_ops.destroy_temporary_variable(var, var_name="dup") val2 = gen_state_ops.destroy_temporary_variable(var, var_name="dup") @@ -201,14 +202,14 @@ class VariableOpTest(test.TestCase): self.evaluate(final) def testTemporaryVariableNoLeak(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): var = gen_state_ops.temporary_variable( [1, 2], dtypes.float32, var_name="bar") final = array_ops.identity(var) self.evaluate(final) def testTwoTemporaryVariablesNoLeaks(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): var1 = gen_state_ops.temporary_variable( [1, 2], dtypes.float32, var_name="var1") var2 = gen_state_ops.temporary_variable( @@ -217,13 +218,13 @@ class VariableOpTest(test.TestCase): self.evaluate(final) def testAssignDependencyAcrossDevices(self): - with self.test_session(use_gpu=True): + with test_util.use_gpu(): # The variable and an op to increment it are on the GPU. var = state_ops.variable_op([1], dtypes.float32) self.evaluate(state_ops.assign(var, [1.0])) increment = state_ops.assign_add(var, [1.0]) with ops.control_dependencies([increment]): - with ops.device("/cpu:0"): + with test_util.force_cpu(): # This mul op is pinned to the CPU, but reads the variable from the # GPU. The test ensures that the dependency on 'increment' is still # honored, i.e., the Send and Recv from GPU to CPU should take place diff --git a/tensorflow/python/ops/ragged/ragged_segment_op_test.py b/tensorflow/python/ops/ragged/ragged_segment_op_test.py index 228c9bc5e4..40a101b4da 100644 --- a/tensorflow/python/ops/ragged/ragged_segment_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_segment_op_test.py @@ -118,8 +118,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, combiner) segmented = segment_op(rt, segment_ids, num_segments) - with self.test_session(): - self.assertListEqual(self.evaluate(segmented).tolist(), expected) + self.assertListEqual(self.evaluate(segmented).tolist(), expected) @parameterized.parameters( (ragged.segment_sum, sum, [0, 0, 1, 1, 2, 2]), @@ -155,9 +154,8 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, combiner) segmented = segment_op(rt, segment_ids, num_segments) - with self.test_session(): - self.assertNestedListAmostEqual( - self.evaluate(segmented).tolist(), expected, places=5) + self.assertNestedListAmostEqual( + self.evaluate(segmented).tolist(), expected, places=5) def testRaggedRankTwo(self): rt = ragged.constant([ @@ -172,16 +170,14 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, [], # row 1 [[411, 412], [321, 322], [331]] # row 2 ] # pyformat: disable - with self.test_session(): - self.assertEqual(self.evaluate(segmented1).tolist(), expected1) + self.assertEqual(self.evaluate(segmented1).tolist(), expected1) segment_ids2 = [1, 2, 1, 1] segmented2 = ragged.segment_sum(rt, segment_ids2, 3) expected2 = [[], [[111+411, 112+412, 113, 114], [121+321, 322], [331]], []] # pyformat: disable - with self.test_session(): - self.assertEqual(self.evaluate(segmented2).tolist(), expected2) + self.assertEqual(self.evaluate(segmented2).tolist(), expected2) def testRaggedSegmentIds(self): rt = ragged.constant([ @@ -195,8 +191,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, expected = [[], [111+321, 112+322, 113, 114], [121+331+411, 412]] # pyformat: disable - with self.test_session(): - self.assertEqual(self.evaluate(segmented).tolist(), expected) + self.assertEqual(self.evaluate(segmented).tolist(), expected) def testShapeMismatchError1(self): dt = constant_op.constant([1, 2, 3, 4, 5, 6]) @@ -226,7 +221,7 @@ class RaggedSegmentOpsTest(test_util.TensorFlowTestCase, array_ops.placeholder_with_default(segment_ids.values, None), array_ops.placeholder_with_default(segment_ids.row_splits, None)) segmented2 = ragged.segment_sum(rt, segment_ids2, 3) - with self.test_session(): + with self.cached_session(): self.assertRaisesRegexp( errors.InvalidArgumentError, 'segment_ids.shape must be a prefix of data.shape.*', segmented2.eval) diff --git a/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py b/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py index cd382fe0b8..befe30f0e1 100644 --- a/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_tensor_bounding_shape_op_test.py @@ -28,49 +28,39 @@ class RaggedTensorBoundingShapeOp(test_util.TensorFlowTestCase): def testDocStringExample(self): # This is the example from ragged.bounding_shape.__doc__. rt = ragged.constant([[1, 2, 3, 4], [5], [], [6, 7, 8, 9], [10]]) - with self.test_session(): - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt)).tolist(), [5, 4]) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt)).tolist(), [5, 4]) def test2DRaggedTensorWithOneRaggedDimension(self): values = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] rt1 = ragged.from_row_splits(values, [0, 2, 5, 6, 6, 7]) rt2 = ragged.from_row_splits(values, [0, 7]) rt3 = ragged.from_row_splits(values, [0, 0, 7, 7]) - with self.test_session(): - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt1)).tolist(), [5, 3]) - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt2)).tolist(), [1, 7]) - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt3)).tolist(), [3, 7]) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt1)).tolist(), [5, 3]) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt2)).tolist(), [1, 7]) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt3)).tolist(), [3, 7]) def test3DRaggedTensorWithOneRaggedDimension(self): values = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]] rt1 = ragged.from_row_splits(values, [0, 2, 5, 6, 6, 7]) rt2 = ragged.from_row_splits(values, [0, 7]) rt3 = ragged.from_row_splits(values, [0, 0, 7, 7]) - with self.test_session(): - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt1)).tolist(), [5, 3, 2]) - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt2)).tolist(), [1, 7, 2]) - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt3)).tolist(), [3, 7, 2]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt1)).tolist(), [5, 3, 2]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt2)).tolist(), [1, 7, 2]) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt3)).tolist(), [3, 7, 2]) def testNonRaggedTensor(self): dt = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] - with self.test_session(): - self.assertEqual( - self.evaluate(ragged.bounding_shape(dt)).tolist(), [4, 3]) + self.assertEqual(self.evaluate(ragged.bounding_shape(dt)).tolist(), [4, 3]) def testExplicitAxisOptimizations(self): rt = ragged.from_row_splits(b'a b c d e f g'.split(), [0, 2, 5, 6, 6, 7]) - with self.test_session(): - self.assertEqual(self.evaluate(ragged.bounding_shape(rt, 0)).tolist(), 5) - self.assertEqual(self.evaluate(ragged.bounding_shape(rt, 1)).tolist(), 3) - self.assertEqual( - self.evaluate(ragged.bounding_shape(rt, [1, 0])).tolist(), [3, 5]) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt, 0)).tolist(), 5) + self.assertEqual(self.evaluate(ragged.bounding_shape(rt, 1)).tolist(), 3) + self.assertEqual( + self.evaluate(ragged.bounding_shape(rt, [1, 0])).tolist(), [3, 5]) if __name__ == '__main__': diff --git a/tensorflow/python/ops/ragged/ragged_tensor_test.py b/tensorflow/python/ops/ragged/ragged_tensor_test.py index 66b15d9bcc..fa681c07bb 100644 --- a/tensorflow/python/ops/ragged/ragged_tensor_test.py +++ b/tensorflow/python/ops/ragged/ragged_tensor_test.py @@ -118,9 +118,8 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # From section: "Component Tensors" rt = ragged.from_row_splits( values=[3, 1, 4, 1, 5, 9, 2, 6], row_splits=[0, 4, 4, 7, 8, 8]) - with self.test_session(): - self.assertEqual(rt.tolist(), - [[3, 1, 4, 1], [], [5, 9, 2], [6], []]) + self.assertEqual( + self.evaluate(rt).tolist(), [[3, 1, 4, 1], [], [5, 9, 2], [6], []]) del rt # From section: "Alternative Row-Partitioning Schemes" @@ -132,9 +131,8 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt4 = ragged.from_row_starts(values, row_starts=[0, 4, 4, 7, 8]) rt5 = ragged.from_row_limits(values, row_limits=[4, 4, 7, 8, 8]) for rt in (rt1, rt2, rt3, rt4, rt5): - with self.test_session(): - self.assertEqual(rt.tolist(), - [[3, 1, 4, 1], [], [5, 9, 2], [6], []]) + self.assertEqual( + self.evaluate(rt).tolist(), [[3, 1, 4, 1], [], [5, 9, 2], [6], []]) del rt1, rt2, rt3, rt4, rt5 # From section: "Multiple Ragged Dimensions" @@ -142,28 +140,27 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): values=[3, 1, 4, 1, 5, 9, 2, 6], row_splits=[0, 4, 4, 7, 8, 8]) outer_rt = ragged.from_row_splits(values=inner_rt, row_splits=[0, 3, 3, 5]) self.assertEqual(outer_rt.ragged_rank, 2) - with self.test_session(): - self.assertEqual(outer_rt.tolist(), - [[[3, 1, 4, 1], [], [5, 9, 2]], [], [[6], []]]) + self.assertEqual( + self.evaluate(outer_rt).tolist(), + [[[3, 1, 4, 1], [], [5, 9, 2]], [], [[6], []]]) del inner_rt, outer_rt # From section: "Multiple Ragged Dimensions" rt = ragged.from_nested_row_splits( inner_values=[3, 1, 4, 1, 5, 9, 2, 6], nested_row_splits=([0, 3, 3, 5], [0, 4, 4, 7, 8, 8])) - with self.test_session(): - self.assertEqual(rt.tolist(), - [[[3, 1, 4, 1], [], [5, 9, 2]], [], [[6], []]]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[3, 1, 4, 1], [], [5, 9, 2]], [], [[6], []]]) del rt # From section: "Uniform Inner Dimensions" rt = ragged.from_row_splits( values=array_ops.ones([5, 3]), row_splits=[0, 2, 5]) - with self.test_session(): - self.assertEqual( - rt.tolist(), - [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]]]) - self.assertEqual(rt.shape.as_list(), [2, None, 3]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]]]) + self.assertEqual(rt.shape.as_list(), [2, None, 3]) del rt #============================================================================= @@ -208,9 +205,9 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt = ragged.RaggedTensor( values=values, row_splits=row_splits, internal=True) - with self.test_session(): - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testRaggedTensorConstructionErrors(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -262,11 +259,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_value_rowids, value_rowids) # cached_value_rowids - with self.test_session(): - self.assertAllEqual(rt_value_rowids, value_rowids) - self.assertEqual(self.evaluate(rt_nrows), 5) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertAllEqual(rt_value_rowids, value_rowids) + self.assertEqual(self.evaluate(rt_nrows), 5) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromValueRowIdsWithDerivedNRowsDynamic(self): # nrows is not known at graph creation time. @@ -285,11 +282,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_value_rowids, value_rowids) # cached_value_rowids - with self.test_session(): - self.assertAllEqual(rt_value_rowids, value_rowids) - self.assertEqual(self.evaluate(rt_nrows), 5) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertAllEqual(rt_value_rowids, value_rowids) + self.assertEqual(self.evaluate(rt_nrows), 5) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromValueRowIdsWithExplicitNRows(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -308,10 +305,9 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_value_rowids, value_rowids) # cached_value_rowids self.assertIs(rt_nrows, nrows) # cached_nrows - with self.test_session(): - self.assertEqual( - rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g'], [], []]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g'], [], []]) def testFromValueRowIdsWithExplicitNRowsEqualToDefault(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -330,11 +326,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_value_rowids, value_rowids) # cached_value_rowids self.assertIs(rt_nrows, nrows) # cached_nrows - with self.test_session(): - self.assertAllEqual(rt_value_rowids, value_rowids) - self.assertAllEqual(rt_nrows, nrows) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertAllEqual(rt_value_rowids, value_rowids) + self.assertAllEqual(rt_nrows, nrows) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromValueRowIdsWithEmptyValues(self): rt = ragged.from_value_rowids([], []) @@ -344,9 +340,8 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertEqual(rt.ragged_rank, 1) self.assertEqual(rt.values.shape.as_list(), [0]) self.assertEqual(ragged.value_rowids(rt).shape.as_list(), [0]) - with self.test_session(): - self.assertEqual(self.evaluate(rt_nrows).tolist(), 0) - self.assertEqual(rt.tolist(), []) + self.assertEqual(self.evaluate(rt_nrows).tolist(), 0) + self.assertEqual(self.evaluate(rt).tolist(), []) def testFromRowSplits(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -363,10 +358,10 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_row_splits, row_splits) - with self.test_session(): - self.assertEqual(self.evaluate(rt_nrows), 5) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual(self.evaluate(rt_nrows), 5) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromRowSplitsWithEmptySplits(self): err_msg = 'row_splits tensor may not be empty' @@ -387,11 +382,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt_nrows = ragged.nrows(rt) self.assertIs(rt_values, values) - with self.test_session(): - self.assertEqual(self.evaluate(rt_nrows), 5) - self.assertAllEqual(rt_row_starts, row_starts) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual(self.evaluate(rt_nrows), 5) + self.assertAllEqual(rt_row_starts, row_starts) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromRowLimits(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -407,11 +402,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt_nrows = ragged.nrows(rt) self.assertIs(rt_values, values) - with self.test_session(): - self.assertEqual(self.evaluate(rt_nrows), 5) - self.assertAllEqual(rt_row_limits, row_limits) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual(self.evaluate(rt_nrows), 5) + self.assertAllEqual(rt_row_limits, row_limits) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromRowLengths(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -428,11 +423,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values, values) self.assertIs(rt_row_lengths, row_lengths) # cached_nrows - with self.test_session(): - self.assertEqual(self.evaluate(rt_nrows), 5) - self.assertAllEqual(rt_row_lengths, row_lengths) - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual(self.evaluate(rt_nrows), 5) + self.assertAllEqual(rt_row_lengths, row_lengths) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) def testFromNestedValueRowIdsWithDerivedNRows(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -452,12 +447,11 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt_values_value_rowids = ragged.value_rowids(rt_values) self.assertIs(rt_values_values, values) - with self.test_session(): - self.assertAllEqual(rt_value_rowids, nested_value_rowids[0]) - self.assertAllEqual(rt_values_value_rowids, nested_value_rowids[1]) - self.assertEqual( - rt.tolist(), - [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) + self.assertAllEqual(rt_value_rowids, nested_value_rowids[0]) + self.assertAllEqual(rt_values_value_rowids, nested_value_rowids[1]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) def testFromNestedValueRowIdsWithExplicitNRows(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -483,14 +477,14 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt_values_nrows = ragged.nrows(rt_values) self.assertIs(rt_values_values, values) - with self.test_session(): - self.assertAllEqual(rt_value_rowids, nested_value_rowids[0]) - self.assertAllEqual(rt_values_value_rowids, nested_value_rowids[1]) - self.assertAllEqual(rt_nrows, nrows[0]) - self.assertAllEqual(rt_values_nrows, nrows[1]) - self.assertEqual(rt.tolist(), - [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], - [[b'f'], [b'g'], []], [], []]) + self.assertAllEqual(rt_value_rowids, nested_value_rowids[0]) + self.assertAllEqual(rt_values_value_rowids, nested_value_rowids[1]) + self.assertAllEqual(rt_nrows, nrows[0]) + self.assertAllEqual(rt_values_nrows, nrows[1]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g'], []], [], + []]) def testFromNestedValueRowIdsWithExplicitNRowsMismatch(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -535,10 +529,9 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): self.assertIs(rt_values_values, inner_values) self.assertIs(rt_row_splits, nested_row_splits[0]) self.assertIs(rt_values_row_splits, nested_row_splits[1]) - with self.test_session(): - self.assertEqual( - rt.tolist(), - [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) def testFromNestedRowSplitsWithNonListInput(self): with self.assertRaisesRegexp(TypeError, @@ -603,31 +596,31 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt2 = ragged.from_value_rowids(values, value_rowids) for rt in [rt1, rt2]: - with self.test_session(): - self.assertEqual(rt.tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) - self.assertEqual( - self.evaluate(rt.values).tolist(), - [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) - self.assertEqual(rt.values.shape.dims[0].value, 7) - self.assertEqual( - self.evaluate(ragged.value_rowids(rt)).tolist(), - [0, 0, 2, 2, 2, 3, 4]) - self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 5) - self.assertEqual( - self.evaluate(rt.row_splits).tolist(), [0, 2, 2, 5, 6, 7]) - self.assertEqual( - self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 2, 5, 6]) - self.assertEqual( - self.evaluate(ragged.row_limits(rt)).tolist(), [2, 2, 5, 6, 7]) - self.assertEqual( - self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 0, 3, 1, 1]) - self.assertEqual( - self.evaluate(rt.inner_values).tolist(), - [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) - self.assertEqual( - [self.evaluate(s).tolist() for s in rt.nested_row_splits], - [[0, 2, 2, 5, 6, 7]]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual( + self.evaluate(rt.values).tolist(), + [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) + self.assertEqual(rt.values.shape.dims[0].value, 7) + self.assertEqual( + self.evaluate(ragged.value_rowids(rt)).tolist(), + [0, 0, 2, 2, 2, 3, 4]) + self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 5) + self.assertEqual( + self.evaluate(rt.row_splits).tolist(), [0, 2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 2, 5, 6]) + self.assertEqual( + self.evaluate(ragged.row_limits(rt)).tolist(), [2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 0, 3, 1, 1]) + self.assertEqual( + self.evaluate(rt.inner_values).tolist(), + [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) + self.assertEqual( + [self.evaluate(s).tolist() for s in rt.nested_row_splits], + [[0, 2, 2, 5, 6, 7]]) def testRaggedTensorAccessors_3d_with_ragged_rank_1(self): values = [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]] @@ -637,32 +630,32 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt2 = ragged.from_value_rowids(values, value_rowids) for rt in [rt1, rt2]: - with self.test_session(): - self.assertEqual(rt.tolist(), - [[[0, 1], [2, 3]], [], [[4, 5], [6, 7], [8, 9]], - [[10, 11]], [[12, 13]]]) - self.assertEqual( - self.evaluate(rt.values).tolist(), - [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]]) - self.assertEqual(rt.values.shape.dims[0].value, 7) - self.assertEqual( - self.evaluate(ragged.value_rowids(rt)).tolist(), - [0, 0, 2, 2, 2, 3, 4]) - self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 5) - self.assertEqual( - self.evaluate(rt.row_splits).tolist(), [0, 2, 2, 5, 6, 7]) - self.assertEqual( - self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 2, 5, 6]) - self.assertEqual( - self.evaluate(ragged.row_limits(rt)).tolist(), [2, 2, 5, 6, 7]) - self.assertEqual( - self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 0, 3, 1, 1]) - self.assertEqual( - self.evaluate(rt.inner_values).tolist(), - [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]]) - self.assertEqual( - [self.evaluate(s).tolist() for s in rt.nested_row_splits], - [[0, 2, 2, 5, 6, 7]]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[0, 1], [2, 3]], [], [[4, 5], [6, 7], [8, 9]], [[10, 11]], + [[12, 13]]]) + self.assertEqual( + self.evaluate(rt.values).tolist(), + [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]]) + self.assertEqual(rt.values.shape.dims[0].value, 7) + self.assertEqual( + self.evaluate(ragged.value_rowids(rt)).tolist(), + [0, 0, 2, 2, 2, 3, 4]) + self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 5) + self.assertEqual( + self.evaluate(rt.row_splits).tolist(), [0, 2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 2, 5, 6]) + self.assertEqual( + self.evaluate(ragged.row_limits(rt)).tolist(), [2, 2, 5, 6, 7]) + self.assertEqual( + self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 0, 3, 1, 1]) + self.assertEqual( + self.evaluate(rt.inner_values).tolist(), + [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]]) + self.assertEqual( + [self.evaluate(s).tolist() for s in rt.nested_row_splits], + [[0, 2, 2, 5, 6, 7]]) def testRaggedTensorAccessors_3d_with_ragged_rank_2(self): values = constant_op.constant(['a', 'b', 'c', 'd', 'e', 'f', 'g']) @@ -678,42 +671,39 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt2 = ragged.from_nested_value_rowids(values, nested_value_rowids) for rt in [rt1, rt2]: - with self.test_session(): - self.assertEqual( - rt.tolist(), - [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) - self.assertEqual( - self.evaluate(rt.values).tolist(), - [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) - self.assertEqual(rt.values.shape.dims[0].value, 5) - self.assertEqual( - self.evaluate(ragged.value_rowids(rt)).tolist(), [0, 0, 1, 3, 3]) - self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 4) - self.assertEqual(self.evaluate(rt.row_splits).tolist(), [0, 2, 3, 3, 5]) - self.assertEqual( - self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 3, 3]) - self.assertEqual( - self.evaluate(ragged.row_limits(rt)).tolist(), [2, 3, 3, 5]) - self.assertEqual( - self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 1, 0, 2]) - self.assertEqual( - self.evaluate(rt.inner_values).tolist(), - [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) - self.assertEqual( - [self.evaluate(s).tolist() for s in rt.nested_row_splits], - [[0, 2, 3, 3, 5], [0, 2, 2, 5, 6, 7]]) + self.assertEqual( + self.evaluate(rt).tolist(), + [[[b'a', b'b'], []], [[b'c', b'd', b'e']], [], [[b'f'], [b'g']]]) + self.assertEqual( + self.evaluate(rt.values).tolist(), + [[b'a', b'b'], [], [b'c', b'd', b'e'], [b'f'], [b'g']]) + self.assertEqual(rt.values.shape.dims[0].value, 5) + self.assertEqual( + self.evaluate(ragged.value_rowids(rt)).tolist(), [0, 0, 1, 3, 3]) + self.assertEqual(self.evaluate(ragged.nrows(rt)).tolist(), 4) + self.assertEqual(self.evaluate(rt.row_splits).tolist(), [0, 2, 3, 3, 5]) + self.assertEqual( + self.evaluate(ragged.row_starts(rt)).tolist(), [0, 2, 3, 3]) + self.assertEqual( + self.evaluate(ragged.row_limits(rt)).tolist(), [2, 3, 3, 5]) + self.assertEqual( + self.evaluate(ragged.row_lengths(rt)).tolist(), [2, 1, 0, 2]) + self.assertEqual( + self.evaluate(rt.inner_values).tolist(), + [b'a', b'b', b'c', b'd', b'e', b'f', b'g']) + self.assertEqual( + [self.evaluate(s).tolist() for s in rt.nested_row_splits], + [[0, 2, 3, 3, 5], [0, 2, 2, 5, 6, 7]]) def testNRowsWithTensorInput(self): dt = constant_op.constant([[1, 2, 3], [4, 5, 6]]) nrows = ragged.nrows(dt) - with self.test_session(): - self.assertEqual(self.evaluate(nrows), 2) + self.assertEqual(self.evaluate(nrows), 2) def testRowLengthsWithTensorInput(self): dt = constant_op.constant([[1, 2, 3], [4, 5, 6]]) row_lengths = ragged.row_lengths(dt) - with self.test_session(): - self.assertEqual(self.evaluate(row_lengths).tolist(), [3, 3]) + self.assertEqual(self.evaluate(row_lengths).tolist(), [3, 3]) #============================================================================= # RaggedTensor.shape @@ -766,29 +756,27 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): expected: The expected value of rt.__getitem__(slice_spec), as a python list; or an exception class. """ - with self.test_session(): - tensor_slice_spec1 = _make_tensor_slice_spec(slice_spec, True) - tensor_slice_spec2 = _make_tensor_slice_spec(slice_spec, False) - value1 = self.evaluate(rt.__getitem__(slice_spec)) - value2 = self.evaluate(rt.__getitem__(tensor_slice_spec1)) - value3 = self.evaluate(rt.__getitem__(tensor_slice_spec2)) - if hasattr(value1, 'tolist'): - value1 = value1.tolist() - if hasattr(value2, 'tolist'): - value2 = value2.tolist() - if hasattr(value3, 'tolist'): - value3 = value3.tolist() - self.assertEqual(value1, expected, 'slice_spec=%s' % (slice_spec,)) - self.assertEqual(value2, expected, 'slice_spec=%s' % (slice_spec,)) - self.assertEqual(value3, expected, 'slice_spec=%s' % (slice_spec,)) + tensor_slice_spec1 = _make_tensor_slice_spec(slice_spec, True) + tensor_slice_spec2 = _make_tensor_slice_spec(slice_spec, False) + value1 = self.evaluate(rt.__getitem__(slice_spec)) + value2 = self.evaluate(rt.__getitem__(tensor_slice_spec1)) + value3 = self.evaluate(rt.__getitem__(tensor_slice_spec2)) + if hasattr(value1, 'tolist'): + value1 = value1.tolist() + if hasattr(value2, 'tolist'): + value2 = value2.tolist() + if hasattr(value3, 'tolist'): + value3 = value3.tolist() + self.assertEqual(value1, expected, 'slice_spec=%s' % (slice_spec,)) + self.assertEqual(value2, expected, 'slice_spec=%s' % (slice_spec,)) + self.assertEqual(value3, expected, 'slice_spec=%s' % (slice_spec,)) def _TestGetItemException(self, rt, slice_spec, expected, message): """Helper function for testing RaggedTensor.__getitem__ exceptions.""" - with self.test_session(): - tensor_slice_spec1 = _make_tensor_slice_spec(slice_spec, True) - self.assertRaisesRegexp(expected, message, rt.__getitem__, slice_spec) - self.assertRaisesRegexp(expected, message, rt.__getitem__, - tensor_slice_spec1) + tensor_slice_spec1 = _make_tensor_slice_spec(slice_spec, True) + self.assertRaisesRegexp(expected, message, rt.__getitem__, slice_spec) + self.assertRaisesRegexp(expected, message, rt.__getitem__, + tensor_slice_spec1) @parameterized.parameters( # Tests for rt[i] @@ -860,8 +848,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt = ragged.from_row_splits(EXAMPLE_RAGGED_TENSOR_2D_VALUES, EXAMPLE_RAGGED_TENSOR_2D_SPLITS) - with self.test_session(): - self.assertEqual(rt.tolist(), EXAMPLE_RAGGED_TENSOR_2D) + self.assertEqual(self.evaluate(rt).tolist(), EXAMPLE_RAGGED_TENSOR_2D) self._TestGetItem(rt, slice_spec, expected) # pylint: disable=invalid-slice-index @@ -905,8 +892,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): # if sys.version_info[0] == 3: # message = 'must be str, not int' - with self.test_session(): - self.assertEqual(rt.tolist(), EXAMPLE_RAGGED_TENSOR_2D) + self.assertEqual(self.evaluate(rt).tolist(), EXAMPLE_RAGGED_TENSOR_2D) self._TestGetItemException(rt, slice_spec, expected, message) @parameterized.parameters( @@ -980,8 +966,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt = ragged.from_nested_row_splits( EXAMPLE_RAGGED_TENSOR_4D_VALUES, [EXAMPLE_RAGGED_TENSOR_4D_SPLITS1, EXAMPLE_RAGGED_TENSOR_4D_SPLITS2]) - with self.test_session(): - self.assertEqual(rt.tolist(), EXAMPLE_RAGGED_TENSOR_4D) + self.assertEqual(self.evaluate(rt).tolist(), EXAMPLE_RAGGED_TENSOR_4D) self._TestGetItem(rt, slice_spec, expected) @parameterized.parameters( @@ -1003,8 +988,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt = ragged.from_nested_row_splits( EXAMPLE_RAGGED_TENSOR_4D_VALUES, [EXAMPLE_RAGGED_TENSOR_4D_SPLITS1, EXAMPLE_RAGGED_TENSOR_4D_SPLITS2]) - with self.test_session(): - self.assertEqual(rt.tolist(), EXAMPLE_RAGGED_TENSOR_4D) + self.assertEqual(self.evaluate(rt).tolist(), EXAMPLE_RAGGED_TENSOR_4D) self._TestGetItemException(rt, slice_spec, expected, message) @parameterized.parameters( @@ -1044,8 +1028,7 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): EXAMPLE_RAGGED_TENSOR_2D_SPLITS, dtype=dtypes.int64) splits = array_ops.placeholder_with_default(splits, None) rt = ragged.from_row_splits(EXAMPLE_RAGGED_TENSOR_2D_VALUES, splits) - with self.test_session(): - self.assertEqual(rt.tolist(), EXAMPLE_RAGGED_TENSOR_2D) + self.assertEqual(self.evaluate(rt).tolist(), EXAMPLE_RAGGED_TENSOR_2D) self._TestGetItem(rt, slice_spec, expected) @parameterized.parameters( @@ -1065,43 +1048,43 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): splits2 = [0, 2, 2, 3] values = constant_op.constant([['a', 'b'], ['c', 'd'], ['e', 'f']]) rt = ragged.from_nested_row_splits(values, [splits1, splits2]) - with self.test_session(): - rt_newaxis0 = rt[array_ops.newaxis] - rt_newaxis1 = rt[:, array_ops.newaxis] - rt_newaxis2 = rt[:, :, array_ops.newaxis] - rt_newaxis3 = rt[:, :, :, array_ops.newaxis] - rt_newaxis4 = rt[:, :, :, :, array_ops.newaxis] - - self.assertEqual(rt.tolist(), - [[[[b'a', b'b'], [b'c', b'd']], [], [[b'e', b'f']]], []]) - self.assertEqual( - rt_newaxis0.tolist(), - [[[[[b'a', b'b'], [b'c', b'd']], [], [[b'e', b'f']]], []]]) - self.assertEqual( - rt_newaxis1.tolist(), - [[[[[b'a', b'b'], [b'c', b'd']], [], [[b'e', b'f']]]], [[]]]) - self.assertEqual( - rt_newaxis2.tolist(), - [[[[[b'a', b'b'], [b'c', b'd']]], [[]], [[[b'e', b'f']]]], []]) - self.assertEqual( - rt_newaxis3.tolist(), - [[[[[b'a', b'b']], [[b'c', b'd']]], [], [[[b'e', b'f']]]], []]) - self.assertEqual( - rt_newaxis4.tolist(), - [[[[[b'a'], [b'b']], [[b'c'], [b'd']]], [], [[[b'e'], [b'f']]]], []]) - - self.assertEqual(rt.ragged_rank, 2) - self.assertEqual(rt_newaxis0.ragged_rank, 3) - self.assertEqual(rt_newaxis1.ragged_rank, 3) - self.assertEqual(rt_newaxis2.ragged_rank, 3) - self.assertEqual(rt_newaxis3.ragged_rank, 2) - self.assertEqual(rt_newaxis4.ragged_rank, 2) - - self.assertEqual(rt_newaxis0.shape.as_list(), [1, None, None, None, 2]) - self.assertEqual(rt_newaxis1.shape.as_list(), [2, None, None, None, 2]) - self.assertEqual(rt_newaxis2.shape.as_list(), [2, None, None, None, 2]) - self.assertEqual(rt_newaxis3.shape.as_list(), [2, None, None, 1, 2]) - self.assertEqual(rt_newaxis4.shape.as_list(), [2, None, None, 2, 1]) + rt_newaxis0 = rt[array_ops.newaxis] + rt_newaxis1 = rt[:, array_ops.newaxis] + rt_newaxis2 = rt[:, :, array_ops.newaxis] + rt_newaxis3 = rt[:, :, :, array_ops.newaxis] + rt_newaxis4 = rt[:, :, :, :, array_ops.newaxis] + + self.assertEqual( + self.evaluate(rt).tolist(), + [[[[b'a', b'b'], [b'c', b'd']], [], [[b'e', b'f']]], []]) + self.assertEqual( + self.evaluate(rt_newaxis0).tolist(), + [[[[[b'a', b'b'], [b'c', b'd']], [], [[b'e', b'f']]], []]]) + self.assertEqual( + self.evaluate(rt_newaxis1).tolist(), + [[[[[b'a', b'b'], [b'c', b'd']], [], [[b'e', b'f']]]], [[]]]) + self.assertEqual( + self.evaluate(rt_newaxis2).tolist(), + [[[[[b'a', b'b'], [b'c', b'd']]], [[]], [[[b'e', b'f']]]], []]) + self.assertEqual( + self.evaluate(rt_newaxis3).tolist(), + [[[[[b'a', b'b']], [[b'c', b'd']]], [], [[[b'e', b'f']]]], []]) + self.assertEqual( + self.evaluate(rt_newaxis4).tolist(), + [[[[[b'a'], [b'b']], [[b'c'], [b'd']]], [], [[[b'e'], [b'f']]]], []]) + + self.assertEqual(rt.ragged_rank, 2) + self.assertEqual(rt_newaxis0.ragged_rank, 3) + self.assertEqual(rt_newaxis1.ragged_rank, 3) + self.assertEqual(rt_newaxis2.ragged_rank, 3) + self.assertEqual(rt_newaxis3.ragged_rank, 2) + self.assertEqual(rt_newaxis4.ragged_rank, 2) + + self.assertEqual(rt_newaxis0.shape.as_list(), [1, None, None, None, 2]) + self.assertEqual(rt_newaxis1.shape.as_list(), [2, None, None, None, 2]) + self.assertEqual(rt_newaxis2.shape.as_list(), [2, None, None, None, 2]) + self.assertEqual(rt_newaxis3.shape.as_list(), [2, None, None, 1, 2]) + self.assertEqual(rt_newaxis4.shape.as_list(), [2, None, None, 2, 1]) #============================================================================= # RaggedTensor.__str__ @@ -1151,13 +1134,15 @@ class RaggedTensorTest(test_util.TensorFlowTestCase, parameterized.TestCase): rt2_times_10 = rt2.with_inner_values(rt2.inner_values * 10) rt1_expanded = rt1.with_values(array_ops.expand_dims(rt1.values, axis=1)) - with self.test_session(): - self.assertEqual(rt1_plus_10.tolist(), - [[11, 12], [13, 14, 15], [16], [], [17]]) - self.assertEqual(rt2_times_10.tolist(), - [[[10, 20], [30, 40, 50]], [[60]], [], [[], [70]]]) - self.assertEqual(rt1_expanded.tolist(), - [[[1], [2]], [[3], [4], [5]], [[6]], [], [[7]]]) + self.assertEqual( + self.evaluate(rt1_plus_10).tolist(), + [[11, 12], [13, 14, 15], [16], [], [17]]) + self.assertEqual( + self.evaluate(rt2_times_10).tolist(), + [[[10, 20], [30, 40, 50]], [[60]], [], [[], [70]]]) + self.assertEqual( + self.evaluate(rt1_expanded).tolist(), + [[[1], [2]], [[3], [4], [5]], [[6]], [], [[7]]]) #============================================================================= # Session.run -- GitLab From 567c0692de57f0a6b2680b510aa731281a7081e0 Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Tue, 27 Nov 2018 22:25:15 -0800 Subject: [PATCH 438/672] Implement some OptionalVariants functionality. * ZerosLike variant registry function * BinaryAdd variant registry function * Shape variant registry function * Enables copying nested variants between host/devices * Refactors some common code from the corresponding TensorList functions. This should also enable TensorLists containing OptionalVariants (previously some of this code assumed any nested variant was also a TensorList). PiperOrigin-RevId: 223112633 --- tensorflow/core/BUILD | 1 + tensorflow/core/kernels/data/BUILD | 5 + tensorflow/core/kernels/data/optional_ops.cc | 104 ++++---------- .../core/kernels/data/optional_ops.cu.cc | 37 +++++ tensorflow/core/kernels/data/optional_ops.h | 119 ++++++++++++++++ tensorflow/core/kernels/list_kernels.h | 87 +----------- tensorflow/core/util/tensor_ops_util.h | 128 ++++++++++++++++++ .../python/data/kernel_tests/optional_test.py | 120 ++++++++++++++++ 8 files changed, 440 insertions(+), 161 deletions(-) create mode 100644 tensorflow/core/kernels/data/optional_ops.cu.cc create mode 100644 tensorflow/core/util/tensor_ops_util.h diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 20b1916e7d..9cd0edabdd 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -928,6 +928,7 @@ tf_cuda_library( "util/stream_executor_util.h", "util/strided_slice_op.h", "util/tensor_format.h", + "util/tensor_ops_util.h", "util/tensor_slice_reader.h", "util/tensor_slice_reader_cache.h", "util/tensor_slice_writer.h", diff --git a/tensorflow/core/kernels/data/BUILD b/tensorflow/core/kernels/data/BUILD index dcb6975669..f1eeda20d3 100644 --- a/tensorflow/core/kernels/data/BUILD +++ b/tensorflow/core/kernels/data/BUILD @@ -621,6 +621,10 @@ tf_kernel_library( name = "optional_ops", srcs = ["optional_ops.cc"], hdrs = ["optional_ops.h"], + gpu_srcs = [ + "optional_ops.cu.cc", + "optional_ops.h", + ], deps = [ "//tensorflow/core:core_cpu_internal", "//tensorflow/core:dataset_ops_op_lib", @@ -628,6 +632,7 @@ tf_kernel_library( "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:protos_all_cc", + "//third_party/eigen3", ], ) diff --git a/tensorflow/core/kernels/data/optional_ops.cc b/tensorflow/core/kernels/data/optional_ops.cc index 2ab5c83082..bee857f53c 100644 --- a/tensorflow/core/kernels/data/optional_ops.cc +++ b/tensorflow/core/kernels/data/optional_ops.cc @@ -22,75 +22,6 @@ limitations under the License. namespace tensorflow { namespace data { namespace { -const char kOptionalVariantTypeName[] = "tensorflow::data::Optional"; - -// An `OptionalVariant` can represent either an "actual value" (a tuple of -// tensors) or "none", and may be stored in a DT_VARIANT tensor. -class OptionalVariant { - public: - // Create an `OptionalVariant` with no actual value. - OptionalVariant() : values_(nullptr) {} - - // Create an `OptionalVariant` with the actual value given by the tuple of - // tensors in `values`. - explicit OptionalVariant(std::vector values) - : values_(new std::vector(std::move(values))) {} - - OptionalVariant(const OptionalVariant& other) : values_(other.values_) {} - - // Returns true if `this` represents an actual value. - bool has_value() const { return values_ != nullptr; } - - // REQUIRES: `this->has_value()` must be true. - const std::vector& get_values() const { - CHECK(values_) << "Tried to get values from an empty OptionalVariant"; - return *values_; - } - - // Implementations of the necessary methods for using `OptionalVariant` - // objects in DT_VARIANT tensors. - string TypeName() const { return kOptionalVariantTypeName; } - void Encode(VariantTensorData* data) const { - data->set_metadata(values_ != nullptr); - if (values_ != nullptr) { - for (const auto& t : *values_) { - *(data->add_tensors()) = t; - } - } - } - - bool Decode(const VariantTensorData& data) { - if (data.type_name() != TypeName()) { - return false; - } - bool has_value = false; - if (!data.get_metadata(&has_value)) { - return false; - } - if (has_value) { - values_.reset(new std::vector(data.tensors())); - } else { - values_.reset(); - } - return true; - } - - string DebugString() const { - if (values_) { - return strings::StrCat("OptionalVariant<", "values: (", - str_util::Join(*values_, ", ", - [](string* s, const Tensor& elem) { - *s = elem.DebugString(); - }), - ")>"); - } else { - return strings::StrCat("OptionalVariant"); - } - } - - private: - std::shared_ptr> values_; -}; class OptionalNoneOp : public OpKernel { public: @@ -143,6 +74,12 @@ class OptionalGetValueOp : public OpKernel { explicit OptionalGetValueOp(OpKernelConstruction* ctx) : OpKernel(ctx) { OP_REQUIRES_OK(ctx, ctx->GetAttr("output_shapes", &output_shapes_)); OP_REQUIRES_OK(ctx, ctx->GetAttr("output_types", &output_types_)); + OP_REQUIRES( + ctx, output_shapes_.size() == output_types_.size(), + errors::InvalidArgument( + "output_types and output_shapes must be same length, got:\n", + "output_types: ", output_types_.size(), "\n", + "output_shapes: ", output_shapes_.size())); } void Compute(OpKernelContext* ctx) override { @@ -162,6 +99,10 @@ class OptionalGetValueOp : public OpKernel { ctx, optional->has_value(), errors::InvalidArgument("The given optional does not have a value.")); const auto& components = optional->get_values(); + OP_REQUIRES(ctx, components.size() == output_types_.size(), + errors::InvalidArgument( + "The given optional has ", components.size(), + " components, expected ", output_types_.size())); for (int i = 0; i < components.size(); ++i) { OP_REQUIRES( ctx, components[i].dtype() == output_types_[i], @@ -213,15 +154,7 @@ static Status OptionalDeviceCopy( std::vector to_values; to_values.reserve(from_values.size()); for (const Tensor& t : from_values) { - if (t.dtype() == DT_VARIANT) { - // TODO(b/116349787): Implement support for nested variants. - return errors::Unimplemented( - "Support for copying nested variants to device has not yet been " - "implemented."); - } - } - for (const Tensor& t : from_values) { - if (DMAHelper::CanUseDMA(&t)) { + if (DMAHelper::CanUseDMA(&t) || t.dtype() == DT_VARIANT) { Tensor tmp(t.dtype()); TF_RETURN_IF_ERROR(copy(t, &tmp)); to_values.push_back(std::move(tmp)); @@ -272,5 +205,20 @@ Status WriteOptionalNoneToOutput(OpKernelContext* ctx, int output_index) { return Status::OK(); } +REGISTER_UNARY_VARIANT_UNARY_OP_FUNCTION(ZEROS_LIKE_VARIANT_UNARY_OP, + DEVICE_CPU, OptionalVariant, + OptionalZerosLike); + +REGISTER_UNARY_VARIANT_BINARY_OP_FUNCTION(ADD_VARIANT_BINARY_OP, DEVICE_CPU, + OptionalVariant, + OptionalBinaryAdd); + +Status OptionalShape(const OptionalVariant& x, TensorShape* s) { + *s = TensorShape({}); + return Status::OK(); +} + +REGISTER_UNARY_VARIANT_SHAPE_FUNCTION(OptionalVariant, OptionalShape); + } // namespace data } // namespace tensorflow diff --git a/tensorflow/core/kernels/data/optional_ops.cu.cc b/tensorflow/core/kernels/data/optional_ops.cu.cc new file mode 100644 index 0000000000..eb4a95a6f2 --- /dev/null +++ b/tensorflow/core/kernels/data/optional_ops.cu.cc @@ -0,0 +1,37 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#define EIGEN_USE_THREADS +#if GOOGLE_CUDA +#define EIGEN_USE_GPU + +#include "tensorflow/core/kernels/data/optional_ops.h" + +#include "tensorflow/core/framework/variant_op_registry.h" + +namespace tensorflow { +namespace data { + +REGISTER_UNARY_VARIANT_UNARY_OP_FUNCTION(ZEROS_LIKE_VARIANT_UNARY_OP, + DEVICE_GPU, OptionalVariant, + OptionalZerosLike); + +REGISTER_UNARY_VARIANT_BINARY_OP_FUNCTION(ADD_VARIANT_BINARY_OP, DEVICE_GPU, + OptionalVariant, + OptionalBinaryAdd); + +} // namespace data +} // namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/data/optional_ops.h b/tensorflow/core/kernels/data/optional_ops.h index 2cbf2933f5..ef14e84311 100644 --- a/tensorflow/core/kernels/data/optional_ops.h +++ b/tensorflow/core/kernels/data/optional_ops.h @@ -19,10 +19,13 @@ limitations under the License. #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/variant_tensor_data.h" +#include "tensorflow/core/util/tensor_ops_util.h" namespace tensorflow { namespace data { +const char kOptionalVariantTypeName[] = "tensorflow::data::Optional"; + // Stores a DT_VARIANT value representing an Optional with the given value // in the `output_index`^th output of the given kernel execution context. Status WriteOptionalWithValueToOutput(OpKernelContext* ctx, int output_index, @@ -32,6 +35,122 @@ Status WriteOptionalWithValueToOutput(OpKernelContext* ctx, int output_index, // in the `output_index`^th output of the given kernel execution context. Status WriteOptionalNoneToOutput(OpKernelContext* ctx, int output_index); +// An `OptionalVariant` can represent either an "actual value" (a tuple of +// tensors) or "none", and may be stored in a DT_VARIANT tensor. +class OptionalVariant { + public: + // Create an `OptionalVariant` with no actual value. + OptionalVariant() : values_(nullptr) {} + + // Create an `OptionalVariant` with the actual value given by the tuple of + // tensors in `values`. + explicit OptionalVariant(std::vector values) + : values_(new std::vector(std::move(values))) {} + + OptionalVariant(const OptionalVariant& other) : values_(other.values_) {} + + // Returns true if `this` represents an actual value. + bool has_value() const { return values_ != nullptr; } + + // REQUIRES: `this->has_value()` must be true. + const std::vector& get_values() const { + DCHECK(values_) << "Tried to get values from an empty OptionalVariant"; + return *values_; + } + + // Implementations of the necessary methods for using `OptionalVariant` + // objects in DT_VARIANT tensors. + string TypeName() const { return kOptionalVariantTypeName; } + void Encode(VariantTensorData* data) const { + data->set_metadata(values_ != nullptr); + if (values_ != nullptr) { + for (const auto& t : *values_) { + *(data->add_tensors()) = t; + } + } + } + + bool Decode(const VariantTensorData& data) { + if (data.type_name() != TypeName()) { + return false; + } + bool has_value = false; + if (!data.get_metadata(&has_value)) { + return false; + } + if (has_value) { + values_.reset(new std::vector(data.tensors())); + } else { + values_.reset(); + } + return true; + } + + string DebugString() const { + if (values_) { + return strings::StrCat("OptionalVariant<", "values: (", + str_util::Join(*values_, ", ", + [](string* s, const Tensor& elem) { + *s = elem.DebugString(); + }), + ")>"); + } else { + return strings::StrCat("OptionalVariant"); + } + } + + private: + std::shared_ptr> values_; +}; + +template +Status OptionalZerosLike(OpKernelContext* ctx, const OptionalVariant& x, + OptionalVariant* y) { + if (!x.has_value()) { + *y = x; + return Status::OK(); + } + std::vector zero_tensors; + for (const Tensor& tensor : x.get_values()) { + Tensor zero_t; + TF_RETURN_IF_ERROR(ZerosLikeTensor(ctx, tensor, &zero_t)); + zero_tensors.push_back(std::move(zero_t)); + } + *y = OptionalVariant(zero_tensors); + return Status::OK(); +} + +template +Status OptionalBinaryAdd(OpKernelContext* ctx, const OptionalVariant& a, + const OptionalVariant& b, OptionalVariant* out) { + // TODO(skyewm): should adding a value to a non-value be a no-op instead? + if (a.has_value() != b.has_value()) { + return errors::InvalidArgument( + "Cannot add optionals because one has a value and the other doesn't."); + } + if (!a.has_value()) { + *out = a; + return Status::OK(); + } + if (a.get_values().size() != b.get_values().size()) { + return errors::InvalidArgument( + "Cannot add optionals because they have different numbers of " + "components (", + a.get_values().size(), " vs. ", b.get_values().size(), ")."); + } + std::vector out_tensors; + for (int i = 0; i < a.get_values().size(); ++i) { + const Tensor& a_tensor = a.get_values()[i]; + const Tensor& b_tensor = b.get_values()[i]; + Tensor out_tensor; + TF_RETURN_IF_ERROR( + BinaryAddTensors(ctx, a_tensor, b_tensor, &out_tensor)); + out_tensors.push_back(std::move(out_tensor)); + } + *out = OptionalVariant(out_tensors); + return Status::OK(); +} + } // namespace data } // namespace tensorflow diff --git a/tensorflow/core/kernels/list_kernels.h b/tensorflow/core/kernels/list_kernels.h index 75d91aff49..d4adc068a2 100644 --- a/tensorflow/core/kernels/list_kernels.h +++ b/tensorflow/core/kernels/list_kernels.h @@ -30,6 +30,7 @@ limitations under the License. #include "tensorflow/core/kernels/concat_lib.h" #include "tensorflow/core/lib/core/coding.h" #include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/util/tensor_ops_util.h" #include "tensorflow/core/util/util.h" namespace tensorflow { @@ -357,51 +358,10 @@ Status TensorListBinaryAdd(OpKernelContext* c, const TensorList& a, for (int i = 0; i < a.tensors.size(); ++i) { const Tensor& a_tensor = a.tensors[i]; const Tensor& b_tensor = b.tensors[i]; - if (a_tensor.dtype() == DT_INVALID) { - out->tensors.push_back(b_tensor); - continue; - } - if (b_tensor.dtype() == DT_INVALID) { - out->tensors.push_back(a_tensor); - continue; - } - if (a_tensor.shape() != b_tensor.shape()) { - // TODO(apassos) support broadcasting additions here? - return errors::InvalidArgument( - "Trying to add two tensors with incompatible element shapes. " - "One is ", - a_tensor.shape().DebugString(), " and the other is ", - b_tensor.shape().DebugString(), " in position ", i); - } Tensor out_tensor; - AllocatorAttributes attr; - if (a_tensor.dtype() == DT_VARIANT) { - attr.set_on_host(true); - } - TF_RETURN_IF_ERROR(c->allocate_temp(a_tensor.dtype(), a_tensor.shape(), - &out_tensor, attr)); + TF_RETURN_IF_ERROR( + BinaryAddTensors(c, a_tensor, b_tensor, &out_tensor)); out->tensors.push_back(out_tensor); - switch (out_tensor.dtype()) { -#define DTYPE_CASE(dtype) \ - case DataTypeToEnum::value: \ - out_tensor.flat().device(c->eigen_device()) = \ - a_tensor.flat() + b_tensor.flat(); \ - break; - - TF_CALL_NUMBER_TYPES(DTYPE_CASE) - -#undef DTYPE_CASE - case DataTypeToEnum::value: { - Variant* v_out = &(out_tensor.scalar()()); - TF_RETURN_IF_ERROR(BinaryOpVariants( - c, ADD_VARIANT_BINARY_OP, a_tensor.scalar()(), - b_tensor.scalar()(), v_out)); - break; - } - default: - return errors::InvalidArgument("Trying to add unsupported dtype ", - out_tensor.dtype()); - } } return Status::OK(); } @@ -414,46 +374,7 @@ Status TensorListZerosLike(OpKernelContext* c, const TensorList& x, y->tensors.reserve(x.tensors.size()); for (const Tensor& t : x.tensors) { Tensor out_tensor; - AllocatorAttributes attr; - if (t.dtype() == DT_VARIANT) { - attr.set_on_host(true); - } - TF_RETURN_IF_ERROR( - c->allocate_temp(t.dtype(), t.shape(), &out_tensor, attr)); - switch (out_tensor.dtype()) { -#define DTYPE_CASE(dtype) \ - case DataTypeToEnum::value: \ - out_tensor.flat().device(c->eigen_device()) = \ - out_tensor.flat().constant(dtype(0)); \ - break; - - TF_CALL_POD_TYPES(DTYPE_CASE) - -#undef DTYPE_CASE - - case DT_INVALID: { - // Uninitialized tensor in the TensorList. - out_tensor = Tensor(DT_INVALID); - break; - } - case DataTypeToEnum::value: { - const TensorList* inner_x = t.scalar()().get(); - if (inner_x == nullptr) { - return errors::InvalidArgument("Input handle is not a list. Saw: '", - t.scalar()().DebugString(), - "'"); - } - TensorList inner_y; - TF_RETURN_IF_ERROR(TensorListZerosLike(c, *inner_x, &inner_y)); - out_tensor.scalar()() = std::move(inner_y); - break; - } - - default: - return errors::InvalidArgument( - "Trying to compute zeros_like for unsupported dtype ", - DataTypeString(out_tensor.dtype())); - } + TF_RETURN_IF_ERROR(ZerosLikeTensor(c, t, &out_tensor)); y->tensors.emplace_back(out_tensor); } return Status::OK(); diff --git a/tensorflow/core/util/tensor_ops_util.h b/tensorflow/core/util/tensor_ops_util.h new file mode 100644 index 0000000000..615f088a9b --- /dev/null +++ b/tensorflow/core/util/tensor_ops_util.h @@ -0,0 +1,128 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#ifndef TENSORFLOW_CORE_UTIL_TENSOR_OPS_UTIL_H_ +#define TENSORFLOW_CORE_UTIL_TENSOR_OPS_UTIL_H_ + +#define EIGEN_USE_THREADS + +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/framework/types.h" +#include "tensorflow/core/framework/variant_op_registry.h" +#include "tensorflow/core/lib/core/status.h" + +namespace tensorflow { + +typedef Eigen::ThreadPoolDevice CPUDevice; +typedef Eigen::GpuDevice GPUDevice; + +template +Status ZerosLikeTensor(OpKernelContext* ctx, const Tensor& x, Tensor* out) { + AllocatorAttributes attr; + if (x.dtype() == DT_VARIANT) { + attr.set_on_host(true); + } + TF_RETURN_IF_ERROR(ctx->allocate_temp(x.dtype(), x.shape(), out, attr)); + + switch (out->dtype()) { +#define DTYPE_CASE(dtype) \ + case DataTypeToEnum::value: \ + /* TODO(skyewm): use SetZeroFunctor like in ZerosLikeOp? */ \ + out->flat().device(ctx->eigen_device()) = \ + out->flat().constant(dtype(0)); \ + break; + + TF_CALL_POD_TYPES(DTYPE_CASE) +#undef DTYPE_CASE + + case DT_INVALID: { + *out = Tensor(DT_INVALID); + break; + } + case DataTypeToEnum::value: { + Variant* out_variant = out->scalar().data(); + TF_RETURN_IF_ERROR( + UnaryOpVariant(ctx, ZEROS_LIKE_VARIANT_UNARY_OP, + x.scalar()(), out_variant)); + break; + } + default: + return errors::InvalidArgument( + "Trying to compute zeros_like for unsupported dtype ", + DataTypeString(out->dtype())); + } + return Status::OK(); +} + +template +Status BinaryAddTensors(OpKernelContext* ctx, const Tensor& a, const Tensor& b, + Tensor* out) { + if (a.dtype() == DT_INVALID) { + *out = b; + return Status::OK(); + } + if (b.dtype() == DT_INVALID) { + *out = a; + return Status::OK(); + } + if (a.dtype() != b.dtype()) { + return errors::InvalidArgument( + "Trying to add two tensors with incompatible element types. ", + "One is ", DataTypeString(a.dtype()), " and the other is ", + DataTypeString(b.dtype())); + } + if (a.shape() != b.shape()) { + // TODO(apassos) support broadcasting additions here? + return errors::InvalidArgument( + "Trying to add two tensors with incompatible element shapes. ", + "One is ", a.shape().DebugString(), " and the other is ", + b.shape().DebugString()); + } + + AllocatorAttributes attr; + if (a.dtype() == DT_VARIANT) { + attr.set_on_host(true); + } + TF_RETURN_IF_ERROR(ctx->allocate_temp(a.dtype(), a.shape(), out, attr)); + + switch (out->dtype()) { +#define DTYPE_CASE(dtype) \ + case DataTypeToEnum::value: \ + out->flat().device(ctx->eigen_device()) = \ + a.flat() + b.flat(); \ + break; + + TF_CALL_NUMBER_TYPES(DTYPE_CASE) +#undef DTYPE_CASE + + case DataTypeToEnum::value: { + Variant* out_variant = out->scalar().data(); + TF_RETURN_IF_ERROR(BinaryOpVariants( + ctx, ADD_VARIANT_BINARY_OP, a.scalar()(), + b.scalar()(), out_variant)); + break; + } + default: + return errors::InvalidArgument("Trying to add unsupported dtype ", + out->dtype()); + } + return Status::OK(); +} + +} // namespace tensorflow + +#endif // TENSORFLOW_CORE_UTIL_TENSOR_OPS_UTIL_H_ diff --git a/tensorflow/python/data/kernel_tests/optional_test.py b/tensorflow/python/data/kernel_tests/optional_test.py index 856985e9fd..864013171d 100644 --- a/tensorflow/python/data/kernel_tests/optional_test.py +++ b/tensorflow/python/data/kernel_tests/optional_test.py @@ -33,6 +33,7 @@ from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -87,6 +88,90 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): with self.assertRaises(errors.InvalidArgumentError): self.evaluate(opt.get_value()) + def testAddN(self): + devices = ["/cpu:0"] + if test_util.is_gpu_available(): + devices.append("/gpu:0") + for device in devices: + with ops.device(device): + # With value + opt1 = optional_ops.Optional.from_value((1.0, 2.0)) + opt2 = optional_ops.Optional.from_value((3.0, 4.0)) + + add_tensor = math_ops.add_n([opt1._variant_tensor, + opt2._variant_tensor]) + add_opt = optional_ops._OptionalImpl(add_tensor, opt1.value_structure) + self.assertAllEqual(self.evaluate(add_opt.get_value()), (4.0, 6.0)) + + # Without value + opt_none1 = optional_ops.Optional.none_from_structure( + opt1.value_structure) + opt_none2 = optional_ops.Optional.none_from_structure( + opt2.value_structure) + add_tensor = math_ops.add_n([opt_none1._variant_tensor, + opt_none2._variant_tensor]) + add_opt = optional_ops._OptionalImpl(add_tensor, + opt_none1.value_structure) + self.assertFalse(self.evaluate(add_opt.has_value())) + + def testNestedAddN(self): + devices = ["/cpu:0"] + if test_util.is_gpu_available(): + devices.append("/gpu:0") + for device in devices: + with ops.device(device): + opt1 = optional_ops.Optional.from_value([1, 2.0]) + opt2 = optional_ops.Optional.from_value([3, 4.0]) + opt3 = optional_ops.Optional.from_value((5.0, opt1._variant_tensor)) + opt4 = optional_ops.Optional.from_value((6.0, opt2._variant_tensor)) + + add_tensor = math_ops.add_n([opt3._variant_tensor, + opt4._variant_tensor]) + add_opt = optional_ops._OptionalImpl(add_tensor, opt3.value_structure) + self.assertEqual(self.evaluate(add_opt.get_value()[0]), 11.0) + + inner_add_opt = optional_ops._OptionalImpl(add_opt.get_value()[1], + opt1.value_structure) + self.assertAllEqual(inner_add_opt.get_value(), [4, 6.0]) + + def testZerosLike(self): + devices = ["/cpu:0"] + if test_util.is_gpu_available(): + devices.append("/gpu:0") + for device in devices: + with ops.device(device): + # With value + opt = optional_ops.Optional.from_value((1.0, 2.0)) + zeros_tensor = array_ops.zeros_like(opt._variant_tensor) + zeros_opt = optional_ops._OptionalImpl(zeros_tensor, + opt.value_structure) + self.assertAllEqual(self.evaluate(zeros_opt.get_value()), + (0.0, 0.0)) + + # Without value + opt_none = optional_ops.Optional.none_from_structure( + opt.value_structure) + zeros_tensor = array_ops.zeros_like(opt_none._variant_tensor) + zeros_opt = optional_ops._OptionalImpl(zeros_tensor, + opt_none.value_structure) + self.assertFalse(self.evaluate(zeros_opt.has_value())) + + def testNestedZerosLike(self): + devices = ["/cpu:0"] + if test_util.is_gpu_available(): + devices.append("/gpu:0") + for device in devices: + with ops.device(device): + opt1 = optional_ops.Optional.from_value(1.0) + opt2 = optional_ops.Optional.from_value(opt1._variant_tensor) + + zeros_tensor = array_ops.zeros_like(opt2._variant_tensor) + zeros_opt = optional_ops._OptionalImpl(zeros_tensor, + opt2.value_structure) + inner_zeros_opt = optional_ops._OptionalImpl(zeros_opt.get_value(), + opt1.value_structure) + self.assertEqual(self.evaluate(inner_zeros_opt.get_value()), 0.0) + def testCopyToGPU(self): if not test_util.is_gpu_available(): self.skipTest("No GPU available") @@ -116,6 +201,41 @@ class OptionalTest(test_base.DatasetTestBase, parameterized.TestCase): self.evaluate(gpu_optional_with_value_values)) self.assertFalse(self.evaluate(gpu_optional_none_has_value)) + def testNestedCopyToGPU(self): + if not test_util.is_gpu_available(): + self.skipTest("No GPU available") + + with ops.device("/cpu:0"): + optional_with_value = optional_ops.Optional.from_value( + (constant_op.constant(37.0), constant_op.constant("Foo"), + constant_op.constant(42))) + optional_none = optional_ops.Optional.none_from_structure( + structure.TensorStructure(dtypes.float32, [])) + nested_optional = optional_ops.Optional.from_value( + (optional_with_value._variant_tensor, optional_none._variant_tensor, + 1.0)) + + with ops.device("/gpu:0"): + gpu_nested_optional = optional_ops._OptionalImpl( + array_ops.identity(nested_optional._variant_tensor), + nested_optional.value_structure) + + gpu_nested_optional_has_value = gpu_nested_optional.has_value() + gpu_nested_optional_values = gpu_nested_optional.get_value() + + self.assertTrue(self.evaluate(gpu_nested_optional_has_value)) + + inner_with_value = optional_ops._OptionalImpl( + gpu_nested_optional_values[0], optional_with_value.value_structure) + + inner_none = optional_ops._OptionalImpl( + gpu_nested_optional_values[1], optional_none.value_structure) + + self.assertEqual((37.0, b"Foo", 42), + self.evaluate(inner_with_value.get_value())) + self.assertFalse(self.evaluate(inner_none.has_value())) + self.assertEqual(1.0, self.evaluate(gpu_nested_optional_values[2])) + def _assertElementValueEqual(self, expected, actual): if isinstance(expected, dict): self.assertItemsEqual(list(expected.keys()), list(actual.keys())) -- GitLab From 95e808ba44075dfe0b7db57bb49d2e64a1977a95 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 23:53:33 -0800 Subject: [PATCH 439/672] Replace `tf.estimator.inputs` with `tf.compat.v1.estimator.inputs` PiperOrigin-RevId: 223118522 --- tensorflow/examples/learn/iris_custom_decay_dnn.py | 4 ++-- tensorflow/examples/learn/iris_custom_model.py | 4 ++-- tensorflow/examples/tutorials/layers/cnn_mnist.py | 9 +++------ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tensorflow/examples/learn/iris_custom_decay_dnn.py b/tensorflow/examples/learn/iris_custom_decay_dnn.py index 4a219694d1..73bf20fada 100644 --- a/tensorflow/examples/learn/iris_custom_decay_dnn.py +++ b/tensorflow/examples/learn/iris_custom_decay_dnn.py @@ -76,12 +76,12 @@ def main(unused_argv): classifier = tf.estimator.Estimator(model_fn=my_model) # Train. - train_input_fn = tf.estimator.inputs.numpy_input_fn( + train_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={X_FEATURE: x_train}, y=y_train, num_epochs=None, shuffle=True) classifier.train(input_fn=train_input_fn, steps=1000) # Predict. - test_input_fn = tf.estimator.inputs.numpy_input_fn( + test_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={X_FEATURE: x_test}, y=y_test, num_epochs=1, shuffle=False) predictions = classifier.predict(input_fn=test_input_fn) y_predicted = np.array(list(p['class'] for p in predictions)) diff --git a/tensorflow/examples/learn/iris_custom_model.py b/tensorflow/examples/learn/iris_custom_model.py index c6bdb86ba5..bf34d72ba0 100644 --- a/tensorflow/examples/learn/iris_custom_model.py +++ b/tensorflow/examples/learn/iris_custom_model.py @@ -73,12 +73,12 @@ def main(unused_argv): classifier = tf.estimator.Estimator(model_fn=my_model) # Train. - train_input_fn = tf.estimator.inputs.numpy_input_fn( + train_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={X_FEATURE: x_train}, y=y_train, num_epochs=None, shuffle=True) classifier.train(input_fn=train_input_fn, steps=1000) # Predict. - test_input_fn = tf.estimator.inputs.numpy_input_fn( + test_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={X_FEATURE: x_test}, y=y_test, num_epochs=1, shuffle=False) predictions = classifier.predict(input_fn=test_input_fn) y_predicted = np.array(list(p['class'] for p in predictions)) diff --git a/tensorflow/examples/tutorials/layers/cnn_mnist.py b/tensorflow/examples/tutorials/layers/cnn_mnist.py index 1e8d7d05e1..670e929236 100644 --- a/tensorflow/examples/tutorials/layers/cnn_mnist.py +++ b/tensorflow/examples/tutorials/layers/cnn_mnist.py @@ -134,7 +134,7 @@ def main(unused_argv): tensors=tensors_to_log, every_n_iter=50) # Train the model - train_input_fn = tf.estimator.inputs.numpy_input_fn( + train_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={"x": train_data}, y=train_labels, batch_size=100, @@ -146,11 +146,8 @@ def main(unused_argv): hooks=[logging_hook]) # Evaluate the model and print results - eval_input_fn = tf.estimator.inputs.numpy_input_fn( - x={"x": eval_data}, - y=eval_labels, - num_epochs=1, - shuffle=False) + eval_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( + x={"x": eval_data}, y=eval_labels, num_epochs=1, shuffle=False) eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn) print(eval_results) -- GitLab From a99ef3499273abc701441b31819235d85a8bb5e3 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 27 Nov 2018 23:57:17 -0800 Subject: [PATCH 440/672] Replace `tf.estimator.inputs` with `tf.compat.v1.estimator.inputs` PiperOrigin-RevId: 223118818 --- tensorflow/contrib/boosted_trees/examples/boston.py | 4 ++-- tensorflow/contrib/boosted_trees/examples/boston_combined.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/boosted_trees/examples/boston.py b/tensorflow/contrib/boosted_trees/examples/boston.py index 54c4ff059e..09b240a700 100644 --- a/tensorflow/contrib/boosted_trees/examples/boston.py +++ b/tensorflow/contrib/boosted_trees/examples/boston.py @@ -90,13 +90,13 @@ def _make_experiment_fn(output_dir): (x_train, y_train), (x_test, y_test) = tf.keras.datasets.boston_housing.load_data() - train_input_fn = tf.estimator.inputs.numpy_input_fn( + train_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={"x": x_train}, y=y_train, batch_size=FLAGS.batch_size, num_epochs=None, shuffle=True) - eval_input_fn = tf.estimator.inputs.numpy_input_fn( + eval_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={"x": x_test}, y=y_test, num_epochs=1, shuffle=False) feature_columns = [ diff --git a/tensorflow/contrib/boosted_trees/examples/boston_combined.py b/tensorflow/contrib/boosted_trees/examples/boston_combined.py index e04b56afbf..d640af354f 100644 --- a/tensorflow/contrib/boosted_trees/examples/boston_combined.py +++ b/tensorflow/contrib/boosted_trees/examples/boston_combined.py @@ -80,13 +80,13 @@ def _make_experiment_fn(output_dir): (x_train, y_train), (x_test, y_test) = tf.keras.datasets.boston_housing.load_data() - train_input_fn = tf.estimator.inputs.numpy_input_fn( + train_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={"x": x_train}, y=y_train, batch_size=FLAGS.batch_size, num_epochs=None, shuffle=True) - eval_input_fn = tf.estimator.inputs.numpy_input_fn( + eval_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( x={"x": x_test}, y=y_test, num_epochs=1, shuffle=False) feature_columns = [ -- GitLab From e5130baf339e9b820178693ff371085d90edcd41 Mon Sep 17 00:00:00 2001 From: Nick Felt Date: Wed, 28 Nov 2018 00:03:24 -0800 Subject: [PATCH 441/672] Remove summary recording context managers from 2.0 API PiperOrigin-RevId: 223119687 --- tensorflow/contrib/summary/summary.py | 1 - tensorflow/python/ops/summary_ops_v2.py | 10 ++++------ .../tools/api/golden/v2/tensorflow.summary.pbtxt | 8 -------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tensorflow/contrib/summary/summary.py b/tensorflow/contrib/summary/summary.py index 605625c305..42898e797c 100644 --- a/tensorflow/contrib/summary/summary.py +++ b/tensorflow/contrib/summary/summary.py @@ -79,7 +79,6 @@ from tensorflow.python.ops.summary_ops_v2 import image from tensorflow.python.ops.summary_ops_v2 import import_event from tensorflow.python.ops.summary_ops_v2 import initialize from tensorflow.python.ops.summary_ops_v2 import never_record_summaries -from tensorflow.python.ops.summary_ops_v2 import record_summaries from tensorflow.python.ops.summary_ops_v2 import record_summaries_every_n_global_steps from tensorflow.python.ops.summary_ops_v2 import scalar from tensorflow.python.ops.summary_ops_v2 import should_record_summaries diff --git a/tensorflow/python/ops/summary_ops_v2.py b/tensorflow/python/ops/summary_ops_v2.py index a0ad43b444..3f99b9f877 100644 --- a/tensorflow/python/ops/summary_ops_v2.py +++ b/tensorflow/python/ops/summary_ops_v2.py @@ -58,7 +58,6 @@ _RUN_NAME_PATTERNS = re.compile(r"^[^\x00-\x1F<>]{0,512}$") _USER_NAME_PATTERNS = re.compile(r"^[a-z]([-a-z0-9]{0,29}[a-z0-9])?$", re.I) -@tf_export("summary.should_record_summaries", v1=[]) def should_record_summaries(): """Returns boolean Tensor which is true if summaries should be recorded.""" global _SHOULD_RECORD_SUMMARIES @@ -67,9 +66,8 @@ def should_record_summaries(): return should() if callable(should) else should -@tf_export("summary.record_summaries", v1=[]) @tf_contextlib.contextmanager -def record_summaries(boolean=True): +def _record_summaries(boolean=True): """Sets summary recording on or off per the provided boolean value. The provided value can be a python boolean, a scalar boolean Tensor, or @@ -105,17 +103,17 @@ def record_summaries_every_n_global_steps(n, global_step=None): should = lambda: math_ops.equal(global_step % n, 0) if not context.executing_eagerly(): should = should() - return record_summaries(should) + return _record_summaries(should) def always_record_summaries(): """Sets the should_record_summaries Tensor to always true.""" - return record_summaries(True) + return _record_summaries(True) def never_record_summaries(): """Sets the should_record_summaries Tensor to always false.""" - return record_summaries(False) + return _record_summaries(False) @tf_export("summary.SummaryWriter", v1=[]) diff --git a/tensorflow/tools/api/golden/v2/tensorflow.summary.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.summary.pbtxt index 26c979c0c6..42a74a65fb 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.summary.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.summary.pbtxt @@ -44,12 +44,4 @@ tf_module { name: "import_event" argspec: "args=[\'tensor\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "record_summaries" - argspec: "args=[\'boolean\'], varargs=None, keywords=None, defaults=[\'True\'], " - } - member_method { - name: "should_record_summaries" - argspec: "args=[], varargs=None, keywords=None, defaults=None" - } } -- GitLab From daff4a0cb32c28b4e2bfdf72fe961e5b8235146e Mon Sep 17 00:00:00 2001 From: Benjamin Tan Wei Hao Date: Wed, 28 Nov 2018 16:45:43 +0800 Subject: [PATCH 442/672] Fix typo: s/dimemension/dimension/ --- tensorflow/contrib/tensorrt/convert/convert_nodes.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index cb2a1ca87a..c72b5c1c41 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -181,7 +181,7 @@ Status ValidateTensorProperties(const string& producer_node_type, if (shape.dim_size(d) < 0) { return errors::InvalidArgument( "Input tensor with shape ", shape.DebugString(), - " has an unknown non-batch dimemension at dim ", d); + " has an unknown non-batch dimension at dim ", d); } } return Status::OK(); -- GitLab From 5e4982f018b6704d727ae30e4458a7d281572039 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 01:02:11 -0800 Subject: [PATCH 443/672] compat: Update forward compatibility horizon to 2018-11-28 PiperOrigin-RevId: 223125260 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index cb359cd084..1f43793962 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 27) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 28) @tf_export("compat.forward_compatible") -- GitLab From b093a6d05ba501a6cfa7c9cfd8d85863477640fc Mon Sep 17 00:00:00 2001 From: Tamara Norman Date: Wed, 28 Nov 2018 02:45:18 -0800 Subject: [PATCH 444/672] Add more test coverage over get_variable PiperOrigin-RevId: 223136044 --- .../kernel_tests/variable_scope_test.py | 22 +++++++++++++++++++ tensorflow/python/ops/variable_scope.py | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index 37012af299..3720f736ac 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -1312,6 +1312,28 @@ class VariableScopeTest(test.TestCase): # Ensure it is possible to do get_variable with a _ref dtype passed in. _ = variable_scope.get_variable("w", shape=[5, 6], dtype=v.dtype) + @test_util.run_in_graph_and_eager_modes + @run_inside_wrap_function_in_eager_mode + def testGetVariableWithInitializerWhichTakesNoArgs(self): + v = variable_scope.get_variable("foo", initializer=lambda: [2]) + self.assertEqual(v.name, "foo:0") + + @test_util.run_in_graph_and_eager_modes + @run_inside_wrap_function_in_eager_mode + def testGetVariableWithInitializerWhichTakesOptionalArgs(self): + v = variable_scope.get_variable("foo", initializer=lambda x=True: [2]) + self.assertEqual(v.name, "foo:0") + + @test_util.run_in_graph_and_eager_modes + @run_inside_wrap_function_in_eager_mode + def testGetVariableWithInitializerWhichTakesUnprovidedArgsAndNoShape(self): + with self.assertRaisesRegexp( + ValueError, + "The initializer passed is not valid. It should be a callable with no " + "arguments and the shape should not be provided or an instance of " + "`tf.keras.initializers.*' and `shape` should be fully defined."): + variable_scope.get_variable("foo", initializer=lambda x: [2]) + @test_util.run_in_graph_and_eager_modes @run_inside_wrap_function_in_eager_mode def testTwoGraphs(self): diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index 87ef046100..ad81862a58 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -909,12 +909,12 @@ class _VariableStore(object): # Instantiate initializer if provided initializer is a type object. if tf_inspect.isclass(initializer): initializer = initializer(dtype=dtype) - spec = tf_inspect.getargspec(initializer) if shape is not None and shape.is_fully_defined(): init_val = lambda: initializer( # pylint: disable=g-long-lambda shape.as_list(), dtype=dtype, partition_info=partition_info) variable_dtype = dtype.base_dtype - elif len(spec.args) == len(spec.defaults or []): + elif len(tf_inspect.getargspec(initializer).args) == len( + tf_inspect.getargspec(initializer).defaults or []): init_val = initializer variable_dtype = None else: -- GitLab From 3f64581ca9022df350e4ae51b34e1a8352858771 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 28 Nov 2018 03:06:47 -0800 Subject: [PATCH 445/672] [TF:XLA] Zero pad or truncate the fft axes for rfft This matches the tf docs. Previously this was an error. PiperOrigin-RevId: 223138348 --- tensorflow/compiler/tests/fft_test.py | 41 +++++++++++++++++++ tensorflow/compiler/tf2xla/kernels/fft_ops.cc | 28 ++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/tests/fft_test.py b/tensorflow/compiler/tests/fft_test.py index 61abf9c9c0..0edd0c35aa 100644 --- a/tensorflow/compiler/tests/fft_test.py +++ b/tensorflow/compiler/tests/fft_test.py @@ -158,6 +158,23 @@ class FFTTest(xla_test.XLATestCase): self._VerifyFftMethod(INNER_DIMS_3D, np.real, _to_expected, _tf_fn) + def testRFFT3DMismatchedSize(self): + + def _to_expected(x): + return np.fft.rfftn( + x, + axes=(-3, -2, -1), + s=[x.shape[-3] // 2, x.shape[-2], x.shape[-1] * 2]) + + def _tf_fn(x): + return signal.rfft3d( + x, + fft_length=[ + x.shape[-3].value // 2, x.shape[-2].value, x.shape[-1].value * 2 + ]) + + self._VerifyFftMethod(INNER_DIMS_3D, np.real, _to_expected, _tf_fn) + def testIRFFT(self): def _tf_fn(x): @@ -202,6 +219,30 @@ class FFTTest(xla_test.XLATestCase): self._VerifyFftMethod(INNER_DIMS_3D, _to_input, _to_expected, _tf_fn) + def testIRFFT3DMismatchedSize(self): + + def _to_input(x): + return np.fft.rfftn( + np.real(x), + axes=(-3, -2, -1), + s=[x.shape[-3] // 2, x.shape[-2], x.shape[-1] * 2]) + + def _to_expected(x): + return np.fft.irfftn( + x, + axes=(-3, -2, -1), + s=[x.shape[-3] // 2, x.shape[-2], x.shape[-1] * 2]) + + def _tf_fn(x): + return signal.irfft3d( + x, + fft_length=[ + x.shape[-3].value // 2, x.shape[-2].value, x.shape[-1].value * 2 + ]) + + self._VerifyFftMethod(INNER_DIMS_3D, _to_input, _to_expected, _tf_fn) + + if __name__ == "__main__": googletest.main() diff --git a/tensorflow/compiler/tf2xla/kernels/fft_ops.cc b/tensorflow/compiler/tf2xla/kernels/fft_ops.cc index 9b06357d9b..6df8b5367d 100644 --- a/tensorflow/compiler/tf2xla/kernels/fft_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/fft_ops.cc @@ -20,6 +20,7 @@ limitations under the License. #include "tensorflow/compiler/tf2xla/xla_op_registry.h" #include "tensorflow/compiler/xla/client/xla_builder.h" #include "tensorflow/compiler/xla/literal_util.h" +#include "tensorflow/compiler/xla/util.h" #include "tensorflow/core/framework/numeric_op.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/tensor.h" @@ -50,11 +51,36 @@ class GenericFftOp : public XlaOpKernel { errors::InvalidArgument("input must be at least 1 dimensional")); std::vector fft_length; + xla::XlaOp input = ctx->Input(0); if (fft_type_ == FftType::RFFT || fft_type_ == FftType::IRFFT) { OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntVector(1, &fft_length)); OP_REQUIRES(ctx, fft_length.size() == fft_rank_, errors::InvalidArgument("fft_length must be length ", fft_rank_, " vector")); + + // Zero pad or truncate the axes we're doing FFT on. + absl::InlinedVector slice_sizes = input_shape.dim_sizes(); + std::vector> padding_sizes(slice_sizes.size()); + std::vector expected_sizes = fft_length; + // IRFFT wants the innermost axis to be n / 2 + 1. + if (fft_type_ == FftType::IRFFT) { + expected_sizes[fft_rank_ - 1] = fft_length[fft_rank_ - 1] / 2 + 1; + } + for (int i = 0; i < fft_rank_; i++) { + int index = input_shape.dims() - fft_rank_ + i; + if (input_shape.dim_size(index) > expected_sizes[i]) { + slice_sizes[index] = expected_sizes[i]; + } else { + padding_sizes[index].second = + expected_sizes[i] - input_shape.dim_size(index); + } + } + + std::vector start_indices(input_shape.dims(), 0); + std::vector strides(input_shape.dims(), 1); + input = xla::Pad(xla::Slice(input, start_indices, slice_sizes, strides), + XlaHelpers::Zero(ctx->builder(), ctx->input_type(0)), + xla::MakeEdgePaddingConfig(padding_sizes)); } else { // Innermost axis provides the FFT length. for (int i = 0; i < fft_rank_; i++) { @@ -63,7 +89,7 @@ class GenericFftOp : public XlaOpKernel { } } - xla::XlaOp fft = xla::Fft(ctx->Input(0), fft_type_, fft_length); + xla::XlaOp fft = xla::Fft(input, fft_type_, fft_length); ctx->SetOutput(0, fft); } -- GitLab From d64dfd97e0ba3b46f69bfeb54cd868fb2ac340df Mon Sep 17 00:00:00 2001 From: James Keeling Date: Wed, 28 Nov 2018 03:55:55 -0800 Subject: [PATCH 446/672] Use internal stack trace library in registry This change is functionally a no-op. Instead of using the native traceback library, we use tf_stack.extract_stack() to get the frame we care about and tf_stack.convert_stack() to convert this to the same format. This reduces the number of file posix.stat calls. In my example application, we reduce the time spent in register() by a factor of 15. We also add a test to verify that we're extracting the same information. PiperOrigin-RevId: 223142289 --- tensorflow/python/framework/registry.py | 11 ++++++----- tensorflow/python/framework/registry_test.py | 4 +++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tensorflow/python/framework/registry.py b/tensorflow/python/framework/registry.py index 2e45acb499..4357c76bd6 100644 --- a/tensorflow/python/framework/registry.py +++ b/tensorflow/python/framework/registry.py @@ -23,10 +23,9 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import traceback - from tensorflow.python.platform import tf_logging as logging from tensorflow.python.util import compat +from tensorflow.python.util import tf_stack # Registry mechanism below is based on mapreduce.python.mrpython.Register. @@ -57,15 +56,17 @@ class Registry(object): if name in self._registry: (filename, line_number, function_name, _) = ( self._registry[name][_LOCATION_TAG]) - raise KeyError("Registering two %s with name '%s' !" + raise KeyError("Registering two %s with name '%s'! " "(Previous registration was in %s %s:%d)" % (self._name, name, function_name, filename, line_number)) logging.vlog(1, "Registering %s (%s) in %s.", name, candidate, self._name) # stack trace is [this_function, Register(), user_function,...] # so the user function is #2. - stack = traceback.extract_stack() - self._registry[name] = {_TYPE_TAG: candidate, _LOCATION_TAG: stack[2]} + stack = tf_stack.extract_stack() + user_function = stack[2] + location_tag = tf_stack.convert_stack([user_function])[0] + self._registry[name] = {_TYPE_TAG: candidate, _LOCATION_TAG: location_tag} def list(self): """Lists registered items. diff --git a/tensorflow/python/framework/registry_test.py b/tensorflow/python/framework/registry_test.py index a821e16f26..1a0d3f200d 100644 --- a/tensorflow/python/framework/registry_test.py +++ b/tensorflow/python/framework/registry_test.py @@ -45,7 +45,9 @@ class RegistryTest(test.TestCase): def testDuplicate(self): myreg = registry.Registry('testbar') myreg.register(bar, 'Bar') - with self.assertRaises(KeyError): + with self.assertRaisesRegexp( + KeyError, r'Registering two testbar with name \'Bar\'! ' + r'\(Previous registration was in [^ ]+ .*.py:[0-9]+\)'): myreg.register(bar, 'Bar') -- GitLab From 192d588eaf6e37c98fd7583cad19c2d1e55fbb67 Mon Sep 17 00:00:00 2001 From: Peter Buchlovsky Date: Wed, 28 Nov 2018 07:30:45 -0800 Subject: [PATCH 447/672] Fix incompatible device colocation warning. PiperOrigin-RevId: 223163333 --- .../contrib/distribute/python/mirrored_strategy.py | 4 +++- .../contrib/distribute/python/one_device_strategy.py | 9 +++++++-- .../distribute/python/parameter_server_strategy.py | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy.py b/tensorflow/contrib/distribute/python/mirrored_strategy.py index 7719715875..4a594f056e 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy.py @@ -20,6 +20,7 @@ from __future__ import print_function import functools +from tensorflow.python.distribute import device_util from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import mirrored_strategy from tensorflow.python.distribute import values @@ -133,7 +134,8 @@ class MirroredExtended(CoreMirroredExtended): if self._cluster_spec: worker_device_pairs = self._worker_devices else: - worker_device_pairs = [("/job:localhost", self._devices)] + worker = device_util.canonicalize("/device:CPU:0") + worker_device_pairs = [(worker, self._devices)] return values.DatasetIterator(dataset, worker_device_pairs) def _distribute_dataset(self, dataset_fn): diff --git a/tensorflow/contrib/distribute/python/one_device_strategy.py b/tensorflow/contrib/distribute/python/one_device_strategy.py index 7a2e225ca0..e322b6acb8 100644 --- a/tensorflow/contrib/distribute/python/one_device_strategy.py +++ b/tensorflow/contrib/distribute/python/one_device_strategy.py @@ -20,6 +20,7 @@ from __future__ import print_function import six +from tensorflow.python.distribute import device_util from tensorflow.python.distribute import distribute_lib from tensorflow.python.distribute import values from tensorflow.python.framework import constant_op @@ -68,7 +69,9 @@ class OneDeviceExtended(distribute_lib.DistributionStrategyExtended): def _make_dataset_iterator(self, dataset): """Make iterator from dataset without splitting the batch.""" - return values.DatasetIterator(dataset, [("/job:localhost", [self._device])]) + worker = device_util.canonicalize("/device:CPU:0") + worker_device_pairs = [(worker, [self._device])] + return values.DatasetIterator(dataset, worker_device_pairs) def _distribute_dataset(self, dataset_fn): return values.PerReplicaDataset( @@ -78,8 +81,10 @@ class OneDeviceExtended(distribute_lib.DistributionStrategyExtended): self, input_fn, replication_mode=distribute_lib.InputReplicationMode.PER_WORKER): + worker = device_util.canonicalize("/device:CPU:0") + worker_device_pairs = [(worker, [self._device])] return values.InputFunctionIterator( - input_fn, [("/job:localhost", [self._device])], + input_fn, worker_device_pairs, [distribute_lib.InputContext()]) def _broadcast_to(self, tensor, destinations): diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy.py b/tensorflow/contrib/distribute/python/parameter_server_strategy.py index 8c33d3a143..75ee41c4cf 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy.py @@ -199,7 +199,7 @@ class ParameterServerExtended(distribute_lib.DistributionStrategyExtended): def _initialize_local(self, num_gpus_per_worker): """Initialize internal devices for local training.""" - self._worker_device = "/job:localhost" + self._worker_device = device_util.canonicalize("/device:CPU:0") # Define compute devices which is a list of device strings and one for each # replica. When there are GPUs, replicate operations on these GPUs. # Otherwise, place operations on CPU. -- GitLab From 36a445c3531e90948d6de34af2af59e34f361b86 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 28 Nov 2018 08:29:03 -0800 Subject: [PATCH 448/672] Deprecate tf.train._ classes in TF 2.0 API in favor of tf.keras.optimizers._ ones. PiperOrigin-RevId: 223171873 --- tensorflow/python/training/adadelta.py | 2 +- tensorflow/python/training/adagrad.py | 2 +- tensorflow/python/training/adagrad_da.py | 2 +- tensorflow/python/training/adam.py | 2 +- tensorflow/python/training/ftrl.py | 2 +- .../python/training/gradient_descent.py | 2 +- tensorflow/python/training/momentum.py | 2 +- tensorflow/python/training/optimizer.py | 2 +- .../python/training/proximal_adagrad.py | 2 +- tensorflow/python/training/rmsprop.py | 2 +- ...tensorflow.train.-adadelta-optimizer.pbtxt | 51 ------------------- ...sorflow.train.-adagrad-d-a-optimizer.pbtxt | 51 ------------------- .../tensorflow.train.-adagrad-optimizer.pbtxt | 51 ------------------- .../v2/tensorflow.train.-adam-optimizer.pbtxt | 51 ------------------- .../v2/tensorflow.train.-ftrl-optimizer.pbtxt | 51 ------------------- ...ow.train.-gradient-descent-optimizer.pbtxt | 51 ------------------- ...tensorflow.train.-momentum-optimizer.pbtxt | 51 ------------------- .../v2/tensorflow.train.-optimizer.pbtxt | 50 ------------------ ...ow.train.-proximal-adagrad-optimizer.pbtxt | 51 ------------------- ...nsorflow.train.-r-m-s-prop-optimizer.pbtxt | 51 ------------------- .../api/golden/v2/tensorflow.train.pbtxt | 40 --------------- tensorflow/tools/compatibility/renames_v2.py | 10 ++++ 22 files changed, 20 insertions(+), 559 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-adadelta-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-d-a-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-adam-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-ftrl-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-gradient-descent-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-momentum-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-proximal-adagrad-optimizer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-r-m-s-prop-optimizer.pbtxt diff --git a/tensorflow/python/training/adadelta.py b/tensorflow/python/training/adadelta.py index 95eca76496..dd21016000 100644 --- a/tensorflow/python/training/adadelta.py +++ b/tensorflow/python/training/adadelta.py @@ -25,7 +25,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.AdadeltaOptimizer") +@tf_export(v1=["train.AdadeltaOptimizer"]) class AdadeltaOptimizer(optimizer.Optimizer): """Optimizer that implements the Adadelta algorithm. diff --git a/tensorflow/python/training/adagrad.py b/tensorflow/python/training/adagrad.py index cc0da26b27..10c043bae1 100644 --- a/tensorflow/python/training/adagrad.py +++ b/tensorflow/python/training/adagrad.py @@ -28,7 +28,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.AdagradOptimizer") +@tf_export(v1=["train.AdagradOptimizer"]) class AdagradOptimizer(optimizer.Optimizer): """Optimizer that implements the Adagrad algorithm. diff --git a/tensorflow/python/training/adagrad_da.py b/tensorflow/python/training/adagrad_da.py index 5ba403554f..e23b7134b3 100644 --- a/tensorflow/python/training/adagrad_da.py +++ b/tensorflow/python/training/adagrad_da.py @@ -26,7 +26,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.AdagradDAOptimizer") +@tf_export(v1=["train.AdagradDAOptimizer"]) class AdagradDAOptimizer(optimizer.Optimizer): """Adagrad Dual Averaging algorithm for sparse linear models. diff --git a/tensorflow/python/training/adam.py b/tensorflow/python/training/adam.py index 704ad6d3fe..0c701f4712 100644 --- a/tensorflow/python/training/adam.py +++ b/tensorflow/python/training/adam.py @@ -29,7 +29,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.AdamOptimizer") +@tf_export(v1=["train.AdamOptimizer"]) class AdamOptimizer(optimizer.Optimizer): """Optimizer that implements the Adam algorithm. diff --git a/tensorflow/python/training/ftrl.py b/tensorflow/python/training/ftrl.py index 2fafc9a2d8..a2ef3c76b4 100644 --- a/tensorflow/python/training/ftrl.py +++ b/tensorflow/python/training/ftrl.py @@ -25,7 +25,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.FtrlOptimizer") +@tf_export(v1=["train.FtrlOptimizer"]) class FtrlOptimizer(optimizer.Optimizer): """Optimizer that implements the FTRL algorithm. diff --git a/tensorflow/python/training/gradient_descent.py b/tensorflow/python/training/gradient_descent.py index ef50f6315d..1a527345ef 100644 --- a/tensorflow/python/training/gradient_descent.py +++ b/tensorflow/python/training/gradient_descent.py @@ -26,7 +26,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.GradientDescentOptimizer") +@tf_export(v1=["train.GradientDescentOptimizer"]) class GradientDescentOptimizer(optimizer.Optimizer): """Optimizer that implements the gradient descent algorithm. """ diff --git a/tensorflow/python/training/momentum.py b/tensorflow/python/training/momentum.py index 4a280e7c51..f3bc83bbfa 100644 --- a/tensorflow/python/training/momentum.py +++ b/tensorflow/python/training/momentum.py @@ -25,7 +25,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.MomentumOptimizer") +@tf_export(v1=["train.MomentumOptimizer"]) class MomentumOptimizer(optimizer.Optimizer): """Optimizer that implements the Momentum algorithm. diff --git a/tensorflow/python/training/optimizer.py b/tensorflow/python/training/optimizer.py index 2556e6274a..900afeed6c 100644 --- a/tensorflow/python/training/optimizer.py +++ b/tensorflow/python/training/optimizer.py @@ -214,7 +214,7 @@ def _get_processor(v): raise NotImplementedError("Trying to optimize unsupported type ", v) -@tf_export("train.Optimizer") +@tf_export(v1=["train.Optimizer"]) class Optimizer( # Optimizers inherit from CheckpointableBase rather than Checkpointable # since they do most of their dependency management themselves (slot diff --git a/tensorflow/python/training/proximal_adagrad.py b/tensorflow/python/training/proximal_adagrad.py index 9bd677b8ef..2ea628a56b 100644 --- a/tensorflow/python/training/proximal_adagrad.py +++ b/tensorflow/python/training/proximal_adagrad.py @@ -26,7 +26,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.ProximalAdagradOptimizer") +@tf_export(v1=["train.ProximalAdagradOptimizer"]) class ProximalAdagradOptimizer(optimizer.Optimizer): # pylint: disable=line-too-long """Optimizer that implements the Proximal Adagrad algorithm. diff --git a/tensorflow/python/training/rmsprop.py b/tensorflow/python/training/rmsprop.py index f38c9861d6..fb53b5883f 100644 --- a/tensorflow/python/training/rmsprop.py +++ b/tensorflow/python/training/rmsprop.py @@ -50,7 +50,7 @@ from tensorflow.python.training import training_ops from tensorflow.python.util.tf_export import tf_export -@tf_export("train.RMSPropOptimizer") +@tf_export(v1=["train.RMSPropOptimizer"]) class RMSPropOptimizer(optimizer.Optimizer): """Optimizer that implements the RMSProp algorithm. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-adadelta-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-adadelta-optimizer.pbtxt deleted file mode 100644 index 1f1d8b6f9e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-adadelta-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.AdadeltaOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'rho\', \'epsilon\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=[\'0.001\', \'0.95\', \'1e-08\', \'False\', \'Adadelta\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-d-a-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-d-a-optimizer.pbtxt deleted file mode 100644 index a7c05d4849..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-d-a-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.AdagradDAOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'global_step\', \'initial_gradient_squared_accumulator_value\', \'l1_regularization_strength\', \'l2_regularization_strength\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=[\'0.1\', \'0.0\', \'0.0\', \'False\', \'AdagradDA\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-optimizer.pbtxt deleted file mode 100644 index bc8b92389c..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-adagrad-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.AdagradOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'initial_accumulator_value\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=[\'0.1\', \'False\', \'Adagrad\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-adam-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-adam-optimizer.pbtxt deleted file mode 100644 index 5d17be9378..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-adam-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.AdamOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'beta1\', \'beta2\', \'epsilon\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=[\'0.001\', \'0.9\', \'0.999\', \'1e-08\', \'False\', \'Adam\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-ftrl-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-ftrl-optimizer.pbtxt deleted file mode 100644 index d265fdeb01..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-ftrl-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.FtrlOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'learning_rate_power\', \'initial_accumulator_value\', \'l1_regularization_strength\', \'l2_regularization_strength\', \'use_locking\', \'name\', \'accum_name\', \'linear_name\', \'l2_shrinkage_regularization_strength\'], varargs=None, keywords=None, defaults=[\'-0.5\', \'0.1\', \'0.0\', \'0.0\', \'False\', \'Ftrl\', \'None\', \'None\', \'0.0\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-gradient-descent-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-gradient-descent-optimizer.pbtxt deleted file mode 100644 index c673e29cd4..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-gradient-descent-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.GradientDescentOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'GradientDescent\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-momentum-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-momentum-optimizer.pbtxt deleted file mode 100644 index 8199f63b9b..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-momentum-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.MomentumOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'momentum\', \'use_locking\', \'name\', \'use_nesterov\'], varargs=None, keywords=None, defaults=[\'False\', \'Momentum\', \'False\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-optimizer.pbtxt deleted file mode 100644 index 876bb35e39..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-optimizer.pbtxt +++ /dev/null @@ -1,50 +0,0 @@ -path: "tensorflow.train.Optimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-proximal-adagrad-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-proximal-adagrad-optimizer.pbtxt deleted file mode 100644 index 14349a74ef..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-proximal-adagrad-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.ProximalAdagradOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'initial_accumulator_value\', \'l1_regularization_strength\', \'l2_regularization_strength\', \'use_locking\', \'name\'], varargs=None, keywords=None, defaults=[\'0.1\', \'0.0\', \'0.0\', \'False\', \'ProximalAdagrad\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-r-m-s-prop-optimizer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-r-m-s-prop-optimizer.pbtxt deleted file mode 100644 index 906384a287..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-r-m-s-prop-optimizer.pbtxt +++ /dev/null @@ -1,51 +0,0 @@ -path: "tensorflow.train.RMSPropOptimizer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "GATE_GRAPH" - mtype: "" - } - member { - name: "GATE_NONE" - mtype: "" - } - member { - name: "GATE_OP" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'learning_rate\', \'decay\', \'momentum\', \'epsilon\', \'use_locking\', \'centered\', \'name\'], varargs=None, keywords=None, defaults=[\'0.9\', \'0.0\', \'1e-10\', \'False\', \'False\', \'RMSProp\'], " - } - member_method { - name: "apply_gradients" - argspec: "args=[\'self\', \'grads_and_vars\', \'global_step\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "compute_gradients" - argspec: "args=[\'self\', \'loss\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'False\', \'None\'], " - } - member_method { - name: "get_name" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot" - argspec: "args=[\'self\', \'var\', \'name\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_slot_names" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "minimize" - argspec: "args=[\'self\', \'loss\', \'global_step\', \'var_list\', \'gate_gradients\', \'aggregation_method\', \'colocate_gradients_with_ops\', \'name\', \'grad_loss\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'1\', \'None\', \'False\', \'None\', \'None\'], " - } - member_method { - name: "variables" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt index d47bc09e66..4a4f387131 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt @@ -1,21 +1,5 @@ path: "tensorflow.train" tf_module { - member { - name: "AdadeltaOptimizer" - mtype: "" - } - member { - name: "AdagradDAOptimizer" - mtype: "" - } - member { - name: "AdagradOptimizer" - mtype: "" - } - member { - name: "AdamOptimizer" - mtype: "" - } member { name: "BytesList" mtype: "" @@ -88,18 +72,10 @@ tf_module { name: "FloatList" mtype: "" } - member { - name: "FtrlOptimizer" - mtype: "" - } member { name: "GlobalStepWaiterHook" mtype: "" } - member { - name: "GradientDescentOptimizer" - mtype: "" - } member { name: "Int64List" mtype: "" @@ -112,10 +88,6 @@ tf_module { name: "LoggingTensorHook" mtype: "" } - member { - name: "MomentumOptimizer" - mtype: "" - } member { name: "MonitoredSession" mtype: "" @@ -128,22 +100,10 @@ tf_module { name: "NanTensorHook" mtype: "" } - member { - name: "Optimizer" - mtype: "" - } - member { - name: "ProximalAdagradOptimizer" - mtype: "" - } member { name: "ProximalGradientDescentOptimizer" mtype: "" } - member { - name: "RMSPropOptimizer" - mtype: "" - } member { name: "Scaffold" mtype: "" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index c5efc04d04..49c152bb86 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -581,10 +581,20 @@ renames = { 'tf.to_int64': 'tf.compat.v1.to_int64', 'tf.trace': 'tf.linalg.trace', 'tf.train.LooperThread': 'tf.compat.v1.train.LooperThread', + 'tf.train.AdadeltaOptimizer': 'tf.compat.v1.train.AdadeltaOptimizer', + 'tf.train.AdagradDAOptimizer': 'tf.compat.v1.train.AdagradDAOptimizer', + 'tf.train.AdagradOptimizer': 'tf.compat.v1.train.AdagradOptimizer', + 'tf.train.AdamOptimizer': 'tf.compat.v1.train.AdamOptimizer', + 'tf.train.FtrlOptimizer': 'tf.compat.v1.train.FtrlOptimizer', + 'tf.train.GradientDescentOptimizer': 'tf.compat.v1.train.GradientDescentOptimizer', + 'tf.train.MomentumOptimizer': 'tf.compat.v1.train.MomentumOptimizer', 'tf.train.MonitoredTrainingSession': 'tf.compat.v1.train.MonitoredTrainingSession', 'tf.train.NewCheckpointReader': 'tf.compat.v1.train.NewCheckpointReader', + 'tf.train.Optimizer': 'tf.compat.v1.train.Optimizer', 'tf.train.ProfilerHook': 'tf.compat.v1.train.ProfilerHook', + 'tf.train.ProximalAdagradOptimizer': 'tf.compat.v1.train.ProximalAdagradOptimizer', 'tf.train.QueueRunner': 'tf.compat.v1.train.QueueRunner', + 'tf.train.RMSPropOptimizer': 'tf.compat.v1.train.RMSPropOptimizer', 'tf.train.Saver': 'tf.compat.v1.train.Saver', 'tf.train.SaverDef': 'tf.compat.v1.train.SaverDef', 'tf.train.SyncReplicasOptimizer': 'tf.compat.v1.train.SyncReplicasOptimizer', -- GitLab From ae85f10ed9f6aff20d984d188b384ea56fc646af Mon Sep 17 00:00:00 2001 From: Mahmoud Abuzaina Date: Wed, 28 Nov 2018 08:41:39 -0800 Subject: [PATCH 449/672] Addressed review comments --- tensorflow/core/kernels/BUILD | 22 ++ tensorflow/core/kernels/mkl_avgpooling_op.cc | 172 +++++++++----- tensorflow/core/kernels/mkl_maxpooling_op.cc | 215 +++++++++++------- .../core/kernels/mkl_pooling_ops_common.cc | 49 ++-- .../core/kernels/mkl_pooling_ops_common.h | 44 ++-- .../kernels/mkl_quantized_pooling_ops_test.cc | 201 ++++++++++++++++ 6 files changed, 526 insertions(+), 177 deletions(-) create mode 100644 tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index b523e3e718..eb209fc718 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -6269,6 +6269,28 @@ tf_cc_test( ], ) +tf_cc_test_mkl( + name = "mkl_quantized_pooling_ops_test", + size = "small", + srcs = ["mkl_quantized_pooling_ops_test.cc"], + deps = [ + ":mkl_input_conversion_op", + ":mkl_pooling_ops", + ":ops_testutil", + ":ops_util", + ":quantization_utils", + ":quantized_ops", + "//tensorflow/core:array_ops_op_lib", + "//tensorflow/core:framework", + "//tensorflow/core:math_ops_op_lib", + "//tensorflow/core:nn_ops_op_lib", + "//tensorflow/core:protos_all_cc", + "//tensorflow/core:test", + "//tensorflow/core:test_main", + "//tensorflow/core:testlib", + ], +) + tf_cc_test( name = "quantized_reshape_op_test", size = "small", diff --git a/tensorflow/core/kernels/mkl_avgpooling_op.cc b/tensorflow/core/kernels/mkl_avgpooling_op.cc index 2409f7e9dc..a5dc317969 100644 --- a/tensorflow/core/kernels/mkl_avgpooling_op.cc +++ b/tensorflow/core/kernels/mkl_avgpooling_op.cc @@ -53,16 +53,19 @@ class MklAvgPoolingOp : public OpKernel { OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument("Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument("Sliding window stride field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window stride field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, - errors::Unimplemented("Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented( + "Pooling is not yet supported on the " + "batch dimension.")); } void Compute(OpKernelContext* context) override { @@ -228,16 +231,19 @@ class MklAvgPoolingGradOp : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument("Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument("Sliding window strides field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window strides field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, - errors::Unimplemented("Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented( + "Pooling is not yet supported on the " + "batch dimension.")); } void Compute(OpKernelContext* context) override { @@ -357,22 +363,22 @@ class MklAvgPoolingGradOp : public OpKernel { if (!outbackprop_in_mkl_format) { // For avgpooling, tensor_in_shape should have 1 dimension, and 4 // elements. - OP_REQUIRES( - context, - tensor_in_shape.dims() == 1 && tensor_in_shape.NumElements() == 4, - errors::InvalidArgument("original input shape must be " - "1-dimensional and 4 elements")); + OP_REQUIRES(context, tensor_in_shape.dims() == 1 && + tensor_in_shape.NumElements() == 4, + errors::InvalidArgument( + "original input shape must be " + "1-dimensional and 4 elements")); // For avgpooling, out_backprop should have 4 dimensions. - OP_REQUIRES(context, out_backprop.dims() == 4, - errors::InvalidArgument("out_backprop must be " - "4-dimensional")); + OP_REQUIRES( + context, out_backprop.dims() == 4, + errors::InvalidArgument("out_backprop must be 4-dimensional")); } else { // Input in MKL format. // For avgpooling, out_backprop should have 4 dimensions. - OP_REQUIRES(context, out_backprop_shape.GetDimension() == 4, - errors::InvalidArgument("out_backprop must be " - "4-dimensional")); + OP_REQUIRES( + context, out_backprop_shape.GetDimension() == 4, + errors::InvalidArgument("out_backprop must be 4-dimensional")); } // TODO(inteltf): Get outbackprop layout. @@ -484,9 +490,9 @@ class MklAvgPoolingOp : public MklPoolingForwardOpBase { dnn_shape_input.IsMklTensor() ? dnn_shape_input.GetSizesAsMklDnnDims() : is_pool2d ? TFShapeToMklDnnDimsInNCHW(input_tensor.shape(), - this->data_format_tf_) - : TFShapeToMklDnnDimsInNCDHW(input_tensor.shape(), - this->data_format_tf_); + this->data_format_tf_) + : TFShapeToMklDnnDimsInNCDHW(input_tensor.shape(), + this->data_format_tf_); memory::desc input_md = dnn_shape_input.IsMklTensor() ? dnn_shape_input.GetMklLayout() : memory::desc(src_dims, MklDnnType(), @@ -494,9 +500,17 @@ class MklAvgPoolingOp : public MklPoolingForwardOpBase { // Get an average pooling primitive from the op pool MklPoolingFwdPrimitive* pooling_fwd = nullptr; + prop_kind pooling_prop_kind; + bool int8_forward_inference = + std::is_same::value || std::is_same::value; + if (int8_forward_inference) + pooling_prop_kind = prop_kind::forward_inference; + else + pooling_prop_kind = prop_kind::forward_training; MklPoolingParams fwdParams(src_dims, output_dims_mkl_order, filter_dims, strides, padding_left, padding_right, - algorithm::pooling_avg_exclude_padding); + algorithm::pooling_avg_exclude_padding, + pooling_prop_kind); pooling_fwd = MklPoolingFwdPrimitiveFactory::Get(fwdParams); // allocate output tensor @@ -523,10 +537,31 @@ class MklAvgPoolingOp : public MklPoolingForwardOpBase { // execute pooling pooling_fwd->Execute(src_data, dst_data); - } catch (mkldnn::error& e) { - string error_msg = "Status: " + std::to_string(e.status) + - ", message: " + string(e.message) + ", in file " + - string(__FILE__) + ":" + std::to_string(__LINE__); + + // Pass min, max from input to output + if (int8_forward_inference) { + const Tensor& min_input_t = MklGetInput(context, 1); + const Tensor& max_input_t = MklGetInput(context, 2); + const float min_input = min_input_t.flat()(0); + const float max_input = max_input_t.flat()(0); + + Tensor* output_min = nullptr; + Tensor* output_max = nullptr; + MklDnnShape output_min_mkl_shape, output_max_mkl_shape; + output_min_mkl_shape.SetMklTensor(false); + output_max_mkl_shape.SetMklTensor(false); + AllocateOutputSetMklShape(context, 1, &output_min, {}, + output_min_mkl_shape); + AllocateOutputSetMklShape(context, 2, &output_max, {}, + output_max_mkl_shape); + output_min->flat()(0) = min_input; + output_max->flat()(0) = max_input; + } + } + catch (mkldnn::error& e) { + string error_msg = "Status: " + std::to_string(e.status) + ", message: " + + string(e.message) + ", in file " + string(__FILE__) + + ":" + std::to_string(__LINE__); OP_REQUIRES_OK( context, errors::Aborted("Operation received an exception:", error_msg)); @@ -576,24 +611,26 @@ class MklAvgPoolingGradOp : public MklPoolingBackwardOpBase { orig_input_mkl_shape.IsMklTensor() ? orig_input_mkl_shape.GetSizesAsMklDnnDims() : is_pool2d ? TFShapeToMklDnnDimsInNCHW(orig_input_shape, - this->data_format_tf_) - : TFShapeToMklDnnDimsInNCDHW(orig_input_shape, - this->data_format_tf_); + this->data_format_tf_) + : TFShapeToMklDnnDimsInNCDHW(orig_input_shape, + this->data_format_tf_); memory::dims diff_dst_dims = grad_mkl_shape.IsMklTensor() ? grad_mkl_shape.GetSizesAsMklDnnDims() : is_pool2d ? TFShapeToMklDnnDimsInNCHW(grad_tensor.shape(), - this->data_format_tf_) - : TFShapeToMklDnnDimsInNCDHW(grad_tensor.shape(), - this->data_format_tf_); + this->data_format_tf_) + : TFShapeToMklDnnDimsInNCDHW(grad_tensor.shape(), + this->data_format_tf_); memory::dims output_dims_mkl_order; this->GetOutputDims(pool_params, &output_dims_mkl_order); - MklPoolingParams bwdParams(orig_input_dims_mkl_order, - output_dims_mkl_order, filter_dims, strides, - padding_left, padding_right, - algorithm::pooling_avg_exclude_padding); + // Pass prop_kind::forward_training to create a forward primitive + // that is used in the backward pass + MklPoolingParams bwdParams( + orig_input_dims_mkl_order, output_dims_mkl_order, filter_dims, + strides, padding_left, padding_right, + algorithm::pooling_avg_exclude_padding, prop_kind::forward_training); MklPoolingBwdPrimitive* pooling_bwd = MklPoolingBwdPrimitiveFactory::Get(bwdParams); @@ -623,10 +660,11 @@ class MklAvgPoolingGradOp : public MklPoolingBackwardOpBase { // execute pooling op pooling_bwd->Execute(diff_dst_data, diff_src_data); - } catch (mkldnn::error& e) { - string error_msg = "Status: " + std::to_string(e.status) + - ", message: " + string(e.message) + ", in file " + - string(__FILE__) + ":" + std::to_string(__LINE__); + } + catch (mkldnn::error& e) { + string error_msg = "Status: " + std::to_string(e.status) + ", message: " + + string(e.message) + ", in file " + string(__FILE__) + + ":" + std::to_string(__LINE__); OP_REQUIRES_OK(context, errors::Aborted("Compute received an exception:", error_msg)); } @@ -645,28 +683,28 @@ class MklAvgPoolingGradOp : public MklPoolingBackwardOpBase { const MklDnnShape& original_input_mkl_shape, const MklDnnShape& input_gradient_mkl_shape) { if (!original_input_mkl_shape.IsMklTensor()) { - OP_REQUIRES( - context, - tensor_in_shape.dims() == 1 && tensor_in_shape.NumElements() == 4, - errors::InvalidArgument("original input shape must be " - "1-dimensional and 4 elements")); + OP_REQUIRES(context, tensor_in_shape.dims() == 1 && + tensor_in_shape.NumElements() == 4, + errors::InvalidArgument( + "original input shape must be " + "1-dimensional and 4 elements")); } else { - OP_REQUIRES(context, - original_input_mkl_shape.GetDimension() == 1 && - original_input_mkl_shape.DimSize(0) == 4, - errors::InvalidArgument("original input shape must be " - "1-dimensional and 4 elements")); + OP_REQUIRES(context, original_input_mkl_shape.GetDimension() == 1 && + original_input_mkl_shape.DimSize(0) == 4, + errors::InvalidArgument( + "original input shape must be " + "1-dimensional and 4 elements")); } if (!input_gradient_mkl_shape.IsMklTensor()) { // For avgpooling, input_gradient_diff_dst should have 4 dimensions. - OP_REQUIRES(context, input_gradient_tensor.dims() == 4, - errors::InvalidArgument("Gradient shape must be " - "4-dimensional")); + OP_REQUIRES( + context, input_gradient_tensor.dims() == 4, + errors::InvalidArgument("Gradient shape must be 4-dimensional")); } else { - OP_REQUIRES(context, input_gradient_mkl_shape.GetDimension() == 4, - errors::InvalidArgument("Gradient shape must be " - "4-dimensional")); + OP_REQUIRES( + context, input_gradient_mkl_shape.GetDimension() == 4, + errors::InvalidArgument("Gradient shape must be 4-dimensional")); } } }; // MklAvgPoolingGradOp @@ -691,6 +729,18 @@ REGISTER_KERNEL_BUILDER(Name("_MklAvgPool") .Label(mkl_op_registry::kMklOpLabel), MklAvgPoolingOp); +REGISTER_KERNEL_BUILDER(Name("_MklQuantizedAvgPool") + .Device(DEVICE_CPU) + .TypeConstraint("T") + .Label(mkl_op_registry::kMklQuantizedOpLabel), + MklAvgPoolingOp); + +REGISTER_KERNEL_BUILDER(Name("_MklQuantizedAvgPool") + .Device(DEVICE_CPU) + .TypeConstraint("T") + .Label(mkl_op_registry::kMklQuantizedOpLabel), + MklAvgPoolingOp); + REGISTER_KERNEL_BUILDER(Name("_MklAvgPoolGrad") .Device(DEVICE_CPU) .TypeConstraint("T") diff --git a/tensorflow/core/kernels/mkl_maxpooling_op.cc b/tensorflow/core/kernels/mkl_maxpooling_op.cc index 256d48f4d5..cd72530bce 100644 --- a/tensorflow/core/kernels/mkl_maxpooling_op.cc +++ b/tensorflow/core/kernels/mkl_maxpooling_op.cc @@ -54,16 +54,19 @@ class MklMaxPoolingOp : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument("Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument("Sliding window stride field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window stride field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, - errors::Unimplemented("Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented( + "Pooling is not yet supported on the " + "batch dimension.")); workspace_enabled_ = false; // We may not get this attribute for this node if it does not go through @@ -213,12 +216,14 @@ class MklMaxPoolingGradOp : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument("Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument("Sliding window strides field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window strides field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, errors::Unimplemented( @@ -399,19 +404,18 @@ class MklMaxPoolingGradOp : public OpKernel { if (workspace_enabled == false) { if (convert_input != nullptr) { if (input_in_mkl_format == false) { - CHECK_EQ(dnnConversionExecute_F32( - convert_input, - const_cast(static_cast( - tensor_in.flat().data())), - input_buf), - E_SUCCESS); + CHECK_EQ( + dnnConversionExecute_F32( + convert_input, const_cast(static_cast( + tensor_in.flat().data())), + input_buf), + E_SUCCESS); CHECK_EQ(dnnDelete_F32(convert_input), E_SUCCESS); convert_input = nullptr; } else { input_shape.GetConvertedFlatData( - lt_input_prim, - const_cast( - static_cast(tensor_in.flat().data())), + lt_input_prim, const_cast(static_cast( + tensor_in.flat().data())), input_buf); } pooling_resfwd[dnnResourceSrc] = input_buf; @@ -456,9 +460,8 @@ class MklMaxPoolingGradOp : public OpKernel { CHECK_EQ(dnnDelete_F32(convert_outbackprop), E_SUCCESS); } else { output_backprop_shape.GetConvertedFlatData( - lt_outbackprop_prim, - const_cast( - static_cast(out_backprop.flat().data())), + lt_outbackprop_prim, const_cast(static_cast( + out_backprop.flat().data())), outbackprop_buf); } pooling_res[dnnResourceDiffDst] = outbackprop_buf; @@ -520,7 +523,6 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { MklDnnData dnn_data_input(&cpu_engine); MklDnnData dnn_data_output(&cpu_engine); - MklDnnData dnn_data_wksp(&cpu_engine); // initialize variables for the pooling op MklPoolParameters pool_params; @@ -550,13 +552,13 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { dnn_shape_input.IsMklTensor() ? dnn_shape_input.GetMklLayout() : is_pool2d ? memory::desc( - TFShapeToMklDnnDimsInNCHW(input_tensor_shape, - this->data_format_tf_), - MklDnnType(), this->data_format_mkldnn_) - : memory::desc( - TFShapeToMklDnnDimsInNCDHW( - input_tensor_shape, this->data_format_tf_), - MklDnnType(), this->data_format_mkldnn_); + TFShapeToMklDnnDimsInNCHW( + input_tensor_shape, this->data_format_tf_), + MklDnnType(), this->data_format_mkldnn_) + : memory::desc( + TFShapeToMklDnnDimsInNCDHW( + input_tensor_shape, this->data_format_tf_), + MklDnnType(), this->data_format_mkldnn_); // Get src/filter/stride/padding information memory::dims src_dims = @@ -564,17 +566,24 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { ? dnn_shape_input.GetSizesAsMklDnnDims() : is_pool2d ? TFShapeToMklDnnDimsInNCHW(input_tensor.shape(), this->data_format_tf_) - : TFShapeToMklDnnDimsInNCDHW(input_tensor.shape(), - this->data_format_tf_); + : TFShapeToMklDnnDimsInNCDHW(input_tensor.shape(), + this->data_format_tf_); memory::dims filter_dims, strides, padding_left, padding_right; this->PoolParamsToDims(&pool_params, &filter_dims, &strides, &padding_left, &padding_right, is_pool2d); // Get a pooling op from the cached pool MklPoolingFwdPrimitive* pooling_fwd = nullptr; + prop_kind pooling_prop_kind; + bool int8_forward_inference = + std::is_same::value || std::is_same::value; + if (int8_forward_inference) + pooling_prop_kind = prop_kind::forward_inference; + else + pooling_prop_kind = prop_kind::forward_training; MklPoolingParams fwdParams(src_dims, output_dims_mkl_order, filter_dims, strides, padding_left, padding_right, - algorithm::pooling_max); + algorithm::pooling_max, pooling_prop_kind); pooling_fwd = MklPoolingFwdPrimitiveFactory::Get(fwdParams); // allocate output tensor @@ -586,10 +595,6 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { pooling_fwd->GetDstMemoryFormat(), output_tensor); - AllocateWorkspaceTensor(context, *(pooling_fwd->GetPoolingFwdPd()), - &dnn_data_wksp); - OP_REQUIRES_OK(context, context->status()); - // check wehther we need to reorder src const T* src_data = input_tensor.flat().data(); if (input_md.data.format != pooling_fwd->GetSrcMemoryFormat()) { @@ -603,14 +608,44 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { } T* dst_data = output_tensor->flat().data(); - void* ws_data = dnn_data_wksp.GetOpMem().get_data_handle(); - - // execute pooling op - pooling_fwd->Execute(src_data, dst_data, ws_data); - } catch (mkldnn::error& e) { - string error_msg = "Status: " + std::to_string(e.status) + - ", message: " + string(e.message) + ", in file " + - string(__FILE__) + ":" + std::to_string(__LINE__); + + if (int8_forward_inference) { + // Execute pooling op + pooling_fwd->Execute(src_data, dst_data); + + // pass min, max from input to output + const Tensor& min_input_t = MklGetInput(context, 1); + const Tensor& max_input_t = MklGetInput(context, 2); + const float min_input = min_input_t.flat()(0); + const float max_input = max_input_t.flat()(0); + + Tensor* output_min = nullptr; + Tensor* output_max = nullptr; + MklDnnShape output_min_mkl_shape, output_max_mkl_shape; + output_min_mkl_shape.SetMklTensor(false); + output_max_mkl_shape.SetMklTensor(false); + AllocateOutputSetMklShape(context, 1, &output_min, {}, + output_min_mkl_shape); + AllocateOutputSetMklShape(context, 2, &output_max, {}, + output_max_mkl_shape); + output_min->flat()(0) = min_input; + output_max->flat()(0) = max_input; + } else { + MklDnnData dnn_data_wksp(&cpu_engine); + AllocateWorkspaceTensor(context, *(pooling_fwd->GetPoolingFwdPd()), + &dnn_data_wksp); + OP_REQUIRES_OK(context, context->status()); + T* ws_data = + static_cast(dnn_data_wksp.GetOpMem().get_data_handle()); + + // execute pooling op + pooling_fwd->Execute(src_data, dst_data, ws_data); + } + } + catch (mkldnn::error& e) { + string error_msg = "Status: " + std::to_string(e.status) + ", message: " + + string(e.message) + ", in file " + string(__FILE__) + + ":" + std::to_string(__LINE__); OP_REQUIRES_OK(context, errors::Aborted("Compute received an exception:", error_msg)); } @@ -684,24 +719,25 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { orig_input_mkl_shape.IsMklTensor() ? orig_input_mkl_shape.GetSizesAsMklDnnDims() : is_pool2d ? TFShapeToMklDnnDimsInNCHW(orig_input_shape, - this->data_format_tf_) - : TFShapeToMklDnnDimsInNCDHW(orig_input_shape, - this->data_format_tf_); + this->data_format_tf_) + : TFShapeToMklDnnDimsInNCDHW(orig_input_shape, + this->data_format_tf_); memory::dims diff_dst_dims = grad_mkl_shape.IsMklTensor() ? grad_mkl_shape.GetSizesAsMklDnnDims() : is_pool2d ? TFShapeToMklDnnDimsInNCHW(grad_tensor.shape(), - this->data_format_tf_) - : TFShapeToMklDnnDimsInNCDHW(grad_tensor.shape(), - this->data_format_tf_); + this->data_format_tf_) + : TFShapeToMklDnnDimsInNCDHW(grad_tensor.shape(), + this->data_format_tf_); memory::dims output_dims_mkl_order; this->GetOutputDims(pool_params, &output_dims_mkl_order); MklPoolingParams bwdParams( orig_input_dims_mkl_order, output_dims_mkl_order, filter_dims, - strides, padding_left, padding_right, algorithm::pooling_max); + strides, padding_left, padding_right, algorithm::pooling_max, + prop_kind::forward_training); MklPoolingBwdPrimitive* pooling_bwd = MklPoolingBwdPrimitiveFactory::Get(bwdParams); @@ -736,11 +772,10 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { if (ws_md.data.format != pooling_bwd->GetWorkspaceFormat()) { memory::dims ws_dims; ws_dims.assign(ws_md.data.dims, ws_md.data.dims + ws_md.data.ndims); - auto target_ws = - memory::primitive_desc({{ws_dims}, - pooling_bwd->GetWorkspaceDataType(), - pooling_bwd->GetWorkspaceFormat()}, - cpu_engine); + auto target_ws = memory::primitive_desc( + {{ws_dims}, pooling_bwd->GetWorkspaceDataType(), + pooling_bwd->GetWorkspaceFormat()}, + cpu_engine); workspace_dnn_data.SetUsrMem(ws_md, &workspace_tensor); workspace_dnn_data.CheckReorderToOpMem(target_ws); ws_data = workspace_dnn_data.GetOpMem().get_data_handle(); @@ -750,10 +785,11 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { // execute pooling pooling_bwd->Execute(diff_dst_data, diff_src_data, ws_data); - } catch (mkldnn::error& e) { - string error_msg = "Status:" + std::to_string(e.status) + - ", message: " + string(e.message) + ". in file " + - string(__FILE__) + ":" + std::to_string(__LINE__); + } + catch (mkldnn::error& e) { + string error_msg = "Status:" + std::to_string(e.status) + ", message: " + + string(e.message) + ". in file " + string(__FILE__) + + ":" + std::to_string(__LINE__); OP_REQUIRES_OK(context, errors::Aborted("Compute received an exception:", error_msg)); } @@ -788,46 +824,45 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { const MklDnnShape& workspace_mkl_shape) { if (!orig_input_mkl_shape.IsMklTensor()) { OP_REQUIRES(context, orig_input_tensor.dims() == 4, - errors::InvalidArgument("Original input shape must be " - "4-dimensional")); + errors::InvalidArgument( + "Original input shape must be 4-dimensional")); } else { OP_REQUIRES(context, orig_input_mkl_shape.GetDimension() == 4, - errors::InvalidArgument("Original input shape must be " - "4-dimensional")); + errors::InvalidArgument( + "Original input shape must be 4-dimensional")); } if (!orig_output_mkl_shape.IsMklTensor()) { - OP_REQUIRES(context, orig_output_tensor.dims() == 4, - errors::InvalidArgument("Original output must be " - "4-dimensional")); + OP_REQUIRES( + context, orig_output_tensor.dims() == 4, + errors::InvalidArgument("Original output must be 4-dimensional")); } else { - OP_REQUIRES(context, orig_output_mkl_shape.GetDimension() == 4, - errors::InvalidArgument("Original output must be " - "4-dimensional")); + OP_REQUIRES( + context, orig_output_mkl_shape.GetDimension() == 4, + errors::InvalidArgument("Original output must be 4-dimensional")); } if (!grad_mkl_shape.IsMklTensor()) { OP_REQUIRES(context, grad_tensor.dims() == 4, errors::InvalidArgument("Gradient must be 4-dimensional")); } else { OP_REQUIRES(context, grad_mkl_shape.GetDimension() == 4, - errors::InvalidArgument("Gradient must be " - "4-dimensional")); + errors::InvalidArgument("Gradient must be 4-dimensional")); } if (this->workspace_enabled_) { // The workspace should not be an MKL tensor OP_REQUIRES(context, workspace_mkl_shape.IsMklTensor() == false, - errors::InvalidArgument("Workspace tensor should not" - " be an MKL Tensor.")); + errors::InvalidArgument( + "Workspace tensor should not be an MKL Tensor.")); // It should only have one dimension - OP_REQUIRES(context, workspace_tensor.dims() == 1, - errors::InvalidArgument("Workspace tensor must be " - "1-dimensional")); - } else { OP_REQUIRES( - context, this->workspace_enabled_, - errors::Unimplemented("MKL-DNN Max Pooling does not " - "yet support the use case " - "where MaxPoolGrad is called without first" - " calling MaxPool.")); + context, workspace_tensor.dims() == 1, + errors::InvalidArgument("Workspace tensor must be 1-dimensional")); + } else { + OP_REQUIRES(context, this->workspace_enabled_, + errors::Unimplemented( + "MKL-DNN Max Pooling does not " + "yet support the use case " + "where MaxPoolGrad is called without first" + " calling MaxPool.")); } } }; // MklMaxPoolingGradOp @@ -852,6 +887,18 @@ REGISTER_KERNEL_BUILDER(Name("_MklMaxPool") .Label(mkl_op_registry::kMklOpLabel), MklMaxPoolingOp); +REGISTER_KERNEL_BUILDER(Name("_MklQuantizedMaxPool") + .Device(DEVICE_CPU) + .TypeConstraint("T") + .Label(mkl_op_registry::kMklQuantizedOpLabel), + MklMaxPoolingOp); + +REGISTER_KERNEL_BUILDER(Name("_MklQuantizedMaxPool") + .Device(DEVICE_CPU) + .TypeConstraint("T") + .Label(mkl_op_registry::kMklQuantizedOpLabel), + MklMaxPoolingOp); + REGISTER_KERNEL_BUILDER(Name("_MklMaxPoolGrad") .Device(DEVICE_CPU) .TypeConstraint("T") diff --git a/tensorflow/core/kernels/mkl_pooling_ops_common.cc b/tensorflow/core/kernels/mkl_pooling_ops_common.cc index 5398e6113f..cf3f0f1469 100644 --- a/tensorflow/core/kernels/mkl_pooling_ops_common.cc +++ b/tensorflow/core/kernels/mkl_pooling_ops_common.cc @@ -41,28 +41,33 @@ void MklPoolingFwdPrimitive::Setup(const MklPoolingParams& fwdParams) { << "Pooling algorithm kind is not supported"; context_.alg_kind = fwdParams.alg_kind; + context_.prop_kind = fwdParams.prop_kind; + // create memory desc // FIXME: Pooling doesn't expose to get the src_primitive_desc, // so src format is currently hard-coded. // A utility function is used to do this, // which may be broken with future CPU architectures bool is_2d = (fwdParams.src_dims.size() == 4); - context_.src_md.reset( - new memory::desc({fwdParams.src_dims}, MklDnnType(), - get_desired_format(fwdParams.src_dims[1], is_2d))); + if (std::is_same::value || std::is_same::value) + context_.src_fmt = is_2d ? memory::format::nhwc : memory::format::ndhwc; + else + context_.src_fmt = get_desired_format(fwdParams.src_dims[1], is_2d); + + context_.src_md.reset(new memory::desc({fwdParams.src_dims}, MklDnnType(), + context_.src_fmt)); context_.dst_md.reset(new memory::desc({fwdParams.dst_dims}, MklDnnType(), memory::format::any)); // create a pooling descriptor context_.fwd_desc.reset(new pooling_forward::desc( - prop_kind::forward_training, fwdParams.alg_kind, *context_.src_md, + fwdParams.prop_kind, fwdParams.alg_kind, *context_.src_md, *context_.dst_md, fwdParams.strides, fwdParams.filter_dims, fwdParams.padding_left, fwdParams.padding_right, padding_kind::zero)); context_.fwd_pd.reset( new pooling_forward::primitive_desc(*context_.fwd_desc, cpu_engine_)); // store expected primitive format - context_.src_fmt = get_desired_format(fwdParams.src_dims[1], is_2d); context_.dst_fmt = static_cast( context_.fwd_pd.get()->dst_primitive_desc().desc().data.format); @@ -74,7 +79,8 @@ void MklPoolingFwdPrimitive::Setup(const MklPoolingParams& fwdParams) { new memory(context_.fwd_pd.get()->dst_primitive_desc(), DummyData)); // for max pooling, need to return workspace(ws) for backward computing - if (fwdParams.alg_kind == pooling_max) { + if (fwdParams.alg_kind == pooling_max && + fwdParams.prop_kind == prop_kind::forward_training) { auto ws_pd = context_.fwd_pd.get()->workspace_primitive_desc().desc().data; // store workspace's dims and format to create workspace tensor context_.ws_fmt = static_cast(ws_pd.format); @@ -101,7 +107,9 @@ void MklPoolingFwdPrimitive::Execute(const T* src_data, T* dst_data, context_.src_mem->set_data_handle( static_cast(const_cast(src_data))); context_.dst_mem->set_data_handle(static_cast(dst_data)); - if (context_.alg_kind == pooling_max) { // max pooling must have ws + if (context_.alg_kind == pooling_max && + context_.prop_kind == + prop_kind::forward_training) { // max pooling must have ws DCHECK(ws_data != nullptr); context_.ws_mem->set_data_handle(ws_data); } @@ -110,13 +118,17 @@ void MklPoolingFwdPrimitive::Execute(const T* src_data, T* dst_data, // set back data handle context_.src_mem->set_data_handle(DummyData); context_.dst_mem->set_data_handle(DummyData); - if (context_.alg_kind == pooling_max) { // max pooling must have ws + if (context_.alg_kind == pooling_max && + context_.prop_kind == + prop_kind::forward_training) { // max pooling must have ws DCHECK(ws_data != nullptr); context_.ws_mem->set_data_handle(DummyData); } } template class MklPoolingFwdPrimitive; +template class MklPoolingFwdPrimitive; +template class MklPoolingFwdPrimitive; template void MklPoolingBwdPrimitive::Setup(const MklPoolingParams& bwdParams) { @@ -143,7 +155,7 @@ void MklPoolingBwdPrimitive::Setup(const MklPoolingParams& bwdParams) { // create a forward primitive, // which will be used as a hint for creating backward primitive context_.fwd_desc.reset(new pooling_forward::desc( - prop_kind::forward_training, bwdParams.alg_kind, *context_.diff_src_md, + bwdParams.prop_kind, bwdParams.alg_kind, *context_.diff_src_md, *context_.diff_dst_md, bwdParams.strides, bwdParams.filter_dims, bwdParams.padding_left, bwdParams.padding_right, padding_kind::zero)); context_.fwd_pd.reset( @@ -368,21 +380,24 @@ void MklPoolParameters::Init(OpKernelContext* context, // any padding, and expects the depth_window to equal the depth // stride (no overlapping). OP_REQUIRES(context, depth % depth_window == 0, - errors::Unimplemented("Depthwise max pooling requires the" - " depth window to evenly divide the" - " input depth")); + errors::Unimplemented( + "Depthwise max pooling requires the" + " depth window to evenly divide the" + " input depth")); OP_REQUIRES(context, depth_stride == depth_window, - errors::Unimplemented("Depthwise max pooling requires the" - " depth window to equal the depth" - " stride")); + errors::Unimplemented( + "Depthwise max pooling requires the" + " depth window to equal the depth" + " stride")); // The current version of depthwise max is only implemented on CPU. OP_REQUIRES(context, (DeviceType(static_cast(context->device()) ->attributes() .device_type()) == DeviceType(DEVICE_CPU)), - errors::Unimplemented("Depthwise max pooling is currently " - "only implemented for CPU devices.")); + errors::Unimplemented( + "Depthwise max pooling is currently " + "only implemented for CPU devices.")); out_depth = depth / depth_window; } diff --git a/tensorflow/core/kernels/mkl_pooling_ops_common.h b/tensorflow/core/kernels/mkl_pooling_ops_common.h index 49f799d7ba..d214c39484 100644 --- a/tensorflow/core/kernels/mkl_pooling_ops_common.h +++ b/tensorflow/core/kernels/mkl_pooling_ops_common.h @@ -18,8 +18,8 @@ limitations under the License. #ifdef INTEL_MKL #include -#include #include +#include #include "tensorflow/core/util/mkl_util.h" #include "tensorflow/core/util/padding.h" @@ -50,18 +50,20 @@ struct MklPoolingParams { memory::dims padding_left; memory::dims padding_right; mkldnn::algorithm alg_kind; + mkldnn::prop_kind prop_kind; MklPoolingParams(memory::dims src_dims, memory::dims dst_dims, memory::dims filter_dims, memory::dims strides, memory::dims padding_left, memory::dims padding_right, - mkldnn::algorithm alg_kind) + mkldnn::algorithm alg_kind, mkldnn::prop_kind prop_kind) : src_dims(src_dims), dst_dims(dst_dims), filter_dims(filter_dims), strides(strides), padding_left(padding_left), padding_right(padding_right), - alg_kind(alg_kind) {} + alg_kind(alg_kind), + prop_kind(prop_kind) {} }; template @@ -97,6 +99,9 @@ class MklPoolingFwdPrimitive : public MklPrimitive { // algorithm mkldnn::algorithm alg_kind; + // Kind of propagation, forward or backward + mkldnn::prop_kind prop_kind; + // expected memory format memory::format src_fmt; memory::format dst_fmt; @@ -187,6 +192,7 @@ class MklPoolingFwdPrimitiveFactory : public MklPrimitiveFactory { key_creator.AddAsKey(fwdParams.padding_left); key_creator.AddAsKey(fwdParams.padding_right); key_creator.AddAsKey(static_cast(fwdParams.alg_kind)); + key_creator.AddAsKey(static_cast(fwdParams.prop_kind)); return key_creator.GetKey(); } @@ -443,25 +449,33 @@ class MklPoolingOpBase : public OpKernel { explicit MklPoolingOpBase(OpKernelConstruction* context) : OpKernel(context), workspace_enabled_(false) { string data_format; - OP_REQUIRES_OK(context, context->GetAttr("data_format", &data_format)); + if (std::is_same::value || std::is_same::value) { + // current quantized convolution doesn't have data_format attribute. + data_format = "NHWC"; + } else { + OP_REQUIRES_OK(context, context->GetAttr("data_format", &data_format)); + } OP_REQUIRES(context, FormatFromString(data_format, &this->data_format_tf_), errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &this->ksize_)); OP_REQUIRES(context, this->ksize_.size() == 4 || this->ksize_.size() == 5, - errors::InvalidArgument("Sliding window ksize field must " - "specify 4 or 5 dimensions")); + errors::InvalidArgument( + "Sliding window ksize field must " + "specify 4 or 5 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &this->stride_)); OP_REQUIRES(context, this->stride_.size() == 4 || this->stride_.size() == 5, - errors::InvalidArgument("Sliding window strides field must " - "specify 4 or 5 dimensions")); + errors::InvalidArgument( + "Sliding window strides field must " + "specify 4 or 5 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &this->padding_)); OP_REQUIRES(context, this->ksize_[0] == 1 && this->stride_[0] == 1, - errors::Unimplemented("Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented( + "Pooling is not yet supported on the " + "batch dimension.")); bool is_pool2d = (this->ksize_.size() == 4); this->data_format_mkldnn_ = is_pool2d ? TFDataFormatToMklDnnDataFormat(this->data_format_tf_) - : TFDataFormatToMklDnn3DDataFormat(this->data_format_tf_); + : TFDataFormatToMklDnn3DDataFormat(this->data_format_tf_); // We may not get this attribute for this node if it does not go through // graph rewrite pass. So we do not check for error while retrieving this @@ -655,10 +669,10 @@ class MklPoolingForwardOpBase : public MklPoolingOpBase { OP_REQUIRES(context, input_tensor.dims() == 4 || input_tensor.dims() == 5, errors::InvalidArgument("Input must be 4 or 5-dimensional")); } else { - OP_REQUIRES(context, input_mkl_shape.GetDimension() == 4 || - input_mkl_shape.GetDimension() == 5, - errors::InvalidArgument("Input shape must be " - "4 or 5-dimensional")); + OP_REQUIRES( + context, input_mkl_shape.GetDimension() == 4 || + input_mkl_shape.GetDimension() == 5, + errors::InvalidArgument("Input shape must be 4 or 5-dimensional")); } } // .Input("value: T") diff --git a/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc b/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc new file mode 100644 index 0000000000..92fc1bfd07 --- /dev/null +++ b/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc @@ -0,0 +1,201 @@ +/* Copyright 2015 The TensorFlow Authors. 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. +==============================================================================*/ +#ifdef INTEL_MKL +#define EIGEN_USE_THREADS + +#include "tensorflow/core/framework/allocator.h" +#include "tensorflow/core/framework/fake_input.h" +#include "tensorflow/core/framework/node_def_builder.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/framework/tensor_testutil.h" +#include "tensorflow/core/framework/types.h" +#include "tensorflow/core/framework/types.pb.h" +#include "tensorflow/core/kernels/ops_testutil.h" +#include "tensorflow/core/kernels/ops_util.h" +#include "tensorflow/core/kernels/quantization_utils.h" +#include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { + +// Helper class for converting MKL tensors to TF tensors and comparing to +// expected values + +static const uint8 dummy_tensor[] = {0, 0, 0, 0, 0, 0, 0, 0}; +static const TensorShape dummy_shape({8}); + +class ConvMklToTF : public OpsTestBase { + public: + template + void ConvertMKL2TF(DataType dtype, const Tensor& first, const Tensor& second, + Tensor& output) { + // Create an MKL to TF conversion node and execute it + TF_EXPECT_OK(NodeDefBuilder("mkl_to_tf_op", "_MklToTf") + .Input(FakeInput(dtype)) // Input + .Input(FakeInput(DT_UINT8)) // Mkl second tensor + .Attr("T", dtype) + .Attr("_kernel", "MklOp") + .Finalize(node_def())); + TF_EXPECT_OK(InitOp()); + AddInputFromArray(first.shape(), first.flat()); + AddInputFromArray(second.shape(), second.flat()); + TF_ASSERT_OK(RunOpKernel()); + + output = *GetOutput(0); + } + void TestBody() {}; +}; + +class QuantizedPoolingTest : public OpsTestBase {}; + +TEST_F(QuantizedPoolingTest, SmallAveragePooling) { + const int ksize = 2; + const int stride = 2; + TF_ASSERT_OK(NodeDefBuilder("quantized_avg_pool_op", "_MklQuantizedAvgPool") + .Input(FakeInput(DT_QUINT8)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_UINT8)) // MKl second tensor + .Input(FakeInput(DT_UINT8)) // MKl second tensor + .Input(FakeInput(DT_UINT8)) // MKl second tensor + .Attr("T", DataTypeToEnum::v()) + .Attr("ksize", {1, ksize, ksize, 1}) + .Attr("strides", {1, stride, stride, 1}) + .Attr("padding", "SAME") + .Attr("_kernel", "QuantizedMklOp") + .Finalize(node_def())); + TF_ASSERT_OK(InitOp()); + const float input_min = 0.0f; + const float input_max = 255.0f; + const int input_height = 4; + const int input_width = 4; + const int input_channels = 2; + Tensor input_float(DT_FLOAT, {1, input_height, input_width, input_channels}); + test::FillValues( + &input_float, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}); + Tensor input_quantized = + FloatTensorToQuantized(input_float, input_min, input_max); + + const int expected_width = input_width / stride; + const int expected_height = input_height / stride; + + // The input pools we are averaging. (NHWC input, quantized.) + // 0th channel 1st channel + // 1 3 | 5 7 2 4 | 6 8 + // 9 11 | 13 15 10 12 | 14 16 + // ------------- ------------- + // 17 19 | 21 23 18 20 | 22 24 + // 25 27 | 29 31 26 28 | 30 32 + Tensor expected_float(DT_FLOAT, + {1, expected_height, expected_width, input_channels}); + test::FillValues(&expected_float, {6, 7, 10, 11, 22, 23, 26, 27}); + + AddInputFromArray(input_quantized.shape(), + input_quantized.flat()); + AddInputFromArray(TensorShape({1}), {input_min}); + AddInputFromArray(TensorShape({1}), {input_max}); + AddInputFromArray(dummy_shape, dummy_tensor); + AddInputFromArray(dummy_shape, dummy_tensor); + AddInputFromArray(dummy_shape, dummy_tensor); + + TF_ASSERT_OK(RunOpKernel()); + + const Tensor& output = *GetOutput(0); + const Tensor& mkl_shape_tensor = *GetOutput(3); + ConvMklToTF conv_comp; + Tensor output_quantized; + conv_comp.ConvertMKL2TF(DT_QUINT8, output, mkl_shape_tensor, + output_quantized); + + const float output_min = GetOutput(1)->flat()(0); + const float output_max = GetOutput(2)->flat()(0); + Tensor output_float = + QuantizedTensorToFloat(output_quantized, output_min, output_max); + + test::ExpectTensorNear(expected_float, output_float, 0.2); +} + +TEST_F(QuantizedPoolingTest, SmallMaxPooling) { + const int ksize = 2; + const int stride = 2; + TF_ASSERT_OK(NodeDefBuilder("quantized_max_pool_op", "_MklQuantizedMaxPool") + .Input(FakeInput(DT_QUINT8)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_FLOAT)) + .Input(FakeInput(DT_UINT8)) // MKl second tensor + .Input(FakeInput(DT_UINT8)) // MKl second tensor + .Input(FakeInput(DT_UINT8)) // MKl second tensor + .Attr("T", DataTypeToEnum::v()) + .Attr("ksize", {1, ksize, ksize, 1}) + .Attr("strides", {1, stride, stride, 1}) + .Attr("padding", "SAME") + .Attr("_kernel", "QuantizedMklOp") + .Finalize(node_def())); + TF_ASSERT_OK(InitOp()); + const float input_min = 0.0f; + const float input_max = 255.0f; + const int input_height = 4; + const int input_width = 4; + const int input_channels = 2; + Tensor input_float(DT_FLOAT, {1, input_height, input_width, input_channels}); + test::FillValues( + &input_float, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}); + Tensor input_quantized = + FloatTensorToQuantized(input_float, input_min, input_max); + const int expected_width = input_width / stride; + const int expected_height = input_height / stride; + + // The max is computed from these input pools. (NHWC input, quantized.) + // 0th channel 1st channel + // 1 3 | 5 7 2 4 | 6 8 + // 9 11 | 13 15 10 12 | 14 16 + // ------------- ------------- + // 17 19 | 21 23 18 20 | 22 24 + // 25 27 | 29 31 26 28 | 30 32 + + Tensor expected_float(DT_FLOAT, + {1, expected_height, expected_width, input_channels}); + test::FillValues(&expected_float, {11, 12, 15, 16, 27, 28, 31, 32}); + AddInputFromArray(input_quantized.shape(), + input_quantized.flat()); + AddInputFromArray(TensorShape({1}), {input_min}); + AddInputFromArray(TensorShape({1}), {input_max}); + AddInputFromArray(dummy_shape, dummy_tensor); + AddInputFromArray(dummy_shape, dummy_tensor); + AddInputFromArray(dummy_shape, dummy_tensor); + + TF_ASSERT_OK(RunOpKernel()); + + const Tensor& output = *GetOutput(0); + const Tensor& mkl_shape_tensor = *GetOutput(3); + ConvMklToTF conv_comp; + Tensor output_quantized; + conv_comp.ConvertMKL2TF(DT_QUINT8, output, mkl_shape_tensor, + output_quantized); + + const float output_min = GetOutput(1)->flat()(0); + const float output_max = GetOutput(2)->flat()(0); + Tensor output_float = + QuantizedTensorToFloat(output_quantized, output_min, output_max); + + test::ExpectTensorNear(expected_float, output_float, 0.2); +} +} // namespace tensorflow +#endif -- GitLab From 3bace0cdcd9e773462ae95e26d1e75c4d0c64908 Mon Sep 17 00:00:00 2001 From: Mahmoud Abuzaina Date: Wed, 28 Nov 2018 09:00:27 -0800 Subject: [PATCH 450/672] Fixed a bug in quantized convolution --- tensorflow/core/kernels/mkl_conv_ops.cc | 162 ++++++++++++------------ 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/tensorflow/core/kernels/mkl_conv_ops.cc b/tensorflow/core/kernels/mkl_conv_ops.cc index dc6f783623..8e3b669a59 100644 --- a/tensorflow/core/kernels/mkl_conv_ops.cc +++ b/tensorflow/core/kernels/mkl_conv_ops.cc @@ -323,7 +323,7 @@ class MklConvFwdPrimitiveFactory : public MklPrimitiveFactory { const MklConvFwdParams& convFwdDims, bool do_not_cache) { MklConvFwdPrimitive* conv_fwd = nullptr; - if (do_not_cache) { /* Always create new primitive */ + if (do_not_cache) {/* Always create new primitive */ conv_fwd = new MklConvFwdPrimitive( convFwdDims); } else { @@ -423,15 +423,16 @@ class MklConvOp : public OpKernel { OP_REQUIRES(context, FormatFromString(data_format, &data_format_), errors::InvalidArgument("Invalid data format")); OP_REQUIRES(context, strides_.size() == 4, - errors::InvalidArgument("Sliding window strides field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window strides field must " + "specify 4 dimensions")); const int64 stride_n = GetTensorDim(strides_, data_format_, 'N'); const int64 stride_c = GetTensorDim(strides_, data_format_, 'C'); - OP_REQUIRES( - context, stride_n == 1 && stride_c == 1, - errors::InvalidArgument("Current implementation does not yet support " - "strides in the batch and depth dimensions.")); + OP_REQUIRES(context, stride_n == 1 && stride_c == 1, + errors::InvalidArgument( + "Current implementation does not yet support " + "strides in the batch and depth dimensions.")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); } @@ -465,19 +466,18 @@ class MklConvOp : public OpKernel { filter.shape().DebugString())); for (int i = 0; i < 3; i++) { - OP_REQUIRES( - context, - FastBoundsCheck(filter.dim_size(i), std::numeric_limits::max()), - errors::InvalidArgument("filter too large")); + OP_REQUIRES(context, FastBoundsCheck(filter.dim_size(i), + std::numeric_limits::max()), + errors::InvalidArgument("filter too large")); } const int64 input_depth = input_in_mkl_format ? GetMklTensorDim(mkl_context.input_shape, 'C') : GetTensorDim(input, data_format_, 'C'); - OP_REQUIRES(context, input_depth == filter.dim_size(2), - errors::InvalidArgument( - "input and filter must have the same depth: ", input_depth, - " vs ", filter.dim_size(2))); + OP_REQUIRES( + context, input_depth == filter.dim_size(2), + errors::InvalidArgument("input and filter must have the same depth: ", + input_depth, " vs ", filter.dim_size(2))); // The last dimension for filter is out_depth. const int out_depth = static_cast(filter.dim_size(3)); @@ -486,10 +486,9 @@ class MklConvOp : public OpKernel { const int64 input_rows_raw = input_in_mkl_format ? GetMklTensorDim(mkl_context.input_shape, 'H') : GetTensorDim(input, data_format_, 'H'); - OP_REQUIRES( - context, - FastBoundsCheck(input_rows_raw, std::numeric_limits::max()), - errors::InvalidArgument("Input rows too large")); + OP_REQUIRES(context, FastBoundsCheck(input_rows_raw, + std::numeric_limits::max()), + errors::InvalidArgument("Input rows too large")); const int input_rows = static_cast(input_rows_raw); const int filter_rows = static_cast(filter.dim_size(0)); @@ -498,10 +497,9 @@ class MklConvOp : public OpKernel { const int64 input_cols_raw = input_in_mkl_format ? GetMklTensorDim(mkl_context.input_shape, 'W') : GetTensorDim(input, data_format_, 'W'); - OP_REQUIRES( - context, - FastBoundsCheck(input_cols_raw, std::numeric_limits::max()), - errors::InvalidArgument("Input cols too large")); + OP_REQUIRES(context, FastBoundsCheck(input_cols_raw, + std::numeric_limits::max()), + errors::InvalidArgument("Input cols too large")); const int input_cols = static_cast(input_cols_raw); const int filter_cols = static_cast(filter.dim_size(1)); @@ -509,10 +507,9 @@ class MklConvOp : public OpKernel { const int64 input_batch_raw = input_in_mkl_format ? GetMklTensorDim(mkl_context.input_shape, 'N') : GetTensorDim(input, data_format_, 'N'); - OP_REQUIRES( - context, - FastBoundsCheck(input_batch_raw, std::numeric_limits::max()), - errors::InvalidArgument("batch is too large")); + OP_REQUIRES(context, FastBoundsCheck(input_batch_raw, + std::numeric_limits::max()), + errors::InvalidArgument("batch is too large")); const int batch = static_cast(input_batch_raw); // For now we take the stride from the second and third dimensions only (we @@ -730,7 +727,7 @@ class MklConvOp : public OpKernel { mkl_prim_convert_input; dnnLayout_t mkl_lt_internal_filter, mkl_lt_internal_bias, mkl_lt_internal_input; - void *mkl_buf_convert_input, *mkl_buf_convert_filter, + void* mkl_buf_convert_input, *mkl_buf_convert_filter, *mkl_buf_convert_bias; mkl_prim_convert_filter = nullptr; mkl_prim_convert_bias = nullptr; @@ -863,21 +860,23 @@ class MklConvOp : public OpKernel { OP_REQUIRES(context, FormatFromString(data_format, &data_format_), errors::InvalidArgument("Invalid data format")); OP_REQUIRES(context, (strides_.size() == 4 || strides_.size() == 5), - errors::InvalidArgument("Sliding window strides field must " - "specify 4 or 5 dimensions")); + errors::InvalidArgument( + "Sliding window strides field must " + "specify 4 or 5 dimensions")); const int64 stride_n = GetTensorDim(strides_, data_format_, 'N'); const int64 stride_c = GetTensorDim(strides_, data_format_, 'C'); - OP_REQUIRES( - context, stride_n == 1 && stride_c == 1, - errors::InvalidArgument("Current implementation does not yet support " - "strides in the batch and depth dimensions.")); + OP_REQUIRES(context, stride_n == 1 && stride_c == 1, + errors::InvalidArgument( + "Current implementation does not yet support " + "strides in the batch and depth dimensions.")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); if (strides_.size() == 4) { OP_REQUIRES(context, dilations_.size() == 4, - errors::InvalidArgument("Sliding window dilations field must " - "specify 4 dimensions")); + errors::InvalidArgument( + "Sliding window dilations field must " + "specify 4 dimensions")); const int64 dilation_n = GetTensorDim(dilations_, data_format_, 'N'); const int64 dilation_c = GetTensorDim(dilations_, data_format_, 'C'); const int64 dilation_h = GetTensorDim(dilations_, data_format_, 'H'); @@ -891,19 +890,18 @@ class MklConvOp : public OpKernel { errors::InvalidArgument("Dilated rates should be larger than 0.")); } else if (strides_.size() == 5) { OP_REQUIRES(context, dilations_.size() == 5, - errors::InvalidArgument("Dilation rates field must " - "specify 5 dimensions")); - OP_REQUIRES(context, - (GetTensorDim(dilations_, data_format_, 'N') == 1 && - GetTensorDim(dilations_, data_format_, 'C') == 1), + errors::InvalidArgument( + "Dilation rates field must " + "specify 5 dimensions")); + OP_REQUIRES(context, (GetTensorDim(dilations_, data_format_, 'N') == 1 && + GetTensorDim(dilations_, data_format_, 'C') == 1), errors::InvalidArgument( "Current implementation does not yet support " "dilations rates in the batch and depth dimensions.")); OP_REQUIRES( - context, - (GetTensorDim(dilations_, data_format_, '0') > 0 && - GetTensorDim(dilations_, data_format_, '1') > 0 && - GetTensorDim(dilations_, data_format_, '2') > 0), + context, (GetTensorDim(dilations_, data_format_, '0') > 0 && + GetTensorDim(dilations_, data_format_, '1') > 0 && + GetTensorDim(dilations_, data_format_, '2') > 0), errors::InvalidArgument("Dilated rates should be larger than 0.")); } } @@ -918,8 +916,9 @@ class MklConvOp : public OpKernel { GetMklShape(context, kInputIndex_Src, &src_mkl_shape); GetMklShape(context, kInputIndex_Filter, &filter_mkl_shape); OP_REQUIRES(context, filter_mkl_shape.IsMklTensor() == false, - errors::InvalidArgument("Filter should not be in " - "Mkl Layout")); + errors::InvalidArgument( + "Filter should not be in " + "Mkl Layout")); MklDnnData src(&cpu_engine_); MklDnnData filter(&cpu_engine_); @@ -955,9 +954,8 @@ class MklConvOp : public OpKernel { filter_mkl_shape.SetMklTensor(false); Tensor* output_filter_tensor = nullptr; // MklConv2D also outputs converted filter as 2nd output. - if (typeid(Tinput) == typeid(float) && - typeid(Tfilter) == typeid(float) && - typeid(Toutput) == typeid(float)) { + if (typeid(Tinput) == typeid(float)&&typeid(Tfilter) == + typeid(float)&&typeid(Toutput) == typeid(float)) { filter_mkl_shape.SetMklTensor(false); AllocateOutputSetMklShape(context, kOutputIndex_Filter, &output_filter_tensor, filter_tf_shape, @@ -1044,8 +1042,8 @@ class MklConvOp : public OpKernel { AllocateOutputTensor(context, *conv_fwd_pd, dst_dims_mkl_order, tf_fmt, &dst_tensor); Tensor* filter_out_tensor = nullptr; - if (typeid(Tinput) == typeid(float) && typeid(Tfilter) == typeid(float) && - typeid(Toutput) == typeid(float)) { + if (typeid(Tinput) == typeid(float)&&typeid(Tfilter) == + typeid(float)&&typeid(Toutput) == typeid(float)) { AllocateFilterOutputTensor(context, *conv_fwd_pd, TFShapeToMklDnnDims(filter_tf_shape), &filter_out_tensor); @@ -1067,8 +1065,14 @@ class MklConvOp : public OpKernel { Tfilter* filter_data = nullptr; if (filter_md.data.format != conv_fwd->GetFilterMemoryFormat()) { filter.SetUsrMem(filter_md, &filter_tensor); - filter.CheckReorderToOpMem(conv_fwd_pd.get()->weights_primitive_desc(), - filter.GetTensorBuffer(filter_out_tensor)); + if (filter_out_tensor == nullptr) { + filter.CheckReorderToOpMem( + conv_fwd_pd.get()->weights_primitive_desc()); + } else { + filter.CheckReorderToOpMem( + conv_fwd_pd.get()->weights_primitive_desc(), + filter.GetTensorBuffer(filter_out_tensor)); + } filter_data = static_cast(filter.GetOpMem().get_data_handle()); } else { @@ -1088,7 +1092,8 @@ class MklConvOp : public OpKernel { // delete primitive since it is not cached. if (do_not_cache) delete conv_fwd; - } catch (mkldnn::error& e) { + } + catch (mkldnn::error& e) { string error_msg = tensorflow::strings::StrCat( "Status: ", e.status, ", message: ", string(e.message), ", in file ", __FILE__, ":", __LINE__); @@ -1533,8 +1538,8 @@ class MklQuantizedConv2DSumReluOp const float max_filter = context->input(5 + bias_index_offset).flat()(0); - reorder_sum_scale = 255.0 * 127.0 / - (std::max(std::abs(max_input), std::abs(min_input)) * + reorder_sum_scale = + 255.0 * 127.0 / (std::max(std::abs(max_input), std::abs(min_input)) * std::max(std::abs(max_filter), std::abs(min_filter))); std::vector scales; scales.push_back(reorder_sum_scale); @@ -1784,34 +1789,31 @@ REGISTER_KERNEL_BUILDER( #endif // INTEL_MKL_ML // Register 2D operations -#define REGISTER_MKL_CPU_2D(T) \ - REGISTER_KERNEL_BUILDER( \ - Name("_MklConv2D") \ - .Device(DEVICE_CPU) \ - .TypeConstraint("T") \ - .Label(mkl_op_registry::kMklOpLabel), \ - MklConvOp); \ - REGISTER_KERNEL_BUILDER( \ - Name("_MklConv2DWithBias") \ - .Device(DEVICE_CPU) \ - .TypeConstraint("T") \ - .Label(mkl_op_registry::kMklOpLabel), \ - MklConvOp); \ - REGISTER_KERNEL_BUILDER(Name("__MklDummyConv2DWithBias") \ - .Device(DEVICE_CPU) \ - .TypeConstraint("T") \ - .Label(mkl_op_registry::kMklOpLabel), \ +#define REGISTER_MKL_CPU_2D(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("_MklConv2D").Device(DEVICE_CPU).TypeConstraint("T").Label( \ + mkl_op_registry::kMklOpLabel), \ + MklConvOp); \ + REGISTER_KERNEL_BUILDER( \ + Name("_MklConv2DWithBias") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ + MklConvOp); \ + REGISTER_KERNEL_BUILDER(Name("__MklDummyConv2DWithBias") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ MklDummyOp); TF_CALL_float(REGISTER_MKL_CPU_2D); // Register 3D operations -#define REGISTER_MKL_CPU_3D(T) \ - REGISTER_KERNEL_BUILDER(Name("_MklConv3D") \ - .Device(DEVICE_CPU) \ - .TypeConstraint("T") \ - .Label(mkl_op_registry::kMklOpLabel), \ - MklConvOp); +#define REGISTER_MKL_CPU_3D(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("_MklConv3D").Device(DEVICE_CPU).TypeConstraint("T").Label( \ + mkl_op_registry::kMklOpLabel), \ + MklConvOp); TF_CALL_float(REGISTER_MKL_CPU_3D); } // namespace tensorflow -- GitLab From 0ae35dd8c952350208f443b4c47c538ef3edb728 Mon Sep 17 00:00:00 2001 From: Martin Wicke Date: Wed, 28 Nov 2018 09:03:01 -0800 Subject: [PATCH 451/672] Fix path to update script. PiperOrigin-RevId: 223177077 --- tensorflow/tools/pip_package/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index 001aa22227..34c600abaf 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -107,7 +107,7 @@ CONSOLE_SCRIPTS = [ # TensorBoard command, pip will inappropriately remove it during install, # even though the command is not removed, just moved to a different wheel. 'tensorboard = tensorboard.main:run_main', - 'tf_upgrade_v2 = tensorflow.python.tools.compatibility.tf_upgrade_v2:main', + 'tf_upgrade_v2 = tensorflow.tools.compatibility.tf_upgrade_v2:main', ] # pylint: enable=line-too-long -- GitLab From 68f506dd57f9dc84208f518c08a10af031bd582f Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 28 Nov 2018 09:06:42 -0800 Subject: [PATCH 452/672] Remove deprecated session-based tf.train._ classes from TF 2.0 API. PiperOrigin-RevId: 223177761 --- .../python/training/monitored_session.py | 10 +- tensorflow/python/training/session_manager.py | 2 +- tensorflow/python/training/supervisor.py | 2 +- ...sorflow.train.-chief-session-creator.pbtxt | 14 -- ...ain.-monitored-session.-step-context.pbtxt | 21 --- .../tensorflow.train.-monitored-session.pbtxt | 34 ---- .../tensorflow.train.-session-creator.pbtxt | 12 -- .../tensorflow.train.-session-manager.pbtxt | 21 --- ...ular-monitored-session.-step-context.pbtxt | 21 --- ...ow.train.-singular-monitored-session.pbtxt | 38 ----- .../v2/tensorflow.train.-supervisor.pbtxt | 153 ------------------ ...orflow.train.-worker-session-creator.pbtxt | 14 -- .../api/golden/v2/tensorflow.train.pbtxt | 28 ---- tensorflow/tools/compatibility/renames_v2.py | 9 +- 14 files changed, 15 insertions(+), 364 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-chief-session-creator.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.-step-context.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-session-creator.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-session-manager.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.-step-context.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-supervisor.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-worker-session-creator.pbtxt diff --git a/tensorflow/python/training/monitored_session.py b/tensorflow/python/training/monitored_session.py index ccd9014648..c40bd2b859 100644 --- a/tensorflow/python/training/monitored_session.py +++ b/tensorflow/python/training/monitored_session.py @@ -508,7 +508,7 @@ def MonitoredTrainingSession(master='', # pylint: disable=invalid-name stop_grace_period_secs=stop_grace_period_secs) -@tf_export('train.SessionCreator') +@tf_export(v1=['train.SessionCreator']) @six.add_metaclass(abc.ABCMeta) class SessionCreator(object): """A factory for tf.Session.""" @@ -519,7 +519,7 @@ class SessionCreator(object): 'create_session is not implemented for {}.'.format(self)) -@tf_export('train.ChiefSessionCreator') +@tf_export(v1=['train.ChiefSessionCreator']) class ChiefSessionCreator(SessionCreator): """Creates a tf.Session for a chief.""" @@ -571,7 +571,7 @@ class ChiefSessionCreator(SessionCreator): init_fn=self._scaffold.init_fn) -@tf_export('train.WorkerSessionCreator') +@tf_export(v1=['train.WorkerSessionCreator']) class WorkerSessionCreator(SessionCreator): """Creates a tf.Session for a worker.""" @@ -851,7 +851,7 @@ class _MonitoredSession(object): return self._coordinated_creator.tf_sess -@tf_export('train.MonitoredSession') +@tf_export(v1=['train.MonitoredSession']) class MonitoredSession(_MonitoredSession): """Session-like object that handles initialization, recovery and hooks. @@ -934,7 +934,7 @@ class MonitoredSession(_MonitoredSession): stop_grace_period_secs=stop_grace_period_secs) -@tf_export('train.SingularMonitoredSession') +@tf_export(v1=['train.SingularMonitoredSession']) class SingularMonitoredSession(_MonitoredSession): """Session-like object that handles initialization, restoring, and hooks. diff --git a/tensorflow/python/training/session_manager.py b/tensorflow/python/training/session_manager.py index cd313c2ce0..14658630c5 100644 --- a/tensorflow/python/training/session_manager.py +++ b/tensorflow/python/training/session_manager.py @@ -46,7 +46,7 @@ def _maybe_name(obj): return "" % type(obj) -@tf_export("train.SessionManager") +@tf_export(v1=["train.SessionManager"]) class SessionManager(object): """Training helper that restores from checkpoint and creates session. diff --git a/tensorflow/python/training/supervisor.py b/tensorflow/python/training/supervisor.py index a5e626d320..de60dd456f 100644 --- a/tensorflow/python/training/supervisor.py +++ b/tensorflow/python/training/supervisor.py @@ -40,7 +40,7 @@ from tensorflow.python.util import deprecation from tensorflow.python.util.tf_export import tf_export -@tf_export("train.Supervisor") +@tf_export(v1=["train.Supervisor"]) class Supervisor(object): """A training helper that checkpoints models and computes summaries. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-chief-session-creator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-chief-session-creator.pbtxt deleted file mode 100644 index abbe273be3..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-chief-session-creator.pbtxt +++ /dev/null @@ -1,14 +0,0 @@ -path: "tensorflow.train.ChiefSessionCreator" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member_method { - name: "__init__" - argspec: "args=[\'self\', \'scaffold\', \'master\', \'config\', \'checkpoint_dir\', \'checkpoint_filename_with_path\'], varargs=None, keywords=None, defaults=[\'None\', \'\', \'None\', \'None\', \'None\'], " - } - member_method { - name: "create_session" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.-step-context.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.-step-context.pbtxt deleted file mode 100644 index 03efe6639e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.-step-context.pbtxt +++ /dev/null @@ -1,21 +0,0 @@ -path: "tensorflow.train.MonitoredSession.StepContext" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "session" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'session\', \'run_with_hooks_fn\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "request_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "run_with_hooks" - argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.pbtxt deleted file mode 100644 index 09b7b3fb53..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-monitored-session.pbtxt +++ /dev/null @@ -1,34 +0,0 @@ -path: "tensorflow.train.MonitoredSession" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "StepContext" - mtype: "" - } - member { - name: "graph" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'session_creator\', \'hooks\', \'stop_grace_period_secs\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'120\'], " - } - member_method { - name: "close" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "run" - argspec: "args=[\'self\', \'fetches\', \'feed_dict\', \'options\', \'run_metadata\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " - } - member_method { - name: "run_step_fn" - argspec: "args=[\'self\', \'step_fn\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "should_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-creator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-session-creator.pbtxt deleted file mode 100644 index beb232715f..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-creator.pbtxt +++ /dev/null @@ -1,12 +0,0 @@ -path: "tensorflow.train.SessionCreator" -tf_class { - is_instance: "" - is_instance: "" - member_method { - name: "__init__" - } - member_method { - name: "create_session" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-manager.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-session-manager.pbtxt deleted file mode 100644 index 448764fe08..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-manager.pbtxt +++ /dev/null @@ -1,21 +0,0 @@ -path: "tensorflow.train.SessionManager" -tf_class { - is_instance: "" - is_instance: "" - member_method { - name: "__init__" - argspec: "args=[\'self\', \'local_init_op\', \'ready_op\', \'ready_for_local_init_op\', \'graph\', \'recovery_wait_secs\', \'local_init_run_options\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'30\', \'None\'], " - } - member_method { - name: "prepare_session" - argspec: "args=[\'self\', \'master\', \'init_op\', \'saver\', \'checkpoint_dir\', \'checkpoint_filename_with_path\', \'wait_for_checkpoint\', \'max_wait_secs\', \'config\', \'init_feed_dict\', \'init_fn\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'False\', \'7200\', \'None\', \'None\', \'None\'], " - } - member_method { - name: "recover_session" - argspec: "args=[\'self\', \'master\', \'saver\', \'checkpoint_dir\', \'checkpoint_filename_with_path\', \'wait_for_checkpoint\', \'max_wait_secs\', \'config\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'False\', \'7200\', \'None\'], " - } - member_method { - name: "wait_for_session" - argspec: "args=[\'self\', \'master\', \'config\', \'max_wait_secs\'], varargs=None, keywords=None, defaults=[\'None\', \'inf\'], " - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.-step-context.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.-step-context.pbtxt deleted file mode 100644 index 36d8ce7ff8..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.-step-context.pbtxt +++ /dev/null @@ -1,21 +0,0 @@ -path: "tensorflow.train.SingularMonitoredSession.StepContext" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "session" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'session\', \'run_with_hooks_fn\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "request_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "run_with_hooks" - argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.pbtxt deleted file mode 100644 index de0f2c1c1a..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-singular-monitored-session.pbtxt +++ /dev/null @@ -1,38 +0,0 @@ -path: "tensorflow.train.SingularMonitoredSession" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "StepContext" - mtype: "" - } - member { - name: "graph" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'hooks\', \'scaffold\', \'master\', \'config\', \'checkpoint_dir\', \'stop_grace_period_secs\', \'checkpoint_filename_with_path\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'\', \'None\', \'None\', \'120\', \'None\'], " - } - member_method { - name: "close" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "raw_session" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "run" - argspec: "args=[\'self\', \'fetches\', \'feed_dict\', \'options\', \'run_metadata\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], " - } - member_method { - name: "run_step_fn" - argspec: "args=[\'self\', \'step_fn\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "should_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-supervisor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-supervisor.pbtxt deleted file mode 100644 index 9677e5a98e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-supervisor.pbtxt +++ /dev/null @@ -1,153 +0,0 @@ -path: "tensorflow.train.Supervisor" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "USE_DEFAULT" - mtype: "" - } - member { - name: "coord" - mtype: "" - } - member { - name: "global_step" - mtype: "" - } - member { - name: "init_feed_dict" - mtype: "" - } - member { - name: "init_op" - mtype: "" - } - member { - name: "is_chief" - mtype: "" - } - member { - name: "ready_for_local_init_op" - mtype: "" - } - member { - name: "ready_op" - mtype: "" - } - member { - name: "save_model_secs" - mtype: "" - } - member { - name: "save_path" - mtype: "" - } - member { - name: "save_summaries_secs" - mtype: "" - } - member { - name: "saver" - mtype: "" - } - member { - name: "session_manager" - mtype: "" - } - member { - name: "summary_op" - mtype: "" - } - member { - name: "summary_writer" - mtype: "" - } - member_method { - name: "Loop" - argspec: "args=[\'self\', \'timer_interval_secs\', \'target\', \'args\', \'kwargs\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "PrepareSession" - argspec: "args=[\'self\', \'master\', \'config\', \'wait_for_checkpoint\', \'max_wait_secs\', \'start_standard_services\'], varargs=None, keywords=None, defaults=[\'\', \'None\', \'False\', \'7200\', \'True\'], " - } - member_method { - name: "RequestStop" - argspec: "args=[\'self\', \'ex\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "ShouldStop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "StartQueueRunners" - argspec: "args=[\'self\', \'sess\', \'queue_runners\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "StartStandardServices" - argspec: "args=[\'self\', \'sess\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "Stop" - argspec: "args=[\'self\', \'threads\', \'close_summary_writer\', \'ignore_live_threads\'], varargs=None, keywords=None, defaults=[\'None\', \'True\', \'False\'], " - } - member_method { - name: "StopOnException" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "SummaryComputed" - argspec: "args=[\'self\', \'sess\', \'summary\', \'global_step\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "WaitForStop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'graph\', \'ready_op\', \'ready_for_local_init_op\', \'is_chief\', \'init_op\', \'init_feed_dict\', \'local_init_op\', \'logdir\', \'summary_op\', \'saver\', \'global_step\', \'save_summaries_secs\', \'save_model_secs\', \'recovery_wait_secs\', \'stop_grace_secs\', \'checkpoint_basename\', \'session_manager\', \'summary_writer\', \'init_fn\', \'local_init_run_options\'], varargs=None, keywords=None, defaults=[\'None\', \'0\', \'0\', \'True\', \'0\', \'None\', \'0\', \'None\', \'0\', \'0\', \'0\', \'120\', \'600\', \'30\', \'120\', \'model.ckpt\', \'None\', \'0\', \'None\', \'None\'], " - } - member_method { - name: "loop" - argspec: "args=[\'self\', \'timer_interval_secs\', \'target\', \'args\', \'kwargs\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "managed_session" - argspec: "args=[], varargs=args, keywords=kwds, defaults=None" - } - member_method { - name: "prepare_or_wait_for_session" - argspec: "args=[\'self\', \'master\', \'config\', \'wait_for_checkpoint\', \'max_wait_secs\', \'start_standard_services\'], varargs=None, keywords=None, defaults=[\'\', \'None\', \'False\', \'7200\', \'True\'], " - } - member_method { - name: "request_stop" - argspec: "args=[\'self\', \'ex\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "should_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "start_queue_runners" - argspec: "args=[\'self\', \'sess\', \'queue_runners\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "start_standard_services" - argspec: "args=[\'self\', \'sess\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "stop" - argspec: "args=[\'self\', \'threads\', \'close_summary_writer\', \'ignore_live_threads\'], varargs=None, keywords=None, defaults=[\'None\', \'True\', \'False\'], " - } - member_method { - name: "stop_on_exception" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "summary_computed" - argspec: "args=[\'self\', \'sess\', \'summary\', \'global_step\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "wait_for_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-worker-session-creator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-worker-session-creator.pbtxt deleted file mode 100644 index ac26358068..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-worker-session-creator.pbtxt +++ /dev/null @@ -1,14 +0,0 @@ -path: "tensorflow.train.WorkerSessionCreator" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member_method { - name: "__init__" - argspec: "args=[\'self\', \'scaffold\', \'master\', \'config\', \'max_wait_secs\'], varargs=None, keywords=None, defaults=[\'None\', \'\', \'None\', \'1800\'], " - } - member_method { - name: "create_session" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt index 4a4f387131..a30f67350a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt @@ -20,10 +20,6 @@ tf_module { name: "CheckpointSaverListener" mtype: "" } - member { - name: "ChiefSessionCreator" - mtype: "" - } member { name: "ClusterDef" mtype: "" @@ -88,10 +84,6 @@ tf_module { name: "LoggingTensorHook" mtype: "" } - member { - name: "MonitoredSession" - mtype: "" - } member { name: "NanLossDuringTrainingError" mtype: "" @@ -124,14 +116,6 @@ tf_module { name: "ServerDef" mtype: "" } - member { - name: "SessionCreator" - mtype: "" - } - member { - name: "SessionManager" - mtype: "" - } member { name: "SessionRunArgs" mtype: "" @@ -148,10 +132,6 @@ tf_module { name: "SessionRunValues" mtype: "" } - member { - name: "SingularMonitoredSession" - mtype: "" - } member { name: "StepCounterHook" mtype: "" @@ -164,14 +144,6 @@ tf_module { name: "SummarySaverHook" mtype: "" } - member { - name: "Supervisor" - mtype: "" - } - member { - name: "WorkerSessionCreator" - mtype: "" - } member_method { name: "cosine_decay" argspec: "args=[\'learning_rate\', \'global_step\', \'decay_steps\', \'alpha\', \'name\'], varargs=None, keywords=None, defaults=[\'0.0\', \'None\'], " diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 49c152bb86..042ca8adaa 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -117,7 +117,7 @@ renames = { 'tf.debugging.is_strictly_increasing': 'tf.math.is_strictly_increasing', 'tf.decode_base64': 'tf.io.decode_base64', 'tf.decode_compressed': 'tf.io.decode_compressed', - 'tf.decode_csv': 'tf.io.decode_csv', + 'tf.decode_csv': 'tf.compat.v1.decode_csv', 'tf.decode_json_example': 'tf.io.decode_json_example', 'tf.decode_raw': 'tf.io.decode_raw', 'tf.delete_session_tensor': 'tf.compat.v1.delete_session_tensor', @@ -580,6 +580,8 @@ renames = { 'tf.to_int32': 'tf.compat.v1.to_int32', 'tf.to_int64': 'tf.compat.v1.to_int64', 'tf.trace': 'tf.linalg.trace', + 'tf.train.ChiefSessionCreator': 'tf.compat.v1.train.ChiefSessionCreator', + 'tf.train.MonitoredSession': 'tf.compat.v1.train.MonitoredSession', 'tf.train.LooperThread': 'tf.compat.v1.train.LooperThread', 'tf.train.AdadeltaOptimizer': 'tf.compat.v1.train.AdadeltaOptimizer', 'tf.train.AdagradDAOptimizer': 'tf.compat.v1.train.AdagradDAOptimizer', @@ -597,7 +599,12 @@ renames = { 'tf.train.RMSPropOptimizer': 'tf.compat.v1.train.RMSPropOptimizer', 'tf.train.Saver': 'tf.compat.v1.train.Saver', 'tf.train.SaverDef': 'tf.compat.v1.train.SaverDef', + 'tf.train.SessionCreator': 'tf.compat.v1.train.SessionCreator', + 'tf.train.SessionManager': 'tf.compat.v1.train.SessionManager', + 'tf.train.SingularMonitoredSession': 'tf.compat.v1.train.SingularMonitoredSession', + 'tf.train.Supervisor': 'tf.compat.v1.train.Supervisor', 'tf.train.SyncReplicasOptimizer': 'tf.compat.v1.train.SyncReplicasOptimizer', + 'tf.train.WorkerSessionCreator': 'tf.compat.v1.train.WorkerSessionCreator', 'tf.train.VocabInfo': 'tf.compat.v1.train.VocabInfo', 'tf.train.add_queue_runner': 'tf.compat.v1.train.add_queue_runner', 'tf.train.assert_global_step': 'tf.compat.v1.train.assert_global_step', -- GitLab From 938d66d0f2c1507879174c509382de53f19ea2c9 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 28 Nov 2018 09:09:55 -0800 Subject: [PATCH 453/672] [TF:XLA] Remove unused builder arg from XlaHelpers::ConvertElementType PiperOrigin-RevId: 223178269 --- .../compiler/tf2xla/kernels/batch_norm_op.cc | 15 +++++++-------- tensorflow/compiler/tf2xla/kernels/bias_ops.cc | 4 ++-- .../tf2xla/kernels/fake_quantize_ops.cc | 8 ++++---- tensorflow/compiler/tf2xla/kernels/image_ops.cc | 5 ++--- tensorflow/compiler/tf2xla/kernels/l2loss_op.cc | 5 ++--- tensorflow/compiler/tf2xla/kernels/lrn_ops.cc | 17 ++++++----------- .../tf2xla/kernels/reduction_ops_common.cc | 2 +- tensorflow/compiler/tf2xla/kernels/scan_ops.cc | 7 +++---- .../compiler/tf2xla/kernels/softmax_op.cc | 15 +++++++-------- .../compiler/tf2xla/kernels/training_ops.cc | 3 +-- tensorflow/compiler/tf2xla/xla_helpers.cc | 3 +-- tensorflow/compiler/tf2xla/xla_helpers.h | 3 +-- 12 files changed, 37 insertions(+), 50 deletions(-) diff --git a/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc b/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc index a267c0c72f..0e2f335f33 100644 --- a/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc @@ -115,9 +115,9 @@ class FusedBatchNormGradOp : public XlaOpKernel { // operators. For now, cast everything to the statistics type (which // may be more precise than the input type). auto grad_backprop = - XlaHelpers::ConvertElementType(b, ctx->Input(0), scale_dtype); + XlaHelpers::ConvertElementType(ctx->Input(0), scale_dtype); auto activations = - XlaHelpers::ConvertElementType(b, ctx->Input(1), scale_dtype); + XlaHelpers::ConvertElementType(ctx->Input(1), scale_dtype); auto scale = ctx->Input(2); auto mean = ctx->Input(3); auto var = ctx->Input(4); @@ -151,11 +151,11 @@ class FusedBatchNormGradOp : public XlaOpKernel { const DataType accumulation_type = XlaHelpers::SumAccumulationType(scale_dtype); auto converted = - XlaHelpers::ConvertElementType(b, grad_backprop, accumulation_type); + XlaHelpers::ConvertElementType(grad_backprop, accumulation_type); auto reduce = xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), reduction_dims); - offset_backprop = XlaHelpers::ConvertElementType(b, reduce, scale_dtype); + offset_backprop = XlaHelpers::ConvertElementType(reduce, scale_dtype); // scratch1 = rsqrt(pop_var + epsilon) auto neg_half = XlaHelpers::FloatLiteral(b, scale_dtype, -0.5); @@ -165,19 +165,18 @@ class FusedBatchNormGradOp : public XlaOpKernel { // scratch2 = sum(y_backprop * (x - mean)) auto mul = xla::Mul(grad_backprop, xla::Sub(activations, mean, {feature_index})); - converted = XlaHelpers::ConvertElementType(b, mul, accumulation_type); + converted = XlaHelpers::ConvertElementType(mul, accumulation_type); reduce = xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), reduction_dims); - auto scratch2 = XlaHelpers::ConvertElementType(b, reduce, scale_dtype); + auto scratch2 = XlaHelpers::ConvertElementType(reduce, scale_dtype); x_backprop = xla::Mul(grad_backprop, xla::Mul(scratch1, scale), {feature_index}); scale_backprop = xla::Mul(scratch1, scratch2); } - ctx->SetOutput(0, - XlaHelpers::ConvertElementType(b, x_backprop, input_dtype)); + ctx->SetOutput(0, XlaHelpers::ConvertElementType(x_backprop, input_dtype)); ctx->SetOutput(1, scale_backprop); ctx->SetOutput(2, offset_backprop); ctx->SetConstantOutput(3, Tensor()); diff --git a/tensorflow/compiler/tf2xla/kernels/bias_ops.cc b/tensorflow/compiler/tf2xla/kernels/bias_ops.cc index 41f540506b..e7f369b761 100644 --- a/tensorflow/compiler/tf2xla/kernels/bias_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/bias_ops.cc @@ -107,11 +107,11 @@ class BiasAddGradOp : public XlaOpKernel { const DataType accumulation_type = XlaHelpers::SumAccumulationType(input_type(0)); auto converted = - XlaHelpers::ConvertElementType(b, ctx->Input(0), accumulation_type); + XlaHelpers::ConvertElementType(ctx->Input(0), accumulation_type); auto reduce = xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), reduce_dims); - ctx->SetOutput(0, XlaHelpers::ConvertElementType(b, reduce, input_type(0))); + ctx->SetOutput(0, XlaHelpers::ConvertElementType(reduce, input_type(0))); } private: diff --git a/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc b/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc index cdba6680de..142be030f7 100644 --- a/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc @@ -260,19 +260,19 @@ class FakeQuantWithMinMaxVarsGradOp : public XlaOpKernel { xla::XlaOp below_min = xla::Lt(input, nudged_input_min); xla::XlaOp select1 = xla::Select(below_min, gradient, zeroes); xla::XlaOp reduce1 = xla::ReduceAll( - XlaHelpers::ConvertElementType(b, select1, accumulation_type), + XlaHelpers::ConvertElementType(select1, accumulation_type), XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type)); - xla::XlaOp output1 = XlaHelpers::ConvertElementType(b, reduce1, data_type); + xla::XlaOp output1 = XlaHelpers::ConvertElementType(reduce1, data_type); ctx->SetOutput(1, output1); xla::XlaOp above_max = xla::Gt(input, nudged_input_max); xla::XlaOp select2 = xla::Select(above_max, gradient, zeroes); xla::XlaOp reduce2 = xla::ReduceAll( - XlaHelpers::ConvertElementType(b, select2, accumulation_type), + XlaHelpers::ConvertElementType(select2, accumulation_type), XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type)); - xla::XlaOp output2 = XlaHelpers::ConvertElementType(b, reduce2, data_type); + xla::XlaOp output2 = XlaHelpers::ConvertElementType(reduce2, data_type); ctx->SetOutput(2, output2); } diff --git a/tensorflow/compiler/tf2xla/kernels/image_ops.cc b/tensorflow/compiler/tf2xla/kernels/image_ops.cc index b49b2516d8..e9bb0a77e9 100644 --- a/tensorflow/compiler/tf2xla/kernels/image_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/image_ops.cc @@ -191,12 +191,11 @@ class AdjustContrastOpV2 : public XlaOpKernel { DataType type = context->input_type(0); const DataType accumulation_type = XlaHelpers::SumAccumulationType(type); - auto converted = - XlaHelpers::ConvertElementType(b, input, accumulation_type); + auto converted = XlaHelpers::ConvertElementType(input, accumulation_type); auto reduce = xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type), *context->GetOrCreateAdd(accumulation_type), {height_dim, width_dim}); - auto output = XlaHelpers::ConvertElementType(b, reduce, type); + auto output = XlaHelpers::ConvertElementType(reduce, type); output = xla::Div(output, XlaHelpers::FloatLiteral(b, type, height * width)); diff --git a/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc b/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc index f028e361bc..93f029731c 100644 --- a/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc @@ -37,12 +37,11 @@ class L2LossOp : public XlaOpKernel { // output = sum(t ** 2) / 2 const DataType accumulation_type = XlaHelpers::SumAccumulationType(dtype); - auto t = - XlaHelpers::ConvertElementType(b, ctx->Input(0), accumulation_type); + auto t = XlaHelpers::ConvertElementType(ctx->Input(0), accumulation_type); auto square = xla::Mul(t, t); auto reduce = xla::Reduce(square, XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), dims); - auto deconverted = XlaHelpers::ConvertElementType(b, reduce, dtype); + auto deconverted = XlaHelpers::ConvertElementType(reduce, dtype); auto two = XlaHelpers::IntegerLiteral(b, dtype, 2); ctx->SetOutput(0, xla::Div(deconverted, two)); } diff --git a/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc b/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc index 87ee2d3aed..987901d82b 100644 --- a/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc @@ -49,16 +49,14 @@ class LRNOp : public XlaOpKernel { // We use a window of depth_radius_ * 2 + 1, to account for the current // element and a depth_radius_ on either side. auto accumulation_type = XlaHelpers::SumAccumulationType(input_type(0)); - auto converted = - XlaHelpers::ConvertElementType(builder, input, accumulation_type); + auto converted = XlaHelpers::ConvertElementType(input, accumulation_type); auto squared = xla::Mul(converted, converted); auto reduce = xla::ReduceWindow( squared, XlaHelpers::Zero(builder, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), /* window_dimensions = */ {1, 1, 1, depth_radius_ * 2 + 1}, /* window_strides = */ {1, 1, 1, 1}, xla::Padding::kSame); - auto sqr_sum = - XlaHelpers::ConvertElementType(builder, reduce, input_type(0)); + auto sqr_sum = XlaHelpers::ConvertElementType(reduce, input_type(0)); auto scale = xla::Pow( xla::Add(xla::ConstantR0(builder, bias_), @@ -138,15 +136,14 @@ class LRNGradOp : public XlaOpKernel { auto accumulation_type = XlaHelpers::SumAccumulationType(input_type(0)); auto converted = - XlaHelpers::ConvertElementType(builder, in_image, accumulation_type); + XlaHelpers::ConvertElementType(in_image, accumulation_type); auto squared = xla::Mul(converted, converted); auto reduce = xla::ReduceWindow( squared, XlaHelpers::Zero(builder, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), /* window_dimensions = */ {1, 1, 1, depth_radius_ * 2 + 1}, /* window_strides = */ {1, 1, 1, 1}, xla::Padding::kSame); - auto sqr_sum = - XlaHelpers::ConvertElementType(builder, reduce, input_type(0)); + auto sqr_sum = XlaHelpers::ConvertElementType(reduce, input_type(0)); auto norm = xla::Add(xla::ConstantR0(builder, bias_), @@ -157,15 +154,13 @@ class LRNGradOp : public XlaOpKernel { xla::Div(out_image, norm)), in_grads); - auto converted_dy = - XlaHelpers::ConvertElementType(builder, dy, accumulation_type); + auto converted_dy = XlaHelpers::ConvertElementType(dy, accumulation_type); auto dy_reduce = xla::ReduceWindow( converted_dy, XlaHelpers::Zero(builder, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), /* window_dimensions = */ {1, 1, 1, depth_radius_ * 2 + 1}, /* window_strides = */ {1, 1, 1, 1}, xla::Padding::kSame); - auto dy_reduced = - XlaHelpers::ConvertElementType(builder, dy_reduce, input_type(0)); + auto dy_reduced = XlaHelpers::ConvertElementType(dy_reduce, input_type(0)); xla::XlaOp gradients = xla::Add( xla::Mul(in_image, dy_reduced), diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc b/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc index e96cabbb85..b9bb5edba3 100644 --- a/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc +++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc @@ -117,7 +117,7 @@ void XlaReductionOp::Compile(XlaOpKernelContext* ctx) { xla::XlaComputation reduction_computation = r.Build().ConsumeValueOrDie(); auto reduce = xla::Reduce(data, initial, reduction_computation, xla_axes); - auto deconverted = XlaHelpers::ConvertElementType(b, reduce, input_type(0)); + auto deconverted = XlaHelpers::ConvertElementType(reduce, input_type(0)); auto finalized = BuildFinalizer(b, data, deconverted, xla_axes); auto result = keep_dims_ ? xla::Reshape(finalized, final_shape) : finalized; ctx->SetOutput(0, result); diff --git a/tensorflow/compiler/tf2xla/kernels/scan_ops.cc b/tensorflow/compiler/tf2xla/kernels/scan_ops.cc index 7f4fef146f..4b9e1a578b 100644 --- a/tensorflow/compiler/tf2xla/kernels/scan_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/scan_ops.cc @@ -103,11 +103,10 @@ class ScanOp : public XlaOpKernel { reducer = ctx->GetOrCreateMul(dtype); } auto output = xla::ReduceWindowWithGeneralPadding( - XlaHelpers::ConvertElementType(builder, ctx->Input(0), dtype), init, - *reducer, window_dims, window_strides, + XlaHelpers::ConvertElementType(ctx->Input(0), dtype), init, *reducer, + window_dims, window_strides, /*base_dilations=*/{}, /*window_dilations=*/{}, padding); - output = - XlaHelpers::ConvertElementType(builder, output, ctx->input_type(0)); + output = XlaHelpers::ConvertElementType(output, ctx->input_type(0)); // In exclusive mode, we have computed an extra element containing the sum // of all the input elements. Slice off this extra "last" element. diff --git a/tensorflow/compiler/tf2xla/kernels/softmax_op.cc b/tensorflow/compiler/tf2xla/kernels/softmax_op.cc index d6bd927135..20da803353 100644 --- a/tensorflow/compiler/tf2xla/kernels/softmax_op.cc +++ b/tensorflow/compiler/tf2xla/kernels/softmax_op.cc @@ -71,7 +71,7 @@ class SoftmaxOp : public XlaOpKernel { auto reduce = xla::Reduce(converted, xla::Zero(b, xla_accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), {kClassDim}); - auto sum = XlaHelpers::ConvertElementType(b, reduce, type); + auto sum = XlaHelpers::ConvertElementType(reduce, type); auto softmax = log_ // softmax = shifted_logits - log(sum(exp(shifted_logits))) @@ -111,11 +111,11 @@ std::pair CrossEntropyWithLogits( // sum_{class} (exp(logits - max_logits)) const DataType accumulation_type = XlaHelpers::SumAccumulationType(type); auto converted = - XlaHelpers::ConvertElementType(b, exp_shifted_logits, accumulation_type); + XlaHelpers::ConvertElementType(exp_shifted_logits, accumulation_type); auto reduce = xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type), *ctx->GetOrCreateAdd(accumulation_type), {kClassDim}); - auto sum_exp = XlaHelpers::ConvertElementType(b, reduce, type); + auto sum_exp = XlaHelpers::ConvertElementType(reduce, type); // log(sum(exp(logits - max_logits))) auto log_sum_exp = xla::Log(sum_exp); @@ -126,11 +126,10 @@ std::pair CrossEntropyWithLogits( // (The subtraction broadcasts along the batch dimension.) auto sub = xla::Sub(shifted_logits, log_sum_exp, {kBatchDim}); auto mul = xla::Mul(xla::Neg(labels), sub); - auto sum = - xla::Reduce(XlaHelpers::ConvertElementType(b, mul, accumulation_type), - XlaHelpers::Zero(b, accumulation_type), - *ctx->GetOrCreateAdd(accumulation_type), {kClassDim}); - auto loss = XlaHelpers::ConvertElementType(b, sum, type); + auto sum = xla::Reduce(XlaHelpers::ConvertElementType(mul, accumulation_type), + XlaHelpers::Zero(b, accumulation_type), + *ctx->GetOrCreateAdd(accumulation_type), {kClassDim}); + auto loss = XlaHelpers::ConvertElementType(sum, type); // backprop: prob - labels, where // prob = exp(logits - max_logits) / sum(exp(logits - max_logits)) diff --git a/tensorflow/compiler/tf2xla/kernels/training_ops.cc b/tensorflow/compiler/tf2xla/kernels/training_ops.cc index 7077c2e3a5..960c1462ce 100644 --- a/tensorflow/compiler/tf2xla/kernels/training_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/training_ops.cc @@ -320,9 +320,8 @@ class ResourceApplyAdagradDA : public XlaOpKernel { xla::XlaOp lr = ctx->Input(4); xla::XlaOp l1 = ctx->Input(5); xla::XlaOp l2 = ctx->Input(6); - xla::XlaBuilder* const b = ctx->builder(); xla::XlaOp global_step = - XlaHelpers::ConvertElementType(b, ctx->Input(7), dtype_); + XlaHelpers::ConvertElementType(ctx->Input(7), dtype_); accum = accum + grad; squared_accum = squared_accum + xla::Square(grad); diff --git a/tensorflow/compiler/tf2xla/xla_helpers.cc b/tensorflow/compiler/tf2xla/xla_helpers.cc index af378bc95c..c2c0751211 100644 --- a/tensorflow/compiler/tf2xla/xla_helpers.cc +++ b/tensorflow/compiler/tf2xla/xla_helpers.cc @@ -215,8 +215,7 @@ DataType XlaHelpers::SumAccumulationType(const DataType& dtype) { return dtype; } -xla::XlaOp XlaHelpers::ConvertElementType(xla::XlaBuilder* const builder, - const xla::XlaOp& operand, +xla::XlaOp XlaHelpers::ConvertElementType(const xla::XlaOp& operand, const DataType new_element_type) { xla::PrimitiveType convert_to; TF_CHECK_OK(DataTypeToPrimitiveType(new_element_type, &convert_to)); diff --git a/tensorflow/compiler/tf2xla/xla_helpers.h b/tensorflow/compiler/tf2xla/xla_helpers.h index 39578144ca..4858dfee55 100644 --- a/tensorflow/compiler/tf2xla/xla_helpers.h +++ b/tensorflow/compiler/tf2xla/xla_helpers.h @@ -80,8 +80,7 @@ class XlaHelpers { // A helper for creating a ConvertElementType xla op given a DataType rather // than the xla::PrimitiveType. - static xla::XlaOp ConvertElementType(xla::XlaBuilder* const builder, - const xla::XlaOp& operand, + static xla::XlaOp ConvertElementType(const xla::XlaOp& operand, const DataType new_element_type); }; -- GitLab From ebbf59ebc154a0dea65cda4a8ef56416189b43fb Mon Sep 17 00:00:00 2001 From: Tamara Norman Date: Wed, 28 Nov 2018 09:11:50 -0800 Subject: [PATCH 454/672] Remove methods from tf.Variable which in RefVariable are to be deprecated and aren't supported in Resource Variable PiperOrigin-RevId: 223178585 --- tensorflow/python/ops/variables.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index f72b19bcdd..4824c92a5a 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -1055,27 +1055,6 @@ class Variable(six.with_metaclass(VariableMetaclass, else: return None - def __iadd__(self, other): - raise NotImplementedError - - def __isub__(self, other): - raise NotImplementedError - - def __imul__(self, other): - raise NotImplementedError - - def __idiv__(self, other): - raise NotImplementedError - - def __itruediv__(self, other): - raise NotImplementedError - - def __irealdiv__(self, other): - raise NotImplementedError - - def __ipow__(self, other): - raise NotImplementedError - @tf_export(v1=["Variable"]) class VariableV1(Variable): -- GitLab From 01605a8038a70f6622867a0b7bffec61d6e49201 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Wed, 28 Nov 2018 09:32:10 -0800 Subject: [PATCH 455/672] Make tf.constant not take verify_shape in v2 and limit allowed forms. tf.constant([], shape=[3]) no longer allowed tf.constant(0, shape=[3]) still allowed tf.constant([1,2], shape=[1,1,2]) is still ok. This makes eager and non-eager constants more consistent. PiperOrigin-RevId: 223182163 --- .../batch/categorical_split_handler.py | 2 +- .../batch/categorical_split_handler_test.py | 8 +- .../learner/batch/ordinal_split_handler.py | 12 +-- .../batch/ordinal_split_handler_test.py | 13 +-- .../python/training/functions/gbdt_batch.py | 4 +- tensorflow/python/framework/constant_op.py | 81 ++++++++++++++++++- tensorflow/python/framework/tensor_util.py | 28 +++++-- .../python/kernel_tests/constant_op_test.py | 22 +++-- tensorflow/python/ops/init_ops.py | 2 +- .../python/ops/ragged/ragged_const_op_test.py | 4 +- .../tools/api/golden/v1/tensorflow.pbtxt | 2 +- .../tools/api/golden/v2/tensorflow.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 3 + 13 files changed, 144 insertions(+), 39 deletions(-) diff --git a/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler.py b/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler.py index 4da25298cb..d26af58419 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler.py +++ b/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler.py @@ -119,7 +119,7 @@ class EqualitySplitHandler(base_split_handler.BaseSplitHandler): def not_active_inputs(): return (constant_op.constant([], dtype=dtypes.int32), - constant_op.constant([], dtype=dtypes.int64, shape=[1, 2]), + constant_op.constant_v1([], dtype=dtypes.int64, shape=[1, 2]), empty_gradients, empty_hessians) def active_inputs(): diff --git a/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler_test.py b/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler_test.py index a2f708081a..386dc19fc7 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler_test.py +++ b/tensorflow/contrib/boosted_trees/lib/learner/batch/categorical_split_handler_test.py @@ -36,9 +36,9 @@ def get_empty_tensors(gradient_shape, hessian_shape): empty_hess_shape = [1] + hessian_shape.as_list() empty_grad_shape = [1] + gradient_shape.as_list() - empty_gradients = constant_op.constant( + empty_gradients = constant_op.constant_v1( [], dtype=dtypes.float32, shape=empty_grad_shape) - empty_hessians = constant_op.constant( + empty_hessians = constant_op.constant_v1( [], dtype=dtypes.float32, shape=empty_hess_shape) return empty_gradients, empty_hessians @@ -486,8 +486,8 @@ class EqualitySplitHandlerTest(test_util.TensorFlowTestCase): gradients = array_ops.constant([0.2, -0.5, 1.2, 4.0]) hessians = array_ops.constant([0.12, 0.07, 0.2, 0.13]) partition_ids = [0, 0, 0, 1] - indices = array_ops.constant([], dtype=dtypes.int64, shape=[0, 2]) - values = array_ops.constant([], dtype=dtypes.int64) + indices = constant_op.constant_v1([], dtype=dtypes.int64, shape=[0, 2]) + values = constant_op.constant_v1([], dtype=dtypes.int64) gradient_shape = tensor_shape.scalar() hessian_shape = tensor_shape.scalar() diff --git a/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler.py b/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler.py index 1fffbb5f66..0476bed2cd 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler.py +++ b/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler.py @@ -605,7 +605,7 @@ def dense_make_stats_update(is_active, are_buckets_ready, float_column, quantile_buckets, example_partition_ids, gradients, hessians, weights, empty_gradients, empty_hessians): """Updates the state for dense split handler.""" - empty_float = constant_op.constant([], dtype=dtypes.float32) + empty_float = constant_op.constant_v1([], dtype=dtypes.float32) quantile_values, quantile_weights = control_flow_ops.cond( is_active[1], # For the next layer, this handler is inactive. @@ -621,8 +621,8 @@ def dense_make_stats_update(is_active, are_buckets_ready, float_column, return (example_partition_ids, quantized_feature, gradients, hessians) def not_ready_inputs_fn(): - return (constant_op.constant([], dtype=dtypes.int32), - constant_op.constant([[]], dtype=dtypes.int64, shape=[1, 2]), + return (constant_op.constant_v1([], dtype=dtypes.int32), + constant_op.constant_v1([[]], dtype=dtypes.int64, shape=[1, 2]), empty_gradients, empty_hessians) example_partition_ids, feature_ids, gradients, hessians = ( @@ -708,11 +708,11 @@ def sparse_make_stats_update( def quantiles_not_ready(): """The subgraph for when the quantiles are not ready.""" - return (constant_op.constant([], dtype=dtypes.int32), - constant_op.constant([], dtype=dtypes.int64, shape=[1, 2]), + return (constant_op.constant_v1([], dtype=dtypes.int32), + constant_op.constant_v1([], dtype=dtypes.int64, shape=[1, 2]), empty_gradients, empty_hessians) - empty_float = constant_op.constant([], dtype=dtypes.float32) + empty_float = constant_op.constant_v1([], dtype=dtypes.float32) handler_not_active = (constant_op.constant( [], dtype=dtypes.int64, shape=[0, 2]), empty_float, constant_op.constant([0, 1], dtype=dtypes.int64), diff --git a/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler_test.py b/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler_test.py index 74b0ea6989..4a1b528646 100644 --- a/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler_test.py +++ b/tensorflow/contrib/boosted_trees/lib/learner/batch/ordinal_split_handler_test.py @@ -39,9 +39,9 @@ def get_empty_tensors(gradient_shape, hessian_shape): empty_hess_shape = [1] + hessian_shape.as_list() empty_grad_shape = [1] + gradient_shape.as_list() - empty_gradients = constant_op.constant( + empty_gradients = constant_op.constant_v1( [], dtype=dtypes.float32, shape=empty_grad_shape) - empty_hessians = constant_op.constant( + empty_hessians = constant_op.constant_v1( [], dtype=dtypes.float32, shape=empty_hess_shape) return empty_gradients, empty_hessians @@ -1476,9 +1476,9 @@ class SparseSplitHandlerTest(test_util.TensorFlowTestCase): def testEmpty(self): with self.cached_session() as sess: - indices = array_ops.constant([], dtype=dtypes.int64, shape=[0, 2]) + indices = constant_op.constant_v1([], dtype=dtypes.int64, shape=[0, 2]) # No values in this feature column in this mini-batch. - values = array_ops.constant([], dtype=dtypes.float32) + values = constant_op.constant_v1([], dtype=dtypes.float32) sparse_column = sparse_tensor.SparseTensor(indices, values, [4, 1]) gradient_shape = tensor_shape.scalar() @@ -1549,8 +1549,9 @@ class SparseSplitHandlerTest(test_util.TensorFlowTestCase): sparse_column = array_ops.sparse_placeholder(dtypes.float32) # We have two batches - at first, a sparse feature is empty. - empty_indices = array_ops.constant([], dtype=dtypes.int64, shape=[0, 2]) - empty_values = array_ops.constant([], dtype=dtypes.float32) + empty_indices = constant_op.constant_v1([], dtype=dtypes.int64, + shape=[0, 2]) + empty_values = constant_op.constant_v1([], dtype=dtypes.float32) empty_sparse_column = sparse_tensor.SparseTensor(empty_indices, empty_values, [4, 2]) empty_sparse_column = empty_sparse_column.eval(session=sess) diff --git a/tensorflow/contrib/boosted_trees/python/training/functions/gbdt_batch.py b/tensorflow/contrib/boosted_trees/python/training/functions/gbdt_batch.py index 85020c5df2..9fdc2fc0c2 100644 --- a/tensorflow/contrib/boosted_trees/python/training/functions/gbdt_batch.py +++ b/tensorflow/contrib/boosted_trees/python/training/functions/gbdt_batch.py @@ -897,9 +897,9 @@ class GradientBoostedDecisionTreeModel(object): empty_hess_shape = [1] + self._hessian_shape.as_list() empty_grad_shape = [1] + self._gradient_shape.as_list() - empty_gradients = constant_op.constant( + empty_gradients = constant_op.constant_v1( [], dtype=dtypes.float32, shape=empty_grad_shape) - empty_hessians = constant_op.constant( + empty_hessians = constant_op.constant_v1( [], dtype=dtypes.float32, shape=empty_hess_shape) active_handlers = array_ops.unstack(active_handlers, axis=0) diff --git a/tensorflow/python/framework/constant_op.py b/tensorflow/python/framework/constant_op.py index 53d84b2dc7..ade0797dcd 100644 --- a/tensorflow/python/framework/constant_op.py +++ b/tensorflow/python/framework/constant_op.py @@ -114,8 +114,9 @@ def convert_to_eager_tensor(value, ctx, dtype=None): return ops.EagerTensor(value, handle, device, dtype) -@tf_export("constant") -def constant(value, dtype=None, shape=None, name="Const", verify_shape=False): +@tf_export(v1=["constant"]) +def constant_v1( + value, dtype=None, shape=None, name="Const", verify_shape=False): """Creates a constant tensor. The resulting tensor is populated with values of type `dtype`, as @@ -174,6 +175,79 @@ def constant(value, dtype=None, shape=None, name="Const", verify_shape=False): Raises: TypeError: if shape is incorrectly specified or unsupported. """ + return _constant_impl(value, dtype, shape, name, verify_shape=verify_shape, + allow_broadcast=False) + + +@tf_export("constant", v1=[]) +def constant(value, dtype=None, shape=None, name="Const"): + """Creates a constant tensor. + + The resulting tensor is populated with values of type `dtype`, as + specified by arguments `value` and (optionally) `shape` (see examples + below). + + The argument `value` can be a constant value, or a list of values of type + `dtype`. If `value` is a list, then the length of the list must be less + than or equal to the number of elements implied by the `shape` argument (if + specified). In the case where the list length is less than the number of + elements specified by `shape`, the last element in the list will be used + to fill the remaining entries. + + The argument `shape` is optional. If present, it specifies the dimensions of + the resulting tensor. If not present, the shape of `value` is used. + + If the argument `dtype` is not specified, then the type is inferred from + the type of `value`. + + For example: + + ```python + # Constant 1-D Tensor populated with value list. + tensor = tf.constant([1, 2, 3, 4, 5, 6]) => [1 2 3 4 5 6] + + # Constant 1-D Tensor populated with value list. + tensor = tf.constant([1, 2, 3, 4, 5, 6], shape=(2,3)) + => [[1 2 3], [4 5 6]] + + # Constant 2-D tensor populated with scalar value -1. + tensor = tf.constant(-1.0, shape=[2, 3]) => [[-1. -1. -1.] + [-1. -1. -1.]] + ``` + + `tf.constant` differs from `tf.fill` in a few ways: + + * `tf.constant` supports arbitrary constants, not just uniform scalar + Tensors like `tf.fill`. + * `tf.constant` creates a `Const` node in the computation graph with the + exact value at graph construction time. On the other hand, `tf.fill` + creates an Op in the graph that is expanded at runtime. + * Because `tf.constant` only embeds constant values in the graph, it does + not support dynamic shapes based on other runtime Tensors, whereas + `tf.fill` does. + + Args: + value: A constant value (or list) of output type `dtype`. + + dtype: The type of the elements of the resulting tensor. + + shape: Optional dimensions of resulting tensor. + + name: Optional name for the tensor. + + Returns: + A Constant Tensor. + + Raises: + TypeError: if shape is incorrectly specified or unsupported. + """ + return _constant_impl(value, dtype, shape, name, verify_shape=False, + allow_broadcast=True) + + +def _constant_impl( + value, dtype, shape, name, verify_shape, allow_broadcast): + """Implementation of constant.""" ctx = context.context() if ctx.executing_eagerly(): t = convert_to_eager_tensor(value, ctx, dtype) @@ -205,7 +279,8 @@ def constant(value, dtype=None, shape=None, name="Const", verify_shape=False): tensor_value = attr_value_pb2.AttrValue() tensor_value.tensor.CopyFrom( tensor_util.make_tensor_proto( - value, dtype=dtype, shape=shape, verify_shape=verify_shape)) + value, dtype=dtype, shape=shape, verify_shape=verify_shape, + allow_broadcast=allow_broadcast)) dtype_value = attr_value_pb2.AttrValue(type=tensor_value.tensor.dtype) const_tensor = g.create_op( "Const", [], [dtype_value.type], diff --git a/tensorflow/python/framework/tensor_util.py b/tensorflow/python/framework/tensor_util.py index 9db94f5288..f98f301b38 100644 --- a/tensorflow/python/framework/tensor_util.py +++ b/tensorflow/python/framework/tensor_util.py @@ -371,8 +371,10 @@ def _AssertCompatible(values, dtype): (dtype.name, repr(mismatch), type(mismatch).__name__)) +# pylint: disable=invalid-name @tf_export(v1=["make_tensor_proto"]) -def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): +def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False, + allow_broadcast=False): """Create a TensorProto. Args: @@ -380,6 +382,8 @@ def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): dtype: Optional tensor_pb2 DataType value. shape: List of integers representing the dimensions of tensor. verify_shape: Boolean that enables verification of a shape of values. + allow_broadcast:Boolean that enables allowing scalars and 1 length vector + broadcasting. Cannot be true when verify_shape is true. Returns: A `TensorProto`. Depending on the type, it may contain data in the @@ -416,6 +420,8 @@ def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): can not have more elements than what "shape" specifies. """ + if allow_broadcast and verify_shape: + raise ValueError("allow_broadcast and verify_shape are not both allowed.") if isinstance(values, tensor_pb2.TensorProto): return values @@ -504,15 +510,22 @@ def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): shape_size = np.prod(shape, dtype=np.int64) is_same_size = shape_size == nparray.size - if verify_shape: - if not nparray.shape == tuple(shape): + if allow_broadcast: + if nparray.shape == (1,) or nparray.shape == tuple(): + pass + elif nparray.size != shape_size: raise TypeError("Expected Tensor's shape: %s, got %s." % (tuple(shape), nparray.shape)) - if nparray.size > shape_size: - raise ValueError( - "Too many elements provided. Needed at most %d, but received %d" % - (shape_size, nparray.size)) + else: + if verify_shape and nparray.shape != tuple(shape): + raise TypeError("Expected Tensor's shape: %s, got %s." % + (tuple(shape), nparray.shape)) + + if nparray.size > shape_size: + raise ValueError( + "Too many elements provided. Needed at most %d, but received %d" % + (shape_size, nparray.size)) tensor_proto = tensor_pb2.TensorProto( dtype=numpy_dtype.as_datatype_enum, @@ -560,6 +573,7 @@ def make_tensor_proto(values, dtype=None, shape=None, verify_shape=False): append_fn(tensor_proto, proto_values) return tensor_proto +# pylint: enable=invalid-name @tf_export("make_ndarray") diff --git a/tensorflow/python/kernel_tests/constant_op_test.py b/tensorflow/python/kernel_tests/constant_op_test.py index 112e201c88..9c3c96bd31 100644 --- a/tensorflow/python/kernel_tests/constant_op_test.py +++ b/tensorflow/python/kernel_tests/constant_op_test.py @@ -219,16 +219,28 @@ class ConstantTest(test.TestCase): def testShapeInconsistent(self): with ops.Graph().as_default(): - c = constant_op.constant([1, 2, 3, 4, 5, 6, 7], shape=[10]) + c = constant_op.constant_v1([1, 2, 3, 4, 5, 6, 7], shape=[10]) + self.assertEqual(c.get_shape(), [10]) + + with ops.Graph().as_default(): + with self.assertRaisesRegexp( + TypeError, "Expected Tensor's shape"): + c = constant_op.constant([1, 2, 3, 4, 5, 6, 7], shape=[10]) + + def testPromotionShapes(self): + with ops.Graph().as_default(): + c = constant_op.constant([7], shape=[10]) + self.assertEqual(c.get_shape(), [10]) + with ops.Graph().as_default(): + c = constant_op.constant(3, shape=[10]) self.assertEqual(c.get_shape(), [10]) # pylint: disable=g-long-lambda def testShapeWrong(self): with ops.Graph().as_default(): - with self.assertRaisesWithPredicateMatch( - ValueError, - lambda e: ("Too many elements provided. Needed at most 5, " - "but received 7" == str(e))): + with self.assertRaisesRegexp(ValueError, "Too many elements provided."): + constant_op.constant_v1([1, 2, 3, 4, 5, 6, 7], shape=[5]) + with self.assertRaisesRegexp(TypeError, "Expected Tensor's shape"): constant_op.constant([1, 2, 3, 4, 5, 6, 7], shape=[5]) # pylint: enable=g-long-lambda diff --git a/tensorflow/python/ops/init_ops.py b/tensorflow/python/ops/init_ops.py index fe54134af2..03d2201a9a 100644 --- a/tensorflow/python/ops/init_ops.py +++ b/tensorflow/python/ops/init_ops.py @@ -216,7 +216,7 @@ class Constant(Initializer): dtype = self.dtype if verify_shape is None: verify_shape = self._verify_shape - return constant_op.constant( + return constant_op.constant_v1( self.value, dtype=dtype, shape=shape, verify_shape=verify_shape) def get_config(self): diff --git a/tensorflow/python/ops/ragged/ragged_const_op_test.py b/tensorflow/python/ops/ragged/ragged_const_op_test.py index 66c39475fa..9c3b2ac88a 100644 --- a/tensorflow/python/ops/ragged/ragged_const_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_const_op_test.py @@ -238,8 +238,8 @@ class RaggedConstOpTest(test_util.TensorFlowTestCase, parameterized.TestCase): dict( pylist=[1, 2, 3], inner_shape=(1, 1), - exception=ValueError, - message='Too many elements provided.'), + exception=TypeError, + message='Expected Tensor\'s shape'), dict( pylist=[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], inner_shape=(2, 2), diff --git a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt index 656a52945c..a294e3e027 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt @@ -1482,7 +1482,7 @@ tf_module { } member_method { name: "make_tensor_proto" - argspec: "args=[\'values\', \'dtype\', \'shape\', \'verify_shape\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'False\'], " + argspec: "args=[\'values\', \'dtype\', \'shape\', \'verify_shape\', \'allow_broadcast\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'False\', \'False\'], " } member_method { name: "map_fn" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index a48095eb91..0659900ffa 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -558,7 +558,7 @@ tf_module { } member_method { name: "constant" - argspec: "args=[\'value\', \'dtype\', \'shape\', \'name\', \'verify_shape\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'Const\', \'False\'], " + argspec: "args=[\'value\', \'dtype\', \'shape\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'Const\'], " } member_method { name: "control_dependencies" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 059d2ef4de..3cb78afb32 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -52,6 +52,9 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.batch_to_space_nd": { "block_size": "block_shape", }, + "tf.constant": { + "verify_shapes": "verify_shapes_is_now_always_true", + }, "tf.convert_to_tensor": { "preferred_dtype": "dtype_hint" }, -- GitLab From 2948200bbb991cec64653725fd8f990fa015f603 Mon Sep 17 00:00:00 2001 From: Tamara Norman Date: Wed, 28 Nov 2018 09:40:31 -0800 Subject: [PATCH 456/672] Alter documentation for convert_to_tensor, adding additional error thrown and removing on the internal method. PiperOrigin-RevId: 223183729 --- tensorflow/python/framework/ops.py | 49 +++++------------------------- 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 31fa111b3f..5a8a2a48ab 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -1036,12 +1036,12 @@ def convert_to_tensor(value, dtype=None, name=None, preferred_dtype=None): `preferred_dtype` is not possible, this argument has no effect. Returns: - An `Output` based on `value`. + An `Tensor` based on `value`. Raises: - TypeError: If no conversion function is registered for `value`. + TypeError: If no conversion function is registered for `value` to `dtype`. RuntimeError: If a registered conversion function returns an invalid value. - + ValueError: If the `value` is a tensor not of given `dtype` in graph mode. """ return convert_to_tensor_v2(value, dtype, preferred_dtype, name) @@ -1089,12 +1089,12 @@ def convert_to_tensor_v2(value, dtype=None, dtype_hint=None, name=None): name: Optional name to use if a new `Tensor` is created. Returns: - An `Output` based on `value`. + An `Tensor` based on `value`. Raises: - TypeError: If no conversion function is registered for `value`. + TypeError: If no conversion function is registered for `value` to `dtype`. RuntimeError: If a registered conversion function returns an invalid value. - + ValueError: If the `value` is a tensor not of given `dtype` in graph mode. """ return internal_convert_to_tensor( value=value, @@ -1115,42 +1115,7 @@ def internal_convert_to_tensor(value, preferred_dtype=None, ctx=None, accept_symbolic_tensors=True): - """Converts the given `value` to an `Tensor`. - - This function converts Python objects of various types to `Tensor` - objects. It accepts `Tensor` objects, numpy arrays, Python lists, - and Python scalars. For example: - - This function can be useful when composing a new operation in Python - All standard Python op constructors apply this function to each of their - Tensor-valued inputs, which allows those ops to accept numpy arrays, Python - lists, and scalars in addition to `Tensor` objects. - - Args: - value: An object whose type has a registered `Tensor` conversion function. - dtype: Optional element type for the returned tensor. If missing, the - type is inferred from the type of `value`. - name: Optional name to use if a new `Tensor` is created. - as_ref: True if we want the mutable view of Variables, if applicable. - preferred_dtype: Optional element type for the returned tensor, - used when dtype is None. In some cases, a caller may not have a - dtype in mind when converting to a tensor, so preferred_dtype - can be used as a soft preference. If the conversion to - `preferred_dtype` is not possible, this argument has no effect. - ctx: Optional: The value of context.context(). - accept_symbolic_tensors: Whether Keras graph tensors should be accepted as - a valid tensor type during eager execution. - If False, this function will raise an exception if it is passed such - a tensor during eager eager execution. - - Returns: - A `Tensor` based on `value`. - - Raises: - TypeError: If no conversion function is registered for `value`. - RuntimeError: If a registered conversion function returns an invalid value. - - """ + """Implementation of the public convert_to_tensor.""" if ctx is None: ctx = context.context() if isinstance(value, EagerTensor): if ctx.executing_eagerly(): -- GitLab From b6f9a085569d30788443b036ff846dcfc79a4522 Mon Sep 17 00:00:00 2001 From: Brennan Saeta Date: Wed, 28 Nov 2018 09:42:33 -0800 Subject: [PATCH 457/672] [Eager]: Cleanup: Simplify code style. This is a by-product of the DeviceMgr refactor. PiperOrigin-RevId: 223184130 --- tensorflow/core/distributed_runtime/eager/BUILD | 1 + .../core/distributed_runtime/eager/eager_service_impl.cc | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tensorflow/core/distributed_runtime/eager/BUILD b/tensorflow/core/distributed_runtime/eager/BUILD index 055e5dfced..55b2657e74 100644 --- a/tensorflow/core/distributed_runtime/eager/BUILD +++ b/tensorflow/core/distributed_runtime/eager/BUILD @@ -69,6 +69,7 @@ cc_library( "//tensorflow/core/distributed_runtime:worker_env", "//tensorflow/core/distributed_runtime/eager:remote_tensor_handle", "//tensorflow/core/distributed_runtime/rpc:rpc_rendezvous_mgr", + "@com_google_absl//absl/memory", ], ) diff --git a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc index c66466c0a6..13c959d850 100644 --- a/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc +++ b/tensorflow/core/distributed_runtime/eager/eager_service_impl.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/distributed_runtime/eager/eager_service_impl.h" +#include "absl/memory/memory.h" #include "tensorflow/c/c_api_internal.h" #include "tensorflow/c/tf_status_helper.h" #include "tensorflow/core/common_runtime/device_mgr.h" @@ -101,8 +102,8 @@ Status EagerServiceImpl::CreateContext(const CreateContextRequest* request, *response->add_device_attributes() = d->attributes(); } - std::unique_ptr device_mgr( - new tensorflow::DeviceMgr(std::move(devices))); + std::unique_ptr device_mgr = + absl::make_unique(std::move(devices)); auto* r = env_->rendezvous_mgr->Find(request->rendezvous_id()); auto session_name = strings::StrCat("eager_", request->rendezvous_id()); -- GitLab From 14979f572d0b310c606607b15a22146f2b7bd685 Mon Sep 17 00:00:00 2001 From: Allen Lavoie Date: Wed, 28 Nov 2018 09:45:51 -0800 Subject: [PATCH 458/672] Fixes for relative paths when saving weights Fixes a minor incompatibility in POSIX file handling where CreateDir on a blank directory would throw NotFound rather than AlreadyExists. When passed a directory path rather than a prefix, saving creates the directory rather than throwing NotFound. PiperOrigin-RevId: 223184690 --- .../core/platform/posix/posix_file_system.cc | 11 ++-- tensorflow/python/keras/engine/saving_test.py | 53 +++++++++++++++++++ tensorflow/python/kernel_tests/BUILD | 1 + .../kernel_tests/save_restore_ops_test.py | 16 ++++++ .../python/training/checkpointable/util.py | 2 + 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/platform/posix/posix_file_system.cc b/tensorflow/core/platform/posix/posix_file_system.cc index c7afab9583..fc48cab564 100644 --- a/tensorflow/core/platform/posix/posix_file_system.cc +++ b/tensorflow/core/platform/posix/posix_file_system.cc @@ -240,11 +240,14 @@ Status PosixFileSystem::DeleteFile(const string& fname) { } Status PosixFileSystem::CreateDir(const string& name) { - Status result; - if (mkdir(TranslateName(name).c_str(), 0755) != 0) { - result = IOError(name, errno); + string translated = TranslateName(name); + if (translated.empty()) { + return errors::AlreadyExists(name); } - return result; + if (mkdir(translated.c_str(), 0755) != 0) { + return IOError(name, errno); + } + return Status::OK(); } Status PosixFileSystem::DeleteDir(const string& name) { diff --git a/tensorflow/python/keras/engine/saving_test.py b/tensorflow/python/keras/engine/saving_test.py index f376f081cf..375d1010d1 100644 --- a/tensorflow/python/keras/engine/saving_test.py +++ b/tensorflow/python/keras/engine/saving_test.py @@ -32,6 +32,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.keras.engine import saving from tensorflow.python.keras.engine import training +from tensorflow.python.lib.io import file_io from tensorflow.python.ops import array_ops from tensorflow.python.ops import random_ops from tensorflow.python.platform import test @@ -992,5 +993,57 @@ class TestWeightSavingAndLoadingTFFormat(test.TestCase): AssertionError, 'Nothing except the root object matched'): m.load_weights(save_path) + @test_util.run_in_graph_and_eager_modes + def test_directory_passed(self): + m = keras.Model() + v = m.add_weight(name='v', shape=[]) + self.evaluate(v.assign(42.)) + prefix = os.path.join(self.get_temp_dir(), '{}'.format(ops.uid()), 'ckpt/') + m.save_weights(prefix) + self.evaluate(v.assign(2.)) + m.load_weights(prefix) + self.assertEqual(42., self.evaluate(v)) + + @test_util.run_in_graph_and_eager_modes + def test_relative_path(self): + m = keras.Model() + v = m.add_weight(name='v', shape=[]) + os.chdir(self.get_temp_dir()) + + prefix = 'ackpt' + self.evaluate(v.assign(42.)) + m.save_weights(prefix) + self.assertTrue(file_io.file_exists('ackpt.index')) + self.evaluate(v.assign(1.)) + m.load_weights(prefix) + self.assertEqual(42., self.evaluate(v)) + + prefix = 'subdir/ackpt' + self.evaluate(v.assign(43.)) + m.save_weights(prefix) + self.assertTrue(file_io.file_exists('subdir/ackpt.index')) + self.evaluate(v.assign(2.)) + m.load_weights(prefix) + self.assertEqual(43., self.evaluate(v)) + + prefix = 'ackpt/' + self.evaluate(v.assign(44.)) + m.save_weights(prefix) + self.assertTrue(file_io.file_exists('ackpt/.index')) + self.evaluate(v.assign(3.)) + m.load_weights(prefix) + self.assertEqual(44., self.evaluate(v)) + + @test_util.run_in_graph_and_eager_modes + def test_nonexistant_prefix_directory(self): + m = keras.Model() + v = m.add_weight(name='v', shape=[]) + self.evaluate(v.assign(42.)) + prefix = os.path.join(self.get_temp_dir(), '{}'.format(ops.uid()), 'bckpt') + m.save_weights(prefix) + self.evaluate(v.assign(2.)) + m.load_weights(prefix) + self.assertEqual(42., self.evaluate(v)) + if __name__ == '__main__': test.main() diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index 3839928434..de06ec622a 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -831,6 +831,7 @@ tf_py_test( "//tensorflow/core:protos_all_py", "//tensorflow/python:client", "//tensorflow/python:client_testlib", + "//tensorflow/python:constant_op", "//tensorflow/python:io_ops", "//tensorflow/python:io_ops_gen", ], diff --git a/tensorflow/python/kernel_tests/save_restore_ops_test.py b/tensorflow/python/kernel_tests/save_restore_ops_test.py index cb9aa1e34d..be117c4350 100644 --- a/tensorflow/python/kernel_tests/save_restore_ops_test.py +++ b/tensorflow/python/kernel_tests/save_restore_ops_test.py @@ -17,14 +17,30 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import os + from tensorflow.core.protobuf import config_pb2 from tensorflow.python.client import session +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_io_ops from tensorflow.python.ops import io_ops from tensorflow.python.platform import test +class SaveTest(test.TestCase): + + @test_util.run_in_graph_and_eager_modes + def testRelativePath(self): + os.chdir(self.get_temp_dir()) + self.evaluate(io_ops.save_v2( + "ckpt", ["x"], [""], [constant_op.constant(100.)])) + self.assertAllEqual([100.], + self.evaluate(io_ops.restore_v2( + "ckpt", ["x"], [""], [dtypes.float32]))) + + class ShardedFileOpsTest(test.TestCase): def testShardedFileName(self): diff --git a/tensorflow/python/training/checkpointable/util.py b/tensorflow/python/training/checkpointable/util.py index 85844393f3..394cc33ad0 100644 --- a/tensorflow/python/training/checkpointable/util.py +++ b/tensorflow/python/training/checkpointable/util.py @@ -31,6 +31,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors_impl from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape +from tensorflow.python.lib.io import file_io from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_io_ops as io_ops from tensorflow.python.ops import init_ops @@ -1458,6 +1459,7 @@ class CheckpointableSaver(object): elif session is None: session = ops.get_default_session() + file_io.recursive_create_dir(os.path.dirname(file_prefix)) with ops.device("/cpu:0"): save_path = saver.save( sess=_SessionWithFeedDictAdditions( -- GitLab From d6c36d6576fb46f684a33c7ee54b879768811ae6 Mon Sep 17 00:00:00 2001 From: Blake Hechtman Date: Wed, 28 Nov 2018 09:52:03 -0800 Subject: [PATCH 459/672] [XLA] Set the layout of the pad instruction if interior padding was removed. PiperOrigin-RevId: 223185645 --- tensorflow/compiler/xla/service/algebraic_simplifier.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/compiler/xla/service/algebraic_simplifier.cc b/tensorflow/compiler/xla/service/algebraic_simplifier.cc index a9099d9e31..a348bcf0a2 100644 --- a/tensorflow/compiler/xla/service/algebraic_simplifier.cc +++ b/tensorflow/compiler/xla/service/algebraic_simplifier.cc @@ -1685,10 +1685,10 @@ Status AlgebraicSimplifierVisitor::HandlePad(HloInstruction* pad) { } } if (cleared_interior_padding) { - TF_ASSIGN_OR_RETURN(HloInstruction * pad_without_interior_pad, - MakePadHlo(pad->mutable_operand(0), - pad->mutable_operand(1), padding_config)); - return ReplaceInstruction(pad, pad_without_interior_pad); + return ReplaceWithNewInstruction( + pad, + HloInstruction::CreatePad(pad->shape(), pad->mutable_operand(0), + pad->mutable_operand(1), padding_config)); } } -- GitLab From 77296a9c84cde06a3299a8a18cc4ac79051f7db0 Mon Sep 17 00:00:00 2001 From: Karmel Allison Date: Wed, 28 Nov 2018 10:06:55 -0800 Subject: [PATCH 460/672] Exposing export_all_saved_models from the experimental Estimator API in advance of removing it from contrib. PiperOrigin-RevId: 223188420 --- tensorflow/contrib/tpu/python/tpu/tpu_estimator.py | 3 --- tensorflow/python/saved_model/constants.py | 2 +- tensorflow/python/saved_model/signature_constants.py | 2 +- .../v1/tensorflow.estimator.-baseline-classifier.pbtxt | 6 +++++- .../v1/tensorflow.estimator.-baseline-estimator.pbtxt | 6 +++++- .../v1/tensorflow.estimator.-baseline-regressor.pbtxt | 6 +++++- .../v1/tensorflow.estimator.-boosted-trees-classifier.pbtxt | 6 +++++- .../v1/tensorflow.estimator.-boosted-trees-regressor.pbtxt | 6 +++++- .../golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt | 6 +++++- .../golden/v1/tensorflow.estimator.-d-n-n-estimator.pbtxt | 6 +++++- ...orflow.estimator.-d-n-n-linear-combined-classifier.pbtxt | 6 +++++- ...sorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt | 6 +++++- ...sorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt | 6 +++++- .../golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt | 6 +++++- .../api/golden/v1/tensorflow.estimator.-estimator.pbtxt | 6 +++++- .../golden/v1/tensorflow.estimator.-linear-classifier.pbtxt | 6 +++++- .../golden/v1/tensorflow.estimator.-linear-estimator.pbtxt | 6 +++++- .../golden/v1/tensorflow.estimator.-linear-regressor.pbtxt | 6 +++++- .../api/golden/v1/tensorflow.estimator.experimental.pbtxt | 4 ++++ .../v2/tensorflow.estimator.-baseline-classifier.pbtxt | 6 +++++- .../v2/tensorflow.estimator.-baseline-estimator.pbtxt | 6 +++++- .../v2/tensorflow.estimator.-baseline-regressor.pbtxt | 6 +++++- .../v2/tensorflow.estimator.-boosted-trees-classifier.pbtxt | 6 +++++- .../v2/tensorflow.estimator.-boosted-trees-regressor.pbtxt | 6 +++++- .../golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt | 6 +++++- .../golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt | 6 +++++- ...orflow.estimator.-d-n-n-linear-combined-classifier.pbtxt | 6 +++++- ...sorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt | 6 +++++- ...sorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt | 6 +++++- .../golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt | 6 +++++- .../api/golden/v2/tensorflow.estimator.-estimator.pbtxt | 6 +++++- .../golden/v2/tensorflow.estimator.-linear-classifier.pbtxt | 6 +++++- .../golden/v2/tensorflow.estimator.-linear-estimator.pbtxt | 6 +++++- .../golden/v2/tensorflow.estimator.-linear-regressor.pbtxt | 6 +++++- .../api/golden/v2/tensorflow.estimator.experimental.pbtxt | 4 ++++ 35 files changed, 160 insertions(+), 35 deletions(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 77fa73e613..7171587ff7 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -2169,7 +2169,6 @@ class TPUEstimator(estimator_lib.Estimator): builder, input_receiver_fn_map, checkpoint_path, - strip_default_attrs, save_variables=True, mode=model_fn_lib.ModeKeys.PREDICT, export_tags=None, @@ -2184,7 +2183,6 @@ class TPUEstimator(estimator_lib.Estimator): builder, input_receiver_fn_map, checkpoint_path, - strip_default_attrs, save_variables, mode=mode, export_tags=export_tags, @@ -2201,7 +2199,6 @@ class TPUEstimator(estimator_lib.Estimator): builder, input_receiver_fn_map, checkpoint_path, - strip_default_attrs, save_variables=False, mode=mode, export_tags=export_tags, diff --git a/tensorflow/python/saved_model/constants.py b/tensorflow/python/saved_model/constants.py index f696d4815b..1edc0c8d93 100644 --- a/tensorflow/python/saved_model/constants.py +++ b/tensorflow/python/saved_model/constants.py @@ -54,7 +54,7 @@ tf_export( __name__, "MAIN_OP_KEY") # CollectionDef key for the SavedModel train op. -# Not exported while export_all_saved_models is in contrib. +# Not exported while export_all_saved_models is experimental. TRAIN_OP_KEY = "saved_model_train_op" # Schema version for SavedModel. diff --git a/tensorflow/python/saved_model/signature_constants.py b/tensorflow/python/saved_model/signature_constants.py index 96460717ec..0efe176343 100644 --- a/tensorflow/python/saved_model/signature_constants.py +++ b/tensorflow/python/saved_model/signature_constants.py @@ -135,7 +135,7 @@ tf_export( ################################################################################ # Train/Eval API constants. -# Not exported while export_all_saved_models is in contrib. +# Not exported while export_all_saved_models is experimental. SUPERVISED_TRAIN_METHOD_NAME = "tensorflow/supervised/training" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt index af1659528b..225742539d 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-classifier.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-estimator.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-estimator.pbtxt index d218773dfc..38b27f735f 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt index e5794252e4..5c51767d56 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-baseline-regressor.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-classifier.pbtxt index 970abd8622..e138ce936e 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-classifier.pbtxt @@ -33,6 +33,10 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "experimental_feature_importances" argspec: "args=[\'self\', \'normalize\'], varargs=None, keywords=None, defaults=[\'False\'], " @@ -43,7 +47,7 @@ tf_class { } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-regressor.pbtxt index b5bbad965e..eae0a292a9 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-boosted-trees-regressor.pbtxt @@ -33,6 +33,10 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "experimental_feature_importances" argspec: "args=[\'self\', \'normalize\'], varargs=None, keywords=None, defaults=[\'False\'], " @@ -43,7 +47,7 @@ tf_class { } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt index 77e60d426e..a142ca3290 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-classifier.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-estimator.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-estimator.pbtxt index 85ff5a4fb1..09e0d38192 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt index 07aefed63d..85a20828a0 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt index ac13dad2d4..e311f96d3d 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt index 852e8d2f54..e05c7ce0a2 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt index 2779cbe90e..fc3b1d9813 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-d-n-n-regressor.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-estimator.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-estimator.pbtxt index eee57462fb..bff6c86cd7 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-estimator.pbtxt @@ -31,9 +31,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt index 6569e92c6a..d213551c0b 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-classifier.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-estimator.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-estimator.pbtxt index 023edec819..2148374fde 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt index d74bf4f197..004dfccb3b 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.-linear-regressor.pbtxt @@ -33,9 +33,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt index 4b287e1f80..2a9a0346d7 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.estimator.experimental.pbtxt @@ -8,6 +8,10 @@ tf_module { name: "LinearSDCA" mtype: "" } + member_method { + name: "build_raw_supervised_input_receiver_fn" + argspec: "args=[\'features\', \'labels\', \'default_batch_size\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "call_logit_fn" argspec: "args=[\'logit_fn\', \'features\', \'mode\', \'params\', \'config\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt index 07483df83e..22cbcf08f1 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-classifier.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt index d218773dfc..38b27f735f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt index 292b5f32d8..a965042b41 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-baseline-regressor.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-classifier.pbtxt index 970abd8622..e138ce936e 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-classifier.pbtxt @@ -33,6 +33,10 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "experimental_feature_importances" argspec: "args=[\'self\', \'normalize\'], varargs=None, keywords=None, defaults=[\'False\'], " @@ -43,7 +47,7 @@ tf_class { } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-regressor.pbtxt index b5bbad965e..eae0a292a9 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-boosted-trees-regressor.pbtxt @@ -33,6 +33,10 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "experimental_feature_importances" argspec: "args=[\'self\', \'normalize\'], varargs=None, keywords=None, defaults=[\'False\'], " @@ -43,7 +47,7 @@ tf_class { } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt index c542edf64d..f6bd4d2121 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-classifier.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt index 85ff5a4fb1..09e0d38192 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt index 623cbc3648..60627cc197 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-classifier.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt index ac13dad2d4..e311f96d3d 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt index f45e76537a..dc6aca25dd 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-linear-combined-regressor.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt index 8db2196512..7338abc1d9 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-d-n-n-regressor.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-estimator.pbtxt index 71531fd217..a1f0e76c8b 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-estimator.pbtxt @@ -30,9 +30,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "get_variable_names" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt index 72c226b25d..6559c581fb 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-classifier.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt index 023edec819..2148374fde 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-estimator.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt index c4bb19612a..e6ea074ff8 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.-linear-regressor.pbtxt @@ -32,9 +32,13 @@ tf_class { name: "evaluate" argspec: "args=[\'self\', \'input_fn\', \'steps\', \'hooks\', \'checkpoint_path\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\'], " } + member_method { + name: "experimental_export_all_saved_models" + argspec: "args=[\'self\', \'export_dir_base\', \'input_receiver_fn_map\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + } member_method { name: "export_saved_model" - argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " + argspec: "args=[\'self\', \'export_dir_base\', \'serving_input_receiver_fn\', \'assets_extra\', \'as_text\', \'checkpoint_path\', \'experimental_mode\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\', \'infer\'], " } member_method { name: "export_savedmodel" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt index 4b287e1f80..2a9a0346d7 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.estimator.experimental.pbtxt @@ -8,6 +8,10 @@ tf_module { name: "LinearSDCA" mtype: "" } + member_method { + name: "build_raw_supervised_input_receiver_fn" + argspec: "args=[\'features\', \'labels\', \'default_batch_size\'], varargs=None, keywords=None, defaults=[\'None\'], " + } member_method { name: "call_logit_fn" argspec: "args=[\'logit_fn\', \'features\', \'mode\', \'params\', \'config\'], varargs=None, keywords=None, defaults=None" -- GitLab From 8514eb2958f5872dbc7e4d8f7ccdfb81cd5619fe Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 10:15:52 -0800 Subject: [PATCH 461/672] Fix uneven spatial partition. PiperOrigin-RevId: 223189870 --- tensorflow/contrib/tpu/python/tpu/tpu_feed.py | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_feed.py b/tensorflow/contrib/tpu/python/tpu/tpu_feed.py index cf36103277..d5957b7e8e 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_feed.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_feed.py @@ -833,24 +833,30 @@ class _PartitionedInfeedQueue(InfeedQueue): dims = np.array(dims) self._check_input_partition_dims(tensor, dims) output = [tensor] - divds, remainders = np.divmod(np.array(tensor.shape.as_list()), dims) - for axis, (divd, remainder, dim) in enumerate( - np.dstack((divds, remainders, dims))[0]): + shape_list = np.array(tensor.shape.as_list()) + quotients, remainders = np.divmod(shape_list, dims) + for axis, (quotient, remainder, dim, original_size) in enumerate( + zip(quotients, remainders, dims, shape_list)): if dim <= 1: continue if remainder > 0: # For each dimension, when it cannot be evenly partitioned, XLA assumes - # the size of last parts are smaller by 1. E.g. 2D tensor with shape - # (5, 14) and dims are (2, 4). Since 5 % 2 = 1 and 14 % 4 = 2, [5, 14] - # => [[(3, 3), (3, 3), (2, 3), (2, 3)], - # [(2, 3), (2, 3), (2, 2), (2, 2)]] - output = [ - array_ops.split( - x, - num_or_size_splits=[divd + 1] * remainder + - [divd] * (dim - remainder), - axis=axis) for x in output - ] + # tensors are partitioned in a greedy manner by using + # ceil_ratio(size/dim) first. E.g. 2D tensor with shape (5, 14) and dims + # are (2, 4). Since 5 % 2 = 1 and 14 % 4 = 2, [5, 14] => + # [[(3, 4), (3, 4), (2, 4), (2, 2)], + # [(2, 4), (2, 4), (2, 4), (2, 2)]] + ceil_ratio = quotient + 1 + num_full_slots, left_over = np.divmod(original_size, ceil_ratio) + num_or_size_splits = [ceil_ratio] * num_full_slots + [left_over] + if len(num_or_size_splits) < dim: + num_or_size_splits += [0] * (dim - len(num_or_size_splits)) + new_output = [] + for x in output: + new_output.append( + array_ops.split( + x, num_or_size_splits=num_or_size_splits, axis=axis)) + output = new_output else: output = [array_ops.split(x, dim, axis=axis) for x in output] output = nest.flatten(output) -- GitLab From bb75a3f0f6be966ba01a242f5d06170dddef0235 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Wed, 28 Nov 2018 18:37:28 +0000 Subject: [PATCH 462/672] Fix broken path in lite docs This fix fixes broken link in lite docs Signed-off-by: Yong Tang --- tensorflow/lite/tools/optimize/g3doc/quantize_weights.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/tools/optimize/g3doc/quantize_weights.md b/tensorflow/lite/tools/optimize/g3doc/quantize_weights.md index 2517882c84..cea164c38f 100644 --- a/tensorflow/lite/tools/optimize/g3doc/quantize_weights.md +++ b/tensorflow/lite/tools/optimize/g3doc/quantize_weights.md @@ -3,7 +3,7 @@ ## Recommended usage The Quantize Weights transformation is integrated with -[tflite_convert](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/toco/g3doc/cmdline_reference.md#transformation-flags). +[tflite_convert](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/convert/cmdline_reference.md#transformation-flags). The recommended way of invoking this tool is by simply adding the `--post_training_quantize` flag to your original tflite_convert invocation. For -- GitLab From 3553486256ae68ac72ed1ed2688a055381d818a5 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 28 Nov 2018 10:55:57 -0800 Subject: [PATCH 463/672] [TF:XLA] Do the final division of reduce_mean in accumulation type, not input type This reduces the probability of overflow in fp16, matching TF without XLA. PiperOrigin-RevId: 223197560 --- tensorflow/compiler/tests/reduce_ops_test.py | 6 ++++++ tensorflow/compiler/tf2xla/kernels/reduction_ops.cc | 7 +++---- tensorflow/compiler/tf2xla/kernels/reduction_ops.h | 4 ++-- .../compiler/tf2xla/kernels/reduction_ops_common.cc | 9 ++++----- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tensorflow/compiler/tests/reduce_ops_test.py b/tensorflow/compiler/tests/reduce_ops_test.py index 132c59c32c..e8fc81bbb5 100644 --- a/tensorflow/compiler/tests/reduce_ops_test.py +++ b/tensorflow/compiler/tests/reduce_ops_test.py @@ -91,6 +91,7 @@ class ReduceOpsTest(xla_test.XLATestCase, parameterized.TestCase): np.array([], dtype=np.bool).reshape(0, 3), np.array([[False, True, False], [True, True, False]]), ] + ONES = [np.ones([34000, 2])] def testReduceSumF32(self, index_dtype): self._testReduction(math_ops.reduce_sum, np.sum, np.float32, self.REAL_DATA, @@ -149,6 +150,11 @@ class ReduceOpsTest(xla_test.XLATestCase, parameterized.TestCase): self._testReduction(math_ops.reduce_mean, np.mean, np.float32, self.NONEMPTY_REAL_DATA, index_dtype) + def testReduceMeanF16(self, index_dtype): + if np.float16 in self.all_types: + self._testReduction(math_ops.reduce_mean, np.mean, np.float16, self.ONES, + index_dtype) + def testReduceMeanC64(self, index_dtype): self._testReduction(math_ops.reduce_mean, np.mean, np.complex64, self.NONEMPTY_COMPLEX_DATA, index_dtype) diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc b/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc index 132160de70..65e158d64f 100644 --- a/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc @@ -125,10 +125,9 @@ class MeanOp : public XlaReductionOp { auto size = xla::GetDimensionSize(input, dimensions_to_reduce[i]); divisor = xla::Mul(divisor, size); } - xla::PrimitiveType type; - TF_CHECK_OK(DataTypeToPrimitiveType(input_type(0), &type)); - divisor = xla::ConvertElementType(divisor, type); - return reduce_output / divisor; + divisor = xla::ConvertElementType(divisor, xla_reduction_type_); + return XlaHelpers::ConvertElementType(reduce_output / divisor, + input_type(0)); } }; diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops.h b/tensorflow/compiler/tf2xla/kernels/reduction_ops.h index 8f1667df5b..af716eab79 100644 --- a/tensorflow/compiler/tf2xla/kernels/reduction_ops.h +++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops.h @@ -50,8 +50,8 @@ class XlaReductionOp : public XlaOpKernel { // Applies a transformation to the output of the reduction. The desired // computation should be added to 'builder'. Argument 'input' is the original // input of the reduction; 'reduce_output' is the output of the reduction. - // Returns the transformed reduction output, Defaults to returning - // 'reduce_output' unchanged. + // Returns the transformed reduction output. Defaults to returning + // 'reduce_output' converted to the input type. virtual xla::XlaOp BuildFinalizer( xla::XlaBuilder* builder, const xla::XlaOp& input, const xla::XlaOp& reduce_output, diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc b/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc index b9bb5edba3..2ca2a85244 100644 --- a/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc +++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc @@ -35,13 +35,13 @@ XlaReductionOp::XlaReductionOp(OpKernelConstruction* ctx, ctx, DataTypeToPrimitiveType(reduction_type_, &xla_reduction_type_)); } -// Unless BuildFinalizer is overridden the reduction has no -// finalizer. +// The default finalizer converts the results back into the input type. This can +// be overridden. xla::XlaOp XlaReductionOp::BuildFinalizer( xla::XlaBuilder* /*builder*/, const xla::XlaOp& /*input*/, const xla::XlaOp& reduce_output, const std::vector& /*dimensions_to_reduce*/) { - return reduce_output; + return XlaHelpers::ConvertElementType(reduce_output, input_type(0)); } void XlaReductionOp::Compile(XlaOpKernelContext* ctx) { @@ -117,8 +117,7 @@ void XlaReductionOp::Compile(XlaOpKernelContext* ctx) { xla::XlaComputation reduction_computation = r.Build().ConsumeValueOrDie(); auto reduce = xla::Reduce(data, initial, reduction_computation, xla_axes); - auto deconverted = XlaHelpers::ConvertElementType(reduce, input_type(0)); - auto finalized = BuildFinalizer(b, data, deconverted, xla_axes); + auto finalized = BuildFinalizer(b, data, reduce, xla_axes); auto result = keep_dims_ ? xla::Reshape(finalized, final_shape) : finalized; ctx->SetOutput(0, result); } -- GitLab From 652cc2b1ce266c70a7f9ce30570d477d7f74f12a Mon Sep 17 00:00:00 2001 From: Michael Case Date: Wed, 28 Nov 2018 11:33:29 -0800 Subject: [PATCH 464/672] Update TF 2.0 Endpoints PiperOrigin-RevId: 223205389 --- tensorflow/python/ops/nn_impl.py | 40 ++++++++++++++++++- tensorflow/python/ops/nn_test.py | 32 +++++++-------- .../tools/api/golden/v2/tensorflow.nn.pbtxt | 6 +-- .../tools/compatibility/tf_upgrade_v2.py | 40 ++++++++++++------- 4 files changed, 80 insertions(+), 38 deletions(-) diff --git a/tensorflow/python/ops/nn_impl.py b/tensorflow/python/ops/nn_impl.py index 6591da5be8..26bd13eaee 100644 --- a/tensorflow/python/ops/nn_impl.py +++ b/tensorflow/python/ops/nn_impl.py @@ -861,7 +861,7 @@ def normalize_moments(counts, mean_ss, variance_ss, shift, name=None): return (mean, variance) -@tf_export("nn.moments") +@tf_export(v1=["nn.moments"]) def moments( x, axes, @@ -920,6 +920,42 @@ def moments( return (mean, variance) +@tf_export("nn.moments", v1=[]) +def moments_v2( + x, + axes, + shift=None, + keepdims=False, + name=None): + """Calculates the mean and variance of `x`. + + The mean and variance are calculated by aggregating the contents of `x` + across `axes`. If `x` is 1-D and `axes = [0]` this is just the mean + and variance of a vector. + + Note: shift is currently not used; the true mean is computed and used. + + When using these moments for batch normalization (see + `tf.nn.batch_normalization`): + + * for so-called "global normalization", used with convolutional filters with + shape `[batch, height, width, depth]`, pass `axes=[0, 1, 2]`. + * for simple batch normalization pass `axes=[0]` (batch only). + + Args: + x: A `Tensor`. + axes: Array of ints. Axes along which to compute mean and + variance. + shift: Not used in the current implementation. + keepdims: produce moments with the same dimensionality as the input. + name: Name used to scope the operations that compute the moments. + + Returns: + Two `Tensor` objects: `mean` and `variance`. + """ + return moments(x=x, axes=axes, shift=shift, name=name, keep_dims=keepdims) + + @tf_export(v1=["nn.weighted_moments"]) def weighted_moments(x, axes, frequency_weights, name=None, keep_dims=False): """Returns the frequency-weighted mean and variance of `x`. @@ -1076,7 +1112,7 @@ def batch_normalization(x, offset - mean * inv if offset is not None else -mean * inv, x.dtype) -@tf_export("nn.fused_batch_norm") +@tf_export(v1=["nn.fused_batch_norm"]) def fused_batch_norm( x, scale, diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index 96b9d6fc0d..f7c8a7a70a 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -101,8 +101,8 @@ class SoftmaxTest(test_lib.TestCase, parameterized.TestCase): x_np = np.random.randn(*x_shape).astype(np.float32) y_np = self._softmax(x_np) x_tf = constant_op.constant(x_np) - y_tf = nn_ops.softmax(x_tf) - y_tf_last_dim = nn_ops.softmax(x_tf, 1) + y_tf = nn_ops.softmax_v2(x_tf) + y_tf_last_dim = nn_ops.softmax_v2(x_tf, 1) y_tf_np = self.evaluate(y_tf) y_tf_last_dim_np = self.evaluate(y_tf_last_dim) eps = 1e-3 @@ -111,9 +111,9 @@ class SoftmaxTest(test_lib.TestCase, parameterized.TestCase): def testSoftmaxAxes(self): arr = np.linspace(0., 1, 12).reshape(3, 4) - x_neg_axis = nn_ops.softmax(arr, axis=-2) - y_pos_axis = nn_ops.softmax(arr, axis=0) - z_gt_axis = nn_ops.softmax(arr, axis=0) + x_neg_axis = nn_ops.softmax_v2(arr, axis=-2) + y_pos_axis = nn_ops.softmax_v2(arr, axis=0) + z_gt_axis = nn_ops.softmax_v2(arr, axis=0) x_neg_axis_tf = self.evaluate(x_neg_axis) y_pos_axis_tf = self.evaluate(y_pos_axis) z_gt_axis_tf = self.evaluate(z_gt_axis) @@ -126,7 +126,7 @@ class SoftmaxTest(test_lib.TestCase, parameterized.TestCase): x_np = np.random.randn(*x_shape).astype(np.float64) with self.cached_session(): x_tf = constant_op.constant(x_np) - y_tf = nn_ops.softmax(x_tf) + y_tf = nn_ops.softmax_v2(x_tf) err = gradient_checker.compute_gradient_error(x_tf, x_shape, y_tf, x_shape) eps = 2e-8 @@ -189,16 +189,16 @@ class LogSoftmaxTest(test_lib.TestCase, parameterized.TestCase): x_np = np.random.randn(*x_shape).astype(np.float32) y_np = self._log_softmax(x_np) x_tf = constant_op.constant(x_np) - y_tf = nn_ops.log_softmax(x_tf) + y_tf = nn_ops.log_softmax_v2(x_tf) y_tf_np = self.evaluate(y_tf) eps = 1e-3 self.assertAllClose(y_tf_np, y_np, eps) def testLogSoftmaxAxes(self): arr = np.linspace(0., 1, 12).reshape(3, 4) - x_neg_axis = nn_ops.log_softmax(arr, axis=-2) - y_pos_axis = nn_ops.log_softmax(arr, axis=0) - z_gt_axis = nn_ops.log_softmax(arr, axis=0) + x_neg_axis = nn_ops.log_softmax_v2(arr, axis=-2) + y_pos_axis = nn_ops.log_softmax_v2(arr, axis=0) + z_gt_axis = nn_ops.log_softmax_v2(arr, axis=0) x_neg_axis_tf = self.evaluate(x_neg_axis) y_pos_axis_tf = self.evaluate(y_pos_axis) z_gt_axis_tf = self.evaluate(z_gt_axis) @@ -211,7 +211,7 @@ class LogSoftmaxTest(test_lib.TestCase, parameterized.TestCase): x_np = np.random.randn(*x_shape).astype(np.float64) with self.cached_session(): x_tf = constant_op.constant(x_np) - y_tf = nn_ops.log_softmax(x_tf) + y_tf = nn_ops.log_softmax_v2(x_tf) err = gradient_checker.compute_gradient_error(x_tf, x_shape, y_tf, x_shape) eps = 1e-7 @@ -262,7 +262,7 @@ class L2NormalizeTest(test_lib.TestCase): for dim in range(len(x_shape)): y_np = self._l2Normalize(x_np, dim) x_tf = constant_op.constant(x_np, name="x") - y_tf = nn_impl.l2_normalize(x_tf, dim) + y_tf = nn_impl.l2_normalize_v2(x_tf, dim) self.assertAllClose(y_np, self.evaluate(y_tf)) @test_util.run_in_graph_and_eager_modes @@ -273,7 +273,7 @@ class L2NormalizeTest(test_lib.TestCase): dim = [1, 2] y_np = self._l2Normalize(x_np, dim) x_tf = constant_op.constant(x_np, name="x") - y_tf = nn_impl.l2_normalize(x_tf, dim) + y_tf = nn_impl.l2_normalize_v2(x_tf, dim) self.assertAllClose(y_np, self.evaluate(y_tf)) def testL2NormalizeGradient(self): @@ -283,7 +283,7 @@ class L2NormalizeTest(test_lib.TestCase): for dim in range(len(x_shape)): with self.cached_session(): x_tf = constant_op.constant(x_np, name="x") - y_tf = nn_impl.l2_normalize(x_tf, dim) + y_tf = nn_impl.l2_normalize_v2(x_tf, dim) err = gradient_checker.compute_gradient_error(x_tf, x_shape, y_tf, x_shape) print("L2Normalize gradient err = %g " % err) @@ -1034,8 +1034,8 @@ class MomentsTest(test_lib.TestCase): with self.session(graph=g) as sess: inputs = constant_op.constant( input_values, shape=input_shape, dtype=dtypes.float32) - mean, variance = nn_impl.moments( - inputs, moments_axes, keep_dims=keep_dims) + mean, variance = nn_impl.moments_v2( + inputs, moments_axes, keepdims=keep_dims) if check_gradients: err = gradient_checker.compute_gradient_error( diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index 04b189784a..b4d0f95bc3 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -156,10 +156,6 @@ tf_module { name: "fractional_max_pool" argspec: "args=[\'value\', \'pooling_ratio\', \'pseudo_random\', \'overlapping\', \'seed\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'False\', \'0\', \'None\'], " } - member_method { - name: "fused_batch_norm" - argspec: "args=[\'x\', \'scale\', \'offset\', \'mean\', \'variance\', \'epsilon\', \'data_format\', \'is_training\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'0.001\', \'NHWC\', \'True\', \'None\'], " - } member_method { name: "in_top_k" argspec: "args=[\'predictions\', \'targets\', \'k\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " @@ -210,7 +206,7 @@ tf_module { } member_method { name: "moments" - argspec: "args=[\'x\', \'axes\', \'shift\', \'name\', \'keep_dims\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'False\'], " + argspec: "args=[\'x\', \'axes\', \'shift\', \'keepdims\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'False\', \'None\'], " } member_method { name: "nce_loss" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 3cb78afb32..6e8d6e2d0b 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -58,26 +58,44 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.convert_to_tensor": { "preferred_dtype": "dtype_hint" }, + "tf.linalg.l2_normalize": { + "dim": "axis", + }, "tf.math.count_nonzero": { "input_tensor": "input", "keep_dims": "keepdims", "reduction_indices": "axis", }, + "tf.math.l2_normalize": { + "dim": "axis", + }, + "tf.math.log_softmax": { + "dim": "axis", + }, + "tf.math.softmax": { + "dim": "axis" + }, + "tf.nn.l2_normalize": { + "dim": "axis", + }, + "tf.nn.log_softmax": { + "dim": "axis", + }, + "tf.nn.moments": { + "keep_dims": "keepdims", + }, "tf.nn.pool": { "dilation_rate": "dilations" }, "tf.nn.separable_conv2d": { "rate": "dilations" }, + "tf.nn.softmax": { + "dim": "axis" + }, "tf.nn.sufficient_statistics": { "keep_dims": "keepdims" }, - "tf.nn.log_softmax": { - "dim": "axis", - }, - "tf.nn.softmax": { - "dim": "axis", - }, "tf.debugging.assert_all_finite": { "t": "x", "msg": "message", @@ -165,15 +183,6 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.random.stateless_multinomial": { "output_dtype": "dtype", }, - "tf.linalg.l2_normalize": { - "dim": "axis", - }, - "tf.math.l2_normalize": { - "dim": "axis", - }, - "tf.nn.l2_normalize": { - "dim": "axis", - }, "tf.sparse.concat": [ "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" ], @@ -422,6 +431,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.batch_to_space": ["input", "crops", "block_size", "name"], "tf.boolean_mask": ["tensor", "mask", "name", "axis"], "tf.convert_to_tensor": ["value", "dtype", "name", "preferred_dtype"], + "tf.nn.moments": ["x", "axes", "shift", "keepdims", "name"], "tf.nn.convolution": [ "input", "filter", "padding", "strides", "dilation_rate", "name", "data_format" -- GitLab From e55a58c9bf6adf07dce074813b54fc5b16c5be1d Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 11:42:51 -0800 Subject: [PATCH 465/672] Replace `tf.estimator.inputs` with `tf.compat.v1.estimator.inputs` PiperOrigin-RevId: 223207243 --- tensorflow/contrib/learn/python/learn/learn_io/numpy_io.py | 2 +- tensorflow/contrib/learn/python/learn/learn_io/pandas_io.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/learn/python/learn/learn_io/numpy_io.py b/tensorflow/contrib/learn/python/learn/learn_io/numpy_io.py index 29552d24f1..59a67636ae 100644 --- a/tensorflow/contrib/learn/python/learn/learn_io/numpy_io.py +++ b/tensorflow/contrib/learn/python/learn/learn_io/numpy_io.py @@ -27,7 +27,7 @@ from tensorflow.python.estimator.inputs.numpy_io import numpy_input_fn as core_n from tensorflow.python.util.deprecation import deprecated -@deprecated(None, 'Use tf.estimator.inputs.numpy_input_fn.') +@deprecated(None, 'Use tf.compat.v1.estimator.inputs.numpy_input_fn.') def numpy_input_fn(x, y=None, batch_size=128, diff --git a/tensorflow/contrib/learn/python/learn/learn_io/pandas_io.py b/tensorflow/contrib/learn/python/learn/learn_io/pandas_io.py index b4ef055f5a..e9df7258a3 100644 --- a/tensorflow/contrib/learn/python/learn/learn_io/pandas_io.py +++ b/tensorflow/contrib/learn/python/learn/learn_io/pandas_io.py @@ -53,7 +53,7 @@ PANDAS_DTYPES = { } -@deprecated(None, 'Please use tf.estimator.inputs.pandas_input_fn') +@deprecated(None, 'Please use tf.compat.v1.estimator.inputs.pandas_input_fn') def pandas_input_fn(x, y=None, batch_size=128, -- GitLab From e1d54f683f7ca1e7a9377937b34f2f37bcc9a6a8 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 28 Nov 2018 11:50:44 -0800 Subject: [PATCH 466/672] Fix clang-format. --- .../contrib/tensorrt/convert/convert_nodes.cc | 8 ++++---- .../tensorrt/convert/convert_nodes_test.cc | 15 ++++++--------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 6de3aba4d7..3b741a60a7 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -2500,8 +2500,8 @@ tensorflow::Status ConvertSquare(OpConverterParams* params) { const auto& inputs = params->inputs; const auto& node_def = params->node_def; if (inputs.size() != 1) { - return tensorflow::errors::InvalidArgument( - "Square expects one input, at ", node_def.name()); + return tensorflow::errors::InvalidArgument("Square expects one input, at ", + node_def.name()); } if (inputs.at(0).is_weights()) { return tensorflow::errors::Unimplemented( @@ -2516,8 +2516,8 @@ tensorflow::Status ConvertSquare(OpConverterParams* params) { } TRT_ShapedWeights weights = params->weight_store->GetTempWeights( tensorflow::DataType::DT_FLOAT, dims); - auto weights_ptr = static_cast(const_cast( - weights.GetValues())); + auto weights_ptr = + static_cast(const_cast(weights.GetValues())); weights_ptr[0] = 2.f; nvinfer1::IConstantLayer* const2_layer = params->converter->network()->addConstant(dims, weights.GetTrtWeights()); diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index c6cd765887..4894e30b46 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -152,8 +152,7 @@ void ExpectTrtDimsEqualsArray(const std::vector& lhs, } template -void ExpectArrayNear(const std::vector& lhs, - const std::vector& rhs) { +void ExpectArrayNear(const std::vector& lhs, const std::vector& rhs) { ASSERT_EQ(lhs.size(), rhs.size()); for (int i = 0; i < lhs.size(); i++) { EXPECT_FLOAT_EQ(lhs[i], rhs[i]); @@ -2011,9 +2010,7 @@ void TestConvertSquare(OpConverterTest* test) { expected_output_data[i] = value * value; } std::vector output_data(num_inputs); - test->BuildAndRun( - {{"input", input_data}}, "my_square", - &output_data); + test->BuildAndRun({{"input", input_data}}, "my_square", &output_data); ExpectArrayNear(expected_output_data, output_data); } @@ -2021,9 +2018,8 @@ TEST_F(OpConverterTest, ConvertSquare) { { // Input list is empty, should fail. NodeDef node_def = MakeNodeDef("my_square", "Square", {}); - RunValidationAndConversion( - node_def, error::INVALID_ARGUMENT, - "Square expects one input, at my_square"); + RunValidationAndConversion(node_def, error::INVALID_ARGUMENT, + "Square expects one input, at my_square"); } { // Input is weights, should fail. @@ -2033,7 +2029,8 @@ TEST_F(OpConverterTest, ConvertSquare) { auto square = ops::Square(s.WithOpName("my_square"), input); NodeDef node_def = square.operation.node()->def(); AddTestWeights("input", {1, 2, 3}, {1, 2, 3, 4, -5, 6}); - RunValidationAndConversion(node_def, error::UNIMPLEMENTED, + RunValidationAndConversion( + node_def, error::UNIMPLEMENTED, "Square is only implemented for tensors, at my_square"); } -- GitLab From 9433922095a43ca2a8a03373f58c01ab00c8cafe Mon Sep 17 00:00:00 2001 From: Nupur Garg Date: Wed, 28 Nov 2018 11:54:39 -0800 Subject: [PATCH 467/672] Make tflite_convert error if input_shapes are invalid. PiperOrigin-RevId: 223209299 --- tensorflow/lite/python/convert_saved_model.py | 12 +++++++++--- tensorflow/lite/python/convert_saved_model_test.py | 8 ++++++-- tensorflow/lite/python/lite_test.py | 13 +++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/tensorflow/lite/python/convert_saved_model.py b/tensorflow/lite/python/convert_saved_model.py index 3f54d2559c..ad7c87109c 100644 --- a/tensorflow/lite/python/convert_saved_model.py +++ b/tensorflow/lite/python/convert_saved_model.py @@ -197,12 +197,18 @@ def set_tensor_shapes(tensors, shapes): tensors: TensorFlow ops.Tensor. shapes: Dict of strings representing input tensor names to list of integers representing input shapes (e.g., {"foo": : [1, 16, 16, 3]}). + + Raises: + ValueError: `shapes` contains an invalid tensor. """ if shapes: - for tensor in tensors: - shape = shapes.get(tensor_name(tensor)) + tensor_names_to_tensor = {tensor_name(tensor): tensor for tensor in tensors} + for name, shape in shapes.items(): + if name not in tensor_names_to_tensor: + raise ValueError("Invalid tensor \'{}\' found in tensor shapes " + "map.".format(name)) if shape is not None: - tensor.set_shape(shape) + tensor_names_to_tensor[name].set_shape(shape) def freeze_saved_model(saved_model_dir, input_arrays, input_shapes, diff --git a/tensorflow/lite/python/convert_saved_model_test.py b/tensorflow/lite/python/convert_saved_model_test.py index dff582f1a1..0d32c34391 100644 --- a/tensorflow/lite/python/convert_saved_model_test.py +++ b/tensorflow/lite/python/convert_saved_model_test.py @@ -79,8 +79,12 @@ class TensorFunctionsTest(test_util.TensorFlowTestCase): tensor = array_ops.placeholder(shape=[None, 3, 5], dtype=dtypes.float32) self.assertEqual([None, 3, 5], tensor.shape.as_list()) - convert_saved_model.set_tensor_shapes([tensor], - {"invalid-input": [5, 3, 5]}) + with self.assertRaises(ValueError) as error: + convert_saved_model.set_tensor_shapes([tensor], + {"invalid-input": [5, 3, 5]}) + self.assertEqual( + "Invalid tensor 'invalid-input' found in tensor shapes map.", + str(error.exception)) self.assertEqual([None, 3, 5], tensor.shape.as_list()) def testSetTensorShapeEmpty(self): diff --git a/tensorflow/lite/python/lite_test.py b/tensorflow/lite/python/lite_test.py index 5a5697db92..8832247f3c 100644 --- a/tensorflow/lite/python/lite_test.py +++ b/tensorflow/lite/python/lite_test.py @@ -931,12 +931,13 @@ class FromKerasFile(test_util.TensorFlowTestCase): """Test a Sequential tf.keras model testing input shapes argument.""" keras_file = self._getSequentialModel() - # Passing in shape of invalid input array has no impact as long as all input - # arrays have a shape. - converter = lite.TFLiteConverter.from_keras_model_file( - keras_file, input_shapes={'invalid-input': [2, 3]}) - tflite_model = converter.convert() - self.assertTrue(tflite_model) + # Passing in shape of invalid input array raises error. + with self.assertRaises(ValueError) as error: + converter = lite.TFLiteConverter.from_keras_model_file( + keras_file, input_shapes={'invalid-input': [2, 3]}) + self.assertEqual( + "Invalid tensor 'invalid-input' found in tensor shapes map.", + str(error.exception)) # Passing in shape of valid input array. converter = lite.TFLiteConverter.from_keras_model_file( -- GitLab From f3239b05dbf57c231030ec04162c76f0fc120c5d Mon Sep 17 00:00:00 2001 From: Dan Moldovan Date: Wed, 28 Nov 2018 11:58:50 -0800 Subject: [PATCH 468/672] Use the minimal verbosity level by default for autograph in tf.function. PiperOrigin-RevId: 223209980 --- tensorflow/python/framework/func_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/framework/func_graph.py b/tensorflow/python/framework/func_graph.py index f1e508c365..9960e23e6f 100644 --- a/tensorflow/python/framework/func_graph.py +++ b/tensorflow/python/framework/func_graph.py @@ -397,7 +397,7 @@ def func_graph_from_py_func(name, return autograph.converted_call( original_func, None, autograph.ConversionOptions( - verbose=True, + verbose=autograph.Verbosity.BRIEF, recursive=True, strip_decorators=(function.defun, def_function.function), optional_features=(), -- GitLab From 0d40f081369150bdab2ca49fe173d2a19717c0f7 Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Wed, 28 Nov 2018 12:16:50 -0800 Subject: [PATCH 469/672] Simplify semantics of `build`: `build(input_shape)` is a method that implementers of subclasses of Layer or Model can override if they need a state-creation step in-between layer instantiation and layer call. This is typically used to create the weights of Layer subclasses. If you do not override it, it is never called by the framework (i.e. default implementations of `build` are *never called* unless you explicitly call `model.build()` yourself, therefore they never introduce surprising issues). In addition, you can call `model.build(input_shape)` on a Model instance in a standalone way, as a substitute for calling the model on some data to create its weights. This may raise an exception if the request is impossible (then you have to call the model on some data yourself in order to build it). The change also fixes two related issues: - enable `build` to be called on Model subclasses with a signature containing keyword arguments with default values (e.g. `call(self, inputs, training=False, mask=None)`. - enable a Model subclass to be nested in a Sequential model without having to implement `compute_output_shape` on the Model subclass. PiperOrigin-RevId: 223213320 --- tensorflow/python/keras/engine/base_layer.py | 52 ++++++----- tensorflow/python/keras/engine/network.py | 88 +++++++++++-------- tensorflow/python/keras/engine/saving_test.py | 1 - tensorflow/python/keras/engine/sequential.py | 19 ++-- .../python/keras/engine/sequential_test.py | 1 - tensorflow/python/keras/engine/training.py | 10 +-- tensorflow/python/keras/layers/local_test.py | 16 ++-- .../python/keras/model_subclassing_test.py | 58 +++++++++++- 8 files changed, 160 insertions(+), 85 deletions(-) diff --git a/tensorflow/python/keras/engine/base_layer.py b/tensorflow/python/keras/engine/base_layer.py index 8b795935c1..8e35300342 100644 --- a/tensorflow/python/keras/engine/base_layer.py +++ b/tensorflow/python/keras/engine/base_layer.py @@ -200,7 +200,19 @@ class Layer(checkpointable.CheckpointableBase): self._initial_weights = None def build(self, input_shape): - """Creates the variables of the layer.""" + """Creates the variables of the layer (optional, for subclass implementers). + + This is a method that implementers of subclasses of `Layer` or `Model` + can override if they need a state-creation step in-between + layer instantiation and layer call. + + This is typically used to create the weights of `Layer` subclasses. + + Arguments: + input_shape: Instance of `TensorShape`, or list of instances of + `TensorShape` if the layer expects a list of inputs + (one instance per input). + """ self.built = True @doc_controls.for_subclass_implementers @@ -517,25 +529,8 @@ class Layer(checkpointable.CheckpointableBase): with ops.name_scope(self._name_scope()): if not self.built: - # Check input assumptions set before layer building, e.g. input rank. - input_spec.assert_input_compatibility( - self.input_spec, inputs, self.name) - if input_list and self._dtype is None: - try: - self._dtype = input_list[0].dtype.base_dtype.name - except AttributeError: - pass - - if all(hasattr(x, 'shape') for x in input_list): - input_shapes = nest.map_structure(lambda x: x.shape, inputs) - - if (not hasattr(self, '_is_graph_network') or - self.__class__.__name__ == 'Sequential' or - not hasattr(self.build, '_is_default')): - # Only if self is a layer, an instance of a sequential model, or - # the user has manually overwritten the build method do we need to - # build it. - self.build(input_shapes) + # Build layer if applicable (if the `build` method has been overridden). + self._maybe_build(inputs) # We must set self.built since user defined build functions are not # constrained to set self.built. self.built = True @@ -1580,6 +1575,23 @@ class Layer(checkpointable.CheckpointableBase): """ return self._call_is_graph_friendly + def _maybe_build(self, inputs): + # Check input assumptions set before layer building, e.g. input rank. + input_spec.assert_input_compatibility( + self.input_spec, inputs, self.name) + input_list = nest.flatten(inputs) + if input_list and self._dtype is None: + try: + self._dtype = input_list[0].dtype.base_dtype.name + except AttributeError: + pass + input_shapes = None + if all(hasattr(x, 'shape') for x in input_list): + input_shapes = nest.map_structure(lambda x: x.shape, inputs) + # Only call `build` if the user has manually overridden the build method. + if not hasattr(self.build, '_is_default'): + self.build(input_shapes) + class Node(object): """A `Node` describes the connectivity between two layers. diff --git a/tensorflow/python/keras/engine/network.py b/tensorflow/python/keras/engine/network.py index 1040fd8ea3..93ae667c8b 100644 --- a/tensorflow/python/keras/engine/network.py +++ b/tensorflow/python/keras/engine/network.py @@ -769,6 +769,11 @@ class Network(base_layer.Layer): This is to be used for subclassed models, which do not know at instantiation time what their inputs look like. + This method only exists for users who want to call `model.build()` in a + standalone way (as a substitute for calling the model on real data to + build it). It will never be called by the framework (and thus it will + never throw unexpected errors in an unrelated workflow). + Args: input_shape: Single tuple, TensorShape, or list of shapes, where shapes are tuples, integers, or TensorShapes. @@ -805,48 +810,53 @@ class Network(base_layer.Layer): # in a Graph. Since tf.Variable is compatible with both eager execution # and graph building, the variables created after building the model in # a Graph are still valid when executing eagerly. - with context.graph_mode(): - graph = func_graph.FuncGraph('graph') - with graph.as_default(): - if isinstance(input_shape, list): - x = [base_layer_utils.generate_placeholders_from_shape(shape) - for shape in input_shape] + if context.executing_eagerly(): + graph = func_graph.FuncGraph('build_graph') + else: + graph = backend.get_graph() + with graph.as_default(): + if isinstance(input_shape, list): + x = [base_layer_utils.generate_placeholders_from_shape(shape) + for shape in input_shape] + else: + x = base_layer_utils.generate_placeholders_from_shape(input_shape) + + kwargs = {} + call_signature = tf_inspect.getfullargspec(self.call) + call_args = call_signature.args + # Exclude `self`, `inputs`, and any argument with a default value. + if len(call_args) > 2: + if call_signature.defaults: + call_args = call_args[2:-len(call_signature.defaults)] else: - x = base_layer_utils.generate_placeholders_from_shape(input_shape) - - kwargs = {} - num_call_args = len(tf_inspect.getfullargspec(self.call).args) - if self._expects_training_arg and num_call_args == 3: - # Has call signature of call(self, input, training) - kwargs['training'] = False - elif num_call_args > 2: - # Has invalid call signature of call(self, input, *args, **kwargs) - raise ValueError('Currently, you cannot build your model if it has ' - 'positional or keyword arguments that are not ' - 'inputs to the model, but are required for its ' - '`call` method. Instead, in order to instantiate ' - 'and build your model, `call` your model on real ' - 'tensor data with all expected call arguments.') - - try: - self.call(x, **kwargs) - except (errors.InvalidArgumentError, TypeError): - raise ValueError('You cannot build your model by calling `build` ' - 'if your layers do not support float type inputs. ' - 'Instead, in order to instantiate and build your ' - 'model, `call` your model on real tensor data (of ' - 'the correct dtype).') - + call_args = call_args[2:] + for arg in call_args: + if arg == 'training': + # Case where `training` is a positional arg with no default. + kwargs['training'] = False + else: + # Has invalid call signature with unknown positional arguments. + raise ValueError( + 'Currently, you cannot build your model if it has ' + 'positional or keyword arguments that are not ' + 'inputs to the model, but are required for its ' + '`call` method. Instead, in order to instantiate ' + 'and build your model, `call` your model on real ' + 'tensor data with all expected call arguments.') + elif len(call_args) < 2: + # Signature without `inputs`. + raise ValueError('You can only call `build` on a model if its `call` ' + 'method accepts an `inputs` argument.') + try: + self.call(x, **kwargs) + except (errors.InvalidArgumentError, TypeError): + raise ValueError('You cannot build your model by calling `build` ' + 'if your layers do not support float type inputs. ' + 'Instead, in order to instantiate and build your ' + 'model, `call` your model on real tensor data (of ' + 'the correct dtype).') if self._layers: self._track_layers(self._layers) - if self.layers: - for layer in self.layers: - if not layer.built: - raise ValueError('Layer: {} was not built in your model. Calling ' - '`build` manually on a subclassed model is only ' - 'allowed for models with a static topology. ' - 'In this case, you can build your model by ' - 'calling it on real tensor data.'.format(layer)) self.built = True def call(self, inputs, training=None, mask=None): diff --git a/tensorflow/python/keras/engine/saving_test.py b/tensorflow/python/keras/engine/saving_test.py index 375d1010d1..b92f06449e 100644 --- a/tensorflow/python/keras/engine/saving_test.py +++ b/tensorflow/python/keras/engine/saving_test.py @@ -716,7 +716,6 @@ class TestWholeModelSaving(test.TestCase): os.close(fd) os.remove(fname) - def test_saving_constant_initializer_with_numpy(self): if h5py is None: self.skipTest('h5py required to run this test') diff --git a/tensorflow/python/keras/engine/sequential.py b/tensorflow/python/keras/engine/sequential.py index 26866d4714..6e2f76cd80 100644 --- a/tensorflow/python/keras/engine/sequential.py +++ b/tensorflow/python/keras/engine/sequential.py @@ -212,20 +212,16 @@ class Sequential(Model): self._init_graph_network(self.inputs, self.outputs, name=self.name) self.built = True + @base_layer.default def build(self, input_shape=None): if self._is_graph_network: self._init_graph_network(self.inputs, self.outputs, name=self.name) else: if input_shape is None: raise ValueError('You must provide an `input_shape` argument.') + input_shape = tuple(input_shape) self._build_input_shape = input_shape - shape = input_shape - for layer in self.layers: - if not layer.built: - with ops.name_scope(layer._name_scope()): - layer.build(shape) - layer.built = True - shape = layer.compute_output_shape(shape) + super(Sequential, self).build(input_shape) self.built = True def call(self, inputs, training=None, mask=None): @@ -237,8 +233,8 @@ class Sequential(Model): return outputs def _call_and_compute_mask(self, inputs, training=None, mask=None): - if not self.built: - self.build(inputs.shape) + if not self.built and self._is_graph_network: + self._init_graph_network(self.inputs, self.outputs, name=self.name) x = inputs for layer in self.layers: @@ -251,6 +247,11 @@ class Sequential(Model): if isinstance(layer, Network) and layer._compute_output_and_mask_jointly: x, mask = layer._call_and_compute_mask(x, **kwargs) else: + if not layer.built: + # Build layer if applicable. + with ops.name_scope(layer._name_scope()): + layer._maybe_build(x) + layer.built = True x = layer.call(x, **kwargs) if layer.supports_masking: mask = layer.compute_mask(x, mask) diff --git a/tensorflow/python/keras/engine/sequential_test.py b/tensorflow/python/keras/engine/sequential_test.py index 54db0f3566..2e2927bf47 100644 --- a/tensorflow/python/keras/engine/sequential_test.py +++ b/tensorflow/python/keras/engine/sequential_test.py @@ -294,7 +294,6 @@ class TestSequential(test.TestCase, parameterized.TestCase): model.build((None, 10)) self.assertTrue(model.built) - self.assertTrue(model.layers[-1].built) self.assertEqual(len(model.weights), 8) @tf_test_util.run_in_graph_and_eager_modes diff --git a/tensorflow/python/keras/engine/training.py b/tensorflow/python/keras/engine/training.py index 4d3fffb25a..1094e549d7 100644 --- a/tensorflow/python/keras/engine/training.py +++ b/tensorflow/python/keras/engine/training.py @@ -1455,8 +1455,7 @@ class Model(Network): if self.__class__.__name__ == 'Sequential' and not self.built: if tensor_util.is_tensor(inputs): - input_shape = (None,) + tuple(inputs.get_shape().as_list()[1:]) - self.build(input_shape=input_shape) + input_shape = (None,) + tuple(inputs.shape.as_list()[1:]) elif isinstance(inputs, dict): # We assert that the first layer is a FeatureLayer. if not training_utils.is_feature_layer(self.layers[0]): @@ -1464,10 +1463,9 @@ class Model(Network): 'which doesn\'t have FeatureLayer as the first layer' ' is an error.') input_shape = (None,) - self.build(input_shape=input_shape) else: - input_shape = (None,) + inputs.shape[1:] - self.build(input_shape=input_shape) + input_shape = (None,) + tuple(inputs.shape[1:]) + self._build_input_shape = input_shape # On-the-fly setting of symbolic model inputs (either by using the tensor # provided, or by creating a placeholder if Numpy data was provided). @@ -1486,6 +1484,8 @@ class Model(Network): self._feed_input_names.append(k) self._feed_input_shapes.append(K.int_shape(v)) + # TODO(fchollet): consider calling `_maybe_build` before calling the model. + if outputs is None: # Obtain symbolic outputs by calling the model. with K.get_graph().as_default(): diff --git a/tensorflow/python/keras/layers/local_test.py b/tensorflow/python/keras/layers/local_test.py index 2397a607da..1c20d43706 100644 --- a/tensorflow/python/keras/layers/local_test.py +++ b/tensorflow/python/keras/layers/local_test.py @@ -259,13 +259,16 @@ class LocallyConnectedImplementationModeTest(test.TestCase): 'kernel_size': kernel_x + kernel_y, 'strides': stride_x + stride_y, 'data_format': data_format, - 'num_classes': num_classes, - 'input_shape': inputs.shape + 'num_classes': num_classes } - model_1 = get_model(implementation=1, **kwargs) model_2 = get_model(implementation=2, **kwargs) + # Build models. + model_1.train_on_batch(inputs, targets) + model_2.train_on_batch(inputs, targets) + + # Copy weights. copy_model_weights(model_2, model_1) # Compare outputs at initialization. @@ -279,7 +282,6 @@ class LocallyConnectedImplementationModeTest(test.TestCase): y=targets, epochs=num_epochs, batch_size=num_samples) - model_2.fit(x=inputs, y=targets, epochs=num_epochs, @@ -289,7 +291,7 @@ class LocallyConnectedImplementationModeTest(test.TestCase): out_1 = model_1.call(inputs) out_2 = model_2.call(inputs) self.assertAllCloseAccordingToType(out_1, out_2, - rtol=1e-5, atol=1e-5) + atol=1e-4) @tf_test_util.run_in_graph_and_eager_modes def test_make_2d(self): @@ -366,8 +368,7 @@ def get_model(implementation, strides, layers, num_classes, - data_format, - input_shape): + data_format): model = keras.Sequential() if len(kernel_size) == 1: @@ -396,7 +397,6 @@ def get_model(implementation, metrics=[keras.metrics.categorical_accuracy], loss=xent ) - model.build(input_shape) return model diff --git a/tensorflow/python/keras/model_subclassing_test.py b/tensorflow/python/keras/model_subclassing_test.py index 87802d8df0..ccfff57a3b 100644 --- a/tensorflow/python/keras/model_subclassing_test.py +++ b/tensorflow/python/keras/model_subclassing_test.py @@ -726,10 +726,41 @@ class ModelSubclassingTest(test.TestCase): _ = model.evaluate(x, y, verbose=0) self.assertEqual(len(model.weights), 16) - self.assertEqual( - len(model.non_trainable_weights), 4) + self.assertEqual(len(model.non_trainable_weights), 4) self.assertEqual(len(model.trainable_weights), 12) + def test_subclass_nested_in_sequential(self): + num_classes = 2 + num_samples = 100 + input_dim = 50 + + class Inner(keras.Model): + + def __init__(self): + super(Inner, self).__init__() + self.dense1 = keras.layers.Dense(32, activation='relu') + self.dense2 = keras.layers.Dense(num_classes, activation='relu') + self.bn = keras.layers.BatchNormalization() + + def call(self, inputs): + x = self.dense1(inputs) + x = self.dense2(x) + return self.bn(x) + + model = keras.Sequential([Inner()]) + model.compile(loss='mse', + optimizer=RMSPropOptimizer(learning_rate=0.001), + metrics=['acc']) + + x = np.ones((num_samples, input_dim)) + y = np.zeros((num_samples, num_classes)) + model.fit(x, y, epochs=2, batch_size=32, verbose=0) + _ = model.evaluate(x, y, verbose=0) + + self.assertEqual(len(model.weights), 8) + self.assertEqual(len(model.non_trainable_weights), 2) + self.assertEqual(len(model.trainable_weights), 6) + def test_support_for_manual_training_arg(self): # In most cases, the `training` argument is left unspecified, in which # case it defaults to value corresponding to the Model method being used @@ -1038,6 +1069,16 @@ class TrainingNoDefaultModel(keras.Model): return self.dense1(x) +class TrainingMaskingModel(keras.Model): + + def __init__(self): + super(TrainingMaskingModel, self).__init__() + self.dense1 = keras.layers.Dense(1) + + def call(self, x, training=False, mask=None): + return self.dense1(x) + + class CustomCallSignatureTests(test.TestCase): @test_util.run_in_graph_and_eager_modes @@ -1067,6 +1108,19 @@ class CustomCallSignatureTests(test.TestCase): 'has been properly built.')) self.assertTrue(model.built, 'Model should be built after calling `build`.') + @test_util.run_in_graph_and_eager_modes + def test_training_and_mask_args_call_build(self): + input_dim = 2 + + model = TrainingMaskingModel() + self.assertFalse(model.built, 'Model should not have been built') + self.assertFalse(model.weights, ('Model should have no weights since it ' + 'has not been built.')) + model.build((None, input_dim)) + self.assertTrue(model.weights, ('Model should have weights now that it ' + 'has been properly built.')) + self.assertTrue(model.built, 'Model should be built after calling `build`.') + @test_util.run_in_graph_and_eager_modes def test_custom_call_kwargs_and_build(self): first_input_shape = (2, 3) -- GitLab From b0c5cbd7bcec9f44df14bd0738d3bb1a434d9fa8 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Wed, 28 Nov 2018 12:18:18 -0800 Subject: [PATCH 470/672] Add doc generator script for TF2. This uses the stand-alone generator, in "tensroflow/docs", which can be pip-installed. This will make it possible to build the python api-docs docs from the tensorflow-pip installation without building tensorflow from scratch. PiperOrigin-RevId: 223213515 --- tensorflow/tools/docs/BUILD | 25 +++++-- tensorflow/tools/docs/generate2.py | 77 +++++++++++++++++++++ tensorflow/tools/docs/generate2_test.py | 39 +++++++++++ tensorflow/tools/docs/generate_1_0.py | 92 ------------------------- 4 files changed, 135 insertions(+), 98 deletions(-) create mode 100644 tensorflow/tools/docs/generate2.py create mode 100644 tensorflow/tools/docs/generate2_test.py delete mode 100644 tensorflow/tools/docs/generate_1_0.py diff --git a/tensorflow/tools/docs/BUILD b/tensorflow/tools/docs/BUILD index 1a53f24177..b072853a4e 100644 --- a/tensorflow/tools/docs/BUILD +++ b/tensorflow/tools/docs/BUILD @@ -142,17 +142,30 @@ py_test( ], ) -py_binary( - name = "generate_1_0", - srcs = ["generate_1_0.py"], +py_test( + name = "generate2_test", + srcs = ["generate2_test.py"], srcs_version = "PY2AND3", + tags = [ + "manual", + # No reason to run sanitizers or fastbuild for this test. + "noasan", + "nomsan", + "notsan", + "optonly", + ], deps = [ - ":generate_lib", - "//tensorflow:tensorflow_py", - "//tensorflow/python/debug:debug_py", + ":generate2", ], ) +py_binary( + name = "generate2", + srcs = ["generate2.py"], + srcs_version = "PY2AND3", + deps = ["//tensorflow:tensorflow_py"], +) + py_library( name = "py_guide_parser", srcs = ["py_guide_parser.py"], diff --git a/tensorflow/tools/docs/generate2.py b/tensorflow/tools/docs/generate2.py new file mode 100644 index 0000000000..3dfd0dca33 --- /dev/null +++ b/tensorflow/tools/docs/generate2.py @@ -0,0 +1,77 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +r"""A tool to generate api_docs for TensorFlow2. + +``` +python generate2.py --output_dir=/tmp/out +``` + +Requires a local installation of: + https://github.com/tensorflow/docs/tree/master/tools + tf-nightly-2.0-preview +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from os import path + +from absl import app +from absl import flags + +import tensorflow as tf + +from tensorflow_docs.api_generator import generate_lib + +FLAGS = flags.FLAGS + +flags.DEFINE_string( + "code_url_prefix", + "/code/stable/tensorflow/", + "A url to prepend to code paths when creating links to defining code") + +flags.DEFINE_string( + "output_dir", "/tmp/out", + "A directory, where the docs will be output to.") + + +def build_docs(output_dir, code_url_prefix): + """Build api docs for tensorflow v2. + + Args: + output_dir: A string path, where to put the files. + code_url_prefix: prefix for "Defined in" links. + """ + base_dir = path.dirname(tf.__file__) + doc_generator = generate_lib.DocGenerator( + root_title="TensorFlow 2.0 Preview", + py_modules=[("tf", tf)], + base_dir=base_dir, + search_hints=True, + code_url_prefix=code_url_prefix, + site_path="api_docs/") + + doc_generator.build(output_dir) + + +def main(argv): + del argv + build_docs(output_dir=FLAGS.output_dir, + code_url_prefix=FLAGS.code_url_prefix) + + +if __name__ == "__main__": + app.run(main) diff --git a/tensorflow/tools/docs/generate2_test.py b/tensorflow/tools/docs/generate2_test.py new file mode 100644 index 0000000000..774d45c536 --- /dev/null +++ b/tensorflow/tools/docs/generate2_test.py @@ -0,0 +1,39 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for tensorflow.tools.docs.generate2.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import shutil + +from tensorflow.python.platform import googletest +from tensorflow.tools.docs import generate2 + + +class Generate2Test(googletest.TestCase): + + def test_end_to_end(self): + output_dir = os.path.join(googletest.GetTempDir(), 'output') + if os.path.exists(output_dir): + shutil.rmtree(output_dir) + os.makedirs(output_dir) + generate2.build_docs(output_dir=output_dir, code_url_prefix='') + + +if __name__ == '__main__': + googletest.main() diff --git a/tensorflow/tools/docs/generate_1_0.py b/tensorflow/tools/docs/generate_1_0.py deleted file mode 100644 index f4384e0ced..0000000000 --- a/tensorflow/tools/docs/generate_1_0.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2015 The TensorFlow Authors. 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. -# ============================================================================== -"""Generate docs for the TensorFlow Python API.""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import os -import sys - -import tensorflow as tf - -from tensorflow.python import debug as tf_debug -from tensorflow.python.util import tf_inspect -from tensorflow.tools.docs import generate_lib - -if __name__ == '__main__': - doc_generator = generate_lib.DocGenerator() - doc_generator.add_output_dir_argument() - doc_generator.add_src_dir_argument() - - # This doc generator works on the TensorFlow codebase. Since this script lives - # at tensorflow/tools/docs, and all code is defined somewhere inside - # tensorflow/, we can compute the base directory (two levels up), which is - # valid unless we're trying to apply this to a different code base, or are - # moving the script around. - script_dir = os.path.dirname(tf_inspect.getfile(tf_inspect.currentframe())) - default_base_dir = os.path.join(script_dir, '..', '..') - doc_generator.add_base_dir_argument(default_base_dir) - - flags = doc_generator.parse_known_args() - - # tf_debug is not imported with tf, it's a separate module altogether - doc_generator.set_py_modules([('tf', tf), ('tfdbg', tf_debug)]) - - doc_generator.set_do_not_descend_map({ - 'tf': ['cli', 'lib', 'wrappers'], - 'tf.contrib': [ - 'compiler', - 'factorization', - 'grid_rnn', - 'labeled_tensor', - 'quantization', - 'session_bundle', - 'slim', - 'solvers', - 'specs', - 'tensor_forest', - 'tensorboard', - 'testing', - 'training', - 'tfprof', - ], - 'tf.contrib.bayesflow': [ - 'entropy', 'monte_carlo', 'special_math', - 'stochastic_gradient_estimators', 'stochastic_graph', - 'stochastic_tensor', 'stochastic_variables', 'variational_inference' - ], - 'tf.contrib.distributions': ['bijector'], - 'tf.contrib.ffmpeg': ['ffmpeg_ops'], - 'tf.contrib.graph_editor': [ - 'edit', 'match', 'reroute', 'subgraph', 'transform', 'select', 'util' - ], - 'tf.contrib.layers': ['feature_column', 'summaries'], - 'tf.contrib.learn': [ - 'datasets', - 'head', - 'graph_actions', - 'io', - 'models', - 'monitors', - 'ops', - 'preprocessing', - 'utils', - ], - 'tf.contrib.util': ['loader'], - }) - - sys.exit(doc_generator.build(flags)) -- GitLab From 8bfd68f96fdafbe378f36cab827d950ec198d2b4 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 28 Nov 2018 12:22:45 -0800 Subject: [PATCH 471/672] Change API for string_to_hash_* API for TF 2.0. PiperOrigin-RevId: 223214232 --- .../api_def_StringToHashBucket.pbtxt | 8 +-- .../python_api/api_def_StringToNumber.pbtxt | 8 +-- .../ops/ragged/ragged_elementwise_ops.py | 2 +- tensorflow/python/ops/string_ops.py | 51 +++++++++++++++++++ .../api/golden/v2/tensorflow.strings.pbtxt | 4 +- tensorflow/tools/compatibility/renames_v2.py | 4 +- .../tools/compatibility/tf_upgrade_v2.py | 18 +++++++ 7 files changed, 76 insertions(+), 19 deletions(-) diff --git a/tensorflow/core/api_def/python_api/api_def_StringToHashBucket.pbtxt b/tensorflow/core/api_def/python_api/api_def_StringToHashBucket.pbtxt index cf0b8831ef..dc4493c841 100644 --- a/tensorflow/core/api_def/python_api/api_def_StringToHashBucket.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_StringToHashBucket.pbtxt @@ -1,10 +1,4 @@ op { graph_op_name: "StringToHashBucket" - endpoint { - name: "strings.to_hash_bucket" - } - endpoint { - name: "string_to_hash_bucket" - deprecation_version: 2 - } + visibility: HIDDEN } diff --git a/tensorflow/core/api_def/python_api/api_def_StringToNumber.pbtxt b/tensorflow/core/api_def/python_api/api_def_StringToNumber.pbtxt index 155dd26750..9c89d02fb7 100644 --- a/tensorflow/core/api_def/python_api/api_def_StringToNumber.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_StringToNumber.pbtxt @@ -1,10 +1,4 @@ op { graph_op_name: "StringToNumber" - endpoint { - name: "strings.to_number" - } - endpoint { - name: "string_to_number" - deprecation_version: 2 - } + visibility: HIDDEN } diff --git a/tensorflow/python/ops/ragged/ragged_elementwise_ops.py b/tensorflow/python/ops/ragged/ragged_elementwise_ops.py index 23d0e8b5fc..edf721b5a7 100644 --- a/tensorflow/python/ops/ragged/ragged_elementwise_ops.py +++ b/tensorflow/python/ops/ragged/ragged_elementwise_ops.py @@ -348,7 +348,7 @@ _TF_ELEMENTWISE_OPS = [ (string_ops.regex_replace, 'input'), (string_ops.string_join, '[inputs]'), (string_ops.string_strip, 'input'), - (string_ops.string_to_hash_bucket, 'string_tensor'), + (string_ops.string_to_hash_bucket, 'input'), (string_ops.string_to_hash_bucket_fast, 'input'), (string_ops.string_to_hash_bucket_strong, 'input'), (string_ops.substr, 'input'), diff --git a/tensorflow/python/ops/string_ops.py b/tensorflow/python/ops/string_ops.py index b2090da631..b6b329c486 100644 --- a/tensorflow/python/ops/string_ops.py +++ b/tensorflow/python/ops/string_ops.py @@ -28,6 +28,7 @@ from tensorflow.python.framework import ops from tensorflow.python.framework import sparse_tensor from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops +from tensorflow.python.ops import gen_parsing_ops from tensorflow.python.ops import gen_string_ops from tensorflow.python.ops import math_ops @@ -391,3 +392,53 @@ ops.NotDifferentiable("StringSplit") ops.NotDifferentiable("AsString") ops.NotDifferentiable("EncodeBase64") ops.NotDifferentiable("DecodeBase64") + + +@tf_export("strings.to_number", v1=[]) +def string_to_number(input, out_type=dtypes.float32, name=None): + r"""Converts each string in the input Tensor to the specified numeric type. + + (Note that int32 overflow results in an error while float overflow + results in a rounded value.) + + Args: + input: A `Tensor` of type `string`. + out_type: An optional `tf.DType` from: `tf.float32, tf.float64, tf.int32, + tf.int64`. Defaults to `tf.float32`. + The numeric type to interpret each string in `string_tensor` as. + name: A name for the operation (optional). + + Returns: + A `Tensor` of type `out_type`. + """ + return gen_parsing_ops.string_to_number(input, out_type, name) +tf_export(v1=["strings.to_number", "string_to_number"])( + gen_parsing_ops.string_to_number + ) + + +@tf_export("strings.to_hash_bucket", v1=[]) +def string_to_hash_bucket(input, num_buckets, name=None): + # pylint: disable=line-too-long + r"""Converts each string in the input Tensor to its hash mod by a number of buckets. + + The hash function is deterministic on the content of the string within the + process. + + Note that the hash function may change from time to time. + This functionality will be deprecated and it's recommended to use + `tf.string_to_hash_bucket_fast()` or `tf.string_to_hash_bucket_strong()`. + + Args: + input: A `Tensor` of type `string`. + num_buckets: An `int` that is `>= 1`. The number of buckets. + name: A name for the operation (optional). + + Returns: + A `Tensor` of type `int64`. + """ + # pylint: enable=line-too-long + return gen_string_ops.string_to_hash_bucket(input, num_buckets, name) +tf_export(v1=["strings.to_hash_bucket", "string_to_hash_bucket"])( + gen_string_ops.string_to_hash_bucket + ) diff --git a/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt index 2ccb3a4594..f2f4879fe8 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.strings.pbtxt @@ -38,7 +38,7 @@ tf_module { } member_method { name: "to_hash_bucket" - argspec: "args=[\'string_tensor\', \'num_buckets\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + argspec: "args=[\'input\', \'num_buckets\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "to_hash_bucket_fast" @@ -50,7 +50,7 @@ tf_module { } member_method { name: "to_number" - argspec: "args=[\'string_tensor\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " + argspec: "args=[\'input\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\"\", \'None\'], " } member_method { name: "unicode_script" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 042ca8adaa..319b0ba7c9 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -552,10 +552,10 @@ renames = { 'tf.squared_difference': 'tf.math.squared_difference', 'tf.string_join': 'tf.strings.join', 'tf.string_strip': 'tf.strings.strip', - 'tf.string_to_hash_bucket': 'tf.strings.to_hash_bucket', + 'tf.string_to_hash_bucket': 'tf.compat.v1.string_to_hash_bucket', 'tf.string_to_hash_bucket_fast': 'tf.strings.to_hash_bucket_fast', 'tf.string_to_hash_bucket_strong': 'tf.strings.to_hash_bucket_strong', - 'tf.string_to_number': 'tf.strings.to_number', + 'tf.string_to_number': 'tf.compat.v1.string_to_number', 'tf.summary.audio': 'tf.compat.v1.summary.audio', 'tf.summary.get_summary_description': 'tf.compat.v1.summary.get_summary_description', 'tf.summary.histogram': 'tf.compat.v1.summary.histogram', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 6e8d6e2d0b..af57211cad 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -183,6 +183,18 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.random.stateless_multinomial": { "output_dtype": "dtype", }, + "tf.string_to_number": { + "string_tensor": "input", + }, + "tf.strings.to_number": { + "string_tensor": "input", + }, + "tf.string_to_hash_bucket": { + "string_tensor": "input", + }, + "tf.strings.to_hash_bucket": { + "string_tensor": "input", + }, "tf.sparse.concat": [ "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" ], @@ -393,6 +405,10 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.sparse.concat", "tf.sparse_split": "tf.sparse.split", + "tf.string_to_hash_bucket": + "tf.strings.to_hash_bucket", + "tf.string_to_number": + "tf.strings.to_number", "tf.multinomial": "tf.random.categorical", "tf.random.multinomial": @@ -407,6 +423,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.math.confusion_matrix", "tf.train.confusion_matrix": "tf.math.confusion_matrix", + "tf.decode_csv": + "tf.io.decode_csv", }) # pylint: enable=line-too-long -- GitLab From 95f218770fe2dfd577625d803756fb9c9459bd6c Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Wed, 28 Nov 2018 12:27:46 -0800 Subject: [PATCH 472/672] Fix tflite makefile for new C glob path. Fixes #23926 Thanks @pglushkov for looking into this fix. PiperOrigin-RevId: 223214968 --- tensorflow/lite/tools/make/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/lite/tools/make/Makefile b/tensorflow/lite/tools/make/Makefile index 28374f13b7..06a1f36105 100644 --- a/tensorflow/lite/tools/make/Makefile +++ b/tensorflow/lite/tools/make/Makefile @@ -85,6 +85,7 @@ CORE_CC_ALL_SRCS := \ $(wildcard tensorflow/lite/*.cc) \ $(wildcard tensorflow/lite/*.c) \ $(wildcard tensorflow/lite/c/*.c) \ +$(wildcard tensorflow/lite/core/*.cc) \ $(wildcard tensorflow/lite/core/api/*.cc) ifneq ($(BUILD_TYPE),micro) CORE_CC_ALL_SRCS += \ -- GitLab From 9b9fb0c6cf857ec8924373150f36f5f8f0ad5806 Mon Sep 17 00:00:00 2001 From: Peter Ma Date: Wed, 28 Nov 2018 12:44:34 -0800 Subject: [PATCH 473/672] Add a simple guard for the case when the requested output port number is out of range of the num_outputs of the input node. PiperOrigin-RevId: 223217630 --- tensorflow/core/grappler/costs/graph_properties.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tensorflow/core/grappler/costs/graph_properties.cc b/tensorflow/core/grappler/costs/graph_properties.cc index 270b75269c..1df26d94d1 100644 --- a/tensorflow/core/grappler/costs/graph_properties.cc +++ b/tensorflow/core/grappler/costs/graph_properties.cc @@ -679,6 +679,11 @@ class SymbolicShapeRefiner { "' was not previously added to SymbolicShapeRefiner."); } + if (src_output >= c->inference_context->num_outputs()) + return errors::OutOfRange("src_output = ", src_output, + ", but num_outputs is only ", + c->inference_context->num_outputs()); + // Propagate input node's NodeContext info to the current node's // NodeContext: // output_tensor_protos to input_tensor_protos and input_tensors, and -- GitLab From 065c8648d694faa549c5b7bdf9787f4077fe0328 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 28 Nov 2018 12:50:08 -0800 Subject: [PATCH 474/672] Switch sigmoid to sin for tests which used an unsupported op (previously sigmoid) to break graph into multiple segments --- .../test/binary_tensor_weight_broadcast_test.py | 8 ++++++-- .../test/multi_connection_neighbor_engine_test.py | 12 +++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py index b53cb3c091..ed56226729 100644 --- a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py +++ b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py @@ -56,10 +56,14 @@ class BinaryTensorWeightBroadcastTest(trt_test.TfTrtIntegrationTestBase): ]: a = self._ConstOp(weights_shape) f = x + a - x = math_ops.sigmoid(f) + # sin is used to break the graph into separate segments since it is an + # unsupported op. + x = math_ops.sin(f) a = self._ConstOp(weights_shape) f = a + x - x = math_ops.sigmoid(f) + # sin is used to break the graph into separate segments since it is an + # unsupported op. + x = math_ops.sin(f) gen_array_ops.reshape(x, [5, -1], name=output_name) return trt_test.TfTrtIntegrationTestParams( gdef=g.as_graph_def(), diff --git a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py index 11be4feaf7..1bb4a02a49 100644 --- a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py +++ b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py @@ -60,14 +60,20 @@ class MultiConnectionNeighborEngineTest(trt_test.TfTrtIntegrationTestBase): b = constant_op.constant( np.random.normal(5.0, 1.0, [1, 4, 1, 1]), name="bias", dtype=dtype) q = conv - b - edge = math_ops.sigmoid(q) + # sin is used to break the graph into separate segments since it is an + # unsupported op. + edge = math_ops.sin(q) b = constant_op.constant( np.random.normal(5.0, 1.0, [1, 4, 1, 1]), name="bias", dtype=dtype) d = b + conv - edge3 = math_ops.sigmoid(d) + # sin is used to break the graph into separate segments since it is an + # unsupported op. + edge3 = math_ops.sin(d) - edge1 = gen_math_ops.tan(conv) + # sin is used to break the graph into separate segments since it is an + # unsupported op. + edge1 = math_ops.sin(conv) t = t - edge1 q = q + edge t = t + q -- GitLab From 49feaad5524dd259cb86637ec44228420440f8be Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 28 Nov 2018 13:03:18 -0800 Subject: [PATCH 475/672] Switch to self.trt_incompatible_op --- .../test/binary_tensor_weight_broadcast_test.py | 8 ++------ .../test/multi_connection_neighbor_engine_test.py | 12 +++--------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py index ed56226729..5ab94cd931 100644 --- a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py +++ b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py @@ -56,14 +56,10 @@ class BinaryTensorWeightBroadcastTest(trt_test.TfTrtIntegrationTestBase): ]: a = self._ConstOp(weights_shape) f = x + a - # sin is used to break the graph into separate segments since it is an - # unsupported op. - x = math_ops.sin(f) + x = self.trt_incompatible_op(f) a = self._ConstOp(weights_shape) f = a + x - # sin is used to break the graph into separate segments since it is an - # unsupported op. - x = math_ops.sin(f) + x = self.trt_incompatible_op(f) gen_array_ops.reshape(x, [5, -1], name=output_name) return trt_test.TfTrtIntegrationTestParams( gdef=g.as_graph_def(), diff --git a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py index 1bb4a02a49..468b2c96e1 100644 --- a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py +++ b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py @@ -60,20 +60,14 @@ class MultiConnectionNeighborEngineTest(trt_test.TfTrtIntegrationTestBase): b = constant_op.constant( np.random.normal(5.0, 1.0, [1, 4, 1, 1]), name="bias", dtype=dtype) q = conv - b - # sin is used to break the graph into separate segments since it is an - # unsupported op. - edge = math_ops.sin(q) + edge = self.trt_incompatible_op(q) b = constant_op.constant( np.random.normal(5.0, 1.0, [1, 4, 1, 1]), name="bias", dtype=dtype) d = b + conv - # sin is used to break the graph into separate segments since it is an - # unsupported op. - edge3 = math_ops.sin(d) + edge3 = self.trt_incompatible_op(d) - # sin is used to break the graph into separate segments since it is an - # unsupported op. - edge1 = math_ops.sin(conv) + edge1 = self.trt_incompatible_op(conv) t = t - edge1 q = q + edge t = t + q -- GitLab From f1f921f4c74e5d18d77476c873c600836443f137 Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Wed, 28 Nov 2018 13:36:14 -0800 Subject: [PATCH 476/672] Function optimizer documentation and tensor mapping. PiperOrigin-RevId: 223226824 --- .../grappler/optimizers/function_optimizer.cc | 216 ++++++++++-------- 1 file changed, 127 insertions(+), 89 deletions(-) diff --git a/tensorflow/core/grappler/optimizers/function_optimizer.cc b/tensorflow/core/grappler/optimizers/function_optimizer.cc index 22013ea2db..9faab6614c 100644 --- a/tensorflow/core/grappler/optimizers/function_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/function_optimizer.cc @@ -33,6 +33,7 @@ limitations under the License. #include "tensorflow/core/framework/op_def.pb.h" #include "tensorflow/core/framework/versions.pb.h" #include "tensorflow/core/graph/graph_constructor.h" +#include "tensorflow/core/graph/tensor_id.h" #include "tensorflow/core/grappler/grappler_item.h" #include "tensorflow/core/grappler/mutable_graph_view.h" #include "tensorflow/core/grappler/op_types.h" @@ -109,6 +110,28 @@ AttrSlice FunctionInstantiationAttributes(const FunctionDef& func, } } +class FakeCPUDevice : public Device { + public: + FakeCPUDevice(Env* env, const DeviceAttributes& attr) : Device(env, attr) {} + Status Sync() override { return Status::OK(); } +}; + +// -------------------------------------------------------------------------- // +// Function specialization. +// +// FunctionDef is somewhat similar to function template in C++, given all the +// type parameters (and attribute values) it generates a statically defined +// graph from the type parametrized "graph template" (function body). +// +// Function specialization instantiates a parametrized FunctionDef into a +// statically defined graph, and then converts it back to the fully defined +// FunctionDef (it doesn't have any unknown type parameters or attribute +// values, known as placeholders). +// +// Given the fully specified graph we can apply all the Grappler optimizers to +// it (see details in MetaOptimizer). Also we can push known constant inputs +// into the function body, and remove unused outputs/inputs. + // Specialized function instantiation type parameters, body parameters, and // const inputs. struct FunctionSpecializationSignature { @@ -208,12 +231,6 @@ struct FunctionSpecialization { std::vector> output_mapping; }; -class FakeCPUDevice : public Device { - public: - FakeCPUDevice(Env* env, const DeviceAttributes& attr) : Device(env, attr) {} - Status Sync() override { return Status::OK(); } -}; - class FunctionOptimizerContext { public: explicit FunctionOptimizerContext(RewriterConfig::Toggle opt_level, @@ -242,9 +259,9 @@ class FunctionOptimizerContext { return flr_; } - const gtl::FlatMap>>& - output_mappings() const { - return output_mappings_; + const gtl::FlatMap& + tensor_mapping() const { + return tensor_mapping_; } const GraphView& graph_view() const { return graph_view_; } @@ -275,20 +292,18 @@ class FunctionOptimizerContext { specialized_functions_.emplace(sig, specialized_func); } - void AddOutputMapping(const string& func_node, + void AddTensorMapping(const string& func_node, const FunctionSpecialization& specialized_func) { - output_mappings_.emplace(func_node, specialized_func.output_mapping); - } - - // Return true if we had any specialized function that changed it's output - // mapping, and it's required to update output consumers to new ports ids. - bool RequiresOutputMapping() const { - for (const auto& m1 : output_mappings_) { - for (const std::pair& m2 : m1.second) { - if (m2.first != m2.second) return true; + for (const auto& pair : specialized_func.output_mapping) { + int from_idx = pair.first; + int to_idx = pair.second; + if (from_idx != to_idx) { + SafeTensorId from_tensor(func_node, from_idx); + SafeTensorId to_tensor(func_node, to_idx); + auto inserted = tensor_mapping_.insert({from_tensor, to_tensor}); + DCHECK(inserted.second); } } - return false; } private: @@ -352,9 +367,15 @@ class FunctionOptimizerContext { gtl::FlatSet fetch_tensors_; // format: node_name:port gtl::FlatSet fetch_nodes_; // format: node_name - // Output mappings that have to be applied to the graph after all functions - // are specialized (node name -> output mappings). - gtl::FlatMap>> output_mappings_; + // After function inlining and specialization, the optimized graph might be in + // invalid state, nodes can read from non-existing function call nodes that + // were inlined, or they can read from output index that is no longer valid + // after unused outputs pruning. + // + // Tensor mapping that has to be applied to the graph after all functions + // optimizations (invalidated tensor id -> optimized graph tensor id). + gtl::FlatMap + tensor_mapping_; // Use graph view to find active outputs of the function caller nodes. GraphView graph_view_; @@ -378,49 +399,6 @@ const FunctionDef* FindFunctionCall(const FunctionOptimizerContext& ctx, return ctx.function_library().Find(node.op()); } -// Returns true iff `node` is a direct function call of `func`, and we know how -// to inline it into the main graph. -bool IsInlinableDirectFunctionCall(const FunctionOptimizerContext& ctx, - const FunctionDef& func, - const NodeDef& node) { - // Indirect function calls (PartitionedCallOp) have automatic control - // dependencies and inlined separately from direct function calls. - bool is_direct_function_call = IsDirectFunctionCall(func, node); - - // For direct function calls we insert IdentityN nodes before/after inlined - // function body to preserve function call semantics (all inputs evaluated - // before function evaluation starts, and all function body nodes finished - // before output consumed by other nodes). - bool has_inputs = func.signature().input_arg_size() > 0; - // TODO(ezhulenev): Relax constraint on output args? - bool has_outputs = func.signature().output_arg_size() > 0; - - // Function must execute all the nodes in a function body that might have side - // effects. After inlining these nodes into the main graph, we can no longer - // guarantee that. For now we disable inlining functions with side effects. - // - // Attaching control dependency to the output IdentityN node is not safe, - // because it might be split or pruned in a later optimization pass. - // - // Indirect function calls (via PartitionedCallOp) have automatic dependency - // tracking, and allow us to safely inline functions with side effects. - bool free_of_side_effects = - std::all_of(func.node_def().begin(), func.node_def().end(), - [&ctx](const NodeDef& node) { - return IsFreeOfSideEffect(node, &ctx.function_library()); - }); - - bool marked_noinline = MarkedNoInline(func); - bool marked_specialized = MarkedSpecialized(func); - - // We ignore `_noinline` marker in aggressive mode. - bool aggressive = ctx.opt_level() == RewriterConfig::AGGRESSIVE; - - return is_direct_function_call && has_inputs && has_outputs && - free_of_side_effects && !marked_specialized && - (!marked_noinline || aggressive); -} - gtl::FlatSet GetActiveOutputs(const NodeDef& node, const FunctionOptimizerContext& ctx, int size_hint = 0) { @@ -730,7 +708,7 @@ Status SpecializeFunction(const NodeDef& func_node, const FunctionDef& func, TF_RETURN_IF_ERROR(UpdateSpecializedFunctionNode( func, func_node, *already_specialized, specialized_func_node)); - ctx->AddOutputMapping(specialized_func_node->name(), *already_specialized); + ctx->AddTensorMapping(specialized_func_node->name(), *already_specialized); return Status::OK(); } @@ -792,11 +770,78 @@ Status SpecializeFunction(const NodeDef& func_node, const FunctionDef& func, func, func_node, func_specialization, specialized_func_node)); ctx->AddSpecializedFunction(signature, func_specialization); - ctx->AddOutputMapping(specialized_func_node->name(), func_specialization); + ctx->AddTensorMapping(specialized_func_node->name(), func_specialization); return Status::OK(); } +// -------------------------------------------------------------------------- // +// Inline direct functions calls. +// +// When we inline direct function calls, we instantiate the function body from +// its FunctionDef and caller node attributes, and embed the instantiated graph +// into the "main graph". When we do that, we must preserve the function call +// semantics: +// +// 1) All input nodes must be executed before any of function body nodes will +// start executing. +// 2) All function body nodes must be executed before any of the nodes, reading +// outputs of the function will start executing. +// 3) All nodes with side effects inside a function must be executed, this is +// different from the nodes with side effects in the main graph, that can be +// pruned if they are not in transitive dependency set of any of the fetch +// nodes. +// 4) All nodes of the function body must be execute on the device specified by +// the function caller node. +// +// To guarantee that function call semantics are preserved after inlining, we +// insert an IdentityN node before the inlined function body, and hook all +// inputs into that, and we insert another IdentityN node to hook all function +// outputs to it. + +// Returns true iff `node` is a direct function call of `func`, and we know how +// to inline it into the main graph. +bool IsInlinableDirectFunctionCall(const FunctionOptimizerContext& ctx, + const FunctionDef& func, + const NodeDef& node) { + // Indirect function calls (PartitionedCallOp) have automatic control + // dependencies and inlined separately from direct function calls. + bool is_direct_function_call = IsDirectFunctionCall(func, node); + + // For direct function calls we insert IdentityN nodes before/after inlined + // function body to preserve function call semantics (all inputs evaluated + // before function evaluation starts, and all function body nodes finished + // before output consumed by other nodes). + bool has_inputs = func.signature().input_arg_size() > 0; + // TODO(ezhulenev): Relax constraint on output args? + bool has_outputs = func.signature().output_arg_size() > 0; + + // Function must execute all the nodes in a function body that might have side + // effects. After inlining these nodes into the main graph, we can no longer + // guarantee that. For now we disable inlining functions with side effects. + // + // Attaching control dependency to the output IdentityN node is not safe, + // because it might be split or pruned in a later optimization pass. + // + // Indirect function calls (via PartitionedCallOp) have automatic dependency + // tracking, and allow us to safely inline functions with side effects. + bool free_of_side_effects = + std::all_of(func.node_def().begin(), func.node_def().end(), + [&ctx](const NodeDef& node) { + return IsFreeOfSideEffect(node, &ctx.function_library()); + }); + + bool marked_noinline = MarkedNoInline(func); + bool marked_specialized = MarkedSpecialized(func); + + // We ignore `_noinline` marker in aggressive mode. + bool aggressive = ctx.opt_level() == RewriterConfig::AGGRESSIVE; + + return is_direct_function_call && has_inputs && has_outputs && + free_of_side_effects && !marked_specialized && + (!marked_noinline || aggressive); +} + // Create an IdentityN node to hook the function inputs to: this ensures that // they're all evaluated before the evaluation of the function body starts. NodeDef InlinedFunctionInputsNode(const NodeDef& func_node, @@ -1141,27 +1186,20 @@ Status FunctionOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, #undef TF_SKIP_ERROR_IF_GRAPH_UNMODIFIED } - // Function specialization might change the number of function outputs, so we - // have to process the final optimized graph and update all the node mapping. - if (ctx.RequiresOutputMapping()) { - MutableGraphView optimized_graph_view(optimized_graph); - for (const auto& output_mapping : ctx.output_mappings()) { - const auto& node_name = output_mapping.first; - const auto& mappings = output_mapping.second; - - for (const std::pair& mapping : mappings) { - int from = mapping.first; - int to = mapping.second; - - // Get the output port corresponding to the old output position. - MutableGraphView::OutputPort from_port = - optimized_graph_view.GetOutputPort(node_name, from); - - // Update all input ports that read from old output port. - for (MutableGraphView::InputPort to_port : - optimized_graph_view.GetFanout(from_port)) { - *to_port.node->mutable_input(to_port.port_id) = - strings::StrCat(node_name, ":", to); + // After function specialization and inlining graph might be in invalid + // state, and some nodes can read tensors that do not exists anymore in the + // optimized graph: function call node was fully inlined into the graph, or + // output index was invalidated by the output pruning. + + if (!ctx.tensor_mapping().empty()) { + for (NodeDef& node : *optimized_graph->mutable_node()) { + for (int idx = 0; idx < node.input_size(); ++idx) { + TensorId input_tensor = ParseTensorName(node.input(idx)); + if (input_tensor.index() == Graph::kControlSlot) break; + + auto mapping = ctx.tensor_mapping().find(input_tensor); + if (mapping != ctx.tensor_mapping().end()) { + node.set_input(idx, mapping->second.ToString()); } } } -- GitLab From 3788915eab102422065e5c3ea1eabaafcd1a1f86 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 28 Nov 2018 13:40:02 -0800 Subject: [PATCH 477/672] [TF:XLA] Bump open source llvm revision to r347752 PiperOrigin-RevId: 223227528 --- tensorflow/workspace.bzl | 8 ++++---- third_party/llvm/llvm.autogenerated.BUILD | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index d9d40874a4..30694b43e3 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -472,11 +472,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "llvm", build_file = clean_dep("//third_party/llvm:llvm.autogenerated.BUILD"), - sha256 = "7b4f705c532ee2aafb6e8b9013ad22ec8bb1823a153cd2d6ddb6b7faef818874", - strip_prefix = "llvm-9ad322c7dfd4385be9a515d734f70700f192ebae", + sha256 = "6c9b98f745b1cf2a9ef34f6220d0f94620ee5c828151924299913f1822cd40d1", + strip_prefix = "llvm-9d5ac66dc1ff01dee56354344c9da0879f1bdc36", urls = [ - "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/9ad322c7dfd4385be9a515d734f70700f192ebae.tar.gz", - "https://github.com/llvm-mirror/llvm/archive/9ad322c7dfd4385be9a515d734f70700f192ebae.tar.gz", + "https://mirror.bazel.build/github.com/llvm-mirror/llvm/archive/9d5ac66dc1ff01dee56354344c9da0879f1bdc36.tar.gz", + "https://github.com/llvm-mirror/llvm/archive/9d5ac66dc1ff01dee56354344c9da0879f1bdc36.tar.gz", ], ) diff --git a/third_party/llvm/llvm.autogenerated.BUILD b/third_party/llvm/llvm.autogenerated.BUILD index 776935739a..eb468aa65f 100644 --- a/third_party/llvm/llvm.autogenerated.BUILD +++ b/third_party/llvm/llvm.autogenerated.BUILD @@ -823,6 +823,7 @@ cc_library( ]), copts = llvm_copts + ["-Iexternal/llvm/lib/Target/ARM"], deps = [ + ":arm_asm_printer", ":arm_desc", ":arm_info", ":arm_utils", @@ -2141,6 +2142,7 @@ cc_library( ":core", ":global_i_sel", ":mc", + ":profile_data", ":selection_dag", ":support", ":target", -- GitLab From 9316e38ef9cf53c88bc144f3ef5c9e4635427d66 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Wed, 28 Nov 2018 13:51:24 -0800 Subject: [PATCH 478/672] Fixing issues with the v2 script and the gfile API. PiperOrigin-RevId: 223229634 --- tensorflow/python/lib/io/file_io.py | 2 +- .../api/golden/v1/tensorflow.io.gfile.pbtxt | 2 +- .../api/golden/v2/tensorflow.io.gfile.pbtxt | 2 +- tensorflow/tools/compatibility/renames_v2.py | 15 ++++++++++-- .../tools/compatibility/tf_upgrade_v2.py | 24 +++++++++---------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/tensorflow/python/lib/io/file_io.py b/tensorflow/python/lib/io/file_io.py index 645cf8e95c..4caa5750bf 100644 --- a/tensorflow/python/lib/io/file_io.py +++ b/tensorflow/python/lib/io/file_io.py @@ -509,7 +509,7 @@ def rename(oldname, newname, overwrite=False): @tf_export("io.gfile.rename") -def rename_v2(src, dst, overwrite): +def rename_v2(src, dst, overwrite=False): """Rename or move a file / directory. Args: diff --git a/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt index e5aba7eff9..93d9b0fd75 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.io.gfile.pbtxt @@ -34,7 +34,7 @@ tf_module { } member_method { name: "rename" - argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=[\'False\'], " } member_method { name: "rmtree" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt index e5aba7eff9..93d9b0fd75 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.io.gfile.pbtxt @@ -34,7 +34,7 @@ tf_module { } member_method { name: "rename" - argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'src\', \'dst\', \'overwrite\'], varargs=None, keywords=None, defaults=[\'False\'], " } member_method { name: "rmtree" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 319b0ba7c9..70757556c1 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -94,13 +94,13 @@ renames = { 'tf.assign_sub': 'tf.compat.v1.assign_sub', 'tf.batch_to_space_nd': 'tf.compat.v1.batch_to_space_nd', 'tf.betainc': 'tf.math.betainc', - 'tf.bincount': 'tf.math.bincount', + 'tf.bincount': 'tf.compat.v1.bincount', 'tf.ceil': 'tf.math.ceil', 'tf.check_numerics': 'tf.debugging.check_numerics', 'tf.cholesky': 'tf.linalg.cholesky', 'tf.cholesky_solve': 'tf.linalg.cholesky_solve', 'tf.colocate_with': 'tf.compat.v1.colocate_with', - 'tf.confusion_matrix': 'tf.math.confusion_matrix', + 'tf.confusion_matrix': 'tf.compat.v1.confusion_matrix', 'tf.conj': 'tf.math.conj', 'tf.container': 'tf.compat.v1.container', 'tf.convert_to_tensor_or_indexed_slices': 'tf.compat.v1.convert_to_tensor_or_indexed_slices', @@ -299,6 +299,17 @@ renames = { 'tf.logging.warn': 'tf.compat.v1.logging.warn', 'tf.logging.warning': 'tf.compat.v1.logging.warning', 'tf.logical_xor': 'tf.math.logical_xor', + 'tf.losses.absolute_difference': 'tf.compat.v1.losses.absolute_difference', + 'tf.losses.compute_weighted_loss': 'tf.compat.v1.losses.compute_weighted_loss', + 'tf.losses.cosine_distance': 'tf.compat.v1.losses.cosine_distance', + 'tf.losses.hinge_loss': 'tf.compat.v1.losses.hinge_loss', + 'tf.losses.huber_loss': 'tf.compat.v1.losses.huber_loss', + 'tf.losses.log_loss': 'tf.compat.v1.losses.log_loss', + 'tf.losses.mean_pairwise_squared_error': 'tf.compat.v1.losses.mean_pairwise_squared_error', + 'tf.losses.mean_squared_error': 'tf.compat.v1.losses.mean_squared_error', + 'tf.losses.sigmoid_cross_entropy': 'tf.compat.v1.losses.sigmoid_cross_entropy', + 'tf.losses.softmax_cross_entropy': 'tf.compat.v1.losses.softmax_cross_entropy', + 'tf.losses.sparse_softmax_cross_entropy': 'tf.compat.v1.losses.sparse_softmax_cross_entropy', 'tf.make_template': 'tf.compat.v1.make_template', 'tf.make_tensor_proto': 'tf.compat.v1.make_tensor_proto', 'tf.manip.batch_to_space_nd': 'tf.compat.v1.manip.batch_to_space_nd', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index af57211cad..b63e0b0a1b 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -286,29 +286,29 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.batch_to_space_nd": "tf.batch_to_space", "tf.gfile.Copy": - "tf.io.gfile.Copy", + "tf.io.gfile.copy", "tf.gfile.DeleteRecursively": - "tf.io.gfile.DeleteRecursively", + "tf.io.gfile.rmtree", "tf.gfile.Exists": - "tf.io.gfile.Exists", + "tf.io.gfile.exists", "tf.gfile.Glob": - "tf.io.gfile.Glob", + "tf.io.gfile.glob", "tf.gfile.IsDirectory": - "tf.io.gfile.IsDirectory", + "tf.io.gfile.isdir", "tf.gfile.ListDirectory": - "tf.io.gfile.ListDirectory", + "tf.io.gfile.listdir", "tf.gfile.MakeDirs": - "tf.io.gfile.MakeDirs", + "tf.io.gfile.makedirs", "tf.gfile.MkDir": - "tf.io.gfile.MkDir", + "tf.io.gfile.mkdir", "tf.gfile.Remove": - "tf.io.gfile.Remove", + "tf.io.gfile.remove", "tf.gfile.Rename": - "tf.io.gfile.Rename", + "tf.io.gfile.rename", "tf.gfile.Stat": - "tf.io.gfile.Stat", + "tf.io.gfile.stat", "tf.gfile.Walk": - "tf.io.gfile.Walk", + "tf.io.gfile.walk", "tf.contrib.data.AUTOTUNE": "tf.data.experimental.AUTOTUNE", "tf.contrib.data.Counter": -- GitLab From 15b43008238cc3c9dc81d31ae3997b582ea190b1 Mon Sep 17 00:00:00 2001 From: Pavithra Vijay Date: Wed, 28 Nov 2018 14:02:54 -0800 Subject: [PATCH 479/672] Add `reset_states` function to confusion matrix metrics. PiperOrigin-RevId: 223231590 --- tensorflow/python/keras/metrics.py | 21 +++++ tensorflow/python/keras/metrics_test.py | 116 ++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index b74b6ccf5e..0519493a0a 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -25,6 +25,7 @@ import sys import types import weakref from enum import Enum +import numpy as np import six from tensorflow.python.eager import context @@ -900,6 +901,11 @@ class _ConfusionMatrixConditionCount(Metric): result = self.accumulator[0] return ops.convert_to_tensor(result) + def reset_states(self): + num_thresholds = len(to_list(self.thresholds)) + for v in self.variables: + K.set_value(v, np.zeros((num_thresholds,))) + @tf_export('metrics.FalsePositives', 'keras.metrics.FalsePositives') class FalsePositives(_ConfusionMatrixConditionCount): @@ -1180,6 +1186,11 @@ class Precision(Metric): result = math_ops.div_no_nan(self.tp, self.tp + self.fp) return result if isinstance(self.thresholds, (list, tuple)) else result[0] + def reset_states(self): + num_thresholds = len(to_list(self.thresholds)) + for v in self.variables: + K.set_value(v, np.zeros((num_thresholds,))) + @tf_export('metrics.Recall', 'keras.metrics.Recall') class Recall(Metric): @@ -1260,6 +1271,11 @@ class Recall(Metric): result = math_ops.div_no_nan(self.tp, self.tp + self.fn) return result if isinstance(self.thresholds, (list, tuple)) else result[0] + def reset_states(self): + num_thresholds = len(to_list(self.thresholds)) + for v in self.variables: + K.set_value(v, np.zeros((num_thresholds,))) + @six.add_metaclass(abc.ABCMeta) class SensitivitySpecificityBase(Metric): @@ -1319,6 +1335,11 @@ class SensitivitySpecificityBase(Metric): _ConfusionMatrix.FALSE_NEGATIVES: self.fn, }, y_true, y_pred, self.thresholds, sample_weight) + def reset_states(self): + num_thresholds = len(self.thresholds) + for v in self.variables: + K.set_value(v, np.zeros((num_thresholds,))) + class SensitivityAtSpecificity(SensitivitySpecificityBase): """Computes the sensitivity at a given specificity. diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index 40611a5d75..9a88391dc1 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -28,13 +28,16 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.keras import backend as K +from tensorflow.python.keras import layers from tensorflow.python.keras import metrics +from tensorflow.python.keras.models import Sequential from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops from tensorflow.python.ops import variables from tensorflow.python.platform import test from tensorflow.python.training.checkpointable import util as checkpointable_utils +from tensorflow.python.training.rmsprop import RMSPropOptimizer class KerasMetricsTest(test.TestCase): @@ -367,6 +370,19 @@ class KerasMetricsTest(test.TestCase): self.assertAlmostEqual(result, 0.93, 2) # 2.5/2.7 +def _get_simple_sequential_model(compile_metrics): + model = Sequential() + model.add( + layers.Dense( + 3, activation='relu', input_dim=4, kernel_initializer='ones')) + model.add(layers.Dense(1, activation='sigmoid', kernel_initializer='ones')) + model.compile( + loss='mae', + metrics=compile_metrics, + optimizer=RMSPropOptimizer(learning_rate=0.001)) + return model + + @test_util.run_all_in_graph_and_eager_modes class FalsePositivesTest(test.TestCase): @@ -435,6 +451,16 @@ class FalsePositivesTest(test.TestCase): r'Threshold values must be in \[0, 1\]. Invalid values: \[-1, 2\]'): metrics.FalsePositives(thresholds=[-1, 0.5, 2]) + def test_reset_states(self): + fp_obj = metrics.FalsePositives() + model = _get_simple_sequential_model([fp_obj]) + x = np.ones((100, 4)) + y = np.zeros((100, 1)) + model.evaluate(x, y) + self.assertEqual(self.evaluate(fp_obj.accumulator), 100.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(fp_obj.accumulator), 100.) + @test_util.run_all_in_graph_and_eager_modes class FalseNegativesTest(test.TestCase): @@ -497,6 +523,16 @@ class FalseNegativesTest(test.TestCase): result = fn_obj(y_true, y_pred, sample_weight=sample_weight) self.assertAllClose([4., 16., 23.], self.evaluate(result)) + def test_reset_states(self): + fn_obj = metrics.FalseNegatives() + model = _get_simple_sequential_model([fn_obj]) + x = np.zeros((100, 4)) + y = np.ones((100, 1)) + model.evaluate(x, y) + self.assertEqual(self.evaluate(fn_obj.accumulator), 100.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(fn_obj.accumulator), 100.) + @test_util.run_all_in_graph_and_eager_modes class TrueNegativesTest(test.TestCase): @@ -559,6 +595,16 @@ class TrueNegativesTest(test.TestCase): result = tn_obj(y_true, y_pred, sample_weight=sample_weight) self.assertAllClose([5., 15., 23.], self.evaluate(result)) + def test_reset_states(self): + tn_obj = metrics.TrueNegatives() + model = _get_simple_sequential_model([tn_obj]) + x = np.zeros((100, 4)) + y = np.zeros((100, 1)) + model.evaluate(x, y) + self.assertEqual(self.evaluate(tn_obj.accumulator), 100.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(tn_obj.accumulator), 100.) + @test_util.run_all_in_graph_and_eager_modes class TruePositivesTest(test.TestCase): @@ -620,6 +666,16 @@ class TruePositivesTest(test.TestCase): result = tp_obj(y_true, y_pred, sample_weight=37.) self.assertAllClose([222., 111., 37.], self.evaluate(result)) + def test_reset_states(self): + tp_obj = metrics.TruePositives() + model = _get_simple_sequential_model([tp_obj]) + x = np.ones((100, 4)) + y = np.ones((100, 1)) + model.evaluate(x, y) + self.assertEqual(self.evaluate(tp_obj.accumulator), 100.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(tp_obj.accumulator), 100.) + @test_util.run_all_in_graph_and_eager_modes class PrecisionTest(test.TestCase): @@ -732,6 +788,18 @@ class PrecisionTest(test.TestCase): self.assertArrayNear([expected_precision, 0], self.evaluate(p_obj.result()), 1e-3) + def test_reset_states(self): + p_obj = metrics.Precision() + model = _get_simple_sequential_model([p_obj]) + x = np.concatenate((np.ones((50, 4)), np.ones((50, 4)))) + y = np.concatenate((np.ones((50, 1)), np.zeros((50, 1)))) + model.evaluate(x, y) + self.assertEqual(self.evaluate(p_obj.tp), 50.) + self.assertEqual(self.evaluate(p_obj.fp), 50.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(p_obj.tp), 50.) + self.assertEqual(self.evaluate(p_obj.fp), 50.) + @test_util.run_all_in_graph_and_eager_modes class RecallTest(test.TestCase): @@ -843,6 +911,18 @@ class RecallTest(test.TestCase): self.assertArrayNear([expected_recall, 0], self.evaluate(r_obj.result()), 1e-3) + def test_reset_states(self): + r_obj = metrics.Recall() + model = _get_simple_sequential_model([r_obj]) + x = np.concatenate((np.ones((50, 4)), np.zeros((50, 4)))) + y = np.concatenate((np.ones((50, 1)), np.ones((50, 1)))) + model.evaluate(x, y) + self.assertEqual(self.evaluate(r_obj.tp), 50.) + self.assertEqual(self.evaluate(r_obj.fn), 50.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(r_obj.tp), 50.) + self.assertEqual(self.evaluate(r_obj.fn), 50.) + @test_util.run_all_in_graph_and_eager_modes class SensitivityAtSpecificityTest(test.TestCase, parameterized.TestCase): @@ -932,6 +1012,24 @@ class SensitivityAtSpecificityTest(test.TestCase, parameterized.TestCase): with self.assertRaisesRegexp(ValueError, '`num_thresholds` must be > 0.'): metrics.SensitivityAtSpecificity(0.4, num_thresholds=-1) + def test_reset_states(self): + s_obj = metrics.SensitivityAtSpecificity(0.5, num_thresholds=1) + model = _get_simple_sequential_model([s_obj]) + x = np.concatenate((np.ones((25, 4)), np.zeros((25, 4)), np.zeros((25, 4)), + np.ones((25, 4)))) + y = np.concatenate((np.ones((25, 1)), np.zeros((25, 1)), np.ones((25, 1)), + np.zeros((25, 1)))) + model.evaluate(x, y) + self.assertEqual(self.evaluate(s_obj.tp), 25.) + self.assertEqual(self.evaluate(s_obj.fp), 25.) + self.assertEqual(self.evaluate(s_obj.fn), 25.) + self.assertEqual(self.evaluate(s_obj.tn), 25.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(s_obj.tp), 25.) + self.assertEqual(self.evaluate(s_obj.fp), 25.) + self.assertEqual(self.evaluate(s_obj.fn), 25.) + self.assertEqual(self.evaluate(s_obj.tn), 25.) + @test_util.run_all_in_graph_and_eager_modes class SpecificityAtSensitivityTest(test.TestCase, parameterized.TestCase): @@ -1021,6 +1119,24 @@ class SpecificityAtSensitivityTest(test.TestCase, parameterized.TestCase): with self.assertRaisesRegexp(ValueError, '`num_thresholds` must be > 0.'): metrics.SpecificityAtSensitivity(0.4, num_thresholds=-1) + def test_reset_states(self): + s_obj = metrics.SpecificityAtSensitivity(0.5, num_thresholds=1) + model = _get_simple_sequential_model([s_obj]) + x = np.concatenate((np.ones((25, 4)), np.zeros((25, 4)), np.zeros((25, 4)), + np.ones((25, 4)))) + y = np.concatenate((np.ones((25, 1)), np.zeros((25, 1)), np.ones((25, 1)), + np.zeros((25, 1)))) + model.evaluate(x, y) + self.assertEqual(self.evaluate(s_obj.tp), 25.) + self.assertEqual(self.evaluate(s_obj.fp), 25.) + self.assertEqual(self.evaluate(s_obj.fn), 25.) + self.assertEqual(self.evaluate(s_obj.tn), 25.) + model.evaluate(x, y) + self.assertEqual(self.evaluate(s_obj.tp), 25.) + self.assertEqual(self.evaluate(s_obj.fp), 25.) + self.assertEqual(self.evaluate(s_obj.fn), 25.) + self.assertEqual(self.evaluate(s_obj.tn), 25.) + if __name__ == '__main__': test.main() -- GitLab From a04691962177976c60aba998f477f5a8165451ed Mon Sep 17 00:00:00 2001 From: Michael Kuperstein Date: Wed, 28 Nov 2018 14:35:10 -0800 Subject: [PATCH 480/672] [XLA] Do not generate denormals when constructing no_duplicate bf16 literals PiperOrigin-RevId: 223237542 --- tensorflow/compiler/xla/tests/test_utils.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/xla/tests/test_utils.cc b/tensorflow/compiler/xla/tests/test_utils.cc index 8b4be6607f..eafa48ed7b 100644 --- a/tensorflow/compiler/xla/tests/test_utils.cc +++ b/tensorflow/compiler/xla/tests/test_utils.cc @@ -56,7 +56,8 @@ void PopulateWithIntNext(Literal* literal) { template <> void PopulateWithIntNext(Literal* literal) { // Duplicates may be generated if we don't have enough bits. - uint16 next_value = 0; + // Start at 0x80 rather than 0 to avoid denormals. + uint16 next_value = 0x80; for (bfloat16& value : literal->data()) { // Zero-out the MSB of the exponent to avoid Infs and NaNs, and put it into // the sign bit. We could be less wasteful, but this is best-effort anyway. -- GitLab From 2185cf1ba8cc0ce72624d43f90c21feb96d6d1a0 Mon Sep 17 00:00:00 2001 From: Sachin Joglekar Date: Wed, 28 Nov 2018 14:37:50 -0800 Subject: [PATCH 481/672] Adds string support in Java API Fixes #21213. PiperOrigin-RevId: 223238001 --- .../java/org/tensorflow/lite/DataType.java | 9 +- .../main/java/org/tensorflow/lite/Tensor.java | 2 + tensorflow/lite/java/src/main/native/BUILD | 1 + .../native/nativeinterpreterwrapper_jni.cc | 2 + .../lite/java/src/main/native/tensor_jni.cc | 115 +++++++++++++++--- .../org/tensorflow/lite/DataTypeTest.java | 1 + .../lite/NativeInterpreterWrapperTest.java | 47 +++++++ tensorflow/lite/java/src/testdata/string.bin | Bin 0 -> 584 bytes 8 files changed, 160 insertions(+), 17 deletions(-) create mode 100644 tensorflow/lite/java/src/testdata/string.bin diff --git a/tensorflow/lite/java/src/main/java/org/tensorflow/lite/DataType.java b/tensorflow/lite/java/src/main/java/org/tensorflow/lite/DataType.java index 41093e8ffe..bd47574f71 100644 --- a/tensorflow/lite/java/src/main/java/org/tensorflow/lite/DataType.java +++ b/tensorflow/lite/java/src/main/java/org/tensorflow/lite/DataType.java @@ -27,7 +27,10 @@ public enum DataType { UINT8(3), /** 64-bit signed integer. */ - INT64(4); + INT64(4), + + /** Strings. */ + STRING(5); private final int value; @@ -46,6 +49,8 @@ public enum DataType { return 1; case INT64: return 8; + case STRING: + return -1; } throw new IllegalArgumentException( "DataType error: DataType " + this + " is not supported yet"); @@ -82,6 +87,8 @@ public enum DataType { return "byte"; case INT64: return "long"; + case STRING: + return "string"; } throw new IllegalArgumentException( "DataType error: DataType " + this + " is not supported yet"); diff --git a/tensorflow/lite/java/src/main/java/org/tensorflow/lite/Tensor.java b/tensorflow/lite/java/src/main/java/org/tensorflow/lite/Tensor.java index 6ca47aa3ed..7aa24b4198 100644 --- a/tensorflow/lite/java/src/main/java/org/tensorflow/lite/Tensor.java +++ b/tensorflow/lite/java/src/main/java/org/tensorflow/lite/Tensor.java @@ -162,6 +162,8 @@ public final class Tensor { return DataType.UINT8; } else if (long.class.equals(c)) { return DataType.INT64; + } else if (String.class.equals(c)) { + return DataType.STRING; } } throw new IllegalArgumentException( diff --git a/tensorflow/lite/java/src/main/native/BUILD b/tensorflow/lite/java/src/main/native/BUILD index 2abba24345..8f95f14518 100644 --- a/tensorflow/lite/java/src/main/native/BUILD +++ b/tensorflow/lite/java/src/main/native/BUILD @@ -43,6 +43,7 @@ cc_library( "//tensorflow/lite:context", "//tensorflow/lite:framework", "//tensorflow/lite:schema_fbs_version", + "//tensorflow/lite:string_util", ], alwayslink = 1, ) diff --git a/tensorflow/lite/java/src/main/native/nativeinterpreterwrapper_jni.cc b/tensorflow/lite/java/src/main/native/nativeinterpreterwrapper_jni.cc index c7389c5811..1e98f94250 100644 --- a/tensorflow/lite/java/src/main/native/nativeinterpreterwrapper_jni.cc +++ b/tensorflow/lite/java/src/main/native/nativeinterpreterwrapper_jni.cc @@ -78,6 +78,8 @@ int getDataType(TfLiteType data_type) { return 3; case kTfLiteInt64: return 4; + case kTfLiteString: + return 5; default: return -1; } diff --git a/tensorflow/lite/java/src/main/native/tensor_jni.cc b/tensorflow/lite/java/src/main/native/tensor_jni.cc index 1d813d50da..035bec6a44 100644 --- a/tensorflow/lite/java/src/main/native/tensor_jni.cc +++ b/tensorflow/lite/java/src/main/native/tensor_jni.cc @@ -16,8 +16,10 @@ limitations under the License. #include "tensorflow/lite/java/src/main/native/tensor_jni.h" #include #include +#include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/interpreter.h" #include "tensorflow/lite/java/src/main/native/exception_jni.h" +#include "tensorflow/lite/string_util.h" namespace { @@ -48,7 +50,7 @@ TfLiteTensor* GetTensorFromHandle(JNIEnv* env, jlong handle) { return reinterpret_cast(handle)->tensor(); } -size_t elementByteSize(TfLiteType data_type) { +size_t ElementByteSize(TfLiteType data_type) { // The code in this file makes the assumption that the // TensorFlow TF_DataTypes and the Java primitive types // have the same byte sizes. Validate that: @@ -77,11 +79,11 @@ size_t elementByteSize(TfLiteType data_type) { } } -size_t writeOneDimensionalArray(JNIEnv* env, jobject object, TfLiteType type, +size_t WriteOneDimensionalArray(JNIEnv* env, jobject object, TfLiteType type, void* dst, size_t dst_size) { jarray array = static_cast(object); const int num_elements = env->GetArrayLength(array); - size_t to_copy = num_elements * elementByteSize(type); + size_t to_copy = num_elements * ElementByteSize(type); if (to_copy > dst_size) { throwException(env, kIllegalStateException, "Internal error: cannot write Java array of %d bytes to " @@ -126,10 +128,10 @@ size_t writeOneDimensionalArray(JNIEnv* env, jobject object, TfLiteType type, } } -size_t readOneDimensionalArray(JNIEnv* env, TfLiteType data_type, +size_t ReadOneDimensionalArray(JNIEnv* env, TfLiteType data_type, const void* src, size_t src_size, jarray dst) { const int len = env->GetArrayLength(dst); - const size_t size = len * elementByteSize(data_type); + const size_t size = len * ElementByteSize(data_type); if (size > src_size) { throwException( env, kIllegalStateException, @@ -170,17 +172,17 @@ size_t readOneDimensionalArray(JNIEnv* env, TfLiteType data_type, return 0; } -size_t readMultiDimensionalArray(JNIEnv* env, TfLiteType data_type, char* src, +size_t ReadMultiDimensionalArray(JNIEnv* env, TfLiteType data_type, char* src, size_t src_size, int dims_left, jarray dst) { if (dims_left == 1) { - return readOneDimensionalArray(env, data_type, src, src_size, dst); + return ReadOneDimensionalArray(env, data_type, src, src_size, dst); } else { jobjectArray ndarray = static_cast(dst); int len = env->GetArrayLength(ndarray); size_t size = 0; for (int i = 0; i < len; ++i) { jarray row = static_cast(env->GetObjectArrayElement(ndarray, i)); - size += readMultiDimensionalArray(env, data_type, src + size, + size += ReadMultiDimensionalArray(env, data_type, src + size, src_size - size, dims_left - 1, row); env->DeleteLocalRef(row); if (env->ExceptionCheck()) return size; @@ -189,10 +191,43 @@ size_t readMultiDimensionalArray(JNIEnv* env, TfLiteType data_type, char* src, } } -size_t writeMultiDimensionalArray(JNIEnv* env, jobject src, TfLiteType type, +// Returns the total number of strings read. +int ReadMultiDimensionalStringArray(JNIEnv* env, TfLiteTensor* tensor, + int dims_left, int start_str_index, + jarray dst) { + jobjectArray object_array = static_cast(dst); + int len = env->GetArrayLength(object_array); + int num_strings_read = 0; + + // If dst is a 1-dimensional array, copy the strings into it. Else + // recursively call ReadMultiDimensionalStringArray over sub-dimensions. + if (dims_left == 1) { + for (int i = 0; i < len; ++i) { + const tflite::StringRef strref = + tflite::GetString(tensor, start_str_index + num_strings_read); + jstring string_dest = env->NewStringUTF(strref.str); + env->SetObjectArrayElement(object_array, i, string_dest); + env->DeleteLocalRef(string_dest); + ++num_strings_read; + } + } else { + for (int i = 0; i < len; ++i) { + jarray row = + static_cast(env->GetObjectArrayElement(object_array, i)); + num_strings_read += ReadMultiDimensionalStringArray( + env, tensor, dims_left - 1, start_str_index + num_strings_read, row); + env->DeleteLocalRef(row); + if (env->ExceptionCheck()) return num_strings_read; + } + } + + return num_strings_read; +} + +size_t WriteMultiDimensionalArray(JNIEnv* env, jobject src, TfLiteType type, int dims_left, char** dst, int dst_size) { if (dims_left <= 1) { - return writeOneDimensionalArray(env, src, type, *dst, dst_size); + return WriteOneDimensionalArray(env, src, type, *dst, dst_size); } else { jobjectArray ndarray = static_cast(src); int len = env->GetArrayLength(ndarray); @@ -200,7 +235,7 @@ size_t writeMultiDimensionalArray(JNIEnv* env, jobject src, TfLiteType type, for (int i = 0; i < len; ++i) { jobject row = env->GetObjectArrayElement(ndarray, i); char* next_dst = *dst + sz; - sz += writeMultiDimensionalArray(env, row, type, dims_left - 1, &next_dst, + sz += WriteMultiDimensionalArray(env, row, type, dims_left - 1, &next_dst, dst_size - sz); env->DeleteLocalRef(row); if (env->ExceptionCheck()) return sz; @@ -209,6 +244,44 @@ size_t writeMultiDimensionalArray(JNIEnv* env, jobject src, TfLiteType type, } } +void PopulateStringDynamicBuffer(JNIEnv* env, jobject src, + tflite::DynamicBuffer* dst_buffer, + int dims_left) { + jobjectArray object_array = static_cast(src); + const int num_elements = env->GetArrayLength(object_array); + + // If src is a 1-dimensional array, add the strings into dst_buffer. Else + // recursively call populateStringDynamicBuffer over sub-dimensions. + if (dims_left <= 1) { + for (int i = 0; i < num_elements; ++i) { + jstring string_obj = + static_cast(env->GetObjectArrayElement(object_array, i)); + const char* chars = env->GetStringUTFChars(string_obj, nullptr); + // + 1 for terminating character. + const int byte_len = env->GetStringUTFLength(string_obj) + 1; + dst_buffer->AddString(chars, byte_len); + env->ReleaseStringUTFChars(string_obj, chars); + env->DeleteLocalRef(string_obj); + } + } else { + for (int i = 0; i < num_elements; ++i) { + jobject row = env->GetObjectArrayElement(object_array, i); + PopulateStringDynamicBuffer(env, row, dst_buffer, dims_left - 1); + env->DeleteLocalRef(row); + if (env->ExceptionCheck()) return; + } + } +} + +void WriteMultiDimensionalStringArray(JNIEnv* env, jobject src, + TfLiteTensor* tensor) { + tflite::DynamicBuffer dst_buffer; + PopulateStringDynamicBuffer(env, src, &dst_buffer, tensor->dims->size); + if (!env->ExceptionCheck()) { + dst_buffer.WriteToTensor(tensor); + } +} + } // namespace JNIEXPORT jlong JNICALL Java_org_tensorflow_lite_Tensor_create( @@ -266,8 +339,14 @@ Java_org_tensorflow_lite_Tensor_readMultiDimensionalArray(JNIEnv* env, "Internal error: Cannot copy empty/scalar Tensors."); return; } - readMultiDimensionalArray(env, tensor->type, tensor->data.raw, tensor->bytes, - num_dims, static_cast(value)); + if (tensor->type == kTfLiteString) { + ReadMultiDimensionalStringArray(env, tensor, num_dims, 0, + static_cast(value)); + } else { + ReadMultiDimensionalArray(env, tensor->type, tensor->data.raw, + tensor->bytes, num_dims, + static_cast(value)); + } } JNIEXPORT void JNICALL @@ -277,7 +356,7 @@ Java_org_tensorflow_lite_Tensor_writeMultiDimensionalArray(JNIEnv* env, jobject src) { TfLiteTensor* tensor = GetTensorFromHandle(env, handle); if (tensor == nullptr) return; - if (tensor->data.raw == nullptr) { + if (tensor->type != kTfLiteString && tensor->data.raw == nullptr) { throwException(env, kIllegalArgumentException, "Internal error: Target Tensor hasn't been allocated."); return; @@ -287,8 +366,12 @@ Java_org_tensorflow_lite_Tensor_writeMultiDimensionalArray(JNIEnv* env, "Internal error: Cannot copy empty/scalar Tensors."); return; } - writeMultiDimensionalArray(env, src, tensor->type, tensor->dims->size, - &tensor->data.raw, tensor->bytes); + if (tensor->type == kTfLiteString) { + WriteMultiDimensionalStringArray(env, src, tensor); + } else { + WriteMultiDimensionalArray(env, src, tensor->type, tensor->dims->size, + &tensor->data.raw, tensor->bytes); + } } JNIEXPORT jint JNICALL Java_org_tensorflow_lite_Tensor_dtype(JNIEnv* env, diff --git a/tensorflow/lite/java/src/test/java/org/tensorflow/lite/DataTypeTest.java b/tensorflow/lite/java/src/test/java/org/tensorflow/lite/DataTypeTest.java index 6d6417f895..8412ec0e9d 100644 --- a/tensorflow/lite/java/src/test/java/org/tensorflow/lite/DataTypeTest.java +++ b/tensorflow/lite/java/src/test/java/org/tensorflow/lite/DataTypeTest.java @@ -30,6 +30,7 @@ public final class DataTypeTest { assertThat(DataType.INT32.byteSize()).isEqualTo(4); assertThat(DataType.UINT8.byteSize()).isEqualTo(1); assertThat(DataType.INT64.byteSize()).isEqualTo(8); + assertThat(DataType.STRING.byteSize()).isEqualTo(-1); } @Test diff --git a/tensorflow/lite/java/src/test/java/org/tensorflow/lite/NativeInterpreterWrapperTest.java b/tensorflow/lite/java/src/test/java/org/tensorflow/lite/NativeInterpreterWrapperTest.java index 07d334c33b..b00efa77cb 100644 --- a/tensorflow/lite/java/src/test/java/org/tensorflow/lite/NativeInterpreterWrapperTest.java +++ b/tensorflow/lite/java/src/test/java/org/tensorflow/lite/NativeInterpreterWrapperTest.java @@ -43,6 +43,9 @@ public final class NativeInterpreterWrapperTest { private static final String BYTE_MODEL_PATH = "tensorflow/lite/java/src/testdata/uint8.bin"; + private static final String STRING_MODEL_PATH = + "tensorflow/lite/java/src/testdata/string.bin"; + private static final String QUANTIZED_MODEL_PATH = "tensorflow/lite/java/src/testdata/quantized.bin"; @@ -224,6 +227,50 @@ public final class NativeInterpreterWrapperTest { wrapper.close(); } + @Test + public void testRunWithString() { + NativeInterpreterWrapper wrapper = new NativeInterpreterWrapper(STRING_MODEL_PATH); + String[] oneD = {"s1", "s22", "s333"}; + String[][] twoD = {oneD, oneD, oneD, oneD, oneD, oneD, oneD, oneD}; + String[][][] threeD = {twoD, twoD, twoD, twoD, twoD, twoD, twoD, twoD}; + String[][][][] fourD = {threeD, threeD}; + Object[] inputs = {fourD}; + String[][][][] parsedOutputs = new String[2][4][4][12]; + Map outputs = new HashMap<>(); + outputs.put(0, parsedOutputs); + wrapper.run(inputs, outputs); + String[] outputOneD = parsedOutputs[0][0][0]; + String[] expected = { + "s1", "s22", "s333", "s1", "s22", "s333", "s1", "s22", "s333", "s1", "s22", "s333" + }; + assertThat(outputOneD).isEqualTo(expected); + wrapper.close(); + } + + @Test + public void testRunWithString_wrongShapeError() { + NativeInterpreterWrapper wrapper = new NativeInterpreterWrapper(STRING_MODEL_PATH); + String[] oneD = {"s1", "s22", "s333"}; + String[][] twoD = {oneD, oneD, oneD, oneD, oneD, oneD, oneD, oneD}; + String[][][] threeD = {twoD, twoD, twoD, twoD, twoD, twoD, twoD, twoD}; + String[][][][] fourD = {threeD, threeD}; + Object[] inputs = {fourD}; + String[][][][] parsedOutputs = new String[2][4][4][10]; + Map outputs = new HashMap<>(); + outputs.put(0, parsedOutputs); + try { + wrapper.run(inputs, outputs); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e) + .hasMessageThat() + .contains( + "Cannot copy between a TensorFlowLite tensor with shape [2, 4, 4, 12] and " + + "a Java object with shape [2, 4, 4, 10]"); + } + wrapper.close(); + } + @Test public void testRunWithByteBufferHavingBytes() { NativeInterpreterWrapper wrapper = new NativeInterpreterWrapper(BYTE_MODEL_PATH); diff --git a/tensorflow/lite/java/src/testdata/string.bin b/tensorflow/lite/java/src/testdata/string.bin new file mode 100644 index 0000000000000000000000000000000000000000..36a2509acdfa17841d0c128674e7b4e382ad00fc GIT binary patch literal 584 zcmb1OU|3JeSkj0_A6 z2@DJj{2+b)&i)F{`FUljMJ1^zdJHTK3=Ad=3=BF95IrFNihuwAhyDBiAH)`5U|?Wk zU;wKF@j>RE`1k++nScNP^Dv0OZ3l^i>=I#MVBlb2V31*i*bA~7gh6J2+*ZKAz_0^q zUflox{}~tAXYL2@ATi%W_!^U~up^9o8!7{K=Mfb9pV0hs~P z2eONSq23unGcX*2*ueyn2bl??RiI%4QqRl4zz~#LoRL_Nst+c?Zes)c7ZSc44D3kZ z3v(~Xe2{w$!0Iu>2xM-4X-Pq8Nqk9aUU7aASRD)4T##N+9Evc2NKovtGl1O1z#zf^ z3O@!020;)XB&)%|09FNZI|zgP4bl(7AT|R78v_Re3j-V2d`LWj)Pej4!k};isRhvx Mwd`QE3=9ln00k8^3;+NC literal 0 HcmV?d00001 -- GitLab From bbb81ea42831b244289a059de9e4be0203dc4c35 Mon Sep 17 00:00:00 2001 From: Francois Chollet Date: Wed, 28 Nov 2018 14:51:37 -0800 Subject: [PATCH 482/672] Clarify the display of the time taken per "step" in the progbar ("samples" or (gradient descent) "steps"). Also fix the issue where the progbar would sometime display "0.0001e-6us/step" PiperOrigin-RevId: 223240441 --- tensorflow/python/keras/callbacks.py | 3 ++- tensorflow/python/keras/utils/generic_utils.py | 12 +++++++----- .../golden/v1/tensorflow.keras.utils.-progbar.pbtxt | 2 +- .../golden/v2/tensorflow.keras.utils.-progbar.pbtxt | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/keras/callbacks.py b/tensorflow/python/keras/callbacks.py index 8223e795bc..3e3c087e3f 100644 --- a/tensorflow/python/keras/callbacks.py +++ b/tensorflow/python/keras/callbacks.py @@ -494,7 +494,8 @@ class ProgbarLogger(Callback): self.progbar = Progbar( target=self.target, verbose=self.verbose, - stateful_metrics=self.stateful_metrics) + stateful_metrics=self.stateful_metrics, + unit_name='step' if self.use_steps else 'sample') def on_batch_begin(self, batch, logs=None): if self.seen < self.target: diff --git a/tensorflow/python/keras/utils/generic_utils.py b/tensorflow/python/keras/utils/generic_utils.py index 375bd9d196..c331ce430b 100644 --- a/tensorflow/python/keras/utils/generic_utils.py +++ b/tensorflow/python/keras/utils/generic_utils.py @@ -319,14 +319,16 @@ class Progbar(object): will be displayed as-is. All others will be averaged by the progbar before display. interval: Minimum visual progress update interval (in seconds). + unit_name: Display name for step counts (usually "step" or "sample"). """ def __init__(self, target, width=30, verbose=1, interval=0.05, - stateful_metrics=None): + stateful_metrics=None, unit_name='step'): self.target = target self.width = width self.verbose = verbose self.interval = interval + self.unit_name = unit_name if stateful_metrics: self.stateful_metrics = set(stateful_metrics) else: @@ -425,12 +427,12 @@ class Progbar(object): info = ' - ETA: %s' % eta_format else: - if time_per_unit >= 1: - info += ' %.0fs/step' % time_per_unit + if time_per_unit >= 1 or time_per_unit == 0: + info += ' %.0fs/%s' % (time_per_unit, self.unit_name) elif time_per_unit >= 1e-3: - info += ' %.0fms/step' % (time_per_unit * 1e3) + info += ' %.0fms/%s' % (time_per_unit * 1e3, self.unit_name) else: - info += ' %.0fus/step' % (time_per_unit * 1e6) + info += ' %.0fus/%s' % (time_per_unit * 1e6, self.unit_name) for k in self._values_order: info += ' - %s:' % k diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.utils.-progbar.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.utils.-progbar.pbtxt index be4496e753..8177cc71ed 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.keras.utils.-progbar.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.utils.-progbar.pbtxt @@ -4,7 +4,7 @@ tf_class { is_instance: "" member_method { name: "__init__" - argspec: "args=[\'self\', \'target\', \'width\', \'verbose\', \'interval\', \'stateful_metrics\'], varargs=None, keywords=None, defaults=[\'30\', \'1\', \'0.05\', \'None\'], " + argspec: "args=[\'self\', \'target\', \'width\', \'verbose\', \'interval\', \'stateful_metrics\', \'unit_name\'], varargs=None, keywords=None, defaults=[\'30\', \'1\', \'0.05\', \'None\', \'step\'], " } member_method { name: "add" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.utils.-progbar.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.utils.-progbar.pbtxt index be4496e753..8177cc71ed 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.utils.-progbar.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.utils.-progbar.pbtxt @@ -4,7 +4,7 @@ tf_class { is_instance: "" member_method { name: "__init__" - argspec: "args=[\'self\', \'target\', \'width\', \'verbose\', \'interval\', \'stateful_metrics\'], varargs=None, keywords=None, defaults=[\'30\', \'1\', \'0.05\', \'None\'], " + argspec: "args=[\'self\', \'target\', \'width\', \'verbose\', \'interval\', \'stateful_metrics\', \'unit_name\'], varargs=None, keywords=None, defaults=[\'30\', \'1\', \'0.05\', \'None\', \'step\'], " } member_method { name: "add" -- GitLab From a7b3f17a16ea09195839ac0b88335dd783cbef76 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 14:56:02 -0800 Subject: [PATCH 483/672] Add parallel_iterations option to batch_jacobian and jacobian functions. PiperOrigin-RevId: 223241273 --- tensorflow/python/eager/backprop.py | 18 ++++++++++++++---- tensorflow/python/eager/backprop_test.py | 17 +++++++++++++++++ .../golden/v1/tensorflow.-gradient-tape.pbtxt | 4 ++-- .../golden/v2/tensorflow.-gradient-tape.pbtxt | 4 ++-- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/eager/backprop.py b/tensorflow/python/eager/backprop.py index 69d444a90e..29f9b2cda3 100644 --- a/tensorflow/python/eager/backprop.py +++ b/tensorflow/python/eager/backprop.py @@ -955,6 +955,7 @@ class GradientTape(object): target, sources, unconnected_gradients=UnconnectedGradients.NONE, + parallel_iterations=None, experimental_use_pfor=True): """Computes the jacobian using operations recorded in context of this tape. @@ -978,6 +979,8 @@ class GradientTape(object): alters the value which will be returned if the target and sources are unconnected. The possible values and effects are detailed in 'UnconnectedGradients' and it defaults to 'none'. + parallel_iterations: A knob to control how many iterations are dispatched + in parallel. This knob can be used to control the total memory usage. experimental_use_pfor: If true, vectorizes the jacobian computation. Else falls back to a sequential while_loop. Vectorization can sometimes fail or lead to excessive memory usage. This option can be used to disable @@ -1016,7 +1019,8 @@ class GradientTape(object): if experimental_use_pfor: try: - output = pfor_ops.pfor(loop_fn, target_size) + output = pfor_ops.pfor(loop_fn, target_size, + parallel_iterations=parallel_iterations) except ValueError as err: six.reraise( ValueError, @@ -1032,7 +1036,8 @@ class GradientTape(object): " to compute the jacobian with eager execution enabled and with " " experimental_use_pfor set to False.") output = pfor_ops.for_loop( - loop_fn, [target.dtype] * len(flat_sources), target_size) + loop_fn, [target.dtype] * len(flat_sources), target_size, + parallel_iterations=parallel_iterations) for i, out in enumerate(output): if out is not None: @@ -1049,6 +1054,7 @@ class GradientTape(object): target, source, unconnected_gradients=UnconnectedGradients.NONE, + parallel_iterations=None, experimental_use_pfor=True): """Computes and stacks per-example jacobians. @@ -1081,6 +1087,8 @@ class GradientTape(object): alters the value which will be returned if the target and sources are unconnected. The possible values and effects are detailed in 'UnconnectedGradients' and it defaults to 'none'. + parallel_iterations: A knob to control how many iterations are dispatched + in parallel. This knob can be used to control the total memory usage. experimental_use_pfor: If true, uses pfor for computing the Jacobian. Else uses a tf.while_loop. @@ -1127,7 +1135,8 @@ class GradientTape(object): if experimental_use_pfor: try: - output = pfor_ops.pfor(loop_fn, target_row_size) + output = pfor_ops.pfor(loop_fn, target_row_size, + parallel_iterations=parallel_iterations) except ValueError as err: six.reraise( ValueError, @@ -1142,7 +1151,8 @@ class GradientTape(object): "GradientTape must be created with persistent=True" " to compute the batch_jacobian with eager execution enabled and " " with experimental_use_pfor set to False.") - output = pfor_ops.for_loop(loop_fn, target.dtype, target_row_size) + output = pfor_ops.for_loop(loop_fn, target.dtype, target_row_size, + parallel_iterations=parallel_iterations) if output is None: return None output = array_ops.reshape(output, diff --git a/tensorflow/python/eager/backprop_test.py b/tensorflow/python/eager/backprop_test.py index 08553b9f27..3cec40a48f 100644 --- a/tensorflow/python/eager/backprop_test.py +++ b/tensorflow/python/eager/backprop_test.py @@ -1303,6 +1303,14 @@ class JacobianTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'No converter'): g.jacobian(y, x, experimental_use_pfor=True) + def test_parallel_iterations(self): + with backprop.GradientTape(persistent=True) as g: + x = constant_op.constant([[1., 2], [3, 4]]) + g.watch(x) + y = math_ops.matmul(x, x) + self.assertAllClose(g.jacobian(y, x, parallel_iterations=2), + g.jacobian(y, x, parallel_iterations=3)) + @test_util.run_all_in_graph_and_eager_modes class BatchJacobianTest(test.TestCase): @@ -1397,5 +1405,14 @@ class BatchJacobianTest(test.TestCase): with self.assertRaisesRegexp(ValueError, 'No converter'): g.batch_jacobian(y, x, experimental_use_pfor=True) + def test_parallel_iterations(self): + with backprop.GradientTape(persistent=True) as g: + x = constant_op.constant([[1., 2], [3, 4]]) + g.watch(x) + w = constant_op.constant([[1., 2, 3, 4], [5, 6, 7, 8]]) + y = math_ops.matmul(x, w) + self.assertAllClose(g.batch_jacobian(y, x, parallel_iterations=2), + g.batch_jacobian(y, x, parallel_iterations=3)) + if __name__ == '__main__': test.main() diff --git a/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt index e37d29995a..2299a009d3 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.-gradient-tape.pbtxt @@ -8,7 +8,7 @@ tf_class { } member_method { name: "batch_jacobian" - argspec: "args=[\'self\', \'target\', \'source\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + argspec: "args=[\'self\', \'target\', \'source\', \'unconnected_gradients\', \'parallel_iterations\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'None\', \'True\'], " } member_method { name: "gradient" @@ -16,7 +16,7 @@ tf_class { } member_method { name: "jacobian" - argspec: "args=[\'self\', \'target\', \'sources\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + argspec: "args=[\'self\', \'target\', \'sources\', \'unconnected_gradients\', \'parallel_iterations\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'None\', \'True\'], " } member_method { name: "reset" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt index e37d29995a..2299a009d3 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.-gradient-tape.pbtxt @@ -8,7 +8,7 @@ tf_class { } member_method { name: "batch_jacobian" - argspec: "args=[\'self\', \'target\', \'source\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + argspec: "args=[\'self\', \'target\', \'source\', \'unconnected_gradients\', \'parallel_iterations\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'None\', \'True\'], " } member_method { name: "gradient" @@ -16,7 +16,7 @@ tf_class { } member_method { name: "jacobian" - argspec: "args=[\'self\', \'target\', \'sources\', \'unconnected_gradients\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'True\'], " + argspec: "args=[\'self\', \'target\', \'sources\', \'unconnected_gradients\', \'parallel_iterations\', \'experimental_use_pfor\'], varargs=None, keywords=None, defaults=[\'UnconnectedGradients.NONE\', \'None\', \'True\'], " } member_method { name: "reset" -- GitLab From 36325c5234ba3a8449448d9fdabc82a73bb3a9a5 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 15:09:38 -0800 Subject: [PATCH 484/672] Don't create an automatic rename rule for any symbol with a manually-specified rename. PiperOrigin-RevId: 223243781 --- tensorflow/tools/compatibility/BUILD | 15 ++- tensorflow/tools/compatibility/renames_v2.py | 34 ++---- .../tools/compatibility/tf_upgrade_v2.py | 93 ++-------------- .../tools/compatibility/tf_upgrade_v2_main.py | 100 ++++++++++++++++++ tensorflow/tools/compatibility/update/BUILD | 1 + .../update/generate_v2_renames_map.py | 10 +- 6 files changed, 133 insertions(+), 120 deletions(-) create mode 100644 tensorflow/tools/compatibility/tf_upgrade_v2_main.py diff --git a/tensorflow/tools/compatibility/BUILD b/tensorflow/tools/compatibility/BUILD index a6574dac53..197fa75015 100644 --- a/tensorflow/tools/compatibility/BUILD +++ b/tensorflow/tools/compatibility/BUILD @@ -51,8 +51,8 @@ py_library( srcs_version = "PY2AND3", ) -py_binary( - name = "tf_upgrade_v2", +py_library( + name = "tf_upgrade_v2_lib", srcs = [ "renames_v2.py", "tf_upgrade_v2.py", @@ -61,6 +61,17 @@ py_binary( deps = [":ast_edits"], ) +py_binary( + name = "tf_upgrade_v2", + srcs = ["tf_upgrade_v2_main.py"], + main = "tf_upgrade_v2_main.py", + srcs_version = "PY2AND3", + deps = [ + ":ast_edits", + ":tf_upgrade_v2_lib", + ], +) + py_test( name = "tf_upgrade_v2_test", srcs = ["tf_upgrade_v2_test.py"], diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 70757556c1..8dbeb078b6 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -92,15 +92,12 @@ renames = { 'tf.assign': 'tf.compat.v1.assign', 'tf.assign_add': 'tf.compat.v1.assign_add', 'tf.assign_sub': 'tf.compat.v1.assign_sub', - 'tf.batch_to_space_nd': 'tf.compat.v1.batch_to_space_nd', 'tf.betainc': 'tf.math.betainc', - 'tf.bincount': 'tf.compat.v1.bincount', 'tf.ceil': 'tf.math.ceil', 'tf.check_numerics': 'tf.debugging.check_numerics', 'tf.cholesky': 'tf.linalg.cholesky', 'tf.cholesky_solve': 'tf.linalg.cholesky_solve', 'tf.colocate_with': 'tf.compat.v1.colocate_with', - 'tf.confusion_matrix': 'tf.compat.v1.confusion_matrix', 'tf.conj': 'tf.math.conj', 'tf.container': 'tf.compat.v1.container', 'tf.convert_to_tensor_or_indexed_slices': 'tf.compat.v1.convert_to_tensor_or_indexed_slices', @@ -110,6 +107,7 @@ renames = { 'tf.create_partitioned_variables': 'tf.compat.v1.create_partitioned_variables', 'tf.cross': 'tf.linalg.cross', 'tf.cumprod': 'tf.math.cumprod', + 'tf.data.Iterator': 'tf.compat.v1.data.Iterator', 'tf.debugging.is_finite': 'tf.math.is_finite', 'tf.debugging.is_inf': 'tf.math.is_inf', 'tf.debugging.is_nan': 'tf.math.is_nan', @@ -117,7 +115,6 @@ renames = { 'tf.debugging.is_strictly_increasing': 'tf.math.is_strictly_increasing', 'tf.decode_base64': 'tf.io.decode_base64', 'tf.decode_compressed': 'tf.io.decode_compressed', - 'tf.decode_csv': 'tf.compat.v1.decode_csv', 'tf.decode_json_example': 'tf.io.decode_json_example', 'tf.decode_raw': 'tf.io.decode_raw', 'tf.delete_session_tensor': 'tf.compat.v1.delete_session_tensor', @@ -180,21 +177,9 @@ renames = { 'tf.get_session_tensor': 'tf.compat.v1.get_session_tensor', 'tf.get_variable': 'tf.compat.v1.get_variable', 'tf.get_variable_scope': 'tf.compat.v1.get_variable_scope', - 'tf.gfile.Copy': 'tf.compat.v1.gfile.Copy', - 'tf.gfile.DeleteRecursively': 'tf.compat.v1.gfile.DeleteRecursively', - 'tf.gfile.Exists': 'tf.compat.v1.gfile.Exists', 'tf.gfile.FastGFile': 'tf.compat.v1.gfile.FastGFile', 'tf.gfile.GFile': 'tf.compat.v1.gfile.GFile', - 'tf.gfile.Glob': 'tf.compat.v1.gfile.Glob', - 'tf.gfile.IsDirectory': 'tf.compat.v1.gfile.IsDirectory', - 'tf.gfile.ListDirectory': 'tf.compat.v1.gfile.ListDirectory', - 'tf.gfile.MakeDirs': 'tf.compat.v1.gfile.MakeDirs', - 'tf.gfile.MkDir': 'tf.compat.v1.gfile.MkDir', 'tf.gfile.Open': 'tf.compat.v1.gfile.Open', - 'tf.gfile.Remove': 'tf.compat.v1.gfile.Remove', - 'tf.gfile.Rename': 'tf.compat.v1.gfile.Rename', - 'tf.gfile.Stat': 'tf.compat.v1.gfile.Stat', - 'tf.gfile.Walk': 'tf.compat.v1.gfile.Walk', 'tf.global_norm': 'tf.linalg.global_norm', 'tf.global_variables': 'tf.compat.v1.global_variables', 'tf.global_variables_initializer': 'tf.compat.v1.global_variables_initializer', @@ -274,7 +259,6 @@ renames = { 'tf.layers.separable_conv2d': 'tf.compat.v1.layers.separable_conv2d', 'tf.lbeta': 'tf.math.lbeta', 'tf.lgamma': 'tf.math.lgamma', - 'tf.load_file_system_library': 'tf.compat.v1.load_file_system_library', 'tf.local_variables': 'tf.compat.v1.local_variables', 'tf.local_variables_initializer': 'tf.compat.v1.local_variables_initializer', 'tf.log_sigmoid': 'tf.math.log_sigmoid', @@ -312,7 +296,6 @@ renames = { 'tf.losses.sparse_softmax_cross_entropy': 'tf.compat.v1.losses.sparse_softmax_cross_entropy', 'tf.make_template': 'tf.compat.v1.make_template', 'tf.make_tensor_proto': 'tf.compat.v1.make_tensor_proto', - 'tf.manip.batch_to_space_nd': 'tf.compat.v1.manip.batch_to_space_nd', 'tf.manip.gather_nd': 'tf.gather_nd', 'tf.manip.reshape': 'tf.reshape', 'tf.manip.reverse': 'tf.reverse', @@ -367,7 +350,6 @@ renames = { 'tf.min_max_variable_partitioner': 'tf.compat.v1.min_max_variable_partitioner', 'tf.model_variables': 'tf.compat.v1.model_variables', 'tf.moving_average_variables': 'tf.compat.v1.moving_average_variables', - 'tf.multinomial': 'tf.compat.v1.multinomial', 'tf.nn.bidirectional_dynamic_rnn': 'tf.compat.v1.nn.bidirectional_dynamic_rnn', 'tf.nn.conv3d_backprop_filter_v2': 'tf.nn.conv3d_backprop_filter', 'tf.nn.ctc_beam_search_decoder_v2': 'tf.nn.ctc_beam_search_decoder', @@ -376,6 +358,7 @@ renames = { 'tf.nn.depthwise_conv2d_native_backprop_filter': 'tf.nn.depthwise_conv2d_backprop_filter', 'tf.nn.depthwise_conv2d_native_backprop_input': 'tf.nn.depthwise_conv2d_backprop_input', 'tf.nn.dynamic_rnn': 'tf.compat.v1.nn.dynamic_rnn', + 'tf.nn.fused_batch_norm': 'tf.compat.v1.nn.fused_batch_norm', 'tf.nn.log_uniform_candidate_sampler': 'tf.random.log_uniform_candidate_sampler', 'tf.nn.quantized_avg_pool': 'tf.compat.v1.nn.quantized_avg_pool', 'tf.nn.quantized_conv2d': 'tf.compat.v1.nn.quantized_conv2d', @@ -417,10 +400,8 @@ renames = { 'tf.python_io.tf_record_iterator': 'tf.compat.v1.python_io.tf_record_iterator', 'tf.qr': 'tf.linalg.qr', 'tf.quantize': 'tf.quantization.quantize', - 'tf.quantize_v2': 'tf.compat.v1.quantize_v2', 'tf.quantized_concat': 'tf.quantization.quantized_concat', 'tf.random.get_seed': 'tf.compat.v1.random.get_seed', - 'tf.random.multinomial': 'tf.compat.v1.random.multinomial', 'tf.random.set_random_seed': 'tf.compat.v1.random.set_random_seed', 'tf.random.stateless_multinomial': 'tf.compat.v1.random.stateless_multinomial', 'tf.random_crop': 'tf.image.random_crop', @@ -540,7 +521,6 @@ renames = { 'tf.sparse_segment_sum': 'tf.compat.v1.sparse_segment_sum', 'tf.sparse_slice': 'tf.sparse.slice', 'tf.sparse_softmax': 'tf.sparse.softmax', - 'tf.sparse_split': 'tf.compat.v1.sparse_split', 'tf.sparse_tensor_dense_matmul': 'tf.sparse.sparse_dense_matmul', 'tf.sparse_tensor_to_dense': 'tf.sparse.to_dense', 'tf.sparse_to_dense': 'tf.compat.v1.sparse_to_dense', @@ -563,10 +543,8 @@ renames = { 'tf.squared_difference': 'tf.math.squared_difference', 'tf.string_join': 'tf.strings.join', 'tf.string_strip': 'tf.strings.strip', - 'tf.string_to_hash_bucket': 'tf.compat.v1.string_to_hash_bucket', 'tf.string_to_hash_bucket_fast': 'tf.strings.to_hash_bucket_fast', 'tf.string_to_hash_bucket_strong': 'tf.strings.to_hash_bucket_strong', - 'tf.string_to_number': 'tf.compat.v1.string_to_number', 'tf.summary.audio': 'tf.compat.v1.summary.audio', 'tf.summary.get_summary_description': 'tf.compat.v1.summary.get_summary_description', 'tf.summary.histogram': 'tf.compat.v1.summary.histogram', @@ -591,16 +569,16 @@ renames = { 'tf.to_int32': 'tf.compat.v1.to_int32', 'tf.to_int64': 'tf.compat.v1.to_int64', 'tf.trace': 'tf.linalg.trace', - 'tf.train.ChiefSessionCreator': 'tf.compat.v1.train.ChiefSessionCreator', - 'tf.train.MonitoredSession': 'tf.compat.v1.train.MonitoredSession', - 'tf.train.LooperThread': 'tf.compat.v1.train.LooperThread', 'tf.train.AdadeltaOptimizer': 'tf.compat.v1.train.AdadeltaOptimizer', 'tf.train.AdagradDAOptimizer': 'tf.compat.v1.train.AdagradDAOptimizer', 'tf.train.AdagradOptimizer': 'tf.compat.v1.train.AdagradOptimizer', 'tf.train.AdamOptimizer': 'tf.compat.v1.train.AdamOptimizer', + 'tf.train.ChiefSessionCreator': 'tf.compat.v1.train.ChiefSessionCreator', 'tf.train.FtrlOptimizer': 'tf.compat.v1.train.FtrlOptimizer', 'tf.train.GradientDescentOptimizer': 'tf.compat.v1.train.GradientDescentOptimizer', + 'tf.train.LooperThread': 'tf.compat.v1.train.LooperThread', 'tf.train.MomentumOptimizer': 'tf.compat.v1.train.MomentumOptimizer', + 'tf.train.MonitoredSession': 'tf.compat.v1.train.MonitoredSession', 'tf.train.MonitoredTrainingSession': 'tf.compat.v1.train.MonitoredTrainingSession', 'tf.train.NewCheckpointReader': 'tf.compat.v1.train.NewCheckpointReader', 'tf.train.Optimizer': 'tf.compat.v1.train.Optimizer', @@ -615,8 +593,8 @@ renames = { 'tf.train.SingularMonitoredSession': 'tf.compat.v1.train.SingularMonitoredSession', 'tf.train.Supervisor': 'tf.compat.v1.train.Supervisor', 'tf.train.SyncReplicasOptimizer': 'tf.compat.v1.train.SyncReplicasOptimizer', - 'tf.train.WorkerSessionCreator': 'tf.compat.v1.train.WorkerSessionCreator', 'tf.train.VocabInfo': 'tf.compat.v1.train.VocabInfo', + 'tf.train.WorkerSessionCreator': 'tf.compat.v1.train.WorkerSessionCreator', 'tf.train.add_queue_runner': 'tf.compat.v1.train.add_queue_runner', 'tf.train.assert_global_step': 'tf.compat.v1.train.assert_global_step', 'tf.train.basic_train_loop': 'tf.compat.v1.train.basic_train_loop', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index b63e0b0a1b..9e010cd7b9 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -18,8 +18,6 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import argparse - from tensorflow.tools.compatibility import ast_edits from tensorflow.tools.compatibility import renames_v2 @@ -275,14 +273,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): }, } - # Mapping from function to the new name of the function - self.symbol_renames = renames_v2.renames # pylint: disable=line-too-long # Add additional renames not in renames_v2.py here. # IMPORTANT: For the renames in here, if you also need to add to # function_reorders or function_keyword_renames, use the OLD function name. # These renames happen after the arguments have been processed. - self.symbol_renames.update({ + self.manual_symbol_renames = { "tf.batch_to_space_nd": "tf.batch_to_space", "tf.gfile.Copy": @@ -425,13 +421,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.math.confusion_matrix", "tf.decode_csv": "tf.io.decode_csv", - }) + } # pylint: enable=line-too-long - # For custom behavior and if auto-generate rename in renames_v2.py - # is incorrect, add the op name here to exclude it from renames_v2.py. - excluded_renames = [ - ] + # Mapping from function to the new name of the function + self.symbol_renames = renames_v2.renames + self.symbol_renames.update(self.manual_symbol_renames) # Variables that should be changed to functions. self.change_to_function = {} @@ -711,7 +706,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): self.symbol_renames = { name: new_name for name, new_name in self.symbol_renames.items() - if name not in self.function_warnings and name not in excluded_renames + if name not in self.function_warnings } export_saved_model_renamed = ( @@ -772,79 +767,3 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "", error="{} requires manual check.".format(name)) return _helper - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Convert a TensorFlow Python file to 2.0 - -Simple usage: - tf_upgrade_v2.py --infile foo.py --outfile bar.py - tf_upgrade_v2.py --intree ~/code/old --outtree ~/code/new -""") - parser.add_argument( - "--infile", - dest="input_file", - help="If converting a single file, the name of the file " - "to convert") - parser.add_argument( - "--outfile", - dest="output_file", - help="If converting a single file, the output filename.") - parser.add_argument( - "--intree", - dest="input_tree", - help="If converting a whole tree of files, the directory " - "to read from (relative or absolute).") - parser.add_argument( - "--outtree", - dest="output_tree", - help="If converting a whole tree of files, the output " - "directory (relative or absolute).") - parser.add_argument( - "--copyotherfiles", - dest="copy_other_files", - help=("If converting a whole tree of files, whether to " - "copy the other files."), - type=bool, - default=False) - parser.add_argument( - "--reportfile", - dest="report_filename", - help=("The name of the file where the report log is " - "stored." - "(default: %(default)s)"), - default="report.txt") - args = parser.parse_args() - - upgrade = ast_edits.ASTCodeUpgrader(TFAPIChangeSpec()) - report_text = None - report_filename = args.report_filename - files_processed = 0 - if args.input_file: - if not args.output_file: - raise ValueError( - "--outfile= argument is required when converting a " - "single file.") - files_processed, report_text, errors = upgrade.process_file( - args.input_file, args.output_file) - files_processed = 1 - elif args.input_tree: - if not args.output_tree: - raise ValueError( - "--outtree= argument is required when converting a " - "file tree.") - files_processed, report_text, errors = upgrade.process_tree( - args.input_tree, args.output_tree, args.copy_other_files) - else: - parser.print_help() - if report_text: - open(report_filename, "w").write(report_text) - print("TensorFlow 2.0 Upgrade Script") - print("-----------------------------") - print("Converted %d files\n" % files_processed) - print("Detected %d errors that require attention" % len(errors)) - print("-" * 80) - print("\n".join(errors)) - print("\nMake sure to read the detailed log %r\n" % report_filename) diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_main.py b/tensorflow/tools/compatibility/tf_upgrade_v2_main.py new file mode 100644 index 0000000000..498258dfa8 --- /dev/null +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_main.py @@ -0,0 +1,100 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Upgrader for Python scripts from 1.* TensorFlow to 2.0 TensorFlow.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import argparse + +from tensorflow.tools.compatibility import ast_edits +from tensorflow.tools.compatibility import tf_upgrade_v2 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Convert a TensorFlow Python file to 2.0 + +Simple usage: + tf_upgrade_v2.py --infile foo.py --outfile bar.py + tf_upgrade_v2.py --intree ~/code/old --outtree ~/code/new +""") + parser.add_argument( + "--infile", + dest="input_file", + help="If converting a single file, the name of the file " + "to convert") + parser.add_argument( + "--outfile", + dest="output_file", + help="If converting a single file, the output filename.") + parser.add_argument( + "--intree", + dest="input_tree", + help="If converting a whole tree of files, the directory " + "to read from (relative or absolute).") + parser.add_argument( + "--outtree", + dest="output_tree", + help="If converting a whole tree of files, the output " + "directory (relative or absolute).") + parser.add_argument( + "--copyotherfiles", + dest="copy_other_files", + help=("If converting a whole tree of files, whether to " + "copy the other files."), + type=bool, + default=False) + parser.add_argument( + "--reportfile", + dest="report_filename", + help=("The name of the file where the report log is " + "stored." + "(default: %(default)s)"), + default="report.txt") + args = parser.parse_args() + + upgrade = ast_edits.ASTCodeUpgrader(tf_upgrade_v2.TFAPIChangeSpec()) + report_text = None + report_filename = args.report_filename + files_processed = 0 + if args.input_file: + if not args.output_file: + raise ValueError( + "--outfile= argument is required when converting a " + "single file.") + files_processed, report_text, errors = upgrade.process_file( + args.input_file, args.output_file) + files_processed = 1 + elif args.input_tree: + if not args.output_tree: + raise ValueError( + "--outtree= argument is required when converting a " + "file tree.") + files_processed, report_text, errors = upgrade.process_tree( + args.input_tree, args.output_tree, args.copy_other_files) + else: + parser.print_help() + if report_text: + open(report_filename, "w").write(report_text) + print("TensorFlow 2.0 Upgrade Script") + print("-----------------------------") + print("Converted %d files\n" % files_processed) + print("Detected %d errors that require attention" % len(errors)) + print("-" * 80) + print("\n".join(errors)) + print("\nMake sure to read the detailed log %r\n" % report_filename) diff --git a/tensorflow/tools/compatibility/update/BUILD b/tensorflow/tools/compatibility/update/BUILD index 0ee4550815..b9725a74ee 100644 --- a/tensorflow/tools/compatibility/update/BUILD +++ b/tensorflow/tools/compatibility/update/BUILD @@ -12,5 +12,6 @@ py_binary( "//tensorflow/python:no_contrib", "//tensorflow/tools/common:public_api", "//tensorflow/tools/common:traverse", + "//tensorflow/tools/compatibility:tf_upgrade_v2_lib", ], ) diff --git a/tensorflow/tools/compatibility/update/generate_v2_renames_map.py b/tensorflow/tools/compatibility/update/generate_v2_renames_map.py index 949946c827..554b42c171 100644 --- a/tensorflow/tools/compatibility/update/generate_v2_renames_map.py +++ b/tensorflow/tools/compatibility/update/generate_v2_renames_map.py @@ -32,6 +32,7 @@ from tensorflow.python.util import tf_decorator from tensorflow.python.util import tf_export from tensorflow.tools.common import public_api from tensorflow.tools.common import traverse +from tensorflow.tools.compatibility import tf_upgrade_v2 _OUTPUT_FILE_PATH = 'third_party/tensorflow/tools/compatibility/renames_v2.py' @@ -102,7 +103,7 @@ def collect_constant_renames(): """Looks for constants that need to be renamed in TF 2.0. Returns: - List of tuples of the form (current name, new name). + Set of tuples of the form (current name, new name). """ renames = set() for module in sys.modules.values(): @@ -135,7 +136,7 @@ def collect_function_renames(): """Looks for functions/classes that need to be renamed in TF 2.0. Returns: - List of tuples of the form (current name, new name). + Set of tuples of the form (current name, new name). """ # Set of rename lines to write to output file in the form: # 'tf.deprecated_name': 'tf.canonical_name' @@ -181,12 +182,15 @@ def update_renames_v2(output_file_path): function_renames = collect_function_renames() constant_renames = collect_constant_renames() all_renames = function_renames.union(constant_renames) + manual_renames = set( + tf_upgrade_v2.TFAPIChangeSpec().manual_symbol_renames.keys()) # List of rename lines to write to output file in the form: # 'tf.deprecated_name': 'tf.canonical_name' rename_lines = [ get_rename_line(name, canonical_name) - for name, canonical_name in all_renames] + for name, canonical_name in all_renames + if 'tf.' + name not in manual_renames] renames_file_text = '%srenames = {\n%s\n}\n' % ( _FILE_HEADER, ',\n'.join(sorted(rename_lines))) file_io.write_string_to_file(output_file_path, renames_file_text) -- GitLab From 672840616bd8b65ed9089ae687a714abfd87f63e Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Wed, 28 Nov 2018 15:17:45 -0800 Subject: [PATCH 485/672] Remove unused imports --- .../tensorrt/test/binary_tensor_weight_broadcast_test.py | 1 - .../tensorrt/test/multi_connection_neighbor_engine_test.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py index 5ab94cd931..6840ed20d1 100644 --- a/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py +++ b/tensorflow/contrib/tensorrt/test/binary_tensor_weight_broadcast_test.py @@ -26,7 +26,6 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import gen_array_ops -from tensorflow.python.ops import math_ops from tensorflow.python.platform import test diff --git a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py index 468b2c96e1..8587fea6db 100644 --- a/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py +++ b/tensorflow/contrib/tensorrt/test/multi_connection_neighbor_engine_test.py @@ -25,8 +25,6 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops -from tensorflow.python.ops import gen_math_ops -from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn from tensorflow.python.platform import test -- GitLab From 02a69ef199e2ed05a3498d3ee738bd493fe48b77 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 15:18:56 -0800 Subject: [PATCH 486/672] Test to show how constant 1D gather crashes toco. PiperOrigin-RevId: 223245378 --- tensorflow/lite/build_def.bzl | 1 + tensorflow/lite/testing/generate_examples.py | 32 +++++++++++++++++++ .../resolve_constant_gather.cc | 4 +++ 3 files changed, 37 insertions(+) diff --git a/tensorflow/lite/build_def.bzl b/tensorflow/lite/build_def.bzl index 5d615f0c5a..4a49c14cc9 100644 --- a/tensorflow/lite/build_def.bzl +++ b/tensorflow/lite/build_def.bzl @@ -242,6 +242,7 @@ def generated_test_models(): "fully_connected", "fused_batch_norm", "gather", + "gather_buggy", "global_batch_norm", "greater", "greater_equal", diff --git a/tensorflow/lite/testing/generate_examples.py b/tensorflow/lite/testing/generate_examples.py index b143f45b32..71382edaba 100644 --- a/tensorflow/lite/testing/generate_examples.py +++ b/tensorflow/lite/testing/generate_examples.py @@ -105,6 +105,8 @@ KNOWN_BUGS = { r"div.*int32": "72051395", # No support for SplitV r"split.*num_or_size_splits=\[2,2\]": "73377559", + # Constant 1D gather crashes toco. + r"gather_buggy.*input_shape=\[3\].*": "120029508", } @@ -1233,6 +1235,36 @@ def make_gather_tests(zip_path): expected_tf_success=60) +def make_gather_buggy_tests(zip_path): + """Make a set of tests to show gather crashes toco.""" + + test_parameters = [{ + "input_shape": [[3]], + "reference_shape": [[2]], + }, { + "input_shape": [[2, 3]], + "reference_shape": [[2, 3]], + }] + + def build_graph(parameters): + """Build a graph where the inputs to Gather are constants.""" + reference = tf.placeholder( + dtype=tf.int32, shape=parameters["reference_shape"]) + gather_input = tf.constant( + create_tensor_data(tf.int32, parameters["input_shape"])) + gather_indices = tf.constant([0, 1], tf.int32) + out = tf.equal(reference, tf.gather(gather_input, gather_indices)) + return [reference], [out] + + def build_inputs(parameters, sess, inputs, outputs): + reference_values = np.zeros(parameters["reference_shape"], dtype=np.int32) + return [reference_values], sess.run( + outputs, feed_dict={inputs[0]: reference_values}) + + make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs, + expected_tf_success=2) + + def make_global_batch_norm_tests(zip_path): """Make a set of tests to do batch_norm_with_global_normalization.""" diff --git a/tensorflow/lite/toco/graph_transformations/resolve_constant_gather.cc b/tensorflow/lite/toco/graph_transformations/resolve_constant_gather.cc index 1149930131..c72135923e 100644 --- a/tensorflow/lite/toco/graph_transformations/resolve_constant_gather.cc +++ b/tensorflow/lite/toco/graph_transformations/resolve_constant_gather.cc @@ -47,6 +47,10 @@ inline void Gather(const Array& input_array, int input_rank, stride *= input_shape.dims(i); } + // Let's make sure we have enough space for all element in the memcpy() + // below, which writes 'stride' elements startng at 'i * stride'. + CHECK_EQ(stride * coords_shape.dims(0), output_data.size()); + for (int i = 0; i < coords_shape.dims(0); ++i) { DCHECK_GE(coords_data[i], 0); DCHECK_LT(coords_data[i], input_shape.dims(rev_input_rank)); -- GitLab From 029389e0c69919392bd9a0d070d0d58498b0fb1d Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Wed, 28 Nov 2018 15:20:44 -0800 Subject: [PATCH 487/672] Update Eigen to commit 135398e50bed. PiperOrigin-RevId: 223245685 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 30694b43e3..0ea5d68ea8 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -134,11 +134,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): tf_http_archive( name = "eigen_archive", build_file = clean_dep("//third_party:eigen.BUILD"), - sha256 = "8fa7ba1af23f0320be05f4658061138d6eb8dd1f320669cbf305b3a034f9d1c2", - strip_prefix = "eigen-eigen-ea671884cc96", + sha256 = "6e505fa8bf8d234d0338679b390cb89f850d870214c751b01a5db7f647e4d438", + strip_prefix = "eigen-eigen-135398e50bed", urls = [ - "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/ea671884cc96.tar.gz", - "https://bitbucket.org/eigen/eigen/get/ea671884cc96.tar.gz", + "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/135398e50bed.tar.gz", + "https://bitbucket.org/eigen/eigen/get/135398e50bed.tar.gz", ], ) -- GitLab From b8759f4a5fb718d925f82a9aaf601d786a7419ca Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 15:23:27 -0800 Subject: [PATCH 488/672] Switch to new tf.distribute.Strategy reduce API. No longer allow a list as a reduce or broadcast destination, since it isn't used outside of tests and will make future support for model parallelism more tricky. PiperOrigin-RevId: 223246154 --- .../collective_all_reduce_strategy_test.py | 7 +-- .../python/cross_device_ops_test.py | 10 ++--- .../distribute/python/minimize_loss_test.py | 11 +++-- .../python/mirrored_strategy_multigpu_test.py | 32 +------------- .../python/parameter_server_strategy_test.py | 2 +- .../distribute/python/strategy_test_lib.py | 6 ++- .../python/distribute/distribute_lib.py | 44 +++++++++++++------ tensorflow/python/distribute/values.py | 8 ++-- .../engine/distributed_training_utils.py | 7 +-- tensorflow/python/training/moving_averages.py | 3 +- .../v1/tensorflow.distribute.-strategy.pbtxt | 2 +- .../v2/tensorflow.distribute.-strategy.pbtxt | 2 +- 12 files changed, 56 insertions(+), 78 deletions(-) diff --git a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py index 09239ffc72..eba3585a55 100644 --- a/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py +++ b/tensorflow/contrib/distribute/python/collective_all_reduce_strategy_test.py @@ -131,7 +131,7 @@ class CollectiveAllReduceStrategyTestBase( before_list.append(fetched) with ops.control_dependencies([fetched]): # TODO(yuefengz): support non-Mirrored variable as destinations. - g = d.reduce( + g = d.extended.reduce_to( reduce_util.ReduceOp.SUM, g, destinations=v) with ops.control_dependencies( d.update(v, update, g, grouped=False)): @@ -225,10 +225,7 @@ class CollectiveAllReduceStrategyTestBase( return array_ops.identity(x) x = distribution.call_for_each_replica(model_fn) - reduced_x = distribution.unwrap( - distribution.reduce( - reduce_util.ReduceOp.MEAN, x, - destinations='/cpu:0'))[0] + reduced_x = distribution.reduce(reduce_util.ReduceOp.MEAN, x) x = distribution.unwrap(x)[0] sess.run(variables.global_variables_initializer()) diff --git a/tensorflow/contrib/distribute/python/cross_device_ops_test.py b/tensorflow/contrib/distribute/python/cross_device_ops_test.py index 5d8690beb5..3602cc9209 100644 --- a/tensorflow/contrib/distribute/python/cross_device_ops_test.py +++ b/tensorflow/contrib/distribute/python/cross_device_ops_test.py @@ -132,11 +132,9 @@ class CrossDeviceOpsTestBase(test.TestCase, parameterized.TestCase): destination_mirrored = _fake_mirrored(1., devices) destination_different = _fake_mirrored(1., _cpu_device) destination_str = _cpu_device - destination_list = devices all_destinations = [ destination_mirrored, destination_different, destination_str, - destination_list ] # test reduce() @@ -320,10 +318,10 @@ class SingleWorkerCrossDeviceOpsTest(CrossDeviceOpsTestBase): if batch_reduce: result = cross_device_ops_instance.batch_reduce( - reduce_op, [(per_replica, devices)]) + reduce_op, [(per_replica, per_replica)]) else: result = cross_device_ops_instance.reduce( - reduce_op, per_replica, devices) + reduce_op, per_replica, per_replica) total_indices_with_dups = [1, 1, 3] total_indices_without_dups = [1, 3] @@ -510,11 +508,9 @@ class MultiWorkerCollectiveAllReduceTest( destination_mirrored = _fake_mirrored(1., devices) destination_different = _fake_mirrored(1., _cpu_device) destination_str = _cpu_device - destination_list = devices all_destinations = [ - destination_different, destination_mirrored, destination_str, - destination_list + destination_different, destination_mirrored, destination_str ] # test reduce() diff --git a/tensorflow/contrib/distribute/python/minimize_loss_test.py b/tensorflow/contrib/distribute/python/minimize_loss_test.py index 129b394bb6..dcc9df4cda 100644 --- a/tensorflow/contrib/distribute/python/minimize_loss_test.py +++ b/tensorflow/contrib/distribute/python/minimize_loss_test.py @@ -486,12 +486,11 @@ class MinimizeLossStepTest(test.TestCase, parameterized.TestCase): if not reduced: self.assertLen(distribution.unwrap(loss_output), distribution.num_replicas_in_sync) - loss_output = distribution.reduce( - reduce_util.ReduceOp.MEAN, loss_output, destinations="/device:CPU:0") - - unwrapped_output = distribution.unwrap(loss_output) - self.assertLen(unwrapped_output, 1) - loss_tensor = unwrapped_output[0] + loss_tensor = distribution.reduce(reduce_util.ReduceOp.MEAN, loss_output) + else: + unwrapped_output = distribution.unwrap(loss_output) + self.assertLen(unwrapped_output, 1) + loss_tensor = unwrapped_output[0] self.assertEqual(initial_loss.dtype, loss_tensor.dtype) self.assertEqual(initial_loss.shape, loss_tensor.shape) diff --git a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py index b304f63501..fee37daa42 100644 --- a/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py +++ b/tensorflow/contrib/distribute/python/mirrored_strategy_multigpu_test.py @@ -96,14 +96,9 @@ class MirroredTwoDeviceDistributionTest(strategy_test_lib.DistributionTestBase, def testReduceToCpu(self, distribution): with distribution.scope(): result = distribution.extended.call_for_each_replica(_replica_id) - reduced = distribution.reduce( - reduce_util.ReduceOp.SUM, - result, - destinations="/device:CPU:0") - unwrapped = distribution.unwrap(reduced) - self.assertEqual(1, len(unwrapped)) + reduced = distribution.reduce(reduce_util.ReduceOp.SUM, result) expected = sum(range(distribution.num_replicas_in_sync)) - self.assertEqual(expected, self.evaluate(unwrapped[0])) + self.assertEqual(expected, self.evaluate(reduced)) def testMakeInputFnIterator(self, distribution): dataset_fn = lambda: dataset_ops.Dataset.range(10) @@ -136,29 +131,6 @@ class MirroredOneDeviceDistributionTest( strategy_test_lib.DistributionTestBase, parameterized.TestCase): - @combinations.generate(combinations.combine( - distribution=[ - combinations.NamedDistribution( - "Mirrored1CPU", - lambda: mirrored_strategy.MirroredStrategy(["/device:CPU:0"]), - required_gpus=1), - combinations.mirrored_strategy_with_one_gpu, - combinations.NamedDistribution( - "CoreMirrored1CPU", - lambda: mirrored_strategy.CoreMirroredStrategy(["/device:CPU:0"]), - required_gpus=1), - combinations.core_mirrored_strategy_with_one_gpu], - mode=["graph", "eager"])) - def testReduceToMultipleDestinations(self, distribution): - with distribution.scope(): - reduced = distribution.extended.reduce_to( - reduce_util.ReduceOp.SUM, - 1.0, - destinations=["/device:CPU:0", "/device:GPU:0"]) - unwrapped = distribution.unwrap(reduced) - self.assertLen(unwrapped, 2) - self.assertEqual(1.0, self.evaluate(unwrapped[0])) - @combinations.generate(one_device_combinations()) def testMinimizeLoss(self, distribution): if context.executing_eagerly(): diff --git a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py index 4debe72ca6..83d7473666 100644 --- a/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py +++ b/tensorflow/contrib/distribute/python/parameter_server_strategy_test.py @@ -481,7 +481,7 @@ class ParameterServerStrategyTestBase( before_list.append(fetched) with ops.control_dependencies([fetched]): # TODO(yuefengz): support non-Mirrored variable as destinations. - g = d.reduce( + g = d.extended.reduce_to( reduce_util.ReduceOp.SUM, g, destinations=v) with ops.control_dependencies( d.update(v, update, g, grouped=False)): diff --git a/tensorflow/contrib/distribute/python/strategy_test_lib.py b/tensorflow/contrib/distribute/python/strategy_test_lib.py index 756e5bdc1e..d50b142c5e 100644 --- a/tensorflow/contrib/distribute/python/strategy_test_lib.py +++ b/tensorflow/contrib/distribute/python/strategy_test_lib.py @@ -116,7 +116,8 @@ class DistributionTestBase(test.TestCase): before_list.append(fetched) # control_dependencies irrelevant but harmless in eager execution with ops.control_dependencies([fetched]): - g = d.reduce(reduce_util.ReduceOp.SUM, g, destinations=v) + g = d.extended.reduce_to( + reduce_util.ReduceOp.SUM, g, destinations=v) with ops.control_dependencies(d.update( v, update, g, grouped=False)): after_list.append(d.read_var(v)) @@ -170,7 +171,8 @@ class DistributionTestBase(test.TestCase): fetched = d.read_var(v) before_list.append(fetched) with ops.control_dependencies([fetched]): - g = d.reduce(reduce_util.ReduceOp.SUM, g, destinations=v) + g = d.extended.reduce_to( + reduce_util.ReduceOp.SUM, g, destinations=v) with ops.control_dependencies(d.update( v, update, g, grouped=False)): after_list.append(d.read_var(v)) diff --git a/tensorflow/python/distribute/distribute_lib.py b/tensorflow/python/distribute/distribute_lib.py index a1f03eab61..2213499be0 100644 --- a/tensorflow/python/distribute/distribute_lib.py +++ b/tensorflow/python/distribute/distribute_lib.py @@ -489,10 +489,19 @@ class DistributionStrategy(object): kwargs.pop("run_concurrently", None) # Ignore old option. return self._extended.call_for_each_replica(fn, args, kwargs) - @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` - def reduce(self, aggregation, value, destinations): - """DEPRECATED: use extended.reduce_to() instead.""" - return self._extended.reduce_to(aggregation, value, destinations) + def reduce(self, reduce_op, value): + """Reduce `value` across replicas. + + Args: + reduce_op: A `tf.distribute.ReduceOp` value specifying how values should + be combined. + value: A "per replica" value to be combined into a single tensor. + + Returns: + A `Tensor`. + """ + _require_cross_replica_context_extended(self._extended) + return self._extended._reduce(reduce_op, value) # pylint: disable=protected-access @doc_controls.do_not_generate_docs # DEPRECATED, moving to `extended` def batch_reduce(self, aggregation, value_destination_pairs): @@ -1039,14 +1048,15 @@ class DistributionStrategyExtended(object): Args: tensor: A Tensor value to broadcast. - destinations: A mirrored variable, device string, or list of device - strings, specifying the destination devices to copy `tensor` to. + destinations: A mirrored variable or device string specifying the + destination devices to copy `tensor` to. Returns: A value mirrored to `destinations` devices. """ # TODO(josh11b): More docstring _require_cross_replica_context_extended(self) + assert not isinstance(destinations, (list, tuple)) return self._broadcast_to(tensor, destinations) def _broadcast_to(self, tensor, destinations): @@ -1154,6 +1164,11 @@ class DistributionStrategyExtended(object): def _call_for_each_replica(self, fn, args, kwargs): raise NotImplementedError("must be implemented in descendants") + def _reduce(self, reduce_op, value): + # Default implementation until we have an implementation for each strategy. + return self._unwrap(self._reduce_to( + reduce_op, value, device_util.current() or "/device:CPU:0"))[0] + def reduce_to(self, reduce_op, value, destinations): """Combine (via e.g. sum or mean) values across replicas. @@ -1163,26 +1178,27 @@ class DistributionStrategyExtended(object): `tf.VariableAggregation.SUM`, `tf.VariableAggregation.MEAN`, value: A per-replica value with one value per replica. - destinations: A mirrored variable, a per-replica tensor, a device string, - or list of device strings. The return value will be copied to all - destination devices (or all the devices where the `destinations` value - resides). To perform an all-reduction, pass `value` to `destinations`. + destinations: A mirrored variable, a per-replica tensor, or a device + string. The return value will be copied to all destination devices (or + all the devices where the `destinations` value resides). To perform an + all-reduction, pass `value` to `destinations`. Returns: A value mirrored to `destinations`. """ # TODO(josh11b): More docstring - # TODO(josh11b): Return an unwrapped value if colocate_with is a - # single device. _require_cross_replica_context_extended(self) + assert not isinstance(destinations, (list, tuple)) # TODO(priyag): Remove this when all callers have been updated. if isinstance(reduce_op, variable_scope.VariableAggregation): - assert reduce_op in [ + assert reduce_op in ( variable_scope.VariableAggregation.SUM, variable_scope.VariableAggregation.MEAN, - ] + ) reduce_op = reduce_util.ReduceOp.from_variable_aggregation(reduce_op) + assert (reduce_op == reduce_util.ReduceOp.SUM or + reduce_op == reduce_util.ReduceOp.MEAN) return self._reduce_to(reduce_op, value, destinations) def _reduce_to(self, reduce_op, value, destinations): diff --git a/tensorflow/python/distribute/values.py b/tensorflow/python/distribute/values.py index 7dd1062e38..f3f7676f04 100644 --- a/tensorflow/python/distribute/values.py +++ b/tensorflow/python/distribute/values.py @@ -324,7 +324,7 @@ def _apply_aggregation(strategy, value, aggregation, destinations): return strategy.broadcast(strategy.unwrap(value)[0], destinations=destinations) reduce_op = reduce_util.ReduceOp.from_variable_aggregation(aggregation) - return strategy.reduce(reduce_op, value=value, destinations=destinations) + return strategy.extended.reduce_to(reduce_op, value, destinations) class _MirroredSaveable(saver.BaseSaverBuilder.ResourceVariableSaveable): @@ -1672,13 +1672,11 @@ class MultiStepContext(object): self._last_step_outputs[name] = output else: distribution = distribution_strategy_context.get_distribution_strategy() - self._last_step_outputs[name] = distribution.reduce( - reduce_op, output, destinations="/device:CPU:0") + self._last_step_outputs[name] = distribution.reduce(reduce_op, output) else: assert reduce_op is not None def merge_fn(distribution, value): - self._last_step_outputs[name] = distribution.reduce( - reduce_op, value, destinations="/device:CPU:0") + self._last_step_outputs[name] = distribution.reduce(reduce_op, value) # Setting this inside the `merge_fn` because all replicas share the same # context object, so it's more robust to set it only once (even if all # the replicas are trying to set the same value). diff --git a/tensorflow/python/keras/engine/distributed_training_utils.py b/tensorflow/python/keras/engine/distributed_training_utils.py index 8b0076163e..cd8e0342cd 100644 --- a/tensorflow/python/keras/engine/distributed_training_utils.py +++ b/tensorflow/python/keras/engine/distributed_training_utils.py @@ -94,11 +94,8 @@ def unwrap_values(distribution_strategy, grouped_inputs, grouped_outputs, grouped_inputs) if with_loss_tensor: # reduce loss tensor before adding it to the list of fetches - loss = distribution_strategy.unwrap( - distribution_strategy.reduce(distribute_lib.get_loss_reduction(), - grouped_outputs[0], - destinations='/device:CPU:0'))[0] - + loss = distribution_strategy.reduce(distribute_lib.get_loss_reduction(), + grouped_outputs[0]) all_outputs = flatten_perdevice_values(distribution_strategy, grouped_outputs[1:]) all_outputs = [loss] + all_outputs diff --git a/tensorflow/python/training/moving_averages.py b/tensorflow/python/training/moving_averages.py index 9b5449498b..8785f9a8e7 100644 --- a/tensorflow/python/training/moving_averages.py +++ b/tensorflow/python/training/moving_averages.py @@ -96,7 +96,8 @@ def assign_moving_average(variable, value, decay, zero_debias=True, name=None): # In a replica context, we update variable using the mean of value across # replicas. def merge_fn(strategy, v, value): - value = strategy.reduce(ds_reduce_util.ReduceOp.MEAN, value, v) + value = strategy.extended.reduce_to( + ds_reduce_util.ReduceOp.MEAN, value, v) return strategy.update(v, update_fn, value) return replica_context.merge_call(merge_fn, args=(variable, value)) diff --git a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt index 0fd9a3b42d..9eb73d2c0d 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.distribute.-strategy.pbtxt @@ -104,7 +104,7 @@ tf_class { } member_method { name: "reduce" - argspec: "args=[\'self\', \'aggregation\', \'value\', \'destinations\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'self\', \'reduce_op\', \'value\'], varargs=None, keywords=None, defaults=None" } member_method { name: "run_steps_on_dataset" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt index 0fd9a3b42d..9eb73d2c0d 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.distribute.-strategy.pbtxt @@ -104,7 +104,7 @@ tf_class { } member_method { name: "reduce" - argspec: "args=[\'self\', \'aggregation\', \'value\', \'destinations\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[\'self\', \'reduce_op\', \'value\'], varargs=None, keywords=None, defaults=None" } member_method { name: "run_steps_on_dataset" -- GitLab From dde79c2ef338414c3ebdb62c0cd74821ea2ad089 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 28 Nov 2018 15:43:24 -0800 Subject: [PATCH 489/672] Remove more symbols from TF 2.0 API. - train.CheckpointSaverListener - train.NanLossDuringTrainingError - train.Scaffold - train.SecondOrStepTimer - train.SessionRunArgs - train.SessionRunContext - train.SessionRunValues PiperOrigin-RevId: 223249504 --- .../training/basic_session_run_hooks.py | 6 +-- .../python/training/monitored_session.py | 2 +- .../python/training/session_run_hook.py | 6 +-- ...low.train.-checkpoint-saver-listener.pbtxt | 24 --------- ...rain.-nan-loss-during-training-error.pbtxt | 12 ----- .../v2/tensorflow.train.-scaffold.pbtxt | 53 ------------------- ...nsorflow.train.-second-or-step-timer.pbtxt | 26 --------- .../tensorflow.train.-session-run-args.pbtxt | 27 ---------- ...ensorflow.train.-session-run-context.pbtxt | 25 --------- ...tensorflow.train.-session-run-values.pbtxt | 27 ---------- .../api/golden/v2/tensorflow.train.pbtxt | 28 ---------- tensorflow/tools/compatibility/renames_v2.py | 7 +++ 12 files changed, 14 insertions(+), 229 deletions(-) delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-checkpoint-saver-listener.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-nan-loss-during-training-error.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-scaffold.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-second-or-step-timer.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-args.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-context.pbtxt delete mode 100644 tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-values.pbtxt diff --git a/tensorflow/python/training/basic_session_run_hooks.py b/tensorflow/python/training/basic_session_run_hooks.py index 60db654e9c..b64c7ada62 100644 --- a/tensorflow/python/training/basic_session_run_hooks.py +++ b/tensorflow/python/training/basic_session_run_hooks.py @@ -83,7 +83,7 @@ class _HookTimer(object): raise NotImplementedError -@tf_export("train.SecondOrStepTimer") +@tf_export(v1=["train.SecondOrStepTimer"]) class SecondOrStepTimer(_HookTimer): """Timer that triggers at most once every N seconds or once every N steps. """ @@ -429,7 +429,7 @@ class StopAtStepHook(session_run_hook.SessionRunHook): run_context.request_stop() -@tf_export("train.CheckpointSaverListener") +@tf_export(v1=["train.CheckpointSaverListener"]) class CheckpointSaverListener(object): """Interface for listeners that take action before or after checkpoint save. @@ -718,7 +718,7 @@ class StepCounterHook(session_run_hook.SessionRunHook): self._last_global_step = stale_global_step -@tf_export("train.NanLossDuringTrainingError") +@tf_export(v1=["train.NanLossDuringTrainingError"]) class NanLossDuringTrainingError(RuntimeError): def __str__(self): diff --git a/tensorflow/python/training/monitored_session.py b/tensorflow/python/training/monitored_session.py index c40bd2b859..6a7d27df5c 100644 --- a/tensorflow/python/training/monitored_session.py +++ b/tensorflow/python/training/monitored_session.py @@ -54,7 +54,7 @@ _PREEMPTION_ERRORS = (errors.AbortedError, errors.UnavailableError) USE_DEFAULT = object() -@tf_export('train.Scaffold') +@tf_export(v1=['train.Scaffold']) class Scaffold(object): """Structure to create or gather pieces commonly needed to train a model. diff --git a/tensorflow/python/training/session_run_hook.py b/tensorflow/python/training/session_run_hook.py index 5daea93128..e9a61def74 100644 --- a/tensorflow/python/training/session_run_hook.py +++ b/tensorflow/python/training/session_run_hook.py @@ -186,7 +186,7 @@ class SessionRunHook(object): pass -@tf_export("train.SessionRunArgs") +@tf_export(v1=["train.SessionRunArgs"]) class SessionRunArgs( collections.namedtuple("SessionRunArgs", ["fetches", "feed_dict", "options"])): @@ -211,7 +211,7 @@ class SessionRunArgs( return super(SessionRunArgs, cls).__new__(cls, fetches, feed_dict, options) -@tf_export("train.SessionRunContext") +@tf_export(v1=["train.SessionRunContext"]) class SessionRunContext(object): """Provides information about the `session.run()` call being made. @@ -263,7 +263,7 @@ class SessionRunContext(object): self._stop_requested = True -@tf_export("train.SessionRunValues") +@tf_export(v1=["train.SessionRunValues"]) class SessionRunValues( collections.namedtuple("SessionRunValues", ["results", "options", "run_metadata"])): diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-checkpoint-saver-listener.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-checkpoint-saver-listener.pbtxt deleted file mode 100644 index 9d3688e565..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-checkpoint-saver-listener.pbtxt +++ /dev/null @@ -1,24 +0,0 @@ -path: "tensorflow.train.CheckpointSaverListener" -tf_class { - is_instance: "" - is_instance: "" - member_method { - name: "__init__" - } - member_method { - name: "after_save" - argspec: "args=[\'self\', \'session\', \'global_step_value\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "before_save" - argspec: "args=[\'self\', \'session\', \'global_step_value\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "begin" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "end" - argspec: "args=[\'self\', \'session\', \'global_step_value\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-nan-loss-during-training-error.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-nan-loss-during-training-error.pbtxt deleted file mode 100644 index e415819b3d..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-nan-loss-during-training-error.pbtxt +++ /dev/null @@ -1,12 +0,0 @@ -path: "tensorflow.train.NanLossDuringTrainingError" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "args" - mtype: "" - } - member_method { - name: "__init__" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-scaffold.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-scaffold.pbtxt deleted file mode 100644 index 38cc98b48e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-scaffold.pbtxt +++ /dev/null @@ -1,53 +0,0 @@ -path: "tensorflow.train.Scaffold" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "init_feed_dict" - mtype: "" - } - member { - name: "init_fn" - mtype: "" - } - member { - name: "init_op" - mtype: "" - } - member { - name: "local_init_op" - mtype: "" - } - member { - name: "ready_for_local_init_op" - mtype: "" - } - member { - name: "ready_op" - mtype: "" - } - member { - name: "saver" - mtype: "" - } - member { - name: "summary_op" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'init_op\', \'init_feed_dict\', \'init_fn\', \'ready_op\', \'ready_for_local_init_op\', \'local_init_op\', \'summary_op\', \'saver\', \'copy_from_scaffold\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\'], " - } - member_method { - name: "default_local_init_op" - argspec: "args=[], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "finalize" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "get_or_default" - argspec: "args=[\'arg_name\', \'collection_key\', \'default_constructor\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-second-or-step-timer.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-second-or-step-timer.pbtxt deleted file mode 100644 index 3c5a6ac13c..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-second-or-step-timer.pbtxt +++ /dev/null @@ -1,26 +0,0 @@ -path: "tensorflow.train.SecondOrStepTimer" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member_method { - name: "__init__" - argspec: "args=[\'self\', \'every_secs\', \'every_steps\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " - } - member_method { - name: "last_triggered_step" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "reset" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "should_trigger_for_step" - argspec: "args=[\'self\', \'step\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "update_last_triggered_step" - argspec: "args=[\'self\', \'step\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-args.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-args.pbtxt deleted file mode 100644 index 442990893e..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-args.pbtxt +++ /dev/null @@ -1,27 +0,0 @@ -path: "tensorflow.train.SessionRunArgs" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "feed_dict" - mtype: "" - } - member { - name: "fetches" - mtype: "" - } - member { - name: "options" - mtype: "" - } - member_method { - name: "__init__" - } - member_method { - name: "count" - } - member_method { - name: "index" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-context.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-context.pbtxt deleted file mode 100644 index d5adb15c95..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-context.pbtxt +++ /dev/null @@ -1,25 +0,0 @@ -path: "tensorflow.train.SessionRunContext" -tf_class { - is_instance: "" - is_instance: "" - member { - name: "original_args" - mtype: "" - } - member { - name: "session" - mtype: "" - } - member { - name: "stop_requested" - mtype: "" - } - member_method { - name: "__init__" - argspec: "args=[\'self\', \'original_args\', \'session\'], varargs=None, keywords=None, defaults=None" - } - member_method { - name: "request_stop" - argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-values.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-values.pbtxt deleted file mode 100644 index 0b401d59c4..0000000000 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.-session-run-values.pbtxt +++ /dev/null @@ -1,27 +0,0 @@ -path: "tensorflow.train.SessionRunValues" -tf_class { - is_instance: "" - is_instance: "" - is_instance: "" - member { - name: "options" - mtype: "" - } - member { - name: "results" - mtype: "" - } - member { - name: "run_metadata" - mtype: "" - } - member_method { - name: "__init__" - } - member_method { - name: "count" - } - member_method { - name: "index" - } -} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt index a30f67350a..2cc3b7ee1d 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.train.pbtxt @@ -16,10 +16,6 @@ tf_module { name: "CheckpointSaverHook" mtype: "" } - member { - name: "CheckpointSaverListener" - mtype: "" - } member { name: "ClusterDef" mtype: "" @@ -84,10 +80,6 @@ tf_module { name: "LoggingTensorHook" mtype: "" } - member { - name: "NanLossDuringTrainingError" - mtype: "" - } member { name: "NanTensorHook" mtype: "" @@ -96,14 +88,6 @@ tf_module { name: "ProximalGradientDescentOptimizer" mtype: "" } - member { - name: "Scaffold" - mtype: "" - } - member { - name: "SecondOrStepTimer" - mtype: "" - } member { name: "SequenceExample" mtype: "" @@ -116,22 +100,10 @@ tf_module { name: "ServerDef" mtype: "" } - member { - name: "SessionRunArgs" - mtype: "" - } - member { - name: "SessionRunContext" - mtype: "" - } member { name: "SessionRunHook" mtype: "" } - member { - name: "SessionRunValues" - mtype: "" - } member { name: "StepCounterHook" mtype: "" diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index 8dbeb078b6..ae57478473 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -573,6 +573,7 @@ renames = { 'tf.train.AdagradDAOptimizer': 'tf.compat.v1.train.AdagradDAOptimizer', 'tf.train.AdagradOptimizer': 'tf.compat.v1.train.AdagradOptimizer', 'tf.train.AdamOptimizer': 'tf.compat.v1.train.AdamOptimizer', + 'tf.train.CheckpointSaverListener': 'tf.compat.v1.train.CheckpointSaverListener', 'tf.train.ChiefSessionCreator': 'tf.compat.v1.train.ChiefSessionCreator', 'tf.train.FtrlOptimizer': 'tf.compat.v1.train.FtrlOptimizer', 'tf.train.GradientDescentOptimizer': 'tf.compat.v1.train.GradientDescentOptimizer', @@ -580,6 +581,7 @@ renames = { 'tf.train.MomentumOptimizer': 'tf.compat.v1.train.MomentumOptimizer', 'tf.train.MonitoredSession': 'tf.compat.v1.train.MonitoredSession', 'tf.train.MonitoredTrainingSession': 'tf.compat.v1.train.MonitoredTrainingSession', + 'tf.train.NanLossDuringTrainingError': 'tf.compat.v1.train.NanLossDuringTrainingError', 'tf.train.NewCheckpointReader': 'tf.compat.v1.train.NewCheckpointReader', 'tf.train.Optimizer': 'tf.compat.v1.train.Optimizer', 'tf.train.ProfilerHook': 'tf.compat.v1.train.ProfilerHook', @@ -588,8 +590,13 @@ renames = { 'tf.train.RMSPropOptimizer': 'tf.compat.v1.train.RMSPropOptimizer', 'tf.train.Saver': 'tf.compat.v1.train.Saver', 'tf.train.SaverDef': 'tf.compat.v1.train.SaverDef', + 'tf.train.Scaffold': 'tf.compat.v1.train.Scaffold', + 'tf.train.SecondOrStepTimer': 'tf.compat.v1.train.SecondOrStepTimer', 'tf.train.SessionCreator': 'tf.compat.v1.train.SessionCreator', 'tf.train.SessionManager': 'tf.compat.v1.train.SessionManager', + 'tf.train.SessionRunArgs': 'tf.compat.v1.train.SessionRunArgs', + 'tf.train.SessionRunContext': 'tf.compat.v1.train.SessionRunContext', + 'tf.train.SessionRunValues': 'tf.compat.v1.train.SessionRunValues', 'tf.train.SingularMonitoredSession': 'tf.compat.v1.train.SingularMonitoredSession', 'tf.train.Supervisor': 'tf.compat.v1.train.Supervisor', 'tf.train.SyncReplicasOptimizer': 'tf.compat.v1.train.SyncReplicasOptimizer', -- GitLab From 9831eb8bbfd5226db87dad087e509eae0af07e9a Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 28 Nov 2018 15:52:59 -0800 Subject: [PATCH 490/672] Factor out some Operation mutations from Function into Operation. These mutations are used to rewrite a forward function call to output its intermediates when creating a gradient call. This change is in preparation for making cond_v2 and while_v2 do the same thing, instead of outputing all intermediates from the forward call when its created. PiperOrigin-RevId: 223250964 --- tensorflow/python/eager/function.py | 20 ++++++---------- tensorflow/python/framework/ops.py | 36 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index 68cdb1a871..d9c16aa7b8 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -467,20 +467,14 @@ class Function(object): # Rewrite an inference call op to be a forward call op if op.get_attr("f").name.encode() == self._inference_function.name: - func = attr_value_pb2.AttrValue( - func=attr_value_pb2.NameAttrList( - name=self._forward_function.name)) - op._set_attr("f", func) - types = attr_value_pb2.AttrValue.ListValue( - type=self._forward_function._output_types) - op._set_attr("Tout", attr_value_pb2.AttrValue(list=types)) - for i in range( - num_inference_outputs, len(self._forward_function._output_types)): - t = ops.Tensor(op, i, self._forward_function._output_types[i]) - t.set_shape(self._forward_function._output_shapes[i]) + op._set_func_attr("f", self._forward_function.name) + op._set_type_list_attr("Tout", self._forward_function._output_types) + op._add_outputs( + self._forward_function._output_types[num_inference_outputs:], + self._forward_function._output_shapes[num_inference_outputs:]) + for i in range(num_inference_outputs, len(op.outputs)): func_graph_output = self._forward_function._func_graph_outputs[i] - custom_gradient.copy_handle_data(func_graph_output, t) - op._outputs.append(t) + custom_gradient.copy_handle_data(func_graph_output, op.outputs[i]) # pylint: enable=protected-access # Compute the gradients using the side outputs side_outputs = op.outputs[num_inference_outputs:] diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 5a8a2a48ab..fc692a2510 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -2126,6 +2126,23 @@ class Operation(object): """Removes any control inputs to this operation.""" c_api.RemoveAllControlInputs(self._graph._c_graph, self._c_op) # pylint: disable=protected-access + def _add_outputs(self, types, shapes): + """Adds new Tensors to self.outputs. + + Note: this is generally unsafe to use. This is used in certain situations in + conjunction with _set_type_list_attr. + + Arguments: + types: list of DTypes + shapes: list of TensorShapes + """ + assert len(types) == len(shapes) + orig_num_outputs = len(self.outputs) + for i in range(len(types)): + t = Tensor(self, orig_num_outputs + i, types[i]) + self._outputs.append(t) + t.set_shape(shapes[i]) + def __str__(self): return str(self.node_def) @@ -2338,6 +2355,25 @@ class Operation(object): finally: c_api.TF_DeleteBuffer(buf) + def _set_func_attr(self, attr_name, func_name): + """Private method used to set a function attribute in the node_def.""" + func = attr_value_pb2.NameAttrList(name=func_name) + self._set_attr(attr_name, attr_value_pb2.AttrValue(func=func)) + + def _set_type_list_attr(self, attr_name, types): + """Private method used to set a function attribute in the node_def.""" + if not types: return + if isinstance(types[0], dtypes.DType): + types = [dt.as_datatype_enum for dt in types] + types_list = attr_value_pb2.AttrValue.ListValue(type=types) + self._set_attr(attr_name, attr_value_pb2.AttrValue(list=types_list)) + + def _set_shape_list_attr(self, attr_name, shapes): + """Private method used to set a function attribute in the node_def.""" + shapes = [s.as_proto() for s in shapes] + shapes_list = attr_value_pb2.AttrValue.ListValue(shape=shapes) + self._set_attr(attr_name, attr_value_pb2.AttrValue(list=shapes_list)) + def get_attr(self, name): """Returns the value of the attr of this op with the given `name`. -- GitLab From 0f98c067fa1aa361267c21a068a18820b35aed70 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 28 Nov 2018 16:00:07 -0800 Subject: [PATCH 491/672] Add publicly available corpus for string_to_number fuzz. PiperOrigin-RevId: 223252037 --- tensorflow/core/kernels/fuzzing/BUILD | 3 +++ .../2db83ea58639b6d7d585fa12e3947a82 | 1 + .../36b4a931886b941dc41180050d12ca94 | 1 + .../50a2fabfdd276f573ff97ace8b11c5f4 | 1 + .../62edb2a1eee34b001652cd86584becf2 | 1 + .../90013d1ec28c46a5c00574e60c70b6fc | 1 + .../94f3e3cee6957ce5815326d6788c85f4 | 1 + .../96f547bc04bb913da0bc08915238ebd8 | 1 + .../d3a903d18fc11e1f35c572ad4da690ed | 1 + .../e3b629c92af44260c189deb32d6f06f3 | 1 + .../f03eecf3bcfe4967a1888156a3115c8d | 1 + .../fa54ca9186f77122ae2a82684a062e16 | 1 + .../fuzzing/tf_ops_fuzz_target_lib.bzl | 26 ++++++++++++------- 13 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/2db83ea58639b6d7d585fa12e3947a82 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/36b4a931886b941dc41180050d12ca94 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/50a2fabfdd276f573ff97ace8b11c5f4 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/62edb2a1eee34b001652cd86584becf2 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/90013d1ec28c46a5c00574e60c70b6fc create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/94f3e3cee6957ce5815326d6788c85f4 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/96f547bc04bb913da0bc08915238ebd8 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/d3a903d18fc11e1f35c572ad4da690ed create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/e3b629c92af44260c189deb32d6f06f3 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/f03eecf3bcfe4967a1888156a3115c8d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_to_number/fa54ca9186f77122ae2a82684a062e16 diff --git a/tensorflow/core/kernels/fuzzing/BUILD b/tensorflow/core/kernels/fuzzing/BUILD index 6f3a49805c..193041241c 100644 --- a/tensorflow/core/kernels/fuzzing/BUILD +++ b/tensorflow/core/kernels/fuzzing/BUILD @@ -18,11 +18,14 @@ cc_library( ) load("//tensorflow/core/kernels/fuzzing:tf_ops_fuzz_target_lib.bzl", "tf_ops_fuzz_target_lib") +load("//tensorflow/core/kernels/fuzzing:tf_ops_fuzz_target_lib.bzl", "tf_oss_fuzz_corpus") tf_ops_fuzz_target_lib("identity") tf_ops_fuzz_target_lib("string_to_number") +tf_oss_fuzz_corpus("string_to_number") + tf_ops_fuzz_target_lib("string_split") tf_ops_fuzz_target_lib("string_split_v2") diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/2db83ea58639b6d7d585fa12e3947a82 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/2db83ea58639b6d7d585fa12e3947a82 new file mode 100644 index 0000000000..3de80927d5 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/2db83ea58639b6d7d585fa12e3947a82 @@ -0,0 +1 @@ +6.023e+23 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/36b4a931886b941dc41180050d12ca94 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/36b4a931886b941dc41180050d12ca94 new file mode 100644 index 0000000000..d531129b28 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/36b4a931886b941dc41180050d12ca94 @@ -0,0 +1 @@ +6.023e-23 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/50a2fabfdd276f573ff97ace8b11c5f4 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/50a2fabfdd276f573ff97ace8b11c5f4 new file mode 100644 index 0000000000..d81cc0710e --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/50a2fabfdd276f573ff97ace8b11c5f4 @@ -0,0 +1 @@ +42 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/62edb2a1eee34b001652cd86584becf2 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/62edb2a1eee34b001652cd86584becf2 new file mode 100644 index 0000000000..72f88139d0 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/62edb2a1eee34b001652cd86584becf2 @@ -0,0 +1 @@ +0xabcdef diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/90013d1ec28c46a5c00574e60c70b6fc b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/90013d1ec28c46a5c00574e60c70b6fc new file mode 100644 index 0000000000..c1113b83e8 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/90013d1ec28c46a5c00574e60c70b6fc @@ -0,0 +1 @@ +3.14159265359 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/94f3e3cee6957ce5815326d6788c85f4 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/94f3e3cee6957ce5815326d6788c85f4 new file mode 100644 index 0000000000..320aa3f00e --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/94f3e3cee6957ce5815326d6788c85f4 @@ -0,0 +1 @@ +0.69314718056 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/96f547bc04bb913da0bc08915238ebd8 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/96f547bc04bb913da0bc08915238ebd8 new file mode 100644 index 0000000000..51b7b732f6 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/96f547bc04bb913da0bc08915238ebd8 @@ -0,0 +1 @@ +6.023e23 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/d3a903d18fc11e1f35c572ad4da690ed b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/d3a903d18fc11e1f35c572ad4da690ed new file mode 100644 index 0000000000..9a0be0764b --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/d3a903d18fc11e1f35c572ad4da690ed @@ -0,0 +1 @@ +1.61803 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/e3b629c92af44260c189deb32d6f06f3 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/e3b629c92af44260c189deb32d6f06f3 new file mode 100644 index 0000000000..6a0e60d48b --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/e3b629c92af44260c189deb32d6f06f3 @@ -0,0 +1 @@ +-42 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/f03eecf3bcfe4967a1888156a3115c8d b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/f03eecf3bcfe4967a1888156a3115c8d new file mode 100644 index 0000000000..ea9cd255bc --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/f03eecf3bcfe4967a1888156a3115c8d @@ -0,0 +1 @@ +6.023E+23 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_to_number/fa54ca9186f77122ae2a82684a062e16 b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/fa54ca9186f77122ae2a82684a062e16 new file mode 100644 index 0000000000..00f1e2ed8f --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_to_number/fa54ca9186f77122ae2a82684a062e16 @@ -0,0 +1 @@ +2.71828182846 diff --git a/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl b/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl index f752b59568..ed54abb742 100644 --- a/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl +++ b/tensorflow/core/kernels/fuzzing/tf_ops_fuzz_target_lib.bzl @@ -1,13 +1,19 @@ """Fuzzing template for TensorFlow ops.""" def tf_ops_fuzz_target_lib(name): - native.cc_library( - name = name + "_fuzz_lib", - srcs = [name + "_fuzz.cc"], - deps = [ - "//tensorflow/core/kernels/fuzzing:fuzz_session", - "//tensorflow/cc:cc_ops", - ], - tags = ["no_windows"], - alwayslink = 1, - ) + native.cc_library( + name = name + "_fuzz_lib", + srcs = [name + "_fuzz.cc"], + deps = [ + "//tensorflow/core/kernels/fuzzing:fuzz_session", + "//tensorflow/cc:cc_ops", + ], + tags = ["no_windows"], + alwayslink = 1, + ) + +def tf_oss_fuzz_corpus(name): + native.filegroup( + name = name + "_corpus", + srcs = native.glob(["corpus/" + name + "/*"]), + ) -- GitLab From bd737c846ca453ac06c0a2dadece7c57a1f1efec Mon Sep 17 00:00:00 2001 From: Mark Heffernan Date: Wed, 28 Nov 2018 16:04:22 -0800 Subject: [PATCH 492/672] Replace Shape with a C++ class in XLA. No functional change. Rename the proto message Shape to ShapeProto and define an in-place replacement C++ class named Shape with an interface which mirrors the protobuf generated code interface. Having Shape as a C++ class enables greater flexibility in the interface, enables enforcement of invariants, and potential performance improvements. PiperOrigin-RevId: 223252977 --- tensorflow/compiler/aot/codegen.cc | 9 +- tensorflow/compiler/aot/compile.cc | 16 +- .../compiler/aot/tests/tfcompile_test.cc | 8 +- tensorflow/compiler/tf2xla/shape_util.h | 1 + .../xla_jit_compiled_cpu_function_test.cc | 12 +- tensorflow/compiler/xla/client/BUILD | 1 + tensorflow/compiler/xla/client/client.cc | 18 +- .../xla/client/executable_build_options.h | 1 + tensorflow/compiler/xla/client/lib/testing.cc | 6 +- .../compiler/xla/client/sharding_builder.cc | 4 +- tensorflow/compiler/xla/client/xla_builder.cc | 294 ++++++++++-------- tensorflow/compiler/xla/index_util.h | 1 + tensorflow/compiler/xla/literal.cc | 16 +- tensorflow/compiler/xla/literal_test.cc | 53 ++-- .../compiler/xla/python_api/xla_shape.py | 7 +- tensorflow/compiler/xla/rpc/BUILD | 1 - tensorflow/compiler/xla/rpc/xla_service.proto | 1 - .../xla/service/compile_only_service.cc | 2 +- .../compiler/xla/service/cpu/xfeed_manager.h | 1 + tensorflow/compiler/xla/service/hlo.proto | 6 +- .../compiler/xla/service/hlo_instruction.cc | 142 ++++----- .../compiler/xla/service/hlo_instructions.cc | 4 +- tensorflow/compiler/xla/service/hlo_lexer.h | 1 + tensorflow/compiler/xla/service/hlo_module.cc | 4 +- .../compiler/xla/service/hlo_proto_util.cc | 9 +- .../compiler/xla/service/hlo_proto_util.h | 5 +- .../compiler/xla/service/llvm_ir/ir_array.h | 1 + .../compiler/xla/service/llvm_ir/llvm_util.cc | 7 +- .../compiler/xla/service/local_service.cc | 8 +- tensorflow/compiler/xla/service/service.cc | 36 ++- .../compiler/xla/service/shape_inference.cc | 2 +- tensorflow/compiler/xla/shape.cc | 55 +++- tensorflow/compiler/xla/shape.h | 98 +++++- tensorflow/compiler/xla/shape_test.cc | 63 +++- tensorflow/compiler/xla/shape_util.cc | 34 +- tensorflow/compiler/xla/shape_util.h | 6 +- tensorflow/compiler/xla/shape_util_test.cc | 31 -- .../xla/tests/client_library_test_base.cc | 4 +- tensorflow/compiler/xla/tests/client_test.cc | 6 +- tensorflow/compiler/xla/tests/reshape_test.cc | 6 +- .../compiler/xla/tools/replay_computation.cc | 21 +- tensorflow/compiler/xla/util.h | 7 + tensorflow/compiler/xla/xla.proto | 14 +- tensorflow/compiler/xla/xla_data.proto | 12 +- .../compiler/xrt/kernels/xrt_compile_ops.cc | 11 +- tensorflow/compiler/xrt/tests/raw_api_test.cc | 67 ++-- 46 files changed, 670 insertions(+), 442 deletions(-) diff --git a/tensorflow/compiler/aot/codegen.cc b/tensorflow/compiler/aot/codegen.cc index 697599f3bb..e0ac7130a6 100644 --- a/tensorflow/compiler/aot/codegen.cc +++ b/tensorflow/compiler/aot/codegen.cc @@ -175,7 +175,8 @@ Status GenArgMethods(const tf2xla::Config& config, } for (int i = 0; i < num_args; ++i) { std::vector> rewrites; - TF_RETURN_IF_ERROR(AddRewritesForShape(i, ps.parameters(i), &rewrites)); + TF_RETURN_IF_ERROR( + AddRewritesForShape(i, xla::Shape(ps.parameters(i)), &rewrites)); const string code = R"( void set_arg{{NAME}}_data(void* data) { set_arg_data({{I}}, data); @@ -218,8 +219,8 @@ Status GenResultMethods(const tf2xla::Config& config, } for (int i = 0; i < ps.result().tuple_shapes_size(); ++i) { std::vector> rewrites; - TF_RETURN_IF_ERROR( - AddRewritesForShape(i, ps.result().tuple_shapes(i), &rewrites)); + TF_RETURN_IF_ERROR(AddRewritesForShape( + i, xla::Shape(ps.result().tuple_shapes(i)), &rewrites)); string code = R"( {{TYPE}}* result{{NAME}}_data() { return static_cast<{{TYPE}}*>(result_data({{I}})); @@ -588,7 +589,7 @@ class {{CLASS}} : public tensorflow::XlaCompiledCpuFunction { {"{{METHODS_RESULT}}\n", methods_result}, {"{{NS_END}}\n", ns_end}, {"{{NS_START}}\n", ns_start}, - {"{{PROGRAM_SHAPE}}", xla::ShapeUtil::HumanString(ps)}, + {"{{PROGRAM_SHAPE}}", xla::ShapeUtil::HumanString(xla::ProgramShape(ps))}, {"{{PROGRAM_SHAPE_SHIM_EXPRESSION}}", metadata_result.program_shape_access_shim}, {"{{RESULT_INDEX}}", absl::StrCat(result_index)}, diff --git a/tensorflow/compiler/aot/compile.cc b/tensorflow/compiler/aot/compile.cc index 3bc99ef7e6..9fc223bdc7 100644 --- a/tensorflow/compiler/aot/compile.cc +++ b/tensorflow/compiler/aot/compile.cc @@ -58,15 +58,21 @@ Status CompileXla(xla::CompileOnlyClient* client, } compile_result->program_shape = pshape_or.ValueOrDie()->ToProto(); xla::ProgramShapeProto* pshape = &compile_result->program_shape; - std::vector arg_layouts; - arg_layouts.reserve(pshape->parameters_size()); + + // AotXlaComputationInstance::argument_layouts is a vector of Shape + // pointers. Accumulate the Shape objects themselves in a separate vector + // while building the vector of pointers. + std::vector arg_layout_ptrs(pshape->parameters_size()); + std::vector arg_layouts(pshape->parameters_size()); for (int i = 0; i < pshape->parameters_size(); ++i) { - arg_layouts.push_back(pshape->mutable_parameters(i)); + arg_layouts[i] = xla::Shape(*pshape->mutable_parameters(i)); + arg_layout_ptrs[i] = &arg_layouts[i]; } xla::CompileOnlyClient::AotXlaComputationInstance instance; instance.computation = &computation; - instance.argument_layouts = std::move(arg_layouts); - instance.result_layout = &pshape->result(); + instance.argument_layouts = std::move(arg_layout_ptrs); + xla::Shape result_shape(pshape->result()); + instance.result_layout = &result_shape; xla::StatusOr>> aot_or = client->CompileAheadOfTime({instance}, aot_opts); if (!aot_or.ok()) { diff --git a/tensorflow/compiler/aot/tests/tfcompile_test.cc b/tensorflow/compiler/aot/tests/tfcompile_test.cc index 711feed8f3..4dd79e5882 100644 --- a/tensorflow/compiler/aot/tests/tfcompile_test.cc +++ b/tensorflow/compiler/aot/tests/tfcompile_test.cc @@ -529,10 +529,12 @@ TEST(TFCompileTest, ProgramShape) { const xla::ProgramShapeProto* muladd_shape = muladd.ProgramShape(); ASSERT_TRUE(muladd_shape != nullptr); ASSERT_EQ(muladd_shape->parameters_size(), 2); - EXPECT_TRUE(ShapeUtil::Compatible(muladd_shape->parameters(0), f32_2x2)); - EXPECT_TRUE(ShapeUtil::Compatible(muladd_shape->parameters(1), f32_2x2)); + EXPECT_TRUE( + ShapeUtil::Compatible(xla::Shape(muladd_shape->parameters(0)), f32_2x2)); + EXPECT_TRUE( + ShapeUtil::Compatible(xla::Shape(muladd_shape->parameters(1)), f32_2x2)); - const xla::Shape& muladd_result = muladd_shape->result(); + const xla::Shape muladd_result(muladd_shape->result()); ASSERT_EQ(muladd_result.element_type(), xla::TUPLE); ASSERT_EQ(ShapeUtil::TupleElementCount(muladd_result), 2); const xla::Shape& muladd_result0 = diff --git a/tensorflow/compiler/tf2xla/shape_util.h b/tensorflow/compiler/tf2xla/shape_util.h index f7e34a5b40..0b231ea8e7 100644 --- a/tensorflow/compiler/tf2xla/shape_util.h +++ b/tensorflow/compiler/tf2xla/shape_util.h @@ -18,6 +18,7 @@ limitations under the License. #ifndef TENSORFLOW_COMPILER_TF2XLA_SHAPE_UTIL_H_ #define TENSORFLOW_COMPILER_TF2XLA_SHAPE_UTIL_H_ +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/framework/tensor_shape.h" #include "tensorflow/core/framework/types.pb.h" diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc index 4496255d00..8846088678 100644 --- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc +++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc @@ -116,13 +116,13 @@ TEST(XlaJitCompiledCpuFunction, Sum) { // Check program shape. using xla::ShapeUtil; const xla::Shape s32 = ShapeUtil::MakeShape(xla::S32, {}); - const xla::ProgramShapeProto* program_shape = function.ProgramShape(); - ASSERT_TRUE(program_shape != nullptr); - ASSERT_EQ(program_shape->parameters_size(), 2); - EXPECT_TRUE(ShapeUtil::Compatible(program_shape->parameters(0), s32)); - EXPECT_TRUE(ShapeUtil::Compatible(program_shape->parameters(1), s32)); + ASSERT_TRUE(function.ProgramShape() != nullptr); + const xla::ProgramShape program_shape(*function.ProgramShape()); + ASSERT_EQ(program_shape.parameters_size(), 2); + EXPECT_TRUE(ShapeUtil::Compatible(program_shape.parameters(0), s32)); + EXPECT_TRUE(ShapeUtil::Compatible(program_shape.parameters(1), s32)); - const xla::Shape& result = program_shape->result(); + const xla::Shape& result = program_shape.result(); ASSERT_EQ(result.element_type(), xla::TUPLE); ASSERT_EQ(ShapeUtil::TupleElementCount(result), 1); const xla::Shape& result0 = ShapeUtil::GetTupleElementShape(result, 0); diff --git a/tensorflow/compiler/xla/client/BUILD b/tensorflow/compiler/xla/client/BUILD index ad2e525efd..fe99564d3c 100644 --- a/tensorflow/compiler/xla/client/BUILD +++ b/tensorflow/compiler/xla/client/BUILD @@ -81,6 +81,7 @@ cc_library( "//tensorflow/core:lib", "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:span", ], ) diff --git a/tensorflow/compiler/xla/client/client.cc b/tensorflow/compiler/xla/client/client.cc index eef2844e0d..74b76f9299 100644 --- a/tensorflow/compiler/xla/client/client.cc +++ b/tensorflow/compiler/xla/client/client.cc @@ -20,6 +20,7 @@ limitations under the License. #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" +#include "absl/types/optional.h" #include "tensorflow/compiler/xla/client/xla_computation.h" #include "tensorflow/compiler/xla/debug_options_flags.h" #include "tensorflow/compiler/xla/execution_options_util.h" @@ -42,7 +43,7 @@ StatusOr Client::Transfer(const GlobalData& data, TransferToClientRequest request; *request.mutable_data() = data.handle(); if (shape_with_layout != nullptr) { - *request.mutable_shape_with_layout() = *shape_with_layout; + *request.mutable_shape_with_layout() = shape_with_layout->ToProto(); } TransferToClientResponse response; @@ -123,7 +124,7 @@ StatusOr Client::TransferFromOutfeed( } request.set_replica_id(replica_id); if (shape_with_layout != nullptr) { - *request.mutable_shape_with_layout() = *shape_with_layout; + *request.mutable_shape_with_layout() = shape_with_layout->ToProto(); } TransferFromOutfeedResponse response; @@ -170,11 +171,14 @@ StatusOr Client::ExecuteAndTransfer( std::unique_ptr data, Execute(computation, arguments, execution_options, execution_profile)); - const Shape* shape_with_output_layout = nullptr; + absl::optional shape_with_output_layout; if (execution_options && execution_options->has_shape_with_output_layout()) { - shape_with_output_layout = &execution_options->shape_with_output_layout(); + shape_with_output_layout = + Shape(execution_options->shape_with_output_layout()); } - return Transfer(*data, shape_with_output_layout); + return Transfer(*data, shape_with_output_layout.has_value() + ? &(*shape_with_output_layout) + : nullptr); } StatusOr Client::ComputeConstant(const XlaComputation& computation, @@ -229,7 +233,7 @@ StatusOr Client::Compile( // The argument shapes affect how the computation is compiled. for (const auto& arg_shape : argument_shapes) { - *request.add_input_shape_with_layout() = arg_shape; + *request.add_input_shape_with_layout() = arg_shape.ToProto(); } CompileResponse response; @@ -458,7 +462,7 @@ StatusOr Client::GetShape(const GlobalData& data) { return s; } - return response.shape(); + return Shape(response.shape()); } StatusOr Client::ExecutionStatsAsString( diff --git a/tensorflow/compiler/xla/client/executable_build_options.h b/tensorflow/compiler/xla/client/executable_build_options.h index dd8cb5598a..a58090253b 100644 --- a/tensorflow/compiler/xla/client/executable_build_options.h +++ b/tensorflow/compiler/xla/client/executable_build_options.h @@ -19,6 +19,7 @@ limitations under the License. #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "tensorflow/compiler/xla/service/device_memory_allocator.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/util.h" #include "tensorflow/compiler/xla/xla.pb.h" #include "tensorflow/compiler/xla/xla_data.pb.h" diff --git a/tensorflow/compiler/xla/client/lib/testing.cc b/tensorflow/compiler/xla/client/lib/testing.cc index a44681f586..a95bbf2c8c 100644 --- a/tensorflow/compiler/xla/client/lib/testing.cc +++ b/tensorflow/compiler/xla/client/lib/testing.cc @@ -66,7 +66,7 @@ std::unique_ptr MakeFakeDataViaDeviceOrDie(const Shape& shape, XlaComputation computation = b.Build().ConsumeValueOrDie(); auto execution_options = CreateDefaultExecutionOptions(); - *execution_options.mutable_shape_with_output_layout() = shape; + *execution_options.mutable_shape_with_output_layout() = shape.ToProto(); return client->Execute(computation, /*arguments=*/{}, &execution_options) .ConsumeValueOrDie(); } @@ -98,8 +98,8 @@ std::vector> MakeFakeArgumentsOrDie( auto program_shape = computation.proto().host_program_shape(); std::vector> results; - for (const Shape& shape : program_shape.parameters()) { - results.push_back(MakeFakeDataOrDie(shape, client)); + for (const ShapeProto& shape : program_shape.parameters()) { + results.push_back(MakeFakeDataOrDie(Shape(shape), client)); } return results; } diff --git a/tensorflow/compiler/xla/client/sharding_builder.cc b/tensorflow/compiler/xla/client/sharding_builder.cc index 176802b33e..fb9ea6ec3f 100644 --- a/tensorflow/compiler/xla/client/sharding_builder.cc +++ b/tensorflow/compiler/xla/client/sharding_builder.cc @@ -36,7 +36,7 @@ OpSharding Tile(const Shape& tile_shape, const TileAssignment& tile_assignment) { OpSharding result; result.set_type(OpSharding::Type::OpSharding_Type_OTHER); - *result.mutable_tile_shape() = tile_shape; + *result.mutable_tile_shape() = tile_shape.ToProto(); for (int64 dim : tile_assignment.dimensions()) { result.add_tile_assignment_dimensions(dim); } @@ -52,7 +52,7 @@ OpSharding Tile1D(const Shape& tile_shape, int64 num_tiles) { CHECK_EQ(ShapeUtil::Rank(tile_shape), 1); std::vector dimensions(1, num_tiles); - *result.mutable_tile_shape() = tile_shape; + *result.mutable_tile_shape() = tile_shape.ToProto(); auto& tile_dimension = (*result.mutable_tile_shape()->mutable_dimensions())[0]; tile_dimension = CeilOfRatio(static_cast(tile_dimension), num_tiles); diff --git a/tensorflow/compiler/xla/client/xla_builder.cc b/tensorflow/compiler/xla/client/xla_builder.cc index f17bc456a6..0630f3cf66 100644 --- a/tensorflow/compiler/xla/client/xla_builder.cc +++ b/tensorflow/compiler/xla/client/xla_builder.cc @@ -102,7 +102,7 @@ StatusOr XlaBuilder::GetShape(const XlaOp& op) const { TF_RETURN_IF_ERROR(first_error_); TF_ASSIGN_OR_RETURN(auto instr, LookUpInstruction(op)); - return instr->shape(); + return Shape(instr->shape()); } StatusOr> XlaBuilder::GetOperandShapes( @@ -155,7 +155,7 @@ StatusOr XlaBuilder::GetProgramShape(int64 root_id) const { ProgramShape program_shape; - *program_shape.mutable_result() = root_proto->shape(); + *program_shape.mutable_result() = Shape(root_proto->shape()); // Check that the parameter numbers are continuous from 0, and add parameter // shapes and names to the program shape. @@ -172,7 +172,7 @@ StatusOr XlaBuilder::GetProgramShape(int64 root_id) const { const int64 index = instr.parameter_number(); TF_RET_CHECK(index >= 0 && index < param_count) << "invalid parameter number: " << index; - *program_shape.mutable_parameters(index) = instr.shape(); + *program_shape.mutable_parameters(index) = Shape(instr.shape()); *program_shape.mutable_parameter_names(index) = instr.name(); } } @@ -329,7 +329,7 @@ StatusOr XlaBuilder::InDimBroadcast( TF_RETURN_IF_ERROR(first_error_); HloInstructionProto instr; - *instr.mutable_shape() = shape; + *instr.mutable_shape() = shape.ToProto(); for (int64 dim : broadcast_dimensions) { instr.add_dimensions(dim); } @@ -380,8 +380,9 @@ XlaOp XlaBuilder::UnaryOp(HloOpcode unop, const XlaOp& operand) { return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferUnaryOpShape(unop, operand_shape)); + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), unop, {operand}); }); } @@ -392,9 +393,10 @@ XlaOp XlaBuilder::BinaryOp(HloOpcode binop, const XlaOp& lhs, const XlaOp& rhs, HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& lhs_shape, GetShape(lhs)); TF_ASSIGN_OR_RETURN(const Shape& rhs_shape, GetShape(rhs)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferBinaryOpShape( binop, lhs_shape, rhs_shape, broadcast_dimensions)); + *instr.mutable_shape() = shape.ToProto(); const int64 lhs_rank = ShapeUtil::Rank(lhs_shape); const int64 rhs_rank = ShapeUtil::Rank(rhs_shape); @@ -408,7 +410,7 @@ XlaOp XlaBuilder::BinaryOp(HloOpcode binop, const XlaOp& lhs, const XlaOp& rhs, const Shape& from_shape = should_broadcast_lhs ? lhs_shape : rhs_shape; std::vector to_size; - for (int64 size : instr.shape().dimensions()) { + for (int64 size : shape.dimensions()) { to_size.push_back(size); } for (int64 from_dim = 0; from_dim < ShapeUtil::Rank(from_shape); @@ -428,14 +430,14 @@ XlaOp XlaBuilder::BinaryOp(HloOpcode binop, const XlaOp& lhs, const XlaOp& rhs, } TF_ASSIGN_OR_RETURN(Shape updated_lhs_shape, GetShape(updated_lhs)); - if (!ShapeUtil::SameDimensions(instr.shape(), updated_lhs_shape)) { + if (!ShapeUtil::SameDimensions(shape, updated_lhs_shape)) { TF_ASSIGN_OR_RETURN(updated_lhs, - AddBroadcastSequence(instr.shape(), updated_lhs)); + AddBroadcastSequence(shape, updated_lhs)); } TF_ASSIGN_OR_RETURN(Shape updated_rhs_shape, GetShape(updated_rhs)); - if (!ShapeUtil::SameDimensions(instr.shape(), updated_rhs_shape)) { + if (!ShapeUtil::SameDimensions(shape, updated_rhs_shape)) { TF_ASSIGN_OR_RETURN(updated_rhs, - AddBroadcastSequence(instr.shape(), updated_rhs)); + AddBroadcastSequence(shape, updated_rhs)); } return AddInstruction(std::move(instr), binop, {updated_lhs, updated_rhs}); @@ -449,30 +451,28 @@ XlaOp XlaBuilder::TernaryOp(HloOpcode triop, const XlaOp& lhs, const XlaOp& rhs, TF_ASSIGN_OR_RETURN(const Shape& lhs_shape, GetShape(lhs)); TF_ASSIGN_OR_RETURN(const Shape& rhs_shape, GetShape(rhs)); TF_ASSIGN_OR_RETURN(const Shape& ehs_shape, GetShape(ehs)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), - ShapeInference::InferTernaryOpShape( - triop, lhs_shape, rhs_shape, ehs_shape)); + TF_ASSIGN_OR_RETURN( + Shape shape, ShapeInference::InferTernaryOpShape(triop, lhs_shape, + rhs_shape, ehs_shape)); + *instr.mutable_shape() = shape.ToProto(); XlaOp updated_lhs = lhs; XlaOp updated_rhs = rhs; XlaOp updated_ehs = ehs; - if (!ShapeUtil::IsTuple(instr.shape())) { + if (!ShapeUtil::IsTuple(shape)) { if (!ShapeUtil::IsTuple(lhs_shape) && - !ShapeUtil::SameDimensions(instr.shape(), lhs_shape)) { + !ShapeUtil::SameDimensions(shape, lhs_shape)) { // lhs is being implicitly broadcasted. Change to explicit. - TF_ASSIGN_OR_RETURN(updated_lhs, - AddBroadcastSequence(instr.shape(), lhs)); + TF_ASSIGN_OR_RETURN(updated_lhs, AddBroadcastSequence(shape, lhs)); } if (!ShapeUtil::IsTuple(rhs_shape) && - !ShapeUtil::SameDimensions(instr.shape(), rhs_shape)) { + !ShapeUtil::SameDimensions(shape, rhs_shape)) { // rhs is being implicitly broadcasted. Change to explicit. - TF_ASSIGN_OR_RETURN(updated_rhs, - AddBroadcastSequence(instr.shape(), rhs)); + TF_ASSIGN_OR_RETURN(updated_rhs, AddBroadcastSequence(shape, rhs)); } if (!ShapeUtil::IsTuple(ehs_shape) && - !ShapeUtil::SameDimensions(instr.shape(), ehs_shape)) { + !ShapeUtil::SameDimensions(shape, ehs_shape)) { // ehs is being implicitly broadcasted. Change to explicit. - TF_ASSIGN_OR_RETURN(updated_ehs, - AddBroadcastSequence(instr.shape(), ehs)); + TF_ASSIGN_OR_RETURN(updated_ehs, AddBroadcastSequence(shape, ehs)); } } return AddInstruction(std::move(instr), triop, @@ -493,7 +493,7 @@ XlaOp XlaBuilder::Mul(const XlaOp& lhs, const XlaOp& rhs, XlaOp XlaBuilder::ConstantLiteral(const LiteralSlice& literal) { return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; - *instr.mutable_shape() = literal.shape(); + *instr.mutable_shape() = literal.shape().ToProto(); *instr.mutable_literal() = literal.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kConstant); }); @@ -502,7 +502,7 @@ XlaOp XlaBuilder::ConstantLiteral(const LiteralSlice& literal) { XlaOp XlaBuilder::Iota(const Shape& shape, int64 iota_dimension) { return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; - *instr.mutable_shape() = shape; + *instr.mutable_shape() = shape.ToProto(); instr.add_dimensions(iota_dimension); return AddInstruction(std::move(instr), HloOpcode::kIota); }); @@ -522,10 +522,10 @@ XlaOp XlaBuilder::Call(const XlaComputation& computation, [](const Shape& shape) { return &shape; }); TF_ASSIGN_OR_RETURN(const ProgramShape& called_program_shape, computation.GetProgramShape()); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferCallShape(operand_shape_ptrs, - /*to_apply=*/called_program_shape)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferCallShape( + operand_shape_ptrs, + /*to_apply=*/called_program_shape)); + *instr.mutable_shape() = shape.ToProto(); AddCalledComputation(computation, &instr); @@ -543,7 +543,7 @@ XlaOp XlaBuilder::Parameter(int64 parameter_number, const Shape& shape, } instr.set_parameter_number(parameter_number); instr.set_name(name); - *instr.mutable_shape() = shape; + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kParameter); }); } @@ -601,7 +601,7 @@ StatusOr XlaBuilder::Reshape(const Shape& shape, const XlaOp& operand) { TF_RETURN_IF_ERROR(first_error_); HloInstructionProto instr; - *instr.mutable_shape() = shape; + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kReshape, {operand}); } @@ -613,9 +613,9 @@ XlaOp XlaBuilder::Slice(const XlaOp& operand, HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferSliceShape(operand_shape, start_indices, - limit_indices, strides)); + Shape shape, ShapeInference::InferSliceShape( + operand_shape, start_indices, limit_indices, strides)); + *instr.mutable_shape() = shape.ToProto(); for (int i = 0; i < start_indices.size(); i++) { auto* slice_config = instr.add_slice_dimensions(); slice_config->set_start(start_indices[i]); @@ -650,9 +650,10 @@ XlaOp XlaBuilder::DynamicSlice(const XlaOp& operand, const XlaOp& start_indices, TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); TF_ASSIGN_OR_RETURN(const Shape& start_indices_shape, GetShape(start_indices)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferDynamicSliceShape( operand_shape, start_indices_shape, slice_sizes)); + *instr.mutable_shape() = shape.ToProto(); for (int64 size : slice_sizes) { instr.add_dynamic_slice_sizes(size); @@ -672,9 +673,10 @@ XlaOp XlaBuilder::DynamicUpdateSlice(const XlaOp& operand, const XlaOp& update, TF_ASSIGN_OR_RETURN(const Shape& update_shape, GetShape(update)); TF_ASSIGN_OR_RETURN(const Shape& start_indices_shape, GetShape(start_indices)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferDynamicUpdateSliceShape( operand_shape, update_shape, start_indices_shape)); + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kDynamicUpdateSlice, {operand, update, start_indices}); @@ -690,9 +692,9 @@ XlaOp XlaBuilder::ConcatInDim(absl::Span operands, TF_ASSIGN_OR_RETURN(const auto& operand_shapes, GetOperandShapes(operands)); absl::c_transform(operand_shapes, std::back_inserter(operand_shape_ptrs), [](const Shape& shape) { return &shape; }); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferConcatOpShape(operand_shape_ptrs, dimension)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferConcatOpShape( + operand_shape_ptrs, dimension)); + *instr.mutable_shape() = shape.ToProto(); instr.add_dimensions(dimension); @@ -709,10 +711,9 @@ XlaOp XlaBuilder::Pad(const XlaOp& operand, const XlaOp& padding_value, TF_ASSIGN_OR_RETURN(const Shape& padding_value_shape, GetShape(padding_value)); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferPadShape(operand_shape, padding_value_shape, - padding_config)); - + Shape shape, ShapeInference::InferPadShape( + operand_shape, padding_value_shape, padding_config)); + *instr.mutable_shape() = shape.ToProto(); *instr.mutable_padding_config() = padding_config; return AddInstruction(std::move(instr), HloOpcode::kPad, @@ -725,7 +726,7 @@ XlaOp XlaBuilder::Reshape(const XlaOp& operand, absl::Span new_sizes) { return ReportErrorOrReturn([&]() -> StatusOr { TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN(const Shape& shape, + TF_ASSIGN_OR_RETURN(const Shape shape, ShapeInference::InferReshapeShape( operand_shape, dimensions, new_sizes)); XlaOp transposed = IsIdentityPermutation(dimensions) @@ -738,7 +739,7 @@ XlaOp XlaBuilder::Reshape(const XlaOp& operand, XlaOp XlaBuilder::Reshape(const XlaOp& operand, absl::Span new_sizes) { return ReportErrorOrReturn([&]() -> StatusOr { - TF_ASSIGN_OR_RETURN(auto shape, GetShape(operand)); + TF_ASSIGN_OR_RETURN(Shape shape, GetShape(operand)); std::vector dimensions(shape.dimensions_size()); std::iota(dimensions.begin(), dimensions.end(), 0); return Reshape(operand, dimensions, new_sizes); @@ -788,7 +789,7 @@ XlaOp XlaBuilder::Collapse(const XlaOp& operand, void XlaBuilder::Trace(const string& tag, const XlaOp& operand) { ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; - *instr.mutable_shape() = ShapeUtil::MakeNil(); + *instr.mutable_shape() = ShapeUtil::MakeNil().ToProto(); *instr.mutable_literal() = LiteralUtil::CreateR1U8(tag).ToProto(); return AddInstruction(std::move(instr), HloOpcode::kTrace, {operand}); }); @@ -814,9 +815,10 @@ XlaOp XlaBuilder::Tuple(absl::Span elements) { TF_ASSIGN_OR_RETURN(const auto& operand_shapes, GetOperandShapes(elements)); absl::c_transform(operand_shapes, std::back_inserter(operand_shape_ptrs), [](const Shape& shape) { return &shape; }); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(const Shape shape, ShapeInference::InferVariadicOpShape( HloOpcode::kTuple, operand_shape_ptrs)); + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kTuple, elements); }); } @@ -831,7 +833,7 @@ XlaOp XlaBuilder::GetTupleElement(const XlaOp& tuple_data, int64 index) { ShapeUtil::HumanString(tuple_shape)); } *instr.mutable_shape() = - ShapeUtil::GetTupleElementShape(tuple_shape, index); + ShapeUtil::GetTupleElementShape(tuple_shape, index).ToProto(); instr.set_tuple_index(index); @@ -890,9 +892,10 @@ XlaOp XlaBuilder::DotGeneral(const XlaOp& lhs, const XlaOp& rhs, HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& lhs_shape, GetShape(lhs)); TF_ASSIGN_OR_RETURN(const Shape& rhs_shape, GetShape(rhs)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferDotOpShape(lhs_shape, rhs_shape, dimension_numbers)); + *instr.mutable_shape() = shape.ToProto(); *instr.mutable_dot_dimension_numbers() = dimension_numbers; if (precision_config != nullptr) { *instr.mutable_precision_config() = *precision_config; @@ -1034,10 +1037,11 @@ XlaOp XlaBuilder::ConvGeneralDilated( MakeWindow(window_dimensions, window_strides, padding, lhs_dilation, rhs_dilation)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferConvolveShape( lhs_shape, rhs_shape, feature_group_count, instr.window(), dimension_numbers)); + *instr.mutable_shape() = shape.ToProto(); *instr.mutable_convolution_dimension_numbers() = dimension_numbers; instr.set_feature_group_count(feature_group_count); @@ -1110,10 +1114,9 @@ XlaOp XlaBuilder::Fft(const XlaOp& operand, const FftType fft_type, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferFftShape(operand_shape, fft_type, fft_length)); - + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferFftShape( + operand_shape, fft_type, fft_length)); + *instr.mutable_shape() = shape.ToProto(); instr.set_fft_type(fft_type); for (int64 i : fft_length) { instr.add_fft_length(i); @@ -1131,7 +1134,7 @@ XlaOp XlaBuilder::Infeed(const Shape& shape, const string& config) { } const Shape infeed_instruction_shape = ShapeUtil::MakeTupleShape({shape, ShapeUtil::MakeTokenShape()}); - *instr.mutable_shape() = infeed_instruction_shape; + *instr.mutable_shape() = infeed_instruction_shape.ToProto(); instr.set_infeed_config(config); if (ShapeUtil::IsArray(shape) && sharding() && @@ -1152,7 +1155,7 @@ XlaOp XlaBuilder::Infeed(const Shape& shape, const string& config) { XlaOp token; auto make_token = [&]() { HloInstructionProto token_instr; - *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); return AddInstruction(std::move(token_instr), HloOpcode::kAfterAll, {}); }; if (sharding()) { @@ -1191,7 +1194,7 @@ XlaOp XlaBuilder::Infeed(const Shape& shape, const string& config) { // TODO(b/80000000): Remove this when clients have been updated to handle // tokens. HloInstructionProto infeed_data; - *infeed_data.mutable_shape() = shape; + *infeed_data.mutable_shape() = shape.ToProto(); infeed_data.set_tuple_index(0); return AddInstruction(std::move(infeed_data), HloOpcode::kGetTupleElement, {infeed}); @@ -1207,7 +1210,7 @@ XlaOp XlaBuilder::InfeedWithToken(const XlaOp& token, const Shape& shape, } const Shape infeed_instruction_shape = ShapeUtil::MakeTupleShape({shape, ShapeUtil::MakeTokenShape()}); - *instr.mutable_shape() = infeed_instruction_shape; + *instr.mutable_shape() = infeed_instruction_shape.ToProto(); instr.set_infeed_config(config); if (ShapeUtil::IsArray(shape) && sharding() && @@ -1232,7 +1235,7 @@ void XlaBuilder::Outfeed(const XlaOp& operand, const Shape& shape_with_layout, ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; - *instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); // Check and set outfeed shape. if (!LayoutUtil::HasLayout(shape_with_layout)) { @@ -1245,14 +1248,14 @@ void XlaBuilder::Outfeed(const XlaOp& operand, const Shape& shape_with_layout, ShapeUtil::HumanStringWithLayout(shape_with_layout), ShapeUtil::HumanStringWithLayout(operand_shape)); } - *instr.mutable_outfeed_shape() = shape_with_layout; + *instr.mutable_outfeed_shape() = shape_with_layout.ToProto(); instr.set_outfeed_config(outfeed_config); // Outfeed takes a token as its second operand. Generate the token to pass // to the outfeed. HloInstructionProto token_instr; - *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); TF_ASSIGN_OR_RETURN(XlaOp token, AddInstruction(std::move(token_instr), HloOpcode::kAfterAll, {})); @@ -1266,7 +1269,7 @@ void XlaBuilder::Outfeed(const XlaOp& operand, const Shape& shape_with_layout, // TODO(b/80000000): Remove this when clients have been updated to handle // tokens. HloInstructionProto tuple_instr; - *tuple_instr.mutable_shape() = ShapeUtil::MakeNil(); + *tuple_instr.mutable_shape() = ShapeUtil::MakeNil().ToProto(); // The dummy tuple should have no sharding. { @@ -1285,7 +1288,7 @@ XlaOp XlaBuilder::OutfeedWithToken(const XlaOp& operand, const XlaOp& token, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; - *instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); // Check and set outfeed shape. if (!LayoutUtil::HasLayout(shape_with_layout)) { @@ -1298,7 +1301,7 @@ XlaOp XlaBuilder::OutfeedWithToken(const XlaOp& operand, const XlaOp& token, ShapeUtil::HumanStringWithLayout(shape_with_layout), ShapeUtil::HumanStringWithLayout(operand_shape)); } - *instr.mutable_outfeed_shape() = shape_with_layout; + *instr.mutable_outfeed_shape() = shape_with_layout.ToProto(); instr.set_outfeed_config(outfeed_config); @@ -1310,7 +1313,7 @@ XlaOp XlaBuilder::OutfeedWithToken(const XlaOp& operand, const XlaOp& token, XlaOp XlaBuilder::CreateToken() { return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; - *instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); return AddInstruction(std::move(instr), HloOpcode::kAfterAll); }); } @@ -1330,7 +1333,7 @@ XlaOp XlaBuilder::AfterAll(absl::Span tokens) { } } HloInstructionProto instr; - *instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); return AddInstruction(std::move(instr), HloOpcode::kAfterAll, tokens); }); } @@ -1347,7 +1350,7 @@ XlaOp XlaBuilder::CustomCall( "are reserved for internal use.", call_target_name); } - *instr.mutable_shape() = shape; + *instr.mutable_shape() = shape.ToProto(); instr.set_custom_call_target(call_target_name); instr.set_custom_call_opaque(opaque); if (operand_shapes_with_layout.has_value()) { @@ -1371,7 +1374,7 @@ XlaOp XlaBuilder::CustomCall( "constrained layout.", operand_num); } - *instr.add_operand_shapes_with_layout() = operand_shape; + *instr.add_operand_shapes_with_layout() = operand_shape.ToProto(); ++operand_num; } } @@ -1525,9 +1528,9 @@ XlaOp XlaBuilder::Transpose(const XlaOp& operand, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferTransposeShape(operand_shape, permutation)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferTransposeShape( + operand_shape, permutation)); + *instr.mutable_shape() = shape.ToProto(); for (int64 dim : permutation) { instr.add_dimensions(dim); } @@ -1540,9 +1543,9 @@ XlaOp XlaBuilder::Rev(const XlaOp& operand, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferReverseShape(operand_shape, dimensions)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferReverseShape( + operand_shape, dimensions)); + *instr.mutable_shape() = shape.ToProto(); for (int64 dim : dimensions) { instr.add_dimensions(dim); } @@ -1561,9 +1564,9 @@ XlaOp XlaBuilder::Sort(const XlaOp& keys, absl::Span values, GetOperandShapes(values)); absl::c_transform(values_shapes, std::back_inserter(operand_shape_ptrs), [](const Shape& shape) { return &shape; }); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), - ShapeInference::InferVariadicOpShape( - HloOpcode::kSort, operand_shape_ptrs)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferVariadicOpShape( + HloOpcode::kSort, operand_shape_ptrs)); + *instr.mutable_shape() = shape.ToProto(); if (dimension == -1) { TF_ASSIGN_OR_RETURN(const Shape& keys_shape, GetShape(keys)); dimension = ShapeUtil::Rank(keys_shape) - 1; @@ -1585,9 +1588,9 @@ XlaOp XlaBuilder::ConvertElementType(const XlaOp& operand, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferConvertShape(operand_shape, new_element_type)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferConvertShape( + operand_shape, new_element_type)); + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kConvert, {operand}); }); } @@ -1597,9 +1600,9 @@ XlaOp XlaBuilder::BitcastConvertType(const XlaOp& operand, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferConvertShape(operand_shape, new_element_type)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferConvertShape( + operand_shape, new_element_type)); + *instr.mutable_shape() = shape.ToProto(); return AddInstruction(std::move(instr), HloOpcode::kBitcastConvert, {operand}); }); @@ -1631,11 +1634,11 @@ XlaOp XlaBuilder::Map(absl::Span operands, TF_ASSIGN_OR_RETURN(const ProgramShape& called_program_shape, computation.GetProgramShape()); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferMapShape(operand_shape_ptrs, called_program_shape, - dimensions)); + Shape shape, ShapeInference::InferMapShape( + operand_shape_ptrs, called_program_shape, dimensions)); + *instr.mutable_shape() = shape.ToProto(); - const Shape& output_shape = instr.shape(); + Shape output_shape(instr.shape()); const int64 output_rank = ShapeUtil::Rank(output_shape); AddCalledComputation(computation, &instr); std::vector new_operands(operands.begin(), operands.end()); @@ -1678,7 +1681,7 @@ XlaOp XlaBuilder::RngOp(RandomDistribution distribution, } TF_RETURN_IF_ERROR(ShapeUtil::ValidateShapeWithOptionalLayout(shape)); - *instr.mutable_shape() = shape; + *instr.mutable_shape() = shape.ToProto(); instr.set_distribution(distribution); @@ -1706,10 +1709,10 @@ XlaOp XlaBuilder::While(const XlaComputation& condition, TF_ASSIGN_OR_RETURN(const auto& condition_program_shape, condition.GetProgramShape()); TF_ASSIGN_OR_RETURN(const Shape& init_shape, GetShape(init)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferWhileShape(condition_program_shape, - body_program_shape, init_shape)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferWhileShape( + condition_program_shape, + body_program_shape, init_shape)); + *instr.mutable_shape() = shape.ToProto(); // Body comes before condition computation in the vector. AddCalledComputation(body, &instr); AddCalledComputation(condition, &instr); @@ -1726,10 +1729,10 @@ XlaOp XlaBuilder::Gather(const XlaOp& input, const XlaOp& start_indices, TF_ASSIGN_OR_RETURN(const Shape& input_shape, GetShape(input)); TF_ASSIGN_OR_RETURN(const Shape& start_indices_shape, GetShape(start_indices)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferGatherShape(input_shape, start_indices_shape, + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferGatherShape( + input_shape, start_indices_shape, dimension_numbers, slice_sizes)); + *instr.mutable_shape() = shape.ToProto(); *instr.mutable_gather_dimension_numbers() = dimension_numbers; for (int64 bound : slice_sizes) { @@ -1754,10 +1757,11 @@ XlaOp XlaBuilder::Scatter(const XlaOp& input, const XlaOp& scatter_indices, TF_ASSIGN_OR_RETURN(const Shape& updates_shape, GetShape(updates)); TF_ASSIGN_OR_RETURN(const ProgramShape& to_apply_shape, update_computation.GetProgramShape()); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferScatterShape( input_shape, scatter_indices_shape, updates_shape, to_apply_shape, dimension_numbers)); + *instr.mutable_shape() = shape.ToProto(); *instr.mutable_scatter_dimension_numbers() = dimension_numbers; @@ -1784,10 +1788,11 @@ XlaOp XlaBuilder::Conditional(const XlaOp& predicate, const XlaOp& true_operand, TF_ASSIGN_OR_RETURN(const ProgramShape& false_computation_shape, false_computation.GetProgramShape()); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), + Shape shape, ShapeInference::InferConditionalShape( predicate_shape, true_operand_shape, false_operand_shape, true_computation_shape, false_computation_shape)); + *instr.mutable_shape() = shape.ToProto(); // The index of true_computation must be 0 and that of false computation // must be 1. @@ -1829,9 +1834,10 @@ XlaOp XlaBuilder::Reduce(absl::Span operands, [](const Shape& shape) { return &shape; }); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), + Shape shape, ShapeInference::InferReduceShape( operand_shape_ptrs, dimensions_to_reduce, called_program_shape)); + *instr.mutable_shape() = shape.ToProto(); for (int64 dim : dimensions_to_reduce) { instr.add_dimensions(dim); @@ -1894,10 +1900,10 @@ XlaOp XlaBuilder::ReduceWindowWithGeneralPadding( MakeWindow(window_dimensions, window_strides, padding, /*lhs_dilation=*/base_dilations, /*rhs_dilation=*/window_dilations)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferReduceWindowShape(operand_shape, init_shape, - instr.window(), to_apply_shape)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferReduceWindowShape( + operand_shape, init_shape, + instr.window(), to_apply_shape)); + *instr.mutable_shape() = shape.ToProto(); AddCalledComputation(computation, &instr); return AddInstruction(std::move(instr), HloOpcode::kReduceWindow, @@ -1915,9 +1921,10 @@ XlaOp XlaBuilder::BatchNormTraining(const XlaOp& operand, const XlaOp& scale, TF_ASSIGN_OR_RETURN(const Shape& scale_shape, GetShape(scale)); TF_ASSIGN_OR_RETURN(const Shape& offset_shape, GetShape(offset)); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), + Shape shape, ShapeInference::InferBatchNormTrainingShape( operand_shape, scale_shape, offset_shape, feature_index)); + *instr.mutable_shape() = shape.ToProto(); instr.set_epsilon(epsilon); instr.set_feature_index(feature_index); @@ -1939,10 +1946,11 @@ XlaOp XlaBuilder::BatchNormInference(const XlaOp& operand, const XlaOp& scale, TF_ASSIGN_OR_RETURN(const Shape& offset_shape, GetShape(offset)); TF_ASSIGN_OR_RETURN(const Shape& mean_shape, GetShape(mean)); TF_ASSIGN_OR_RETURN(const Shape& variance_shape, GetShape(variance)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), - ShapeInference::InferBatchNormInferenceShape( - operand_shape, scale_shape, offset_shape, - mean_shape, variance_shape, feature_index)); + TF_ASSIGN_OR_RETURN( + Shape shape, ShapeInference::InferBatchNormInferenceShape( + operand_shape, scale_shape, offset_shape, mean_shape, + variance_shape, feature_index)); + *instr.mutable_shape() = shape.ToProto(); instr.set_epsilon(epsilon); instr.set_feature_index(feature_index); @@ -1964,10 +1972,11 @@ XlaOp XlaBuilder::BatchNormGrad(const XlaOp& operand, const XlaOp& scale, TF_ASSIGN_OR_RETURN(const Shape& batch_mean_shape, GetShape(batch_mean)); TF_ASSIGN_OR_RETURN(const Shape& batch_var_shape, GetShape(batch_var)); TF_ASSIGN_OR_RETURN(const Shape& grad_output_shape, GetShape(grad_output)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferBatchNormGradShape( operand_shape, scale_shape, batch_mean_shape, batch_var_shape, grad_output_shape, feature_index)); + *instr.mutable_shape() = shape.ToProto(); instr.set_epsilon(epsilon); instr.set_feature_index(feature_index); @@ -1998,9 +2007,9 @@ XlaOp XlaBuilder::CrossReplicaSum( return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferCrossReplicaSumShape({&operand_shape})); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferCrossReplicaSumShape( + {&operand_shape})); + *instr.mutable_shape() = shape.ToProto(); for (const ReplicaGroup& group : replica_groups) { *instr.add_replica_groups() = group; @@ -2053,8 +2062,8 @@ XlaOp XlaBuilder::AllToAll(const XlaOp& operand, int64 split_dimension, absl::c_transform(slice_shapes, std::back_inserter(slice_shape_ptrs), [](const Shape& shape) { return &shape; }); TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferAllToAllTupleShape(slice_shape_ptrs)); + Shape shape, ShapeInference::InferAllToAllTupleShape(slice_shape_ptrs)); + *instr.mutable_shape() = shape.ToProto(); for (const ReplicaGroup& group : replica_groups) { *instr.add_replica_groups() = group; } @@ -2079,8 +2088,9 @@ XlaOp XlaBuilder::CollectivePermute( TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); HloInstructionProto instr; TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), + Shape shape, ShapeInference::InferCollectivePermuteShape(operand_shape)); + *instr.mutable_shape() = shape.ToProto(); for (const auto& pair : source_target_pairs) { auto* proto_pair = instr.add_source_target_pairs(); @@ -2129,10 +2139,11 @@ XlaOp XlaBuilder::SelectAndScatterWithGeneralPadding( TF_ASSIGN_OR_RETURN(*instr.mutable_window(), MakeWindow(window_dimensions, window_strides, padding, /*lhs_dilation=*/{}, /*rhs_dilation=*/{})); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferSelectAndScatterShape( operand_shape, select_shape, instr.window(), source_shape, init_shape, scatter_shape)); + *instr.mutable_shape() = shape.ToProto(); AddCalledComputation(select, &instr); AddCalledComputation(scatter, &instr); @@ -2147,9 +2158,10 @@ XlaOp XlaBuilder::ReducePrecision(const XlaOp& operand, const int exponent_bits, return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN(*instr.mutable_shape(), + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferReducePrecisionShape( operand_shape, exponent_bits, mantissa_bits)); + *instr.mutable_shape() = shape.ToProto(); instr.set_exponent_bits(exponent_bits); instr.set_mantissa_bits(mantissa_bits); return AddInstruction(std::move(instr), HloOpcode::kReducePrecision, @@ -2164,7 +2176,7 @@ void XlaBuilder::Send(const XlaOp& operand, const ChannelHandle& handle) { // TODO(b/80000000): Remove this when clients have been updated to handle // tokens. HloInstructionProto token_instr; - *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); TF_ASSIGN_OR_RETURN(XlaOp token, AddInstruction(std::move(token_instr), HloOpcode::kAfterAll, {})); @@ -2183,15 +2195,17 @@ XlaOp XlaBuilder::SendWithToken(const XlaOp& operand, const XlaOp& token, // token}. HloInstructionProto send_instr; TF_ASSIGN_OR_RETURN(const Shape& shape, GetShape(operand)); - *send_instr.mutable_shape() = ShapeUtil::MakeTupleShape( - {shape, ShapeUtil::MakeShape(U32, {}), ShapeUtil::MakeTokenShape()}); + *send_instr.mutable_shape() = + ShapeUtil::MakeTupleShape( + {shape, ShapeUtil::MakeShape(U32, {}), ShapeUtil::MakeTokenShape()}) + .ToProto(); send_instr.set_channel_id(handle.handle()); TF_ASSIGN_OR_RETURN(XlaOp send, AddInstruction(std::move(send_instr), HloOpcode::kSend, {operand, token})); HloInstructionProto send_done_instr; - *send_done_instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *send_done_instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); send_done_instr.set_channel_id(handle.handle()); return AddInstruction(std::move(send_done_instr), HloOpcode::kSendDone, {send}); @@ -2205,7 +2219,7 @@ XlaOp XlaBuilder::Recv(const Shape& shape, const ChannelHandle& handle) { // TODO(b/80000000): Remove this when clients have been updated to handle // tokens. HloInstructionProto token_instr; - *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *token_instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); TF_ASSIGN_OR_RETURN(XlaOp token, AddInstruction(std::move(token_instr), HloOpcode::kAfterAll, {})); @@ -2216,7 +2230,7 @@ XlaOp XlaBuilder::Recv(const Shape& shape, const ChannelHandle& handle) { // TODO(b/80000000): Remove this when clients have been updated to handle // tokens. HloInstructionProto recv_data; - *recv_data.mutable_shape() = shape; + *recv_data.mutable_shape() = shape.ToProto(); recv_data.set_tuple_index(0); return AddInstruction(std::move(recv_data), HloOpcode::kGetTupleElement, {recv}); @@ -2233,15 +2247,18 @@ XlaOp XlaBuilder::RecvWithToken(const XlaOp& token, const Shape& shape, // Recv instruction produces a tuple of {receive buffer, U32 context, // token}. HloInstructionProto recv_instr; - *recv_instr.mutable_shape() = ShapeUtil::MakeTupleShape( - {shape, ShapeUtil::MakeShape(U32, {}), ShapeUtil::MakeTokenShape()}); + *recv_instr.mutable_shape() = + ShapeUtil::MakeTupleShape( + {shape, ShapeUtil::MakeShape(U32, {}), ShapeUtil::MakeTokenShape()}) + .ToProto(); recv_instr.set_channel_id(handle.handle()); TF_ASSIGN_OR_RETURN(XlaOp recv, AddInstruction(std::move(recv_instr), HloOpcode::kRecv, {token})); HloInstructionProto recv_done_instr; *recv_done_instr.mutable_shape() = - ShapeUtil::MakeTupleShape({shape, ShapeUtil::MakeTokenShape()}); + ShapeUtil::MakeTupleShape({shape, ShapeUtil::MakeTokenShape()}) + .ToProto(); recv_done_instr.set_channel_id(handle.handle()); return AddInstruction(std::move(recv_done_instr), HloOpcode::kRecvDone, {recv}); @@ -2275,9 +2292,11 @@ XlaOp XlaBuilder::SendToHost(const XlaOp& operand, const XlaOp& token, // Send instruction produces a tuple of {aliased operand, U32 context, // token}. HloInstructionProto send_instr; - *send_instr.mutable_shape() = ShapeUtil::MakeTupleShape( - {shape_with_layout, ShapeUtil::MakeShape(U32, {}), - ShapeUtil::MakeTokenShape()}); + *send_instr.mutable_shape() = + ShapeUtil::MakeTupleShape({shape_with_layout, + ShapeUtil::MakeShape(U32, {}), + ShapeUtil::MakeTokenShape()}) + .ToProto(); send_instr.set_channel_id(handle.handle()); send_instr.set_is_host_transfer(true); TF_ASSIGN_OR_RETURN(XlaOp send, @@ -2285,7 +2304,7 @@ XlaOp XlaBuilder::SendToHost(const XlaOp& operand, const XlaOp& token, {operand, token})); HloInstructionProto send_done_instr; - *send_done_instr.mutable_shape() = ShapeUtil::MakeTokenShape(); + *send_done_instr.mutable_shape() = ShapeUtil::MakeTokenShape().ToProto(); send_done_instr.set_channel_id(handle.handle()); send_done_instr.set_is_host_transfer(true); return AddInstruction(std::move(send_done_instr), HloOpcode::kSendDone, @@ -2314,8 +2333,10 @@ XlaOp XlaBuilder::RecvFromHost(const XlaOp& token, const Shape& shape, // Recv instruction produces a tuple of {receive buffer, U32 context, // token}. HloInstructionProto recv_instr; - *recv_instr.mutable_shape() = ShapeUtil::MakeTupleShape( - {shape, ShapeUtil::MakeShape(U32, {}), ShapeUtil::MakeTokenShape()}); + *recv_instr.mutable_shape() = + ShapeUtil::MakeTupleShape( + {shape, ShapeUtil::MakeShape(U32, {}), ShapeUtil::MakeTokenShape()}) + .ToProto(); recv_instr.set_channel_id(handle.handle()); recv_instr.set_is_host_transfer(true); TF_ASSIGN_OR_RETURN(XlaOp recv, AddInstruction(std::move(recv_instr), @@ -2323,7 +2344,8 @@ XlaOp XlaBuilder::RecvFromHost(const XlaOp& token, const Shape& shape, HloInstructionProto recv_done_instr; *recv_done_instr.mutable_shape() = - ShapeUtil::MakeTupleShape({shape, ShapeUtil::MakeTokenShape()}); + ShapeUtil::MakeTupleShape({shape, ShapeUtil::MakeTokenShape()}) + .ToProto(); recv_done_instr.set_channel_id(handle.handle()); recv_done_instr.set_is_host_transfer(true); return AddInstruction(std::move(recv_done_instr), HloOpcode::kRecvDone, @@ -2335,9 +2357,9 @@ XlaOp XlaBuilder::GetDimensionSize(const XlaOp& operand, int64 dimension) { return ReportErrorOrReturn([&]() -> StatusOr { HloInstructionProto instr; TF_ASSIGN_OR_RETURN(const auto& operand_shape, GetShape(operand)); - TF_ASSIGN_OR_RETURN( - *instr.mutable_shape(), - ShapeInference::InferGetDimensionSizeShape(operand_shape, dimension)); + TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferGetDimensionSizeShape( + operand_shape, dimension)); + *instr.mutable_shape() = shape.ToProto(); instr.add_dimensions(dimension); return AddInstruction(std::move(instr), HloOpcode::kGetDimensionSize, {operand}); diff --git a/tensorflow/compiler/xla/index_util.h b/tensorflow/compiler/xla/index_util.h index 458bdaf2f8..d76f61eb62 100644 --- a/tensorflow/compiler/xla/index_util.h +++ b/tensorflow/compiler/xla/index_util.h @@ -21,6 +21,7 @@ limitations under the License. #include #include "absl/types/span.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/platform/macros.h" diff --git a/tensorflow/compiler/xla/literal.cc b/tensorflow/compiler/xla/literal.cc index f2fcb93717..8f480c1f10 100644 --- a/tensorflow/compiler/xla/literal.cc +++ b/tensorflow/compiler/xla/literal.cc @@ -292,16 +292,17 @@ Status MutableLiteralBase::CopyElementFrom(const LiteralSlice& src_literal, if (!proto.has_shape()) { return InvalidArgument("LiteralProto has no shape"); } - if (ShapeUtil::HasPrimitiveType(proto.shape(), OPAQUE)) { + Shape shape(proto.shape()); + if (ShapeUtil::HasPrimitiveType(shape, OPAQUE)) { return InvalidArgument("Literal shape cannot include OPAQUE sub-shape"); } - if (!LayoutUtil::HasLayout(proto.shape())) { + if (!LayoutUtil::HasLayout(shape)) { return InvalidArgument("LiteralProto has no layout"); } - TF_RETURN_IF_ERROR(ShapeUtil::ValidateShapeWithOptionalLayout(proto.shape())); + TF_RETURN_IF_ERROR(ShapeUtil::ValidateShapeWithOptionalLayout(shape)); - Literal literal(proto.shape()); + Literal literal(shape); TF_RETURN_IF_ERROR(literal.root_piece_->ForEachMutableSubpieceWithStatus( [&](const ShapeIndex& index, Piece* piece) { @@ -1794,7 +1795,7 @@ void CopyToRepeatedField(RepeatedFieldT* dest, } // namespace void LiteralBase::Piece::WriteToProto(LiteralProto* proto) const { - *proto->mutable_shape() = subshape(); + *proto->mutable_shape() = subshape().ToProto(); switch (subshape().element_type()) { case PRED: CopyToRepeatedField(proto->mutable_preds(), data()); @@ -1900,8 +1901,9 @@ Status LiteralBase::Piece::CopyFromProto(const LiteralProto& proto) { // These conditions should have been checked in // MutableLiteralBase::CreateFromProto. TF_RET_CHECK(proto.has_shape()); - TF_RET_CHECK(LayoutUtil::HasLayout(proto.shape())); - TF_RET_CHECK(ShapeUtil::Equal(proto.shape(), subshape())); + Shape shape(proto.shape()); + TF_RET_CHECK(LayoutUtil::HasLayout(shape)); + TF_RET_CHECK(ShapeUtil::Equal(shape, subshape())); if (LayoutUtil::IsSparseArray(subshape())) { // Compute the number of elements (indices) in the sparse shape and reserve diff --git a/tensorflow/compiler/xla/literal_test.cc b/tensorflow/compiler/xla/literal_test.cc index bd93517728..49363ad802 100644 --- a/tensorflow/compiler/xla/literal_test.cc +++ b/tensorflow/compiler/xla/literal_test.cc @@ -1377,13 +1377,26 @@ TEST_F(LiteralUtilTest, BitcastConvertBetweenInvalidTypes) { absl::StrContains(status.error_message(), "bit widths are different")); } +// Sets the layout of the given ShapeProto to the default. +void SetDefaultLayoutOnProto(ShapeProto* shape_proto) { + CHECK(ShapeUtil::IsArrayPrimitiveType(shape_proto->element_type())); + shape_proto->mutable_layout()->set_format(DENSE); + auto* minor_to_major = + shape_proto->mutable_layout()->mutable_minor_to_major(); + minor_to_major->Resize(shape_proto->dimensions_size(), 0); + const int64 size = minor_to_major->size(); + for (int64 i = 0; i < size; ++i) { + minor_to_major->Set(i, size - 1 - i); + } +} + TEST_F(LiteralUtilTest, CopyFromProto_Bool) { LiteralProto p; p.mutable_shape()->set_element_type(PRED); for (int len = 0; len < 25; ++len) { p.mutable_shape()->clear_dimensions(); p.mutable_shape()->add_dimensions(len); - LayoutUtil::SetToDefaultLayout(p.mutable_shape()); + SetDefaultLayoutOnProto(p.mutable_shape()); p.clear_preds(); for (int i = 0; i < len; ++i) { p.add_preds((i % 2) == (len % 2)); @@ -1409,7 +1422,7 @@ TEST_F(LiteralUtilTest, ToProto_f16) { EXPECT_EQ(4, m.data().size()); LiteralProto p = m.ToProto(); - EXPECT_EQ(4, ShapeUtil::ElementsIn(p.shape())); + EXPECT_EQ(4, ShapeUtil::ElementsIn(Shape(p.shape()))); EXPECT_EQ(8, p.f16s().size()); const char* d = p.f16s().data(); EXPECT_EQ(d[0], 0); @@ -1432,7 +1445,7 @@ TEST_F(LiteralUtilTest, CopyFromProto_f16) { p.mutable_shape()->set_element_type(F16); p.mutable_shape()->clear_dimensions(); p.mutable_shape()->add_dimensions(4); - LayoutUtil::SetToDefaultLayout(p.mutable_shape()); + SetDefaultLayoutOnProto(p.mutable_shape()); p.clear_f16s(); p.set_f16s(half_vals, 8); TF_ASSERT_OK_AND_ASSIGN(Literal literal, Literal::CreateFromProto(p)); @@ -1454,7 +1467,7 @@ TEST_F(LiteralUtilTest, CopyFromProto_u16) { p.mutable_shape()->set_element_type(U16); p.mutable_shape()->clear_dimensions(); p.mutable_shape()->add_dimensions(4); - LayoutUtil::SetToDefaultLayout(p.mutable_shape()); + SetDefaultLayoutOnProto(p.mutable_shape()); p.clear_u16s(); p.set_u16s(uint16_vals, 8); TF_ASSERT_OK_AND_ASSIGN(Literal literal, Literal::CreateFromProto(p)); @@ -1756,7 +1769,7 @@ TEST_F(LiteralUtilTest, ProtoRoundTrip) { TEST_F(LiteralUtilTest, InvalidProtoNoValues) { // Proto contains a shape, but no values. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeShape(F32, {3}); + *proto.mutable_shape() = ShapeUtil::MakeShape(F32, {3}).ToProto(); Status status = Literal::CreateFromProto(proto).status(); ASSERT_FALSE(status.ok()); EXPECT_THAT(status.error_message(), @@ -1777,7 +1790,7 @@ TEST_F(LiteralUtilTest, InvalidProtoNoShape) { TEST_F(LiteralUtilTest, InvalidProtoWrongContainer) { // Proto contains values in wrong container. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeShape(F32, {3}); + *proto.mutable_shape() = ShapeUtil::MakeShape(F32, {3}).ToProto(); proto.add_preds(false); proto.add_preds(true); proto.add_preds(false); @@ -1790,7 +1803,7 @@ TEST_F(LiteralUtilTest, InvalidProtoWrongContainer) { TEST_F(LiteralUtilTest, InvalidProtoTooFewValues) { // Proto contains too few values. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeShape(F32, {42, 2}); + *proto.mutable_shape() = ShapeUtil::MakeShape(F32, {42, 2}).ToProto(); proto.add_f32s(1.0); proto.add_f32s(2.0); proto.add_f32s(3.0); @@ -1803,7 +1816,7 @@ TEST_F(LiteralUtilTest, InvalidProtoTooFewValues) { TEST_F(LiteralUtilTest, InvalidProtoTooManyValues) { // Proto contains too many values. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeShape(S32, {2}); + *proto.mutable_shape() = ShapeUtil::MakeShape(S32, {2}).ToProto(); proto.add_s32s(42); proto.add_s32s(-10); proto.add_s32s(100); @@ -1816,8 +1829,8 @@ TEST_F(LiteralUtilTest, InvalidProtoTooManyValues) { TEST_F(LiteralUtilTest, InvalidProtoMissingLayout) { // Proto shape missing layout. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeShape(PRED, {2, 2}); - LayoutUtil::ClearLayout(proto.mutable_shape()); + *proto.mutable_shape() = ShapeUtil::MakeShape(PRED, {2, 2}).ToProto(); + proto.mutable_shape()->clear_layout(); proto.add_preds(true); proto.add_preds(false); proto.add_preds(true); @@ -1830,11 +1843,13 @@ TEST_F(LiteralUtilTest, InvalidProtoMissingLayout) { TEST_F(LiteralUtilTest, InvalidProtoTooFewTupleElements) { // Proto has the too few tuple elements. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeTupleShape( - {ShapeUtil::MakeShape(PRED, {2}), ShapeUtil::MakeShape(F32, {})}); + *proto.mutable_shape() = + ShapeUtil::MakeTupleShape( + {ShapeUtil::MakeShape(PRED, {2}), ShapeUtil::MakeShape(F32, {})}) + .ToProto(); LiteralProto* element0 = proto.add_tuple_literals(); *element0->mutable_shape() = - ShapeUtil::GetTupleElementShape(proto.shape(), 0); + ShapeUtil::GetTupleElementShape(Shape(proto.shape()), 0).ToProto(); element0->add_preds(false); element0->add_preds(true); @@ -1846,19 +1861,21 @@ TEST_F(LiteralUtilTest, InvalidProtoTooFewTupleElements) { TEST_F(LiteralUtilTest, InvalidProtoTooManyTupleElements) { // Proto has the too many tuple elements. LiteralProto proto; - *proto.mutable_shape() = ShapeUtil::MakeTupleShape( - {ShapeUtil::MakeShape(PRED, {2}), ShapeUtil::MakeShape(F32, {})}); + *proto.mutable_shape() = + ShapeUtil::MakeTupleShape( + {ShapeUtil::MakeShape(PRED, {2}), ShapeUtil::MakeShape(F32, {})}) + .ToProto(); LiteralProto* element0 = proto.add_tuple_literals(); *element0->mutable_shape() = - ShapeUtil::GetTupleElementShape(proto.shape(), 0); + ShapeUtil::GetTupleElementShape(Shape(proto.shape()), 0).ToProto(); element0->add_preds(false); element0->add_preds(true); LiteralProto* element1 = proto.add_tuple_literals(); *element1->mutable_shape() = - ShapeUtil::GetTupleElementShape(proto.shape(), 1); + ShapeUtil::GetTupleElementShape(Shape(proto.shape()), 1).ToProto(); element1->add_f32s(42.0); LiteralProto* element2 = proto.add_tuple_literals(); - *element2->mutable_shape() = ShapeUtil::MakeShape(F32, {}); + *element2->mutable_shape() = ShapeUtil::MakeShape(F32, {}).ToProto(); element2->add_f32s(123.0); Status status = Literal::CreateFromProto(proto).status(); diff --git a/tensorflow/compiler/xla/python_api/xla_shape.py b/tensorflow/compiler/xla/python_api/xla_shape.py index f158f6b241..95b2bf300e 100644 --- a/tensorflow/compiler/xla/python_api/xla_shape.py +++ b/tensorflow/compiler/xla/python_api/xla_shape.py @@ -25,9 +25,10 @@ from tensorflow.compiler.xla.python_api import types class Shape(object): - """Wraps a xla_data_pb2.Shape message with a convenient Python type. + """Wraps a xla_data_pb2.ShapeProto message with a convenient Python type. - Provides direct access to the underlying xla_data_pb2.Shape message in the + Provides direct access to the underlying xla_data_pb2.ShapeProto message in + the message attribute, along with accessor wrappers to the message's fields. Avoid direct access to .message unless interacting directly with protobuf APIs like CopyFrom. In other words, prefer hauling the shape around in a Shape, and @@ -48,7 +49,7 @@ class Shape(object): Raises: ValueError: if element_type is TUPLE but dimensions are not Shape objects. """ - self.message = xla_data_pb2.Shape() + self.message = xla_data_pb2.ShapeProto() self.message.element_type = element_type if element_type == xla_data_pb2.TUPLE: if not all(isinstance(subshape, Shape) for subshape in dimensions): diff --git a/tensorflow/compiler/xla/rpc/BUILD b/tensorflow/compiler/xla/rpc/BUILD index 3abb3855a4..26affbcceb 100644 --- a/tensorflow/compiler/xla/rpc/BUILD +++ b/tensorflow/compiler/xla/rpc/BUILD @@ -16,7 +16,6 @@ xla_proto_library( use_grpc_plugin = True, visibility = ["//visibility:public"], deps = [ - "//tensorflow/compiler/xla:xla_data_proto", "//tensorflow/compiler/xla:xla_proto", ], ) diff --git a/tensorflow/compiler/xla/rpc/xla_service.proto b/tensorflow/compiler/xla/rpc/xla_service.proto index e4f332cda2..0ff8adc2ac 100644 --- a/tensorflow/compiler/xla/rpc/xla_service.proto +++ b/tensorflow/compiler/xla/rpc/xla_service.proto @@ -43,7 +43,6 @@ limitations under the License. syntax = "proto3"; import "tensorflow/compiler/xla/xla.proto"; -import "tensorflow/compiler/xla/xla_data.proto"; package xla; diff --git a/tensorflow/compiler/xla/service/compile_only_service.cc b/tensorflow/compiler/xla/service/compile_only_service.cc index 0237f16673..1965925fa7 100644 --- a/tensorflow/compiler/xla/service/compile_only_service.cc +++ b/tensorflow/compiler/xla/service/compile_only_service.cc @@ -89,7 +89,7 @@ CompileOnlyService::CompileAheadOfTime( ExecutionOptions execution_options; *execution_options.mutable_debug_options() = debug_options; *execution_options.mutable_shape_with_output_layout() = - *instance.result_layout; + instance.result_layout->ToProto(); TF_ASSIGN_OR_RETURN( std::unique_ptr module_config, CreateModuleConfig( diff --git a/tensorflow/compiler/xla/service/cpu/xfeed_manager.h b/tensorflow/compiler/xla/service/cpu/xfeed_manager.h index 990ff94ba2..70008947f3 100644 --- a/tensorflow/compiler/xla/service/cpu/xfeed_manager.h +++ b/tensorflow/compiler/xla/service/cpu/xfeed_manager.h @@ -23,6 +23,7 @@ limitations under the License. #include #include "absl/types/span.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/statusor.h" #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" diff --git a/tensorflow/compiler/xla/service/hlo.proto b/tensorflow/compiler/xla/service/hlo.proto index c62c935af7..414c632712 100644 --- a/tensorflow/compiler/xla/service/hlo.proto +++ b/tensorflow/compiler/xla/service/hlo.proto @@ -51,7 +51,7 @@ message HloInstructionProto { string name = 1; string opcode = 2; - xla.Shape shape = 3; + xla.ShapeProto shape = 3; xla.OpMetadata metadata = 7; @@ -132,7 +132,7 @@ message HloInstructionProto { string custom_call_opaque = 53; // Shape of outfeed request. - xla.Shape outfeed_shape = 29; + xla.ShapeProto outfeed_shape = 29; // Describes the dimension numbers used for a dot operation xla.DotDimensionNumbers dot_dimension_numbers = 30; @@ -190,7 +190,7 @@ message HloInstructionProto { // 'operand_shapes_with_layout' must contain a shape with layout for each // operand. bool constrain_layout = 56; - repeated Shape operand_shapes_with_layout = 57; + repeated xla.ShapeProto operand_shapes_with_layout = 57; } // Serialization of HloComputation. diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index 1e3881c34f..2bdb617731 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -93,7 +93,8 @@ StatusOr> HloInstruction::CreateFromProto( [&computation_map](int64 id) { return computation_map.contains(id); })) << proto.name() << " instruction references invalid computation id(s)"; - TF_RETURN_IF_ERROR(ShapeUtil::ValidateShapeWithOptionalLayout(proto.shape())); + Shape shape(proto.shape()); + TF_RETURN_IF_ERROR(ShapeUtil::ValidateShapeWithOptionalLayout(shape)); switch (opcode) { // Ops migrated to subclasses. @@ -101,23 +102,23 @@ StatusOr> HloInstruction::CreateFromProto( TF_RET_CHECK(proto.operand_ids_size() == 3) << "BatchNormTraining instruction should have 3 operands but sees " << proto.operand_ids_size(); - instruction = CreateBatchNormTraining( - proto.shape(), operands(0), operands(1), operands(2), proto.epsilon(), - proto.feature_index()); + instruction = + CreateBatchNormTraining(shape, operands(0), operands(1), operands(2), + proto.epsilon(), proto.feature_index()); break; case HloOpcode::kBatchNormInference: TF_RET_CHECK(proto.operand_ids_size() == 5) << "BatchNormInference instruction should have 5 operands but sees " << proto.operand_ids_size(); instruction = CreateBatchNormInference( - proto.shape(), operands(0), operands(1), operands(2), operands(3), + shape, operands(0), operands(1), operands(2), operands(3), operands(4), proto.epsilon(), proto.feature_index()); break; case HloOpcode::kBatchNormGrad: TF_RET_CHECK(proto.operand_ids_size() == 5) << "BatchNormGrad instruction should have 5 operands but sees " << proto.operand_ids_size(); - instruction = CreateBatchNormGrad(proto.shape(), operands(0), operands(1), + instruction = CreateBatchNormGrad(shape, operands(0), operands(1), operands(2), operands(3), operands(4), proto.epsilon(), proto.feature_index()); break; @@ -127,7 +128,7 @@ StatusOr> HloInstruction::CreateFromProto( << proto.operand_ids_size(); std::vector fft_length(proto.fft_length().begin(), proto.fft_length().end()); - instruction = CreateFft(proto.shape(), operands(0), proto.fft_type(), + instruction = CreateFft(shape, operands(0), proto.fft_type(), absl::Span(fft_length)); break; } @@ -148,7 +149,7 @@ StatusOr> HloInstruction::CreateFromProto( TF_RET_CHECK(proto.operand_ids_size() == 1) << "Recv instruction should have 1 operand but sees " << proto.operand_ids_size(); - instruction = CreateRecv(proto.shape().tuple_shapes(0), operands(0), + instruction = CreateRecv(shape.tuple_shapes(0), operands(0), proto.channel_id(), proto.is_host_transfer()); break; case HloOpcode::kRecvDone: @@ -161,7 +162,7 @@ StatusOr> HloInstruction::CreateFromProto( TF_RET_CHECK(proto.operand_ids_size() == 1) << "Reverse instruction should have 1 operand but sees " << proto.operand_ids_size(); - instruction = CreateReverse(proto.shape(), operands(0), + instruction = CreateReverse(shape, operands(0), std::vector(proto.dimensions().begin(), proto.dimensions().end())); break; @@ -170,7 +171,7 @@ StatusOr> HloInstruction::CreateFromProto( << "Concatenate instruction should have 1 dimension but sees " << proto.dimensions_size(); instruction = - CreateConcatenate(proto.shape(), all_operands(), proto.dimensions(0)); + CreateConcatenate(shape, all_operands(), proto.dimensions(0)); break; case HloOpcode::kReduce: TF_RET_CHECK(proto.operand_ids_size() % 2 == 0) @@ -188,7 +189,7 @@ StatusOr> HloInstruction::CreateFromProto( absl::MakeSpan(reduce_operands) .subspan(reduce_operands.size() / 2, reduce_operands.size()); instruction = - CreateReduce(proto.shape(), inputs, init_values, + CreateReduce(shape, inputs, init_values, std::vector(proto.dimensions().begin(), proto.dimensions().end()), computations(0)); @@ -203,7 +204,7 @@ StatusOr> HloInstruction::CreateFromProto( auto sort_operands = all_operands(); HloInstruction* keys = sort_operands[0]; instruction = CreateSort( - proto.shape(), proto.dimensions(0), keys, + shape, proto.dimensions(0), keys, absl::Span(sort_operands).subspan(1)); break; } @@ -212,7 +213,7 @@ StatusOr> HloInstruction::CreateFromProto( << "Transpose instruction should have 1 operand but sees " << proto.operand_ids_size(); instruction = - CreateTranspose(proto.shape(), operands(0), + CreateTranspose(shape, operands(0), std::vector(proto.dimensions().begin(), proto.dimensions().end())); break; @@ -221,7 +222,7 @@ StatusOr> HloInstruction::CreateFromProto( << "Broadcast instruction should have 1 operand but sees " << proto.operand_ids_size(); instruction = - CreateBroadcast(proto.shape(), operands(0), + CreateBroadcast(shape, operands(0), std::vector(proto.dimensions().begin(), proto.dimensions().end())); break; @@ -229,7 +230,7 @@ StatusOr> HloInstruction::CreateFromProto( TF_RET_CHECK(proto.called_computation_ids_size() == 1) << "Map instruction should have 1 called computation but sees " << proto.called_computation_ids_size(); - instruction = CreateMap(proto.shape(), all_operands(), computations(0)); + instruction = CreateMap(shape, all_operands(), computations(0)); break; case HloOpcode::kSlice: { TF_RET_CHECK(proto.operand_ids_size() == 1) @@ -242,8 +243,8 @@ StatusOr> HloInstruction::CreateFromProto( slice_limits.push_back(slice_dimensions.limit()); slice_strides.push_back(slice_dimensions.stride()); } - instruction = CreateSlice(proto.shape(), operands(0), slice_starts, - slice_limits, slice_strides); + instruction = CreateSlice(shape, operands(0), slice_starts, slice_limits, + slice_strides); break; } case HloOpcode::kConstant: { @@ -253,7 +254,7 @@ StatusOr> HloInstruction::CreateFromProto( Literal::CreateFromProto(proto.literal())); instruction = CreateConstant(std::move(literal)); } else { - instruction = absl::make_unique(proto.shape()); + instruction = absl::make_unique(shape); } break; } @@ -284,55 +285,54 @@ StatusOr> HloInstruction::CreateFromProto( tensorflow::gtl::FindPtrOrNull(computation_map, fusion_id); TF_RET_CHECK(fused_computation != nullptr) << "No fusion computation with id " << fusion_id; - instruction = CreateFusion(proto.shape(), fusion_kind, all_operands(), - fused_computation); + instruction = + CreateFusion(shape, fusion_kind, all_operands(), fused_computation); break; } case HloOpcode::kRng: - instruction = - CreateRng(proto.shape(), proto.distribution(), all_operands()); + instruction = CreateRng(shape, proto.distribution(), all_operands()); break; case HloOpcode::kParameter: - instruction = CreateParameter(proto.parameter_number(), proto.shape(), - proto.name()); + instruction = + CreateParameter(proto.parameter_number(), shape, proto.name()); break; case HloOpcode::kGetTupleElement: TF_RET_CHECK(proto.operand_ids_size() == 1) << "GetTupleElement instruction should have 1 operand but sees " << proto.operand_ids_size(); - instruction = CreateGetTupleElement(proto.shape(), operands(0), - proto.tuple_index()); + instruction = + CreateGetTupleElement(shape, operands(0), proto.tuple_index()); break; case HloOpcode::kReducePrecision: TF_RET_CHECK(proto.operand_ids_size() == 1) << "ReducePrecision instruction should have 1 operand but sees " << proto.operand_ids_size(); - instruction = - CreateReducePrecision(proto.shape(), operands(0), - proto.exponent_bits(), proto.mantissa_bits()); + instruction = CreateReducePrecision( + shape, operands(0), proto.exponent_bits(), proto.mantissa_bits()); break; case HloOpcode::kInfeed: { - TF_RET_CHECK(ShapeUtil::IsTuple(proto.shape()) && - (ShapeUtil::TupleElementCount(proto.shape()) == 2)) + TF_RET_CHECK(ShapeUtil::IsTuple(shape) && + (ShapeUtil::TupleElementCount(shape) == 2)) << "Infeed should have a tuple shape with 2 operands, but has: " - << proto.shape(); - const Shape& data_shape = - ShapeUtil::GetTupleElementShape(proto.shape(), 0); + << shape; + const Shape& data_shape = ShapeUtil::GetTupleElementShape(shape, 0); TF_RET_CHECK(proto.operand_ids_size() == 1) << "Infeed instruction should have 1 operand but sees " << proto.operand_ids_size(); instruction = CreateInfeed(data_shape, operands(0), proto.infeed_config()); } break; - case HloOpcode::kOutfeed: + case HloOpcode::kOutfeed: { TF_RET_CHECK(proto.operand_ids_size() == 2) << "Outfeed instruction should have 2 operands but sees " << proto.operand_ids_size(); + Shape outfeed_shape(proto.outfeed_shape()); TF_RETURN_IF_ERROR( - ShapeUtil::ValidateShapeWithOptionalLayout(proto.outfeed_shape())); - instruction = CreateOutfeed(proto.outfeed_shape(), operands(0), - operands(1), proto.outfeed_config()); + ShapeUtil::ValidateShapeWithOptionalLayout(outfeed_shape)); + instruction = CreateOutfeed(outfeed_shape, operands(0), operands(1), + proto.outfeed_config()); break; + } case HloOpcode::kCrossReplicaSum: { TF_RET_CHECK(proto.called_computation_ids_size() == 1) << "CrossReplicaSum should have 1 called computation but sees " @@ -342,7 +342,7 @@ StatusOr> HloInstruction::CreateFromProto( all_reduce_id = proto.all_reduce_id(); } instruction = CreateCrossReplicaSum( - proto.shape(), all_operands(), computations(0), + shape, all_operands(), computations(0), /*replica_groups=*/ std::vector(proto.replica_groups().begin(), proto.replica_groups().end()), @@ -352,7 +352,7 @@ StatusOr> HloInstruction::CreateFromProto( } case HloOpcode::kAllToAll: { instruction = CreateAllToAll( - proto.shape(), all_operands(), + shape, all_operands(), /*replica_groups=*/ std::vector(proto.replica_groups().begin(), proto.replica_groups().end())); @@ -368,8 +368,8 @@ StatusOr> HloInstruction::CreateFromProto( source_target_pairs[i].first = proto.source_target_pairs(i).source(); source_target_pairs[i].second = proto.source_target_pairs(i).target(); } - instruction = CreateCollectivePermute(proto.shape(), operands(0), - source_target_pairs); + instruction = + CreateCollectivePermute(shape, operands(0), source_target_pairs); break; } case HloOpcode::kConvolution: { @@ -382,7 +382,7 @@ StatusOr> HloInstruction::CreateFromProto( precision_config.mutable_operand_precision()->Resize( proto.operand_ids_size(), PrecisionConfig::DEFAULT); instruction = CreateConvolve( - proto.shape(), operands(0), operands(1), + shape, operands(0), operands(1), std::max(proto.feature_group_count(), 1), proto.window(), proto.convolution_dimension_numbers(), precision_config); break; @@ -394,7 +394,7 @@ StatusOr> HloInstruction::CreateFromProto( TF_RET_CHECK(proto.called_computation_ids_size() == 1) << "ReduceWindow should have 1 called computation but sees " << proto.called_computation_ids_size(); - instruction = CreateReduceWindow(proto.shape(), operands(0), operands(1), + instruction = CreateReduceWindow(shape, operands(0), operands(1), proto.window(), computations(0)); break; case HloOpcode::kSelectAndScatter: @@ -404,9 +404,9 @@ StatusOr> HloInstruction::CreateFromProto( TF_RET_CHECK(proto.called_computation_ids_size() == 2) << "SelectAndScatter should have 2 called computations but sees " << proto.called_computation_ids_size(); - instruction = CreateSelectAndScatter( - proto.shape(), operands(0), computations(0), proto.window(), - operands(1), operands(2), computations(1)); + instruction = CreateSelectAndScatter(shape, operands(0), computations(0), + proto.window(), operands(1), + operands(2), computations(1)); break; case HloOpcode::kCustomCall: if (proto.constrain_layout()) { @@ -414,16 +414,17 @@ StatusOr> HloInstruction::CreateFromProto( // vector of pointers essentially) so create a vector of shapes to pass // in. std::vector operand_shapes; - for (const Shape& shape : proto.operand_shapes_with_layout()) { - operand_shapes.push_back(shape); + for (const ShapeProto& shape_proto : + proto.operand_shapes_with_layout()) { + operand_shapes.emplace_back(shape_proto); } - instruction = CreateCustomCall( - proto.shape(), all_operands(), proto.custom_call_target(), - operand_shapes, proto.custom_call_opaque()); + instruction = + CreateCustomCall(shape, all_operands(), proto.custom_call_target(), + operand_shapes, proto.custom_call_opaque()); } else { - instruction = CreateCustomCall(proto.shape(), all_operands(), - proto.custom_call_target(), - proto.custom_call_opaque()); + instruction = + CreateCustomCall(shape, all_operands(), proto.custom_call_target(), + proto.custom_call_opaque()); } if (proto.has_window()) { static_cast(instruction.get()) @@ -443,8 +444,8 @@ StatusOr> HloInstruction::CreateFromProto( << "Pad instruction should have 2 operands but sees " << proto.operand_ids_size(); TF_RET_CHECK(proto.has_padding_config()); - instruction = CreatePad(proto.shape(), operands(0), operands(1), - proto.padding_config()); + instruction = + CreatePad(shape, operands(0), operands(1), proto.padding_config()); break; case HloOpcode::kDynamicSlice: { TF_RET_CHECK(proto.operand_ids_size() == 2) @@ -452,8 +453,8 @@ StatusOr> HloInstruction::CreateFromProto( << proto.operand_ids_size(); std::vector slice_sizes(proto.dynamic_slice_sizes_size()); absl::c_copy(proto.dynamic_slice_sizes(), slice_sizes.begin()); - instruction = CreateDynamicSlice(proto.shape(), operands(0), operands(1), - slice_sizes); + instruction = + CreateDynamicSlice(shape, operands(0), operands(1), slice_sizes); break; } case HloOpcode::kGather: { @@ -469,7 +470,7 @@ StatusOr> HloInstruction::CreateFromProto( for (int64 bound : proto.gather_slice_sizes()) { gather_slice_sizes.push_back(bound); } - instruction = CreateGather(proto.shape(), operands(0), operands(1), + instruction = CreateGather(shape, operands(0), operands(1), *gather_dimension_numbers, gather_slice_sizes); break; } @@ -485,16 +486,15 @@ StatusOr> HloInstruction::CreateFromProto( auto scatter_dimension_numbers = absl::make_unique( proto.scatter_dimension_numbers()); - instruction = - CreateScatter(proto.shape(), operands(0), operands(1), operands(2), - computations(0), *scatter_dimension_numbers); + instruction = CreateScatter(shape, operands(0), operands(1), operands(2), + computations(0), *scatter_dimension_numbers); break; } case HloOpcode::kIota: TF_RET_CHECK(proto.dimensions_size() == 1) << "Iota instruction should have 1 dimension but sees " << proto.dimensions_size(); - instruction = CreateIota(proto.shape(), proto.dimensions(0)); + instruction = CreateIota(shape, proto.dimensions(0)); break; case HloOpcode::kDot: { TF_RET_CHECK(proto.has_dot_dimension_numbers()) @@ -506,8 +506,8 @@ StatusOr> HloInstruction::CreateFromProto( precision_config.mutable_operand_precision()->Resize( proto.operand_ids_size(), PrecisionConfig::DEFAULT); instruction = absl::make_unique( - proto.shape(), operands(0), operands(1), - proto.dot_dimension_numbers(), precision_config); + shape, operands(0), operands(1), proto.dot_dimension_numbers(), + precision_config); break; } case HloOpcode::kDomain: { @@ -529,7 +529,7 @@ StatusOr> HloInstruction::CreateFromProto( exit_hlo_sharding = std::make_shared(sharding); } instruction = absl::make_unique( - proto.shape(), operands(0), + shape, operands(0), absl::make_unique(entry_hlo_sharding), absl::make_unique(exit_hlo_sharding)); break; @@ -537,11 +537,11 @@ StatusOr> HloInstruction::CreateFromProto( case HloOpcode::kGetDimensionSize: TF_RET_CHECK(proto.operand_ids_size() == 1); TF_RET_CHECK(proto.dimensions_size() == 1); - instruction = CreateGetDimensionSize(proto.shape(), operands(0), - proto.dimensions(0)); + instruction = + CreateGetDimensionSize(shape, operands(0), proto.dimensions(0)); break; default: { - instruction = absl::WrapUnique(new HloInstruction(opcode, proto.shape())); + instruction = absl::WrapUnique(new HloInstruction(opcode, shape)); for (const int64 operand_id : proto.operand_ids()) { instruction->AppendOperand(instruction_map.at(operand_id)); } @@ -2234,7 +2234,7 @@ HloInstructionProto HloInstruction::ToProto() const { proto.set_id(unique_id_); proto.set_name(name_); proto.set_opcode(HloOpcodeString(opcode_)); - *proto.mutable_shape() = shape_; + *proto.mutable_shape() = shape_.ToProto(); for (const HloInstruction* operand : operands_) { proto.add_operand_ids(operand->unique_id()); } diff --git a/tensorflow/compiler/xla/service/hlo_instructions.cc b/tensorflow/compiler/xla/service/hlo_instructions.cc index ed3b2f1564..6a57b75488 100644 --- a/tensorflow/compiler/xla/service/hlo_instructions.cc +++ b/tensorflow/compiler/xla/service/hlo_instructions.cc @@ -1615,7 +1615,7 @@ HloOutfeedInstruction::HloOutfeedInstruction(const Shape& outfeed_shape, HloInstructionProto HloOutfeedInstruction::ToProto() const { HloInstructionProto proto = HloInstruction::ToProto(); proto.set_outfeed_config(outfeed_config()); - *proto.mutable_outfeed_shape() = outfeed_shape(); + *proto.mutable_outfeed_shape() = outfeed_shape().ToProto(); return proto; } @@ -1867,7 +1867,7 @@ HloInstructionProto HloCustomCallInstruction::ToProto() const { if (layout_constrained()) { proto.set_constrain_layout(true); for (const Shape& shape : operand_shapes_with_layout_) { - *proto.add_operand_shapes_with_layout() = shape; + *proto.add_operand_shapes_with_layout() = shape.ToProto(); } } return proto; diff --git a/tensorflow/compiler/xla/service/hlo_lexer.h b/tensorflow/compiler/xla/service/hlo_lexer.h index 3e2f8bcd52..d6a2b292a3 100644 --- a/tensorflow/compiler/xla/service/hlo_lexer.h +++ b/tensorflow/compiler/xla/service/hlo_lexer.h @@ -20,6 +20,7 @@ limitations under the License. #include "absl/strings/string_view.h" #include "tensorflow/compiler/xla/service/hlo_token.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/platform/logging.h" diff --git a/tensorflow/compiler/xla/service/hlo_module.cc b/tensorflow/compiler/xla/service/hlo_module.cc index a01853fe1f..fe8371384c 100644 --- a/tensorflow/compiler/xla/service/hlo_module.cc +++ b/tensorflow/compiler/xla/service/hlo_module.cc @@ -257,7 +257,7 @@ StatusOr> HloModule::CreateFromProto( // the entry parameters and root. TF_RET_CHECK(proto.has_host_program_shape()) << "No program shape found in the proto"; - const auto& expected_program_shape = proto.host_program_shape(); + ProgramShape expected_program_shape(proto.host_program_shape()); TF_RET_CHECK(expected_program_shape.parameters_size() == module_config.entry_computation_layout().parameter_count()); for (int i = 0; i < expected_program_shape.parameters_size(); ++i) { @@ -369,7 +369,7 @@ StatusOr HloModule::CreateModuleConfigFromProto( const HloModuleProto& module, const DebugOptions& debug_options) { TF_RET_CHECK(module.has_host_program_shape()) << "No program shape found in the proto"; - const auto& program_shape = module.host_program_shape(); + ProgramShape program_shape(module.host_program_shape()); HloModuleConfig module_config(ProgramShape{program_shape}); module_config.set_debug_options(debug_options); diff --git a/tensorflow/compiler/xla/service/hlo_proto_util.cc b/tensorflow/compiler/xla/service/hlo_proto_util.cc index cf33668f5b..981d06ce10 100644 --- a/tensorflow/compiler/xla/service/hlo_proto_util.cc +++ b/tensorflow/compiler/xla/service/hlo_proto_util.cc @@ -48,7 +48,7 @@ StatusOr> CreateModuleFromProto( return std::move(module); } -StatusOr> EntryComputationParameterShapes( +StatusOr> EntryComputationParameterShapes( const HloProto& hlo_proto) { if (!hlo_proto.has_hlo_module()) { return NotFound("HloProto missing HloModuleProto."); @@ -57,15 +57,16 @@ StatusOr> EntryComputationParameterShapes( return NotFound("HloProto missing program shape."); } - std::vector parameter_shapes; + std::vector parameter_shapes; const auto& program_shape = hlo_proto.hlo_module().host_program_shape(); - for (const Shape& shape : program_shape.parameters()) { + for (const ShapeProto& shape : program_shape.parameters()) { parameter_shapes.push_back(&shape); } return parameter_shapes; } -StatusOr EntryComputationOutputShape(const HloProto& hlo_proto) { +StatusOr EntryComputationOutputShape( + const HloProto& hlo_proto) { if (!hlo_proto.has_hlo_module()) { return NotFound("HloProto missing HloModuleProto."); } diff --git a/tensorflow/compiler/xla/service/hlo_proto_util.h b/tensorflow/compiler/xla/service/hlo_proto_util.h index 1db82dd6fc..31ea2aaffd 100644 --- a/tensorflow/compiler/xla/service/hlo_proto_util.h +++ b/tensorflow/compiler/xla/service/hlo_proto_util.h @@ -43,12 +43,13 @@ StatusOr> CreateModuleFromProto( // Returns the shapes of the parameters of the entry computation. Shape pointers // refer to shapes inside of the given HloProto. -StatusOr> EntryComputationParameterShapes( +StatusOr> EntryComputationParameterShapes( const HloProto& hlo_proto); // Returns the shape of the output of the entry computation. The shape pointer // refers to the output shape inside of the given HloProto. -StatusOr EntryComputationOutputShape(const HloProto& hlo_proto); +StatusOr EntryComputationOutputShape( + const HloProto& hlo_proto); } // namespace xla diff --git a/tensorflow/compiler/xla/service/llvm_ir/ir_array.h b/tensorflow/compiler/xla/service/llvm_ir/ir_array.h index 1540a40ef8..d6d84994ee 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/ir_array.h +++ b/tensorflow/compiler/xla/service/llvm_ir/ir_array.h @@ -25,6 +25,7 @@ limitations under the License. #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Value.h" #include "tensorflow/compiler/xla/map_util.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/types.h" #include "tensorflow/compiler/xla/xla_data.pb.h" #include "tensorflow/core/platform/logging.h" diff --git a/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc b/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc index df78726166..ceea24685a 100644 --- a/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc +++ b/tensorflow/compiler/xla/service/llvm_ir/llvm_util.cc @@ -244,10 +244,11 @@ StatusOr EncodeSelfDescribingShapeConstant(const Shape& shape, StatusOr DecodeSelfDescribingShapeConstant(const void* shape_ptr, int32 size_bytes) { - Shape shape; - TF_RET_CHECK(shape.ParseFromArray(shape_ptr, size_bytes)); + ShapeProto shape_proto; + TF_RET_CHECK(shape_proto.ParseFromArray(shape_ptr, size_bytes)); + Shape shape(shape_proto); TF_RETURN_IF_ERROR(ShapeUtil::ValidateShape(shape)); - return shape; + return std::move(shape); } llvm::Constant* ConvertLiteralToIrConstant(const Literal& literal, diff --git a/tensorflow/compiler/xla/service/local_service.cc b/tensorflow/compiler/xla/service/local_service.cc index ddc8691e77..6c89700983 100644 --- a/tensorflow/compiler/xla/service/local_service.cc +++ b/tensorflow/compiler/xla/service/local_service.cc @@ -101,12 +101,12 @@ ExecutionOptions CreateExecutionOptions( } if (build_options.result_layout() != nullptr) { *execution_options.mutable_shape_with_output_layout() = - *build_options.result_layout(); + build_options.result_layout()->ToProto(); } else { + Shape result_shape(program_shape->result()); + LayoutUtil::SetToDefaultLayout(&result_shape); *execution_options.mutable_shape_with_output_layout() = - program_shape->result(); - LayoutUtil::SetToDefaultLayout( - execution_options.mutable_shape_with_output_layout()); + result_shape.ToProto(); } return execution_options; } diff --git a/tensorflow/compiler/xla/service/service.cc b/tensorflow/compiler/xla/service/service.cc index c4b0a5c080..3b336d5c9d 100644 --- a/tensorflow/compiler/xla/service/service.cc +++ b/tensorflow/compiler/xla/service/service.cc @@ -41,6 +41,7 @@ limitations under the License. #include "tensorflow/compiler/xla/service/source_map_util.h" #include "tensorflow/compiler/xla/service/stream_pool.h" #include "tensorflow/compiler/xla/service/transfer_manager.h" +#include "tensorflow/compiler/xla/shape.h" #include "tensorflow/compiler/xla/shape_layout.h" #include "tensorflow/compiler/xla/shape_util.h" #include "tensorflow/compiler/xla/status_macros.h" @@ -275,8 +276,8 @@ StatusOr> Service::CreateModuleConfig( } if (execution_options != nullptr && execution_options->has_shape_with_output_layout()) { - const auto& shape_with_output_layout = - execution_options->shape_with_output_layout(); + const Shape shape_with_output_layout( + execution_options->shape_with_output_layout()); TF_RETURN_IF_ERROR( ValidateResultShape(shape_with_output_layout, program_shape.result())); TF_RETURN_IF_ERROR( @@ -818,14 +819,17 @@ Status Service::Compile(const CompileRequest* arg, CompileResponse* result) { "The compile request does not support multiple device handles."); } - std::vector argument_shapes; - absl::c_transform(arg->input_shape_with_layout(), - std::back_inserter(argument_shapes), - [](const Shape& shape) { return &shape; }); + std::vector argument_shapes; + argument_shapes.reserve(arg->input_shape_with_layout_size()); + std::vector argument_shape_ptrs; + for (const ShapeProto& shape_proto : arg->input_shape_with_layout()) { + argument_shapes.push_back(Shape(shape_proto)); + argument_shape_ptrs.push_back(&argument_shapes.back()); + } TF_ASSIGN_OR_RETURN( std::unique_ptr module_config, CreateModuleConfig(ProgramShape{arg->computation().host_program_shape()}, - argument_shapes, &arg->execution_options())); + argument_shape_ptrs, &arg->execution_options())); VLOG(3) << "Compile created HloModuleConfig computation layout: " << module_config->entry_computation_layout().ToString(); @@ -930,14 +934,14 @@ Status Service::TransferToClient(const TransferToClientRequest* arg, TF_ASSIGN_OR_RETURN(const ShapedBuffer* shaped_buffer, allocation_tracker_.ResolveForReplica(arg->data(), 0)); - const Shape* return_shape; + Shape return_shape; if (arg->has_shape_with_layout()) { - if (!LayoutUtil::HasLayout(arg->shape_with_layout())) { + return_shape = Shape(arg->shape_with_layout()); + if (!LayoutUtil::HasLayout(return_shape)) { return InvalidArgument("shape_with_layout must have layout if present."); } - return_shape = &arg->shape_with_layout(); } else { - return_shape = &shaped_buffer->on_host_shape(); + return_shape = Shape(shaped_buffer->on_host_shape()); } TF_ASSIGN_OR_RETURN(auto stream, execute_backend_->BorrowStream( @@ -948,11 +952,11 @@ Status Service::TransferToClient(const TransferToClientRequest* arg, execute_backend_->transfer_manager()->TransferLiteralFromDevice( stream.get(), *shaped_buffer)); - if (LayoutUtil::LayoutsInShapesEqual(*return_shape, result_literal.shape())) { + if (LayoutUtil::LayoutsInShapesEqual(return_shape, result_literal.shape())) { *result->mutable_literal() = result_literal.ToProto(); } else { *result->mutable_literal() = - result_literal.Relayout(*return_shape).ToProto(); + result_literal.Relayout(return_shape).ToProto(); } return Status::OK(); } @@ -1045,11 +1049,11 @@ Status Service::TransferFromOutfeed(const TransferFromOutfeedRequest* arg, executor = replicas[arg->replica_id()]; } - auto literal = Literal::CreateFromShape(arg->shape_with_layout()); + auto literal = Literal::CreateFromShape(Shape(arg->shape_with_layout())); TF_RETURN_IF_ERROR( execute_backend_->transfer_manager()->TransferLiteralFromOutfeed( - executor, arg->shape_with_layout(), literal)); + executor, Shape(arg->shape_with_layout()), literal)); *result->mutable_literal() = literal.ToProto(); return Status::OK(); } @@ -1103,7 +1107,7 @@ Status Service::ComputeConstantGraph(const ComputeConstantGraphRequest* arg, Status Service::GetShape(const GetShapeRequest* arg, GetShapeResponse* result) { TF_ASSIGN_OR_RETURN(const ShapedBuffer* buffer, allocation_tracker_.ResolveForReplica(arg->data(), 0)); - *result->mutable_shape() = buffer->on_host_shape(); + *result->mutable_shape() = buffer->on_host_shape().ToProto(); return Status::OK(); } diff --git a/tensorflow/compiler/xla/service/shape_inference.cc b/tensorflow/compiler/xla/service/shape_inference.cc index 528d5c0ecc..7e7282a737 100644 --- a/tensorflow/compiler/xla/service/shape_inference.cc +++ b/tensorflow/compiler/xla/service/shape_inference.cc @@ -1018,7 +1018,7 @@ ShapeInference::InferDegenerateDimensionBroadcastShape(HloOpcode operation, switch (opcode) { case HloOpcode::kTuple: { Shape result = ShapeUtil::MakeTupleShape({}); - result.mutable_tuple_shapes()->Reserve(operand_shapes.size()); + result.mutable_tuple_shapes()->reserve(operand_shapes.size()); for (const Shape* shape : operand_shapes) { ShapeUtil::AppendShapeToTuple(*shape, &result); } diff --git a/tensorflow/compiler/xla/shape.cc b/tensorflow/compiler/xla/shape.cc index d209389c74..746ab9e997 100644 --- a/tensorflow/compiler/xla/shape.cc +++ b/tensorflow/compiler/xla/shape.cc @@ -21,11 +21,56 @@ limitations under the License. namespace xla { +Shape::Shape(const ShapeProto& shape_proto) { + set_element_type(shape_proto.element_type()); + dimensions_.reserve(shape_proto.dimensions_size()); + for (const int64 dimension : shape_proto.dimensions()) { + add_dimensions(dimension); + } + tuple_shapes_.reserve(shape_proto.tuple_shapes_size()); + for (const ShapeProto& element_shape : shape_proto.tuple_shapes()) { + *add_tuple_shapes() = Shape(element_shape); + } + if (shape_proto.has_layout()) { + *mutable_layout() = shape_proto.layout(); + } +} + +ShapeProto Shape::ToProto() const { + ShapeProto proto; + proto.set_element_type(element_type_); + proto.mutable_dimensions()->Reserve(dimensions_size()); + for (const int64 dimension : dimensions()) { + proto.add_dimensions(dimension); + } + proto.mutable_tuple_shapes()->Reserve(tuple_shapes_size()); + for (const Shape& shape : tuple_shapes()) { + *proto.add_tuple_shapes() = shape.ToProto(); + } + if (has_layout()) { + *proto.mutable_layout() = layout(); + } + return proto; +} + +string Shape::ToString(bool print_layout) const { + if (print_layout) { + return ShapeUtil::HumanStringWithLayout(*this); + } else { + return ShapeUtil::HumanString(*this); + } +} + +std::ostream& operator<<(std::ostream& out, const Shape& shape) { + out << shape.ToString(/*print_layout=*/true); + return out; +} + ProgramShape::ProgramShape(const ProgramShapeProto& program_shape_proto) { - for (const Shape& shape : program_shape_proto.parameters()) { - *add_parameters() = shape; + for (const ShapeProto& shape_proto : program_shape_proto.parameters()) { + *add_parameters() = Shape(shape_proto); } - *mutable_result() = program_shape_proto.result(); + *mutable_result() = Shape(program_shape_proto.result()); for (const string& name : program_shape_proto.parameter_names()) { add_parameter_names(name); } @@ -34,9 +79,9 @@ ProgramShape::ProgramShape(const ProgramShapeProto& program_shape_proto) { ProgramShapeProto ProgramShape::ToProto() const { ProgramShapeProto proto; for (const Shape& shape : parameters()) { - *proto.add_parameters() = shape; + *proto.add_parameters() = shape.ToProto(); } - *proto.mutable_result() = result(); + *proto.mutable_result() = result().ToProto(); for (const string& name : parameter_names()) { proto.add_parameter_names(name); } diff --git a/tensorflow/compiler/xla/shape.h b/tensorflow/compiler/xla/shape.h index c3aecb1736..7f6b14ab42 100644 --- a/tensorflow/compiler/xla/shape.h +++ b/tensorflow/compiler/xla/shape.h @@ -26,6 +26,102 @@ limitations under the License. namespace xla { +// A shape describes the number of dimensions in a array, the bounds of each +// dimension, and the primitive component type. For tuples, shape describes the +// structure (number of elements and nesting). +class Shape { + public: + Shape() = default; + + // Construct a shape from a ShapeProto. + explicit Shape(const ShapeProto& shape_proto); + + // Returns a ShapeProto representation of the Shape. + ShapeProto ToProto() const; + + // Returns a human-readable string that represents the given shape, with or + // without layout. e.g. "F32[42,12] {0, 1}" or "F32[64]". + string ToString(bool print_layout = false) const; + + // The following methods mirror the protobuf generated code interface for the + // message ShapeProto. This enabled easy migration of this data structure + // from a proto to a proper C++ class. + // TODO(b/29771030): Replace or augment these methods with a more ergonomic + // interface. + + // Methods for accessing the primitive type. + PrimitiveType element_type() const { return element_type_; } + void set_element_type(PrimitiveType value) { element_type_ = value; } + + // Methods for accessing the dimensions array. + int dimensions_size() const { return dimensions_.size(); } + int64 dimensions(int index) const { return dimensions_.at(index); } + void set_dimensions(int index, int64 value) { dimensions_.at(index) = value; } + void add_dimensions(int64 value) { dimensions_.push_back(value); } + void clear_dimensions() { dimensions_.clear(); } + const std::vector& dimensions() const { return dimensions_; } + std::vector* mutable_dimensions() { return &dimensions_; } + + // Methods for accessing the tuple subshapes. This field only non-empty for + // tuple shapes. + int tuple_shapes_size() const { return tuple_shapes_.size(); } + const Shape& tuple_shapes(int index) const { return tuple_shapes_.at(index); } + Shape* mutable_tuple_shapes(int index) { return &tuple_shapes_.at(index); } + Shape* add_tuple_shapes() { + tuple_shapes_.push_back(Shape()); + return &tuple_shapes_.back(); + } + void clear_tuple_shapes() { tuple_shapes_.clear(); } + const std::vector& tuple_shapes() const { return tuple_shapes_; } + std::vector* mutable_tuple_shapes() { return &tuple_shapes_; } + + // Methods for accessing the layout field. + bool has_layout() const { return layout_.has_value(); } + const Layout& layout() const { + if (layout_.has_value()) { + return *layout_; + } else { + return Layout::default_instance(); + } + } + Layout* mutable_layout() { + if (!layout_.has_value()) { + layout_ = Layout(); + } + return &layout_.value(); + } + void clear_layout() { layout_.reset(); } + + void Swap(Shape* other) { + using std::swap; + swap(*this, *other); + } + + void Clear() { + element_type_ = PRIMITIVE_TYPE_INVALID; + dimensions_.clear(); + tuple_shapes_.clear(); + layout_.reset(); + } + + string SerializeAsString() const { return ToProto().SerializeAsString(); } + string ShortDebugString() const { return ToProto().ShortDebugString(); } + string DebugString() const { return ToProto().DebugString(); } + + public: + // The element type of this shape (tuple, array, etc). + PrimitiveType element_type_ = PRIMITIVE_TYPE_INVALID; + + // The array bounds of the dimensions. This is nonempty only for array shapes. + std::vector dimensions_; + + // The tuple element subshapes. This is nonempty only for tuple shapes. + std::vector tuple_shapes_; + + // The array layout of the shape. This is present only for array shapes. + absl::optional layout_; +}; + // Shape of the parameters and output of an XLA computation. This is analogous // to a traditional function signature. class ProgramShape { @@ -61,7 +157,6 @@ class ProgramShape { // Methods for accessing and manipulating the Shape of the result. const Shape& result() const { return result_; } Shape* mutable_result() { return &result_; } - void clear_result() { result_.Clear(); } // Methods for accessing and manipulating the names of the parameters. int parameter_names_size() const { return parameter_names_.size(); } @@ -101,6 +196,7 @@ class ProgramShape { Shape result_; }; +std::ostream& operator<<(std::ostream& out, const Shape& shape); std::ostream& operator<<(std::ostream& out, const ProgramShape& program_shape); } // namespace xla diff --git a/tensorflow/compiler/xla/shape_test.cc b/tensorflow/compiler/xla/shape_test.cc index cc3a5eb1d6..e396897eee 100644 --- a/tensorflow/compiler/xla/shape_test.cc +++ b/tensorflow/compiler/xla/shape_test.cc @@ -30,7 +30,51 @@ limitations under the License. namespace xla { namespace { -TEST(ShapeTest, ProgramShapeToFromProto) { +class ShapeTest : public ::testing::Test { + protected: + const Shape opaque_ = ShapeUtil::MakeOpaqueShape(); + const Shape token_ = ShapeUtil::MakeTokenShape(); + const Shape scalar_ = ShapeUtil::MakeShape(F32, {}); + const Shape matrix_ = ShapeUtil::MakeShape(U32, {1, 2}); + const Shape matrix2_ = ShapeUtil::MakeShapeWithLayout(S32, {3, 4}, {0, 1}); + const Shape tuple_ = + ShapeUtil::MakeTupleShape({opaque_, scalar_, matrix_, matrix2_}); + const Shape nested_tuple_ = + ShapeUtil::MakeTupleShape({tuple_, matrix_, token_}); +}; + +TEST_F(ShapeTest, ShapeToFromProto) { + for (const Shape& shape : + {opaque_, token_, scalar_, matrix_, matrix2_, tuple_, nested_tuple_}) { + Shape shape_copy(shape.ToProto()); + EXPECT_TRUE(ShapeUtil::Equal(shape, shape_copy)) + << shape << " != " << shape_copy; + } +} + +TEST_F(ShapeTest, ShapeToString) { + EXPECT_EQ("opaque[]", opaque_.ToString()); + EXPECT_EQ("token[]", token_.ToString()); + EXPECT_EQ("f32[]", scalar_.ToString()); + EXPECT_EQ("u32[1,2]", matrix_.ToString()); + EXPECT_EQ("s32[3,4]", matrix2_.ToString()); + EXPECT_EQ("(opaque[], f32[], u32[1,2], s32[3,4])", tuple_.ToString()); + EXPECT_EQ("((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", + nested_tuple_.ToString()); + + EXPECT_EQ("opaque[]", opaque_.ToString(/*print_layout=*/true)); + EXPECT_EQ("f32[]", scalar_.ToString(/*print_layout=*/true)); + EXPECT_EQ("u32[1,2]{1,0}", matrix_.ToString(/*print_layout=*/true)); + EXPECT_EQ("s32[3,4]{0,1}", matrix2_.ToString(/*print_layout=*/true)); + EXPECT_EQ("(opaque[], f32[], u32[1,2]{1,0}, s32[3,4]{0,1})", + tuple_.ToString(/*print_layout=*/true)); + EXPECT_EQ( + "((opaque[], f32[], u32[1,2]{1,0}, s32[3,4]{0,1}), u32[1,2]{1,0}, " + "token[])", + nested_tuple_.ToString(/*print_layout=*/true)); +} + +TEST_F(ShapeTest, ProgramShapeToFromProto) { ProgramShape program_shape; *program_shape.add_parameters() = ShapeUtil::MakeShape(F32, {1, 2, 3}); *program_shape.add_parameters() = ShapeUtil::MakeTokenShape(); @@ -67,17 +111,10 @@ TEST(ShapeTest, ProgramShapeToFromProto) { } } -TEST(ShapeTest, ProgramShapeToString) { - Shape opaque = ShapeUtil::MakeOpaqueShape(); - Shape token = ShapeUtil::MakeTokenShape(); - Shape scalar = ShapeUtil::MakeShape(F32, {}); - Shape matrix = ShapeUtil::MakeShape(U32, {1, 2}); - Shape matrix2 = ShapeUtil::MakeShapeWithLayout(S32, {3, 4}, {0, 1}); - Shape tuple = ShapeUtil::MakeTupleShape({opaque, scalar, matrix, matrix2}); - Shape nested_tuple = ShapeUtil::MakeTupleShape({tuple, matrix, token}); - +TEST_F(ShapeTest, ProgramShapeToString) { ProgramShape prog = ShapeUtil::MakeProgramShape( - {opaque, scalar, matrix, matrix2, tuple, nested_tuple}, nested_tuple); + {opaque_, scalar_, matrix_, matrix2_, tuple_, nested_tuple_}, + nested_tuple_); EXPECT_EQ( "((unknown): opaque[], " "(unknown): f32[], " @@ -87,7 +124,7 @@ TEST(ShapeTest, ProgramShapeToString) { "(unknown): ((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])) " "-> " "((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", - ShapeUtil::HumanString(prog)); + prog.ToString()); prog.add_parameter_names("arg0"); prog.add_parameter_names("scalar"); @@ -105,7 +142,7 @@ TEST(ShapeTest, ProgramShapeToString) { "token[])) " "-> " "((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", - ShapeUtil::HumanString(prog)); + prog.ToString()); } } // namespace diff --git a/tensorflow/compiler/xla/shape_util.cc b/tensorflow/compiler/xla/shape_util.cc index b05ec209cc..82662b1dbb 100644 --- a/tensorflow/compiler/xla/shape_util.cc +++ b/tensorflow/compiler/xla/shape_util.cc @@ -79,14 +79,14 @@ bool ShapeIndexView::StartsWith(ShapeIndexView prefix) const { indices_.subspan(0, prefix.size()) == prefix.indices_; } -namespace { - -// Returns whether the given primitive type corresponds to an array shape. -bool IsArrayPrimitiveType(PrimitiveType primitive_type) { +/* static */ bool ShapeUtil::IsArrayPrimitiveType( + PrimitiveType primitive_type) { return primitive_type != PRIMITIVE_TYPE_INVALID && primitive_type != TUPLE && primitive_type != OPAQUE && primitive_type != TOKEN; } +namespace { + // Recursive helper for comparing the equality of two shapes. Returns true if // the shapes are the same. If compare_layouts is true, then layouts must also // match. @@ -203,7 +203,7 @@ StatusOr MakeShapeWithLayoutInternal( /* static */ ProgramShape ShapeUtil::MakeProgramShape( std::initializer_list parameters, Shape result) { ProgramShape program_shape; - for (const auto& shape : parameters) { + for (const Shape& shape : parameters) { *program_shape.add_parameters() = shape; } *program_shape.mutable_result() = std::move(result); @@ -272,7 +272,7 @@ ShapeUtil::MakeShapeWithDescendingLayoutAndSamePhysicalLayout( /* static */ Shape ShapeUtil::MakeTupleShape(absl::Span shapes) { Shape result; result.set_element_type(TUPLE); - result.mutable_tuple_shapes()->Reserve(shapes.size()); + result.mutable_tuple_shapes()->reserve(shapes.size()); for (const auto& shape : shapes) { AppendShapeToTuple(shape, &result); } @@ -563,20 +563,6 @@ StatusOr StringToPrimitiveType(const string& name) { HumanString(program_shape.result())); } -/* static */ string ShapeUtil::HumanString( - const ProgramShapeProto& program_shape_proto) { - std::vector parameters; - for (auto& shape : program_shape_proto.parameters()) { - const int i = parameters.size(); - parameters.push_back(StrCat(i < program_shape_proto.parameter_names_size() - ? program_shape_proto.parameter_names(i) - : "(unknown)", - ": ", HumanString(shape))); - } - return StrCat("(", absl::StrJoin(parameters, ", "), ") -> ", - HumanString(program_shape_proto.result())); -} - namespace { // Parses shapes with simple recursive descent structure -- consumes from the // front of s and passes that view recursively as required. @@ -1610,7 +1596,8 @@ ShapeUtil::DimensionsUnmodifiedByReshape(const Shape& input_shape, /* static */ Shape ShapeUtil::DeleteDimension(int64 dim_to_delete, Shape shape) { CHECK(IsArray(shape)); - shape.mutable_dimensions()->erase(shape.dimensions().begin() + dim_to_delete); + shape.mutable_dimensions()->erase(shape.mutable_dimensions()->begin() + + dim_to_delete); if (LayoutUtil::HasLayout(shape)) { Layout* layout = shape.mutable_layout(); layout->set_format(DENSE); @@ -1644,11 +1631,6 @@ ShapeUtil::DimensionsUnmodifiedByReshape(const Shape& input_shape, return shape; } -std::ostream& operator<<(std::ostream& out, const Shape& shape) { - out << ShapeUtil::HumanStringWithLayout(shape); - return out; -} - /*static*/ size_t ShapeUtil::Hash(const Shape& shape) { using tensorflow::hash; using tensorflow::Hash64Combine; diff --git a/tensorflow/compiler/xla/shape_util.h b/tensorflow/compiler/xla/shape_util.h index 3796c5be5d..84a27f662a 100644 --- a/tensorflow/compiler/xla/shape_util.h +++ b/tensorflow/compiler/xla/shape_util.h @@ -240,7 +240,6 @@ class ShapeUtil { // // (param_name: f32[42x12], ...) -> f32[24x42] static string HumanString(const ProgramShape& program_shape); - static string HumanString(const ProgramShapeProto& program_shape_proto); // Parses a ShapeUtil::HumanString-format shape string back into a shape // object. @@ -469,6 +468,9 @@ class ShapeUtil { // arrays. static bool IsArray(const Shape& shape); + // Returns whether the given primitive type corresponds to an array shape. + static bool IsArrayPrimitiveType(PrimitiveType primitive_type); + // Returns whether the shape is a tuple with at least one element which is // also a tuple. static bool IsNestedTuple(const Shape& shape); @@ -796,8 +798,6 @@ class ShapeUtil { TF_DISALLOW_COPY_AND_ASSIGN(ShapeUtil); }; -std::ostream& operator<<(std::ostream& out, const Shape& shape); - } // namespace xla #endif // TENSORFLOW_COMPILER_XLA_SHAPE_UTIL_H_ diff --git a/tensorflow/compiler/xla/shape_util_test.cc b/tensorflow/compiler/xla/shape_util_test.cc index ce6330a0dc..60bdbe3020 100644 --- a/tensorflow/compiler/xla/shape_util_test.cc +++ b/tensorflow/compiler/xla/shape_util_test.cc @@ -546,37 +546,6 @@ TEST(ShapeUtilTest, IsLeafIndex) { EXPECT_TRUE(ShapeUtil::IsLeafIndex(nested_tuple_shape, {1, 1})); } -TEST(ShapeUtilTest, HumanString) { - Shape opaque = ShapeUtil::MakeOpaqueShape(); - Shape token = ShapeUtil::MakeTokenShape(); - Shape scalar = ShapeUtil::MakeShape(F32, {}); - Shape matrix = ShapeUtil::MakeShape(U32, {1, 2}); - Shape matrix2 = ShapeUtil::MakeShapeWithLayout(S32, {3, 4}, {0, 1}); - Shape tuple = ShapeUtil::MakeTupleShape({opaque, scalar, matrix, matrix2}); - Shape nested_tuple = ShapeUtil::MakeTupleShape({tuple, matrix, token}); - - EXPECT_EQ("opaque[]", ShapeUtil::HumanString(opaque)); - EXPECT_EQ("token[]", ShapeUtil::HumanString(token)); - EXPECT_EQ("f32[]", ShapeUtil::HumanString(scalar)); - EXPECT_EQ("u32[1,2]", ShapeUtil::HumanString(matrix)); - EXPECT_EQ("s32[3,4]", ShapeUtil::HumanString(matrix2)); - EXPECT_EQ("(opaque[], f32[], u32[1,2], s32[3,4])", - ShapeUtil::HumanString(tuple)); - EXPECT_EQ("((opaque[], f32[], u32[1,2], s32[3,4]), u32[1,2], token[])", - ShapeUtil::HumanString(nested_tuple)); - - EXPECT_EQ("opaque[]", ShapeUtil::HumanStringWithLayout(opaque)); - EXPECT_EQ("f32[]", ShapeUtil::HumanStringWithLayout(scalar)); - EXPECT_EQ("u32[1,2]{1,0}", ShapeUtil::HumanStringWithLayout(matrix)); - EXPECT_EQ("s32[3,4]{0,1}", ShapeUtil::HumanStringWithLayout(matrix2)); - EXPECT_EQ("(opaque[], f32[], u32[1,2]{1,0}, s32[3,4]{0,1})", - ShapeUtil::HumanStringWithLayout(tuple)); - EXPECT_EQ( - "((opaque[], f32[], u32[1,2]{1,0}, s32[3,4]{0,1}), u32[1,2]{1,0}, " - "token[])", - ShapeUtil::HumanStringWithLayout(nested_tuple)); -} - TEST(ShapeUtilTest, ForEachSubshapeArray) { const Shape shape = ShapeUtil::MakeShape(F32, {2, 3}); int calls = 0; diff --git a/tensorflow/compiler/xla/tests/client_library_test_base.cc b/tensorflow/compiler/xla/tests/client_library_test_base.cc index b98572e24c..12c0299833 100644 --- a/tensorflow/compiler/xla/tests/client_library_test_base.cc +++ b/tensorflow/compiler/xla/tests/client_library_test_base.cc @@ -107,7 +107,7 @@ StatusOr ClientLibraryTestBase::ExecuteAndTransfer( ExecutionOptions execution_options = execution_options_; if (shape_with_output_layout != nullptr) { *execution_options.mutable_shape_with_output_layout() = - *shape_with_output_layout; + shape_with_output_layout->ToProto(); } return client_->ExecuteAndTransfer(computation, arguments, &execution_options); @@ -127,7 +127,7 @@ StatusOr ClientLibraryTestBase::ExecuteAndTransferReference( ExecutionOptions execution_options = execution_options_; if (shape_with_output_layout != nullptr) { *execution_options.mutable_shape_with_output_layout() = - *shape_with_output_layout; + shape_with_output_layout->ToProto(); } execution_options.clear_device_handles(); return ref_client_->ExecuteAndTransfer(computation, arguments, diff --git a/tensorflow/compiler/xla/tests/client_test.cc b/tensorflow/compiler/xla/tests/client_test.cc index 6f2ca84bb6..363dee74b2 100644 --- a/tensorflow/compiler/xla/tests/client_test.cc +++ b/tensorflow/compiler/xla/tests/client_test.cc @@ -50,7 +50,8 @@ XLA_TEST_F(ClientTest, ExecuteWithLayout) { ExecutionOptions execution_options = execution_options_; *execution_options.mutable_shape_with_output_layout() = ShapeUtil::MakeShapeWithLayout(S32, /*dimensions=*/{2, 2}, - execute_layout); + execute_layout) + .ToProto(); TF_ASSERT_OK_AND_ASSIGN( std::unique_ptr data, client_->Execute(computation, {}, &execution_options)); @@ -84,7 +85,8 @@ XLA_TEST_F(ClientTest, ExecuteWithTupleLayout) { {ShapeUtil::MakeShapeWithLayout(S32, /*dimensions=*/{2, 2}, /*minor_to_major=*/{0, 1}), ShapeUtil::MakeShapeWithLayout(S32, /*dimensions=*/{2, 2}, - /*minor_to_major=*/{1, 0})}); + /*minor_to_major=*/{1, 0})}) + .ToProto(); TF_ASSERT_OK_AND_ASSIGN( auto result, diff --git a/tensorflow/compiler/xla/tests/reshape_test.cc b/tensorflow/compiler/xla/tests/reshape_test.cc index dedc95b5ae..298136002e 100644 --- a/tensorflow/compiler/xla/tests/reshape_test.cc +++ b/tensorflow/compiler/xla/tests/reshape_test.cc @@ -618,7 +618,8 @@ XLA_TEST_P(ReshapeTest, R4Dim0MinorLayoutToR2Dim0MajorLayout) { ExecutionOptions execution_options = execution_options_; *execution_options.mutable_shape_with_output_layout() = ShapeUtil::MakeShapeWithLayout(use_bfloat16() ? BF16 : F32, {2, 8}, - {1, 0}); + {1, 0}) + .ToProto(); Literal actual = client_ ->ExecuteAndTransfer(computation, {input.get()}, &execution_options) @@ -767,7 +768,8 @@ XLA_TEST_P(ReshapeTest, NoopReshape) { ExecutionOptions execution_options = execution_options_; *execution_options.mutable_shape_with_output_layout() = ShapeUtil::MakeShapeWithLayout(use_bfloat16() ? BF16 : F32, {7, 2, 3, 5}, - {2, 3, 0, 1}); + {2, 3, 0, 1}) + .ToProto(); Literal output_literal = client_ ->ExecuteAndTransfer(computation, {input_data.get()}, diff --git a/tensorflow/compiler/xla/tools/replay_computation.cc b/tensorflow/compiler/xla/tools/replay_computation.cc index 47be9f5adf..ff2c339992 100644 --- a/tensorflow/compiler/xla/tools/replay_computation.cc +++ b/tensorflow/compiler/xla/tools/replay_computation.cc @@ -82,13 +82,17 @@ struct Options { std::unique_ptr CompileExecutable(const HloSnapshot& module, LocalClient* client) { XlaComputation computation(module.hlo().hlo_module()); - std::vector argument_layouts; - for (const auto& param : + std::vector argument_layouts; + argument_layouts.reserve( + computation.proto().host_program_shape().parameters_size()); + std::vector argument_layout_ptrs; + for (const ShapeProto& param : computation.proto().host_program_shape().parameters()) { - argument_layouts.push_back(¶m); + argument_layouts.push_back(Shape(param)); + argument_layout_ptrs.push_back(&argument_layouts.back()); } return client - ->Compile(computation, argument_layouts, ExecutableBuildOptions()) + ->Compile(computation, argument_layout_ptrs, ExecutableBuildOptions()) .ValueOrDie(); } @@ -149,7 +153,7 @@ StatusOr ReplayComputation(const HloSnapshot& module, << "--generate_fake_infeed only works if the model has 0 or 1 " "infeed ops, but this one has >= 2."; provide_infeed = true; - infeed_shape = instruction.shape(); + infeed_shape = Shape(instruction.shape()); LOG(INFO) << "Generating fake infeed shape for inferred shape: " << ShapeUtil::HumanString(infeed_shape); } @@ -315,9 +319,10 @@ int RealMain(absl::Span args, const Options& opts) { if (snapshot.has_result()) { Literal literal = Literal::CreateFromProto(snapshot.result()).ConsumeValueOrDie(); - fprintf(stdout, "was %s:%s\n", - ShapeUtil::HumanString(snapshot.result().shape()).c_str(), - literal.ToString().c_str()); + fprintf( + stdout, "was %s:%s\n", + ShapeUtil::HumanString(Shape(snapshot.result().shape())).c_str(), + literal.ToString().c_str()); } } } diff --git a/tensorflow/compiler/xla/util.h b/tensorflow/compiler/xla/util.h index b015f4328a..6722641e9d 100644 --- a/tensorflow/compiler/xla/util.h +++ b/tensorflow/compiler/xla/util.h @@ -152,6 +152,13 @@ static inline absl::Span AsInt64Slice( slice.size()); } +// TODO(b/29771030): This nop overload was added to simplify the migration of +// Shape from a proto to a C++ class. Remove after class has been migrated. +static inline absl::Span AsInt64Slice( + absl::Span slice) { + return slice; +} + // As above, but for uint64 types. static inline absl::Span AsUInt64Slice( const tensorflow::protobuf::RepeatedField& v) { diff --git a/tensorflow/compiler/xla/xla.proto b/tensorflow/compiler/xla/xla.proto index 28df3b03f3..f745fb8506 100644 --- a/tensorflow/compiler/xla/xla.proto +++ b/tensorflow/compiler/xla/xla.proto @@ -224,7 +224,7 @@ message ExecutionOptions { // may be faster when using this layout. // // We use a Shape here to accommodate computations that return a tuple. - Shape shape_with_output_layout = 2; + ShapeProto shape_with_output_layout = 2; // Used to seed random-number generators used in this computation. If this is // 0, we generate a seed ourselves. @@ -253,7 +253,7 @@ message TransferToClientRequest { // This optional field directs the service to return the literal in this // layout. A shape is used to hold the layout to accommodate tuples. - Shape shape_with_layout = 2; + ShapeProto shape_with_layout = 2; } message TransferToClientResponse { @@ -281,7 +281,7 @@ message TransferToInfeedResponse { message TransferFromOutfeedRequest { // This optional field directs the service to return the literal in this // layout. A shape is used to hold the layout to accommodate tuples. - Shape shape_with_layout = 1; + ShapeProto shape_with_layout = 1; int64 replica_id = 2; DeviceHandle device_handle = 3; @@ -332,7 +332,7 @@ message CompileRequest { // The layouts of the input arguments. If not set, the default layout will be // used. Although the real arguments are not needed in compilation, the // layouts of the arguments can affect the compilation. - repeated Shape input_shape_with_layout = 3; + repeated ShapeProto input_shape_with_layout = 3; } message CompileResponse { @@ -406,7 +406,7 @@ message LoadDataRequest { string columnio_field = 2; // Individual element shape, excluding rows. - Shape element_shape = 3; + ShapeProto element_shape = 3; // Warning: ColumnIO does not support random-access, so use offset with // caution in performance-critical scenarios. @@ -422,7 +422,7 @@ message LoadDataRequest { message LoadDataResponse { GlobalDataHandle data = 1; - Shape data_shape = 2; + ShapeProto data_shape = 2; int64 available_rows = 3; int64 rows_loaded = 4; int64 nanoseconds = 5; @@ -433,7 +433,7 @@ message GetShapeRequest { } message GetShapeResponse { - Shape shape = 1; + ShapeProto shape = 1; } message UnpackRequest { diff --git a/tensorflow/compiler/xla/xla_data.proto b/tensorflow/compiler/xla/xla_data.proto index 27ef86ab2e..013673dd9e 100644 --- a/tensorflow/compiler/xla/xla_data.proto +++ b/tensorflow/compiler/xla/xla_data.proto @@ -154,7 +154,7 @@ message Layout { // See the XLA documentation for more information on shapes and layouts. // // LINT.IfChange -message Shape { +message ShapeProto { reserved 1; reserved "rank"; @@ -169,7 +169,7 @@ message Shape { repeated int64 dimensions = 3; // For tuples only, the shapes of constitutent shapes in the tuple sequence. - repeated Shape tuple_shapes = 4; + repeated ShapeProto tuple_shapes = 4; // The layout used to back this shape. Layout layout = 5; @@ -184,8 +184,8 @@ message Shape { // Shape of the parameters and output of a computation (like a traditional // function signature). message ProgramShapeProto { - repeated Shape parameters = 1; - Shape result = 2; + repeated ShapeProto parameters = 1; + ShapeProto result = 2; repeated string parameter_names = 3; } @@ -320,7 +320,7 @@ message DeviceAssignmentProto { // Transfers to/from the client are encoded in literal form, and the structure // of the repeated fields is implied by the shape. message LiteralProto { - Shape shape = 1; + ShapeProto shape = 1; repeated bool preds = 2; bytes s8s = 15; bytes u8s = 3; @@ -521,7 +521,7 @@ message OpSharding { } Type type = 1; // The shape of the sharded tile. - Shape tile_shape = 2; + ShapeProto tile_shape = 2; // The shape of the tile assignment tensor - this must be the same rank as // tile_shape and the product of its dimensions must equal // tile_assignment_devices.size(). diff --git a/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc b/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc index 1603b45ff6..2ccdf0f02d 100644 --- a/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc +++ b/tensorflow/compiler/xrt/kernels/xrt_compile_ops.cc @@ -109,14 +109,17 @@ Status XRTCompileOp::Compile(OpKernelContext* ctx, TF_ASSIGN_OR_RETURN(xla::XlaComputation computation, client->LoadSnapshot(computation_proto.hlo_snapshot())); - std::vector argument_layouts( + std::vector argument_layouts( + config.program_shape().parameters_size()); + std::vector argument_layout_ptrs( config.program_shape().parameters_size()); for (int i = 0; i < config.program_shape().parameters_size(); ++i) { - argument_layouts[i] = &config.program_shape().parameters(i); + argument_layouts[i] = xla::Shape(config.program_shape().parameters(i)); + argument_layout_ptrs[i] = &argument_layouts[i]; } xla::ExecutableBuildOptions build_options; build_options.set_device_ordinal(client->default_device_ordinal()); - build_options.set_result_layout(config.program_shape().result()); + build_options.set_result_layout(xla::Shape(config.program_shape().result())); build_options.set_device_allocator(device_ref.backend()->memory_allocator()); if (config.has_debug_options()) { *build_options.mutable_debug_options() = @@ -125,7 +128,7 @@ Status XRTCompileOp::Compile(OpKernelContext* ctx, VLOG(1) << "Building executable"; auto compile_result = - client->Compile(computation, argument_layouts, build_options); + client->Compile(computation, argument_layout_ptrs, build_options); if (!compile_result.ok()) { return compile_result.status(); } diff --git a/tensorflow/compiler/xrt/tests/raw_api_test.cc b/tensorflow/compiler/xrt/tests/raw_api_test.cc index 7e73db98f7..b9262c1843 100644 --- a/tensorflow/compiler/xrt/tests/raw_api_test.cc +++ b/tensorflow/compiler/xrt/tests/raw_api_test.cc @@ -375,9 +375,12 @@ TEST(RawApiTest, CompileAndExecute) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->mutable_result() = xla::ShapeUtil::MakeShape(xla::F32, {2}); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->mutable_result() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); StoreComputationSnapshot(AddAndScale(), c.mutable_hlo_snapshot()); xrt::XRTExecutionConfig e; @@ -427,9 +430,12 @@ TEST(RawApiTest, CompileAndExecuteWithArgumentVector) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->mutable_result() = xla::ShapeUtil::MakeShape(xla::F32, {2}); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->mutable_result() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); StoreComputationSnapshot(AddAndScale(), c.mutable_hlo_snapshot()); xrt::XRTExecutionConfig e; @@ -494,8 +500,8 @@ TEST(RawApiTest, CompileWithXlaReturnShapes) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->add_parameters() = param_shape; - *shapes->mutable_result() = result_shape; + *shapes->add_parameters() = param_shape.ToProto(); + *shapes->mutable_result() = result_shape.ToProto(); StoreComputationSnapshot(xla_computation, c.mutable_hlo_snapshot()); Scope root = Scope::NewRootScope().WithDevice(DeviceFromFlag()); @@ -510,8 +516,9 @@ TEST(RawApiTest, CompileWithXlaReturnShapes) { TF_EXPECT_OK(session.Run(tensorflow::ClientSession::FeedType(), {c_handle.program_shape}, {release}, &outputs)); - xla::ProgramShapeProto program_shape; - EXPECT_TRUE(program_shape.ParseFromString(outputs[0].vec()(0))); + xla::ProgramShapeProto program_shape_proto; + EXPECT_TRUE(program_shape_proto.ParseFromString(outputs[0].vec()(0))); + xla::ProgramShape program_shape(program_shape_proto); EXPECT_EQ(program_shape.parameters_size(), 1); VLOG(2) << "Param: " @@ -547,11 +554,11 @@ TEST(RawApiTest, DotGeneralWithLayoutTest) { auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); *shapes->add_parameters() = - xla::ShapeUtil::MakeShapeWithLayout(xla::F32, {2, 2}, {0, 1}); + xla::ShapeUtil::MakeShapeWithLayout(xla::F32, {2, 2}, {0, 1}).ToProto(); *shapes->add_parameters() = - xla::ShapeUtil::MakeShapeWithLayout(xla::F32, {2, 1}, {0, 1}); + xla::ShapeUtil::MakeShapeWithLayout(xla::F32, {2, 1}, {0, 1}).ToProto(); *shapes->mutable_result() = - xla::ShapeUtil::MakeShapeWithLayout(xla::F32, {2, 1}, {0, 1}); + xla::ShapeUtil::MakeShapeWithLayout(xla::F32, {2, 1}, {0, 1}).ToProto(); StoreComputationSnapshot(Dot(), c.mutable_hlo_snapshot()); xrt::XRTExecutionConfig e; @@ -592,7 +599,7 @@ TEST(RawApiTest, CompileAndExecuteZeroArg) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->mutable_result() = xla::ShapeUtil::MakeShape(xla::F32, {}); + *shapes->mutable_result() = xla::ShapeUtil::MakeShape(xla::F32, {}).ToProto(); xrt::XRTExecutionConfig e; e.set_release_input_handles(true); @@ -632,10 +639,13 @@ TEST(RawApiTest, CompileAndExecuteReturnTuple) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->mutable_result() = xla::ShapeUtil::MakeTupleShape( - {xla::ShapeUtil::MakeShape(xla::F32, {2})}); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->mutable_result() = + xla::ShapeUtil::MakeTupleShape({xla::ShapeUtil::MakeShape(xla::F32, {2})}) + .ToProto(); StoreComputationSnapshot(AddAndTuple(), c.mutable_hlo_snapshot()); xrt::XRTExecutionConfig e; @@ -675,10 +685,13 @@ TEST(RawApiTest, LeakCompilationReference) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::F32, {2}); - *shapes->mutable_result() = xla::ShapeUtil::MakeTupleShape( - {xla::ShapeUtil::MakeShape(xla::F32, {2})}); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->add_parameters() = + xla::ShapeUtil::MakeShape(xla::F32, {2}).ToProto(); + *shapes->mutable_result() = + xla::ShapeUtil::MakeTupleShape({xla::ShapeUtil::MakeShape(xla::F32, {2})}) + .ToProto(); StoreComputationSnapshot(AddAndTuple(), c.mutable_hlo_snapshot()); Scope root = Scope::NewRootScope().WithDevice(DeviceFromFlag()); @@ -703,9 +716,9 @@ TEST(RawApiTest, CompileAndExecuteWithS64Argument) { xrt::XLAComputation c; auto config = c.mutable_config(); auto shapes = config->mutable_program_shape(); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::S64, {}); - *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::S64, {}); - *shapes->mutable_result() = xla::ShapeUtil::MakeShape(xla::S64, {}); + *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::S64, {}).ToProto(); + *shapes->add_parameters() = xla::ShapeUtil::MakeShape(xla::S64, {}).ToProto(); + *shapes->mutable_result() = xla::ShapeUtil::MakeShape(xla::S64, {}).ToProto(); StoreComputationSnapshot(AddS64(), c.mutable_hlo_snapshot()); xrt::XRTExecutionConfig e; @@ -742,8 +755,8 @@ TEST(RawApiTest, CompileAndExecuteWithS64Argument) { xla::ProgramShapeProto program_shape; EXPECT_TRUE(program_shape.ParseFromString(outputs[1].vec()(0))); EXPECT_EQ(program_shape.parameters_size(), 2); - EXPECT_TRUE( - xla::ShapeUtil::HasPrimitiveType(program_shape.result(), xla::S64)); + EXPECT_TRUE(xla::ShapeUtil::HasPrimitiveType( + xla::Shape(program_shape.result()), xla::S64)); } } // namespace -- GitLab From 048d6a34bb30f0bf8f57650aa6369587b90bfefc Mon Sep 17 00:00:00 2001 From: Igor Ganichev Date: Wed, 28 Nov 2018 16:08:10 -0800 Subject: [PATCH 493/672] Add device info to function debugging utilities Also, remove the assumption that RetVal nodes have a single input. Various optimization passes can add control inputs to RetVal nodes. PiperOrigin-RevId: 223253576 --- tensorflow/core/BUILD | 1 + tensorflow/core/framework/function.cc | 44 ++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 9cd0edabdd..4313d4f1a8 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -2679,6 +2679,7 @@ tf_cuda_library( ":version_lib", "@com_google_absl//absl/base", "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/strings", "//tensorflow/core/platform/default/build_config:platformlib", "//tensorflow/core/kernels:bounds_check", "//third_party/eigen3", diff --git a/tensorflow/core/framework/function.cc b/tensorflow/core/framework/function.cc index 6809c27197..b69a40f312 100644 --- a/tensorflow/core/framework/function.cc +++ b/tensorflow/core/framework/function.cc @@ -21,6 +21,7 @@ limitations under the License. #include #include "absl/container/flat_hash_set.h" +#include "absl/strings/str_join.h" #include "tensorflow/core/framework/common_shape_fns.h" #include "tensorflow/core/framework/function.pb_text.h" #include "tensorflow/core/framework/graph.pb.h" @@ -32,6 +33,7 @@ limitations under the License. #include "tensorflow/core/lib/gtl/inlined_vector.h" #include "tensorflow/core/lib/gtl/map_util.h" #include "tensorflow/core/lib/strings/str_util.h" +#include "tensorflow/core/util/device_name_utils.h" #include "tensorflow/core/util/equal_graph_def.h" namespace tensorflow { @@ -507,6 +509,16 @@ string Print(const NodeDef& n) { entries.push_back(strings::StrCat(a.first, "=", Print(a.second))); } std::sort(entries.begin(), entries.end()); + // Add a short device string at the end of all attributes. + if (!n.device().empty()) { + DeviceNameUtils::ParsedName parsed; + if (DeviceNameUtils::ParseFullName(n.device(), &parsed)) { + entries.push_back( + strings::StrCat("device=", parsed.type, ":", parsed.id)); + } else { + entries.push_back("device="); + } + } strings::StrAppend(&out, "[", str_util::Join(entries, ", "), "]"); } strings::StrAppend(&out, "("); @@ -590,26 +602,50 @@ string Print(gtl::ArraySlice nodes) { std::sort(ret.begin(), ret.end(), comp); string out; strings::StrAppend(&out, "\n("); - auto get_type = [](const NodeDef& n) { + auto get_type_and_device = [](const NodeDef& n) { DataType dt; if (!GetNodeAttr(n, "T", &dt).ok()) { dt = DT_INVALID; } + if (!n.device().empty()) { + DeviceNameUtils::ParsedName parsed; + if (DeviceNameUtils::ParseFullName(n.device(), &parsed)) { + return strings::StrCat(DataTypeString(dt), "@", parsed.type, ":", + parsed.id); + } else { + return strings::StrCat(DataTypeString(dt), "@", + ""); + } + } return DataTypeString(dt); }; for (size_t i = 0; i < arg.size(); ++i) { const NodeDef* n = arg[i]; if (i > 0) strings::StrAppend(&out, ", "); CHECK_GE(n->attr_size(), 2); - strings::StrAppend(&out, n->name(), ":", get_type(*n)); + strings::StrAppend(&out, n->name(), ":", get_type_and_device(*n)); } strings::StrAppend(&out, ") -> ("); for (size_t i = 0; i < ret.size(); ++i) { const NodeDef* n = ret[i]; if (i > 0) strings::StrAppend(&out, ", "); CHECK_LE(2, n->attr_size()); - CHECK_EQ(1, n->input_size()); - strings::StrAppend(&out, n->input(0), ":", get_type(*n)); + + // The _RetVal op should have a unique non-control input. We assert that + // here and add it to the output. + bool found_non_control_input = false; + for (const string& input : n->input()) { + if (!input.empty() && input[0] != '^') { + DCHECK_EQ(found_non_control_input, false) + << "RetVal node has more than one non-control input: " + << absl::StrJoin(n->input(), ", "); + strings::StrAppend(&out, n->input(0), ":", get_type_and_device(*n)); + found_non_control_input = true; + } + } + DCHECK_EQ(found_non_control_input, true) + << "RetVal did not have any non-control inputs: " + << absl::StrJoin(n->input(), ", "); } strings::StrAppend(&out, ") {\n"); for (size_t i = 0; i < body.size(); ++i) { -- GitLab From b86dd9ee886487cbb9ce62ad315256bc4ea0982f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 16:09:52 -0800 Subject: [PATCH 494/672] Improve performance of grouped convolutions. PiperOrigin-RevId: 223253872 --- .../convolution_feature_group_converter.cc | 255 ++++++++++++----- .../compiler/xla/tests/convolution_test.cc | 257 ++++++++++++++++++ 2 files changed, 450 insertions(+), 62 deletions(-) diff --git a/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc b/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc index 10c53f15f5..09c3f32860 100644 --- a/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc +++ b/tensorflow/compiler/xla/service/convolution_feature_group_converter.cc @@ -270,78 +270,209 @@ Status ConvolutionVisitor::HandleConvolution(HloInstruction* convolution) { TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( convolution, std::move(new_convolution))); } else { - // The filter expansion mechanism adds zeroes in the kernel. - // For an OF = 12, IF = 6, and kernel IF = 2, the expanded filter mask - // would look like (IF on the Y-axis, OF on the X-axis) - // 1 1 1 1 0 0 0 0 0 0 0 0 - // 1 1 1 1 0 0 0 0 0 0 0 0 - // 0 0 0 0 1 1 1 1 0 0 0 0 - // 0 0 0 0 1 1 1 1 0 0 0 0 - // 0 0 0 0 0 0 0 0 1 1 1 1 - // 0 0 0 0 0 0 0 0 1 1 1 1 - // - // Instead of convolving the above with the input, we instead slice the - // kernel into three kernels, each containing islands of 1s from the filter - // above. We also slice the activations in the IF dimension with each slice - // of size = group_size. For each slice, we perform convolutions, and - // concatenate the generated outputs in the output OF dimension. - - std::vector sliced_convolutions; + int64 activation_input_feature_dim = dim_numbers.input_feature_dimension(); auto activation = convolution->mutable_operand(0); - std::vector slice_strides(filter->shape().dimensions_size(), 1); - std::vector filter_slice_starts(filter->shape().dimensions_size(), - 0); - std::vector filter_slice_limits(filter->shape().dimensions().begin(), - filter->shape().dimensions().end()); - std::vector activation_slice_starts( - activation->shape().dimensions_size(), 0); - std::vector activation_slice_limits( - activation->shape().dimensions().begin(), - activation->shape().dimensions().end()); int64 output_feature = filter->shape().dimensions(kernel_output_feature_dim); - auto output_feature_dim = dim_numbers.output_feature_dimension(); - int64 filter_slice_width = output_feature / group_count; - int64 activation_input_feature_dim = dim_numbers.input_feature_dimension(); + int64 input_feature = + activation->shape().dimensions(activation_input_feature_dim); + + // If group_count == output_feature, then we map those grouped convolutions + // onto depthwise convolution + reduce. E.g., we would turn + // [2, 12]{B, IF} conv [3, 4]{IF, OF} into + // [2, 12]{B, IF} depth conv [1, 12]{IF, OF}, and then use a reduce window + // of {1, 3} on the generated [2, 12] output to produce the final result of + // [2, 4]. + if (group_count == output_feature && !filter_expansion_) { + Shape reshaped_filter_shape = filter->shape(); + + if (kernel_input_feature_dim < kernel_output_feature_dim) { + // Transpose IF and OF on the kernel. + std::vector filter_dims; + for (int64 i = 0; i < dim_numbers.kernel_spatial_dimensions().size(); + ++i) { + filter_dims.push_back(dim_numbers.kernel_spatial_dimensions(i)); + } + filter_dims.push_back(kernel_output_feature_dim); + filter_dims.push_back(kernel_input_feature_dim); + + Shape transposed_filter = filter->shape(); + auto& dimensions = *transposed_filter.mutable_dimensions(); + std::swap(dimensions[kernel_input_feature_dim], + dimensions[kernel_output_feature_dim]); + + filter = add(HloInstruction::CreateTranspose(transposed_filter, filter, + filter_dims)); + } else { + // For depthwise convolutions, we want the kernel input feature + // dimension to be smaller than the output feature dimension. If that's + // not the case, we swap the dimensions. + + auto& dimensions = *reshaped_filter_shape.mutable_dimensions(); + std::swap(dimensions[kernel_input_feature_dim], + dimensions[kernel_output_feature_dim]); + + dim_numbers.set_kernel_input_feature_dimension( + kernel_output_feature_dim); + + dim_numbers.set_kernel_output_feature_dimension( + kernel_input_feature_dim); + std::swap(kernel_output_feature_dim, kernel_input_feature_dim); + } - for (int64 i = 0; i < group_count; i++) { - filter_slice_starts[kernel_output_feature_dim] = i * filter_slice_width; - filter_slice_limits[kernel_output_feature_dim] = - (i + 1) * filter_slice_width; - auto filter_sliced_shape = filter->shape(); - filter_sliced_shape.set_dimensions(kernel_output_feature_dim, - filter_slice_width); - auto filter_slice = add(HloInstruction::CreateSlice( - filter_sliced_shape, filter, filter_slice_starts, filter_slice_limits, - slice_strides)); - - activation_slice_starts[activation_input_feature_dim] = i * group_size; - activation_slice_limits[activation_input_feature_dim] = - (i + 1) * group_size; - auto activation_sliced_shape = activation->shape(); - activation_sliced_shape.set_dimensions(activation_input_feature_dim, - group_size); - auto activation_slice = add(HloInstruction::CreateSlice( - activation_sliced_shape, activation, activation_slice_starts, - activation_slice_limits, slice_strides)); - - auto conv_slice_shape = convolution->shape(); - conv_slice_shape.set_dimensions(output_feature_dim, filter_slice_width); + reshaped_filter_shape.set_dimensions(kernel_input_feature_dim, 1); + reshaped_filter_shape.set_dimensions(kernel_output_feature_dim, + group_count * group_size); + auto reshaped_filter = + add(HloInstruction::CreateReshape(reshaped_filter_shape, filter)); + Shape reshaped_convolution_shape = convolution->shape(); + reshaped_convolution_shape.set_dimensions( + dim_numbers.output_feature_dimension(), group_count * group_size); auto new_convolution = add(HloInstruction::CreateConvolve( - conv_slice_shape, activation_slice, filter_slice, - /*feature_group_count=*/1, convolution->window(), dim_numbers, - convolution->precision_config())); + reshaped_convolution_shape, convolution->mutable_operand(0), + reshaped_filter, /*feature_group_count=*/input_feature, + convolution->window(), dim_numbers, convolution->precision_config())); + + // Create the reduce window. + Window window; + for (int64 i = 0; i < new_convolution->shape().dimensions_size(); ++i) { + auto* dim = window.add_dimensions(); + dim->set_padding_low(0); + dim->set_padding_high(0); + dim->set_window_dilation(1); + dim->set_base_dilation(1); + if (i == dim_numbers.output_feature_dimension()) { + dim->set_stride(group_size); + dim->set_size(group_size); + } else { + dim->set_stride(1); + dim->set_size(1); + } + } - sliced_convolutions.push_back(new_convolution); - } + auto reduce_window_shape = new_convolution->shape(); + reduce_window_shape.set_dimensions(dim_numbers.output_feature_dimension(), + group_count); + + auto zero_literal = LiteralUtil::CreateR0(0.0f); + TF_ASSIGN_OR_RETURN(zero_literal, zero_literal.Convert(F32)); + auto zero = add(HloInstruction::CreateConstant(std::move(zero_literal))); + + auto reduce_function = [&]() -> HloComputation* { + HloComputation::Builder b("add_computation"); + Shape shape = ShapeUtil::MakeShape(F32, {}); + auto lhs = + b.AddInstruction(HloInstruction::CreateParameter(0, shape, "lhs")); + auto rhs = + b.AddInstruction(HloInstruction::CreateParameter(1, shape, "rhs")); + auto scalar_op = b.AddInstruction( + HloInstruction::CreateBinary(shape, HloOpcode::kAdd, lhs, rhs)); + return computation_->parent()->AddEmbeddedComputation( + b.Build(scalar_op)); + }; + + // Ensure that data input to reduce window is of type F32. + if (primitive_util::BitWidth(new_convolution->shape().element_type()) < + primitive_util::BitWidth(F32)) { + Shape convert_shape = new_convolution->shape(); + convert_shape.set_element_type(F32); + new_convolution = add(HloInstruction::CreateBitcastConvert( + convert_shape, new_convolution)); + } - auto new_conv = HloInstruction::CreateConcatenate( - convolution->shape(), sliced_convolutions, output_feature_dim); - TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( - convolution, std::move(new_conv))); + auto reduce_window = add(HloInstruction::CreateReduceWindow( + reduce_window_shape, new_convolution, zero, window, + reduce_function())); + + Shape convert_back_shape = reduce_window->shape(); + convert_back_shape.set_element_type(activation->shape().element_type()); + + // Convert reduced data back to the original data type. + auto reduce_window_converted = HloInstruction::CreateBitcastConvert( + convert_back_shape, reduce_window); + TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( + convolution, std::move(reduce_window_converted))); + + } else { + // The filter expansion mechanism adds zeroes in the kernel. + // For an OF = 12, IF = 6, and kernel IF = 2, the expanded filter mask + // would look like (IF on the Y-axis, OF on the X-axis) + // 1 1 1 1 0 0 0 0 0 0 0 0 + // 1 1 1 1 0 0 0 0 0 0 0 0 + // 0 0 0 0 1 1 1 1 0 0 0 0 + // 0 0 0 0 1 1 1 1 0 0 0 0 + // 0 0 0 0 0 0 0 0 1 1 1 1 + // 0 0 0 0 0 0 0 0 1 1 1 1 + // + // Instead of convolving the above with the input, we instead slice the + // kernel into three kernels, each containing islands of 1s from the + // filter above. We also slice the activations in the IF dimension with + // each slice of size = group_size. For each slice, we perform + // convolutions, and concatenate the generated outputs in the output OF + // dimension. + + std::vector sliced_convolutions; + auto activation = convolution->mutable_operand(0); + std::vector slice_strides(filter->shape().dimensions_size(), 1); + std::vector filter_slice_starts(filter->shape().dimensions_size(), + 0); + std::vector filter_slice_limits( + filter->shape().dimensions().begin(), + filter->shape().dimensions().end()); + std::vector activation_slice_starts( + activation->shape().dimensions_size(), 0); + std::vector activation_slice_limits( + activation->shape().dimensions().begin(), + activation->shape().dimensions().end()); + + int64 output_feature = + filter->shape().dimensions(kernel_output_feature_dim); + auto output_feature_dim = dim_numbers.output_feature_dimension(); + int64 filter_slice_width = output_feature / group_count; + + int64 activation_input_feature_dim = + dim_numbers.input_feature_dimension(); + + for (int64 i = 0; i < group_count; i++) { + filter_slice_starts[kernel_output_feature_dim] = i * filter_slice_width; + filter_slice_limits[kernel_output_feature_dim] = + (i + 1) * filter_slice_width; + auto filter_sliced_shape = filter->shape(); + filter_sliced_shape.set_dimensions(kernel_output_feature_dim, + filter_slice_width); + auto filter_slice = add(HloInstruction::CreateSlice( + filter_sliced_shape, filter, filter_slice_starts, + filter_slice_limits, slice_strides)); + + activation_slice_starts[activation_input_feature_dim] = i * group_size; + activation_slice_limits[activation_input_feature_dim] = + (i + 1) * group_size; + auto activation_sliced_shape = activation->shape(); + activation_sliced_shape.set_dimensions(activation_input_feature_dim, + group_size); + auto activation_slice = add(HloInstruction::CreateSlice( + activation_sliced_shape, activation, activation_slice_starts, + activation_slice_limits, slice_strides)); + + auto conv_slice_shape = convolution->shape(); + conv_slice_shape.set_dimensions(output_feature_dim, filter_slice_width); + + auto new_convolution = add(HloInstruction::CreateConvolve( + conv_slice_shape, activation_slice, filter_slice, + /*feature_group_count=*/1, convolution->window(), dim_numbers, + convolution->precision_config())); + + sliced_convolutions.push_back(new_convolution); + } + + auto new_conv = HloInstruction::CreateConcatenate( + convolution->shape(), sliced_convolutions, output_feature_dim); + TF_RETURN_IF_ERROR(computation_->ReplaceWithNewInstruction( + convolution, std::move(new_conv))); + } } return Status::OK(); diff --git a/tensorflow/compiler/xla/tests/convolution_test.cc b/tensorflow/compiler/xla/tests/convolution_test.cc index 7e81905260..4a58a1ed66 100644 --- a/tensorflow/compiler/xla/tests/convolution_test.cc +++ b/tensorflow/compiler/xla/tests/convolution_test.cc @@ -1410,6 +1410,263 @@ TYPED_TEST(Convolve2D_1x2x2x1024_2x2x128x512_Grouped_Valid, Types) { this->RunTest(); } +template +class Convolve2D_1x2x2x1024_2x2x128x8_Grouped_Valid : public ConvolutionTest { + public: + void RunTest() { + XlaBuilder builder(TestName()); + std::vector input_dims = {1, 2, 2, 1024}; + std::vector filter_dims = {2, 2, 128, 8}; + Shape input_shape = ShapeUtil::MakeShapeWithType(input_dims); + Shape filter_shape = ShapeUtil::MakeShapeWithType(filter_dims); + { + auto input = Parameter(&builder, 0, input_shape, "input"); + auto filter = Parameter(&builder, 1, filter_shape, "filter"); + + // Tensorflow dimension numbers for 2D convolution. + ConvolutionDimensionNumbers dnums; + dnums.set_input_batch_dimension(0); + dnums.set_output_batch_dimension(0); + dnums.add_input_spatial_dimensions(1); + dnums.add_output_spatial_dimensions(1); + dnums.add_input_spatial_dimensions(2); + dnums.add_output_spatial_dimensions(2); + dnums.set_input_feature_dimension(3); + dnums.set_output_feature_dimension(3); + dnums.add_kernel_spatial_dimensions(0); + dnums.add_kernel_spatial_dimensions(1); + dnums.set_kernel_input_feature_dimension(2); + dnums.set_kernel_output_feature_dimension(3); + + ConvWithGeneralDimensions(input, filter, {1, 1}, Padding::kValid, dnums, + /*feature_group_count=*/8); + } + + std::vector input_elems(ShapeUtil::ElementsIn(input_shape), + static_cast(1)); + + auto input_r1 = LiteralUtil::CreateR1(input_elems); + auto input_r4 = input_r1.Reshape(input_dims).ConsumeValueOrDie(); + + std::vector filter_elems(ShapeUtil::ElementsIn(filter_shape), + static_cast(2)); + + auto filter_r1 = LiteralUtil::CreateR1(filter_elems); + auto filter_r4 = filter_r1.Reshape(filter_dims).ConsumeValueOrDie(); + + std::vector output_elems(8, static_cast(1024)); + auto expected_r1 = LiteralUtil::CreateR1(output_elems); + auto expected_r4 = expected_r1.Reshape({1, 1, 1, 8}).ConsumeValueOrDie(); + + auto input_literal = + client_->TransferToServer(input_r4).ConsumeValueOrDie(); + auto filter_literal = + client_->TransferToServer(filter_r4).ConsumeValueOrDie(); + + ComputeAndCompareLiteral(&builder, expected_r4, + {input_literal.get(), filter_literal.get()}, + error_spec_); + } +}; + +TYPED_TEST_CASE(Convolve2D_1x2x2x1024_2x2x128x8_Grouped_Valid, TestTypes); +TYPED_TEST(Convolve2D_1x2x2x1024_2x2x128x8_Grouped_Valid, Types) { + this->RunTest(); +} + +template +class Convolve2D_1x2x2x12_2x2x3x4_Grouped_Valid : public ConvolutionTest { + public: + void RunTest() { + XlaBuilder builder(TestName()); + std::vector input_dims = {1, 2, 2, 12}; + std::vector filter_dims = {2, 2, 3, 4}; + Shape input_shape = ShapeUtil::MakeShapeWithType(input_dims); + Shape filter_shape = ShapeUtil::MakeShapeWithType(filter_dims); + { + auto input = Parameter(&builder, 0, input_shape, "input"); + auto filter = Parameter(&builder, 1, filter_shape, "filter"); + + // Tensorflow dimension numbers for 2D convolution. + ConvolutionDimensionNumbers dnums; + dnums.set_input_batch_dimension(0); + dnums.set_output_batch_dimension(0); + dnums.add_input_spatial_dimensions(1); + dnums.add_output_spatial_dimensions(1); + dnums.add_input_spatial_dimensions(2); + dnums.add_output_spatial_dimensions(2); + dnums.set_input_feature_dimension(3); + dnums.set_output_feature_dimension(3); + dnums.add_kernel_spatial_dimensions(0); + dnums.add_kernel_spatial_dimensions(1); + dnums.set_kernel_input_feature_dimension(2); + dnums.set_kernel_output_feature_dimension(3); + + ConvWithGeneralDimensions(input, filter, {1, 1}, Padding::kValid, dnums, + /*feature_group_count=*/4); + } + + std::vector input_elems(ShapeUtil::ElementsIn(input_shape)); + iota_int_init_value(input_elems, 1); + auto input_r1 = LiteralUtil::CreateR1(input_elems); + auto input_r4 = input_r1.Reshape(input_dims).ConsumeValueOrDie(); + + std::vector filter_elems(ShapeUtil::ElementsIn(filter_shape)); + iota_int_init_value(filter_elems, 1); + auto filter_r1 = LiteralUtil::CreateR1(filter_elems); + auto filter_r4 = filter_r1.Reshape(filter_dims).ConsumeValueOrDie(); + + auto expected_r1 = + LiteralUtil::CreateR1({static_cast(7712), static_cast(8816), + static_cast(9992), static_cast(11240)}); + auto expected_r4 = expected_r1.Reshape({1, 1, 1, 4}).ConsumeValueOrDie(); + + auto input_literal = + client_->TransferToServer(input_r4).ConsumeValueOrDie(); + auto filter_literal = + client_->TransferToServer(filter_r4).ConsumeValueOrDie(); + + ComputeAndCompareLiteral(&builder, expected_r4, + {input_literal.get(), filter_literal.get()}, + error_spec_); + } +}; + +TYPED_TEST_CASE(Convolve2D_1x2x2x12_2x2x3x4_Grouped_Valid, TestTypes); +TYPED_TEST(Convolve2D_1x2x2x12_2x2x3x4_Grouped_Valid, Types) { + this->RunTest(); +} + +template +class Convolve2D_1x2x2x12_2x2x3x4_Grouped_Valid_Filter_OF_In_Sublanes + : public ConvolutionTest { + public: + void RunTest() { + XlaBuilder builder(TestName()); + std::vector input_dims = {1, 2, 2, 12}; + std::vector filter_dims = {2, 2, 4, 3}; + Shape input_shape = ShapeUtil::MakeShapeWithType(input_dims); + Shape filter_shape = ShapeUtil::MakeShapeWithType(filter_dims); + { + auto input = Parameter(&builder, 0, input_shape, "input"); + auto filter = Parameter(&builder, 1, filter_shape, "filter"); + + // Tensorflow dimension numbers for 2D convolution. + ConvolutionDimensionNumbers dnums; + dnums.set_input_batch_dimension(0); + dnums.set_output_batch_dimension(0); + dnums.add_input_spatial_dimensions(1); + dnums.add_output_spatial_dimensions(1); + dnums.add_input_spatial_dimensions(2); + dnums.add_output_spatial_dimensions(2); + dnums.set_input_feature_dimension(3); + dnums.set_output_feature_dimension(3); + dnums.add_kernel_spatial_dimensions(0); + dnums.add_kernel_spatial_dimensions(1); + dnums.set_kernel_input_feature_dimension(3); + dnums.set_kernel_output_feature_dimension(2); + + ConvWithGeneralDimensions(input, filter, {1, 1}, Padding::kValid, dnums, + /*feature_group_count=*/4); + } + + std::vector input_elems(ShapeUtil::ElementsIn(input_shape)); + iota_int_init_value(input_elems, 1); + auto input_r1 = LiteralUtil::CreateR1(input_elems); + auto input_r4 = input_r1.Reshape(input_dims).ConsumeValueOrDie(); + + std::vector filter_elems(ShapeUtil::ElementsIn(filter_shape)); + iota_int_init_value(filter_elems, 1); + auto filter_r1 = LiteralUtil::CreateR1(filter_elems); + auto filter_r4 = filter_r1.Reshape(filter_dims).ConsumeValueOrDie(); + auto filter_r4_relaid = + filter_r4.Relayout(LayoutUtil::MakeLayout({3, 2, 1, 0})); + auto expected_r1 = LiteralUtil::CreateR1( + {static_cast(6968), static_cast(8516), static_cast(10280), + static_cast(12260)}); + auto expected_r4 = expected_r1.Reshape({1, 1, 1, 4}).ConsumeValueOrDie(); + + auto input_literal = + client_->TransferToServer(input_r4).ConsumeValueOrDie(); + auto filter_literal = + client_->TransferToServer(filter_r4_relaid).ConsumeValueOrDie(); + + ComputeAndCompareLiteral(&builder, expected_r4, + {input_literal.get(), filter_literal.get()}, + error_spec_); + } +}; + +TYPED_TEST_CASE(Convolve2D_1x2x2x12_2x2x3x4_Grouped_Valid_Filter_OF_In_Sublanes, + TestTypes); +TYPED_TEST(Convolve2D_1x2x2x12_2x2x3x4_Grouped_Valid_Filter_OF_In_Sublanes, + Types) { + this->RunTest(); +} + +template +class Convolve2D_1x1x1x12_1x1x3x4_Grouped_Valid : public ConvolutionTest { + public: + void RunTest() { + XlaBuilder builder(TestName()); + std::vector input_dims = {1, 1, 1, 12}; + std::vector filter_dims = {1, 1, 3, 4}; + Shape input_shape = ShapeUtil::MakeShapeWithType(input_dims); + Shape filter_shape = ShapeUtil::MakeShapeWithType(filter_dims); + { + auto input = Parameter(&builder, 0, input_shape, "input"); + auto filter = Parameter(&builder, 1, filter_shape, "filter"); + + // Tensorflow dimension numbers for 2D convolution. + ConvolutionDimensionNumbers dnums; + dnums.set_input_batch_dimension(0); + dnums.set_output_batch_dimension(0); + dnums.add_input_spatial_dimensions(1); + dnums.add_output_spatial_dimensions(1); + dnums.add_input_spatial_dimensions(2); + dnums.add_output_spatial_dimensions(2); + dnums.set_input_feature_dimension(3); + dnums.set_output_feature_dimension(3); + dnums.add_kernel_spatial_dimensions(0); + dnums.add_kernel_spatial_dimensions(1); + dnums.set_kernel_input_feature_dimension(2); + dnums.set_kernel_output_feature_dimension(3); + + ConvWithGeneralDimensions(input, filter, {1, 1}, Padding::kValid, dnums, + /*feature_group_count=*/4); + } + + std::vector input_elems(ShapeUtil::ElementsIn(input_shape)); + iota_int_init_value(input_elems, 1); + auto input_r1 = LiteralUtil::CreateR1(input_elems); + auto input_r4 = input_r1.Reshape(input_dims).ConsumeValueOrDie(); + + std::vector filter_elems(ShapeUtil::ElementsIn(filter_shape)); + iota_int_init_value(filter_elems, 1); + auto filter_r1 = LiteralUtil::CreateR1(filter_elems); + auto filter_r4 = filter_r1.Reshape(filter_dims).ConsumeValueOrDie(); + + auto expected_r1 = + LiteralUtil::CreateR1({static_cast(38), static_cast(98), + static_cast(176), static_cast(272)}); + auto expected_r4 = expected_r1.Reshape({1, 1, 1, 4}).ConsumeValueOrDie(); + + auto input_literal = + client_->TransferToServer(input_r4).ConsumeValueOrDie(); + auto filter_literal = + client_->TransferToServer(filter_r4).ConsumeValueOrDie(); + + ComputeAndCompareLiteral(&builder, expected_r4, + {input_literal.get(), filter_literal.get()}, + error_spec_); + } +}; + +TYPED_TEST_CASE(Convolve2D_1x1x1x12_1x1x3x4_Grouped_Valid, TestTypes); +TYPED_TEST(Convolve2D_1x1x1x12_1x1x3x4_Grouped_Valid, Types) { + this->RunTest(); +} + // Test fixture to run convolution tests with and without convolution // canonicalization enabled. class ConvolveWithAndWithoutCanonicalization -- GitLab From ea680ae952681ed88738b91deb5463d178b42c43 Mon Sep 17 00:00:00 2001 From: Shining Sun Date: Wed, 28 Nov 2018 16:12:34 -0800 Subject: [PATCH 495/672] Remove "return_same_structure" argument from while_loop_v2. PiperOrigin-RevId: 223254267 --- .../python/kernel_tests/while_v2_test.py | 89 ++++++++++++++----- tensorflow/python/ops/control_flow_ops.py | 16 ++-- tensorflow/python/ops/while_v2.py | 6 +- .../tools/api/golden/v2/tensorflow.pbtxt | 2 +- 4 files changed, 78 insertions(+), 35 deletions(-) diff --git a/tensorflow/python/kernel_tests/while_v2_test.py b/tensorflow/python/kernel_tests/while_v2_test.py index 48b32f06aa..e08699922a 100644 --- a/tensorflow/python/kernel_tests/while_v2_test.py +++ b/tensorflow/python/kernel_tests/while_v2_test.py @@ -45,12 +45,25 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def testSingleLoopVar(self): x = constant_op.constant(2.) - ret = while_loop_v2(lambda v: v < 8., lambda v: v * v, [x]) + ret = while_loop_v2( + lambda v: v < 8., lambda v: v * v, [x], return_same_structure=False) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: self.assertEqual(self.evaluate(ret), 16.) self.assertSequenceEqual(self.evaluate(grad), [32.]) + def testReturnSameStructureTrue(self): + x = constant_op.constant(2.) + ret = while_loop_v2( + lambda v: v < 8., lambda v: v * v, [x], return_same_structure=True) + grad = gradients_impl.gradients(ret, [x]) + with self.cached_session() as sess: + eval_result = sess.run(ret) + self.assertIsInstance(eval_result, list) + self.assertLen(eval_result, 1) + self.assertEqual(16., eval_result[0]) + self.assertSequenceEqual(sess.run(grad), [32.]) + def testMultipleLoopVarsBasic(self): x = constant_op.constant(5.) y = constant_op.constant(3.) @@ -59,7 +72,10 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): # y = 3. # while x < 45.: # x = x * y - ret = while_loop_v2(lambda v, _: v < 45., lambda v, w: (v * w, w), [x, y]) + ret = while_loop_v2( + lambda v, _: v < 45., + lambda v, w: (v * w, w), [x, y], + return_same_structure=False) # ret = [x*y^2, y] # Note: This is simply d_ret[0]/d_x since d_ret[1]/d_x is 0. @@ -77,8 +93,10 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): # while x < 45.: # x = x * y # y = x + y - ret = while_loop_v2(lambda v, _: v < 45., lambda v, w: (v * w, v + w), - [x, y]) + ret = while_loop_v2( + lambda v, _: v < 45., + lambda v, w: (v * w, v + w), [x, y], + return_same_structure=False) # ret = [y*x**2 + x*y**2, x*y + x + y] gradx_0 = gradients_impl.gradients(ret[0], [x]) # [2*x*y + y**2] @@ -98,8 +116,12 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def testMultipleWhileLoops(self): x = constant_op.constant(2.) - ret1 = while_loop_v2(lambda v: v < 4., lambda v: v * v, [x]) # x**2 - ret2 = while_loop_v2(lambda v: v < 16., lambda v: v * v, [ret1]) # x**4 + ret1 = while_loop_v2( + lambda v: v < 4., lambda v: v * v, [x], + return_same_structure=False) # x**2 + ret2 = while_loop_v2( + lambda v: v < 16., lambda v: v * v, [ret1], + return_same_structure=False) # x**4 grad = gradients_impl.gradients(ret2, [x]) # 4x**3 grad_grad = gradients_impl.gradients(grad, [x]) # 12x**2 with self.cached_session() as sess: @@ -108,7 +130,9 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def testDoubleDerivative(self): x = constant_op.constant(2.) - ret = while_loop_v2(lambda v: v < 8., lambda v: v**2, [x]) # x**4 + ret = while_loop_v2( + lambda v: v < 8., lambda v: v**2, [x], + return_same_structure=False) # x**4 grad = gradients_impl.gradients(ret, [x]) # 4x**3 grad_grad = gradients_impl.gradients(grad, [x]) # 12x**2 with self.cached_session() as sess: @@ -154,7 +178,10 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def testCaptureExternalTensorInCond(self): x = constant_op.constant(2.) y = constant_op.constant(1.) - ret = while_loop_v2(lambda v: v + y < 9., lambda v: v * 3., [x]) + ret = while_loop_v2( + lambda v: v + y < 9., + lambda v: v * 3., [x], + return_same_structure=False) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: self.assertEqual(self.evaluate(ret), 18.) @@ -163,7 +190,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def testCaptureExternalTensorInBody(self): x = constant_op.constant(2.) y = constant_op.constant(3.) - ret = while_loop_v2(lambda v: v < 8., lambda v: v * y, [x]) + ret = while_loop_v2( + lambda v: v < 8., lambda v: v * y, [x], return_same_structure=False) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: self.assertEqual(self.evaluate(ret), 18.) @@ -184,7 +212,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): tl = list_ops.tensor_list_push_back(tl, constant_op.constant(100.)) return x**2., tl - ret = while_loop_v2(Cond, Body, [x, tensor_list]) + ret = while_loop_v2( + Cond, Body, [x, tensor_list], return_same_structure=False) grad = gradients_impl.gradients(ret[0], x) with self.cached_session() as sess: self.assertEqual(sess.run(ret[0]), 16.) @@ -206,7 +235,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): tl = list_ops.tensor_list_push_back(tl, x) return x**2., tl - ret = while_loop_v2(Cond, Body, [x, tensor_list]) + ret = while_loop_v2( + Cond, Body, [x, tensor_list], return_same_structure=False) for op in ops.get_default_graph().get_operations(): if op.type == "While": @@ -253,7 +283,10 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): y = array_ops.placeholder(dtype=dtypes.float32, shape=shape) # Forward pass. - ret = while_loop_v2(lambda v, u: v < 8., lambda v, u: (v * v, u), [x, y]) + ret = while_loop_v2( + lambda v, u: v < 8., + lambda v, u: (v * v, u), [x, y], + return_same_structure=False) while_op = ret[0].op.inputs[0].op # Get the TensorList output of While op containing the accumulated values # of y. @@ -277,8 +310,10 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def _createWhile(self, name): """Helper function testDefaultName.""" - output = while_v2.while_loop(lambda i: i < 3, lambda i: i + 1, - [constant_op.constant(0)]) + output = while_v2.while_loop( + lambda i: i < 3, + lambda i: i + 1, [constant_op.constant(0)], + return_same_structure=False) while_op = output.op.inputs[0].op self.assertEqual(while_op.type, "While") return while_op @@ -329,9 +364,14 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): def Body(i, previous_sum): prod = constant_op.constant(1.) return i - 1., previous_sum + while_loop_v2( - lambda c, _: c > 0, lambda c, v: (c - 1., v * n), [i, prod])[1] - - result = while_loop_v2(lambda i, _: i >= 0, Body, [m, sum_of_powers])[1] + lambda c, _: c > 0, + lambda c, v: (c - 1., v * n), [i, prod], + return_same_structure=False)[1] + + result = while_loop_v2( + lambda i, _: i >= 0, + Body, [m, sum_of_powers], + return_same_structure=False)[1] grad = gradients_impl.gradients(result, [n]) with self.cached_session() as sess: self.assertEqual(self.evaluate(result), 364.) @@ -345,7 +385,8 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): return v * v x = constant_op.constant(2.) - ret = while_loop_v2(lambda v: v < 8., Body, [x]) + ret = while_loop_v2( + lambda v: v < 8., Body, [x], return_same_structure=False) grad = gradients_impl.gradients(ret, [x]) with self.cached_session() as sess: self.assertEqual(self.evaluate(ret), 16.) @@ -363,13 +404,17 @@ class WhileV2Test(test.TestCase, parameterized.TestCase): return row, col + 1., ta, n # TODO(b/118457764): Remove n from loop_vars from both loops once fixed. - ta = while_loop_v2(lambda _, col, _1, n: col <= n, InnerBody, - [row, constant_op.constant(1.), ta, n])[2] + ta = while_loop_v2( + lambda _, col, _1, n: col <= n, + InnerBody, [row, constant_op.constant(1.), ta, n], + return_same_structure=False)[2] return row + 1., ta, n ta = tensor_array_ops.TensorArray(dtype=dtypes.float32, size=9) - ta = while_loop_v2(lambda row, _, _1: row <= n, Body, - [constant_op.constant(1.), ta, n])[1] + ta = while_loop_v2( + lambda row, _, _1: row <= n, + Body, [constant_op.constant(1.), ta, n], + return_same_structure=False)[1] output = array_ops.reshape(ta.stack(), [3, 3]) self.assertAllEqual( diff --git a/tensorflow/python/ops/control_flow_ops.py b/tensorflow/python/ops/control_flow_ops.py index a36a24ebb0..b7e50c1dae 100644 --- a/tensorflow/python/ops/control_flow_ops.py +++ b/tensorflow/python/ops/control_flow_ops.py @@ -3145,7 +3145,6 @@ def while_loop_v2(cond, back_prop=True, swap_memory=False, maximum_iterations=None, - return_same_structure=False, name=None): """Repeat `body` while the condition `cond` is true. @@ -3221,17 +3220,11 @@ def while_loop_v2(cond, to run. If provided, the `cond` output is AND-ed with an additional condition ensuring the number of iterations executed is no greater than `maximum_iterations`. - return_same_structure: If True, output has same structure as `loop_vars`. If - eager execution is enabled, this is ignored (and always treated as True). name: Optional name prefix for the returned tensors. Returns: - The output tensors for the loop variables after the loop. - If `return_same_structure` is True, the return value has the same - structure as `loop_vars`. - If `return_same_structure` is False, the return value is a Tensor, - TensorArray or IndexedSlice if the length of `loop_vars` is 1, or a list - otherwise. + The output tensors for the loop variables after the loop. The return value + has the same structure as `loop_vars`. Raises: TypeError: if `cond` or `body` is not callable. @@ -3318,7 +3311,7 @@ def while_loop_v2(cond, swap_memory=swap_memory, name=name, maximum_iterations=maximum_iterations, - return_same_structure=return_same_structure) + return_same_structure=True) # pylint: disable=redefined-outer-name @@ -3501,7 +3494,8 @@ def while_loop(cond, loop_vars, shape_invariants=shape_invariants, maximum_iterations=maximum_iterations, - name=name) + name=name, + return_same_structure=return_same_structure) with ops.name_scope(name, "while", loop_vars): if not loop_vars: diff --git a/tensorflow/python/ops/while_v2.py b/tensorflow/python/ops/while_v2.py index 6821b63d0e..59ca29e3ba 100644 --- a/tensorflow/python/ops/while_v2.py +++ b/tensorflow/python/ops/while_v2.py @@ -64,7 +64,8 @@ def while_loop(cond, loop_vars, shape_invariants=None, maximum_iterations=None, - name=None): + name=None, + return_same_structure=True): """Like tf.while_loop, except emits a single While op.""" maximum_iterations = _validate_and_convert_to_tensor(maximum_iterations) # Keep the original loop_vars around to know which args were TensorArrays. @@ -258,6 +259,9 @@ def while_loop(cond, outputs = _pack_sequence_as(orig_loop_vars, outputs[1:1 + num_flattened_outputs]) + if return_same_structure: + return outputs + flattened_outputs = nest.flatten(outputs) if len(flattened_outputs) == 1: return flattened_outputs[0] diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 0659900ffa..40693e7582 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -1130,7 +1130,7 @@ tf_module { } member_method { name: "while_loop" - argspec: "args=[\'cond\', \'body\', \'loop_vars\', \'shape_invariants\', \'parallel_iterations\', \'back_prop\', \'swap_memory\', \'maximum_iterations\', \'return_same_structure\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'True\', \'False\', \'None\', \'False\', \'None\'], " + argspec: "args=[\'cond\', \'body\', \'loop_vars\', \'shape_invariants\', \'parallel_iterations\', \'back_prop\', \'swap_memory\', \'maximum_iterations\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'True\', \'False\', \'None\', \'None\'], " } member_method { name: "zeros" -- GitLab From 3655dc13a2576567a7719bc9307c5faac48fae6b Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 16:15:21 -0800 Subject: [PATCH 496/672] Fix XLA documentation for ReduceWindow PiperOrigin-RevId: 223254699 --- tensorflow/compiler/xla/g3doc/operation_semantics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow/compiler/xla/g3doc/operation_semantics.md b/tensorflow/compiler/xla/g3doc/operation_semantics.md index bc87a60c6e..df74a9b3af 100644 --- a/tensorflow/compiler/xla/g3doc/operation_semantics.md +++ b/tensorflow/compiler/xla/g3doc/operation_semantics.md @@ -1796,8 +1796,9 @@ XlaBuilder builder(client_, "reduce_window_2x3"); auto shape = ShapeUtil::MakeShape(F32, {4, 6}); auto input = builder.Parameter(0, shape, "input"); builder.ReduceWindow( - input, *max, + input, /*init_val=*/builder.ConstantLiteral(LiteralUtil::MinValue(F32)), + *max, /*window_dimensions=*/{2, 3}, /*window_stride_dimensions=*/{2, 3}, Padding::kValid); -- GitLab From d7418be7bff57803de971336dda25cd3d844ac79 Mon Sep 17 00:00:00 2001 From: Mahmoud Abuzaina Date: Wed, 28 Nov 2018 16:27:18 -0800 Subject: [PATCH 497/672] Ran a newer version of clang-format --- tensorflow/core/kernels/mkl_conv_ops.cc | 100 ++++++++++++------------ 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/tensorflow/core/kernels/mkl_conv_ops.cc b/tensorflow/core/kernels/mkl_conv_ops.cc index 8e3b669a59..75f08956b4 100644 --- a/tensorflow/core/kernels/mkl_conv_ops.cc +++ b/tensorflow/core/kernels/mkl_conv_ops.cc @@ -323,7 +323,7 @@ class MklConvFwdPrimitiveFactory : public MklPrimitiveFactory { const MklConvFwdParams& convFwdDims, bool do_not_cache) { MklConvFwdPrimitive* conv_fwd = nullptr; - if (do_not_cache) {/* Always create new primitive */ + if (do_not_cache) { /* Always create new primitive */ conv_fwd = new MklConvFwdPrimitive( convFwdDims); } else { @@ -423,16 +423,15 @@ class MklConvOp : public OpKernel { OP_REQUIRES(context, FormatFromString(data_format, &data_format_), errors::InvalidArgument("Invalid data format")); OP_REQUIRES(context, strides_.size() == 4, - errors::InvalidArgument( - "Sliding window strides field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window strides field must " + "specify 4 dimensions")); const int64 stride_n = GetTensorDim(strides_, data_format_, 'N'); const int64 stride_c = GetTensorDim(strides_, data_format_, 'C'); - OP_REQUIRES(context, stride_n == 1 && stride_c == 1, - errors::InvalidArgument( - "Current implementation does not yet support " - "strides in the batch and depth dimensions.")); + OP_REQUIRES( + context, stride_n == 1 && stride_c == 1, + errors::InvalidArgument("Current implementation does not yet support " + "strides in the batch and depth dimensions.")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); } @@ -727,7 +726,7 @@ class MklConvOp : public OpKernel { mkl_prim_convert_input; dnnLayout_t mkl_lt_internal_filter, mkl_lt_internal_bias, mkl_lt_internal_input; - void* mkl_buf_convert_input, *mkl_buf_convert_filter, + void *mkl_buf_convert_input, *mkl_buf_convert_filter, *mkl_buf_convert_bias; mkl_prim_convert_filter = nullptr; mkl_prim_convert_bias = nullptr; @@ -860,23 +859,21 @@ class MklConvOp : public OpKernel { OP_REQUIRES(context, FormatFromString(data_format, &data_format_), errors::InvalidArgument("Invalid data format")); OP_REQUIRES(context, (strides_.size() == 4 || strides_.size() == 5), - errors::InvalidArgument( - "Sliding window strides field must " - "specify 4 or 5 dimensions")); + errors::InvalidArgument("Sliding window strides field must " + "specify 4 or 5 dimensions")); const int64 stride_n = GetTensorDim(strides_, data_format_, 'N'); const int64 stride_c = GetTensorDim(strides_, data_format_, 'C'); - OP_REQUIRES(context, stride_n == 1 && stride_c == 1, - errors::InvalidArgument( - "Current implementation does not yet support " - "strides in the batch and depth dimensions.")); + OP_REQUIRES( + context, stride_n == 1 && stride_c == 1, + errors::InvalidArgument("Current implementation does not yet support " + "strides in the batch and depth dimensions.")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); if (strides_.size() == 4) { OP_REQUIRES(context, dilations_.size() == 4, - errors::InvalidArgument( - "Sliding window dilations field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window dilations field must " + "specify 4 dimensions")); const int64 dilation_n = GetTensorDim(dilations_, data_format_, 'N'); const int64 dilation_c = GetTensorDim(dilations_, data_format_, 'C'); const int64 dilation_h = GetTensorDim(dilations_, data_format_, 'H'); @@ -890,9 +887,8 @@ class MklConvOp : public OpKernel { errors::InvalidArgument("Dilated rates should be larger than 0.")); } else if (strides_.size() == 5) { OP_REQUIRES(context, dilations_.size() == 5, - errors::InvalidArgument( - "Dilation rates field must " - "specify 5 dimensions")); + errors::InvalidArgument("Dilation rates field must " + "specify 5 dimensions")); OP_REQUIRES(context, (GetTensorDim(dilations_, data_format_, 'N') == 1 && GetTensorDim(dilations_, data_format_, 'C') == 1), errors::InvalidArgument( @@ -916,9 +912,8 @@ class MklConvOp : public OpKernel { GetMklShape(context, kInputIndex_Src, &src_mkl_shape); GetMklShape(context, kInputIndex_Filter, &filter_mkl_shape); OP_REQUIRES(context, filter_mkl_shape.IsMklTensor() == false, - errors::InvalidArgument( - "Filter should not be in " - "Mkl Layout")); + errors::InvalidArgument("Filter should not be in " + "Mkl Layout")); MklDnnData src(&cpu_engine_); MklDnnData filter(&cpu_engine_); @@ -954,8 +949,9 @@ class MklConvOp : public OpKernel { filter_mkl_shape.SetMklTensor(false); Tensor* output_filter_tensor = nullptr; // MklConv2D also outputs converted filter as 2nd output. - if (typeid(Tinput) == typeid(float)&&typeid(Tfilter) == - typeid(float)&&typeid(Toutput) == typeid(float)) { + if (typeid(Tinput) == typeid(float) && + typeid(Tfilter) == typeid(float) && + typeid(Toutput) == typeid(float)) { filter_mkl_shape.SetMklTensor(false); AllocateOutputSetMklShape(context, kOutputIndex_Filter, &output_filter_tensor, filter_tf_shape, @@ -1042,8 +1038,8 @@ class MklConvOp : public OpKernel { AllocateOutputTensor(context, *conv_fwd_pd, dst_dims_mkl_order, tf_fmt, &dst_tensor); Tensor* filter_out_tensor = nullptr; - if (typeid(Tinput) == typeid(float)&&typeid(Tfilter) == - typeid(float)&&typeid(Toutput) == typeid(float)) { + if (typeid(Tinput) == typeid(float) && typeid(Tfilter) == typeid(float) && + typeid(Toutput) == typeid(float)) { AllocateFilterOutputTensor(context, *conv_fwd_pd, TFShapeToMklDnnDims(filter_tf_shape), &filter_out_tensor); @@ -1092,8 +1088,7 @@ class MklConvOp : public OpKernel { // delete primitive since it is not cached. if (do_not_cache) delete conv_fwd; - } - catch (mkldnn::error& e) { + } catch (mkldnn::error& e) { string error_msg = tensorflow::strings::StrCat( "Status: ", e.status, ", message: ", string(e.message), ", in file ", __FILE__, ":", __LINE__); @@ -1789,31 +1784,34 @@ REGISTER_KERNEL_BUILDER( #endif // INTEL_MKL_ML // Register 2D operations -#define REGISTER_MKL_CPU_2D(T) \ - REGISTER_KERNEL_BUILDER( \ - Name("_MklConv2D").Device(DEVICE_CPU).TypeConstraint("T").Label( \ - mkl_op_registry::kMklOpLabel), \ - MklConvOp); \ - REGISTER_KERNEL_BUILDER( \ - Name("_MklConv2DWithBias") \ - .Device(DEVICE_CPU) \ - .TypeConstraint("T") \ - .Label(mkl_op_registry::kMklOpLabel), \ - MklConvOp); \ - REGISTER_KERNEL_BUILDER(Name("__MklDummyConv2DWithBias") \ - .Device(DEVICE_CPU) \ - .TypeConstraint("T") \ - .Label(mkl_op_registry::kMklOpLabel), \ +#define REGISTER_MKL_CPU_2D(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("_MklConv2D") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ + MklConvOp); \ + REGISTER_KERNEL_BUILDER( \ + Name("_MklConv2DWithBias") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ + MklConvOp); \ + REGISTER_KERNEL_BUILDER(Name("__MklDummyConv2DWithBias") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ MklDummyOp); TF_CALL_float(REGISTER_MKL_CPU_2D); // Register 3D operations -#define REGISTER_MKL_CPU_3D(T) \ - REGISTER_KERNEL_BUILDER( \ - Name("_MklConv3D").Device(DEVICE_CPU).TypeConstraint("T").Label( \ - mkl_op_registry::kMklOpLabel), \ - MklConvOp); +#define REGISTER_MKL_CPU_3D(T) \ + REGISTER_KERNEL_BUILDER(Name("_MklConv3D") \ + .Device(DEVICE_CPU) \ + .TypeConstraint("T") \ + .Label(mkl_op_registry::kMklOpLabel), \ + MklConvOp); TF_CALL_float(REGISTER_MKL_CPU_3D); } // namespace tensorflow -- GitLab From e6b3d3b22a26555ccb00403c6db87813752c675b Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 28 Nov 2018 16:15:45 -0800 Subject: [PATCH 498/672] Avoid unused variable warnings from XLA_MAKE_BINARY PiperOrigin-RevId: 223254783 --- tensorflow/compiler/tf2xla/kernels/binary_ops.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tensorflow/compiler/tf2xla/kernels/binary_ops.cc b/tensorflow/compiler/tf2xla/kernels/binary_ops.cc index 47e517a657..74c1dd2406 100644 --- a/tensorflow/compiler/tf2xla/kernels/binary_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/binary_ops.cc @@ -43,6 +43,9 @@ namespace { const std::vector& extend_dimensions) override { \ xla::XlaBuilder* b = ctx->builder(); \ (void)b; \ + (void)lhs_shape; \ + (void)rhs_shape; \ + (void)extend_dimensions; \ return HLO; \ } \ }; \ -- GitLab From 22ff3ec66ef0a2453e353d8b1ed21a1866884381 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 16:24:30 -0800 Subject: [PATCH 499/672] Adds tf.abs to tf.lite schema PiperOrigin-RevId: 223256197 --- tensorflow/lite/builtin_ops.h | 1 + .../lite/core/api/flatbuffer_conversions.cc | 1 + tensorflow/lite/nnapi_delegate.cc | 1 + tensorflow/lite/schema/schema.fbs | 6 + tensorflow/lite/schema/schema_generated.h | 124 +++++++++++++++++- 5 files changed, 127 insertions(+), 6 deletions(-) diff --git a/tensorflow/lite/builtin_ops.h b/tensorflow/lite/builtin_ops.h index 2300ff4ed2..63b5cd1960 100644 --- a/tensorflow/lite/builtin_ops.h +++ b/tensorflow/lite/builtin_ops.h @@ -126,6 +126,7 @@ typedef enum { kTfLiteBuiltinLeakyRelu = 98, kTfLiteBuiltinSquaredDifference = 99, kTfLiteBuiltinMirrorPad = 100, + kTfLiteBuiltinAbs = 101, } TfLiteBuiltinOperator; #ifdef __cplusplus diff --git a/tensorflow/lite/core/api/flatbuffer_conversions.cc b/tensorflow/lite/core/api/flatbuffer_conversions.cc index aa9b372398..d3383bccf0 100644 --- a/tensorflow/lite/core/api/flatbuffer_conversions.cc +++ b/tensorflow/lite/core/api/flatbuffer_conversions.cc @@ -644,6 +644,7 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, } // Below are the ops with no builtin_data strcture. + case BuiltinOperator_ABS: case BuiltinOperator_BATCH_TO_SPACE_ND: // TODO(aselle): Implement call in BuiltinOptions, but nullptrs are // ok for now, since there is no call implementation either. diff --git a/tensorflow/lite/nnapi_delegate.cc b/tensorflow/lite/nnapi_delegate.cc index 58288a8dd4..312cedda6c 100644 --- a/tensorflow/lite/nnapi_delegate.cc +++ b/tensorflow/lite/nnapi_delegate.cc @@ -684,6 +684,7 @@ TfLiteStatus AddOpsAndParams( case tflite::BuiltinOperator_LEAKY_RELU: case tflite::BuiltinOperator_SQUARED_DIFFERENCE: case tflite::BuiltinOperator_MIRROR_PAD: + case tflite::BuiltinOperator_ABS: logError("Op code %d is currently not delegated to NNAPI", builtin); return kTfLiteError; break; diff --git a/tensorflow/lite/schema/schema.fbs b/tensorflow/lite/schema/schema.fbs index 652871d013..094db1a1d5 100644 --- a/tensorflow/lite/schema/schema.fbs +++ b/tensorflow/lite/schema/schema.fbs @@ -203,6 +203,7 @@ enum BuiltinOperator : byte { LEAKY_RELU = 98, SQUARED_DIFFERENCE = 99, MIRROR_PAD = 100, + ABS = 101, } // Options for the builtin operators. @@ -284,6 +285,7 @@ union BuiltinOptions { LeakyReluOptions, SquaredDifferenceOptions, MirrorPadOptions, + AbsOptions, } enum Padding : byte { SAME, VALID } @@ -635,6 +637,10 @@ table OneHotOptions { axis:int; } +table AbsOptions { +} + + table LogicalAndOptions { } diff --git a/tensorflow/lite/schema/schema_generated.h b/tensorflow/lite/schema/schema_generated.h index 1464c75613..1d560b3298 100755 --- a/tensorflow/lite/schema/schema_generated.h +++ b/tensorflow/lite/schema/schema_generated.h @@ -226,6 +226,9 @@ struct LogicalOrOptionsT; struct OneHotOptions; struct OneHotOptionsT; +struct AbsOptions; +struct AbsOptionsT; + struct LogicalAndOptions; struct LogicalAndOptionsT; @@ -512,11 +515,12 @@ enum BuiltinOperator { BuiltinOperator_LEAKY_RELU = 98, BuiltinOperator_SQUARED_DIFFERENCE = 99, BuiltinOperator_MIRROR_PAD = 100, + BuiltinOperator_ABS = 101, BuiltinOperator_MIN = BuiltinOperator_ADD, - BuiltinOperator_MAX = BuiltinOperator_MIRROR_PAD + BuiltinOperator_MAX = BuiltinOperator_ABS }; -inline const BuiltinOperator (&EnumValuesBuiltinOperator())[100] { +inline const BuiltinOperator (&EnumValuesBuiltinOperator())[101] { static const BuiltinOperator values[] = { BuiltinOperator_ADD, BuiltinOperator_AVERAGE_POOL_2D, @@ -617,7 +621,8 @@ inline const BuiltinOperator (&EnumValuesBuiltinOperator())[100] { BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, BuiltinOperator_LEAKY_RELU, BuiltinOperator_SQUARED_DIFFERENCE, - BuiltinOperator_MIRROR_PAD + BuiltinOperator_MIRROR_PAD, + BuiltinOperator_ABS }; return values; } @@ -725,6 +730,7 @@ inline const char * const *EnumNamesBuiltinOperator() { "LEAKY_RELU", "SQUARED_DIFFERENCE", "MIRROR_PAD", + "ABS", nullptr }; return names; @@ -814,11 +820,12 @@ enum BuiltinOptions { BuiltinOptions_LeakyReluOptions = 75, BuiltinOptions_SquaredDifferenceOptions = 76, BuiltinOptions_MirrorPadOptions = 77, + BuiltinOptions_AbsOptions = 78, BuiltinOptions_MIN = BuiltinOptions_NONE, - BuiltinOptions_MAX = BuiltinOptions_MirrorPadOptions + BuiltinOptions_MAX = BuiltinOptions_AbsOptions }; -inline const BuiltinOptions (&EnumValuesBuiltinOptions())[78] { +inline const BuiltinOptions (&EnumValuesBuiltinOptions())[79] { static const BuiltinOptions values[] = { BuiltinOptions_NONE, BuiltinOptions_Conv2DOptions, @@ -897,7 +904,8 @@ inline const BuiltinOptions (&EnumValuesBuiltinOptions())[78] { BuiltinOptions_ResizeNearestNeighborOptions, BuiltinOptions_LeakyReluOptions, BuiltinOptions_SquaredDifferenceOptions, - BuiltinOptions_MirrorPadOptions + BuiltinOptions_MirrorPadOptions, + BuiltinOptions_AbsOptions }; return values; } @@ -982,6 +990,7 @@ inline const char * const *EnumNamesBuiltinOptions() { "LeakyReluOptions", "SquaredDifferenceOptions", "MirrorPadOptions", + "AbsOptions", nullptr }; return names; @@ -1304,6 +1313,10 @@ template<> struct BuiltinOptionsTraits { static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions; }; +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions; +}; + struct BuiltinOptionsUnion { BuiltinOptions type; void *value; @@ -1951,6 +1964,14 @@ struct BuiltinOptionsUnion { return type == BuiltinOptions_MirrorPadOptions ? reinterpret_cast(value) : nullptr; } + AbsOptionsT *AsAbsOptions() { + return type == BuiltinOptions_AbsOptions ? + reinterpret_cast(value) : nullptr; + } + const AbsOptionsT *AsAbsOptions() const { + return type == BuiltinOptions_AbsOptions ? + reinterpret_cast(value) : nullptr; + } }; bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type); @@ -6339,6 +6360,46 @@ inline flatbuffers::Offset CreateOneHotOptions( flatbuffers::Offset CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb, const OneHotOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +struct AbsOptionsT : public flatbuffers::NativeTable { + typedef AbsOptions TableType; + AbsOptionsT() { + } +}; + +struct AbsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AbsOptionsT NativeTableType; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + AbsOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AbsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AbsOptionsBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AbsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + AbsOptionsBuilder &operator=(const AbsOptionsBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAbsOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + AbsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + struct LogicalAndOptionsT : public flatbuffers::NativeTable { typedef LogicalAndOptions TableType; LogicalAndOptionsT() { @@ -7237,6 +7298,9 @@ struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const MirrorPadOptions *builtin_options_as_MirrorPadOptions() const { return builtin_options_type() == BuiltinOptions_MirrorPadOptions ? static_cast(builtin_options()) : nullptr; } + const AbsOptions *builtin_options_as_AbsOptions() const { + return builtin_options_type() == BuiltinOptions_AbsOptions ? static_cast(builtin_options()) : nullptr; + } const flatbuffers::Vector *custom_options() const { return GetPointer *>(VT_CUSTOM_OPTIONS); } @@ -7576,6 +7640,10 @@ template<> inline const MirrorPadOptions *Operator::builtin_options_as inline const AbsOptions *Operator::builtin_options_as() const { + return builtin_options_as_AbsOptions(); +} + struct OperatorBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; @@ -9854,6 +9922,29 @@ inline flatbuffers::Offset CreateOneHotOptions(flatbuffers::FlatB _axis); } +inline AbsOptionsT *AbsOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new AbsOptionsT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void AbsOptions::UnPackTo(AbsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset AbsOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAbsOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AbsOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateAbsOptions( + _fbb); +} + inline LogicalAndOptionsT *LogicalAndOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { auto _o = new LogicalAndOptionsT(); UnPackTo(_o, _resolver); @@ -10708,6 +10799,10 @@ inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *ob auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } default: return false; } } @@ -11034,6 +11129,10 @@ inline void *BuiltinOptionsUnion::UnPack(const void *obj, BuiltinOptions type, c auto ptr = reinterpret_cast(obj); return ptr->UnPack(resolver); } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } default: return nullptr; } } @@ -11348,6 +11447,10 @@ inline flatbuffers::Offset BuiltinOptionsUnion::Pack(flatbuffers::FlatBuff auto ptr = reinterpret_cast(value); return CreateMirrorPadOptions(_fbb, ptr, _rehasher).Union(); } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(value); + return CreateAbsOptions(_fbb, ptr, _rehasher).Union(); + } default: return 0; } } @@ -11662,6 +11765,10 @@ inline BuiltinOptionsUnion::BuiltinOptionsUnion(const BuiltinOptionsUnion &u) FL value = new MirrorPadOptionsT(*reinterpret_cast(u.value)); break; } + case BuiltinOptions_AbsOptions: { + value = new AbsOptionsT(*reinterpret_cast(u.value)); + break; + } default: break; } @@ -12054,6 +12161,11 @@ inline void BuiltinOptionsUnion::Reset() { delete ptr; break; } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } default: break; } value = nullptr; -- GitLab From f6ee54c9b160931623fcc5f52e704e9d6d29f74d Mon Sep 17 00:00:00 2001 From: Skye Wanderman-Milne Date: Wed, 28 Nov 2018 16:49:14 -0800 Subject: [PATCH 500/672] cond_v2: use optional tensors instead of FakeParams. The purpose of this change is to not waste memory allocating large FakeParams, which is especially important on GPU. This also adds a few other fixes needed to get optional variants working with cond_v2, including on GPU. PiperOrigin-RevId: 223260005 --- tensorflow/core/common_runtime/placer.cc | 2 +- tensorflow/core/kernels/control_flow_ops.cc | 1 + tensorflow/python/BUILD | 11 ++ .../python/kernel_tests/cond_v2_test.py | 18 +-- .../kernel_tests/control_flow_ops_py_test.py | 6 +- tensorflow/python/ops/cond_v2.py | 140 +++++++++++++++--- tensorflow/python/ops/control_flow_util.py | 5 + tensorflow/python/ops/gradients_impl.py | 1 + tensorflow/python/ops/optional_grad.py | 33 +++++ 9 files changed, 180 insertions(+), 37 deletions(-) create mode 100644 tensorflow/python/ops/optional_grad.py diff --git a/tensorflow/core/common_runtime/placer.cc b/tensorflow/core/common_runtime/placer.cc index 01e4072f60..515c1971d9 100644 --- a/tensorflow/core/common_runtime/placer.cc +++ b/tensorflow/core/common_runtime/placer.cc @@ -1002,7 +1002,7 @@ Status Placer::Run() { int assigned_device = -1; // Heuristic A application. - if (IsGeneratorNode(node)) { + if (IsGeneratorNode(node) && !node->out_edges().empty()) { const Node* output = (*node->out_edges().begin())->dst(); int output_device_name = output->assigned_device_name_index(); diff --git a/tensorflow/core/kernels/control_flow_ops.cc b/tensorflow/core/kernels/control_flow_ops.cc index 1587eb5114..081ef72c15 100644 --- a/tensorflow/core/kernels/control_flow_ops.cc +++ b/tensorflow/core/kernels/control_flow_ops.cc @@ -78,6 +78,7 @@ TF_CALL_QUANTIZED_TYPES(REGISTER_GPU_SWITCH); TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_REF_SWITCH); TF_CALL_QUANTIZED_TYPES(REGISTER_GPU_REF_SWITCH); REGISTER_GPU_SWITCH(uint64); +TF_CALL_variant(REGISTER_GPU_SWITCH); #undef REGISTER_CPU_SWITCH #undef REGISTER_CPU_REF_SWITCH diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 19d2af4515..2dbca6ed6e 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -1972,6 +1972,15 @@ py_library( ], ) +py_library( + name = "optional_grad", + srcs = ["ops/optional_grad.py"], + srcs_version = "PY2AND3", + deps = [ + ":framework_ops", + ], +) + py_library( name = "sets", srcs = [ @@ -2151,6 +2160,7 @@ py_library( ":graph_to_function_def", ":pywrap_tensorflow", ":util", + "//tensorflow/python/data/ops:dataset_ops", "//tensorflow/python/eager:function", ], ) @@ -2295,6 +2305,7 @@ py_library( ":manip_ops", ":math_grad", ":math_ops", + ":optional_grad", ":platform", ":random_grad", ":resource_variable_ops", diff --git a/tensorflow/python/kernel_tests/cond_v2_test.py b/tensorflow/python/kernel_tests/cond_v2_test.py index ace18dbc44..09e41ec8c6 100644 --- a/tensorflow/python/kernel_tests/cond_v2_test.py +++ b/tensorflow/python/kernel_tests/cond_v2_test.py @@ -126,7 +126,7 @@ class CondV2Test(test.TestCase): self.assertEqual(sess.run(out, {pred: False}), (2.0,)) def _createCond(self, name): - """Helper function for testDefaultName.""" + """Creates a cond_v2 call and returns the output tensor and the cond op.""" pred = constant_op.constant(True, name="pred") x = constant_op.constant(1.0, name="x") @@ -139,11 +139,11 @@ class CondV2Test(test.TestCase): output = cond_v2.cond_v2(pred, true_fn, false_fn, name=name) cond_op = output.op.inputs[0].op self.assertEqual(cond_op.type, "If") - return cond_op + return output, cond_op def testDefaultName(self): with ops.Graph().as_default(): - cond_op = self._createCond(None) + _, cond_op = self._createCond(None) self.assertEqual(cond_op.name, "cond") self.assertRegexpMatches( cond_op.get_attr("then_branch").name, r"cond_true_\d*") @@ -152,14 +152,14 @@ class CondV2Test(test.TestCase): with ops.Graph().as_default(): with ops.name_scope("foo"): - cond1_op = self._createCond("") + _, cond1_op = self._createCond("") self.assertEqual(cond1_op.name, "foo/cond") self.assertRegexpMatches( cond1_op.get_attr("then_branch").name, r"foo_cond_true_\d*") self.assertRegexpMatches( cond1_op.get_attr("else_branch").name, r"foo_cond_false_\d*") - cond2_op = self._createCond(None) + _, cond2_op = self._createCond(None) self.assertEqual(cond2_op.name, "foo/cond_1") self.assertRegexpMatches( cond2_op.get_attr("then_branch").name, r"foo_cond_1_true_\d*") @@ -612,11 +612,11 @@ class CondV2Test(test.TestCase): def testLowering(self): with ops.Graph().as_default() as g: with self.session(graph=g) as sess: - out_cond = self._createCond("cond") + cond_output, _ = self._createCond("cond") run_options = config_pb2.RunOptions(output_partition_graphs=True) run_metadata = config_pb2.RunMetadata() - sess.run(out_cond, options=run_options, run_metadata=run_metadata) + sess.run(cond_output, options=run_options, run_metadata=run_metadata) # If lowering was enabled, there should be a `Switch` node switch_found = any( @@ -641,12 +641,12 @@ class CondV2Test(test.TestCase): # Build the cond_v2 in an XLA context xla_context = control_flow_ops.XLAControlFlowContext() xla_context.Enter() - out_cond = self._createCond("cond") + cond_output, _ = self._createCond("cond") xla_context.Exit() run_options = config_pb2.RunOptions(output_partition_graphs=True) run_metadata = config_pb2.RunMetadata() - sess.run(out_cond, options=run_options, run_metadata=run_metadata) + sess.run(cond_output, options=run_options, run_metadata=run_metadata) # Lowering disabled in XLA, there should be no `Switch` node switch_found = any( diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index 37654abd18..685d0438af 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -446,8 +446,7 @@ class ControlFlowTest(test.TestCase): g = gradients_impl.gradients(y, x)[0] self.assertAllEqual(sess.run(g, {pred: True}), [2.0, 2.0, 2.0]) - # TODO(b/119791601): Enable this. - # self.assertAllEqual(sess.run(g, {pred: False}), [0.0, 0.0, 0.0]) + self.assertAllEqual(sess.run(g, {pred: False}), [0.0, 0.0, 0.0]) @test_util.disable_control_flow_v2("b/113293074") def testCondIndexedSlicesDifferentTypes(self): @@ -2168,11 +2167,8 @@ class ControlFlowTest(test.TestCase): self.assertAllClose(512.0, self.evaluate(r)) def testNestedWhileCondWhileGrad(self): - if control_flow_ops.ENABLE_WHILE_V2 and test_util.is_gpu_available(): - self.skipTest("b/118459209") self._testNestedWhileCondWhileGrad(use_gpu=False) - @test_util.disable_control_flow_v2("b/118459209") def testNestedWhileCondWhileGradGpu(self): self._testNestedWhileCondWhileGrad(use_gpu=True) diff --git a/tensorflow/python/ops/cond_v2.py b/tensorflow/python/ops/cond_v2.py index 927c64919d..f7a95bd909 100644 --- a/tensorflow/python/ops/cond_v2.py +++ b/tensorflow/python/ops/cond_v2.py @@ -30,7 +30,9 @@ from tensorflow.python.framework import func_graph as func_graph_module from tensorflow.python.framework import function_def_to_graph from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops +from tensorflow.python.ops import control_flow_util from tensorflow.python.ops import control_flow_util_v2 as util +from tensorflow.python.ops import gen_dataset_ops from tensorflow.python.ops import gen_functional_ops from tensorflow.python.ops import gen_resource_variable_ops from tensorflow.python.ops import gradients_impl @@ -149,7 +151,9 @@ def _build_cond(pred, true_graph, false_graph, true_inputs, false_inputs, true_inputs, false_inputs) # Add all intermediate tensors as function outputs so they're available for - # the gradient computation. + # the gradient computation. Since the outputs of the two functions must match, + # we wrap all the intermediates in optionals. Each intermediate output will + # have a value iff its corresponding branch is taken. true_intermediates = _get_intermediates(true_graph) false_intermediates = _get_intermediates(false_graph) @@ -157,12 +161,28 @@ def _build_cond(pred, true_graph, false_graph, true_inputs, false_inputs, # Save the original number of outputs to return to the caller. num_cond_outputs = len(true_graph.outputs) - # Make the number/type of new intermediate outputs match. - extra_true_outputs, extra_false_outputs = _pad_params( - true_graph, false_graph, true_intermediates, false_intermediates) + if control_flow_util.InXlaContext(ops.get_default_graph()): + # XLA does not yet support optionals, so output intermediates directly and + # make them match via FakeParams, which can be converted to zeros in XLA. + # TODO(skyewm,jpienaar): can XLA support optionals? + extra_true_outputs, extra_false_outputs = _make_intermediates_match_xla( + true_graph, false_graph, true_intermediates, false_intermediates) + else: + # Wrap intermediates in optionals. + wrapped_true_intermediates = _wrap_intermediates(true_graph, + true_intermediates) + wrapped_false_intermediates = _wrap_intermediates(false_graph, + false_intermediates) + + # Make outputs match by adding none optionals. + extra_true_outputs, extra_false_outputs = _make_intermediates_match( + true_graph, false_graph, + wrapped_true_intermediates, wrapped_false_intermediates) true_graph.outputs.extend(extra_true_outputs) false_graph.outputs.extend(extra_false_outputs) + # TODO(skyewm): somehow indicate it's a bug if this fails. + _check_same_outputs(true_graph, false_graph) # Create the If op. tensors = gen_functional_ops._if( # pylint: disable=protected-access @@ -175,7 +195,8 @@ def _build_cond(pred, true_graph, false_graph, true_inputs, false_inputs, name=name) # TODO(b/110167197) this approach requires cond_v2 to have at least 1 output - util.maybe_set_lowering_attr(tensors[0].op) + if_op = tensors[0].op + util.maybe_set_lowering_attr(if_op) # Return identities for each output of the If op, rather than the output of # the If op directly. This makes pruning work if the output of cond() is @@ -187,6 +208,9 @@ def _build_cond(pred, true_graph, false_graph, true_inputs, false_inputs, # correct output structure tensors = [array_ops.identity(t) for t in tensors] + # Prevent fetching since the variant outputs can't be fetched directly. + if_op.graph.prevent_fetching(if_op) + return tensors[:num_cond_outputs] @@ -278,7 +302,7 @@ def _create_grad_func(func_graph, grads, name): return func_graph_module.func_graph_from_py_func( name, lambda: _grad_fn(func_graph, grads), [], {}, - func_graph=util.CondBranchFuncGraph(name, read_only_collections=False)) + func_graph=_CondGradFuncGraph(name, func_graph)) def _resolve_grad_inputs(cond_graph, grad_graph): @@ -360,28 +384,39 @@ def _separate_unique_inputs(true_inputs, false_inputs): return list(shared_inputs), list(true_only_inputs), list(false_only_inputs) -def _pad_params(true_graph, false_graph, true_params, false_params): - """Returns new param lists that have matching signatures. +def _make_intermediates_match(true_graph, false_graph, + true_optionals, false_optionals): + """Returns new optionals lists that have matching signatures. - This is done by mirroring each param list in the other using dummy params. - There is no merging of params. + This is done by mirroring each list in the other using none optionals. + There is no merging of like optionals. Args: true_graph: FuncGraph false_graph: FuncGraph - true_params: a list of Tensors from true_graph - false_params: a list of Tensors from false_graph + true_optionals: a list of optional Tensors from true_graph + false_optionals: a list of optional Tensors from false_graph Returns: A new list of Tensors in true_graph and a new list of Tensors in - false_graph. The two lists have the same number of Tensors, with matching - types and shapes across the lists. + false_graph. The two lists have the same number of Tensors, all of which + will be optionals of the same shape/type. """ - new_true_params = (true_params + - _create_dummy_params(true_graph, false_params)) - new_false_inputs = (_create_dummy_params(false_graph, true_params) - + false_params) - return new_true_params, new_false_inputs + new_true_optionals = (true_optionals + + _create_none_optionals(true_graph, false_optionals)) + new_false_optionals = (_create_none_optionals(false_graph, true_optionals) + + false_optionals) + return new_true_optionals, new_false_optionals + + +def _make_intermediates_match_xla(true_graph, false_graph, true_intermediates, + false_intermediates): + """Like _make_intermediates_match but for the XLA case.""" + new_true_intermediates = (true_intermediates + + _create_fakeparams(true_graph, false_intermediates)) + new_false_intermediates = (_create_fakeparams(false_graph, true_intermediates) + + false_intermediates) + return new_true_intermediates, new_false_intermediates def _make_inputs_match(true_graph, false_graph, true_inputs, false_inputs): @@ -416,11 +451,11 @@ def _make_inputs_match(true_graph, false_graph, true_inputs, false_inputs): true_graph.inputs = ( [true_input_to_param[t] for t in shared_inputs] + [true_input_to_param[t] for t in true_only_inputs] + - _create_dummy_params(true_graph, false_only_inputs)) + _create_dummy_inputs(true_graph, false_only_inputs)) false_graph.inputs = ( [false_input_to_param[t] for t in shared_inputs] + - _create_dummy_params(false_graph, true_only_inputs) + + _create_dummy_inputs(false_graph, true_only_inputs) + [false_input_to_param[t] for t in false_only_inputs]) # Rewrite the FuncGraphs' state to reflect the new inputs. @@ -432,7 +467,12 @@ def _make_inputs_match(true_graph, false_graph, true_inputs, false_inputs): return new_inputs -def _create_dummy_params(func_graph, template_tensors): +def _wrap_intermediates(func_graph, intermediates): + with func_graph.as_default(): + return [gen_dataset_ops.optional_from_value([t]) for t in intermediates] + + +def _create_dummy_inputs(func_graph, template_tensors): """Creates tensors in func_graph to represent template_tensors. Args: @@ -442,6 +482,27 @@ def _create_dummy_params(func_graph, template_tensors): Returns: A list of tensors in func_graph. """ + with func_graph.as_default(): + return [array_ops.placeholder(t.dtype, shape=t.shape) + for t in template_tensors] + + +def _create_none_optionals(func_graph, template_tensors): + """Creates none optionals in func_graph to represent template_tensors. + + Args: + func_graph: FuncGraph. + template_tensors: a list of tensors in func_graph. + + Returns: + A list of tensors in func_graph. + """ + with func_graph.as_default(): + return [gen_dataset_ops.optional_none() for _ in template_tensors] + + +def _create_fakeparams(func_graph, template_tensors): + """Create FakeParams for the XLA case.""" with func_graph.as_default(): return [gen_functional_ops.fake_param(dtype=t.dtype, shape=t.shape) for t in template_tensors] @@ -474,3 +535,38 @@ def _get_output_shapes(true_graph_outputs, false_graph_outputs): for t_out, f_out in zip(true_graph_outputs, false_graph_outputs) ] return output_shapes + + +class _CondGradFuncGraph(util.CondBranchFuncGraph): + """FuncGraph for the gradient function of the branch of an If op. + + Handles unwrapping optional intermediate values that are captured by the + gradient computation. + """ + + def __init__(self, name, forward_graph): + super(_CondGradFuncGraph, self).__init__(name, read_only_collections=False) + self._forward_graph = forward_graph + + def _capture_helper(self, tensor, name): + if (tensor.graph is not self._forward_graph or + tensor in self._forward_graph.inputs or + tensor in self._forward_graph.outputs): + return super(_CondGradFuncGraph, self)._capture_helper(tensor, name) + + # 'tensor' is an intermediate in the forward graph. We find the corresonding + # optional tensor, which is output from the If op, and capture it as + # normal. We then unwrap the captured optional value to get the raw + # intermediate value. + for consumer in tensor.consumers(): + if (consumer.type == "OptionalFromValue" + and consumer.outputs[0] in self._forward_graph.outputs): + optional = consumer.outputs[0] + captured_optional = super(_CondGradFuncGraph, self)._capture_helper( + optional, name) + return gen_dataset_ops.optional_get_value( + captured_optional, [tensor.dtype], [tensor.shape])[0] + raise ValueError( + "Couldn't find OptionalFromValue consumer for tensor '%s'.\n" + "This is an internal bug, please report at " + "https://github.com/tensorflow/tensorflow/issues." % tensor.name) diff --git a/tensorflow/python/ops/control_flow_util.py b/tensorflow/python/ops/control_flow_util.py index 72c074ed1a..cb628f4aa6 100644 --- a/tensorflow/python/ops/control_flow_util.py +++ b/tensorflow/python/ops/control_flow_util.py @@ -38,6 +38,11 @@ def IsInXLAContext(op): return GetContainingXLAContext(ctxt) is not None +def InXlaContext(graph): + ctxt = graph._get_control_flow_context() # pylint: disable=protected-access + return GetContainingXLAContext(ctxt) is not None + + def IsInWhileLoop(op): ctxt = op._get_control_flow_context() # pylint: disable=protected-access return GetContainingWhileContext(ctxt) is not None diff --git a/tensorflow/python/ops/gradients_impl.py b/tensorflow/python/ops/gradients_impl.py index c8f5cb8349..8cc4d926c7 100644 --- a/tensorflow/python/ops/gradients_impl.py +++ b/tensorflow/python/ops/gradients_impl.py @@ -49,6 +49,7 @@ from tensorflow.python.ops import logging_ops # pylint: disable=unused-import from tensorflow.python.ops import manip_grad # pylint: disable=unused-import from tensorflow.python.ops import math_grad # pylint: disable=unused-import from tensorflow.python.ops import math_ops +from tensorflow.python.ops import optional_grad # pylint: disable=unused-import from tensorflow.python.ops import random_grad # pylint: disable=unused-import from tensorflow.python.ops import resource_variable_ops from tensorflow.python.ops import tensor_array_ops diff --git a/tensorflow/python/ops/optional_grad.py b/tensorflow/python/ops/optional_grad.py new file mode 100644 index 0000000000..0d1eae3cda --- /dev/null +++ b/tensorflow/python/ops/optional_grad.py @@ -0,0 +1,33 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Gradient functions for optional ops.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.ops import gen_dataset_ops + + +@ops.RegisterGradient("OptionalFromValue") +def _OptionalFromValueGrad(op, grad): + return gen_dataset_ops.optional_get_value( + grad, [t.dtype for t in op.inputs], [t.shape for t in op.inputs]) + + +@ops.RegisterGradient("OptionalGetValue") +def _OptionalGetValueGrad(unused_op, *grads): + return gen_dataset_ops.optional_from_value(grads) -- GitLab From 5d14dbd1c35783d072756643c905fef5d7ac28fb Mon Sep 17 00:00:00 2001 From: Sourabh Bajaj Date: Wed, 28 Nov 2018 17:10:02 -0800 Subject: [PATCH 501/672] Fix method name PiperOrigin-RevId: 223263254 --- tensorflow/contrib/distribute/python/keras_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/contrib/distribute/python/keras_test.py b/tensorflow/contrib/distribute/python/keras_test.py index 07027bde8a..6a006cc85f 100644 --- a/tensorflow/contrib/distribute/python/keras_test.py +++ b/tensorflow/contrib/distribute/python/keras_test.py @@ -1263,7 +1263,7 @@ class TestDistributionStrategyCorrectness(test.TestCase, model.add(keras.layers.Dense(1)) initial_weights = model.get_weights() - def fit_and_predict(with_distribution=None): + def fit_eval_and_predict(with_distribution=None): # We have initialized the model to the same weight for the distribution # and non-distribution run. model.set_weights(initial_weights) @@ -1283,10 +1283,10 @@ class TestDistributionStrategyCorrectness(test.TestCase, return weights, eval_result, predict_result - wts_with_ds, eval_with_ds, predict_with_ds = fit_and_predict( + wts_with_ds, eval_with_ds, predict_with_ds = fit_eval_and_predict( with_distribution=distribution) - wts_without_ds, eval_without_ds, predict_without_ds = fit_and_predict( - with_distribution=None) + wts_without_ds, eval_without_ds, predict_without_ds = ( + fit_eval_and_predict(with_distribution=None)) # Verify that the weights, eval results, predict outputs are the same # within some limits of tolerance. -- GitLab From 0be39e80a210919c1dd3223b4b0ac23380372940 Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Thu, 29 Nov 2018 09:15:50 +0800 Subject: [PATCH 502/672] Update tensorflow/core/graph/mkl_layout_pass.cc Use "DCHECK()" instead of "CHECK_EQ". Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index bac434886f..e6c24ab8d4 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -949,7 +949,7 @@ class MklLayoutRewritePass : public GraphOptimizationPass { e->dst_input() == kPermTensorIndex) { // we find the "perm" node, now try to retrieve its value. const TensorProto* proto = nullptr; - CHECK_EQ(GetNodeAttr(perm_node->def(), "value", &proto).ok(), true); + DCHECK(GetNodeAttr(perm_node->def(), "value", &proto).ok()); DataType type; GetNodeAttr(perm_node->def(), "dtype", &type); -- GitLab From 41d41c9730e87e2b98ae24a447f233466d7995af Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Thu, 29 Nov 2018 09:16:49 +0800 Subject: [PATCH 503/672] Update tensorflow/core/graph/mkl_layout_pass.cc Use "DCHECK()" instead of "CHECK_EQ". Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index e6c24ab8d4..55c337cbea 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2694,7 +2694,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( // Create node. Node* new_node; TF_CHECK_OK(nb.Finalize(&**g, &new_node)); - CHECK_NOTNULL(new_node); + DCHECK(new_node); // Fill outputs. for (const Edge* e : transpose_to_nchw->out_edges()) { -- GitLab From d95a04c30511992befcd66dc12f3227fa65891e4 Mon Sep 17 00:00:00 2001 From: Penporn Koanantakool <38085909+penpornk@users.noreply.github.com> Date: Thu, 29 Nov 2018 09:17:09 +0800 Subject: [PATCH 504/672] Update tensorflow/core/graph/mkl_layout_pass.cc Use "DCHECK()" instead of "CHECK_EQ". Co-Authored-By: wenxizhu --- tensorflow/core/graph/mkl_layout_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/core/graph/mkl_layout_pass.cc b/tensorflow/core/graph/mkl_layout_pass.cc index 55c337cbea..edea296c3b 100644 --- a/tensorflow/core/graph/mkl_layout_pass.cc +++ b/tensorflow/core/graph/mkl_layout_pass.cc @@ -2700,7 +2700,7 @@ Status MklLayoutRewritePass::FuseTransposeMklOpTranspose( for (const Edge* e : transpose_to_nchw->out_edges()) { if (!e->IsControlEdge()) { const int kTransposeWithMklOpOutputSlot = 0; - CHECK_NOTNULL((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, + DCHECK((*g)->AddEdge(new_node, kTransposeWithMklOpOutputSlot, e->dst(), e->dst_input())); } } -- GitLab From 7dbc68791c6d5384e5807fefdeee79ccccc4008b Mon Sep 17 00:00:00 2001 From: Mahmoud Abuzaina Date: Wed, 28 Nov 2018 17:17:33 -0800 Subject: [PATCH 505/672] Ran newer version of clang-format --- tensorflow/core/kernels/mkl_avgpooling_op.cc | 51 +++++++----------- tensorflow/core/kernels/mkl_maxpooling_op.cc | 52 ++++++++----------- .../core/kernels/mkl_pooling_ops_common.cc | 19 +++---- .../core/kernels/mkl_pooling_ops_common.h | 15 +++--- .../kernels/mkl_quantized_pooling_ops_test.cc | 14 ++--- 5 files changed, 64 insertions(+), 87 deletions(-) diff --git a/tensorflow/core/kernels/mkl_avgpooling_op.cc b/tensorflow/core/kernels/mkl_avgpooling_op.cc index a5dc317969..939cbd6f96 100644 --- a/tensorflow/core/kernels/mkl_avgpooling_op.cc +++ b/tensorflow/core/kernels/mkl_avgpooling_op.cc @@ -53,19 +53,16 @@ class MklAvgPoolingOp : public OpKernel { OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument( - "Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument( - "Sliding window stride field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window stride field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, - errors::Unimplemented( - "Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented("Pooling is not yet supported on the " + "batch dimension.")); } void Compute(OpKernelContext* context) override { @@ -231,19 +228,16 @@ class MklAvgPoolingGradOp : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument( - "Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument( - "Sliding window strides field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window strides field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, - errors::Unimplemented( - "Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented("Pooling is not yet supported on the " + "batch dimension.")); } void Compute(OpKernelContext* context) override { @@ -365,9 +359,8 @@ class MklAvgPoolingGradOp : public OpKernel { // elements. OP_REQUIRES(context, tensor_in_shape.dims() == 1 && tensor_in_shape.NumElements() == 4, - errors::InvalidArgument( - "original input shape must be " - "1-dimensional and 4 elements")); + errors::InvalidArgument("original input shape must be " + "1-dimensional and 4 elements")); // For avgpooling, out_backprop should have 4 dimensions. OP_REQUIRES( @@ -557,8 +550,7 @@ class MklAvgPoolingOp : public MklPoolingForwardOpBase { output_min->flat()(0) = min_input; output_max->flat()(0) = max_input; } - } - catch (mkldnn::error& e) { + } catch (mkldnn::error& e) { string error_msg = "Status: " + std::to_string(e.status) + ", message: " + string(e.message) + ", in file " + string(__FILE__) + ":" + std::to_string(__LINE__); @@ -660,8 +652,7 @@ class MklAvgPoolingGradOp : public MklPoolingBackwardOpBase { // execute pooling op pooling_bwd->Execute(diff_dst_data, diff_src_data); - } - catch (mkldnn::error& e) { + } catch (mkldnn::error& e) { string error_msg = "Status: " + std::to_string(e.status) + ", message: " + string(e.message) + ", in file " + string(__FILE__) + ":" + std::to_string(__LINE__); @@ -685,15 +676,13 @@ class MklAvgPoolingGradOp : public MklPoolingBackwardOpBase { if (!original_input_mkl_shape.IsMklTensor()) { OP_REQUIRES(context, tensor_in_shape.dims() == 1 && tensor_in_shape.NumElements() == 4, - errors::InvalidArgument( - "original input shape must be " - "1-dimensional and 4 elements")); + errors::InvalidArgument("original input shape must be " + "1-dimensional and 4 elements")); } else { OP_REQUIRES(context, original_input_mkl_shape.GetDimension() == 1 && original_input_mkl_shape.DimSize(0) == 4, - errors::InvalidArgument( - "original input shape must be " - "1-dimensional and 4 elements")); + errors::InvalidArgument("original input shape must be " + "1-dimensional and 4 elements")); } if (!input_gradient_mkl_shape.IsMklTensor()) { diff --git a/tensorflow/core/kernels/mkl_maxpooling_op.cc b/tensorflow/core/kernels/mkl_maxpooling_op.cc index cd72530bce..0697251c7d 100644 --- a/tensorflow/core/kernels/mkl_maxpooling_op.cc +++ b/tensorflow/core/kernels/mkl_maxpooling_op.cc @@ -54,19 +54,16 @@ class MklMaxPoolingOp : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument( - "Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument( - "Sliding window stride field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window stride field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, - errors::Unimplemented( - "Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented("Pooling is not yet supported on the " + "batch dimension.")); workspace_enabled_ = false; // We may not get this attribute for this node if it does not go through @@ -216,14 +213,12 @@ class MklMaxPoolingGradOp : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &ksize_)); OP_REQUIRES(context, ksize_.size() == 4, - errors::InvalidArgument( - "Sliding window ksize field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window ksize field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_)); OP_REQUIRES(context, stride_.size() == 4, - errors::InvalidArgument( - "Sliding window strides field must " - "specify 4 dimensions")); + errors::InvalidArgument("Sliding window strides field must " + "specify 4 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); OP_REQUIRES(context, ksize_[0] == 1 && stride_[0] == 1, errors::Unimplemented( @@ -641,8 +636,7 @@ class MklMaxPoolingOp : public MklPoolingForwardOpBase { // execute pooling op pooling_fwd->Execute(src_data, dst_data, ws_data); } - } - catch (mkldnn::error& e) { + } catch (mkldnn::error& e) { string error_msg = "Status: " + std::to_string(e.status) + ", message: " + string(e.message) + ", in file " + string(__FILE__) + ":" + std::to_string(__LINE__); @@ -772,10 +766,11 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { if (ws_md.data.format != pooling_bwd->GetWorkspaceFormat()) { memory::dims ws_dims; ws_dims.assign(ws_md.data.dims, ws_md.data.dims + ws_md.data.ndims); - auto target_ws = memory::primitive_desc( - {{ws_dims}, pooling_bwd->GetWorkspaceDataType(), - pooling_bwd->GetWorkspaceFormat()}, - cpu_engine); + auto target_ws = + memory::primitive_desc({{ws_dims}, + pooling_bwd->GetWorkspaceDataType(), + pooling_bwd->GetWorkspaceFormat()}, + cpu_engine); workspace_dnn_data.SetUsrMem(ws_md, &workspace_tensor); workspace_dnn_data.CheckReorderToOpMem(target_ws); ws_data = workspace_dnn_data.GetOpMem().get_data_handle(); @@ -785,8 +780,7 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { // execute pooling pooling_bwd->Execute(diff_dst_data, diff_src_data, ws_data); - } - catch (mkldnn::error& e) { + } catch (mkldnn::error& e) { string error_msg = "Status:" + std::to_string(e.status) + ", message: " + string(e.message) + ". in file " + string(__FILE__) + ":" + std::to_string(__LINE__); @@ -857,12 +851,12 @@ class MklMaxPoolingGradOp : public MklPoolingBackwardOpBase { context, workspace_tensor.dims() == 1, errors::InvalidArgument("Workspace tensor must be 1-dimensional")); } else { - OP_REQUIRES(context, this->workspace_enabled_, - errors::Unimplemented( - "MKL-DNN Max Pooling does not " - "yet support the use case " - "where MaxPoolGrad is called without first" - " calling MaxPool.")); + OP_REQUIRES( + context, this->workspace_enabled_, + errors::Unimplemented("MKL-DNN Max Pooling does not " + "yet support the use case " + "where MaxPoolGrad is called without first" + " calling MaxPool.")); } } }; // MklMaxPoolingGradOp diff --git a/tensorflow/core/kernels/mkl_pooling_ops_common.cc b/tensorflow/core/kernels/mkl_pooling_ops_common.cc index cf3f0f1469..dc84d3941e 100644 --- a/tensorflow/core/kernels/mkl_pooling_ops_common.cc +++ b/tensorflow/core/kernels/mkl_pooling_ops_common.cc @@ -380,24 +380,21 @@ void MklPoolParameters::Init(OpKernelContext* context, // any padding, and expects the depth_window to equal the depth // stride (no overlapping). OP_REQUIRES(context, depth % depth_window == 0, - errors::Unimplemented( - "Depthwise max pooling requires the" - " depth window to evenly divide the" - " input depth")); + errors::Unimplemented("Depthwise max pooling requires the" + " depth window to evenly divide the" + " input depth")); OP_REQUIRES(context, depth_stride == depth_window, - errors::Unimplemented( - "Depthwise max pooling requires the" - " depth window to equal the depth" - " stride")); + errors::Unimplemented("Depthwise max pooling requires the" + " depth window to equal the depth" + " stride")); // The current version of depthwise max is only implemented on CPU. OP_REQUIRES(context, (DeviceType(static_cast(context->device()) ->attributes() .device_type()) == DeviceType(DEVICE_CPU)), - errors::Unimplemented( - "Depthwise max pooling is currently " - "only implemented for CPU devices.")); + errors::Unimplemented("Depthwise max pooling is currently " + "only implemented for CPU devices.")); out_depth = depth / depth_window; } diff --git a/tensorflow/core/kernels/mkl_pooling_ops_common.h b/tensorflow/core/kernels/mkl_pooling_ops_common.h index d214c39484..8a60c3be91 100644 --- a/tensorflow/core/kernels/mkl_pooling_ops_common.h +++ b/tensorflow/core/kernels/mkl_pooling_ops_common.h @@ -459,19 +459,16 @@ class MklPoolingOpBase : public OpKernel { errors::InvalidArgument("Invalid data format")); OP_REQUIRES_OK(context, context->GetAttr("ksize", &this->ksize_)); OP_REQUIRES(context, this->ksize_.size() == 4 || this->ksize_.size() == 5, - errors::InvalidArgument( - "Sliding window ksize field must " - "specify 4 or 5 dimensions")); + errors::InvalidArgument("Sliding window ksize field must " + "specify 4 or 5 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("strides", &this->stride_)); OP_REQUIRES(context, this->stride_.size() == 4 || this->stride_.size() == 5, - errors::InvalidArgument( - "Sliding window strides field must " - "specify 4 or 5 dimensions")); + errors::InvalidArgument("Sliding window strides field must " + "specify 4 or 5 dimensions")); OP_REQUIRES_OK(context, context->GetAttr("padding", &this->padding_)); OP_REQUIRES(context, this->ksize_[0] == 1 && this->stride_[0] == 1, - errors::Unimplemented( - "Pooling is not yet supported on the " - "batch dimension.")); + errors::Unimplemented("Pooling is not yet supported on the " + "batch dimension.")); bool is_pool2d = (this->ksize_.size() == 4); this->data_format_mkldnn_ = is_pool2d ? TFDataFormatToMklDnnDataFormat(this->data_format_tf_) diff --git a/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc b/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc index 92fc1bfd07..7c1e32d6e3 100644 --- a/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc +++ b/tensorflow/core/kernels/mkl_quantized_pooling_ops_test.cc @@ -56,7 +56,7 @@ class ConvMklToTF : public OpsTestBase { output = *GetOutput(0); } - void TestBody() {}; + void TestBody(){}; }; class QuantizedPoolingTest : public OpsTestBase {}; @@ -95,9 +95,9 @@ TEST_F(QuantizedPoolingTest, SmallAveragePooling) { const int expected_height = input_height / stride; // The input pools we are averaging. (NHWC input, quantized.) - // 0th channel 1st channel - // 1 3 | 5 7 2 4 | 6 8 - // 9 11 | 13 15 10 12 | 14 16 + // 0th channel 1st channel + // 1 3 | 5 7 2 4 | 6 8 + // 9 11 | 13 15 10 12 | 14 16 // ------------- ------------- // 17 19 | 21 23 18 20 | 22 24 // 25 27 | 29 31 26 28 | 30 32 @@ -163,9 +163,9 @@ TEST_F(QuantizedPoolingTest, SmallMaxPooling) { const int expected_height = input_height / stride; // The max is computed from these input pools. (NHWC input, quantized.) - // 0th channel 1st channel - // 1 3 | 5 7 2 4 | 6 8 - // 9 11 | 13 15 10 12 | 14 16 + // 0th channel 1st channel + // 1 3 | 5 7 2 4 | 6 8 + // 9 11 | 13 15 10 12 | 14 16 // ------------- ------------- // 17 19 | 21 23 18 20 | 22 24 // 25 27 | 29 31 26 28 | 30 32 -- GitLab From 4a68eff3dd3141c75c7cd5e152a1555ef13ae739 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Wed, 28 Nov 2018 17:10:07 -0800 Subject: [PATCH 506/672] [XLA] Add methods to mutate the precision configuration of an HLO PiperOrigin-RevId: 223263273 --- tensorflow/compiler/xla/service/hlo_instruction.cc | 10 ++++++++++ tensorflow/compiler/xla/service/hlo_instruction.h | 1 + tensorflow/compiler/xla/service/hlo_instructions.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index 2bdb617731..36a7a5029b 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -3014,6 +3014,16 @@ const PrecisionConfig& HloInstruction::precision_config() const { LOG(FATAL) << "Unimplemented method."; } +PrecisionConfig* HloInstruction::mutable_precision_config() { + if (auto* convolution = DynCast(this)) { + return convolution->mutable_precision_config(); + } + if (auto* dot = DynCast(this)) { + return dot->mutable_precision_config(); + } + LOG(FATAL) << "Unimplemented method."; +} + HloModule* HloInstruction::GetModule() const { if (parent_) { return parent_->parent(); diff --git a/tensorflow/compiler/xla/service/hlo_instruction.h b/tensorflow/compiler/xla/service/hlo_instruction.h index 87748a771a..8569e86b83 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.h +++ b/tensorflow/compiler/xla/service/hlo_instruction.h @@ -1266,6 +1266,7 @@ class HloInstruction { // superior. // Precondition: opcode must be kConvolution or kDot. const PrecisionConfig& precision_config() const; + PrecisionConfig* mutable_precision_config(); // Sets the debug metadata for this instruction. void set_metadata(const OpMetadata& metadata) { metadata_ = metadata; } diff --git a/tensorflow/compiler/xla/service/hlo_instructions.h b/tensorflow/compiler/xla/service/hlo_instructions.h index 0b07341cb9..e35c6e9150 100644 --- a/tensorflow/compiler/xla/service/hlo_instructions.h +++ b/tensorflow/compiler/xla/service/hlo_instructions.h @@ -955,6 +955,7 @@ class HloConvolutionInstruction : public HloInstruction { // information but it is presumed that the alternate lowering is strictly // superior. const PrecisionConfig& precision_config() const { return precision_config_; } + PrecisionConfig* mutable_precision_config() { return &precision_config_; } string ToCategory() const override; // Returns a serialized representation of this instruction. @@ -1326,6 +1327,7 @@ class HloDotInstruction : public HloInstruction { // information but it is presumed that the alternate lowering is strictly // superior. const PrecisionConfig& precision_config() const { return precision_config_; } + PrecisionConfig* mutable_precision_config() { return &precision_config_; } // Returns a serialized representation of this instruction. HloInstructionProto ToProto() const override; -- GitLab From 4ed87f979bb217155092b086450cf50d5363f4e2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 17:14:53 -0800 Subject: [PATCH 507/672] Automated rollback of commit 0c1eb8861624d6d17c797b70d25330711df5eb2f PiperOrigin-RevId: 223263979 --- .../core/common_runtime/function_test.cc | 4 +- tensorflow/core/graph/edgeset.cc | 2 +- tensorflow/core/graph/edgeset.h | 20 ++++------ tensorflow/core/graph/graph_test.cc | 39 ------------------- tensorflow/core/graph/optimizer_cse_test.cc | 10 ++--- 5 files changed, 13 insertions(+), 62 deletions(-) diff --git a/tensorflow/core/common_runtime/function_test.cc b/tensorflow/core/common_runtime/function_test.cc index 3b4c976685..cab95cb596 100644 --- a/tensorflow/core/common_runtime/function_test.cc +++ b/tensorflow/core/common_runtime/function_test.cc @@ -1433,9 +1433,7 @@ TEST_F(FunctionLibraryRuntimeTest, Gradient_AddSum) { GraphDef actual; g->ToGraphDef(&actual); - // The optimizer is non-deterministic, so we only check that the number of - // nodes is not greater than expected. - EXPECT_LE(actual.node_size(), expected.node_size()); + TF_EXPECT_GRAPH_EQ(expected, actual); } } diff --git a/tensorflow/core/graph/edgeset.cc b/tensorflow/core/graph/edgeset.cc index 02315a3e27..2e0c671461 100644 --- a/tensorflow/core/graph/edgeset.cc +++ b/tensorflow/core/graph/edgeset.cc @@ -37,7 +37,7 @@ std::pair EdgeSet::insert(value_type value) { } } // array is full. convert to set. - s = new gtl::FlatSet; + s = new std::set; for (int i = 0; i < kInline; i++) { s->insert(static_cast(ptrs_[i])); } diff --git a/tensorflow/core/graph/edgeset.h b/tensorflow/core/graph/edgeset.h index 2776c8491c..0a1ee5a666 100644 --- a/tensorflow/core/graph/edgeset.h +++ b/tensorflow/core/graph/edgeset.h @@ -17,18 +17,17 @@ limitations under the License. #define TENSORFLOW_GRAPH_EDGESET_H_ #include - -#include "tensorflow/core/lib/gtl/flatset.h" -#include "tensorflow/core/platform/logging.h" +#include #include "tensorflow/core/platform/macros.h" #include "tensorflow/core/platform/types.h" + +#include "tensorflow/core/platform/logging.h" namespace tensorflow { class Edge; // An unordered set of edges. Uses very little memory for small sets. -// Unlike gtl::FlatSet, EdgeSet does NOT allow mutations during -// iteration. +// Unlike std::set, EdgeSet does NOT allow mutations during iteration. class EdgeSet { public: EdgeSet(); @@ -55,15 +54,12 @@ class EdgeSet { private: // Up to kInline elements are stored directly in ptrs_ (nullptr means none). // If ptrs_[0] == this then ptrs_[1] points to a set. - // kInline must be >= 2, and is chosen such that ptrs_ fills a 64 byte - // cacheline. - static constexpr int kInline = 64 / sizeof(const void*); + static const int kInline = 4; // Must be >= 2. const void* ptrs_[kInline]; - gtl::FlatSet* get_set() const { + std::set* get_set() const { if (ptrs_[0] == this) { - return static_cast*>( - const_cast(ptrs_[1])); + return static_cast*>(const_cast(ptrs_[1])); } else { return nullptr; } @@ -103,7 +99,7 @@ class EdgeSet::const_iterator { friend class EdgeSet; void const* const* array_iter_ = nullptr; - typename gtl::FlatSet::const_iterator tree_iter_; + typename std::set::const_iterator tree_iter_; #ifdef NDEBUG inline void Init(const EdgeSet* e) {} diff --git a/tensorflow/core/graph/graph_test.cc b/tensorflow/core/graph/graph_test.cc index e7762fd414..333c32567f 100644 --- a/tensorflow/core/graph/graph_test.cc +++ b/tensorflow/core/graph/graph_test.cc @@ -799,44 +799,5 @@ BENCHMARK(BM_GraphCreation)->ArgPair(1 << 9, 16); BENCHMARK(BM_GraphCreation)->ArgPair(1 << 12, 16); BENCHMARK(BM_GraphCreation)->ArgPair(1 << 15, 16); -static void BM_ToGraphDef(int iters, int num_nodes, int num_edges_per_node) { - testing::StopTiming(); - const GraphDef graph_def = CreateGraphDef(num_nodes, num_edges_per_node); - const auto registry = OpRegistry::Global(); - GraphConstructorOptions opts; - // Warmup step. - Graph graph(registry); - TF_CHECK_OK(ConvertGraphDefToGraph(opts, graph_def, &graph)); - int64 sum = 0; - testing::StartTiming(); - for (int i = 0; i < iters; ++i) { - GraphDef graph_def; - graph.ToGraphDef(&graph_def); - sum += graph_def.node_size(); - } - VLOG(1) << sum; - testing::StopTiming(); -} -BENCHMARK(BM_ToGraphDef)->ArgPair(10, 2); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 6, 2); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 9, 2); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 12, 2); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 15, 2); -BENCHMARK(BM_ToGraphDef)->ArgPair(10, 4); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 6, 4); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 9, 4); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 12, 4); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 15, 4); -BENCHMARK(BM_ToGraphDef)->ArgPair(10, 8); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 6, 8); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 9, 8); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 12, 8); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 15, 8); -BENCHMARK(BM_ToGraphDef)->ArgPair(10, 16); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 6, 16); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 9, 16); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 12, 16); -BENCHMARK(BM_ToGraphDef)->ArgPair(1 << 15, 16); - } // namespace } // namespace tensorflow diff --git a/tensorflow/core/graph/optimizer_cse_test.cc b/tensorflow/core/graph/optimizer_cse_test.cc index 642298fa95..c1f93ce05a 100644 --- a/tensorflow/core/graph/optimizer_cse_test.cc +++ b/tensorflow/core/graph/optimizer_cse_test.cc @@ -337,13 +337,9 @@ TEST_F(OptimizerCSETest, Constant_Dedup) { EXPECT_EQ(OriginalGraph(), "n/_0(Const);n/_1(Const);n/_2(Const);n/_3(Const);" "n/_4(Const);n/_5(Const);n/_6(Const);n/_7(Const)|"); - std::vector nodes = str_util::Split(DoCSE(), ";|"); - std::set node_set(nodes.begin(), nodes.end()); - // Expect exactly one of each type of node to be retained after CSE. - EXPECT_EQ(node_set.count("n/_0(Const)") + node_set.count("n/_7(Const)"), 1); - EXPECT_EQ(node_set.count("n/_1(Const)") + node_set.count("n/_6(Const)"), 1); - EXPECT_EQ(node_set.count("n/_2(Const)") + node_set.count("n/_5(Const)"), 1); - EXPECT_EQ(node_set.count("n/_3(Const)") + node_set.count("n/_4(Const)"), 1); + // In theory, there are 2^4 possible correct output of CSE. In this + // test, it happens to eliminate the last 4 nodes. + EXPECT_EQ(DoCSE(), "n/_0(Const);n/_1(Const);n/_2(Const);n/_3(Const)|"); } static void BM_CSE(int iters, int op_nodes) { -- GitLab From d9540902ee49425262fc96146b981b005c77ee6c Mon Sep 17 00:00:00 2001 From: Amit Patankar Date: Wed, 28 Nov 2018 17:29:49 -0800 Subject: [PATCH 508/672] Filter gpu tags from Windows CPU. PiperOrigin-RevId: 223265780 --- tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh b/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh index 177ef390db..872072a056 100644 --- a/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh +++ b/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh @@ -126,8 +126,8 @@ N_JOBS="${NUMBER_OF_PROCESSORS}" # which will result testing system installed tensorflow bazel test --announce_rc --config=opt -k --test_output=errors \ --define=no_tensorflow_py_deps=true --test_lang_filters=py \ - --test_tag_filters=-no_pip,-no_windows,-no_oss \ - --build_tag_filters=-no_pip,-no_windows,-no_oss --build_tests_only \ + --test_tag_filters=-no_pip,-no_windows,-no_oss,-gpu \ + --build_tag_filters=-no_pip,-no_windows,-no_oss,-gpu --build_tests_only \ --test_size_filters=small,medium \ --jobs="${N_JOBS}" --test_timeout="300,450,1200,3600" \ --flaky_test_attempts=3 \ -- GitLab From b97727bc3c7a9216670f361b639a60ed516917e0 Mon Sep 17 00:00:00 2001 From: James Keeling Date: Wed, 28 Nov 2018 17:32:18 -0800 Subject: [PATCH 509/672] Use tf_stack instead of tf_inspect to get file and lineno in deprecation.py This is a no-op change, that prevents deprecation warnings triggering large numbers of posix.stat calls. In a test application, this prevents 64150 calls to lstat and 1499 calls to stat. PiperOrigin-RevId: 223266120 --- tensorflow/python/util/deprecation.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/tensorflow/python/util/deprecation.py b/tensorflow/python/util/deprecation.py index 4c68d1aaae..9aaf0c2de9 100644 --- a/tensorflow/python/util/deprecation.py +++ b/tensorflow/python/util/deprecation.py @@ -28,6 +28,7 @@ from tensorflow.python.util import is_in_graph_mode from tensorflow.python.util import tf_contextlib from tensorflow.python.util import tf_decorator from tensorflow.python.util import tf_inspect +from tensorflow.python.util import tf_stack # Allow deprecation warnings to be silenced temporarily with a context manager. @@ -98,21 +99,9 @@ def _validate_deprecation_args(date, instructions): def _call_location(outer=False): """Returns call location given level up from current call.""" - frame = tf_inspect.currentframe() - if frame: - # CPython internals are available, use them for performance. - # walk back two frames to get to deprecated function caller. - frame = frame.f_back - if frame.f_back: - frame = frame.f_back - if outer and frame.f_back: - frame = frame.f_back - return '%s:%d' % (frame.f_code.co_filename, frame.f_lineno) - else: - # Slow fallback path - stack = tf_inspect.stack(0) # 0 avoids generating unused context - entry = stack[3 if outer else 2] - return '%s:%d' % (entry[1], entry[2]) + stack = tf_stack.extract_stack() + frame = stack[-4 if outer else -3] + return '{filename}:{lineno}'.format(filename=frame[0], lineno=frame[1]) def _wrap_decorator(wrapped_function): -- GitLab From da2c2faca13ca71ebf5c3528b7a0e78321e5c544 Mon Sep 17 00:00:00 2001 From: Saurabh Saxena Date: Wed, 28 Nov 2018 17:37:41 -0800 Subject: [PATCH 510/672] Enable testCondAndTensorArray and testCondAndTensorArrayInDefun. PiperOrigin-RevId: 223266910 --- tensorflow/python/kernel_tests/cond_v2_test.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tensorflow/python/kernel_tests/cond_v2_test.py b/tensorflow/python/kernel_tests/cond_v2_test.py index 09e41ec8c6..4baa8b0212 100644 --- a/tensorflow/python/kernel_tests/cond_v2_test.py +++ b/tensorflow/python/kernel_tests/cond_v2_test.py @@ -719,10 +719,6 @@ class CondV2Test(test.TestCase): @test_util.enable_control_flow_v2 def testCondAndTensorArray(self): - if test_util.is_gpu_available(): - old_enable_tensor_array_v2 = tensor_array_ops.ENABLE_TENSOR_ARRAY_V2 - # TODO(b/119689663): Enable this. - tensor_array_ops.ENABLE_TENSOR_ARRAY_V2 = False x = math_ops.range(-5, 5) output = tensor_array_ops.TensorArray(dtype=dtypes.int32, size=x.shape[0]) @@ -744,15 +740,9 @@ class CondV2Test(test.TestCase): output_t = output.stack() self.assertAllEqual( self.evaluate(output_t), [-5, -4, -3, -2, -1, 0, 1, 4, 9, 16]) - if test_util.is_gpu_available(): - tensor_array_ops.ENABLE_TENSOR_ARRAY_V2 = old_enable_tensor_array_v2 @test_util.enable_control_flow_v2 def testCondAndTensorArrayInDefun(self): - if test_util.is_gpu_available(): - old_enable_tensor_array_v2 = tensor_array_ops.ENABLE_TENSOR_ARRAY_V2 - # TODO(b/119689663): Enable this. - tensor_array_ops.ENABLE_TENSOR_ARRAY_V2 = False @function.defun def f(): @@ -780,9 +770,6 @@ class CondV2Test(test.TestCase): self.assertAllEqual( self.evaluate(output_t), [-5, -4, -3, -2, -1, 0, 1, 4, 9, 16]) - if test_util.is_gpu_available(): - tensor_array_ops.ENABLE_TENSOR_ARRAY_V2 = old_enable_tensor_array_v2 - class CondV2CollectionTest(test.TestCase): -- GitLab From 99c20bf32e29a90dbb31f480360eb8881f0bd411 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 17:48:11 -0800 Subject: [PATCH 511/672] Register DataFormatVecPermute with label "host" on CPU to work around crash due to missing kernel. PiperOrigin-RevId: 223268202 --- tensorflow/core/kernels/data_format_ops.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tensorflow/core/kernels/data_format_ops.cc b/tensorflow/core/kernels/data_format_ops.cc index 23319e6d0c..27020cdabd 100644 --- a/tensorflow/core/kernels/data_format_ops.cc +++ b/tensorflow/core/kernels/data_format_ops.cc @@ -156,6 +156,16 @@ TF_CALL_int32(REGISTER_KERNEL); TF_CALL_int64(REGISTER_KERNEL); #undef REGISTER_KERNEL +#define REGISTER_KERNEL(T) \ + REGISTER_KERNEL_BUILDER(Name("DataFormatVecPermute") \ + .Device(DEVICE_CPU) \ + .Label("host") \ + .TypeConstraint("T"), \ + DataFormatVecPermuteOp); +TF_CALL_int32(REGISTER_KERNEL); +TF_CALL_int64(REGISTER_KERNEL); +#undef REGISTER_KERNEL + #if GOOGLE_CUDA // Forward declarations of the functor specializations for GPU. namespace functor { -- GitLab From 693c1ad4a94aec4dc2783096bfc204774927709e Mon Sep 17 00:00:00 2001 From: Katherine Wu Date: Wed, 28 Nov 2018 17:55:17 -0800 Subject: [PATCH 512/672] Save main_op and train_op in SignatureDefs instead of collections. PiperOrigin-RevId: 223268983 --- tensorflow/cc/saved_model/BUILD | 1 + tensorflow/cc/saved_model/constants.h | 9 +- tensorflow/cc/saved_model/loader.cc | 75 ++-- tensorflow/cc/saved_model/loader_test.cc | 14 + .../half_plus_two_v2/00000123/assets/foo.txt | 1 + .../half_plus_two_v2/00000123/saved_model.pb | Bin 0 -> 10774 bytes .../variables/variables.data-00000-of-00001 | Bin 0 -> 12 bytes .../00000123/variables/variables.index | Bin 0 -> 151 bytes .../python/saved_model/keras_saved_model.py | 8 +- .../saved_model/keras_saved_model_test.py | 21 +- tensorflow/python/saved_model/BUILD | 2 + tensorflow/python/saved_model/builder_impl.py | 206 ++++++----- tensorflow/python/saved_model/constants.py | 6 +- tensorflow/python/saved_model/loader_impl.py | 54 ++- tensorflow/python/saved_model/loader_test.py | 109 ++++-- .../python/saved_model/saved_model_test.py | 340 +++++++++--------- .../python/saved_model/signature_def_utils.py | 2 + .../saved_model/signature_def_utils_impl.py | 51 ++- .../saved_model/signature_def_utils_test.py | 18 + tensorflow/python/saved_model/utils_impl.py | 21 ++ .../golden/v2/tensorflow.saved_model.pbtxt | 4 - 21 files changed, 580 insertions(+), 362 deletions(-) create mode 100644 tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt create mode 100644 tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/saved_model.pb create mode 100644 tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.data-00000-of-00001 create mode 100644 tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.index diff --git a/tensorflow/cc/saved_model/BUILD b/tensorflow/cc/saved_model/BUILD index 3d3895c8fa..52345a376c 100644 --- a/tensorflow/cc/saved_model/BUILD +++ b/tensorflow/cc/saved_model/BUILD @@ -133,5 +133,6 @@ filegroup( "testdata/half_plus_two_pbtxt/**", "testdata/half_plus_two_main_op/**", "testdata/half_plus_two/**", + "testdata/half_plus_two_v2/**", ]), ) diff --git a/tensorflow/cc/saved_model/constants.h b/tensorflow/cc/saved_model/constants.h index 645a3f101d..6f00dc324b 100644 --- a/tensorflow/cc/saved_model/constants.h +++ b/tensorflow/cc/saved_model/constants.h @@ -33,10 +33,10 @@ constexpr char kSavedModelFilenamePb[] = "saved_model.pb"; /// SavedModel text format proto filename. constexpr char kSavedModelFilenamePbTxt[] = "saved_model.pbtxt"; -/// SavedModel legacy init op key. +/// SavedModel legacy init op collection key. Used in v1 SavedModels. constexpr char kSavedModelLegacyInitOpKey[] = "legacy_init_op"; -/// SavedModel main op key. +/// SavedModel main op collection key. Used in v1 SavedModels. constexpr char kSavedModelMainOpKey[] = "saved_model_main_op"; /// Directory in which to save the SavedModel variables. @@ -45,6 +45,11 @@ constexpr char kSavedModelVariablesDirectory[] = "variables"; /// SavedModel variables filename. constexpr char kSavedModelVariablesFilename[] = "variables"; +/// SavedModel SignatureDef keys for the initialization and train ops. Used in +/// V2 SavedModels. +constexpr char kSavedModelInitOpSignatureKey[] = "__saved_model_init_op"; +constexpr char kSavedModelTrainOpSignatureKey[] = "__saved_model_train_op"; + } // namespace tensorflow #endif // TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_ diff --git a/tensorflow/cc/saved_model/loader.cc b/tensorflow/cc/saved_model/loader.cc index ec116f68cf..85d3dd01fa 100644 --- a/tensorflow/cc/saved_model/loader.cc +++ b/tensorflow/cc/saved_model/loader.cc @@ -122,34 +122,54 @@ Status RunOnce(const RunOptions& run_options, return run_status; } -bool HasMainOp(const MetaGraphDef& meta_graph_def) { +// RunInitOp will return OK if the initialization op was run successfully. +// An empty init_op_name indicates that there are no init ops to run. +Status RunInitOp(const RunOptions& run_options, const string& export_dir, + const MetaGraphDef& meta_graph_def, + const std::vector& asset_file_defs, + Session* session, const string& init_op_name) { + if (!init_op_name.empty()) { + LOG(INFO) << "Running initialization op on SavedModel bundle."; + std::vector> inputs; + AddAssetsTensorsToInputs(export_dir, asset_file_defs, &inputs); + RunMetadata run_metadata; + return RunOnce(run_options, inputs, {}, {init_op_name}, + nullptr /* outputs */, &run_metadata, session); + } + return Status::OK(); +} + +// A SavedModel may store the name of the initialization op to run in the +// in the SignatureDef (v2) or a collection (v1). If an init_op collection +// exists, then the collection must contain exactly one op. +Status GetInitOp(const string& export_dir, const MetaGraphDef& meta_graph_def, + string* init_op_name) { + const auto& sig_def_map = meta_graph_def.signature_def(); + const auto& init_op_sig_it = + meta_graph_def.signature_def().find(kSavedModelInitOpSignatureKey); + if (init_op_sig_it != sig_def_map.end()) { + *init_op_name = init_op_sig_it->second.outputs() + .find(kSavedModelInitOpSignatureKey) + ->second.name(); + return Status::OK(); + } + const auto& collection_def_map = meta_graph_def.collection_def(); + string init_op_collection_key; if (collection_def_map.find(kSavedModelMainOpKey) != collection_def_map.end()) { - return true; + init_op_collection_key = kSavedModelMainOpKey; + } else { + init_op_collection_key = kSavedModelLegacyInitOpKey; } - return false; -} -Status RunMainOp(const RunOptions& run_options, const string& export_dir, - const MetaGraphDef& meta_graph_def, - const std::vector& asset_file_defs, - Session* session, const string& main_op_key) { - LOG(INFO) << "Running MainOp with key " << main_op_key - << " on SavedModel bundle."; - const auto& collection_def_map = meta_graph_def.collection_def(); - const auto main_op_it = collection_def_map.find(main_op_key); - if (main_op_it != collection_def_map.end()) { - if (main_op_it->second.node_list().value_size() != 1) { + const auto init_op_it = collection_def_map.find(init_op_collection_key); + if (init_op_it != collection_def_map.end()) { + if (init_op_it->second.node_list().value_size() != 1) { return errors::FailedPrecondition( strings::StrCat("Expected exactly one main op in : ", export_dir)); } - std::vector> inputs; - AddAssetsTensorsToInputs(export_dir, asset_file_defs, &inputs); - RunMetadata run_metadata; - const StringPiece main_op_name = main_op_it->second.node_list().value(0); - return RunOnce(run_options, inputs, {}, {string(main_op_name)}, - nullptr /* outputs */, &run_metadata, session); + *init_op_name = init_op_it->second.node_list().value(0); } return Status::OK(); } @@ -236,15 +256,12 @@ Status LoadSavedModelInternal(const SessionOptions& session_options, bundle->meta_graph_def.saver_def().restore_op_name(), bundle->meta_graph_def.saver_def().filename_tensor_name(), asset_file_defs, bundle->session.get())); - if (HasMainOp(bundle->meta_graph_def)) { - TF_RETURN_IF_ERROR(RunMainOp(run_options, export_dir, - bundle->meta_graph_def, asset_file_defs, - bundle->session.get(), kSavedModelMainOpKey)); - } else { - TF_RETURN_IF_ERROR(RunMainOp( - run_options, export_dir, bundle->meta_graph_def, asset_file_defs, - bundle->session.get(), kSavedModelLegacyInitOpKey)); - } + string init_op_name; + TF_RETURN_IF_ERROR( + GetInitOp(export_dir, bundle->meta_graph_def, &init_op_name)); + TF_RETURN_IF_ERROR(RunInitOp(run_options, export_dir, bundle->meta_graph_def, + asset_file_defs, bundle->session.get(), + init_op_name)); return Status::OK(); } diff --git a/tensorflow/cc/saved_model/loader_test.cc b/tensorflow/cc/saved_model/loader_test.cc index 72b8bc1871..597e42bb65 100644 --- a/tensorflow/cc/saved_model/loader_test.cc +++ b/tensorflow/cc/saved_model/loader_test.cc @@ -36,6 +36,8 @@ constexpr char kTestDataMainOp[] = "cc/saved_model/testdata/half_plus_two_main_op/00000123"; constexpr char kTestDataSharded[] = "cc/saved_model/testdata/half_plus_two/00000123"; +constexpr char kTestDataInitOpV2[] = + "cc/saved_model/testdata/half_plus_two_v2/00000123"; class LoaderTest : public ::testing::Test { protected: @@ -227,5 +229,17 @@ TEST_F(LoaderTest, MaybeSavedModelDirectory) { EXPECT_FALSE(MaybeSavedModelDirectory(invalid_export_dir)); } +TEST_F(LoaderTest, SavedModelInitOpV2Format) { + SavedModelBundle bundle; + SessionOptions session_options; + RunOptions run_options; + + const string export_dir = + io::JoinPath(testing::TensorFlowSrcRoot(), kTestDataInitOpV2); + TF_ASSERT_OK(LoadSavedModel(session_options, run_options, export_dir, + {kSavedModelTagServe}, &bundle)); + CheckSavedModelBundle(export_dir, bundle); +} + } // namespace } // namespace tensorflow diff --git a/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt new file mode 100644 index 0000000000..f9ff036688 --- /dev/null +++ b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt @@ -0,0 +1 @@ +asset-file-contents \ No newline at end of file diff --git a/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/saved_model.pb b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/saved_model.pb new file mode 100644 index 0000000000000000000000000000000000000000..a10bbf8fb6bca0fcee6414b2927d2f706de85ebc GIT binary patch literal 10774 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" } - member { - name: "MAIN_OP_KEY" - mtype: "" - } member { name: "PREDICT_INPUTS" mtype: "" -- GitLab From 1a7e7e3009ae0f66c3338d9099c263c58ce77139 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 17:57:39 -0800 Subject: [PATCH 513/672] nn.erosion2d changes for TF 2.0 API * `kernel` is renamed to `filters` * `rates` is renamed to dilations * `data_format` is introduced, must be set to NCHW or an error is raised PiperOrigin-RevId: 223269242 --- tensorflow/python/ops/nn_ops.py | 71 ++++++++++++++++++- .../tools/api/golden/v2/tensorflow.nn.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 6 ++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 2ffe381216..74e88b7653 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -3597,7 +3597,7 @@ def _calc_dilation2d_flops(graph, node): return ops.OpStats("flops", (output_count * filter_height * filter_width * 2)) -@tf_export("nn.erosion2d") +@tf_export(v1=["nn.erosion2d"]) def erosion2d(value, kernel, strides, rates, padding, name=None): """Computes the grayscale erosion of 4-D `value` and 3-D `kernel` tensors. @@ -3656,6 +3656,75 @@ def erosion2d(value, kernel, strides, rates, padding, name=None): name=name)) +@tf_export("nn.erosion2d", v1=[]) +def erosion2d_v2(value, + filters, + strides, + padding, + data_format, + dilations, + name=None): + """Computes the grayscale erosion of 4-D `value` and 3-D `filters` tensors. + + The `value` tensor has shape `[batch, in_height, in_width, depth]` and the + `filters` tensor has shape `[filters_height, filters_width, depth]`, i.e., + each input channel is processed independently of the others with its own + structuring function. The `output` tensor has shape + `[batch, out_height, out_width, depth]`. The spatial dimensions of the + output tensor depend on the `padding` algorithm. We currently only support the + default "NHWC" `data_format`. + + In detail, the grayscale morphological 2-D erosion is given by: + + output[b, y, x, c] = + min_{dy, dx} value[b, + strides[1] * y - dilations[1] * dy, + strides[2] * x - dilations[2] * dx, + c] - + filters[dy, dx, c] + + Duality: The erosion of `value` by the `filters` is equal to the negation of + the dilation of `-value` by the reflected `filters`. + + Args: + value: A `Tensor`. 4-D with shape `[batch, in_height, in_width, depth]`. + filters: A `Tensor`. Must have the same type as `value`. + 3-D with shape `[filters_height, filters_width, depth]`. + strides: A list of `ints` that has length `>= 4`. + 1-D of length 4. The stride of the sliding window for each dimension of + the input tensor. Must be: `[1, stride_height, stride_width, 1]`. + padding: A `string` from: `"SAME", "VALID"`. + The type of padding algorithm to use. + data_format: A `string`, only `"NHWC"` is currently supported. + dilations: A list of `ints` that has length `>= 4`. + 1-D of length 4. The input stride for atrous morphological dilation. + Must be: `[1, rate_height, rate_width, 1]`. + name: A name for the operation (optional). If not specified "erosion2d" + is used. + + Returns: + A `Tensor`. Has the same type as `value`. + 4-D with shape `[batch, out_height, out_width, depth]`. + + Raises: + ValueError: If the `value` depth does not match `filters`' shape, or if + padding is other than `'VALID'` or `'SAME'`. + """ + if data_format != "NHWC": + raise ValueError("Data formats other than NHWC are not yet supported") + + with ops.name_scope(name, "erosion2d", [value, filters]) as name: + # Reduce erosion to dilation by duality. + return math_ops.negative( + gen_nn_ops.dilation2d( + input=math_ops.negative(value), + filter=array_ops.reverse_v2(filters, [0, 1]), + strides=strides, + rates=dilations, + padding=padding, + name=name)) + + @tf_export("math.in_top_k", "nn.in_top_k") def in_top_k(predictions, targets, k, name=None): r"""Says whether the targets are in the top `K` predictions. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt index b4d0f95bc3..4779448760 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.nn.pbtxt @@ -142,7 +142,7 @@ tf_module { } member_method { name: "erosion2d" - argspec: "args=[\'value\', \'kernel\', \'strides\', \'rates\', \'padding\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " + argspec: "args=[\'value\', \'filters\', \'strides\', \'padding\', \'data_format\', \'dilations\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } member_method { name: "fixed_unigram_candidate_sampler" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 9e010cd7b9..d75e52bd0d 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -64,6 +64,10 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "keep_dims": "keepdims", "reduction_indices": "axis", }, + "tf.nn.erosion2d": { + "kernel": "filters", + "rates": "dilations", + }, "tf.math.l2_normalize": { "dim": "axis", }, @@ -699,6 +703,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.nn.conv2d_backprop_input": "WARNING: use_cudnn_on_gpu argument has been removed and \"filter\" " "was renamed to \"filters\"", + "tf.nn.erosion2d": + "WARNING: now requires a data_format argument", "tf.zeros_like": tf_01s_like_no_optimize_comment, "tf.ones_like": tf_01s_like_no_optimize_comment, } -- GitLab From f7b3f57f11c4a4661a456e484310b3e131ddb7f1 Mon Sep 17 00:00:00 2001 From: Anna R Date: Wed, 28 Nov 2018 18:02:09 -0800 Subject: [PATCH 514/672] Internal change. PiperOrigin-RevId: 223269764 --- .../ci_build/windows/cpu/pip/build_tf_windows.sh | 12 +++++++++--- .../ci_build/windows/gpu/pip/build_tf_windows.sh | 11 +++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh b/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh index 872072a056..32438260b4 100644 --- a/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh +++ b/tensorflow/tools/ci_build/windows/cpu/pip/build_tf_windows.sh @@ -58,6 +58,7 @@ PY_TEST_DIR="py_test_dir" SKIP_TEST=0 RELEASE_BUILD=0 TEST_TARGET="//${PY_TEST_DIR}/tensorflow/python/..." +EXTRA_BUILD_FLAGS=${ADDITIONAL_BUILD_ARGS:-} # --skip_test Skip running tests # --enable_remote_cache Add options to enable remote cache for build and test @@ -88,7 +89,11 @@ fi if [[ "$TF_NIGHTLY" == 1 ]]; then python tensorflow/tools/ci_build/update_version.py --nightly - EXTRA_PIP_FLAG="--nightly_flag" + if [ -z ${EXTRA_PIP_FLAGS} ]; then + EXTRA_PIP_FLAGS="--nightly_flag" + else + EXTRA_PIP_FLAGS="${EXTRA_PIP_FLAGS} --nightly_flag" + fi fi # Enable short object file path to avoid long path issue on Windows. @@ -100,7 +105,8 @@ fi run_configure_for_cpu_build -bazel build --announce_rc --config=opt tensorflow/tools/pip_package:build_pip_package || exit $? +bazel build --announce_rc --config=opt ${EXTRA_BUILD_FLAGS} \ + tensorflow/tools/pip_package:build_pip_package || exit $? if [[ "$SKIP_TEST" == 1 ]]; then exit 0 @@ -109,7 +115,7 @@ fi # Create a python test directory to avoid package name conflict create_python_test_dir "${PY_TEST_DIR}" -./bazel-bin/tensorflow/tools/pip_package/build_pip_package "$PWD/${PY_TEST_DIR}" "${EXTRA_PIP_FLAG}" +./bazel-bin/tensorflow/tools/pip_package/build_pip_package "$PWD/${PY_TEST_DIR}" "${EXTRA_PIP_FLAGS}" if [[ "$TF_NIGHTLY" == 1 ]]; then exit 0 diff --git a/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh b/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh index 6178d7794d..6a701fc5a1 100644 --- a/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh +++ b/tensorflow/tools/ci_build/windows/gpu/pip/build_tf_windows.sh @@ -58,6 +58,7 @@ PY_TEST_DIR="py_test_dir" SKIP_TEST=0 RELEASE_BUILD=0 TEST_TARGET="//${PY_TEST_DIR}/tensorflow/python/..." +EXTRA_BUILD_FLAGS=${ADDITIONAL_BUILD_ARGS:-} # --skip_test Skip running tests # --enable_remote_cache Add options to enable remote cache for build and test @@ -88,7 +89,11 @@ fi if [[ "$TF_NIGHTLY" == 1 ]]; then python tensorflow/tools/ci_build/update_version.py --nightly - EXTRA_PIP_FLAG="--nightly_flag" + if [ -z ${EXTRA_PIP_FLAGS} ]; then + EXTRA_PIP_FLAGS="--nightly_flag" + else + EXTRA_PIP_FLAGS="${EXTRA_PIP_FLAGS} --nightly_flag" + fi fi # Enable short object file path to avoid long path issue on Windows. @@ -104,6 +109,7 @@ fi run_configure_for_gpu_build bazel build --announce_rc --config=opt --define=no_tensorflow_py_deps=true \ + ${EXTRA_BUILD_FLAGS} \ tensorflow/tools/pip_package:build_pip_package || exit $? if [[ "$SKIP_TEST" == 1 ]]; then @@ -113,7 +119,8 @@ fi # Create a python test directory to avoid package name conflict create_python_test_dir "${PY_TEST_DIR}" -./bazel-bin/tensorflow/tools/pip_package/build_pip_package "$PWD/${PY_TEST_DIR}" --gpu "${EXTRA_PIP_FLAG}" +./bazel-bin/tensorflow/tools/pip_package/build_pip_package "$PWD/${PY_TEST_DIR}" \ + --gpu "${EXTRA_PIP_FLAGS}" if [[ "$TF_NIGHTLY" == 1 ]]; then exit 0 -- GitLab From e94b2367284b35a20fd5ab5d3d78858a629c74da Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Wed, 28 Nov 2018 18:07:18 -0800 Subject: [PATCH 515/672] Make some feature_column_v2 tests work without sessions This allows the tests to run in v2 mode although quite a few use graph mode when not necessary. This reduces the number of failing tests from 90 to 43. PiperOrigin-RevId: 223270643 --- .../feature_column/feature_column_v2_test.py | 2343 +++++++++-------- 1 file changed, 1314 insertions(+), 1029 deletions(-) diff --git a/tensorflow/python/feature_column/feature_column_v2_test.py b/tensorflow/python/feature_column/feature_column_v2_test.py index 23131e22ed..3147754bee 100644 --- a/tensorflow/python/feature_column/feature_column_v2_test.py +++ b/tensorflow/python/feature_column/feature_column_v2_test.py @@ -228,11 +228,11 @@ class LazyColumnTest(test.TestCase): dense_shape=[0], values=np.array([])) }) - with self.cached_session(): - spv = transformation_cache.get('a', None).eval() - self.assertAllEqual(np.array([0, 1], dtype=np.int64), spv.dense_shape) - self.assertAllEqual( - np.reshape(np.array([], dtype=np.int64), (0, 2)), spv.indices) + + spv = self.evaluate(transformation_cache.get('a', None)) + self.assertAllEqual(np.array([0, 1], dtype=np.int64), spv.dense_shape) + self.assertAllEqual( + np.reshape(np.array([], dtype=np.int64), (0, 2)), spv.indices) class NumericColumnTest(test.TestCase): @@ -317,40 +317,44 @@ class NumericColumnTest(test.TestCase): def test_parse_example_no_default_value(self): price = fc.numeric_column('price', shape=[2]) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'price': - feature_pb2.Feature(float_list=feature_pb2.FloatList( - value=[20., 110.])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'price': + feature_pb2.Feature( + float_list=feature_pb2.FloatList(value=[20., 110.])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([price])) self.assertIn('price', features) - with self.cached_session(): - self.assertAllEqual([[20., 110.]], features['price'].eval()) + + self.assertAllEqual([[20., 110.]], self.evaluate(features['price'])) def test_parse_example_with_default_value(self): price = fc.numeric_column('price', shape=[2], default_value=11.) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'price': - feature_pb2.Feature(float_list=feature_pb2.FloatList( - value=[20., 110.])) - })) - no_data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'something_else': - feature_pb2.Feature(float_list=feature_pb2.FloatList( - value=[20., 110.])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'price': + feature_pb2.Feature( + float_list=feature_pb2.FloatList(value=[20., 110.])) + })) + no_data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'something_else': + feature_pb2.Feature( + float_list=feature_pb2.FloatList(value=[20., 110.])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString(), no_data.SerializeToString()], features=fc.make_parse_example_spec_v2([price])) self.assertIn('price', features) - with self.cached_session(): - self.assertAllEqual([[20., 110.], [11., 11.]], features['price'].eval()) + + self.assertAllEqual([[20., 110.], [11., 11.]], + self.evaluate(features['price'])) def test_normalizer_fn_must_be_callable(self): with self.assertRaisesRegexp(TypeError, 'must be a callable'): @@ -365,8 +369,8 @@ class NumericColumnTest(test.TestCase): output = fc._transform_features_v2({ 'price': [[1., 2.], [5., 6.]] }, [price], None) - with self.cached_session(): - self.assertAllEqual([[3., 4.], [7., 8.]], output[price].eval()) + + self.assertAllEqual([[3., 4.], [7., 8.]], self.evaluate(output[price])) def test_get_dense_tensor(self): @@ -471,17 +475,17 @@ class BucketizedColumnTest(test.TestCase): def test_invalid_boundaries(self): a = fc.numeric_column('aaa') - with self.assertRaisesRegexp( - ValueError, 'boundaries must be a sorted list'): + with self.assertRaisesRegexp(ValueError, + 'boundaries must be a sorted list'): fc.bucketized_column(a, boundaries=None) - with self.assertRaisesRegexp( - ValueError, 'boundaries must be a sorted list'): + with self.assertRaisesRegexp(ValueError, + 'boundaries must be a sorted list'): fc.bucketized_column(a, boundaries=1.) - with self.assertRaisesRegexp( - ValueError, 'boundaries must be a sorted list'): + with self.assertRaisesRegexp(ValueError, + 'boundaries must be a sorted list'): fc.bucketized_column(a, boundaries=[1, 0]) - with self.assertRaisesRegexp( - ValueError, 'boundaries must be a sorted list'): + with self.assertRaisesRegexp(ValueError, + 'boundaries must be a sorted list'): fc.bucketized_column(a, boundaries=[1, 1]) def test_name(self): @@ -518,18 +522,19 @@ class BucketizedColumnTest(test.TestCase): def test_parse_example(self): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 50]) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'price': - feature_pb2.Feature(float_list=feature_pb2.FloatList( - value=[20., 110.])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'price': + feature_pb2.Feature( + float_list=feature_pb2.FloatList(value=[20., 110.])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([bucketized_price])) self.assertIn('price', features) - with self.cached_session(): - self.assertAllEqual([[20., 110.]], features['price'].eval()) + + self.assertAllEqual([[20., 110.]], self.evaluate(features['price'])) def test_transform_feature(self): price = fc.numeric_column('price', shape=[2]) @@ -538,9 +543,12 @@ class BucketizedColumnTest(test.TestCase): transformed_tensor = fc._transform_features_v2({ 'price': [[-1., 1.], [5., 6.]] }, [bucketized_price], None) - with _initialized_session(): - self.assertAllEqual([[0, 1], [3, 4]], - transformed_tensor[bucketized_price].eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual([[0, 1], [3, 4]], + self.evaluate(transformed_tensor[bucketized_price])) def test_get_dense_tensor_one_input_value(self): """Tests _get_dense_tensor() for input with shape=[1].""" @@ -550,14 +558,17 @@ class BucketizedColumnTest(test.TestCase): transformation_cache = fc.FeatureTransformationCache({ 'price': [[-1.], [1.], [5.], [6.]] }) - with _initialized_session(): - bucketized_price_tensor = bucketized_price.get_dense_tensor( - transformation_cache, None) - self.assertAllClose( - # One-hot tensor. - [[[1., 0., 0., 0., 0.]], [[0., 1., 0., 0., 0.]], - [[0., 0., 0., 1., 0.]], [[0., 0., 0., 0., 1.]]], - self.evaluate(bucketized_price_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + bucketized_price_tensor = bucketized_price.get_dense_tensor( + transformation_cache, None) + self.assertAllClose( + # One-hot tensor. + [[[1., 0., 0., 0., 0.]], [[0., 1., 0., 0., 0.]], + [[0., 0., 0., 1., 0.]], [[0., 0., 0., 0., 1.]]], + self.evaluate(bucketized_price_tensor)) def test_get_dense_tensor_two_input_values(self): """Tests _get_dense_tensor() for input with shape=[2].""" @@ -567,14 +578,17 @@ class BucketizedColumnTest(test.TestCase): transformation_cache = fc.FeatureTransformationCache({ 'price': [[-1., 1.], [5., 6.]] }) - with _initialized_session(): - bucketized_price_tensor = bucketized_price.get_dense_tensor( - transformation_cache, None) - self.assertAllClose( - # One-hot tensor. - [[[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.]], - [[0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]]], - self.evaluate(bucketized_price_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + bucketized_price_tensor = bucketized_price.get_dense_tensor( + transformation_cache, None) + self.assertAllClose( + # One-hot tensor. + [[[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.]], + [[0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]]], + self.evaluate(bucketized_price_tensor)) def test_get_sparse_tensors_one_input_value(self): """Tests _get_sparse_tensors() for input with shape=[1].""" @@ -589,8 +603,8 @@ class BucketizedColumnTest(test.TestCase): transformation_cache, None) self.assertIsNone(id_weight_pair.weight_tensor) id_tensor_value = sess.run(id_weight_pair.id_tensor) - self.assertAllEqual( - [[0, 0], [1, 0], [2, 0], [3, 0]], id_tensor_value.indices) + self.assertAllEqual([[0, 0], [1, 0], [2, 0], [3, 0]], + id_tensor_value.indices) self.assertAllEqual([0, 1, 3, 4], id_tensor_value.values) self.assertAllEqual([4, 1], id_tensor_value.dense_shape) @@ -607,8 +621,8 @@ class BucketizedColumnTest(test.TestCase): transformation_cache, None) self.assertIsNone(id_weight_pair.weight_tensor) id_tensor_value = sess.run(id_weight_pair.id_tensor) - self.assertAllEqual( - [[0, 0], [0, 1], [1, 0], [1, 1]], id_tensor_value.indices) + self.assertAllEqual([[0, 0], [0, 1], [1, 0], [1, 1]], + id_tensor_value.indices) # Values 0-4 correspond to the first column of the input price. # Values 5-9 correspond to the second column of the input price. self.assertAllEqual([0, 6, 3, 9], id_tensor_value.values) @@ -649,8 +663,8 @@ class BucketizedColumnTest(test.TestCase): self.evaluate(bucketized_price_var)) self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(predictions)) - sess.run(bucketized_price_var.assign( - [[10.], [20.], [30.], [40.], [50.]])) + sess.run( + bucketized_price_var.assign([[10.], [20.], [30.], [40.], [50.]])) # price -1. is in the 0th bucket, whose weight is 10. # price 1. is in the 1st bucket, whose weight is 20. # price 5. is in the 3rd bucket, whose weight is 40. @@ -677,9 +691,9 @@ class BucketizedColumnTest(test.TestCase): [[0.], [0.], [0.], [0.], [0.], [0.], [0.], [0.], [0.], [0.]], self.evaluate(bucketized_price_var)) self.assertAllClose([[0.], [0.]], self.evaluate(predictions)) - sess.run(bucketized_price_var.assign( - [[10.], [20.], [30.], [40.], [50.], - [60.], [70.], [80.], [90.], [100.]])) + sess.run( + bucketized_price_var.assign([[10.], [20.], [30.], [40.], [50.], + [60.], [70.], [80.], [90.], [100.]])) # 1st example: # price -1. is in the 0th bucket, whose weight is 10. # price 1. is in the 6th bucket, whose weight is 70. @@ -856,24 +870,25 @@ class HashedCategoricalColumnTest(test.TestCase): def test_parse_example(self): a = fc.categorical_column_with_hash_bucket('aaa', 10) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) def test_strings_should_be_hashed(self): hashed_sparse = fc.categorical_column_with_hash_bucket('wire', 10) @@ -887,12 +902,14 @@ class HashedCategoricalColumnTest(test.TestCase): output = outputs[hashed_sparse] # Check exact hashed output. If hashing changes this test will break. expected_values = [6, 4, 1] - with self.cached_session(): - self.assertEqual(dtypes.int64, output.values.dtype) - self.assertAllEqual(expected_values, output.values.eval()) - self.assertAllEqual(wire_tensor.indices.eval(), output.indices.eval()) - self.assertAllEqual(wire_tensor.dense_shape.eval(), - output.dense_shape.eval()) + + self.assertEqual(dtypes.int64, output.values.dtype) + self.assertAllEqual(expected_values, self.evaluate(output.values)) + self.assertAllEqual( + self.evaluate(wire_tensor.indices), self.evaluate(output.indices)) + self.assertAllEqual( + self.evaluate(wire_tensor.dense_shape), + self.evaluate(output.dense_shape)) def test_tensor_dtype_should_be_string_or_integer(self): string_fc = fc.categorical_column_with_hash_bucket( @@ -902,17 +919,11 @@ class HashedCategoricalColumnTest(test.TestCase): float_fc = fc.categorical_column_with_hash_bucket( 'a_float', 10, dtype=dtypes.string) int_tensor = sparse_tensor.SparseTensor( - values=[101], - indices=[[0, 0]], - dense_shape=[1, 1]) + values=[101], indices=[[0, 0]], dense_shape=[1, 1]) string_tensor = sparse_tensor.SparseTensor( - values=['101'], - indices=[[0, 0]], - dense_shape=[1, 1]) + values=['101'], indices=[[0, 0]], dense_shape=[1, 1]) float_tensor = sparse_tensor.SparseTensor( - values=[101.], - indices=[[0, 0]], - dense_shape=[1, 1]) + values=[101.], indices=[[0, 0]], dense_shape=[1, 1]) transformation_cache = fc.FeatureTransformationCache({ 'a_int': int_tensor, 'a_string': string_tensor, @@ -943,8 +954,8 @@ class HashedCategoricalColumnTest(test.TestCase): output = transformation_cache.get(hashed_sparse, None) # Check exact hashed output. If hashing changes this test will break. expected_values = [3, 7, 5] - with self.cached_session(): - self.assertAllEqual(expected_values, output.values.eval()) + + self.assertAllEqual(expected_values, self.evaluate(output.values)) def test_int32_64_is_compatible(self): hashed_sparse = fc.categorical_column_with_hash_bucket( @@ -957,8 +968,8 @@ class HashedCategoricalColumnTest(test.TestCase): output = transformation_cache.get(hashed_sparse, None) # Check exact hashed output. If hashing changes this test will break. expected_values = [3, 7, 5] - with self.cached_session(): - self.assertAllEqual(expected_values, output.values.eval()) + + self.assertAllEqual(expected_values, self.evaluate(output.values)) def test_get_sparse_tensors(self): hashed_sparse = fc.categorical_column_with_hash_bucket('wire', 10) @@ -999,15 +1010,17 @@ class HashedCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)) }) wire_var, bias = model.variables - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), - self.evaluate(wire_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - wire_var.assign(((1.,), (2.,), (3.,), (4.,))).eval() - # 'marlo' -> 3: wire_var[3] = 4 - # 'skywalker' -> 2, 'omar' -> 2: wire_var[2] + wire_var[2] = 3+3 = 6 - self.assertAllClose(((4.,), (6.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), self.evaluate(wire_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(wire_var.assign(((1.,), (2.,), (3.,), (4.,)))) + # 'marlo' -> 3: wire_var[3] = 4 + # 'skywalker' -> 2, 'omar' -> 2: wire_var[2] + wire_var[2] = 3+3 = 6 + self.assertAllClose(((4.,), (6.,)), self.evaluate(predictions)) def test_old_linear_model(self): wire_column = fc.categorical_column_with_hash_bucket('wire', 4) @@ -1022,15 +1035,17 @@ class HashedCategoricalColumnTest(test.TestCase): }, (wire_column,)) bias = get_linear_model_bias() wire_var = get_linear_model_column_var(wire_column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), - self.evaluate(wire_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - wire_var.assign(((1.,), (2.,), (3.,), (4.,))).eval() - # 'marlo' -> 3: wire_var[3] = 4 - # 'skywalker' -> 2, 'omar' -> 2: wire_var[2] + wire_var[2] = 3+3 = 6 - self.assertAllClose(((4.,), (6.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), self.evaluate(wire_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(wire_var.assign(((1.,), (2.,), (3.,), (4.,)))) + # 'marlo' -> 3: wire_var[3] = 4 + # 'skywalker' -> 2, 'omar' -> 2: wire_var[2] + wire_var[2] = 3+3 = 6 + self.assertAllClose(((4.,), (6.,)), self.evaluate(predictions)) def test_serialization(self): wire_column = fc.categorical_column_with_hash_bucket('wire', 4) @@ -1050,13 +1065,13 @@ class HashedCategoricalColumnTest(test.TestCase): class CrossedColumnTest(test.TestCase): def test_keys_empty(self): - with self.assertRaisesRegexp( - ValueError, 'keys must be a list with length > 1'): + with self.assertRaisesRegexp(ValueError, + 'keys must be a list with length > 1'): fc.crossed_column([], 10) def test_keys_length_one(self): - with self.assertRaisesRegexp( - ValueError, 'keys must be a list with length > 1'): + with self.assertRaisesRegexp(ValueError, + 'keys must be a list with length > 1'): fc.crossed_column(['a'], 10) def test_key_type_unsupported(self): @@ -1069,18 +1084,15 @@ class CrossedColumnTest(test.TestCase): ['a', fc.categorical_column_with_hash_bucket('c', 10)], 10) def test_hash_bucket_size_negative(self): - with self.assertRaisesRegexp( - ValueError, 'hash_bucket_size must be > 1'): + with self.assertRaisesRegexp(ValueError, 'hash_bucket_size must be > 1'): fc.crossed_column(['a', 'c'], -1) def test_hash_bucket_size_zero(self): - with self.assertRaisesRegexp( - ValueError, 'hash_bucket_size must be > 1'): + with self.assertRaisesRegexp(ValueError, 'hash_bucket_size must be > 1'): fc.crossed_column(['a', 'c'], 0) def test_hash_bucket_size_none(self): - with self.assertRaisesRegexp( - ValueError, 'hash_bucket_size must be > 1'): + with self.assertRaisesRegexp(ValueError, 'hash_bucket_size must be > 1'): fc.crossed_column(['a', 'c'], None) def test_name(self): @@ -1142,7 +1154,10 @@ class CrossedColumnTest(test.TestCase): crossed1 = fc.crossed_column(['d1', 'd2'], 10) crossed2 = fc.crossed_column([b, 'c', crossed1], 15, hash_key=5) crossed2_copy = copy.deepcopy(crossed2) - self.assertEqual('a_bucketized_X_c_X_d1_X_d2', crossed2_copy.name,) + self.assertEqual( + 'a_bucketized_X_c_X_d1_X_d2', + crossed2_copy.name, + ) self.assertEqual(15, crossed2_copy.hash_bucket_size) self.assertEqual(5, crossed2_copy.hash_key) @@ -1150,27 +1165,30 @@ class CrossedColumnTest(test.TestCase): price = fc.numeric_column('price', shape=[2]) bucketized_price = fc.bucketized_column(price, boundaries=[0, 50]) price_cross_wire = fc.crossed_column([bucketized_price, 'wire'], 10) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'price': - feature_pb2.Feature(float_list=feature_pb2.FloatList( - value=[20., 110.])), - 'wire': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])), - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'price': + feature_pb2.Feature( + float_list=feature_pb2.FloatList(value=[20., 110.])), + 'wire': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])), + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([price_cross_wire])) self.assertIn('price', features) self.assertIn('wire', features) - with self.cached_session(): - self.assertAllEqual([[20., 110.]], features['price'].eval()) - wire_sparse = features['wire'] - self.assertAllEqual([[0, 0], [0, 1]], wire_sparse.indices.eval()) - # Use byte constants to pass the open-source test. - self.assertAllEqual([b'omar', b'stringer'], wire_sparse.values.eval()) - self.assertAllEqual([1, 2], wire_sparse.dense_shape.eval()) + + self.assertAllEqual([[20., 110.]], self.evaluate(features['price'])) + wire_sparse = features['wire'] + self.assertAllEqual([[0, 0], [0, 1]], self.evaluate(wire_sparse.indices)) + # Use byte constants to pass the open-source test. + self.assertAllEqual([b'omar', b'stringer'], + self.evaluate(wire_sparse.values)) + self.assertAllEqual([1, 2], self.evaluate(wire_sparse.dense_shape)) def test_transform_feature(self): price = fc.numeric_column('price', shape=[2]) @@ -1179,21 +1197,22 @@ class CrossedColumnTest(test.TestCase): price_cross_wire = fc.crossed_column([bucketized_price, 'wire'], hash_bucket_size) features = { - 'price': constant_op.constant([[1., 2.], [5., 6.]]), - 'wire': sparse_tensor.SparseTensor( - values=['omar', 'stringer', 'marlo'], - indices=[[0, 0], [1, 0], [1, 1]], - dense_shape=[2, 2]), + 'price': + constant_op.constant([[1., 2.], [5., 6.]]), + 'wire': + sparse_tensor.SparseTensor( + values=['omar', 'stringer', 'marlo'], + indices=[[0, 0], [1, 0], [1, 1]], + dense_shape=[2, 2]), } outputs = fc._transform_features_v2(features, [price_cross_wire], None) output = outputs[price_cross_wire] - with self.cached_session() as sess: - output_val = self.evaluate(output) - self.assertAllEqual( - [[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [1, 3]], output_val.indices) - for val in output_val.values: - self.assertIn(val, list(range(hash_bucket_size))) - self.assertAllEqual([2, 4], output_val.dense_shape) + output_val = self.evaluate(output) + self.assertAllEqual([[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [1, 3]], + output_val.indices) + for val in output_val.values: + self.assertIn(val, list(range(hash_bucket_size))) + self.assertAllEqual([2, 4], output_val.dense_shape) def test_get_sparse_tensors(self): a = fc.numeric_column('a', dtype=dtypes.int32, shape=(2,)) @@ -1221,19 +1240,21 @@ class CrossedColumnTest(test.TestCase): dense_shape=(2, 2)), }) id_weight_pair = crossed2.get_sparse_tensors(transformation_cache, None) - with _initialized_session(): - id_tensor_eval = id_weight_pair.id_tensor.eval() - self.assertAllEqual( - ((0, 0), (0, 1), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), - (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11), (1, 12), (1, 13), - (1, 14), (1, 15)), - id_tensor_eval.indices) - # Check exact hashed output. If hashing changes this test will break. - # All values are within [0, hash_bucket_size). - expected_values = ( - 6, 14, 0, 13, 8, 8, 10, 12, 2, 0, 1, 9, 8, 12, 2, 0, 10, 11) - self.assertAllEqual(expected_values, id_tensor_eval.values) - self.assertAllEqual((2, 16), id_tensor_eval.dense_shape) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + id_tensor_eval = self.evaluate(id_weight_pair.id_tensor) + self.assertAllEqual( + ((0, 0), (0, 1), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), + (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11), (1, 12), (1, 13), + (1, 14), (1, 15)), id_tensor_eval.indices) + # Check exact hashed output. If hashing changes this test will break. + # All values are within [0, hash_bucket_size). + expected_values = (6, 14, 0, 13, 8, 8, 10, 12, 2, 0, 1, 9, 8, 12, 2, 0, + 10, 11) + self.assertAllEqual(expected_values, id_tensor_eval.values) + self.assertAllEqual((2, 16), id_tensor_eval.dense_shape) def test_get_sparse_tensors_simple(self): """Same as test_get_sparse_tensors, but with simpler values.""" @@ -1251,16 +1272,18 @@ class CrossedColumnTest(test.TestCase): dense_shape=(2, 2)), }) id_weight_pair = crossed.get_sparse_tensors(transformation_cache, None) - with _initialized_session(): - id_tensor_eval = id_weight_pair.id_tensor.eval() - self.assertAllEqual( - ((0, 0), (0, 1), (1, 0), (1, 1), (1, 2), (1, 3)), - id_tensor_eval.indices) - # Check exact hashed output. If hashing changes this test will break. - # All values are within [0, hash_bucket_size). - expected_values = (1, 0, 1, 3, 4, 2) - self.assertAllEqual(expected_values, id_tensor_eval.values) - self.assertAllEqual((2, 4), id_tensor_eval.dense_shape) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + id_tensor_eval = self.evaluate(id_weight_pair.id_tensor) + self.assertAllEqual(((0, 0), (0, 1), (1, 0), (1, 1), (1, 2), (1, 3)), + id_tensor_eval.indices) + # Check exact hashed output. If hashing changes this test will break. + # All values are within [0, hash_bucket_size). + expected_values = (1, 0, 1, 3, 4, 2) + self.assertAllEqual(expected_values, id_tensor_eval.values) + self.assertAllEqual((2, 4), id_tensor_eval.dense_shape) def test_linear_model(self): """Tests linear_model. @@ -1310,10 +1333,11 @@ class CrossedColumnTest(test.TestCase): @property def parse_example_spec(self): return { - self.name: parsing_ops.VarLenFeature(dtypes.int32), - '{}_weights'.format(self.name): parsing_ops.VarLenFeature( - dtypes.float32), - } + self.name: + parsing_ops.VarLenFeature(dtypes.int32), + '{}_weights'.format(self.name): + parsing_ops.VarLenFeature(dtypes.float32), + } @property def num_buckets(self): @@ -1537,7 +1561,6 @@ class CrossedColumnTest(test.TestCase): self.assertIs(b, new_crossed.keys[0]) - class LinearModelTest(test.TestCase): def test_raises_if_empty_feature_columns(self): @@ -1692,8 +1715,9 @@ class LinearModelTest(test.TestCase): predictions = model(features) dense_and_sparse_column_var, bias = model.variables with _initialized_session() as sess: - sess.run(dense_and_sparse_column_var.assign( - [[10.], [100.], [1000.], [10000.]])) + sess.run( + dense_and_sparse_column_var.assign([[10.], [100.], [1000.], + [10000.]])) sess.run(bias.assign([5.])) self.assertAllClose([[1005.], [10015.]], self.evaluate(predictions)) @@ -1727,9 +1751,9 @@ class LinearModelTest(test.TestCase): self.assertAllClose(np.zeros((3,)), self.evaluate(bias)) self.assertAllClose(np.zeros((4, 3)), self.evaluate(wire_cast_var)) sess.run( - wire_cast_var.assign([[10., 11., 12.], [100., 110., 120.], [ - 1000., 1100., 1200. - ], [10000., 11000., 12000.]])) + wire_cast_var.assign([[10., 11., 12.], [100., 110., 120.], + [1000., 1100., 1200.], + [10000., 11000., 12000.]])) sess.run(bias.assign([5., 6., 7.])) self.assertAllClose([[1005., 1106., 1207.], [10015., 11017., 12019.]], self.evaluate(predictions)) @@ -1848,10 +1872,7 @@ class LinearModelTest(test.TestCase): price1 = fc.numeric_column('price1', shape=2) price2 = fc.numeric_column('price2') with ops.Graph().as_default(): - features = { - 'price1': [[1., 2.], [5., 6.]], - 'price2': [[3.], [4.]] - } + features = {'price1': [[1., 2.], [5., 6.]], 'price2': [[3.], [4.]]} model = fc.LinearModel([price1, price2]) predictions = model(features) price1_var, price2_var, bias = model.variables @@ -2107,11 +2128,16 @@ class LinearModelTest(test.TestCase): # Provides 1-dim tensor and dense tensor. features = { - 'price': constant_op.constant([-1., 12.,]), - 'body-style': sparse_tensor.SparseTensor( - indices=((0,), (1,)), - values=('sedan', 'hardtop'), - dense_shape=(2,)), + 'price': + constant_op.constant([ + -1., + 12., + ]), + 'body-style': + sparse_tensor.SparseTensor( + indices=((0,), (1,)), + values=('sedan', 'hardtop'), + dense_shape=(2,)), } self.assertEqual(1, features['price'].shape.ndims) self.assertEqual(1, features['body-style'].dense_shape.get_shape()[0]) @@ -2152,9 +2178,7 @@ class LinearModelTest(test.TestCase): price_data = np.array([-1., 12.]) body_style_data = sparse_tensor.SparseTensorValue( - indices=((0,), (1,)), - values=('sedan', 'hardtop'), - dense_shape=(2,)) + indices=((0,), (1,)), values=('sedan', 'hardtop'), dense_shape=(2,)) country_data = np.array(['US', 'CA']) model = fc.LinearModel([price_buckets, body_style, country]) @@ -2602,15 +2626,18 @@ class OldLinearModelTest(test.TestCase): partitioner=partitioned_variables.fixed_size_partitioner(2, axis=0)): fc_old.linear_model( features, [price1, price2], cols_to_vars=cols_to_vars) - with _initialized_session(): - self.assertEqual([0.], cols_to_vars['bias'][0].eval()) - # Partitioning shards the [2, 1] price1 var into 2 [1, 1] Variables. - self.assertAllEqual([[0.]], cols_to_vars[price1][0].eval()) - self.assertAllEqual([[0.]], cols_to_vars[price1][1].eval()) - # Partitioning shards the [3, 1] price2 var into a [2, 1] Variable and - # a [1, 1] Variable. - self.assertAllEqual([[0.], [0.]], cols_to_vars[price2][0].eval()) - self.assertAllEqual([[0.]], cols_to_vars[price2][1].eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertEqual([0.], self.evaluate(cols_to_vars['bias'][0])) + # Partitioning shards the [2, 1] price1 var into 2 [1, 1] Variables. + self.assertAllEqual([[0.]], self.evaluate(cols_to_vars[price1][0])) + self.assertAllEqual([[0.]], self.evaluate(cols_to_vars[price1][1])) + # Partitioning shards the [3, 1] price2 var into a [2, 1] Variable and + # a [1, 1] Variable. + self.assertAllEqual([[0.], [0.]], self.evaluate(cols_to_vars[price2][0])) + self.assertAllEqual([[0.]], self.evaluate(cols_to_vars[price2][1])) def test_fills_cols_to_output_tensors(self): # Provide three _DenseColumn's to input_layer: a _NumericColumn, a @@ -2968,8 +2995,11 @@ class OldLinearModelTest(test.TestCase): } fc_old.linear_model(features, all_cols) bias = get_linear_model_bias() - with _initialized_session(): - self.assertAllClose([0.], self.evaluate(bias)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([0.], self.evaluate(bias)) def test_linear_model_v1_shared_embedding_with_v2_cat_all_other_v2(self): price = fc.numeric_column('price') # v2 @@ -3004,8 +3034,11 @@ class OldLinearModelTest(test.TestCase): } fc_old.linear_model(features, all_cols) bias = get_linear_model_bias() - with _initialized_session(): - self.assertAllClose([0.], self.evaluate(bias)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([0.], self.evaluate(bias)) def test_linear_model_v1_v2_mix(self): price = fc.numeric_column('price') # v2 @@ -3040,8 +3073,11 @@ class OldLinearModelTest(test.TestCase): } fc_old.linear_model(features, all_cols) bias = get_linear_model_bias() - with _initialized_session(): - self.assertAllClose([0.], self.evaluate(bias)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([0.], self.evaluate(bias)) def test_linear_model_v2_shared_embedding_all_other_v1(self): price = fc.numeric_column('price') # v1 @@ -3099,6 +3135,7 @@ class DenseFeaturesTest(test.TestCase): categorical_column = fc.categorical_column_with_identity( key='a', num_buckets=3) embedding_dimension = 2 + def _embedding_column_initializer(shape, dtype, partition_info): del shape # unused del dtype # unused @@ -3204,16 +3241,22 @@ class DenseFeaturesTest(test.TestCase): with ops.Graph().as_default(): features = features = {'a': [0.]} net = fc.DenseFeatures(fc.numeric_column('a'))(features) - with _initialized_session(): - self.assertAllClose([[0.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0.]], self.evaluate(net)) def test_column_generator(self): with ops.Graph().as_default(): features = features = {'a': [0.], 'b': [1.]} columns = (fc.numeric_column(key) for key in features) net = fc.DenseFeatures(columns)(features) - with _initialized_session(): - self.assertAllClose([[0., 1.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0., 1.]], self.evaluate(net)) def test_raises_if_duplicate_name(self): with self.assertRaisesRegexp( @@ -3230,16 +3273,22 @@ class DenseFeaturesTest(test.TestCase): with ops.Graph().as_default(): features = {'price': [[1.], [5.]]} net = fc.DenseFeatures([price])(features) - with _initialized_session(): - self.assertAllClose([[1.], [5.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1.], [5.]], self.evaluate(net)) def test_multi_dimension(self): price = fc.numeric_column('price', shape=2) with ops.Graph().as_default(): features = {'price': [[1., 2.], [5., 6.]]} net = fc.DenseFeatures([price])(features) - with _initialized_session(): - self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) def test_compute_output_shape(self): price1 = fc.numeric_column('price1', shape=2) @@ -3252,10 +3301,12 @@ class DenseFeaturesTest(test.TestCase): dense_features = fc.DenseFeatures([price1, price2]) self.assertEqual((None, 6), dense_features.compute_output_shape((None,))) net = dense_features(features) - with _initialized_session(): - self.assertAllClose( - [[1., 2., 3., 4., 5., 6.], [5., 6., 7., 8., 9., 10.]], - self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2., 3., 4., 5., 6.], [5., 6., 7., 8., 9., 10.]], + self.evaluate(net)) def test_raises_if_shape_mismatch(self): price = fc.numeric_column('price', shape=2) @@ -3271,20 +3322,23 @@ class DenseFeaturesTest(test.TestCase): with ops.Graph().as_default(): features = {'price': [[[1., 2.]], [[5., 6.]]]} net = fc.DenseFeatures([price])(features) - with _initialized_session(): - self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) def test_multi_column(self): price1 = fc.numeric_column('price1', shape=2) price2 = fc.numeric_column('price2') with ops.Graph().as_default(): - features = { - 'price1': [[1., 2.], [5., 6.]], - 'price2': [[3.], [4.]] - } + features = {'price1': [[1., 2.], [5., 6.]], 'price2': [[3.], [4.]]} net = fc.DenseFeatures([price1, price2])(features) - with _initialized_session(): - self.assertAllClose([[1., 2., 3.], [5., 6., 4.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2., 3.], [5., 6., 4.]], self.evaluate(net)) def test_cols_to_output_tensors(self): price1 = fc.numeric_column('price1', shape=2) @@ -3294,10 +3348,14 @@ class DenseFeaturesTest(test.TestCase): features = {'price1': [[1., 2.], [5., 6.]], 'price2': [[3.], [4.]]} dense_features = fc.DenseFeatures([price1, price2]) net = dense_features(features, cols_dict) - with _initialized_session(): - self.assertAllClose([[1., 2.], [5., 6.]], cols_dict[price1].eval()) - self.assertAllClose([[3.], [4.]], cols_dict[price2].eval()) - self.assertAllClose([[1., 2., 3.], [5., 6., 4.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2.], [5., 6.]], + self.evaluate(cols_dict[price1])) + self.assertAllClose([[3.], [4.]], self.evaluate(cols_dict[price2])) + self.assertAllClose([[1., 2., 3.], [5., 6., 4.]], self.evaluate(net)) def test_column_order(self): price_a = fc.numeric_column('price_a') @@ -3309,9 +3367,12 @@ class DenseFeaturesTest(test.TestCase): } net1 = fc.DenseFeatures([price_a, price_b])(features) net2 = fc.DenseFeatures([price_b, price_a])(features) - with _initialized_session(): - self.assertAllClose([[1., 3.]], self.evaluate(net1)) - self.assertAllClose([[1., 3.]], self.evaluate(net2)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 3.]], self.evaluate(net1)) + self.assertAllClose([[1., 3.]], self.evaluate(net2)) def test_fails_for_categorical_column(self): animal = fc.categorical_column_with_identity('animal', num_buckets=4) @@ -3497,6 +3558,7 @@ class DenseFeaturesTest(test.TestCase): (6., 7., 8., 9., 10.), # id 1 (11., 12., 13., 14., 15.) # id 2 ) + def _initializer(shape, dtype, partition_info): del shape, dtype, partition_info return embedding_values @@ -3528,10 +3590,8 @@ class DenseFeaturesTest(test.TestCase): # Each row is formed by concatenating `embedded_body_style`, # `one_hot_body_style`, and `price` in order. - self.assertAllEqual( - [[11., 12., 13., 14., 15., 0., 0., 1., 11.], - [1., 2., 3., 4., 5., 1., 0., 0., 12]], - sess.run(net)) + self.assertAllEqual([[11., 12., 13., 14., 15., 0., 0., 1., 11.], + [1., 2., 3., 4., 5., 1., 0., 0., 12]], sess.run(net)) coord.request_stop() coord.join(threads) @@ -3542,6 +3602,7 @@ class DenseFeaturesTest(test.TestCase): (6., 7., 8., 9., 10.), # id 1 (11., 12., 13., 14., 15.) # id 2 ) + def _initializer(shape, dtype, partition_info): del shape, dtype, partition_info return embedding_values @@ -3562,13 +3623,19 @@ class DenseFeaturesTest(test.TestCase): # Provides 1-dim tensor and dense tensor. features = { - 'price': constant_op.constant([11., 12.,]), - 'body-style': sparse_tensor.SparseTensor( - indices=((0,), (1,)), - values=('sedan', 'hardtop'), - dense_shape=(2,)), + 'price': + constant_op.constant([ + 11., + 12., + ]), + 'body-style': + sparse_tensor.SparseTensor( + indices=((0,), (1,)), + values=('sedan', 'hardtop'), + dense_shape=(2,)), # This is dense tensor for the categorical_column. - 'country': constant_op.constant(['CA', 'US']), + 'country': + constant_op.constant(['CA', 'US']), } self.assertEqual(1, features['price'].shape.ndims) self.assertEqual(1, features['body-style'].dense_shape.get_shape()[0]) @@ -3581,10 +3648,9 @@ class DenseFeaturesTest(test.TestCase): # Each row is formed by concatenating `embedded_body_style`, # `one_hot_body_style`, and `price` in order. - self.assertAllEqual( - [[0., 0., 1., 11., 12., 13., 14., 15., 11.], - [1., 0., 0., 1., 2., 3., 4., 5., 12.]], - sess.run(net)) + self.assertAllEqual([[0., 0., 1., 11., 12., 13., 14., 15., 11.], + [1., 0., 0., 1., 2., 3., 4., 5., 12.]], + sess.run(net)) def test_with_1d_unknown_shape_sparse_tensor(self): embedding_values = ( @@ -3592,6 +3658,7 @@ class DenseFeaturesTest(test.TestCase): (6., 7.), # id 1 (11., 12.) # id 2 ) + def _initializer(shape, dtype, partition_info): del shape, dtype, partition_info return embedding_values @@ -3623,9 +3690,7 @@ class DenseFeaturesTest(test.TestCase): price_data = np.array([11., 12.]) body_style_data = sparse_tensor.SparseTensorValue( - indices=((0,), (1,)), - values=('sedan', 'hardtop'), - dense_shape=(2,)) + indices=((0,), (1,)), values=('sedan', 'hardtop'), dense_shape=(2,)) country_data = np.array([['US'], ['CA']]) net = fc.DenseFeatures([price, one_hot_body_style, embedded_country])( @@ -3794,16 +3859,22 @@ class FunctionalInputLayerTest(test.TestCase): with ops.Graph().as_default(): features = features = {'a': [0.]} net = fc_old.input_layer(features, fc.numeric_column('a')) - with _initialized_session(): - self.assertAllClose([[0.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0.]], self.evaluate(net)) def test_column_generator(self): with ops.Graph().as_default(): features = features = {'a': [0.], 'b': [1.]} columns = (fc.numeric_column(key) for key in features) net = fc_old.input_layer(features, columns) - with _initialized_session(): - self.assertAllClose([[0., 1.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0., 1.]], self.evaluate(net)) def test_raises_if_duplicate_name(self): with self.assertRaisesRegexp( @@ -3818,16 +3889,22 @@ class FunctionalInputLayerTest(test.TestCase): with ops.Graph().as_default(): features = {'price': [[1.], [5.]]} net = fc_old.input_layer(features, [price]) - with _initialized_session(): - self.assertAllClose([[1.], [5.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1.], [5.]], self.evaluate(net)) def test_multi_dimension(self): price = fc.numeric_column('price', shape=2) with ops.Graph().as_default(): features = {'price': [[1., 2.], [5., 6.]]} net = fc_old.input_layer(features, [price]) - with _initialized_session(): - self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) def test_raises_if_shape_mismatch(self): price = fc.numeric_column('price', shape=2) @@ -3843,8 +3920,11 @@ class FunctionalInputLayerTest(test.TestCase): with ops.Graph().as_default(): features = {'price': [[[1., 2.]], [[5., 6.]]]} net = fc_old.input_layer(features, [price]) - with _initialized_session(): - self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2.], [5., 6.]], self.evaluate(net)) def test_multi_column(self): price1 = fc.numeric_column('price1', shape=2) @@ -3852,8 +3932,11 @@ class FunctionalInputLayerTest(test.TestCase): with ops.Graph().as_default(): features = {'price1': [[1., 2.], [5., 6.]], 'price2': [[3.], [4.]]} net = fc_old.input_layer(features, [price1, price2]) - with _initialized_session(): - self.assertAllClose([[1., 2., 3.], [5., 6., 4.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 2., 3.], [5., 6., 4.]], self.evaluate(net)) def test_fills_cols_to_vars(self): # Provide three _DenseColumn's to input_layer: a _NumericColumn, a @@ -3983,9 +4066,12 @@ class FunctionalInputLayerTest(test.TestCase): } net1 = fc_old.input_layer(features, [price_a, price_b]) net2 = fc_old.input_layer(features, [price_b, price_a]) - with _initialized_session(): - self.assertAllClose([[1., 3.]], self.evaluate(net1)) - self.assertAllClose([[1., 3.]], self.evaluate(net2)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[1., 3.]], self.evaluate(net1)) + self.assertAllClose([[1., 3.]], self.evaluate(net2)) def test_fails_for_categorical_column(self): animal = fc.categorical_column_with_identity('animal', num_buckets=4) @@ -4323,8 +4409,11 @@ class MakeParseExampleSpecTest(test.TestCase): key2: parse_spec2, key3: parse_spec3 }))) - self.assertDictEqual( - {key1: parse_spec1, key2: parse_spec2, key3: parse_spec3}, actual) + self.assertDictEqual({ + key1: parse_spec1, + key2: parse_spec2, + key3: parse_spec3 + }, actual) def _assert_sparse_tensor_value(test_case, expected, actual): @@ -4332,7 +4421,8 @@ def _assert_sparse_tensor_value(test_case, expected, actual): test_case.assertAllEqual(expected.indices, actual.indices) test_case.assertEqual( - np.array(expected.values).dtype, np.array(actual.values).dtype) + np.array(expected.values).dtype, + np.array(actual.values).dtype) test_case.assertAllEqual(expected.values, actual.values) test_case.assertEqual(np.int64, np.array(actual.dense_shape).dtype) @@ -4418,8 +4508,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) with self.assertRaisesRegexp(errors.OpError, 'file_does_not_exist'): - with self.cached_session(): - lookup_ops.tables_initializer().run() + self.evaluate(lookup_ops.tables_initializer()) def test_invalid_vocabulary_size(self): with self.assertRaisesRegexp(ValueError, 'Invalid vocabulary_size'): @@ -4447,8 +4536,7 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) with self.assertRaisesRegexp(errors.OpError, 'Invalid vocab_size'): - with self.cached_session(): - lookup_ops.tables_initializer().run() + self.evaluate(lookup_ops.tables_initializer()) def test_invalid_num_oov_buckets(self): with self.assertRaisesRegexp(ValueError, 'Invalid num_oov_buckets'): @@ -4467,8 +4555,8 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dtype=dtypes.float64) def test_invalid_buckets_and_default_value(self): - with self.assertRaisesRegexp( - ValueError, 'both num_oov_buckets and default_value'): + with self.assertRaisesRegexp(ValueError, + 'both num_oov_buckets and default_value'): fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file=self._wire_vocabulary_file_name, @@ -4511,24 +4599,25 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): def test_parse_example(self): a = fc.categorical_column_with_vocabulary_file( key='aaa', vocabulary_file='path_to_file', vocabulary_size=3) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) def test_get_sparse_tensors(self): column = fc.categorical_column_with_vocabulary_file( @@ -4544,14 +4633,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, -1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_none_vocabulary_size(self): column = fc.categorical_column_with_vocabulary_file( @@ -4565,14 +4657,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value(self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array( - (2, -1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_transform_feature(self): column = fc.categorical_column_with_vocabulary_file( @@ -4586,13 +4681,16 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): id_tensor = fc._transform_features_v2({ 'aaa': inputs }, [column], None)[column] - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, -1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) def test_get_sparse_tensors_dense_input(self): column = fc.categorical_column_with_vocabulary_file( @@ -4604,14 +4702,16 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': (('marlo', ''), ('skywalker', 'omar')) }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=np.array((2, -1, 0), dtype=np.int64), - dense_shape=(2, 2)), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1)), + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=(2, 2)), self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_default_value_in_vocabulary(self): column = fc.categorical_column_with_vocabulary_file( @@ -4628,14 +4728,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, 2, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, 2, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_file( @@ -4652,14 +4755,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, 33, 0, 62), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, 33, 0, 62), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_small_vocabulary_size(self): # 'marlo' is the last entry in our vocabulary file, so be setting @@ -4678,14 +4784,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((-1, -1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((-1, -1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_int32(self): column = fc.categorical_column_with_vocabulary_file( @@ -4702,14 +4811,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, -1, 0, 4), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0, 4), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_int32_dense_input(self): default_value = -100 @@ -4724,14 +4836,16 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': ((11, -1, -1), (100, 30, -1), (-1, -1, 22)) }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1), (2, 2)), - values=np.array((2, default_value, 0, 4), dtype=np.int64), - dense_shape=(3, 3)), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1), (2, 2)), + values=np.array((2, default_value, 0, 4), dtype=np.int64), + dense_shape=(3, 3)), self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_int32_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_file( @@ -4749,14 +4863,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, 60, 0, 4), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, 60, 0, 4), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_linear_model(self): wire_column = fc.categorical_column_with_vocabulary_file( @@ -4775,15 +4892,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)) }) wire_var, bias = model.variables - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), - self.evaluate(wire_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - wire_var.assign(((1.,), (2.,), (3.,), (4.,))).eval() - # 'marlo' -> 2: wire_var[2] = 3 - # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 - self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), self.evaluate(wire_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(wire_var.assign(((1.,), (2.,), (3.,), (4.,)))) + # 'marlo' -> 2: wire_var[2] = 3 + # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 + self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) def test_old_linear_model(self): wire_column = fc.categorical_column_with_vocabulary_file( @@ -4802,15 +4921,17 @@ class VocabularyFileCategoricalColumnTest(test.TestCase): }, (wire_column,)) bias = get_linear_model_bias() wire_var = get_linear_model_column_var(wire_column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), - self.evaluate(wire_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - wire_var.assign(((1.,), (2.,), (3.,), (4.,))).eval() - # 'marlo' -> 2: wire_var[2] = 3 - # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 - self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), self.evaluate(wire_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(wire_var.assign(((1.,), (2.,), (3.,), (4.,)))) + # 'marlo' -> 2: wire_var[2] = 3 + # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 + self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) def test_serialization(self): wire_column = fc.categorical_column_with_vocabulary_file( @@ -4892,34 +5013,34 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dtype=dtypes.float32) def test_invalid_mapping_dtype(self): - with self.assertRaisesRegexp( - ValueError, r'vocabulary dtype must be string or integer'): + with self.assertRaisesRegexp(ValueError, + r'vocabulary dtype must be string or integer'): fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(12., 24., 36.)) def test_mismatched_int_dtype(self): - with self.assertRaisesRegexp( - ValueError, r'dtype.*and vocabulary dtype.*do not match'): + with self.assertRaisesRegexp(ValueError, + r'dtype.*and vocabulary dtype.*do not match'): fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo'), dtype=dtypes.int32) def test_mismatched_string_dtype(self): - with self.assertRaisesRegexp( - ValueError, r'dtype.*and vocabulary dtype.*do not match'): + with self.assertRaisesRegexp(ValueError, + r'dtype.*and vocabulary dtype.*do not match'): fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(12, 24, 36), dtype=dtypes.string) def test_none_mapping(self): - with self.assertRaisesRegexp( - ValueError, r'vocabulary_list.*must be non-empty'): + with self.assertRaisesRegexp(ValueError, + r'vocabulary_list.*must be non-empty'): fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=None) def test_empty_mapping(self): - with self.assertRaisesRegexp( - ValueError, r'vocabulary_list.*must be non-empty'): + with self.assertRaisesRegexp(ValueError, + r'vocabulary_list.*must be non-empty'): fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=tuple([])) @@ -4934,8 +5055,8 @@ class VocabularyListCategoricalColumnTest(test.TestCase): key='aaa', vocabulary_list=(12, 24, 36), num_oov_buckets=-1) def test_invalid_buckets_and_default_value(self): - with self.assertRaisesRegexp( - ValueError, 'both num_oov_buckets and default_value'): + with self.assertRaisesRegexp(ValueError, + 'both num_oov_buckets and default_value'): fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(12, 24, 36), @@ -4971,46 +5092,46 @@ class VocabularyListCategoricalColumnTest(test.TestCase): def test_parse_example_string(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) def test_parse_example_int(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=(11, 21, 31)) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(int64_list=feature_pb2.Int64List( - value=[11, 21])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + int64_list=feature_pb2.Int64List(value=[11, 21])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=[11, 21], - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], values=[11, 21], dense_shape=[1, 2]), + self.evaluate(features['aaa'])) def test_get_sparse_tensors(self): column = fc.categorical_column_with_vocabulary_list( @@ -5024,14 +5145,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, -1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_transform_feature(self): column = fc.categorical_column_with_vocabulary_list( @@ -5043,13 +5167,16 @@ class VocabularyListCategoricalColumnTest(test.TestCase): id_tensor = fc._transform_features_v2({ 'aaa': inputs }, [column], None)[column] - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, -1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) def test_get_sparse_tensors_dense_input(self): column = fc.categorical_column_with_vocabulary_list( @@ -5059,14 +5186,16 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': (('marlo', ''), ('skywalker', 'omar')) }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=np.array((2, -1, 0), dtype=np.int64), - dense_shape=(2, 2)), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1)), + values=np.array((2, -1, 0), dtype=np.int64), + dense_shape=(2, 2)), self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_default_value_in_vocabulary(self): column = fc.categorical_column_with_vocabulary_list( @@ -5082,14 +5211,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, 2, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, 2, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_list( @@ -5105,14 +5237,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, 33, 0, 62), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, 33, 0, 62), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_int32(self): column = fc.categorical_column_with_vocabulary_list( @@ -5128,14 +5263,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, -1, 0, 4), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, -1, 0, 4), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_int32_dense_input(self): default_value = -100 @@ -5151,14 +5289,16 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dtype=np.int32) }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1), (2, 2)), - values=np.array((2, default_value, 0, 4), dtype=np.int64), - dense_shape=(3, 3)), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1), (2, 2)), + values=np.array((2, default_value, 0, 4), dtype=np.int64), + dense_shape=(3, 3)), self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_int32_with_oov_buckets(self): column = fc.categorical_column_with_vocabulary_list( @@ -5175,14 +5315,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((2, 60, 0, 4), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((2, 60, 0, 4), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_linear_model(self): wire_column = fc.categorical_column_with_vocabulary_list( @@ -5200,15 +5343,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)) }) wire_var, bias = model.variables - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), - self.evaluate(wire_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - wire_var.assign(((1.,), (2.,), (3.,), (4.,))).eval() - # 'marlo' -> 2: wire_var[2] = 3 - # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 - self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), self.evaluate(wire_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(wire_var.assign(((1.,), (2.,), (3.,), (4.,)))) + # 'marlo' -> 2: wire_var[2] = 3 + # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 + self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) def test_old_linear_model(self): wire_column = fc.categorical_column_with_vocabulary_list( @@ -5226,15 +5371,17 @@ class VocabularyListCategoricalColumnTest(test.TestCase): }, (wire_column,)) bias = get_linear_model_bias() wire_var = get_linear_model_column_var(wire_column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), - self.evaluate(wire_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - wire_var.assign(((1.,), (2.,), (3.,), (4.,))).eval() - # 'marlo' -> 2: wire_var[2] = 3 - # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 - self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,), (0.,)), self.evaluate(wire_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(wire_var.assign(((1.,), (2.,), (3.,), (4.,)))) + # 'marlo' -> 2: wire_var[2] = 3 + # 'skywalker' -> 3, 'omar' -> 0: wire_var[3] + wire_var[0] = 4+1 = 5 + self.assertAllClose(((3.,), (5.,)), self.evaluate(predictions)) def test_serialization(self): wire_column = fc.categorical_column_with_vocabulary_list( @@ -5257,7 +5404,6 @@ class VocabularyListCategoricalColumnTest(test.TestCase): fc.VocabularyListCategoricalColumn._from_config(config)) - class IdentityCategoricalColumnTest(test.TestCase): def test_constructor(self): @@ -5315,61 +5461,63 @@ class IdentityCategoricalColumnTest(test.TestCase): def test_parse_example(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=30) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(int64_list=feature_pb2.Int64List( - value=[11, 21])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + int64_list=feature_pb2.Int64List(value=[11, 21])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([11, 21], dtype=np.int64), - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([11, 21], dtype=np.int64), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) def test_get_sparse_tensors(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=(0, 1, 0), - dense_shape=(2, 2)) + indices=((0, 0), (1, 0), (1, 1)), values=(0, 1, 0), dense_shape=(2, 2)) id_weight_pair = column.get_sparse_tensors( fc.FeatureTransformationCache({ 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((0, 1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((0, 1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_transform_feature(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=(0, 1, 0), - dense_shape=(2, 2)) + indices=((0, 0), (1, 0), (1, 1)), values=(0, 1, 0), dense_shape=(2, 2)) id_tensor = fc._transform_features_v2({ 'aaa': inputs }, [column], None)[column] - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((0, 1, 0), dtype=np.int64), - dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((0, 1, 0), dtype=np.int64), + dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) def test_get_sparse_tensors_dense_input(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) @@ -5378,46 +5526,49 @@ class IdentityCategoricalColumnTest(test.TestCase): 'aaa': ((0, -1), (1, 0)) }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=np.array((0, 1, 0), dtype=np.int64), - dense_shape=(2, 2)), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1)), + values=np.array((0, 1, 0), dtype=np.int64), + dense_shape=(2, 2)), self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_with_inputs_too_small(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=(1, -1, 0), - dense_shape=(2, 2)) + indices=((0, 0), (1, 0), (1, 1)), values=(1, -1, 0), dense_shape=(2, 2)) id_weight_pair = column.get_sparse_tensors( fc.FeatureTransformationCache({ 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - with self.assertRaisesRegexp( - errors.OpError, 'assert_greater_or_equal_0'): - id_weight_pair.id_tensor.eval() + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + with self.assertRaisesRegexp(errors.OpError, 'assert_greater_or_equal_0'): + self.evaluate(id_weight_pair.id_tensor) def test_get_sparse_tensors_with_inputs_too_big(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) inputs = sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=(1, 99, 0), - dense_shape=(2, 2)) + indices=((0, 0), (1, 0), (1, 1)), values=(1, 99, 0), dense_shape=(2, 2)) id_weight_pair = column.get_sparse_tensors( fc.FeatureTransformationCache({ 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - with self.assertRaisesRegexp( - errors.OpError, 'assert_less_than_num_buckets'): - id_weight_pair.id_tensor.eval() + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + with self.assertRaisesRegexp(errors.OpError, + 'assert_less_than_num_buckets'): + self.evaluate(id_weight_pair.id_tensor) def test_get_sparse_tensors_with_default_value(self): column = fc.categorical_column_with_identity( @@ -5431,14 +5582,17 @@ class IdentityCategoricalColumnTest(test.TestCase): 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array((1, 3, 3), dtype=np.int64), - dense_shape=inputs.dense_shape), - id_weight_pair.id_tensor.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array((1, 3, 3), dtype=np.int64), + dense_shape=inputs.dense_shape), + self.evaluate(id_weight_pair.id_tensor)) def test_get_sparse_tensors_with_default_value_and_placeholder_inputs(self): column = fc.categorical_column_with_identity( @@ -5447,14 +5601,15 @@ class IdentityCategoricalColumnTest(test.TestCase): input_values = array_ops.placeholder(dtype=dtypes.int32) input_shape = array_ops.placeholder(dtype=dtypes.int64) inputs = sparse_tensor.SparseTensorValue( - indices=input_indices, - values=input_values, - dense_shape=input_shape) + indices=input_indices, values=input_values, dense_shape=input_shape) id_weight_pair = column.get_sparse_tensors( fc.FeatureTransformationCache({ 'aaa': inputs }), None) self.assertIsNone(id_weight_pair.weight_tensor) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) with _initialized_session(): _assert_sparse_tensor_value( self, @@ -5462,11 +5617,12 @@ class IdentityCategoricalColumnTest(test.TestCase): indices=np.array(((0, 0), (1, 0), (1, 1)), dtype=np.int64), values=np.array((1, 3, 3), dtype=np.int64), dense_shape=np.array((2, 2), dtype=np.int64)), - id_weight_pair.id_tensor.eval(feed_dict={ - input_indices: ((0, 0), (1, 0), (1, 1)), - input_values: (1, -1, 99), - input_shape: (2, 2), - })) + id_weight_pair.id_tensor.eval( + feed_dict={ + input_indices: ((0, 0), (1, 0), (1, 1)), + input_values: (1, -1, 99), + input_shape: (2, 2), + })) def test_linear_model(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) @@ -5481,14 +5637,17 @@ class IdentityCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)) }) weight_var, bias = model.variables - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] = 1 - # weight_var[2] + weight_var[1] = 3+2 = 5 - self.assertAllClose(((1.,), (5.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] = 1 + # weight_var[2] + weight_var[1] = 3+2 = 5 + self.assertAllClose(((1.,), (5.,)), self.evaluate(predictions)) def test_old_linear_model(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) @@ -5503,14 +5662,17 @@ class IdentityCategoricalColumnTest(test.TestCase): }, (column,)) bias = get_linear_model_bias() weight_var = get_linear_model_column_var(column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] = 1 - # weight_var[2] + weight_var[1] = 3+2 = 5 - self.assertAllClose(((1.,), (5.,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] = 1 + # weight_var[2] + weight_var[1] = 3+2 = 5 + self.assertAllClose(((1.,), (5.,)), self.evaluate(predictions)) def test_serialization(self): column = fc.categorical_column_with_identity(key='aaa', num_buckets=3) @@ -5546,11 +5708,16 @@ class TransformFeaturesTest(test.TestCase): } transformed = fc._transform_features_v2( features, [bucketized_price, hashed_sparse], None) - with _initialized_session(): - self.assertIn(bucketized_price.name, transformed[bucketized_price].name) - self.assertAllEqual([[0], [3]], transformed[bucketized_price].eval()) - self.assertIn(hashed_sparse.name, transformed[hashed_sparse].name) - self.assertAllEqual([6, 4, 1], transformed[hashed_sparse].values.eval()) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertIn(bucketized_price.name, transformed[bucketized_price].name) + self.assertAllEqual([[0], [3]], + self.evaluate(transformed[bucketized_price])) + self.assertIn(hashed_sparse.name, transformed[hashed_sparse].name) + self.assertAllEqual([6, 4, 1], + self.evaluate(transformed[hashed_sparse].values)) def test_column_order(self): """When the column is both dense and sparse, uses sparse tensors.""" @@ -5615,9 +5782,9 @@ class IndicatorColumnTest(test.TestCase): 'animal': ['fox', 'fox'] }) output = transformation_cache.get(animal, None) - with self.cached_session(): - self.assertAllEqual([[0., 0., 1., 0.], [0., 0., 1., 0.]], - self.evaluate(output)) + + self.assertAllEqual([[0., 0., 1., 0.], [0., 0., 1., 0.]], + self.evaluate(output)) def test_2D_shape_succeeds(self): # TODO(ispir/cassandrax): Swith to categorical_column_with_keys when ready. @@ -5631,9 +5798,9 @@ class IndicatorColumnTest(test.TestCase): dense_shape=[2, 1]) }) output = transformation_cache.get(animal, None) - with self.cached_session(): - self.assertAllEqual([[0., 0., 1., 0.], [0., 0., 1., 0.]], - self.evaluate(output)) + + self.assertAllEqual([[0., 0., 1., 0.], [0., 0., 1., 0.]], + self.evaluate(output)) def test_multi_hot(self): animal = fc.indicator_column( @@ -5645,8 +5812,8 @@ class IndicatorColumnTest(test.TestCase): indices=[[0, 0], [0, 1]], values=[1, 1], dense_shape=[1, 2]) }) output = transformation_cache.get(animal, None) - with self.cached_session(): - self.assertAllEqual([[0., 2., 0., 0.]], self.evaluate(output)) + + self.assertAllEqual([[0., 2., 0., 0.]], self.evaluate(output)) def test_multi_hot2(self): animal = fc.indicator_column( @@ -5657,8 +5824,8 @@ class IndicatorColumnTest(test.TestCase): indices=[[0, 0], [0, 1]], values=[1, 2], dense_shape=[1, 2]) }) output = transformation_cache.get(animal, None) - with self.cached_session(): - self.assertAllEqual([[0., 1., 1., 0.]], self.evaluate(output)) + + self.assertAllEqual([[0., 1., 1., 0.]], self.evaluate(output)) def test_deep_copy(self): a = fc.categorical_column_with_hash_bucket('a', 4) @@ -5672,40 +5839,44 @@ class IndicatorColumnTest(test.TestCase): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) a_indicator = fc.indicator_column(a) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a_indicator])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) def test_transform(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) a_indicator = fc.indicator_column(a) features = { - 'aaa': sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=('marlo', 'skywalker', 'omar'), - dense_shape=(2, 2)) + 'aaa': + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1)), + values=('marlo', 'skywalker', 'omar'), + dense_shape=(2, 2)) } indicator_tensor = fc._transform_features_v2(features, [a_indicator], None)[a_indicator] - with _initialized_session(): - self.assertAllEqual([[0, 0, 1], [1, 0, 0]], - self.evaluate(indicator_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual([[0, 0, 1], [1, 0, 0]], self.evaluate(indicator_tensor)) def test_transform_with_weighted_column(self): # Github issue 12557 @@ -5719,8 +5890,11 @@ class IndicatorColumnTest(test.TestCase): } indicator_tensor = fc._transform_features_v2(features, [indicator], None)[indicator] - with _initialized_session(): - self.assertAllEqual([[6., 4., 3.]], self.evaluate(indicator_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual([[6., 4., 3.]], self.evaluate(indicator_tensor)) def test_transform_with_missing_value_in_weighted_column(self): # Github issue 12583 @@ -5734,8 +5908,11 @@ class IndicatorColumnTest(test.TestCase): } indicator_tensor = fc._transform_features_v2(features, [indicator], None)[indicator] - with _initialized_session(): - self.assertAllEqual([[0., 4., 2.]], self.evaluate(indicator_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual([[0., 4., 2.]], self.evaluate(indicator_tensor)) def test_transform_with_missing_value_in_categorical_column(self): # Github issue 12583 @@ -5747,8 +5924,11 @@ class IndicatorColumnTest(test.TestCase): } indicator_tensor = fc._transform_features_v2(features, [indicator], None)[indicator] - with _initialized_session(): - self.assertAllEqual([[0., 1., 1.]], self.evaluate(indicator_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual([[0., 1., 1.]], self.evaluate(indicator_tensor)) def test_linear_model(self): animal = fc.indicator_column( @@ -5763,12 +5943,15 @@ class IndicatorColumnTest(test.TestCase): model = fc.LinearModel([animal]) predictions = model(features) weight_var, _ = model.variables - with _initialized_session(): - # All should be zero-initialized. - self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(weight_var)) - self.assertAllClose([[0.]], self.evaluate(predictions)) - weight_var.assign([[1.], [2.], [3.], [4.]]).eval() - self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # All should be zero-initialized. + self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(weight_var)) + self.assertAllClose([[0.]], self.evaluate(predictions)) + self.evaluate(weight_var.assign([[1.], [2.], [3.], [4.]])) + self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) def test_old_linear_model(self): animal = fc.indicator_column( @@ -5782,12 +5965,15 @@ class IndicatorColumnTest(test.TestCase): predictions = fc_old.linear_model(features, [animal]) weight_var = get_linear_model_column_var(animal) - with _initialized_session(): - # All should be zero-initialized. - self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(weight_var)) - self.assertAllClose([[0.]], self.evaluate(predictions)) - weight_var.assign([[1.], [2.], [3.], [4.]]).eval() - self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # All should be zero-initialized. + self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(weight_var)) + self.assertAllClose([[0.]], self.evaluate(predictions)) + self.evaluate(weight_var.assign([[1.], [2.], [3.], [4.]])) + self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) def test_old_linear_model_old_categorical(self): animal = fc.indicator_column( @@ -5801,12 +5987,15 @@ class IndicatorColumnTest(test.TestCase): predictions = fc_old.linear_model(features, [animal]) weight_var = get_linear_model_column_var(animal) - with _initialized_session(): - # All should be zero-initialized. - self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(weight_var)) - self.assertAllClose([[0.]], self.evaluate(predictions)) - weight_var.assign([[1.], [2.], [3.], [4.]]).eval() - self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # All should be zero-initialized. + self.assertAllClose([[0.], [0.], [0.], [0.]], self.evaluate(weight_var)) + self.assertAllClose([[0.]], self.evaluate(predictions)) + self.evaluate(weight_var.assign([[1.], [2.], [3.], [4.]])) + self.assertAllClose([[2. + 3.]], self.evaluate(predictions)) def test_dense_features(self): animal = fc.indicator_column( @@ -5818,8 +6007,11 @@ class IndicatorColumnTest(test.TestCase): indices=[[0, 0], [0, 1]], values=[1, 2], dense_shape=[1, 2]) } net = fc.DenseFeatures([animal])(features) - with _initialized_session(): - self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) def test_input_layer(self): animal = fc.indicator_column( @@ -5831,8 +6023,11 @@ class IndicatorColumnTest(test.TestCase): indices=[[0, 0], [0, 1]], values=[1, 2], dense_shape=[1, 2]) } net = fc_old.input_layer(features, [animal]) - with _initialized_session(): - self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) def test_input_layer_old_categorical(self): animal = fc.indicator_column( @@ -5844,8 +6039,11 @@ class IndicatorColumnTest(test.TestCase): indices=[[0, 0], [0, 1]], values=[1, 2], dense_shape=[1, 2]) } net = fc_old.input_layer(features, [animal]) - with _initialized_session(): - self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose([[0., 1., 1., 0.]], self.evaluate(net)) def test_serialization(self): parent = fc.categorical_column_with_identity('animal', num_buckets=4) @@ -5875,7 +6073,6 @@ class IndicatorColumnTest(test.TestCase): self.assertIs(parent, new_animal.categorical_column) - class _TestStateManager(fc.StateManager): def __init__(self, trainable=True): @@ -6013,40 +6210,45 @@ class EmbeddingColumnTest(test.TestCase): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) a_embedded = fc.embedding_column(a, dimension=2) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a_embedded])) self.assertIn('aaa', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) def test_transform_feature(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=3) a_embedded = fc.embedding_column(a, dimension=2) features = { - 'aaa': sparse_tensor.SparseTensor( - indices=((0, 0), (1, 0), (1, 1)), - values=(0, 1, 0), - dense_shape=(2, 2)) + 'aaa': + sparse_tensor.SparseTensor( + indices=((0, 0), (1, 0), (1, 1)), + values=(0, 1, 0), + dense_shape=(2, 2)) } outputs = fc._transform_features_v2(features, [a, a_embedded], None) output_a = outputs[a] output_embedded = outputs[a_embedded] - with _initialized_session(): - _assert_sparse_tensor_value(self, self.evaluate(output_a), - self.evaluate(output_embedded)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value(self, self.evaluate(output_a), + self.evaluate(output_embedded)) def test_get_dense_tensor(self): # Inputs. @@ -6067,6 +6269,7 @@ class EmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -6105,9 +6308,12 @@ class EmbeddingColumnTest(test.TestCase): global_vars = ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES) self.assertItemsEqual(('embedding_weights:0',), tuple([v.name for v in global_vars])) - with _initialized_session(): - self.assertAllEqual(embedding_values, global_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) def test_get_dense_tensor_old_categorical(self): # Inputs. @@ -6165,9 +6371,12 @@ class EmbeddingColumnTest(test.TestCase): global_vars = ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES) self.assertItemsEqual(('embedding_weights:0',), tuple([v.name for v in global_vars])) - with _initialized_session(): - self.assertAllEqual(embedding_values, global_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) def test_get_dense_tensor_3d(self): # Inputs. @@ -6184,11 +6393,12 @@ class EmbeddingColumnTest(test.TestCase): # Embedding variable. embedding_dimension = 3 embedding_values = ( - (1., 2., 4.), # id 0 - (3., 5., 1.), # id 1 + (1., 2., 4.), # id 0 + (3., 5., 1.), # id 1 (7., 11., 2.), # id 2 - (2., 7., 12.) # id 3 + (2., 7., 12.) # id 3 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -6228,9 +6438,12 @@ class EmbeddingColumnTest(test.TestCase): global_vars = ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES) self.assertItemsEqual(('embedding_weights:0',), tuple([v.name for v in global_vars])) - with _initialized_session(): - self.assertAllEqual(embedding_values, global_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) def test_get_dense_tensor_placeholder_inputs(self): # Inputs. @@ -6251,6 +6464,7 @@ class EmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -6294,16 +6508,21 @@ class EmbeddingColumnTest(test.TestCase): # Assert expected embedding variable and lookups. global_vars = ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES) - self.assertItemsEqual( - ('embedding_weights:0',), tuple([v.name for v in global_vars])) + self.assertItemsEqual(('embedding_weights:0',), + tuple([v.name for v in global_vars])) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) with _initialized_session(): - self.assertAllEqual(embedding_values, global_vars[0].eval()) - self.assertAllEqual(expected_lookups, embedding_lookup.eval( - feed_dict={ - input_indices: sparse_input.indices, - input_values: sparse_input.values, - input_shape: sparse_input.dense_shape, - })) + self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) + self.assertAllEqual( + expected_lookups, + embedding_lookup.eval( + feed_dict={ + input_indices: sparse_input.indices, + input_values: sparse_input.values, + input_shape: sparse_input.dense_shape, + })) def test_get_dense_tensor_restore_from_ckpt(self): # Inputs. @@ -6359,11 +6578,14 @@ class EmbeddingColumnTest(test.TestCase): # Assert expected embedding variable and lookups. global_vars = ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES) - self.assertItemsEqual( - ('embedding_weights:0',), tuple([v.name for v in global_vars])) - with _initialized_session(): - self.assertAllEqual(embedding_values, global_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) + self.assertItemsEqual(('embedding_weights:0',), + tuple([v.name for v in global_vars])) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(embedding_lookup)) def test_linear_model(self): # Inputs. @@ -6382,6 +6604,7 @@ class EmbeddingColumnTest(test.TestCase): embedding_dimension = 2 embedding_shape = (vocabulary_size, embedding_dimension) zeros_embedding_values = np.zeros(embedding_shape) + def _initializer(shape, dtype, partition_info): self.assertAllEqual(embedding_shape, shape) self.assertEqual(dtypes.float32, dtype) @@ -6408,39 +6631,42 @@ class EmbeddingColumnTest(test.TestCase): expected_var_names, [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) trainable_vars = { - v.name: v for v in ops.get_collection( - ops.GraphKeys.TRAINABLE_VARIABLES) + v.name: v + for v in ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES) } self.assertItemsEqual(expected_var_names, trainable_vars.keys()) bias = trainable_vars['linear_model/bias_weights:0'] embedding_weights = trainable_vars[ 'linear_model/aaa_embedding/embedding_weights:0'] linear_weights = trainable_vars['linear_model/aaa_embedding/weights:0'] - with _initialized_session(): - # Predictions with all zero weights. - self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) - self.assertAllClose(zeros_embedding_values, - self.evaluate(embedding_weights)) - self.assertAllClose( - np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights)) - self.assertAllClose( - np.zeros((batch_size, 1)), self.evaluate(predictions)) - - # Predictions with all non-zero weights. - embedding_weights.assign(( - (1., 2.), # id 0 - (3., 5.), # id 1 - (7., 11.) # id 2 - )).eval() - linear_weights.assign(((4.,), (6.,))).eval() - # example 0, ids [2], embedding[0] = [7, 11] - # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] - # example 2, ids [], embedding[2] = [0, 0] - # example 3, ids [1], embedding[3] = [3, 5] - # sum(embeddings * linear_weights) - # = [4*7 + 6*11, 4*2 + 6*3.5, 4*0 + 6*0, 4*3 + 6*5] = [94, 29, 0, 42] - self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), - self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # Predictions with all zero weights. + self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) + self.assertAllClose(zeros_embedding_values, + self.evaluate(embedding_weights)) + self.assertAllClose( + np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights)) + self.assertAllClose(np.zeros((batch_size, 1)), self.evaluate(predictions)) + + # Predictions with all non-zero weights. + self.evaluate( + embedding_weights.assign(( + (1., 2.), # id 0 + (3., 5.), # id 1 + (7., 11.) # id 2 + ))) + self.evaluate(linear_weights.assign(((4.,), (6.,)))) + # example 0, ids [2], embedding[0] = [7, 11] + # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] + # example 2, ids [], embedding[2] = [0, 0] + # example 3, ids [1], embedding[3] = [3, 5] + # sum(embeddings * linear_weights) + # = [4*7 + 6*11, 4*2 + 6*3.5, 4*0 + 6*0, 4*3 + 6*5] = [94, 29, 0, 42] + self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), + self.evaluate(predictions)) def test_dense_features(self): # Inputs. @@ -6461,6 +6687,7 @@ class EmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -6500,9 +6727,12 @@ class EmbeddingColumnTest(test.TestCase): trainable_vars = ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES) self.assertItemsEqual(('dense_features/aaa_embedding/embedding_weights:0',), tuple([v.name for v in trainable_vars])) - with _initialized_session(): - self.assertAllEqual(embedding_values, trainable_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(trainable_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) def test_dense_features_not_trainable(self): # Inputs. @@ -6523,6 +6753,7 @@ class EmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -6559,11 +6790,14 @@ class EmbeddingColumnTest(test.TestCase): global_vars = ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES) self.assertItemsEqual(('dense_features/aaa_embedding/embedding_weights:0',), tuple([v.name for v in global_vars])) - self.assertItemsEqual( - [], ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)) - with _initialized_session(): - self.assertAllEqual(embedding_values, global_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) + self.assertItemsEqual([], + ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(global_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) def test_input_layer(self): # Inputs. @@ -6623,9 +6857,12 @@ class EmbeddingColumnTest(test.TestCase): trainable_vars = ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES) self.assertItemsEqual(('input_layer/aaa_embedding/embedding_weights:0',), tuple([v.name for v in trainable_vars])) - with _initialized_session(): - self.assertAllEqual(embedding_values, trainable_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(feature_layer)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(trainable_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(feature_layer)) def test_old_linear_model(self): # Inputs. @@ -6680,31 +6917,34 @@ class EmbeddingColumnTest(test.TestCase): embedding_weights = trainable_vars[ 'linear_model/aaa_embedding/embedding_weights:0'] linear_weights = trainable_vars['linear_model/aaa_embedding/weights:0'] - with _initialized_session(): - # Predictions with all zero weights. - self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) - self.assertAllClose(zeros_embedding_values, - self.evaluate(embedding_weights)) - self.assertAllClose( - np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights)) - self.assertAllClose( - np.zeros((batch_size, 1)), self.evaluate(predictions)) - - # Predictions with all non-zero weights. - embedding_weights.assign(( - (1., 2.), # id 0 - (3., 5.), # id 1 - (7., 11.) # id 2 - )).eval() - linear_weights.assign(((4.,), (6.,))).eval() - # example 0, ids [2], embedding[0] = [7, 11] - # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] - # example 2, ids [], embedding[2] = [0, 0] - # example 3, ids [1], embedding[3] = [3, 5] - # sum(embeddings * linear_weights) - # = [4*7 + 6*11, 4*2 + 6*3.5, 4*0 + 6*0, 4*3 + 6*5] = [94, 29, 0, 42] - self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), - self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # Predictions with all zero weights. + self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) + self.assertAllClose(zeros_embedding_values, + self.evaluate(embedding_weights)) + self.assertAllClose( + np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights)) + self.assertAllClose(np.zeros((batch_size, 1)), self.evaluate(predictions)) + + # Predictions with all non-zero weights. + self.evaluate( + embedding_weights.assign(( + (1., 2.), # id 0 + (3., 5.), # id 1 + (7., 11.) # id 2 + ))) + self.evaluate(linear_weights.assign(((4.,), (6.,)))) + # example 0, ids [2], embedding[0] = [7, 11] + # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] + # example 2, ids [], embedding[2] = [0, 0] + # example 3, ids [1], embedding[3] = [3, 5] + # sum(embeddings * linear_weights) + # = [4*7 + 6*11, 4*2 + 6*3.5, 4*0 + 6*0, 4*3 + 6*5] = [94, 29, 0, 42] + self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), + self.evaluate(predictions)) def test_old_linear_model_old_categorical(self): # Inputs. @@ -6759,31 +6999,34 @@ class EmbeddingColumnTest(test.TestCase): embedding_weights = trainable_vars[ 'linear_model/aaa_embedding/embedding_weights:0'] linear_weights = trainable_vars['linear_model/aaa_embedding/weights:0'] - with _initialized_session(): - # Predictions with all zero weights. - self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) - self.assertAllClose(zeros_embedding_values, - self.evaluate(embedding_weights)) - self.assertAllClose( - np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights)) - self.assertAllClose( - np.zeros((batch_size, 1)), self.evaluate(predictions)) - - # Predictions with all non-zero weights. - embedding_weights.assign(( - (1., 2.), # id 0 - (3., 5.), # id 1 - (7., 11.) # id 2 - )).eval() - linear_weights.assign(((4.,), (6.,))).eval() - # example 0, ids [2], embedding[0] = [7, 11] - # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] - # example 2, ids [], embedding[2] = [0, 0] - # example 3, ids [1], embedding[3] = [3, 5] - # sum(embeddings * linear_weights) - # = [4*7 + 6*11, 4*2 + 6*3.5, 4*0 + 6*0, 4*3 + 6*5] = [94, 29, 0, 42] - self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), - self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # Predictions with all zero weights. + self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) + self.assertAllClose(zeros_embedding_values, + self.evaluate(embedding_weights)) + self.assertAllClose( + np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights)) + self.assertAllClose(np.zeros((batch_size, 1)), self.evaluate(predictions)) + + # Predictions with all non-zero weights. + self.evaluate( + embedding_weights.assign(( + (1., 2.), # id 0 + (3., 5.), # id 1 + (7., 11.) # id 2 + ))) + self.evaluate(linear_weights.assign(((4.,), (6.,)))) + # example 0, ids [2], embedding[0] = [7, 11] + # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] + # example 2, ids [], embedding[2] = [0, 0] + # example 3, ids [1], embedding[3] = [3, 5] + # sum(embeddings * linear_weights) + # = [4*7 + 6*11, 4*2 + 6*3.5, 4*0 + 6*0, 4*3 + 6*5] = [94, 29, 0, 42] + self.assertAllClose(((94.,), (29.,), (0.,), (42.,)), + self.evaluate(predictions)) def test_serialization(self): @@ -6972,49 +7215,52 @@ class SharedEmbeddingColumnTest(test.TestCase): b = fc.categorical_column_with_vocabulary_list( key='bbb', vocabulary_list=('omar', 'stringer', 'marlo')) a_embedded, b_embedded = fc.shared_embedding_columns_v2([a, b], dimension=2) - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])), - 'bbb': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'stringer', b'marlo'])), - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])), + 'bbb': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'stringer', b'marlo'])), + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a_embedded, b_embedded])) self.assertIn('aaa', features) self.assertIn('bbb', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'stringer', b'marlo'], dtype=np.object_), - dense_shape=[1, 2]), - features['bbb'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'stringer', b'marlo'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['bbb'])) def test_transform_feature(self): a = fc.categorical_column_with_identity(key='aaa', num_buckets=3) b = fc.categorical_column_with_identity(key='bbb', num_buckets=3) a_embedded, b_embedded = fc.shared_embedding_columns_v2([a, b], dimension=2) features = { - 'aaa': sparse_tensor.SparseTensor( - indices=((0, 0), (1, 0), (1, 1)), - values=(0, 1, 0), - dense_shape=(2, 2)), - 'bbb': sparse_tensor.SparseTensor( - indices=((0, 0), (1, 0), (1, 1)), - values=(1, 2, 1), - dense_shape=(2, 2)), + 'aaa': + sparse_tensor.SparseTensor( + indices=((0, 0), (1, 0), (1, 1)), + values=(0, 1, 0), + dense_shape=(2, 2)), + 'bbb': + sparse_tensor.SparseTensor( + indices=((0, 0), (1, 0), (1, 1)), + values=(1, 2, 1), + dense_shape=(2, 2)), } outputs = fc._transform_features_v2(features, [a, a_embedded, b, b_embedded], None) @@ -7022,26 +7268,28 @@ class SharedEmbeddingColumnTest(test.TestCase): output_a_embedded = outputs[a_embedded] output_b = outputs[b] output_b_embedded = outputs[b_embedded] - with _initialized_session(): - _assert_sparse_tensor_value(self, self.evaluate(output_a), - self.evaluate(output_a_embedded)) - _assert_sparse_tensor_value(self, self.evaluate(output_b), - self.evaluate(output_b_embedded)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value(self, self.evaluate(output_a), + self.evaluate(output_a_embedded)) + _assert_sparse_tensor_value(self, self.evaluate(output_b), + self.evaluate(output_b_embedded)) def test_get_dense_tensor(self): # Inputs. vocabulary_size = 3 # -1 values are ignored. - input_a = np.array( - [[2, -1, -1], # example 0, ids [2] - [0, 1, -1]]) # example 1, ids [0, 1] - input_b = np.array( - [[0, -1, -1], # example 0, ids [0] - [-1, -1, -1]]) # example 1, ids [] - input_features = { - 'aaa': input_a, - 'bbb': input_b - } + input_a = np.array([ + [2, -1, -1], # example 0, ids [2] + [0, 1, -1] + ]) # example 1, ids [0, 1] + input_b = np.array([ + [0, -1, -1], # example 0, ids [0] + [-1, -1, -1] + ]) # example 1, ids [] + input_features = {'aaa': input_a, 'bbb': input_b} # Embedding variable. embedding_dimension = 2 @@ -7050,6 +7298,7 @@ class SharedEmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -7091,21 +7340,26 @@ class SharedEmbeddingColumnTest(test.TestCase): self.assertItemsEqual(('aaa_bbb_shared_embedding:0',), tuple([v.name for v in global_vars])) embedding_var = global_vars[0] - with _initialized_session(): - self.assertAllEqual(embedding_values, self.evaluate(embedding_var)) - self.assertAllEqual(expected_lookups_a, self.evaluate(embedding_lookup_a)) - self.assertAllEqual(expected_lookups_b, self.evaluate(embedding_lookup_b)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, self.evaluate(embedding_var)) + self.assertAllEqual(expected_lookups_a, self.evaluate(embedding_lookup_a)) + self.assertAllEqual(expected_lookups_b, self.evaluate(embedding_lookup_b)) def test_get_dense_tensor_placeholder_inputs(self): # Inputs. vocabulary_size = 3 # -1 values are ignored. - input_a = np.array( - [[2, -1, -1], # example 0, ids [2] - [0, 1, -1]]) # example 1, ids [0, 1] - input_b = np.array( - [[0, -1, -1], # example 0, ids [0] - [-1, -1, -1]]) # example 1, ids [] + input_a = np.array([ + [2, -1, -1], # example 0, ids [2] + [0, 1, -1] + ]) # example 1, ids [0, 1] + input_b = np.array([ + [0, -1, -1], # example 0, ids [0] + [-1, -1, -1] + ]) # example 1, ids [] # Specify shape, because dense input must have rank specified. input_a_placeholder = array_ops.placeholder( dtype=dtypes.int64, shape=[None, 3]) @@ -7127,6 +7381,7 @@ class SharedEmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -7157,17 +7412,20 @@ class SharedEmbeddingColumnTest(test.TestCase): batch_size = 2 vocabulary_size = 3 # -1 values are ignored. - input_a = np.array( - [[2, -1, -1], # example 0, ids [2] - [0, 1, -1]]) # example 1, ids [0, 1] - input_b = np.array( - [[0, -1, -1], # example 0, ids [0] - [-1, -1, -1]]) # example 1, ids [] + input_a = np.array([ + [2, -1, -1], # example 0, ids [2] + [0, 1, -1] + ]) # example 1, ids [0, 1] + input_b = np.array([ + [0, -1, -1], # example 0, ids [0] + [-1, -1, -1] + ]) # example 1, ids [] # Embedding variable. embedding_dimension = 2 embedding_shape = (vocabulary_size, embedding_dimension) zeros_embedding_values = np.zeros(embedding_shape) + def _initializer(shape, dtype, partition_info): self.assertAllEqual(embedding_shape, shape) self.assertEqual(dtypes.float32, dtype) @@ -7203,8 +7461,8 @@ class SharedEmbeddingColumnTest(test.TestCase): expected_var_names, [v.name for v in ops.get_collection(ops.GraphKeys.GLOBAL_VARIABLES)]) trainable_vars = { - v.name: v for v in ops.get_collection( - ops.GraphKeys.TRAINABLE_VARIABLES) + v.name: v + for v in ops.get_collection(ops.GraphKeys.TRAINABLE_VARIABLES) } self.assertItemsEqual(expected_var_names, trainable_vars.keys()) bias = trainable_vars['linear_model/bias_weights:0'] @@ -7213,35 +7471,38 @@ class SharedEmbeddingColumnTest(test.TestCase): 'linear_model/aaa_shared_embedding/weights:0'] linear_weights_b = trainable_vars[ 'linear_model/bbb_shared_embedding/weights:0'] - with _initialized_session(): - # Predictions with all zero weights. - self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) - self.assertAllClose(zeros_embedding_values, - self.evaluate(embedding_weights)) - self.assertAllClose( - np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights_a)) - self.assertAllClose( - np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights_b)) - self.assertAllClose( - np.zeros((batch_size, 1)), self.evaluate(predictions)) - - # Predictions with all non-zero weights. - embedding_weights.assign(( - (1., 2.), # id 0 - (3., 5.), # id 1 - (7., 11.) # id 2 - )).eval() - linear_weights_a.assign(((4.,), (6.,))).eval() - # example 0, ids [2], embedding[0] = [7, 11] - # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] - # sum(embeddings * linear_weights) - # = [4*7 + 6*11, 4*2 + 6*3.5] = [94, 29] - linear_weights_b.assign(((3.,), (5.,))).eval() - # example 0, ids [0], embedding[0] = [1, 2] - # example 1, ids [], embedding[1] = 0, 0] - # sum(embeddings * linear_weights) - # = [3*1 + 5*2, 3*0 +5*0] = [13, 0] - self.assertAllClose([[94. + 13.], [29.]], self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + # Predictions with all zero weights. + self.assertAllClose(np.zeros((1,)), self.evaluate(bias)) + self.assertAllClose(zeros_embedding_values, + self.evaluate(embedding_weights)) + self.assertAllClose( + np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights_a)) + self.assertAllClose( + np.zeros((embedding_dimension, 1)), self.evaluate(linear_weights_b)) + self.assertAllClose(np.zeros((batch_size, 1)), self.evaluate(predictions)) + + # Predictions with all non-zero weights. + self.evaluate( + embedding_weights.assign(( + (1., 2.), # id 0 + (3., 5.), # id 1 + (7., 11.) # id 2 + ))) + self.evaluate(linear_weights_a.assign(((4.,), (6.,)))) + # example 0, ids [2], embedding[0] = [7, 11] + # example 1, ids [0, 1], embedding[1] = mean([1, 2] + [3, 5]) = [2, 3.5] + # sum(embeddings * linear_weights) + # = [4*7 + 6*11, 4*2 + 6*3.5] = [94, 29] + self.evaluate(linear_weights_b.assign(((3.,), (5.,)))) + # example 0, ids [0], embedding[0] = [1, 2] + # example 1, ids [], embedding[1] = 0, 0] + # sum(embeddings * linear_weights) + # = [3*1 + 5*2, 3*0 +5*0] = [13, 0] + self.assertAllClose([[94. + 13.], [29.]], self.evaluate(predictions)) def _test_dense_features(self, trainable=True): # Inputs. @@ -7278,6 +7539,7 @@ class SharedEmbeddingColumnTest(test.TestCase): (3., 5.), # id 1 (7., 11.) # id 2 ) + def _initializer(shape, dtype, partition_info): self.assertAllEqual((vocabulary_size, embedding_dimension), shape) self.assertEqual(dtypes.float32, dtype) @@ -7349,9 +7611,13 @@ class SharedEmbeddingColumnTest(test.TestCase): else: self.assertItemsEqual([], tuple([v.name for v in trainable_vars])) shared_embedding_vars = global_vars - with _initialized_session(): - self.assertAllEqual(embedding_values, shared_embedding_vars[0].eval()) - self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllEqual(embedding_values, + self.evaluate(shared_embedding_vars[0])) + self.assertAllEqual(expected_lookups, self.evaluate(dense_features)) def test_dense_features(self): self._test_dense_features() @@ -7379,7 +7645,6 @@ class SharedEmbeddingColumnTest(test.TestCase): # TODO(rohanj): Add tests for (from|get)_config once implemented - class WeightedCategoricalColumnTest(test.TestCase): def test_defaults(self): @@ -7463,43 +7728,43 @@ class WeightedCategoricalColumnTest(test.TestCase): indices=((0, 0), (1, 0), (1, 1)), values=('omar', 'stringer', 'marlo'), dense_shape=(2, 2)) - with self.assertRaisesRegexp( - ValueError, 'values is not in features dictionary'): + with self.assertRaisesRegexp(ValueError, + 'values is not in features dictionary'): fc._transform_features_v2({'ids': inputs}, (column,), None) def test_parse_example(self): a = fc.categorical_column_with_vocabulary_list( key='aaa', vocabulary_list=('omar', 'stringer', 'marlo')) a_weighted = fc.weighted_categorical_column(a, weight_feature_key='weights') - data = example_pb2.Example(features=feature_pb2.Features( - feature={ - 'aaa': - feature_pb2.Feature(bytes_list=feature_pb2.BytesList( - value=[b'omar', b'stringer'])), - 'weights': - feature_pb2.Feature(float_list=feature_pb2.FloatList( - value=[1., 10.])) - })) + data = example_pb2.Example( + features=feature_pb2.Features( + feature={ + 'aaa': + feature_pb2.Feature( + bytes_list=feature_pb2.BytesList( + value=[b'omar', b'stringer'])), + 'weights': + feature_pb2.Feature( + float_list=feature_pb2.FloatList(value=[1., 10.])) + })) features = parsing_ops.parse_example( serialized=[data.SerializeToString()], features=fc.make_parse_example_spec_v2([a_weighted])) self.assertIn('aaa', features) self.assertIn('weights', features) - with self.cached_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([b'omar', b'stringer'], dtype=np.object_), - dense_shape=[1, 2]), - features['aaa'].eval()) - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=[[0, 0], [0, 1]], - values=np.array([1., 10.], dtype=np.float32), - dense_shape=[1, 2]), - features['weights'].eval()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([b'omar', b'stringer'], dtype=np.object_), + dense_shape=[1, 2]), self.evaluate(features['aaa'])) + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=[[0, 0], [0, 1]], + values=np.array([1., 10.], dtype=np.float32), + dense_shape=[1, 2]), self.evaluate(features['weights'])) def test_transform_features(self): column = fc.weighted_categorical_column( @@ -7507,9 +7772,7 @@ class WeightedCategoricalColumnTest(test.TestCase): key='ids', num_buckets=3), weight_feature_key='values') inputs = sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=(0, 1, 0), - dense_shape=(2, 2)) + indices=((0, 0), (1, 0), (1, 1)), values=(0, 1, 0), dense_shape=(2, 2)) weights = sparse_tensor.SparseTensorValue( indices=((0, 0), (1, 0), (1, 1)), values=(0.5, 1.0, 0.1), @@ -7518,19 +7781,22 @@ class WeightedCategoricalColumnTest(test.TestCase): 'ids': inputs, 'values': weights, }, (column,), None)[column] - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array(inputs.values, dtype=np.int64), - dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=weights.indices, - values=np.array(weights.values, dtype=np.float32), - dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array(inputs.values, dtype=np.int64), + dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=weights.indices, + values=np.array(weights.values, dtype=np.float32), + dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) def test_transform_features_dense_input(self): column = fc.weighted_categorical_column( @@ -7545,19 +7811,22 @@ class WeightedCategoricalColumnTest(test.TestCase): 'ids': ((0, -1), (1, 0)), 'values': weights, }, (column,), None)[column] - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=np.array((0, 1, 0), dtype=np.int64), - dense_shape=(2, 2)), self.evaluate(id_tensor)) - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=weights.indices, - values=np.array(weights.values, dtype=np.float32), - dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1)), + values=np.array((0, 1, 0), dtype=np.int64), + dense_shape=(2, 2)), self.evaluate(id_tensor)) + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=weights.indices, + values=np.array(weights.values, dtype=np.float32), + dense_shape=weights.dense_shape), self.evaluate(weight_tensor)) def test_transform_features_dense_weights(self): column = fc.weighted_categorical_column( @@ -7565,26 +7834,27 @@ class WeightedCategoricalColumnTest(test.TestCase): key='ids', num_buckets=3), weight_feature_key='values') inputs = sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=(2, 1, 0), - dense_shape=(2, 2)) + indices=((0, 0), (1, 0), (1, 1)), values=(2, 1, 0), dense_shape=(2, 2)) id_tensor, weight_tensor = fc._transform_features_v2({ 'ids': inputs, 'values': ((.5, 0.), (1., .1)), }, (column,), None)[column] - with _initialized_session(): - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=inputs.indices, - values=np.array(inputs.values, dtype=np.int64), - dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) - _assert_sparse_tensor_value( - self, - sparse_tensor.SparseTensorValue( - indices=((0, 0), (1, 0), (1, 1)), - values=np.array((.5, 1., .1), dtype=np.float32), - dense_shape=(2, 2)), self.evaluate(weight_tensor)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=inputs.indices, + values=np.array(inputs.values, dtype=np.int64), + dense_shape=inputs.dense_shape), self.evaluate(id_tensor)) + _assert_sparse_tensor_value( + self, + sparse_tensor.SparseTensorValue( + indices=((0, 0), (1, 0), (1, 1)), + values=np.array((.5, 1., .1), dtype=np.float32), + dense_shape=(2, 2)), self.evaluate(weight_tensor)) def test_linear_model(self): column = fc.weighted_categorical_column( @@ -7606,15 +7876,18 @@ class WeightedCategoricalColumnTest(test.TestCase): dense_shape=(2, 2)) }) weight_var, bias = model.variables - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] * weights[0, 0] = 1 * .5 = .5 - # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] - # = 3*1 + 2*.1 = 3+.2 = 3.2 - self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] * weights[0, 0] = 1 * .5 = .5 + # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] + # = 3*1 + 2*.1 = 3+.2 = 3.2 + self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) def test_linear_model_mismatched_shape(self): column = fc.weighted_categorical_column( @@ -7678,15 +7951,18 @@ class WeightedCategoricalColumnTest(test.TestCase): 'values': ((.5,), (1.,), (.1,)) }) weight_var, bias = model.variables - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] * weights[0, 0] = 1 * .5 = .5 - # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] - # = 3*1 + 2*.1 = 3+.2 = 3.2 - self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] * weights[0, 0] = 1 * .5 = .5 + # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] + # = 3*1 + 2*.1 = 3+.2 = 3.2 + self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) def test_old_linear_model(self): column = fc.weighted_categorical_column( @@ -7708,15 +7984,18 @@ class WeightedCategoricalColumnTest(test.TestCase): }, (column,)) bias = get_linear_model_bias() weight_var = get_linear_model_column_var(column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] * weights[0, 0] = 1 * .5 = .5 - # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] - # = 3*1 + 2*.1 = 3+.2 = 3.2 - self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] * weights[0, 0] = 1 * .5 = .5 + # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] + # = 3*1 + 2*.1 = 3+.2 = 3.2 + self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) def test_old_linear_model_mismatched_shape(self): column = fc.weighted_categorical_column( @@ -7779,15 +8058,18 @@ class WeightedCategoricalColumnTest(test.TestCase): }, (column,)) bias = get_linear_model_bias() weight_var = get_linear_model_column_var(column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] * weights[0, 0] = 1 * .5 = .5 - # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] - # = 3*1 + 2*.1 = 3+.2 = 3.2 - self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] * weights[0, 0] = 1 * .5 = .5 + # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] + # = 3*1 + 2*.1 = 3+.2 = 3.2 + self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) def test_old_linear_model_old_categorical(self): column = fc.weighted_categorical_column( @@ -7809,15 +8091,18 @@ class WeightedCategoricalColumnTest(test.TestCase): }, (column,)) bias = get_linear_model_bias() weight_var = get_linear_model_column_var(column) - with _initialized_session(): - self.assertAllClose((0.,), self.evaluate(bias)) - self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) - self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) - weight_var.assign(((1.,), (2.,), (3.,))).eval() - # weight_var[0] * weights[0, 0] = 1 * .5 = .5 - # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] - # = 3*1 + 2*.1 = 3+.2 = 3.2 - self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) + + self.evaluate(variables_lib.global_variables_initializer()) + self.evaluate(lookup_ops.tables_initializer()) + + self.assertAllClose((0.,), self.evaluate(bias)) + self.assertAllClose(((0.,), (0.,), (0.,)), self.evaluate(weight_var)) + self.assertAllClose(((0.,), (0.,)), self.evaluate(predictions)) + self.evaluate(weight_var.assign(((1.,), (2.,), (3.,)))) + # weight_var[0] * weights[0, 0] = 1 * .5 = .5 + # weight_var[2] * weights[1, 0] + weight_var[1] * weights[1, 1] + # = 3*1 + 2*.1 = 3+.2 = 3.2 + self.assertAllClose(((.5,), (3.2,)), self.evaluate(predictions)) # TODO(ptucker): Add test with embedding of weighted categorical. -- GitLab From 5916a9f0e4b5b2c4f80767ff83a001a6f86b4395 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 18:39:40 -0800 Subject: [PATCH 516/672] tf.lite.abs support PiperOrigin-RevId: 223273635 --- tensorflow/lite/build_def.bzl | 1 + tensorflow/lite/g3doc/tf_ops_compatibility.md | 11 +++++++++ tensorflow/lite/kernels/elementwise.cc | 13 ++++++++++ tensorflow/lite/kernels/elementwise_test.cc | 13 ++++++++++ tensorflow/lite/kernels/register.cc | 2 ++ tensorflow/lite/testing/generate_examples.py | 24 +++++++++++++++++++ .../propagate_fixed_sizes.cc | 1 + tensorflow/lite/toco/import_tensorflow.cc | 1 + tensorflow/lite/toco/model.h | 14 ++++++++++- tensorflow/lite/toco/tflite/export.cc | 1 - tensorflow/lite/toco/tflite/operator.cc | 4 +++- tensorflow/lite/toco/tooling_util.cc | 1 + 12 files changed, 83 insertions(+), 3 deletions(-) diff --git a/tensorflow/lite/build_def.bzl b/tensorflow/lite/build_def.bzl index 4a49c14cc9..3a31144593 100644 --- a/tensorflow/lite/build_def.bzl +++ b/tensorflow/lite/build_def.bzl @@ -221,6 +221,7 @@ def json_to_tflite(name, src, out): # generated_test_models_failing(). def generated_test_models(): return [ + "abs", "add", "arg_min_max", "avg_pool", diff --git a/tensorflow/lite/g3doc/tf_ops_compatibility.md b/tensorflow/lite/g3doc/tf_ops_compatibility.md index 2864c6aaf4..a96f64cefe 100644 --- a/tensorflow/lite/g3doc/tf_ops_compatibility.md +++ b/tensorflow/lite/g3doc/tf_ops_compatibility.md @@ -139,6 +139,17 @@ following common ops are not supported at the moment: The following TensorFlow Lite operations are fully supported and used in place of the TensorFlow operations listed above: +**ABS** + +``` +Inputs { + 0: a tensor +} +Outputs { + 0: elementwise abs of the input +} +``` + **ADD** ``` diff --git a/tensorflow/lite/kernels/elementwise.cc b/tensorflow/lite/kernels/elementwise.cc index 416a69eb0e..a79388b900 100644 --- a/tensorflow/lite/kernels/elementwise.cc +++ b/tensorflow/lite/kernels/elementwise.cc @@ -15,6 +15,7 @@ limitations under the License. #include #include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/kernels/internal/reference/reference_ops.h" #include "tensorflow/lite/kernels/internal/tensor.h" #include "tensorflow/lite/kernels/kernel_util.h" @@ -74,6 +75,10 @@ inline TfLiteStatus EvalLogical(TfLiteContext* context, TfLiteNode* node, return EvalImpl(context, node, bool_func, kTfLiteBool); } +TfLiteStatus AbsEval(TfLiteContext* context, TfLiteNode* node) { + return EvalNumeric(context, node, std::abs); +} + TfLiteStatus SinEval(TfLiteContext* context, TfLiteNode* node) { return EvalNumeric(context, node, std::sin); } @@ -101,6 +106,14 @@ TfLiteStatus LogicalNotEval(TfLiteContext* context, TfLiteNode* node) { } // namespace } // namespace elementwise +TfLiteRegistration* Register_ABS() { + static TfLiteRegistration r = { + /*init=*/nullptr, /*free=*/nullptr, + elementwise::GenericPrepare, + elementwise::AbsEval}; + return &r; +} + TfLiteRegistration* Register_SIN() { static TfLiteRegistration r = { /*init=*/nullptr, /*free=*/nullptr, diff --git a/tensorflow/lite/kernels/elementwise_test.cc b/tensorflow/lite/kernels/elementwise_test.cc index 52df8dc3cc..7d24320081 100644 --- a/tensorflow/lite/kernels/elementwise_test.cc +++ b/tensorflow/lite/kernels/elementwise_test.cc @@ -74,6 +74,19 @@ TEST(ElementWise, Log) { EXPECT_THAT(m.GetTensorShape(m.output()), ElementsAreArray({1, 1, 4, 1})); } +TEST(FloatActivationsOpTest, Abs) { + ElementWiseOpFloatModel m(BuiltinOperator_ABS, {1, 2, 4, 1}); + m.PopulateTensor(m.input(), { + 0.f, -6.2f, 2.f, 4.f, // + 3.f, -2.f, 10.f, 1.f, // + }); + m.Invoke(); + EXPECT_THAT(m.ExtractVector(m.output()), ElementsAreArray({ + 0.f, 6.2f, 2.f, 4.f, // + 3.f, 2.f, 10.f, 1.f, // + })); +} + TEST(ElementWise, Sqrt) { ElementWiseOpFloatModel m(BuiltinOperator_SQRT, {1, 1, 4, 1}); m.PopulateTensor(m.input(), {0, 1, 2, 4}); diff --git a/tensorflow/lite/kernels/register.cc b/tensorflow/lite/kernels/register.cc index f4aa5cc438..5f48aacf59 100644 --- a/tensorflow/lite/kernels/register.cc +++ b/tensorflow/lite/kernels/register.cc @@ -31,6 +31,7 @@ TfLiteRegistration* Register_RELU_1(); namespace builtin { +TfLiteRegistration* Register_ABS(); TfLiteRegistration* Register_RELU(); TfLiteRegistration* Register_RELU_N1_TO_1(); TfLiteRegistration* Register_RELU6(); @@ -154,6 +155,7 @@ const TfLiteRegistration* BuiltinOpResolver::FindOp(const char* op, } BuiltinOpResolver::BuiltinOpResolver() { + AddBuiltin(BuiltinOperator_ABS, Register_ABS()); AddBuiltin(BuiltinOperator_RELU, Register_RELU()); AddBuiltin(BuiltinOperator_RELU_N1_TO_1, Register_RELU_N1_TO_1()); AddBuiltin(BuiltinOperator_RELU6, Register_RELU6()); diff --git a/tensorflow/lite/testing/generate_examples.py b/tensorflow/lite/testing/generate_examples.py index 71382edaba..566723cdc2 100644 --- a/tensorflow/lite/testing/generate_examples.py +++ b/tensorflow/lite/testing/generate_examples.py @@ -626,6 +626,30 @@ def make_max_pool_tests(zip_path): make_pool_tests(tf.nn.max_pool)(zip_path) +def make_abs_tests(zip_path): + """Make a set of tests to do relu.""" + + # Chose a set of parameters + test_parameters = [{ + "input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3], + [3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]], + }] + + def build_graph(parameters): + input_tensor = tf.placeholder( + dtype=tf.float32, name="input", shape=parameters["input_shape"]) + out = tf.abs(input_tensor) + return [input_tensor], [out] + + def build_inputs(parameters, sess, inputs, outputs): + input_values = create_tensor_data( + np.float32, parameters["input_shape"], min_value=-10, max_value=10) + return [input_values], sess.run( + outputs, feed_dict=dict(zip(inputs, [input_values]))) + + make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) + + def make_relu_tests(zip_path): """Make a set of tests to do relu.""" diff --git a/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc b/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc index 664424860e..b520f7f559 100644 --- a/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc +++ b/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc @@ -1707,6 +1707,7 @@ void ProcessUnpackOperator(Model* model, UnpackOperator* op) { } switch (op->type) { + case OperatorType::kAbs: case OperatorType::kBatchNormalization: case OperatorType::kL2Normalization: case OperatorType::kDequantize: diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index b51f80c1a7..e42c2e2f20 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -2255,6 +2255,7 @@ ConverterMapType GetTensorFlowNodeConverterMapForFlex() { ConverterMapType GetTensorFlowNodeConverterMap() { return std::unordered_map({ + {"Abs", ConvertSimpleOperator}, {"Add", ConvertSimpleOperator}, {"AddN", ConvertSimpleOperatorFlexOk}, {"All", ConvertSimpleOperator}, diff --git a/tensorflow/lite/toco/model.h b/tensorflow/lite/toco/model.h index 92be42f47c..a4883e4694 100644 --- a/tensorflow/lite/toco/model.h +++ b/tensorflow/lite/toco/model.h @@ -154,7 +154,8 @@ enum class OperatorType : uint8 { kUnpack, kZerosLike, kResizeNearestNeighbor, - kLeakyRelu + kLeakyRelu, + kAbs }; // Helper to deal with TensorFlow arrays using a different ordering of @@ -655,6 +656,17 @@ struct MulOperator : Operator { MulOperator() : Operator(OperatorType::kMul) {} }; +// Element-wise Abs operator: +// x -> abs(x) +// +// Inputs: +// inputs[0]: required: the input array +// +// TensorFlow equivalent: Relu +struct AbsOperator : Operator { + AbsOperator() : Operator(OperatorType::kAbs) {} +}; + // Element-wise Relu operator: // x -> max(0, x) // diff --git a/tensorflow/lite/toco/tflite/export.cc b/tensorflow/lite/toco/tflite/export.cc index f17ce900eb..8b9448486d 100644 --- a/tensorflow/lite/toco/tflite/export.cc +++ b/tensorflow/lite/toco/tflite/export.cc @@ -126,7 +126,6 @@ OperatorKey::OperatorKey( type_ = builtin_ops.at(name); return; } - // The logic below is all for custom ops or Flex ops. is_custom_op_ = true; type_ = BuiltinOperator_CUSTOM; diff --git a/tensorflow/lite/toco/tflite/operator.cc b/tensorflow/lite/toco/tflite/operator.cc index 83325f1f79..b28781c32e 100644 --- a/tensorflow/lite/toco/tflite/operator.cc +++ b/tensorflow/lite/toco/tflite/operator.cc @@ -1484,6 +1484,7 @@ std::vector> BuildOperatorList( OperatorType::kMaxPool)); ops.push_back( MakeUnique(::tflite::BuiltinOperator_MUL, OperatorType::kMul)); + ops.push_back( MakeUnique(::tflite::BuiltinOperator_PAD, OperatorType::kPad)); ops.push_back( @@ -1642,7 +1643,8 @@ std::vector> BuildOperatorList( "SQUARE", OperatorType::kSquare)); ops.push_back(MakeUnique>( "ZEROS_LIKE", OperatorType::kZerosLike)); - + ops.push_back( + MakeUnique>("ABS", OperatorType::kAbs)); return ops; } } // namespace diff --git a/tensorflow/lite/toco/tooling_util.cc b/tensorflow/lite/toco/tooling_util.cc index 611add9daf..e3f3fe36f7 100644 --- a/tensorflow/lite/toco/tooling_util.cc +++ b/tensorflow/lite/toco/tooling_util.cc @@ -308,6 +308,7 @@ const char* OperatorTypeName(OperatorType type) { #define HANDLE_OPERATORTYPENAME_CASE(c) \ case OperatorType::k##c: \ return #c; + HANDLE_OPERATORTYPENAME_CASE(Abs) HANDLE_OPERATORTYPENAME_CASE(Add) HANDLE_OPERATORTYPENAME_CASE(AddN) HANDLE_OPERATORTYPENAME_CASE(AveragePool) -- GitLab From c7d52fa78a67cd02bfa96f310308e1edeb8bb356 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Wed, 28 Nov 2018 18:40:58 -0800 Subject: [PATCH 517/672] Add publicly available corpus for string_split fuzz. PiperOrigin-RevId: 223273755 --- .../string_split/4c01a1504da9de2216894743ecc44424 | 1 + .../string_split/5bf16424630b5afbcffe711fb9834440 | 1 + .../string_split/a7185605aef0a8fd682fcb4656e4a736 | 1 + .../string_split/d5606def44fdbb9385dd764612069db0 | Bin 0 -> 42 bytes .../string_split/dbac766f3160de65894bf5153f478146 | 1 + .../string_split/e85ff62f6d457666f54a37a19a115a24 | 1 + .../core/kernels/fuzzing/string_split_fuzz.cc | 3 +-- 7 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split/4c01a1504da9de2216894743ecc44424 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split/5bf16424630b5afbcffe711fb9834440 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split/a7185605aef0a8fd682fcb4656e4a736 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split/d5606def44fdbb9385dd764612069db0 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split/dbac766f3160de65894bf5153f478146 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split/e85ff62f6d457666f54a37a19a115a24 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split/4c01a1504da9de2216894743ecc44424 b/tensorflow/core/kernels/fuzzing/corpus/string_split/4c01a1504da9de2216894743ecc44424 new file mode 100644 index 0000000000..eb84b9e610 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split/4c01a1504da9de2216894743ecc44424 @@ -0,0 +1 @@ +./,abcd.efgh/abcd,efgh.abcd/efgh,abcd.efgh/a \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split/5bf16424630b5afbcffe711fb9834440 b/tensorflow/core/kernels/fuzzing/corpus/string_split/5bf16424630b5afbcffe711fb9834440 new file mode 100644 index 0000000000..4cd522da7b --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split/5bf16424630b5afbcffe711fb9834440 @@ -0,0 +1 @@ +.ab.cd.ef.gh.ab.cd.ef.gh.ab.cd.ef.gh.ab.cd \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split/a7185605aef0a8fd682fcb4656e4a736 b/tensorflow/core/kernels/fuzzing/corpus/string_split/a7185605aef0a8fd682fcb4656e4a736 new file mode 100644 index 0000000000..03cfb6256f --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split/a7185605aef0a8fd682fcb4656e4a736 @@ -0,0 +1 @@ +./, abcde.fghab/cdefg,habcd efgha.bcdef/ghabc \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split/d5606def44fdbb9385dd764612069db0 b/tensorflow/core/kernels/fuzzing/corpus/string_split/d5606def44fdbb9385dd764612069db0 new file mode 100644 index 0000000000000000000000000000000000000000..304b0d66fe08fd1a29827488727702dd9b9bce3e GIT binary patch literal 42 ScmZQbOiE5kO-s)pNCN;-W)Kzt literal 0 HcmV?d00001 diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split/dbac766f3160de65894bf5153f478146 b/tensorflow/core/kernels/fuzzing/corpus/string_split/dbac766f3160de65894bf5153f478146 new file mode 100644 index 0000000000..a8740444aa --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split/dbac766f3160de65894bf5153f478146 @@ -0,0 +1 @@ +./, ?abcdef.ghabcd/efghab,cdefgh abcdef?ghabcd \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split/e85ff62f6d457666f54a37a19a115a24 b/tensorflow/core/kernels/fuzzing/corpus/string_split/e85ff62f6d457666f54a37a19a115a24 new file mode 100644 index 0000000000..47d551466a --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split/e85ff62f6d457666f54a37a19a115a24 @@ -0,0 +1 @@ +./abc.def/gha.bcd/efg.hab/cde.fgh/abc.def/g \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/string_split_fuzz.cc b/tensorflow/core/kernels/fuzzing/string_split_fuzz.cc index 87a548a999..2564f8ed03 100644 --- a/tensorflow/core/kernels/fuzzing/string_split_fuzz.cc +++ b/tensorflow/core/kernels/fuzzing/string_split_fuzz.cc @@ -37,8 +37,7 @@ class FuzzStringSplit : public FuzzSession { // The spec for split is that the delimeter should be 0 or 1 characters. // Naturally, fuzz it with something larger. (This omits the possibility // of handing it a > int32_max size string, which should be tested for in - // an - // explicit test). + // an explicit test). size_t delim_len = static_cast(data[0]); if (delim_len > size) { delim_len = size - 1; -- GitLab From 16c0e72b92497587b6f7e1614869066ed122c9e4 Mon Sep 17 00:00:00 2001 From: Sherry Yang Date: Wed, 28 Nov 2018 18:46:28 -0800 Subject: [PATCH 518/672] Dump graph after graph optimization passes. PiperOrigin-RevId: 223274324 --- tensorflow/core/BUILD | 2 + .../common_runtime/optimization_registry.cc | 14 ++ .../grappler/optimizers/meta_optimizer.cc | 7 + tensorflow/core/util/dump_graph.cc | 121 ++++++++++++++++++ tensorflow/core/util/dump_graph.h | 48 +++++++ tensorflow/core/util/dump_graph_test.cc | 62 +++++++++ 6 files changed, 254 insertions(+) create mode 100644 tensorflow/core/util/dump_graph.cc create mode 100644 tensorflow/core/util/dump_graph.h create mode 100644 tensorflow/core/util/dump_graph_test.cc diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 4313d4f1a8..962780836e 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -911,6 +911,7 @@ tf_cuda_library( "util/bcast.h", "util/cuda_kernel_helper.h", "util/device_name_utils.h", + "util/dump_graph.h", "util/events_writer.h", "util/example_proto_fast_parsing.h", "util/example_proto_helper.h", @@ -3731,6 +3732,7 @@ tf_cc_tests( "util/bcast_test.cc", "util/command_line_flags_test.cc", "util/device_name_utils_test.cc", + "util/dump_graph_test.cc", "util/equal_graph_def_test.cc", "util/events_writer_test.cc", "util/example_proto_fast_parsing_test.cc", diff --git a/tensorflow/core/common_runtime/optimization_registry.cc b/tensorflow/core/common_runtime/optimization_registry.cc index 6ac047295d..9be540b019 100644 --- a/tensorflow/core/common_runtime/optimization_registry.cc +++ b/tensorflow/core/common_runtime/optimization_registry.cc @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/common_runtime/optimization_registry.h" +#include "tensorflow/core/util/dump_graph.h" namespace tensorflow { @@ -39,6 +40,19 @@ Status OptimizationPassRegistry::RunGrouping( VLOG(1) << "Running optimization pass: " << pass->name(); Status s = pass->Run(options); if (!s.ok()) return s; + if (VLOG_IS_ON(1)) { + DumpGraphToFile( + strings::StrCat("after_phase_", phase.first, "_", pass->name()), + **options.graph); + if (options.partition_graphs) { + for (auto& part : *options.partition_graphs) { + DumpGraphToFile( + strings::StrCat("after_phase_", phase.first, "_", + pass->name(), "_partition_", part.first), + *part.second); + } + } + } } } } diff --git a/tensorflow/core/grappler/optimizers/meta_optimizer.cc b/tensorflow/core/grappler/optimizers/meta_optimizer.cc index 6975fa715b..304ddc7710 100644 --- a/tensorflow/core/grappler/optimizers/meta_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/meta_optimizer.cc @@ -39,6 +39,7 @@ limitations under the License. #include "tensorflow/core/grappler/utils/topological_sort.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/gtl/map_util.h" +#include "tensorflow/core/util/dump_graph.h" #include "tensorflow/core/util/ptr_util.h" namespace tensorflow { @@ -462,6 +463,9 @@ Status MetaOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, // optimize TPU functions with Grappler, this check preserves that. if (IsTPUGraphDef(*optimized_graph)) { VLOG(2) << "Skipping optimizing funcs for TPU graphs"; + if (VLOG_IS_ON(1)) { + DumpGraphDefToFile("after_MetaOptimizer", *optimized_graph); + } return Status::OK(); } @@ -555,6 +559,9 @@ Status MetaOptimizer::Optimize(Cluster* cluster, const GrapplerItem& item, VLOG(1) << "Optimized " << optimized_funcs.size() << " functions: " << str_util::Join(optimized_funcs, ", "); + if (VLOG_IS_ON(1)) { + DumpGraphDefToFile("after_MetaOptimizer", *optimized_graph); + } return Status::OK(); } diff --git a/tensorflow/core/util/dump_graph.cc b/tensorflow/core/util/dump_graph.cc new file mode 100644 index 0000000000..5df5cb51cb --- /dev/null +++ b/tensorflow/core/util/dump_graph.cc @@ -0,0 +1,121 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +// Helper functions for dumping Graphs, GraphDefs, and FunctionDefs to files for +// debugging. + +#include "tensorflow/core/util/dump_graph.h" + +#include "absl/strings/str_cat.h" +#include "tensorflow/core/lib/strings/proto_serialization.h" +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/mutex.h" + +namespace tensorflow { + +namespace { + +struct NameCounts { + mutex counts_mutex; + std::unordered_map counts; +}; + +string MakeUniqueFilename(string name) { + static NameCounts& instance = *new NameCounts; + + // Remove illegal characters from `name`. + for (int i = 0; i < name.size(); ++i) { + char ch = name[i]; + if (ch == '/' || ch == '[' || ch == ']' || ch == '*' || ch == '?') { + name[i] = '_'; + } + } + + int count; + { + mutex_lock lock(instance.counts_mutex); + count = instance.counts[name]++; + } + + string filename = name; + if (count > 0) { + absl::StrAppend(&filename, "_", count); + } + absl::StrAppend(&filename, ".pbtxt"); + return filename; +} + +#if defined(TENSORFLOW_LITE_PROTOS) +Status WriteToFile(const string& filepath, + const ::tensorflow::protobuf::MessageLite& proto) { + string s; + if (!SerializeToStringDeterministic(proto, &s)) { + return errors::Internal("Failed to serialize proto to string."); + } + return WriteStringToFile(Env::Default(), filepath, s); +} +#else +Status WriteToFile(const string& filepath, + const ::tensorflow::protobuf::Message& proto) { + return WriteTextProto(Env::Default(), filepath, proto); +} +#endif + +template +string WriteTextProtoToUniqueFile(Env* env, const string& name, + const char* proto_type, T& proto) { + const char* dirname = getenv("TF_DUMP_GRAPH_PREFIX"); + if (!dirname) { + return "(TF_DUMP_GRAPH_PREFIX not specified)"; + } + Status status = env->RecursivelyCreateDir(dirname); + if (!status.ok()) { + LOG(WARNING) << "Failed to create " << dirname << " for dumping " + << proto_type << ": " << status; + return "(unavailable)"; + } + string filepath = absl::StrCat(dirname, "/", MakeUniqueFilename(name)); + status = WriteToFile(filepath, proto); + if (!status.ok()) { + LOG(WARNING) << "Failed to dump " << proto_type << " to file: " << filepath + << " : " << status; + return "(unavailable)"; + } + LOG(INFO) << "Dumped " << proto_type << " to " << filepath; + return filepath; +} + +} // anonymous namespace + +string DumpGraphDefToFile(const string& name, GraphDef const& graph_def) { + return WriteTextProtoToUniqueFile(Env::Default(), name, "GraphDef", + graph_def); +} + +string DumpGraphToFile(const string& name, Graph const& graph, + const FunctionLibraryDefinition* flib_def) { + GraphDef graph_def; + graph.ToGraphDef(&graph_def); + if (flib_def) { + *graph_def.mutable_library() = flib_def->ToProto(); + } + return DumpGraphDefToFile(name, graph_def); +} + +string DumpFunctionDefToFile(const string& name, FunctionDef const& fdef) { + return WriteTextProtoToUniqueFile(Env::Default(), name, "FunctionDef", fdef); +} + +} // namespace tensorflow diff --git a/tensorflow/core/util/dump_graph.h b/tensorflow/core/util/dump_graph.h new file mode 100644 index 0000000000..05e0b79f55 --- /dev/null +++ b/tensorflow/core/util/dump_graph.h @@ -0,0 +1,48 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +// Helper functions for dumping Graphs, GraphDefs, and FunctionDefs to files for +// debugging. + +#ifndef TENSORFLOW_CORE_UTIL_DUMP_GRAPH_H_ +#define TENSORFLOW_CORE_UTIL_DUMP_GRAPH_H_ + +#include "tensorflow/core/framework/function.h" +#include "tensorflow/core/framework/graph.pb.h" +#include "tensorflow/core/graph/graph.h" + +namespace tensorflow { + +// Dumps 'graph_def' to a file, as a GraphDef text proto. Returns the file name +// chosen. +// +// Automatically picks a file name. Prefixes 'name' with the value of the +// TF_DUMP_GRAPH_PREFIX environment variable and suffixes it with ".pbtxt" to +// form a name. If a graph has already been dumped by this process with the same +// name, suffixes with "_n.pbtxt", where 'n' is a sequence number. +string DumpGraphDefToFile(const string& name, GraphDef const& graph_def); + +// Similar to DumpGraphDefToFile, but builds the GraphDef to dump from a 'graph' +// and an optional function library 'flib_def'. Returns the file name chosen. +string DumpGraphToFile(const string& name, Graph const& graph, + const FunctionLibraryDefinition* flib_def = nullptr); + +// Similar to DumpGraphDefToFile, but dumps a function as a FunctionDef text +// proto. Returns the file name chosen. +string DumpFunctionDefToFile(const string& name, FunctionDef const& fdef); + +} // namespace tensorflow + +#endif // TENSORFLOW_CORE_UTIL_DUMP_GRAPH_H_ diff --git a/tensorflow/core/util/dump_graph_test.cc b/tensorflow/core/util/dump_graph_test.cc new file mode 100644 index 0000000000..d01c1c5a02 --- /dev/null +++ b/tensorflow/core/util/dump_graph_test.cc @@ -0,0 +1,62 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ + +#include "tensorflow/core/util/dump_graph.h" +#include "tensorflow/core/graph/graph.h" +#include "tensorflow/core/graph/node_builder.h" +#include "tensorflow/core/lib/io/path.h" +#include "tensorflow/core/lib/strings/proto_serialization.h" +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { +namespace { + +TEST(DumpGraph, DumpGraphToFileSuccess) { + Graph graph(OpRegistry::Global()); + Node* node; + TF_CHECK_OK(NodeBuilder("A", "NoOp").Finalize(&graph, &node)); + + setenv("TF_DUMP_GRAPH_PREFIX", testing::TmpDir().c_str(), 1); + string ret = DumpGraphToFile("graph", graph); + EXPECT_EQ(ret, io::JoinPath(testing::TmpDir(), "graph.pbtxt")); + ret = DumpGraphToFile("graph", graph); + EXPECT_EQ(ret, io::JoinPath(testing::TmpDir(), "graph_1.pbtxt")); + + GraphDef gdef; + TF_CHECK_OK(ReadTextProto( + Env::Default(), io::JoinPath(testing::TmpDir(), "graph.pbtxt"), &gdef)); + string read, written; + gdef.AppendToString(&read); + graph.ToGraphDefDebug().AppendToString(&written); + EXPECT_EQ(read, written); +} + +TEST(DumpGraph, DumpGraphToFileNoEnvPrefix) { + Graph graph(OpRegistry::Global()); + unsetenv("TF_DUMP_GRAPH_PREFIX"); + string ret = DumpGraphToFile("graph", graph); + EXPECT_EQ(ret, "(TF_DUMP_GRAPH_PREFIX not specified)"); +} + +TEST(DumpGraph, DumpFunctionDefToFileSuccess) { + FunctionDef fdef; + setenv("TF_DUMP_GRAPH_PREFIX", testing::TmpDir().c_str(), 1); + string ret = DumpFunctionDefToFile("function", fdef); + EXPECT_EQ(ret, io::JoinPath(testing::TmpDir(), "function.pbtxt")); +} + +} // namespace +} // namespace tensorflow -- GitLab From 5cf68508e9223adc911d347a1dd89d547310617a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 19:15:32 -0800 Subject: [PATCH 519/672] TensorFlow 2.0 fixups for tf.sparse.{add, concat}. Fix their bogus rewrite rules. PiperOrigin-RevId: 223276761 --- tensorflow/python/ops/sparse_ops.py | 107 ++++++++++-------- .../tools/api/golden/v1/tensorflow.pbtxt | 2 +- .../api/golden/v1/tensorflow.sparse.pbtxt | 2 +- .../tools/api/golden/v2/tensorflow.pbtxt | 4 - .../api/golden/v2/tensorflow.sparse.pbtxt | 2 +- .../tools/compatibility/tf_upgrade_v2.py | 20 +++- 6 files changed, 77 insertions(+), 60 deletions(-) diff --git a/tensorflow/python/ops/sparse_ops.py b/tensorflow/python/ops/sparse_ops.py index 91baa6f7b8..245080cb26 100644 --- a/tensorflow/python/ops/sparse_ops.py +++ b/tensorflow/python/ops/sparse_ops.py @@ -185,12 +185,6 @@ def sparse_eye(num_rows, dense_shape=[num_rows, num_columns]) -@tf_export("sparse.concat", "sparse_concat", v1=[]) -def sparse_concat_v2(axis, sp_inputs, expand_nonconcat_dim=False, - concat_dim=None, name=None): - return sparse_concat(axis, sp_inputs, name, expand_nonconcat_dim, concat_dim) - - # pylint: disable=protected-access @tf_export(v1=["sparse.concat", "sparse_concat"]) @deprecation.deprecated_endpoints("sparse_concat") @@ -298,6 +292,11 @@ def sparse_concat(axis, """ axis = deprecation.deprecated_argument_lookup("axis", axis, "concat_dim", concat_dim) + return sparse_concat_v2(axis, sp_inputs, expand_nonconcat_dim, name) + + +@tf_export("sparse.concat", v1=[]) +def sparse_concat_v2(axis, sp_inputs, expand_nonconcat_dim=False, name=None): # pylint: disable=missing-docstring sp_inputs = _convert_to_sparse_tensors(sp_inputs) if len(sp_inputs) == 1: # Degenerate case of one tensor. @@ -325,9 +324,15 @@ def sparse_concat(axis, return sparse_tensor.SparseTensor(output_ind, output_val, output_shape) +sparse_concat_v2.__doc__ = sparse_concat.__doc__.replace( + " concat_dim: The old (deprecated) name for axis.\n", "") + + @tf_export(v1=["sparse.add", "sparse_add"]) @deprecation.deprecated_endpoints("sparse_add") -def sparse_add(a, b, thresh=0): +@deprecation.deprecated_args( + None, "thresh is deprecated, use threshold instead", "thresh") +def sparse_add(a, b, threshold=None, thresh=None): """Adds two tensors, at least one of each is a `SparseTensor`. If one `SparseTensor` and one `Tensor` are passed in, returns a `Tensor`. If @@ -365,12 +370,14 @@ def sparse_add(a, b, thresh=0): Args: a: The first operand; `SparseTensor` or `Tensor`. - b: The second operand; `SparseTensor` or `Tensor`. At least one operand + b: The second operand; `SparseTensor` or `Tensor`. At least one operand must be sparse. - thresh: A 0-D `Tensor`. The magnitude threshold that determines if an - output value/index pair takes space. Its dtype should match that of the - values if they are real; if the latter are complex64/complex128, then the - dtype should be float32/float64, correspondingly. + threshold: An optional 0-D `Tensor` (defaults to `0`). The magnitude + threshold that determines if an output value/index pair takes space. Its + dtype should match that of the values if they are real; if the latter are + complex64/complex128, then the dtype should be float32/float64, + correspondingly. + thresh: Deprecated alias for `threshold`. Returns: A `SparseTensor` or a `Tensor`, representing the sum. @@ -378,34 +385,11 @@ def sparse_add(a, b, thresh=0): Raises: TypeError: If both `a` and `b` are `Tensor`s. Use `tf.add()` instead. """ - sparse_classes = (sparse_tensor.SparseTensor, sparse_tensor.SparseTensorValue) - if not any(isinstance(inp, sparse_classes) for inp in [a, b]): - raise TypeError("At least one input should be SparseTensor; do you mean to" - " use tf.add()?") - - if all(isinstance(inp, sparse_classes) for inp in [a, b]): - a = _convert_to_sparse_tensor(a) - b = _convert_to_sparse_tensor(b) - thresh = ops.convert_to_tensor( - thresh, dtype=a.values.dtype.real_dtype.base_dtype, name="thresh") - output_ind, output_val, output_shape = ( - gen_sparse_ops.sparse_add(a.indices, a.values, a.dense_shape, - b.indices, b.values, b.dense_shape, thresh)) - - # Attempt to get output_shape statically. - a.get_shape().assert_is_compatible_with(b.get_shape()) - static_shape = array_ops.broadcast_static_shape(a.get_shape(), - b.get_shape()) - if static_shape.is_fully_defined(): - output_shape = static_shape.as_list() - - return sparse_tensor.SparseTensor(output_ind, output_val, output_shape) - else: - # swap to make `a` the SparseTensor. - if isinstance(b, sparse_classes): - a, b = b, a - return gen_sparse_ops.sparse_tensor_dense_add(a.indices, a.values, - a.dense_shape, b) + threshold = deprecation.deprecated_argument_lookup("threshold", threshold, + "thresh", thresh) + if threshold is None: + threshold = 0 + return sparse_add_v2(a, b, threshold) @tf_export("sparse.add", v1=[]) @@ -448,12 +432,12 @@ def sparse_add_v2(a, b, threshold=0): Args: a: The first operand; `SparseTensor` or `Tensor`. - b: The second operand; `SparseTensor` or `Tensor`. At least one operand + b: The second operand; `SparseTensor` or `Tensor`. At least one operand must be sparse. - threshold: A 0-D `Tensor`. The magnitude threshold that determines if an - output value/index pair takes space. Its dtype should match that of the - values if they are real; if the latter are complex64/complex128, then the - dtype should be float32/float64, correspondingly. + threshold: A 0-D `Tensor`. The magnitude threshold that determines if an + output value/index pair takes space. Its dtype should match that of the + values if they are real; if the latter are complex64/complex128, then the + dtype should be float32/float64, correspondingly. Returns: A `SparseTensor` or a `Tensor`, representing the sum. @@ -461,10 +445,35 @@ def sparse_add_v2(a, b, threshold=0): Raises: TypeError: If both `a` and `b` are `Tensor`s. Use `tf.add()` instead. """ - return sparse_add( - a=a, - b=b, - thresh=threshold) + sparse_classes = (sparse_tensor.SparseTensor, sparse_tensor.SparseTensorValue) + if not any(isinstance(inp, sparse_classes) for inp in [a, b]): + raise TypeError("At least one input should be SparseTensor; do you mean to" + " use tf.add()?") + + if all(isinstance(inp, sparse_classes) for inp in [a, b]): + a = _convert_to_sparse_tensor(a) + b = _convert_to_sparse_tensor(b) + threshold = ops.convert_to_tensor( + threshold, dtype=a.values.dtype.real_dtype.base_dtype, name="threshold") + output_ind, output_val, output_shape = ( + gen_sparse_ops.sparse_add(a.indices, a.values, a.dense_shape, + b.indices, b.values, b.dense_shape, + threshold)) + + # Attempt to get output_shape statically. + a.get_shape().assert_is_compatible_with(b.get_shape()) + static_shape = array_ops.broadcast_static_shape(a.get_shape(), + b.get_shape()) + if static_shape.is_fully_defined(): + output_shape = static_shape.as_list() + + return sparse_tensor.SparseTensor(output_ind, output_val, output_shape) + else: + # swap to make `a` the SparseTensor. + if isinstance(b, sparse_classes): + a, b = b, a + return gen_sparse_ops.sparse_tensor_dense_add(a.indices, a.values, + a.dense_shape, b) @tf_export("sparse.cross") diff --git a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt index a294e3e027..9c836c5bf8 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt @@ -1982,7 +1982,7 @@ tf_module { } member_method { name: "sparse_add" - argspec: "args=[\'a\', \'b\', \'thresh\'], varargs=None, keywords=None, defaults=[\'0\'], " + argspec: "args=[\'a\', \'b\', \'threshold\', \'thresh\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "sparse_concat" diff --git a/tensorflow/tools/api/golden/v1/tensorflow.sparse.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.sparse.pbtxt index ee4f31774e..33e342bc75 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.sparse.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.sparse.pbtxt @@ -10,7 +10,7 @@ tf_module { } member_method { name: "add" - argspec: "args=[\'a\', \'b\', \'thresh\'], varargs=None, keywords=None, defaults=[\'0\'], " + argspec: "args=[\'a\', \'b\', \'threshold\', \'thresh\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " } member_method { name: "concat" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 40693e7582..f2ae039d9f 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -1020,10 +1020,6 @@ tf_module { name: "space_to_batch_nd" argspec: "args=[\'input\', \'block_shape\', \'paddings\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "sparse_concat" - argspec: "args=[\'axis\', \'sp_inputs\', \'expand_nonconcat_dim\', \'concat_dim\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\', \'None\'], " - } member_method { name: "split" argspec: "args=[\'value\', \'num_or_size_splits\', \'axis\', \'num\', \'name\'], varargs=None, keywords=None, defaults=[\'0\', \'None\', \'split\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.sparse.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.sparse.pbtxt index 4ad94568b2..9808200d72 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.sparse.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.sparse.pbtxt @@ -14,7 +14,7 @@ tf_module { } member_method { name: "concat" - argspec: "args=[\'axis\', \'sp_inputs\', \'expand_nonconcat_dim\', \'concat_dim\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\', \'None\'], " + argspec: "args=[\'axis\', \'sp_inputs\', \'expand_nonconcat_dim\', \'name\'], varargs=None, keywords=None, defaults=[\'False\', \'None\'], " } member_method { name: "cross" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index d75e52bd0d..649d1c17a3 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -102,7 +102,18 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "t": "x", "msg": "message", }, - "tf.sparse.add": ["a", "b", "thresh"], + "tf.sparse.add": { + "thresh": "threshold", + }, + "tf.sparse_add": { + "thresh": "threshold", + }, + "tf.sparse.concat": { + "concat_dim": "axis", + }, + "tf.sparse_concat": { + "concat_dim": "axis", + }, "tf.sparse.split": { "split_dim": "axis", }, @@ -197,9 +208,6 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.strings.to_hash_bucket": { "string_tensor": "input", }, - "tf.sparse.concat": [ - "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" - ], "tf.reduce_all": { "reduction_indices": "axis", "keep_dims": "keepdims", @@ -481,9 +489,13 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.size": ["input", "name", "out_type"], "tf.random.poisson": ["lam", "shape", "dtype", "seed", "name"], "tf.sparse.add": ["a", "b", "thresh"], + "tf.sparse_add": ["a", "b", "thresh"], "tf.sparse.concat": [ "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" ], + "tf.sparse_concat": [ + "axis", "sp_inputs", "name", "expand_nonconcat_dim", "concat_dim" + ], "tf.sparse.segment_mean": [ "data", "indices", "segment_ids", "name", "num_segments" ], -- GitLab From 158bf75a3078e14839c670c109fee7d4c23ce183 Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Wed, 28 Nov 2018 21:00:52 -0800 Subject: [PATCH 520/672] Internal-only change. PiperOrigin-RevId: 223284903 --- tensorflow/core/BUILD | 3 ++- tensorflow/tensorflow.bzl | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 962780836e..7b46e8c9b4 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -96,6 +96,7 @@ load("//tensorflow:tensorflow.bzl", "tf_cc_tests_gpu") load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test") load("//tensorflow:tensorflow.bzl", "tf_version_info_genrule") load("//tensorflow:tensorflow.bzl", "if_nccl") +load("//tensorflow:tensorflow.bzl", "tensorflow_opensource_extra_deps") load("//tensorflow:tensorflow.bzl", "tf_cuda_only_cc_test") # For platform specific build config @@ -1469,7 +1470,7 @@ tf_cuda_library( ":gpu_runtime", ":lib", ":ops", - ], + ] + tensorflow_opensource_extra_deps(), ) cc_library( diff --git a/tensorflow/tensorflow.bzl b/tensorflow/tensorflow.bzl index 4bc68445ac..ed1de5a31c 100644 --- a/tensorflow/tensorflow.bzl +++ b/tensorflow/tensorflow.bzl @@ -2032,3 +2032,6 @@ register_extension_info( extension_name = "cc_library_with_android_deps", label_regex_for_dep = "{extension_name}", ) + +def tensorflow_opensource_extra_deps(): + return [] -- GitLab From 454fd39652993f387bafb83329e93cce7c0db9db Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 28 Nov 2018 21:37:25 -0800 Subject: [PATCH 521/672] Implement SplitV. PiperOrigin-RevId: 223287758 --- tensorflow/lite/build_def.bzl | 1 + tensorflow/lite/builtin_ops.h | 1 + tensorflow/lite/c/builtin_op_data.h | 4 + tensorflow/lite/c/builtin_op_data_test.cc | 1 + .../lite/core/api/flatbuffer_conversions.cc | 8 + .../writer/option_writer_generator.cc | 1 + tensorflow/lite/g3doc/tf_ops_compatibility.md | 16 ++ tensorflow/lite/kernels/BUILD | 17 ++ tensorflow/lite/kernels/register.cc | 2 + tensorflow/lite/kernels/split_v.cc | 207 ++++++++++++++++++ tensorflow/lite/kernels/split_v_test.cc | 175 +++++++++++++++ tensorflow/lite/nnapi_delegate.cc | 1 + tensorflow/lite/schema/schema.fbs | 6 + tensorflow/lite/schema/schema_generated.h | 141 +++++++++++- tensorflow/lite/testing/generate_examples.py | 27 ++- tensorflow/lite/toco/export_tensorflow.cc | 27 +++ .../propagate_array_data_types.cc | 7 + .../propagate_fixed_sizes.cc | 96 ++++++++ tensorflow/lite/toco/import_tensorflow.cc | 20 ++ tensorflow/lite/toco/model.h | 7 + tensorflow/lite/toco/tflite/operator.cc | 22 ++ tensorflow/lite/toco/tflite/operator_test.cc | 8 + tensorflow/lite/toco/tooling_util.cc | 1 + 23 files changed, 787 insertions(+), 9 deletions(-) create mode 100644 tensorflow/lite/kernels/split_v.cc create mode 100644 tensorflow/lite/kernels/split_v_test.cc diff --git a/tensorflow/lite/build_def.bzl b/tensorflow/lite/build_def.bzl index 3a31144593..33cee1ab20 100644 --- a/tensorflow/lite/build_def.bzl +++ b/tensorflow/lite/build_def.bzl @@ -294,6 +294,7 @@ def generated_test_models(): "space_to_depth", "sparse_to_dense", "split", + "splitv", "sqrt", "square", "squared_difference", diff --git a/tensorflow/lite/builtin_ops.h b/tensorflow/lite/builtin_ops.h index 63b5cd1960..f97d3ac4bf 100644 --- a/tensorflow/lite/builtin_ops.h +++ b/tensorflow/lite/builtin_ops.h @@ -127,6 +127,7 @@ typedef enum { kTfLiteBuiltinSquaredDifference = 99, kTfLiteBuiltinMirrorPad = 100, kTfLiteBuiltinAbs = 101, + kTfLiteBuiltinSplitV = 102, } TfLiteBuiltinOperator; #ifdef __cplusplus diff --git a/tensorflow/lite/c/builtin_op_data.h b/tensorflow/lite/c/builtin_op_data.h index 33aaac3c80..6a5a027a9d 100644 --- a/tensorflow/lite/c/builtin_op_data.h +++ b/tensorflow/lite/c/builtin_op_data.h @@ -277,6 +277,10 @@ typedef struct { int num_splits; } TfLiteSplitParams; +typedef struct { + int num_splits; +} TfLiteSplitVParams; + typedef struct { // TODO(ahentz): We can't have dynamic data in this struct, at least not yet. // For now we will fix the maximum possible number of dimensions. diff --git a/tensorflow/lite/c/builtin_op_data_test.cc b/tensorflow/lite/c/builtin_op_data_test.cc index 0e33dcd8c8..4ce7c481e1 100644 --- a/tensorflow/lite/c/builtin_op_data_test.cc +++ b/tensorflow/lite/c/builtin_op_data_test.cc @@ -63,6 +63,7 @@ TEST(IntArray, CanCompileStructs) { TfLiteTransposeParams transpose_params; TfLiteReducerParams reducer_params; TfLiteSplitParams split_params; + TfLiteSplitVParams split_v_params; TfLiteSqueezeParams squeeze_params; TfLiteStridedSliceParams strided_slice_params; TfLiteArgMaxParams arg_max_params; diff --git a/tensorflow/lite/core/api/flatbuffer_conversions.cc b/tensorflow/lite/core/api/flatbuffer_conversions.cc index d3383bccf0..c00a0a3a54 100644 --- a/tensorflow/lite/core/api/flatbuffer_conversions.cc +++ b/tensorflow/lite/core/api/flatbuffer_conversions.cc @@ -506,6 +506,14 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } + case BuiltinOperator_SPLIT_V: { + auto* params = allocator->AllocatePOD(); + if (auto* schema_params = op->builtin_options_as_SplitVOptions()) { + params->num_splits = schema_params->num_splits(); + } + *builtin_data = reinterpret_cast(params); + break; + } case BuiltinOperator_SQUEEZE: { auto* params = allocator->AllocatePOD(); if (auto* schema_params = op->builtin_options_as_SqueezeOptions()) { diff --git a/tensorflow/lite/experimental/writer/option_writer_generator.cc b/tensorflow/lite/experimental/writer/option_writer_generator.cc index b44750e8b2..fa360a2f47 100644 --- a/tensorflow/lite/experimental/writer/option_writer_generator.cc +++ b/tensorflow/lite/experimental/writer/option_writer_generator.cc @@ -56,6 +56,7 @@ static const char* param_structs[] = {"TfLiteConvParams", "TfLiteTransposeParams", "TfLiteReducerParams", "TfLiteSplitParams", + "TfLiteSplitVParams", "TfLiteSqueezeParams", "TfLiteStridedSliceParams", "TfLiteArgMaxParams", diff --git a/tensorflow/lite/g3doc/tf_ops_compatibility.md b/tensorflow/lite/g3doc/tf_ops_compatibility.md index a96f64cefe..6976f058d1 100644 --- a/tensorflow/lite/g3doc/tf_ops_compatibility.md +++ b/tensorflow/lite/g3doc/tf_ops_compatibility.md @@ -866,6 +866,22 @@ Options { } ``` +**SPLIT_V** + +``` +Inputs { + 0: tensor (input) + 1: 1-D tensor (size_splits) + 2: 0-D tensor (axis) +} +Outputs { + 0-N: subtensors built from the input tensors +} +Options { + num_splits: Specifies number of outputs +} +``` + **SQRT** ``` diff --git a/tensorflow/lite/kernels/BUILD b/tensorflow/lite/kernels/BUILD index 0bf4f01ac3..c1b005b580 100644 --- a/tensorflow/lite/kernels/BUILD +++ b/tensorflow/lite/kernels/BUILD @@ -219,6 +219,7 @@ cc_library( "sparse_output_fully_connected.cc", "sparse_to_dense.cc", "split.cc", + "split_v.cc", "squared_difference.cc", "squeeze.cc", "strided_slice.cc", @@ -1065,6 +1066,22 @@ tf_cc_test( ], ) +tf_cc_test( + name = "split_v_test", + size = "small", + srcs = ["split_v_test.cc"], + tags = [ + "no_oss", + "tflite_not_portable_ios", + ], + deps = [ + ":builtin_ops", + "//tensorflow/lite:framework", + "//tensorflow/lite/kernels:test_util", + "@com_google_googletest//:gtest", + ], +) + tf_cc_test( name = "squeeze_test", size = "small", diff --git a/tensorflow/lite/kernels/register.cc b/tensorflow/lite/kernels/register.cc index 5f48aacf59..7f0b9239ee 100644 --- a/tensorflow/lite/kernels/register.cc +++ b/tensorflow/lite/kernels/register.cc @@ -75,6 +75,7 @@ TfLiteRegistration* Register_GATHER(); TfLiteRegistration* Register_TRANSPOSE(); TfLiteRegistration* Register_MEAN(); TfLiteRegistration* Register_SPLIT(); +TfLiteRegistration* Register_SPLIT_V(); TfLiteRegistration* Register_SQUEEZE(); TfLiteRegistration* Register_STRIDED_SLICE(); TfLiteRegistration* Register_EXP(); @@ -211,6 +212,7 @@ BuiltinOpResolver::BuiltinOpResolver() { AddBuiltin(BuiltinOperator_DIV, Register_DIV()); AddBuiltin(BuiltinOperator_SUB, Register_SUB()); AddBuiltin(BuiltinOperator_SPLIT, Register_SPLIT()); + AddBuiltin(BuiltinOperator_SPLIT_V, Register_SPLIT_V()); AddBuiltin(BuiltinOperator_SQUEEZE, Register_SQUEEZE()); AddBuiltin(BuiltinOperator_STRIDED_SLICE, Register_STRIDED_SLICE()); AddBuiltin(BuiltinOperator_EXP, Register_EXP()); diff --git a/tensorflow/lite/kernels/split_v.cc b/tensorflow/lite/kernels/split_v.cc new file mode 100644 index 0000000000..060e3c5f79 --- /dev/null +++ b/tensorflow/lite/kernels/split_v.cc @@ -0,0 +1,207 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#include +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h" +#include "tensorflow/lite/kernels/internal/reference/reference_ops.h" +#include "tensorflow/lite/kernels/internal/tensor.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" + +namespace tflite { +namespace ops { +namespace builtin { +namespace split_v { + +struct OpContext { + OpContext(TfLiteContext* context, TfLiteNode* node) { + params = reinterpret_cast(node->builtin_data); + input = GetInput(context, node, 0); + size_splits = GetInput(context, node, 1); + axis = GetInput(context, node, 2); + } + TfLiteSplitVParams* params; + const TfLiteTensor* input; + const TfLiteTensor* size_splits; + const TfLiteTensor* axis; +}; + +TfLiteStatus UseDynamicOutputTensors(TfLiteContext* context, TfLiteNode* node) { + for (int i = 0; i < NumOutputs(node); ++i) { + SetTensorToDynamic(GetOutput(context, node, i)); + } + return kTfLiteOk; +} + +template +void GetSizeSplitsVector(const TfLiteTensor* size_splits, + std::vector* size_splits_vector) { + const auto num_elements = NumElements(size_splits); + for (int i = 0; i < num_elements; ++i) { + size_splits_vector->push_back(GetTensorData(size_splits)[i]); + } +} + +TfLiteStatus ResizeOutputTensors(TfLiteContext* context, TfLiteNode* node, + const TfLiteTensor* input, + const TfLiteTensor* size_splits, + const TfLiteTensor* axis) { + int axis_value = GetTensorData(axis)[0]; + if (axis_value < 0) { + axis_value += NumDimensions(input); + } + + std::vector size_splits_vector; + if (size_splits->type == kTfLiteInt32) { + GetSizeSplitsVector(size_splits, &size_splits_vector); + } else if (size_splits->type == kTfLiteInt64) { + GetSizeSplitsVector(size_splits, &size_splits_vector); + } else { + context->ReportError(context, "size_splits only support type int32|int64."); + return kTfLiteError; + } + + int minus_one_index = -1; + int64_t size_splits_sum = 0; + + for (int i = 0; i < size_splits_vector.size(); ++i) { + if (size_splits_vector.at(i) == -1) { + if (minus_one_index == -1) { + minus_one_index = i; + } else { + context->ReportError(context, + "The size_splits contains more than one -1."); + } + } else { + size_splits_sum += size_splits_vector.at(i); + } + } + + const int input_size = SizeOfDimension(input, axis_value); + + if (minus_one_index != -1) { + if (size_splits_sum > input_size) { + context->ReportError( + context, + "The sum of size_splits must be less than the dimension of value."); + } else { + size_splits_vector[minus_one_index] = input_size - size_splits_sum; + } + } else if (size_splits_sum != input_size) { + context->ReportError( + context, + "The size_splits must sum to the dimension of value along axis."); + } + + for (int i = 0; i < NumOutputs(node); ++i) { + TfLiteIntArray* output_dims = TfLiteIntArrayCopy(input->dims); + output_dims->data[axis_value] = size_splits_vector.at(i); + TfLiteTensor* output = GetOutput(context, node, i); + TF_LITE_ENSURE_STATUS(context->ResizeTensor(context, output, output_dims)); + } + + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + + OpContext op_context(context, node); + + TF_LITE_ENSURE_EQ(context, NumOutputs(node), op_context.params->num_splits); + + auto input_type = op_context.input->type; + TF_LITE_ENSURE(context, input_type == kTfLiteFloat32 || + input_type == kTfLiteUInt8 || + input_type == kTfLiteInt16); + for (int i = 0; i < NumOutputs(node); ++i) { + GetOutput(context, node, i)->type = input_type; + } + + auto size_splits = op_context.size_splits; + TF_LITE_ENSURE_EQ(context, NumDimensions(size_splits), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), NumElements(size_splits)); + + // If we know the contents of the 'size_splits' tensor and the 'axis' tensor, + // resize all outputs. Otherwise, wait until Eval(). + if (IsConstantTensor(op_context.size_splits) && + IsConstantTensor(op_context.axis)) { + return ResizeOutputTensors(context, node, op_context.input, + op_context.size_splits, op_context.axis); + } else { + return UseDynamicOutputTensors(context, node); + } +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + OpContext op_context(context, node); + + // When the 'size_splits' and the 'axis' tensor is non-const we can't resize + // output tensors in Prepare(), and we have to do it now. + if (!IsConstantTensor(op_context.axis) || + !IsConstantTensor(op_context.size_splits)) { + TF_LITE_ENSURE_OK( + context, ResizeOutputTensors(context, node, op_context.input, + op_context.size_splits, op_context.axis)); + } + + int axis_value = GetTensorData(op_context.axis)[0]; + + // Use split function to build the outputs since they share the same logic. +#define TF_LITE_SPLIT_V(scalar) \ + VectorOfTensors all_outputs(*context, *node->outputs); \ + tflite::SplitParams op_params; \ + op_params.num_split = NumOutputs(node); \ + op_params.axis = axis_value; \ + reference_ops::Split(op_params, GetTensorShape(op_context.input), \ + GetTensorData(op_context.input), \ + all_outputs.shapes(), all_outputs.data()); + switch (op_context.input->type) { + case kTfLiteFloat32: { + TF_LITE_SPLIT_V(float); + break; + } + case kTfLiteUInt8: { + TF_LITE_SPLIT_V(uint8_t); + break; + } + case kTfLiteInt16: { + TF_LITE_SPLIT_V(int16_t); + break; + } + default: + context->ReportError( + context, + "Only float32, uint8 and int16 are currently supported, got %d.", + op_context.input->type); + return kTfLiteError; + } +#undef TF_LITE_SPLIT_V + + return kTfLiteOk; +} + +} // namespace split_v + +TfLiteRegistration* Register_SPLIT_V() { + static TfLiteRegistration r = {nullptr, nullptr, split_v::Prepare, + split_v::Eval}; + return &r; +} + +} // namespace builtin +} // namespace ops +} // namespace tflite diff --git a/tensorflow/lite/kernels/split_v_test.cc b/tensorflow/lite/kernels/split_v_test.cc new file mode 100644 index 0000000000..2d1d36d685 --- /dev/null +++ b/tensorflow/lite/kernels/split_v_test.cc @@ -0,0 +1,175 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#include +#include +#include "tensorflow/lite/interpreter.h" +#include "tensorflow/lite/kernels/register.h" +#include "tensorflow/lite/kernels/test_util.h" +#include "tensorflow/lite/model.h" + +namespace tflite { +namespace { + +using ::testing::ElementsAreArray; + +constexpr int kAxisIsATensor = -1000; + +class SplitVOpModel : public SingleOpModel { + public: + SplitVOpModel(const TensorData& input, const TensorData& size_splits, + int num_splits, int axis) { + input_ = AddInput(input); + size_splits_ = AddInput(size_splits); + if (axis == kAxisIsATensor) { + axis_ = AddInput({TensorType_INT32, {1}}); + } else { + axis_ = AddConstInput(TensorType_INT32, {axis}, {1}); + } + for (int i = 0; i < num_splits; ++i) { + outputs_.push_back(AddOutput(input.type)); + } + SetBuiltinOp(BuiltinOperator_SPLIT_V, BuiltinOptions_SplitVOptions, + CreateSplitVOptions(builder_, num_splits).Union()); + if (axis == kAxisIsATensor) { + BuildInterpreter( + {GetShape(input_), GetShape(size_splits_), GetShape(axis_)}); + } else { + BuildInterpreter({GetShape(input_), GetShape(size_splits_), {}}); + } + } + + void SetInput(std::initializer_list data) { + PopulateTensor(input_, data); + } + void SetSizeSplits(std::initializer_list data) { + PopulateTensor(size_splits_, data); + } + void SetAxis(int axis) { PopulateTensor(axis_, {axis}); } + + std::vector GetOutput(int i) { + return ExtractVector(outputs_[i]); + } + std::vector GetOutputShape(int i) { return GetTensorShape(outputs_[i]); } + + private: + int input_; + int size_splits_; + int axis_; + std::vector outputs_; +}; + +// TODO(ruic): Add tests to test quantized values. b/119638735 +using TensorValues = std::initializer_list; + +void Check(int axis, std::initializer_list input_shape, + std::initializer_list size_splits_shape, + std::vector> output_shapes, + const TensorValues& input_data, + const std::initializer_list& size_splits_data, + const std::vector& output_data) { + int num_splits = size_splits_data.size(); + SplitVOpModel m({TensorType_FLOAT32, input_shape}, + {TensorType_INT32, size_splits_shape}, num_splits, + kAxisIsATensor); + m.SetInput(input_data); + m.SetSizeSplits(size_splits_data); + m.SetAxis(axis); + m.Invoke(); + for (int i = 0; i < num_splits; ++i) { + EXPECT_THAT(m.GetOutput(i), ElementsAreArray(output_data[i])); + EXPECT_THAT(m.GetOutputShape(i), ElementsAreArray(output_shapes[i])); + } + + SplitVOpModel const_m({TensorType_FLOAT32, input_shape}, + {TensorType_INT32, size_splits_shape}, num_splits, + axis); + const_m.SetInput(input_data); + const_m.SetSizeSplits(size_splits_data); + const_m.Invoke(); + for (int i = 0; i < num_splits; ++i) { + EXPECT_THAT(const_m.GetOutput(i), ElementsAreArray(output_data[i])); + EXPECT_THAT(const_m.GetOutputShape(i), ElementsAreArray(output_shapes[i])); + } +} + +TEST(SplitVOpTest, TwoDimensional) { + // Input shape: {4, 3} + // size_splits: {1, 1, 3} + // axis: 0 + // We should have 3 outpus with shapes respectively: + // output 0 : {1, 3} + // output 1 : {1, 3} + // output 1 : {2, 3} + Check(/*axis=*/0, {4, 3}, {3}, {{1, 3}, {1, 3}, {2, 3}}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, {1, 1, 2}, + {{1, 2, 3}, {4, 5, 6}, {7, 8, 9, 10, 11, 12}}); +} + +TEST(SplitVOpTest, FourDimensional) { + Check(/*axis=*/0, {2, 2, 2, 2}, {2}, {{1, 2, 2, 2}, {1, 2, 2, 2}}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, {1, 1}, + { + {1, 2, 3, 4, 5, 6, 7, 8}, + {9, 10, 11, 12, 13, 14, 15, 16}, + }); + Check(/*axis=*/1, {2, 2, 2, 2}, {2}, {{2, 1, 2, 2}, {2, 1, 2, 2}}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, {1, -1}, + { + {1, 2, 3, 4, 9, 10, 11, 12}, + {5, 6, 7, 8, 13, 14, 15, 16}, + }); + Check(/*axis=*/2, {2, 2, 2, 2}, {2}, {{2, 2, 1, 2}, {2, 2, 1, 2}}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, {1, 1}, + { + {1, 2, 5, 6, 9, 10, 13, 14}, + {3, 4, 7, 8, 11, 12, 15, 16}, + }); + Check(/*axis=*/3, {2, 2, 2, 2}, {2}, {{2, 2, 2, 1}, {2, 2, 2, 1}}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, {1, 1}, + { + {1, 3, 5, 7, 9, 11, 13, 15}, + {2, 4, 6, 8, 10, 12, 14, 16}, + }); +} + +TEST(SplitVOpTest, OneDimensional) { + Check(/*axis=*/0, {8}, {8}, {{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}, + {1, 2, 3, 4, 5, 6, 7, 8}, {1, 1, 1, 1, 1, 1, 1, 1}, + {{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}); +} + +TEST(SplitVOpTest, OneDimensional2) { + Check(/*axis=*/0, {8}, {8}, {{1}, {1}, {1}, {1}, {1}, {1}, {2}, {0}}, + {1, 2, 3, 4, 5, 6, 7, 8}, {1, 1, 1, 1, 1, 1, 2, -1}, + {{1}, {2}, {3}, {4}, {5}, {6}, {7, 8}, {}}); +} + +TEST(SplitVOpTest, NegativeAxis) { + Check(/*axis=*/-4, {2, 2, 2, 2}, {2}, {{1, 2, 2, 2}, {1, 2, 2, 2}}, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, {1, 1}, + { + {1, 2, 3, 4, 5, 6, 7, 8}, + {9, 10, 11, 12, 13, 14, 15, 16}, + }); +} + +} // namespace +} // namespace tflite + +int main(int argc, char** argv) { + ::tflite::LogToStderr(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tensorflow/lite/nnapi_delegate.cc b/tensorflow/lite/nnapi_delegate.cc index 312cedda6c..26d75696a1 100644 --- a/tensorflow/lite/nnapi_delegate.cc +++ b/tensorflow/lite/nnapi_delegate.cc @@ -685,6 +685,7 @@ TfLiteStatus AddOpsAndParams( case tflite::BuiltinOperator_SQUARED_DIFFERENCE: case tflite::BuiltinOperator_MIRROR_PAD: case tflite::BuiltinOperator_ABS: + case tflite::BuiltinOperator_SPLIT_V: logError("Op code %d is currently not delegated to NNAPI", builtin); return kTfLiteError; break; diff --git a/tensorflow/lite/schema/schema.fbs b/tensorflow/lite/schema/schema.fbs index 094db1a1d5..6436167303 100644 --- a/tensorflow/lite/schema/schema.fbs +++ b/tensorflow/lite/schema/schema.fbs @@ -204,6 +204,7 @@ enum BuiltinOperator : byte { SQUARED_DIFFERENCE = 99, MIRROR_PAD = 100, ABS = 101, + SPLIT_V = 102, } // Options for the builtin operators. @@ -286,6 +287,7 @@ union BuiltinOptions { SquaredDifferenceOptions, MirrorPadOptions, AbsOptions, + SplitVOptions, } enum Padding : byte { SAME, VALID } @@ -534,6 +536,10 @@ table SplitOptions { num_splits: int; } +table SplitVOptions { + num_splits: int; +} + table StridedSliceOptions { begin_mask: int; end_mask: int; diff --git a/tensorflow/lite/schema/schema_generated.h b/tensorflow/lite/schema/schema_generated.h index 1d560b3298..af8b143364 100755 --- a/tensorflow/lite/schema/schema_generated.h +++ b/tensorflow/lite/schema/schema_generated.h @@ -148,6 +148,9 @@ struct SqueezeOptionsT; struct SplitOptions; struct SplitOptionsT; +struct SplitVOptions; +struct SplitVOptionsT; + struct StridedSliceOptions; struct StridedSliceOptionsT; @@ -516,11 +519,12 @@ enum BuiltinOperator { BuiltinOperator_SQUARED_DIFFERENCE = 99, BuiltinOperator_MIRROR_PAD = 100, BuiltinOperator_ABS = 101, + BuiltinOperator_SPLIT_V = 102, BuiltinOperator_MIN = BuiltinOperator_ADD, - BuiltinOperator_MAX = BuiltinOperator_ABS + BuiltinOperator_MAX = BuiltinOperator_SPLIT_V }; -inline const BuiltinOperator (&EnumValuesBuiltinOperator())[101] { +inline const BuiltinOperator (&EnumValuesBuiltinOperator())[102] { static const BuiltinOperator values[] = { BuiltinOperator_ADD, BuiltinOperator_AVERAGE_POOL_2D, @@ -622,7 +626,8 @@ inline const BuiltinOperator (&EnumValuesBuiltinOperator())[101] { BuiltinOperator_LEAKY_RELU, BuiltinOperator_SQUARED_DIFFERENCE, BuiltinOperator_MIRROR_PAD, - BuiltinOperator_ABS + BuiltinOperator_ABS, + BuiltinOperator_SPLIT_V }; return values; } @@ -731,6 +736,7 @@ inline const char * const *EnumNamesBuiltinOperator() { "SQUARED_DIFFERENCE", "MIRROR_PAD", "ABS", + "SPLIT_V", nullptr }; return names; @@ -821,11 +827,12 @@ enum BuiltinOptions { BuiltinOptions_SquaredDifferenceOptions = 76, BuiltinOptions_MirrorPadOptions = 77, BuiltinOptions_AbsOptions = 78, + BuiltinOptions_SplitVOptions = 79, BuiltinOptions_MIN = BuiltinOptions_NONE, - BuiltinOptions_MAX = BuiltinOptions_AbsOptions + BuiltinOptions_MAX = BuiltinOptions_SplitVOptions }; -inline const BuiltinOptions (&EnumValuesBuiltinOptions())[79] { +inline const BuiltinOptions (&EnumValuesBuiltinOptions())[80] { static const BuiltinOptions values[] = { BuiltinOptions_NONE, BuiltinOptions_Conv2DOptions, @@ -905,7 +912,8 @@ inline const BuiltinOptions (&EnumValuesBuiltinOptions())[79] { BuiltinOptions_LeakyReluOptions, BuiltinOptions_SquaredDifferenceOptions, BuiltinOptions_MirrorPadOptions, - BuiltinOptions_AbsOptions + BuiltinOptions_AbsOptions, + BuiltinOptions_SplitVOptions }; return values; } @@ -991,6 +999,7 @@ inline const char * const *EnumNamesBuiltinOptions() { "SquaredDifferenceOptions", "MirrorPadOptions", "AbsOptions", + "SplitVOptions", nullptr }; return names; @@ -1317,6 +1326,10 @@ template<> struct BuiltinOptionsTraits { static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions; }; +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions; +}; + struct BuiltinOptionsUnion { BuiltinOptions type; void *value; @@ -1972,6 +1985,14 @@ struct BuiltinOptionsUnion { return type == BuiltinOptions_AbsOptions ? reinterpret_cast(value) : nullptr; } + SplitVOptionsT *AsSplitVOptions() { + return type == BuiltinOptions_SplitVOptions ? + reinterpret_cast(value) : nullptr; + } + const SplitVOptionsT *AsSplitVOptions() const { + return type == BuiltinOptions_SplitVOptions ? + reinterpret_cast(value) : nullptr; + } }; bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type); @@ -5048,6 +5069,60 @@ inline flatbuffers::Offset CreateSplitOptions( flatbuffers::Offset CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +struct SplitVOptionsT : public flatbuffers::NativeTable { + typedef SplitVOptions TableType; + int32_t num_splits; + SplitVOptionsT() + : num_splits(0) { + } +}; + +struct SplitVOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SplitVOptionsT NativeTableType; + enum { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { + return GetField(VT_NUM_SPLITS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NUM_SPLITS) && + verifier.EndTable(); + } + SplitVOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SplitVOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SplitVOptionsBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) { + fbb_.AddElement(SplitVOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitVOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + SplitVOptionsBuilder &operator=(const SplitVOptionsBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitVOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) { + SplitVOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + struct StridedSliceOptionsT : public flatbuffers::NativeTable { typedef StridedSliceOptions TableType; int32_t begin_mask; @@ -7301,6 +7376,9 @@ struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const AbsOptions *builtin_options_as_AbsOptions() const { return builtin_options_type() == BuiltinOptions_AbsOptions ? static_cast(builtin_options()) : nullptr; } + const SplitVOptions *builtin_options_as_SplitVOptions() const { + return builtin_options_type() == BuiltinOptions_SplitVOptions ? static_cast(builtin_options()) : nullptr; + } const flatbuffers::Vector *custom_options() const { return GetPointer *>(VT_CUSTOM_OPTIONS); } @@ -7644,6 +7722,10 @@ template<> inline const AbsOptions *Operator::builtin_options_as() c return builtin_options_as_AbsOptions(); } +template<> inline const SplitVOptions *Operator::builtin_options_as() const { + return builtin_options_as_SplitVOptions(); +} + struct OperatorBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; @@ -9261,6 +9343,32 @@ inline flatbuffers::Offset CreateSplitOptions(flatbuffers::FlatBuf _num_splits); } +inline SplitVOptionsT *SplitVOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = new SplitVOptionsT(); + UnPackTo(_o, _resolver); + return _o; +} + +inline void SplitVOptions::UnPackTo(SplitVOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = num_splits(); _o->num_splits = _e; }; +} + +inline flatbuffers::Offset SplitVOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSplitVOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SplitVOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _num_splits = _o->num_splits; + return tflite::CreateSplitVOptions( + _fbb, + _num_splits); +} + inline StridedSliceOptionsT *StridedSliceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { auto _o = new StridedSliceOptionsT(); UnPackTo(_o, _resolver); @@ -10803,6 +10911,10 @@ inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *ob auto ptr = reinterpret_cast(obj); return verifier.VerifyTable(ptr); } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } default: return false; } } @@ -11133,6 +11245,10 @@ inline void *BuiltinOptionsUnion::UnPack(const void *obj, BuiltinOptions type, c auto ptr = reinterpret_cast(obj); return ptr->UnPack(resolver); } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } default: return nullptr; } } @@ -11451,6 +11567,10 @@ inline flatbuffers::Offset BuiltinOptionsUnion::Pack(flatbuffers::FlatBuff auto ptr = reinterpret_cast(value); return CreateAbsOptions(_fbb, ptr, _rehasher).Union(); } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(value); + return CreateSplitVOptions(_fbb, ptr, _rehasher).Union(); + } default: return 0; } } @@ -11769,6 +11889,10 @@ inline BuiltinOptionsUnion::BuiltinOptionsUnion(const BuiltinOptionsUnion &u) FL value = new AbsOptionsT(*reinterpret_cast(u.value)); break; } + case BuiltinOptions_SplitVOptions: { + value = new SplitVOptionsT(*reinterpret_cast(u.value)); + break; + } default: break; } @@ -12166,6 +12290,11 @@ inline void BuiltinOptionsUnion::Reset() { delete ptr; break; } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } default: break; } value = nullptr; diff --git a/tensorflow/lite/testing/generate_examples.py b/tensorflow/lite/testing/generate_examples.py index 566723cdc2..55796846b3 100644 --- a/tensorflow/lite/testing/generate_examples.py +++ b/tensorflow/lite/testing/generate_examples.py @@ -103,8 +103,6 @@ KNOWN_BUGS = { r"batch_to_space_nd.*input_shape=\[8,2,2,2,1,1\]": "70594733", # Div will use floordiv. r"div.*int32": "72051395", - # No support for SplitV - r"split.*num_or_size_splits=\[2,2\]": "73377559", # Constant 1D gather crashes toco. r"gather_buggy.*input_shape=\[3\].*": "120029508", } @@ -1638,7 +1636,7 @@ def make_split_tests(zip_path): test_parameters = [{ "input_shape": [[1, 3, 4, 6], [2, 4, 1], [6, 4], [8]], - "num_or_size_splits": [1, 2, 3, 4, 5, [2, 2]], + "num_or_size_splits": [1, 2, 3, 4, 5], "axis": [0, 1, 2, 3, -4, -3, -2, -1], }] @@ -1656,6 +1654,29 @@ def make_split_tests(zip_path): make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) +def make_splitv_tests(zip_path): + """Make a set of tests to do tf.split_v.""" + + test_parameters = [{ + "input_shape": [[1, 3, 4, 6], [2, 4, 1], [6, 4], [8]], + "size_splits": [[2, 2], [1, 3], [4, 2], [5, 3], + [-1, 1], [-1, 2], [-1, 4]], + "axis": [0, 1, 2, 3, -4, -3, -2, -1], + }] + + def build_graph(parameters): + input_tensor = tf.placeholder( + dtype=tf.float32, name="input", shape=parameters["input_shape"]) + out = tf.split(input_tensor, parameters["size_splits"], parameters["axis"]) + return [input_tensor], [out[0]] + + def build_inputs(parameters, sess, inputs, outputs): + values = [create_tensor_data(np.float32, parameters["input_shape"])] + return values, sess.run(outputs, feed_dict=dict(zip(inputs, values))) + + make_zip_of_tests(zip_path, test_parameters, build_graph, build_inputs) + + def make_concat_tests(zip_path): """Make a set of tests to do concatenation.""" diff --git a/tensorflow/lite/toco/export_tensorflow.cc b/tensorflow/lite/toco/export_tensorflow.cc index bdc3a5b0fb..9fff001552 100644 --- a/tensorflow/lite/toco/export_tensorflow.cc +++ b/tensorflow/lite/toco/export_tensorflow.cc @@ -1158,6 +1158,29 @@ void ConvertSplitOperator(const Model& model, tensorflow_graph); } +void ConvertSplitVOperator(const Model& model, + const TensorFlowSplitVOperator& src_op, + GraphDef* tensorflow_graph) { + tensorflow::NodeDef* split_v_op = tensorflow_graph->add_node(); + split_v_op->set_op("SplitV"); + split_v_op->set_name(src_op.outputs[0]); + for (const auto& input : src_op.inputs) { + *split_v_op->add_input() = input; + } + (*split_v_op->mutable_attr())["T"].set_type( + GetTensorFlowDataType(model, src_op.inputs[0])); + (*split_v_op->mutable_attr())["num_split"].set_i(src_op.num_split); + const auto& split_dim_array = model.GetArray(src_op.inputs[1]); + CHECK(split_dim_array.buffer); + CHECK(split_dim_array.data_type == ArrayDataType::kInt32); + const auto& split_dim_data = + split_dim_array.GetBuffer().data; + CHECK_EQ(split_dim_data.size(), 1); + const int split_dim = split_dim_data[0]; + CreateDummyConcatDimTensorConst(src_op.inputs[0], split_dim, + tensorflow_graph); +} + void ConvertCastOperator(const Model& model, const CastOperator& src_op, GraphDef* tensorflow_graph) { tensorflow::NodeDef* cast_op = tensorflow_graph->add_node(); @@ -2133,6 +2156,10 @@ void ConvertOperator(const Model& model, const Operator& src_op, ConvertSplitOperator(model, static_cast(src_op), tensorflow_graph); + } else if (src_op.type == OperatorType::kSplitV) { + ConvertSplitVOperator(model, + static_cast(src_op), + tensorflow_graph); } else if (src_op.type == OperatorType::kFakeQuant) { ConvertFakeQuantOperator(static_cast(src_op), tensorflow_graph); diff --git a/tensorflow/lite/toco/graph_transformations/propagate_array_data_types.cc b/tensorflow/lite/toco/graph_transformations/propagate_array_data_types.cc index 9a458dccb9..cbae6610d7 100644 --- a/tensorflow/lite/toco/graph_transformations/propagate_array_data_types.cc +++ b/tensorflow/lite/toco/graph_transformations/propagate_array_data_types.cc @@ -86,6 +86,13 @@ void SetDataTypeForAllOutputs(Model* model, Operator* op, SetDataTypeForAllOutputs(model, op, data_type); break; } + case OperatorType::kSplitV: { + // These operators produce output with the same type as its 1st input + CHECK_GE(op->inputs.size(), 3); + const ArrayDataType data_type = model->GetArray(op->inputs[0]).data_type; + SetDataTypeForAllOutputs(model, op, data_type); + break; + } case OperatorType::kTransposeConv: { // These operators produce an output with the same type as their 3rd input CHECK_GE(op->inputs.size(), 3); diff --git a/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc b/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc index b520f7f559..fc2ed07aa0 100644 --- a/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc +++ b/tensorflow/lite/toco/graph_transformations/propagate_fixed_sizes.cc @@ -15,6 +15,7 @@ limitations under the License. #include #include #include +#include #include #include #include @@ -786,6 +787,97 @@ void ProcessTensorFlowSplitOperator(Model* model, TensorFlowSplitOperator* op) { } } +void ProcessTensorFlowSplitVOperator(Model* model, + TensorFlowSplitVOperator* op) { + CHECK_EQ(op->inputs.size(), 3); + + const auto& input_array = model->GetArray(op->inputs[0]); + // Yield until input dims have been resolved. + if (!input_array.has_shape()) { + return; + } + const Shape& input_shape = input_array.shape(); + + // Yield until size_splits is constant. + if (!IsConstantParameterArray(*model, op->inputs[1])) { + return; + } + const auto& size_array = model->GetArray(op->inputs[1]); + // Yield until size_splits dims have been resolved. + if (!size_array.has_shape()) { + return; + } + const Shape& size_shape = size_array.shape(); + + CHECK(size_array.data_type == ArrayDataType::kInt32 || + size_array.data_type == ArrayDataType::kInt64) + << "size_splits must be int32, int64"; + CHECK_EQ(size_shape.dimensions_count(), 1) << "size_splits must be 1-D"; + + std::vector size_splits_vector; + if (size_array.data_type == ArrayDataType::kInt32) { + for (const auto each_size : + size_array.GetBuffer().data) { + size_splits_vector.push_back(each_size); + } + } else { + size_splits_vector = size_array.GetBuffer().data; + } + + // Yield until axis is constant. + if (!IsConstantParameterArray(*model, op->inputs[2])) { + return; + } + const auto& axis_array = model->GetArray(op->inputs[2]); + // Yield until axis dims have been resolved. + if (!axis_array.has_shape()) { + return; + } + + CHECK(axis_array.data_type == ArrayDataType::kInt32) + << "Axis array must be int32."; + CHECK_EQ(RequiredBufferSizeForShape(axis_array.shape()), 1) + << "Axis array must be scalar."; + + int axis = axis_array.GetBuffer().data[0]; + if (axis < 0) { + axis += input_shape.dimensions_count(); + } + + CHECK_EQ(op->num_split, size_splits_vector.size()); + + int64_t minus_one_count = 0, size_splits_sum = 0; + for (auto size : size_splits_vector) { + if (size == -1) { + ++minus_one_count; + } else { + size_splits_sum += size; + } + } + + const int input_size = input_shape.dims(axis); + + CHECK_LE(minus_one_count, 1) << "size_splits can contain at most one -1."; + + if (minus_one_count == 1) { + CHECK_LE(size_splits_sum, input_size); + auto iter = + std::find(size_splits_vector.begin(), size_splits_vector.end(), -1); + *iter = input_size - size_splits_sum; + } else { + CHECK_EQ(size_splits_sum, input_size); + } + + CHECK_EQ(op->outputs.size(), op->num_split); + + for (int i = 0; i < op->outputs.size(); ++i) { + const auto& output = op->outputs[i]; + Shape output_shape = input_shape; + (*output_shape.mutable_dims())[axis] = size_splits_vector.at(i); + model->GetArray(output).copy_shape(output_shape); + } +} + void ProcessAveragePoolOperator(Model* model, AveragePoolOperator* op) { const string& input_name = op->inputs[0]; const auto& input_array = model->GetArray(input_name); @@ -1837,6 +1929,10 @@ void ProcessUnpackOperator(Model* model, UnpackOperator* op) { ProcessTensorFlowSplitOperator(model, static_cast(op)); break; + case OperatorType::kSplitV: + ProcessTensorFlowSplitVOperator( + model, static_cast(op)); + break; case OperatorType::kSqueeze: ProcessSqueezeOperator(model, static_cast(op)); break; diff --git a/tensorflow/lite/toco/import_tensorflow.cc b/tensorflow/lite/toco/import_tensorflow.cc index e42c2e2f20..aa6b4a3bc5 100644 --- a/tensorflow/lite/toco/import_tensorflow.cc +++ b/tensorflow/lite/toco/import_tensorflow.cc @@ -935,6 +935,25 @@ tensorflow::Status ConvertSplitOperator( return tensorflow::Status::OK(); } +tensorflow::Status ConvertSplitVOperator( + const NodeDef& node, const TensorFlowImportFlags& tf_import_flags, + Model* model) { + CHECK_EQ(node.op(), "SplitV"); + TF_QCHECK_OK(CheckInputsCount(node, tf_import_flags, 3)); + auto* op = new TensorFlowSplitVOperator; + op->inputs.push_back(node.input(0)); + op->inputs.push_back(node.input(1)); + op->inputs.push_back(node.input(2)); + const int num_split = GetIntAttr(node, "num_split"); + op->outputs.push_back(node.name()); + for (int i = 1; i < num_split; i++) { + op->outputs.push_back(absl::StrCat(node.name(), ":", i)); + } + op->num_split = num_split; + model->operators.emplace_back(op); + return tensorflow::Status::OK(); +} + tensorflow::Status ConvertSwitchOperator( const NodeDef& node, const TensorFlowImportFlags& tf_import_flags, Model* model) { @@ -2350,6 +2369,7 @@ ConverterMapType GetTensorFlowNodeConverterMap() { {"SpaceToDepth", ConvertSpaceToDepthOperator}, {"SparseToDense", ConvertSparseToDenseOperator}, {"Split", ConvertSplitOperator}, + {"SplitV", ConvertSplitVOperator}, {"Sqrt", ConvertSimpleOperator}, {"Square", ConvertSimpleOperator}, {"SquaredDifference", diff --git a/tensorflow/lite/toco/model.h b/tensorflow/lite/toco/model.h index a4883e4694..d4fe62ac75 100644 --- a/tensorflow/lite/toco/model.h +++ b/tensorflow/lite/toco/model.h @@ -121,6 +121,7 @@ enum class OperatorType : uint8 { kRsqrt, kShape, kSplit, + kSplitV, kSqrt, kSquare, kSquaredDifference, @@ -1401,6 +1402,12 @@ struct TensorFlowSplitOperator : Operator { int num_split = 0; }; +// TensorFlow SplitV equivalent. Refer to TensorFlow documentation for details. +struct TensorFlowSplitVOperator : Operator { + TensorFlowSplitVOperator() : Operator(OperatorType::kSplitV) {} + int num_split = 0; +}; + // TensorFlow Concat equivalent. Refer to TensorFlow documentation for details. // Not fully supported, just a placeholder to handle TensorFlow graphs and // support graph transformations to other operator types by matching sub-graphs. diff --git a/tensorflow/lite/toco/tflite/operator.cc b/tensorflow/lite/toco/tflite/operator.cc index b28781c32e..1c3bee3c5a 100644 --- a/tensorflow/lite/toco/tflite/operator.cc +++ b/tensorflow/lite/toco/tflite/operator.cc @@ -978,6 +978,26 @@ class Split int GetVersion(const Operator& op) const override { return 1; } }; +class SplitV + : public BuiltinOperator { + public: + using BuiltinOperator::BuiltinOperator; + + flatbuffers::Offset WriteOptions( + const TocoOperator& op, + flatbuffers::FlatBufferBuilder* builder) const override { + return ::tflite::CreateSplitVOptions(*builder, op.num_split); + } + + void ReadOptions(const TfLiteOptions& options, + TocoOperator* op) const override { + op->num_split = options.num_splits(); + } + + int GetVersion(const Operator& op) const override { return 1; } +}; + class StridedSlice : public BuiltinOperator> BuildOperatorList( OperatorType::kSqueeze)); ops.push_back( MakeUnique(::tflite::BuiltinOperator_SPLIT, OperatorType::kSplit)); + ops.push_back(MakeUnique(::tflite::BuiltinOperator_SPLIT_V, + OperatorType::kSplitV)); ops.push_back(MakeUnique( ::tflite::BuiltinOperator_STRIDED_SLICE, OperatorType::kStridedSlice)); ops.push_back(MakeUnique(::tflite::BuiltinOperator_TOPK_V2, diff --git a/tensorflow/lite/toco/tflite/operator_test.cc b/tensorflow/lite/toco/tflite/operator_test.cc index 16514760de..09e4435a18 100644 --- a/tensorflow/lite/toco/tflite/operator_test.cc +++ b/tensorflow/lite/toco/tflite/operator_test.cc @@ -310,6 +310,14 @@ TEST_F(OperatorTest, CustomSplit) { EXPECT_EQ(op.num_split, output_toco_op->num_split); } +TEST_F(OperatorTest, CustomSplitV) { + TensorFlowSplitVOperator op; + op.num_split = 123; + auto output_toco_op = SerializeAndDeserialize( + GetOperator("SPLIT_V", OperatorType::kSplitV), op); + EXPECT_EQ(op.num_split, output_toco_op->num_split); +} + TEST_F(OperatorTest, BuiltinAveragePool) { AveragePoolOperator op; op.fused_activation_function = FusedActivationFunctionType::kRelu6; diff --git a/tensorflow/lite/toco/tooling_util.cc b/tensorflow/lite/toco/tooling_util.cc index e3f3fe36f7..44fa658f9c 100644 --- a/tensorflow/lite/toco/tooling_util.cc +++ b/tensorflow/lite/toco/tooling_util.cc @@ -372,6 +372,7 @@ const char* OperatorTypeName(OperatorType type) { HANDLE_OPERATORTYPENAME_CASE(Shape) HANDLE_OPERATORTYPENAME_CASE(Slice) HANDLE_OPERATORTYPENAME_CASE(Split) + HANDLE_OPERATORTYPENAME_CASE(SplitV) HANDLE_OPERATORTYPENAME_CASE(Sqrt) HANDLE_OPERATORTYPENAME_CASE(Square) HANDLE_OPERATORTYPENAME_CASE(Switch) -- GitLab From 71f40f044450736cd6acd29e92ffbfc0e571ee14 Mon Sep 17 00:00:00 2001 From: Yifei Feng Date: Wed, 28 Nov 2018 21:47:10 -0800 Subject: [PATCH 522/672] Remove tf.clip_by_average_norm for TensorFlow 2.0. Also add deprecation warning. PiperOrigin-RevId: 223288438 --- tensorflow/python/kernel_tests/clip_ops_test.py | 16 ++++++++++++++++ tensorflow/python/ops/clip_ops.py | 7 ++++++- tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 4 ---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/tensorflow/python/kernel_tests/clip_ops_test.py b/tensorflow/python/kernel_tests/clip_ops_test.py index d0cd7eb302..5f1b6b6917 100644 --- a/tensorflow/python/kernel_tests/clip_ops_test.py +++ b/tensorflow/python/kernel_tests/clip_ops_test.py @@ -28,6 +28,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import clip_ops from tensorflow.python.ops import gradient_checker from tensorflow.python.ops import gradients_impl +from tensorflow.python.ops import math_ops from tensorflow.python.platform import test @@ -440,6 +441,21 @@ class ClipTest(test.TestCase): self.assertAllClose(np_ans, tf_ans) + def testClipByAverageNormReplacedWithClipByNorm(self): + # Check clip_by_average_norm(t) is the same as + # clip_by_norm(t, clip_norm * tf.to_float(tf.size(t))) + with self.session(use_gpu=True): + x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3]) + # Average norm of x = sqrt(3^2 + 4^2) / 6 = 0.83333333 + # expected answer [[-2.88, 0.0, 0.0], [3.84, 0.0, 0.0]] + clip_norm = constant_op.constant(0.8) + with_norm = clip_ops.clip_by_average_norm(x, clip_norm) + without_norm = clip_ops.clip_by_norm( + x, clip_norm * math_ops.to_float(array_ops.size(x))) + clip_by_average_norm_ans = self.evaluate(with_norm) + clip_by_norm_ans = self.evaluate(without_norm) + self.assertAllClose(clip_by_average_norm_ans, clip_by_norm_ans) + def testClipByValueEmptyTensor(self): # Test case for GitHub issue 19337 zero = array_ops.placeholder(dtype=dtypes.float32, shape=None) diff --git a/tensorflow/python/ops/clip_ops.py b/tensorflow/python/ops/clip_ops.py index 5cd626b92d..82803ac351 100644 --- a/tensorflow/python/ops/clip_ops.py +++ b/tensorflow/python/ops/clip_ops.py @@ -300,7 +300,12 @@ def clip_by_global_norm(t_list, clip_norm, use_norm=None, name=None): return list_clipped, use_norm -@tf_export("clip_by_average_norm") +@deprecation.deprecated( + date=None, + instructions= + "clip_by_average_norm is deprecated in TensorFlow 2.0. Please use " + "clip_by_norm(t, clip_norm * tf.to_float(tf.size(t), name)) instead.") +@tf_export(v1=["clip_by_average_norm"]) def clip_by_average_norm(t, clip_norm, name=None): """Clips tensor values to a maximum average L2-norm. diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index f2ae039d9f..98ea3b6839 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -528,10 +528,6 @@ tf_module { name: "cast" argspec: "args=[\'x\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "clip_by_average_norm" - argspec: "args=[\'t\', \'clip_norm\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } member_method { name: "clip_by_global_norm" argspec: "args=[\'t_list\', \'clip_norm\', \'use_norm\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " -- GitLab From f7ac6ef4e2454938c5fa6a3367892fdc112edab4 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 01:05:54 -0800 Subject: [PATCH 523/672] compat: Update forward compatibility horizon to 2018-11-29 PiperOrigin-RevId: 223304764 --- tensorflow/python/compat/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/compat/compat.py b/tensorflow/python/compat/compat.py index 1f43793962..d9613021a9 100644 --- a/tensorflow/python/compat/compat.py +++ b/tensorflow/python/compat/compat.py @@ -26,7 +26,7 @@ import datetime from tensorflow.python.util import tf_contextlib from tensorflow.python.util.tf_export import tf_export -_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 28) +_FORWARD_COMPATIBILITY_HORIZON = datetime.date(2018, 11, 29) @tf_export("compat.forward_compatible") -- GitLab From 8e16ae7463698f891f7290e62c759c9b17733a57 Mon Sep 17 00:00:00 2001 From: Thomas Joerg Date: Thu, 29 Nov 2018 01:48:48 -0800 Subject: [PATCH 524/672] [XLA:GPU] Prefactoring: Extract ShapesCompatibleForFusion from GpuMultiOutputFusion. PiperOrigin-RevId: 223310314 --- .../compiler/xla/service/gpu/gpu_fusible.cc | 51 ++++ .../compiler/xla/service/gpu/gpu_fusible.h | 10 + .../xla/service/gpu/gpu_fusible_test.cc | 264 ++++++++++++++++++ .../xla/service/gpu/multi_output_fusion.cc | 47 +--- 4 files changed, 327 insertions(+), 45 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc b/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc index 392b149abd..5eafac7232 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc @@ -81,5 +81,56 @@ bool IsInputFusibleReduction(const HloInstruction& instr) { return IsReduceInputFusion(instr) || IsReductionToVector(instr); } +bool ShapesCompatibleForMultiOutputFusion(const HloInstruction& instr1, + const HloInstruction& instr2) { + // Returns the instructions that determines the emitter used for lowering, + // sometimes referred to as "the real hero". + auto get_real_hero = + [&](const HloInstruction* instr) -> const HloInstruction* { + if (instr->opcode() == HloOpcode::kFusion) { + auto fused_expression_root = instr->fused_expression_root(); + if (instr->IsMultiOutputFusion()) { + // If possible, we want to pick a reduction-to-vector operand of the + // fusion root, because it has the most constraints. + for (const auto* inst : fused_expression_root->operands()) { + if (IsReductionToVector(*inst)) { + return inst; + } + } + return fused_expression_root->operands()[0]; + } + return fused_expression_root; + } + return instr; + }; + + // Multi-output fusion kernels share a common parallel loop. The loop + // dimenstions are determined by instruction shapes. + auto get_loop_shape = [&](const HloInstruction* element_instr) { + // Special-case reduction-to-vector ops: The loop dimensions are determined + // by the shape of the first operand. + if (IsReductionToVector(*element_instr)) { + return element_instr->operand(0)->shape(); + } + return element_instr->shape(); + }; + + // All shapes of the root tuple of multi-output fusions should agree, i.e. all + // root ops should have equal output shapes. An exception are + // reduction-to-vector ops. Here the input shapes of the reduction (first + // operand shape) need to be considered. + auto* instr_1 = get_real_hero(&instr1); + auto* instr_2 = get_real_hero(&instr2); + // TODO(tjoerg): Relax the shape constraint. The datatype does not matter. + if (IsReductionToVector(*instr_1) && IsReductionToVector(*instr_2) && + !ShapeUtil::Equal(instr_1->shape(), instr_2->shape())) { + return false; + } + // The elementwise output shapes must be the same (including layout). + // TODO(tjoerg): Further relax the constraint. The datatype does not matter. + return ShapeUtil::EqualIgnoringFpPrecision(get_loop_shape(instr_1), + get_loop_shape(instr_2)); +} + } // namespace gpu } // namespace xla diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible.h b/tensorflow/compiler/xla/service/gpu/gpu_fusible.h index c0be354730..e9d7ba1c4c 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible.h +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible.h @@ -46,6 +46,16 @@ bool IsReduceInputFusion(const HloInstruction& instr); // is either an unfused reduction-to-vector op or a reduce input fusion. bool IsInputFusibleReduction(const HloInstruction& instr); +// Whether instruction shapes are compatible for multi-output fusion, i.e. +// whether the emitters support lowering the resulting fusion. +// This function works for both, sibling and producer-conumser multi-output +// fusion. +// So far, multi-output fusion is supported for loop fusions and reduce +// input fusions only. It is up to the caller to ensure the instructions +// themselves are fusible! +bool ShapesCompatibleForMultiOutputFusion(const HloInstruction& instr1, + const HloInstruction& instr2); + } // namespace gpu } // namespace xla diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc b/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc index 12222500ea..ca07851f8b 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc @@ -336,5 +336,269 @@ TEST_F(GpuFusibleTest, EXPECT_FALSE(IsInputFusibleReduction(*reduce)); } +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_LoopFusions) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_computation_1 { + p0.1 = f32[6400]{0} parameter(0) + ROOT mul = f32[6400]{0} multiply(p0.1, p0.1) + } + + fused_computation_2 { + p0.2 = f32[6400]{0} parameter(0) + const.2 = f32[] constant(1) + ROOT div = f32[6400]{0} divide(p0.2, const.2) + } + + ENTRY entry { + p0 = f32[6400]{0} parameter(0) + fusion.1 = f32[6400]{0} fusion(p0), kind=kLoop, calls=fused_computation_1 + fusion.2 = f32[6400]{0} fusion(p0), kind=kLoop, calls=fused_computation_2 + ROOT root = (f32[6400]{0}, f32[6400]{0}) tuple(fusion.1, fusion.2) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_IgnoreFpPrecision) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_computation_1 { + p0.1 = f32[6400]{0} parameter(0) + ROOT mul = f32[6400]{0} multiply(p0.1, p0.1) + } + + fused_computation_2 { + p0.2 = f32[6400]{0} parameter(0) + ROOT convert = f16[6400]{0} convert(p0.2) + } + + ENTRY entry { + p0 = f32[6400]{0} parameter(0) + fusion.1 = f32[6400]{0} fusion(p0), kind=kLoop, calls=fused_computation_1 + fusion.2 = f32[6400]{0} fusion(p0), kind=kLoop, calls=fused_computation_2 + ROOT root = (f32[6400]{0}, f32[6400]{0}) tuple(fusion.1, fusion.2) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_Reduce) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_computation_1 { + p0.1 = f32[6400]{0} parameter(0) + ROOT mul = f32[6400]{0} multiply(p0.1, p0.1) + } + + ENTRY entry { + p0 = f32[6400]{0} parameter(0) + fusion.1 = f32[6400]{0} fusion(p0), kind=kLoop, calls=fused_computation_1 + const.2 = f32[] constant(0) + reduce = f32[] reduce(p0, const.2), dimensions={0}, to_apply=scalar_add + ROOT root = (f32[6400]{0}, f32[]) tuple(fusion.1, reduce) + })")) + .ValueOrDie(); + const HloInstruction* fusion = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* reduce = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion, *reduce)); +} + +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_Elementwise) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_computation_1 { + p0.1 = f32[6400]{0} parameter(0) + ROOT mul = f32[6400]{0} multiply(p0.1, p0.1) + } + + ENTRY entry { + p0 = f32[6400]{0} parameter(0) + fusion.1 = f32[6400]{0} fusion(p0), kind=kLoop, calls=fused_computation_1 + const.2 = f32[] constant(1) + div = f32[6400]{0} divide(p0, const.2) + ROOT root = (f32[6400]{0}, f32[6400]{0}) tuple(fusion.1, div) + })")) + .ValueOrDie(); + const HloInstruction* fusion = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* div = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion, *div)); +} + +TEST_F(GpuFusibleTest, + ShapesCompatibleForMultiOutputFusion_MultiOutputLoopFusion) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_computation_1 { + p0.1 = f32[8,1,5,16,1,1]{5,4,3,2,1,0} parameter(0) + mul = f32[8,1,5,16,1,1]{5,4,3,2,1,0} multiply(p0.1, p0.1) + exp = f32[8,1,5,16,1,1]{5,4,3,2,1,0} exponential(p0.1) + ROOT tuple = (f32[8,1,5,16,1,1]{5,4,3,2,1,0}, f32[8,1,5,16,1,1]{5,4,3,2,1,0}) tuple(mul, exp) + } + + fused_computation_2 { + p0.2 = f32[8,1,5,16,1,1]{5,4,3,2,1,0} parameter(0) + const.2 = f32[] constant(0) + ROOT add = f32[8,1,5,16,1,1]{5,4,3,2,1,0} add(p0.2, const.2) + } + + ENTRY entry { + p0 = f32[8,1,5,16,1,1]{5,4,3,2,1,0} parameter(0) + fusion.1 = (f32[8,1,5,16,1,1]{5,4,3,2,1,0}, f32[8,1,5,16,1,1]{5,4,3,2,1,0}) fusion(p0), kind=kLoop, calls=fused_computation_1 + fusion.2 = f32[8,1,5,16,1,1]{5,4,3,2,1,0} fusion(p0), kind=kLoop, calls=fused_computation_2 + gte0 = f32[8,1,5,16,1,1]{5,4,3,2,1,0} get-tuple-element(fusion.1), index=0 + gte1 = f32[8,1,5,16,1,1]{5,4,3,2,1,0} get-tuple-element(fusion.1), index=1 + ROOT root = (f32[8,1,5,16,1,1]{5,4,3,2,1,0}, f32[8,1,5,16,1,1]{5,4,3,2,1,0}, f32[8,1,5,16,1,1]{5,4,3,2,1,0}) tuple(gte0, gte1, fusion.2) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0)->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1)->operand(0); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_UnfusedOps) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + ENTRY reduce { + p0 = f32[2,2,2]{2,1,0} parameter(0) + c0 = f32[] constant(0) + exp = f32[2,2,2]{2,1,0} exponential(p0) + reduce = f32[2,2]{1,0} reduce(exp, c0), dimensions={2}, to_apply=scalar_add + ROOT root = (f32[2,2]{1,0}, f32[2,2,2]{2,1,0}) tuple(reduce, exp) + })")) + .ValueOrDie(); + const HloInstruction* reduce = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* exp = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*reduce, *exp)); +} + +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_DifferentLayouts) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + ENTRY reduce { + p0 = f32[2,2,2]{2,1,0} parameter(0) + p1 = f32[2,2,2]{0,1,2} parameter(1) + c0 = f32[] constant(0) + exp = f32[2,2,2]{2,1,0} exponential(p0) + reduce = f32[2,2]{0,1} reduce(p1, c0), dimensions={2}, to_apply=scalar_add + ROOT root = (f32[2,2]{0,1}, f32[2,2,2]{2,1,0}) tuple(reduce, exp) + })")) + .ValueOrDie(); + const HloInstruction* reduce = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* exp = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_FALSE(ShapesCompatibleForMultiOutputFusion(*reduce, *exp)); +} + +TEST_F(GpuFusibleTest, + ShapesCompatibleForMultiOutputFusion_MultiOutputReduceFusion) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_select { + p1.1 = f32[2,2,2]{2,1,0} parameter(1) + c0 = f32[] constant(0) + broadcast = f32[2,2,2]{2,1,0} broadcast(f32[] c0), dimensions={} + greater-than = pred[2,2,2]{2,1,0} greater-than(f32[2,2,2]{2,1,0} p1.1, f32[2,2,2]{2,1,0} broadcast) + p0.1 = f32[2,2,2]{2,1,0} parameter(0) + ROOT select = f32[2,2,2]{2,1,0} select(pred[2,2,2]{2,1,0} greater-than, f32[2,2,2]{2,1,0} p0.1, f32[2,2,2]{2,1,0} broadcast) + } + + fused_reduce { + p0.2 = f32[2,2,2]{2,1,0} parameter(0) + c1 = f32[] constant(0) + r1 = f32[2,2]{1,0} reduce(p0.2, c1), dimensions={2}, to_apply=scalar_add + mul = f32[2,2,2]{2,1,0} multiply(p0.2, p0.2) + r2 = f32[2,2]{1,0} reduce(mul, c1), dimensions={2}, to_apply=scalar_add + ROOT tuple = (f32[2,2]{1,0}, f32[2,2]{1,0}) tuple(r1, r2) + } + + ENTRY reduce { + p0 = f32[2,2,2]{2,1,0} parameter(0) + p1 = f32[2,2,2]{2,1,0} parameter(1) + select = f32[2,2,2]{2,1,0} fusion(p0, p1), kind=kLoop, calls=fused_select + fusion = (f32[2,2]{1,0}, f32[2,2]{1,0}) fusion(select), kind=kInput, calls=fused_reduce + gte0 = f32[2,2]{1,0} get-tuple-element(fusion), index=0 + gte1 = f32[2,2]{1,0} get-tuple-element(fusion), index=1 + ROOT root = (f32[2,2]{1,0}, f32[2,2]{1,0}, f32[2,2,2]{2,1,0}) tuple(gte1, gte1, select) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0)->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1)->operand(0); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + +TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_ReduceFusions) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_reduce_1 { + p0.1 = f32[2,2,2]{2,1,0} parameter(0) + c0 = f32[] constant(0) + ROOT reduce = f32[2,2]{1,0} reduce(f32[2,2,2]{2,1,0} p0.1, f32[] c0), dimensions={0}, to_apply=scalar_add + } + + fused_reduce_2 { + p0.2 = f32[2,2,2]{2,1,0} parameter(0) + mul = f32[2,2,2]{2,1,0} multiply(f32[2,2,2]{2,1,0} p0.2, f32[2,2,2]{2,1,0} p0.2) + c1 = f32[] constant(0) + ROOT reduce = f32[2,2]{1,0} reduce(f32[2,2,2]{2,1,0} mul, f32[] c1), dimensions={0}, to_apply=scalar_add + } + + ENTRY reduce { + p0 = f32[2,2,2]{2,1,0} parameter(0) + p1 = f32[2,2,2]{2,1,0} parameter(1) + reduce_1 = f32[2,2]{1,0} fusion(p0), kind=kLoop, calls=fused_reduce_1 + reduce_2 = f32[2,2]{1,0} fusion(p1), kind=kLoop, calls=fused_reduce_2 + ROOT root = (f32[2,2]{1,0}, f32[2,2,2]{2,1,0}) tuple(reduce_1, reduce_2) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + +TEST_F(GpuFusibleTest, + ShapesCompatibleForMultiOutputFusion_NoReductionToVector) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_element_wise { + p0.1 = f32[2,2,2]{2,1,0} parameter(0) + p1.1 = f32[2,2,2]{2,1,0} parameter(1) + ROOT add = f32[2,2,2]{2,1,0} add(p0.1, p1.1) + } + + fused_reduce { + p0.2 = f32[2,2,2]{2,1,0} parameter(0) + mul = f32[2,2,2]{2,1,0} multiply(f32[2,2,2]{2,1,0} p0.2, f32[2,2,2]{2,1,0} p0.2) + c1 = f32[] constant(0) + // Note that reduce is not a reduction-to-vector. + ROOT reduce = f32[2,2]{1,0} reduce(f32[2,2,2]{2,1,0} mul, f32[] c1), dimensions={1}, to_apply=scalar_add + } + + ENTRY reduce { + p0 = f32[2,2,2]{2,1,0} parameter(0) + p1 = f32[2,2,2]{2,1,0} parameter(1) + element_wise = f32[2,2,2]{2,1,0} fusion(p0, p1), kind=kLoop, calls=fused_element_wise + fusion = (f32[2,2]{1,0}, f32[2,2]{1,0}) fusion(element_wise), kind=kLoop, calls=fused_reduce + ROOT root = (f32[2,2]{1,0}, f32[2,2,2]{2,1,0}) tuple(fusion, element_wise) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_FALSE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + } // namespace gpu } // namespace xla diff --git a/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc b/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc index d9b06828e2..01fddcede6 100644 --- a/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc +++ b/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc @@ -41,50 +41,7 @@ GpuMultiOutputFusion::GpuMultiOutputFusion() : MultiOutputFusion(INT64_MAX) {} bool GpuMultiOutputFusion::ShapesCompatibleForFusion(HloInstruction* instr1, HloInstruction* instr2) { - auto get_element_instr = - [&](const HloInstruction* instr) -> const HloInstruction* { - const HloInstruction* element_instr = instr; - if (instr->opcode() == HloOpcode::kFusion) { - auto fused_expression_root = instr->fused_expression_root(); - if (instr->IsMultiOutputFusion()) { - // If possible, we want to pick a reduce operand of the fusion root, - // because it has the most constraints. - for (const auto* inst : fused_expression_root->operands()) { - if (IsReductionToVector(*inst)) { - return inst; - } - } - return fused_expression_root->operands()[0]; - } else { - element_instr = fused_expression_root; - } - } - return element_instr; - }; - - auto get_element_shape = [&](const HloInstruction* element_instr) { - // Special handling of kReduce instructions -- the fusion - // applies to the first operand. - if (IsReductionToVector(*element_instr)) { - return element_instr->operand(0)->shape(); - } - return element_instr->shape(); - }; - - // The shapes in all tuple operands should agree, unless it is a reduce. - // In that case, the operand of the reduce needs to have the same shape - // as the other tuple operands, but also we need to compare the output - // shapes of the reduces. - auto* element_instr_1 = get_element_instr(instr1); - auto* element_instr_2 = get_element_instr(instr2); - if (element_instr_1->opcode() == HloOpcode::kReduce && - element_instr_2->opcode() == HloOpcode::kReduce && - !ShapeUtil::Equal(element_instr_1->shape(), element_instr_2->shape())) { - return false; - } - // The elementwise output shapes must be the same (including layout). - return ShapeUtil::EqualIgnoringFpPrecision( - get_element_shape(element_instr_1), get_element_shape(element_instr_2)); + return ShapesCompatibleForMultiOutputFusion(*instr1, *instr2); } bool GpuMultiOutputFusion::IsFusible(HloInstruction* instr) { @@ -205,7 +162,7 @@ bool GpuMultiOutputFusion::DoProducerConsumerMultiOutputFusion() { VLOG(3) << producer->name() << " is not a loop fusion."; continue; } - if (!ShapesCompatibleForFusion(producer, consumer)) { + if (!ShapesCompatibleForMultiOutputFusion(*producer, *consumer)) { VLOG(3) << producer->name() << " has an incompatible shape."; continue; } -- GitLab From 85cc252af0b927ce9ebe582678986f264362076f Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 29 Nov 2018 02:38:40 -0800 Subject: [PATCH 525/672] [TF:XLA] Fix implementation of xdivy/xlogy Select only implicitly broadcasts the predicate operand (it's weird). Get the zeros in the right type. As far as I can see this never worked. PiperOrigin-RevId: 223315554 --- tensorflow/compiler/tests/binary_ops_test.py | 15 +++++++++++++++ tensorflow/compiler/tf2xla/kernels/binary_ops.cc | 16 ++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/tensorflow/compiler/tests/binary_ops_test.py b/tensorflow/compiler/tests/binary_ops_test.py index 332381c59e..9a5423c1b2 100644 --- a/tensorflow/compiler/tests/binary_ops_test.py +++ b/tensorflow/compiler/tests/binary_ops_test.py @@ -218,6 +218,21 @@ class BinaryOpsTest(xla_test.XLATestCase): ], equality_test=self.ListsAreClose) + # TF doesn't define these for bf16. + if dtype != dtypes.bfloat16.as_numpy_dtype: + self._testBinary( + gen_math_ops.xdivy, + np.array([0, 4, 3, 2, 1, 0], dtype=dtype), + np.array([0, 5, 6, 7, 8, float("NaN")], dtype=dtype), + expected=np.array([0, 0.8, 0.5, 0.285714, 0.125, 0], dtype=dtype)) + + self._testBinary( + gen_math_ops.xlogy, + np.array([0, 4, 3, 2, 1, 0], dtype=dtype), + np.array([0, 5, 6, 7, 8, float("NaN")], dtype=dtype), + expected=np.array([0, 6.437752, 5.375278, 3.89182, 2.079442, 0], + dtype=dtype)) + def testIntOps(self): for dtype in self.signed_int_types: self._testBinary( diff --git a/tensorflow/compiler/tf2xla/kernels/binary_ops.cc b/tensorflow/compiler/tf2xla/kernels/binary_ops.cc index 74c1dd2406..5e9280c1fe 100644 --- a/tensorflow/compiler/tf2xla/kernels/binary_ops.cc +++ b/tensorflow/compiler/tf2xla/kernels/binary_ops.cc @@ -106,23 +106,23 @@ static xla::XlaOp FloorDivImpl(xla::XlaBuilder* b, DataType dtype, xla::XlaOp x, XLA_MAKE_BINARY(FloorDiv, FloorDivImpl(b, input_type(0), lhs, rhs, broadcast_helper)); -static xla::XlaOp XlogyImpl(xla::XlaBuilder* b, DataType dtype, xla::XlaOp x, - xla::XlaOp y, const BCast& broadcast_helper) { +xla::XlaOp XlogyImpl(xla::XlaOp x, xla::XlaOp y, + const BCast& broadcast_helper) { std::tie(x, y) = XlaBinaryOp::Broadcast(x, y, broadcast_helper); - auto zero = XlaHelpers::Zero(b, dtype); + auto zero = xla::ZerosLike(x); auto is_zero = xla::Eq(x, zero); return xla::Select(is_zero, zero, xla::Mul(x, xla::Log(y))); } -XLA_MAKE_BINARY(Xlogy, XlogyImpl(b, input_type(0), lhs, rhs, broadcast_helper)); +XLA_MAKE_BINARY(Xlogy, XlogyImpl(lhs, rhs, broadcast_helper)); -static xla::XlaOp XdivyImpl(xla::XlaBuilder* b, DataType dtype, xla::XlaOp x, - xla::XlaOp y, const BCast& broadcast_helper) { +xla::XlaOp XdivyImpl(xla::XlaOp x, xla::XlaOp y, + const BCast& broadcast_helper) { std::tie(x, y) = XlaBinaryOp::Broadcast(x, y, broadcast_helper); - auto zero = XlaHelpers::Zero(b, dtype); + auto zero = xla::ZerosLike(x); auto is_zero = xla::Eq(x, zero); return xla::Select(is_zero, zero, xla::Div(x, y)); } -XLA_MAKE_BINARY(Xdivy, XdivyImpl(b, input_type(0), lhs, rhs, broadcast_helper)); +XLA_MAKE_BINARY(Xdivy, XdivyImpl(lhs, rhs, broadcast_helper)); // Implementation of FloorMod. Pseudo-code: // T trunc_mod = std::fmod(x, y); -- GitLab From 3db3e972a33760ebe6662341d5f4320a906582f7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 03:01:51 -0800 Subject: [PATCH 526/672] Enable formatting and format depthwiseconv_uint8_3x3_filter.h This was disabled due to a bug in clang-format, which is fixed now. PiperOrigin-RevId: 223317889 --- .../depthwiseconv_uint8_3x3_filter.h | 168 ++++++++++-------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8_3x3_filter.h b/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8_3x3_filter.h index 3f2ed0b1f0..5859bcaed4 100644 --- a/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8_3x3_filter.h +++ b/tensorflow/lite/kernels/internal/optimized/depthwiseconv_uint8_3x3_filter.h @@ -23,11 +23,6 @@ limitations under the License. namespace tflite { namespace optimized_ops { -// clang-format gets confused with this file and ends up formatting lines to -// be larger than 80 characters. Turn off here and back on at the end of the -// file. -// clang-format off - // See CategorizeDotProductKernel for definitive taxonomy. enum class DotProduct3x3KernelType { kNone = 0, // Parameter combination is not supported for dot product kernels. @@ -120,42 +115,58 @@ struct DepthwiseConvParams { #define OFFSET_OUTPUT_WIDTH 84 #define OFFSET_OUTPUT_HEIGHT 88 -static_assert(offsetof(DepthwiseConvParams, input_depth) == - OFFSET_INPUT_DEPTH, ""); +static_assert(offsetof(DepthwiseConvParams, input_depth) == OFFSET_INPUT_DEPTH, + ""); static_assert(offsetof(DepthwiseConvParams, input_row_size) == - OFFSET_INPUT_ROW_SIZE, ""); + OFFSET_INPUT_ROW_SIZE, + ""); static_assert(offsetof(DepthwiseConvParams, output_depth) == - OFFSET_OUTPUT_DEPTH, ""); + OFFSET_OUTPUT_DEPTH, + ""); static_assert(offsetof(DepthwiseConvParams, output_row_size) == - OFFSET_OUTPUT_ROW_SIZE, ""); + OFFSET_OUTPUT_ROW_SIZE, + ""); static_assert(offsetof(DepthwiseConvParams, filter_row_size) == - OFFSET_FILTER_ROW_SIZE, ""); + OFFSET_FILTER_ROW_SIZE, + ""); static_assert(offsetof(DepthwiseConvParams, input_offset) == - OFFSET_INPUT_OFFSET, ""); + OFFSET_INPUT_OFFSET, + ""); static_assert(offsetof(DepthwiseConvParams, output_offset) == - OFFSET_OUTPUT_OFFSET, ""); + OFFSET_OUTPUT_OFFSET, + ""); static_assert(offsetof(DepthwiseConvParams, filter_offset) == - OFFSET_FILTER_OFFSET, ""); + OFFSET_FILTER_OFFSET, + ""); static_assert(offsetof(DepthwiseConvParams, output_multiplier) == - OFFSET_OUTPUT_MULTIPLIER, ""); + OFFSET_OUTPUT_MULTIPLIER, + ""); static_assert(offsetof(DepthwiseConvParams, output_activation_min) == - OFFSET_OUTPUT_ACTIVATION_MIN, ""); + OFFSET_OUTPUT_ACTIVATION_MIN, + ""); static_assert(offsetof(DepthwiseConvParams, output_activation_max) == - OFFSET_OUTPUT_ACTIVATION_MAX, ""); + OFFSET_OUTPUT_ACTIVATION_MAX, + ""); static_assert(offsetof(DepthwiseConvParams, output_right_shift) == - OFFSET_OUTPUT_RIGHT_SHIFT, ""); -static_assert(offsetof(DepthwiseConvParams, input_width) == - OFFSET_INPUT_WIDTH, ""); + OFFSET_OUTPUT_RIGHT_SHIFT, + ""); +static_assert(offsetof(DepthwiseConvParams, input_width) == OFFSET_INPUT_WIDTH, + ""); static_assert(offsetof(DepthwiseConvParams, input_height) == - OFFSET_INPUT_HEIGHT, ""); + OFFSET_INPUT_HEIGHT, + ""); static_assert(offsetof(DepthwiseConvParams, stride_width) == - OFFSET_STRIDE_WIDTH, ""); + OFFSET_STRIDE_WIDTH, + ""); static_assert(offsetof(DepthwiseConvParams, stride_height) == - OFFSET_STRIDE_HEIGHT, ""); + OFFSET_STRIDE_HEIGHT, + ""); static_assert(offsetof(DepthwiseConvParams, output_width) == - OFFSET_OUTPUT_WIDTH, ""); + OFFSET_OUTPUT_WIDTH, + ""); static_assert(offsetof(DepthwiseConvParams, output_height) == - OFFSET_OUTPUT_HEIGHT, ""); + OFFSET_OUTPUT_HEIGHT, + ""); template struct DepthwiseConvWindow {}; @@ -164,10 +175,10 @@ template <> struct DepthwiseConvWindow<8, 1, 1> { public: static inline void Run(const uint8* input_ptr, const uint8* filter_ptr, - const int32* bias_ptr, uint8* output_ptr, int64_t input_depth, - int64_t input_row_size, int32 output_window_height, - int32 output_window_width, - const DepthwiseConvParams* params_ptr) { + const int32* bias_ptr, uint8* output_ptr, + int64_t input_depth, int64_t input_row_size, + int32 output_window_height, int32 output_window_width, + const DepthwiseConvParams* params_ptr) { const int64_t input_width_increment = 2 * input_depth; const int64_t input_height_increment = 2 * input_row_size; const int64_t output_height_increment = 2 * params_ptr->output_row_size; @@ -1147,10 +1158,10 @@ struct DepthwiseConvWindow<8, 1, 1> { template <> struct DepthwiseConvWindow<8, 2, 2> { static inline void Run(const uint8* input_ptr, const uint8* filter_ptr, - const int32* bias_ptr, uint8* output_ptr, int64_t input_depth, - int64_t input_row_size, int32 output_window_height, - int32 output_window_width, - const DepthwiseConvParams* params_ptr) { + const int32* bias_ptr, uint8* output_ptr, + int64_t input_depth, int64_t input_row_size, + int32 output_window_height, int32 output_window_width, + const DepthwiseConvParams* params_ptr) { const int64_t input_width_increment = 4 * input_depth; const int64_t input_height_increment = 4 * input_row_size; const int64_t output_height_increment = 2 * params_ptr->output_row_size; @@ -2990,11 +3001,10 @@ struct ShuffleParams { ShuffleParams() = default; ShuffleParams(int32 output_width, int32 output_height, int32 stride_width, int32 stride_height) - : output_width(output_width) - , output_height(output_height) - , input_width(get_shuffle_input_size(stride_width, output_width)) - , input_height(get_shuffle_input_size(stride_height, output_height)) { - } + : output_width(output_width), + output_height(output_height), + input_width(get_shuffle_input_size(stride_width, output_width)), + input_height(get_shuffle_input_size(stride_height, output_height)) {} }; template @@ -3003,10 +3013,10 @@ struct DepthwiseConvThroughDepth { // |start_depth| to |end_depth|. Keep this not inlined to maintain a small // binary size. We use a DepthwiseConvParams struct for read only params // to minimize call overhead. - static __attribute__((noinline)) void Run(const uint8* input_ptr, - const uint8* filter_ptr, const int32* bias_ptr, uint8* output_ptr, - int64_t start_depth, int64_t end_depth, int64_t input_depth, - int64_t input_row_size, int32 output_window_height, + static __attribute__((noinline)) void Run( + const uint8* input_ptr, const uint8* filter_ptr, const int32* bias_ptr, + uint8* output_ptr, int64_t start_depth, int64_t end_depth, + int64_t input_depth, int64_t input_row_size, int32 output_window_height, int32 output_window_width, const DepthwiseConvParams& params) { for (; start_depth <= end_depth - 8; start_depth += 8) { DepthwiseConvWindow<8, kStrideWidth, kStrideHeight>::Run( @@ -3029,12 +3039,15 @@ struct DepthwiseConvMultiRow { uint8* output_data, const DepthwiseConvParams& params, const ShuffleParams& shuffle_params, uint8* shuffle_workspace) { - TFLITE_DCHECK(shuffle_params.input_height == + TFLITE_DCHECK( + shuffle_params.input_height == get_shuffle_input_size(kStrideHeight, shuffle_params.output_height)); - TFLITE_DCHECK(shuffle_params.input_width == + TFLITE_DCHECK( + shuffle_params.input_width == get_shuffle_input_size(kStrideWidth, shuffle_params.output_width)); - TFLITE_DCHECK(64 * shuffle_params.input_width * shuffle_params.input_height - <= DEPTHWISECONV_SHUFFLE_WORKSPACE_SIZE); + TFLITE_DCHECK(64 * shuffle_params.input_width * + shuffle_params.input_height <= + DEPTHWISECONV_SHUFFLE_WORKSPACE_SIZE); int32 out_x = start_x; @@ -3045,7 +3058,7 @@ struct DepthwiseConvMultiRow { if (params.output_depth > 64 || (params.output_depth <= 64 && params.input_width > 150)) { for (; out_x <= (end_x - shuffle_params.output_width); - out_x += shuffle_params.output_width) { + out_x += shuffle_params.output_width) { const uint8* input_ptr = input_data; const int32* bias_ptr = bias_data; const uint8* filter_ptr = filter_data; @@ -3091,8 +3104,8 @@ struct DepthwiseConvMultiRow { } // Handle leftover depth. - ConvKernel::Run(input_ptr, filter_ptr, bias_ptr, output_ptr, - depth, params.output_depth, params.input_depth, + ConvKernel::Run(input_ptr, filter_ptr, bias_ptr, output_ptr, depth, + params.output_depth, params.input_depth, params.input_row_size, shuffle_params.output_height, shuffle_params.output_width, params); @@ -3119,13 +3132,15 @@ struct DepthwiseConvMultiRow { // * Horizontal edges. // * Vertical edges. inline void DepthwiseConvHandlePadding(const uint8* input_data, - const uint8* filter_data, const int32* bias_data, uint8* output_data, - const DepthwiseConvParams& params) { + const uint8* filter_data, + const int32* bias_data, + uint8* output_data, + const DepthwiseConvParams& params) { if (params.input_width == 1 && params.input_height == 1) { - const uint8* filter_ptr = filter_data + params.filter_row_size - + params.output_depth; - DepthwiseConvPartial::Run(input_data, filter_ptr, - bias_data, output_data, ¶ms); + const uint8* filter_ptr = + filter_data + params.filter_row_size + params.output_depth; + DepthwiseConvPartial::Run( + input_data, filter_ptr, bias_data, output_data, ¶ms); return; } @@ -3136,27 +3151,27 @@ inline void DepthwiseConvHandlePadding(const uint8* input_data, // Handle top row. const uint8* input_ptr = input_data; - const uint8* filter_ptr = filter_data + params.filter_row_size - + params.output_depth; + const uint8* filter_ptr = + filter_data + params.filter_row_size + params.output_depth; uint8* output_ptr = output_data; - DepthwiseConvPartial::Run(input_ptr, filter_ptr, - bias_data, output_ptr, ¶ms); + DepthwiseConvPartial::Run( + input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); input_ptr += (params.stride_width - 1) * params.input_depth; filter_ptr = filter_data + params.filter_row_size; output_ptr += params.output_depth; for (int32 out_x = out_x_start_corner + 1; out_x < out_x_end_corner; - out_x++) { + out_x++) { DepthwiseConvPartial::Run( input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); input_ptr += params.stride_width * params.input_depth; output_ptr += params.output_depth; } - DepthwiseConvPartial::Run(input_ptr, filter_ptr, - bias_data, output_ptr, ¶ms); + DepthwiseConvPartial::Run( + input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); // Handle left side. input_ptr = input_data + (params.stride_width - 1) * params.input_row_size; @@ -3164,7 +3179,7 @@ inline void DepthwiseConvHandlePadding(const uint8* input_data, output_ptr = output_data + params.output_row_size; for (int32 out_y = out_y_start_corner + 1; out_y < out_y_end_corner; - out_y++) { + out_y++) { DepthwiseConvPartial::Run( input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); input_ptr += params.stride_width * params.input_row_size; @@ -3172,14 +3187,14 @@ inline void DepthwiseConvHandlePadding(const uint8* input_data, } // Handle right side. - input_ptr = input_data + (params.input_width - 2) * params.input_depth - + (params.stride_width - 1) * params.input_row_size; + input_ptr = input_data + (params.input_width - 2) * params.input_depth + + (params.stride_width - 1) * params.input_row_size; filter_ptr = filter_data; output_ptr = output_data + params.output_row_size + - (params.output_width - 1) * params.output_depth; + (params.output_width - 1) * params.output_depth; for (int32 out_y = out_y_start_corner + 1; out_y < out_y_end_corner; - out_y++) { + out_y++) { DepthwiseConvPartial::Run( input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); input_ptr += params.stride_width * params.input_row_size; @@ -3189,26 +3204,26 @@ inline void DepthwiseConvHandlePadding(const uint8* input_data, // Handle bottom row. input_ptr = input_data + (params.input_height - 2) * params.input_row_size; filter_ptr = filter_data + params.output_depth; - output_ptr = output_data + - (params.output_height - 1) * params.output_row_size; + output_ptr = + output_data + (params.output_height - 1) * params.output_row_size; - DepthwiseConvPartial::Run(input_ptr, filter_ptr, - bias_data, output_ptr, ¶ms); + DepthwiseConvPartial::Run( + input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); input_ptr += (params.stride_width == 1) ? 0 : params.input_depth; filter_ptr = filter_data; output_ptr += params.output_depth; for (int32 out_x = out_x_start_corner + 1; out_x < out_x_end_corner; - out_x++) { + out_x++) { DepthwiseConvPartial::Run( input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); input_ptr += params.stride_width * params.input_depth; output_ptr += params.output_depth; } - DepthwiseConvPartial::Run(input_ptr, filter_ptr, - bias_data, output_ptr, ¶ms); + DepthwiseConvPartial::Run( + input_ptr, filter_ptr, bias_data, output_ptr, ¶ms); } inline bool Fast3x3FilterKernelSupported( @@ -3383,8 +3398,8 @@ inline void DepthwiseConv3x3Filter( const int in_x = (out_x * stride_width) - pad_width; const int in_y = (out_y * stride_height) - pad_height; input_ptr += in_y * params.input_row_size + in_x * params.input_depth; - output_ptr += out_y * params.output_row_size - + out_x * params.output_depth; + output_ptr += + out_y * params.output_row_size + out_x * params.output_depth; } // Shuffling shapes that maximize width over the shuffle workspace size @@ -3439,7 +3454,6 @@ inline void DepthwiseConv3x3Filter( } } } -// clang-format on #endif // __aarch64__ -- GitLab From 567b2af37ef10fb0a6ae9727410b202c9b33adb3 Mon Sep 17 00:00:00 2001 From: Thomas Joerg Date: Thu, 29 Nov 2018 07:15:16 -0800 Subject: [PATCH 527/672] [XLA:GPU] Make sure reduction dimensions match for multi-output fusion. PiperOrigin-RevId: 223340884 --- .../compiler/xla/service/gpu/gpu_fusible.cc | 5 +-- .../xla/service/gpu/gpu_fusible_test.cc | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc b/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc index 5eafac7232..452e763a8e 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible.cc @@ -118,12 +118,13 @@ bool ShapesCompatibleForMultiOutputFusion(const HloInstruction& instr1, // All shapes of the root tuple of multi-output fusions should agree, i.e. all // root ops should have equal output shapes. An exception are // reduction-to-vector ops. Here the input shapes of the reduction (first - // operand shape) need to be considered. + // operand shape) and the reduction dimensions need to match. auto* instr_1 = get_real_hero(&instr1); auto* instr_2 = get_real_hero(&instr2); // TODO(tjoerg): Relax the shape constraint. The datatype does not matter. if (IsReductionToVector(*instr_1) && IsReductionToVector(*instr_2) && - !ShapeUtil::Equal(instr_1->shape(), instr_2->shape())) { + (!ShapeUtil::Equal(instr_1->shape(), instr_2->shape()) || + instr_1->dimensions() != instr_2->dimensions())) { return false; } // The elementwise output shapes must be the same (including layout). diff --git a/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc b/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc index ca07851f8b..15d4ee206c 100644 --- a/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc +++ b/tensorflow/compiler/xla/service/gpu/gpu_fusible_test.cc @@ -568,6 +568,37 @@ TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_ReduceFusions) { EXPECT_TRUE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); } +TEST_F(GpuFusibleTest, + ShapesCompatibleForMultiOutputFusion_DifferentReduceDimensions) { + auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( + fused_reduce_1 { + p0.1 = f32[2,2,2]{2,1,0} parameter(0) + c0 = f32[] constant(0) + ROOT reduce = f32[2,2]{1,0} reduce(f32[2,2,2]{2,1,0} p0.1, f32[] c0), dimensions={0}, to_apply=scalar_add + } + + fused_reduce_2 { + p0.2 = f32[2,2,2]{2,1,0} parameter(0) + mul = f32[2,2,2]{2,1,0} multiply(f32[2,2,2]{2,1,0} p0.2, f32[2,2,2]{2,1,0} p0.2) + c1 = f32[] constant(0) + ROOT reduce = f32[2,2]{1,0} reduce(f32[2,2,2]{2,1,0} mul, f32[] c1), dimensions={2}, to_apply=scalar_add + } + + ENTRY reduce { + p0 = f32[2,2,2]{2,1,0} parameter(0) + p1 = f32[2,2,2]{2,1,0} parameter(1) + reduce_1 = f32[2,2]{1,0} fusion(p0), kind=kLoop, calls=fused_reduce_1 + reduce_2 = f32[2,2]{1,0} fusion(p1), kind=kLoop, calls=fused_reduce_2 + ROOT root = (f32[2,2]{1,0}, f32[2,2,2]{2,1,0}) tuple(reduce_1, reduce_2) + })")) + .ValueOrDie(); + const HloInstruction* fusion_1 = + module->entry_computation()->root_instruction()->operand(0); + const HloInstruction* fusion_2 = + module->entry_computation()->root_instruction()->operand(1); + EXPECT_FALSE(ShapesCompatibleForMultiOutputFusion(*fusion_1, *fusion_2)); +} + TEST_F(GpuFusibleTest, ShapesCompatibleForMultiOutputFusion_NoReductionToVector) { auto module = ParseHloString(absl::StrCat(kModulePrefix, R"( -- GitLab From 8497600aded3df12d781758428e12c4f8178f008 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Thu, 29 Nov 2018 07:40:41 -0800 Subject: [PATCH 528/672] Add cond_v2 and while_v2 as a dependency for tests PiperOrigin-RevId: 223343922 --- tensorflow/python/BUILD | 2 ++ tensorflow/python/debug/BUILD | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 2dbca6ed6e..6e4945e6fd 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -1393,6 +1393,7 @@ py_test( srcs_version = "PY2AND3", tags = ["no_pip"], # test_ops_2 is not available in pip. deps = [ + ":cond_v2", ":control_flow_ops", ":errors", ":framework", @@ -1407,6 +1408,7 @@ py_test( ":util", ":variable_scope", ":variables", + ":while_v2", "//tensorflow/core:protos_all_py", "//tensorflow/python/eager:context", "//tensorflow/python/eager:function", diff --git a/tensorflow/python/debug/BUILD b/tensorflow/python/debug/BUILD index 7995123209..c6abd476d9 100644 --- a/tensorflow/python/debug/BUILD +++ b/tensorflow/python/debug/BUILD @@ -557,6 +557,7 @@ py_test( ":source_utils", "//tensorflow/core:protos_all_py", "//tensorflow/python:client", + "//tensorflow/python:cond_v2", "//tensorflow/python:constant_op", "//tensorflow/python:control_flow_ops", "//tensorflow/python:framework_ops", @@ -566,6 +567,7 @@ py_test( "//tensorflow/python:resource_variable_ops", "//tensorflow/python:util", "//tensorflow/python:variables", + "//tensorflow/python:while_v2", "//third_party/py/numpy", ], ) -- GitLab From b692e8a23d91cda733e45041fb36fe045a43872f Mon Sep 17 00:00:00 2001 From: James Keeling Date: Thu, 29 Nov 2018 07:45:13 -0800 Subject: [PATCH 529/672] Improve performance of Operation.get_attr somewhat This function is the fourth most expensive in a simple example I have been benchmarking. It had a somewhat odd loop over possible fields when the code has already checked which field is present using WhichOneof. I've fixed this (though there is still a loop when the oneof field was a list, which I believe is unavoidable.) PiperOrigin-RevId: 223344446 --- tensorflow/python/framework/ops.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index fc692a2510..bd798f9ffa 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -2386,7 +2386,7 @@ class Operation(object): Raises: ValueError: If this op does not have an attr with the given `name`. """ - fields = ["s", "i", "f", "b", "type", "shape", "tensor", "func"] + fields = ("s", "i", "f", "b", "type", "shape", "tensor", "func") try: with c_api_util.tf_buffer() as buf: c_api.TF_OperationGetAttrValueProto(self._c_op, name, buf) @@ -2397,25 +2397,21 @@ class Operation(object): x = attr_value_pb2.AttrValue() x.ParseFromString(data) - # Treat an empty oneof value as an empty list. - if not x.WhichOneof("value"): + oneof_value = x.WhichOneof("value") + if oneof_value is None: return [] - if x.HasField("list"): + if oneof_value == "list": for f in fields: if getattr(x.list, f): if f == "type": - return [dtypes.as_dtype(x) for x in list(getattr(x.list, f))] + return [dtypes.as_dtype(t) for t in x.list.type] else: return list(getattr(x.list, f)) return [] - else: - for f in fields: - if x.HasField(f): - if f == "type": - return dtypes.as_dtype(getattr(x, f)) - else: - return getattr(x, f) - assert False, "Unsupported field type in " + str(x) + if oneof_value == "type": + return dtypes.as_dtype(x.type) + assert oneof_value in fields, "Unsupported field type in " + str(x) + return getattr(x, oneof_value) def run(self, feed_dict=None, session=None): """Runs this operation in a `Session`. -- GitLab From c04f93a0f90ca48e2a3959dbd6554bc3f3f9b320 Mon Sep 17 00:00:00 2001 From: Dan Moldovan Date: Thu, 29 Nov 2018 07:46:00 -0800 Subject: [PATCH 530/672] `defun` is not currently being exposed in the V2 API, so we cannot pass it via generated code. For this reason we handle it separately. PiperOrigin-RevId: 223344539 --- tensorflow/python/autograph/core/converter.py | 13 ++++++++++--- tensorflow/python/framework/func_graph.py | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/autograph/core/converter.py b/tensorflow/python/autograph/core/converter.py index 49e24895a2..e88c4674ee 100644 --- a/tensorflow/python/autograph/core/converter.py +++ b/tensorflow/python/autograph/core/converter.py @@ -82,6 +82,7 @@ from tensorflow.python.autograph.pyct.static_analysis import live_values from tensorflow.python.autograph.pyct.static_analysis import liveness from tensorflow.python.autograph.pyct.static_analysis import reaching_definitions from tensorflow.python.autograph.pyct.static_analysis import type_info +from tensorflow.python.eager import function # TODO(mdan): These contexts can be refactored into first class objects. # For example, we could define Program and Entity abstractions that hold on @@ -96,7 +97,7 @@ class Verbosity(IntEnum): Attributes: * BRIEF: No logging, minimal error messages. * VERBOSE: Detailed logging of generated code, detailed error messages. - """ + """ BRIEF = 0 VERBOSE = 1 @@ -151,7 +152,7 @@ class ConversionOptions(object): optional_features=Feature.ALL): self.recursive = recursive self.verbose = verbose - self.strip_decorators = strip_decorators or () + self._strip_decorators = strip_decorators or () self.force_conversion = force_conversion # TODO(mdan): Rename to conversion_recursion_depth? self.internal_convert_user_code = internal_convert_user_code @@ -161,6 +162,12 @@ class ConversionOptions(object): optional_features = frozenset(optional_features) self.optional_features = optional_features + @property + def strip_decorators(self): + # A few decorators are included by default. + # TODO(mdan): Revert if function.defun becomes a public symbol. + return self._strip_decorators + (function.defun,) + def uses(self, feature): return (Feature.ALL in self.optional_features or feature in self.optional_features) @@ -216,7 +223,7 @@ class ConversionOptions(object): as_qualified_name(ConversionOptions)), recursive_val=parser.parse_expression(str(self.recursive)), verbose_val=parser.parse_expression(str(int(self.verbose))), - strip_decorators_val=list_of_names(self.strip_decorators), + strip_decorators_val=list_of_names(self._strip_decorators), force_conversion_val=parser.parse_expression( str(self.force_conversion)), internal_convert_user_code_val=parser.parse_expression( diff --git a/tensorflow/python/framework/func_graph.py b/tensorflow/python/framework/func_graph.py index 9960e23e6f..a8a7948b99 100644 --- a/tensorflow/python/framework/func_graph.py +++ b/tensorflow/python/framework/func_graph.py @@ -399,7 +399,7 @@ def func_graph_from_py_func(name, autograph.ConversionOptions( verbose=autograph.Verbosity.BRIEF, recursive=True, - strip_decorators=(function.defun, def_function.function), + strip_decorators=(def_function.function,), optional_features=(), ), *args, **kwargs) -- GitLab From c25a0170cd29e0bbc3fd662104494872de38f392 Mon Sep 17 00:00:00 2001 From: Jiri Simsa Date: Thu, 29 Nov 2018 08:19:42 -0800 Subject: [PATCH 531/672] [tf.data] Mitigating the effect map transformation stragglers have on the performance of the MapAndBatchDataset kernel. This CL automatically increases the size of the internal MapAndBatchDataset::GetNext() buffer to prevent map transformation stragglers from reducing effective parallelism of the kernel. PiperOrigin-RevId: 223348858 --- .../kernels/data/map_and_batch_dataset_op.cc | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc b/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc index f389ff12c5..014f37686f 100644 --- a/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc +++ b/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc @@ -38,6 +38,9 @@ namespace tensorflow { namespace data { namespace { +// Maximum number of batch results to buffer. +const int64 kMaxBatchResults = 16; + // See documentation in ../../ops/dataset_ops.cc for a high-level // description of the following op. class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { @@ -243,7 +246,11 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { cond_var_(std::make_shared()), num_parallel_calls_(std::make_shared( params.dataset->num_parallel_calls_, mu_, cond_var_)), - map_func_(std::move(map_func)) { + map_func_(std::move(map_func)), + max_batch_results_(std::min(kMaxBatchResults, + (params.dataset->num_parallel_calls_ + + params.dataset->batch_size_ - 1) / + params.dataset->batch_size_)) { std::vector components = str_util::Split(params.prefix, "::", str_util::SkipEmpty()); prefix_end_ = components.back(); @@ -280,9 +287,11 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { EnsureRunnerThreadStarted(ctx); while (batch_results_.empty() || batch_results_.front()->num_calls > 0) { + ++waiting_; RecordStop(ctx); cond_var_->wait(l); RecordStart(ctx); + --waiting_; } std::swap(result, batch_results_.front()); batch_results_.pop_front(); @@ -572,18 +581,24 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { } auto busy = [this]() EXCLUSIVE_LOCKS_REQUIRED(*mu_) -> bool { int64 num_parallel_calls = num_parallel_calls_->value; - int64 max_batch_results = - (num_parallel_calls + dataset()->batch_size_ - 1) / - dataset()->batch_size_; return num_calls_ >= num_parallel_calls || - (batch_results_.size() > max_batch_results || - (batch_results_.size() == max_batch_results && + (batch_results_.size() > max_batch_results_ || + (batch_results_.size() == max_batch_results_ && call_counter_ % dataset()->batch_size_ == 0)); }; while (true) { { mutex_lock l(*mu_); while (!cancelled_ && busy()) { + if (waiting_ > 0 && num_calls_ < num_parallel_calls_->value && + max_batch_results_ < kMaxBatchResults) { + // If there is a caller waiting for a batch and the number of + // outstanding calls is not maxed out, it means we are out of + // `batch_results_` slots. Instead of waiting for a slot to open + // up, we create a new one to utilize CPU efficiently. + max_batch_results_++; + continue; + } RecordStop(ctx.get()); cond_var_->wait(l); RecordStart(ctx.get()); @@ -761,8 +776,14 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { std::unique_ptr input_impl_; // Buffer for storing the (intermediate) batch results. std::deque> batch_results_ GUARDED_BY(*mu_); + // Background thread used for coordinating input processing. std::unique_ptr runner_thread_ GUARDED_BY(*mu_); + // Determines whether the transformation has been cancelled. bool cancelled_ GUARDED_BY(*mu_) = false; + // Identifies the number of callers currently waiting for a batch result. + int64 waiting_ GUARDED_BY(*mu_) = 0; + // Identifies the maximum number of batch results to store. + int64 max_batch_results_ GUARDED_BY(*mu_); string prefix_end_; }; -- GitLab From 2685945640fb1d62135e43b1d0d05c21649adb3f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 08:22:27 -0800 Subject: [PATCH 532/672] internal change only PiperOrigin-RevId: 223349157 --- tensorflow/compiler/xla/service/hlo_graph_dumper.cc | 10 +++++----- tensorflow/compiler/xla/service/hlo_graph_dumper.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_graph_dumper.cc b/tensorflow/compiler/xla/service/hlo_graph_dumper.cc index 7e9e94ca5f..804feff290 100644 --- a/tensorflow/compiler/xla/service/hlo_graph_dumper.cc +++ b/tensorflow/compiler/xla/service/hlo_graph_dumper.cc @@ -1268,12 +1268,12 @@ const HloInstruction* HloDotDumper::GetNodeForEdge( class GraphRendererRegistry { public: - void AddRenderer(GraphRendererInterface* graph_renderer) { + void SetRenderer(std::shared_ptr graph_renderer) { tensorflow::mutex_lock lock(mu_); graph_renderer_ = graph_renderer; } - GraphRendererInterface* GetDefaultRenderer() { + std::shared_ptr GetDefaultRenderer() { tensorflow::mutex_lock lock(mu_); return graph_renderer_; } @@ -1285,13 +1285,13 @@ class GraphRendererRegistry { private: tensorflow::mutex mu_; - GraphRendererInterface* graph_renderer_ = nullptr; + std::shared_ptr graph_renderer_ GUARDED_BY(mu_); }; } // namespace -Registrar::Registrar(GraphRendererInterface* dumper) { - GraphRendererRegistry::Default()->AddRenderer(dumper); +Registrar::Registrar(std::shared_ptr dumper) { + GraphRendererRegistry::Default()->SetRenderer(dumper); } namespace { diff --git a/tensorflow/compiler/xla/service/hlo_graph_dumper.h b/tensorflow/compiler/xla/service/hlo_graph_dumper.h index 0b11f34abb..8d5945aba8 100644 --- a/tensorflow/compiler/xla/service/hlo_graph_dumper.h +++ b/tensorflow/compiler/xla/service/hlo_graph_dumper.h @@ -87,13 +87,13 @@ void DumpText(const HloModule& module, const string& label, // Class that registers a graph renderer. class Registrar { public: - Registrar(GraphRendererInterface* dumper); + Registrar(std::shared_ptr dumper); }; -#define XLA_INTERNAL_REGISTER_GRAPH_RENDERER(factory, ctr, ...) \ - static ::xla::hlo_graph_dumper::Registrar \ - XLA_INTERNAL_REGISTER_GRAPH_RENDERER_NAME(ctr)(new factory, \ - ##__VA_ARGS__) +#define XLA_INTERNAL_REGISTER_GRAPH_RENDERER(factory, ctr, ...) \ + static ::xla::hlo_graph_dumper::Registrar \ + XLA_INTERNAL_REGISTER_GRAPH_RENDERER_NAME(ctr)( \ + std::make_shared(), ##__VA_ARGS__) // __COUNTER__ must go through another macro to be properly expanded #define XLA_INTERNAL_REGISTER_GRAPH_RENDERER_NAME(ctr) ___##ctr##__object_ -- GitLab From 0b3da9fad5a41276753113b4ceb57ab821c5397f Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 08:34:36 -0800 Subject: [PATCH 533/672] Update protobuf to 3.6.1.1 protobuf 3.6.1.1 contains a fix for protobuf bzl file. This will fix TF Windows build with Bazel@HEAD, allowing us to test TensorFlow in downstream. PiperOrigin-RevId: 223350741 --- tensorflow/workspace.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 0ea5d68ea8..016572a543 100755 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -347,11 +347,11 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): ) PROTOBUF_URLS = [ - "https://mirror.bazel.build/github.com/google/protobuf/archive/v3.6.1.tar.gz", - "https://github.com/google/protobuf/archive/v3.6.1.tar.gz", + "https://mirror.bazel.build/github.com/google/protobuf/archive/v3.6.1.1.tar.gz", + "https://github.com/google/protobuf/archive/v3.6.1.1.tar.gz", ] - PROTOBUF_SHA256 = "3d4e589d81b2006ca603c1ab712c9715a76227293032d05b26fca603f90b3f5b" - PROTOBUF_STRIP_PREFIX = "protobuf-3.6.1" + PROTOBUF_SHA256 = "1ade182f91f0fa6c6116195def5d22270e01b9d03fe91319e4c6215022d0d24b" + PROTOBUF_STRIP_PREFIX = "protobuf-3.6.1.1" tf_http_archive( name = "protobuf_archive", -- GitLab From aafc5f86303ffea242ba99ae487f5206375b94f7 Mon Sep 17 00:00:00 2001 From: Martin Wicke Date: Thu, 29 Nov 2018 09:07:24 -0800 Subject: [PATCH 534/672] Add a note about tf.flags to the converter, and default the copy_other_files option to true. Fix broken tf_upgrade_v2 installation in pip, and optimize RE compilation in AST editor. PiperOrigin-RevId: 223355625 --- tensorflow/tools/compatibility/ast_edits.py | 21 ++++++++++++------- .../tools/compatibility/tf_upgrade_v2.py | 20 ++++++++++++------ .../tools/compatibility/tf_upgrade_v2_main.py | 8 +++++-- .../tools/compatibility/tf_upgrade_v2_test.py | 5 ++--- tensorflow/tools/pip_package/setup.py | 2 +- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/tensorflow/tools/compatibility/ast_edits.py b/tensorflow/tools/compatibility/ast_edits.py index 90bfab3507..eac2150502 100644 --- a/tensorflow/tools/compatibility/ast_edits.py +++ b/tensorflow/tools/compatibility/ast_edits.py @@ -21,11 +21,16 @@ from __future__ import print_function import ast import collections import os +import re import shutil import sys import tempfile import traceback +# Some regular expressions we will need for parsing +FIND_OPEN = re.compile(r"^\s*(\[).*$") +FIND_STRING_CHARS = re.compile(r"['\"]") + class APIChangeSpec(object): """This class defines the transformations that need to happen. @@ -57,7 +62,7 @@ class _FileEditTuple( Fields: comment: A description of the edit and why it was made. line: The line number in the file where the edit occurs (1-indexed). - start: The line number in the file where the edit occurs (0-indexed). + start: The column number in the file where the edit occurs (0-indexed). old: text string to remove (this must match what was in file). new: text string to add in place of `old`. """ @@ -248,13 +253,12 @@ class _ASTCallVisitor(ast.NodeVisitor): This is necessary mainly because ListComp's location reporting reports the next token after the list comprehension list opening. + Returns: + lineno, offset for the given node + Args: node: Node for which we wish to know the lineno and col_offset """ - import re - find_open = re.compile("^\s*(\\[).*$") - find_string_chars = re.compile("['\"]") - if isinstance(node, ast.ListComp): # Strangely, ast.ListComp returns the col_offset of the first token # after the '[' token which appears to be a bug. Workaround by @@ -268,7 +272,7 @@ class _ASTCallVisitor(ast.NodeVisitor): reversed_preceding_text = text[:col][::-1] # First find if a [ can be found with only whitespace between it and # col. - m = find_open.match(reversed_preceding_text) + m = FIND_OPEN.match(reversed_preceding_text) if m: new_col_offset = col - m.start(1) - 1 return line, new_col_offset @@ -287,7 +291,7 @@ class _ASTCallVisitor(ast.NodeVisitor): comment_start = prev_line.find("#") if comment_start == -1: col = len(prev_line) - 1 - elif find_string_chars.search(prev_line[comment_start:]) is None: + elif FIND_STRING_CHARS.search(prev_line[comment_start:]) is None: col = comment_start else: return None, None @@ -391,8 +395,9 @@ class _ASTCallVisitor(ast.NodeVisitor): """ full_name, _ = self._get_attribute_full_path(node) if full_name: - self._rename_functions(node, full_name) + # Make sure the warning comes first, otherwise the name may have changed self._print_warning_for_function(node, full_name) + self._rename_functions(node, full_name) if full_name in self._api_change_spec.change_to_function: if not hasattr(node, "is_function_for_call"): new_text = full_name + "()" diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 649d1c17a3..242bbbc3a7 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -619,11 +619,12 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): } decay_function_comment = ( - "ERROR: has been changed to return a callable instead " - "of a tensor when graph building, but its functionality remains " + "WARNING: has been changed to return a callable instead" + " of a tensor when graph building, but its functionality remains " "unchanged during eager execution (returns a callable like " "before). The converter cannot detect and fix this reliably, so " - "you need to inspect this usage manually.\n" + "this usage has been converted to compat.v1 (even though it may already" + " be correct).\n" ) # TODO(b/118888586): add default value change to update script. @@ -635,17 +636,23 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): assert_return_type_comment = ( "WARNING: assert_* functions have been changed to return None, the " "data argument has been removed, and arguments have been reordered." + "\nThe calls have been converted to compat.v1 for safety (even though " + " they may already have been correct)." ) assert_rank_comment = ( "WARNING: assert_rank_* functions have been changed to return None, and" " the data and summarize arguments have been removed." + "\nThe calls have been converted to compat.v1 for safety (even though " + " they may already have been correct)." ) tf_01s_like_no_optimize_comment = ( "WARNING: tf.zeros_like and tf.ones_like no longer have the optimize " "argument in TF 2.0 or after (also, `tensor' argument is renamed to " "`input')." + "\nThe calls have been converted to compat.v1 for safety (even though " + " they may already have been correct)." ) # Function warnings. placeholder inside warnings will be @@ -670,6 +677,8 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.debugging.assert_rank": assert_rank_comment, "tf.debugging.assert_rank_at_least": assert_rank_comment, "tf.debugging.assert_rank_in": assert_rank_comment, + "tf.flags": "tf.flags has been removed, please use the argparse or absl" + " module if you need command line parsing.", "tf.train.exponential_decay": decay_function_comment, "tf.train.piecewise_constant": @@ -720,15 +729,14 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.zeros_like": tf_01s_like_no_optimize_comment, "tf.ones_like": tf_01s_like_no_optimize_comment, } - # Right now we can't have both a rename and a warning. + self.symbol_renames = { name: new_name for name, new_name in self.symbol_renames.items() - if name not in self.function_warnings } export_saved_model_renamed = ( - "(Manual edit required) Please rename the function export_savedmodel() " + "(Manual edit required) Please rename the method export_savedmodel() " "to export_saved_model(). Two things to note:\n\t(1) The argument " "strip_default_attributes has been removed. The function will always " "strip the default attributes from ops. If this breaks your code, " diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_main.py b/tensorflow/tools/compatibility/tf_upgrade_v2_main.py index 498258dfa8..543d078642 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_main.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_main.py @@ -24,7 +24,7 @@ from tensorflow.tools.compatibility import ast_edits from tensorflow.tools.compatibility import tf_upgrade_v2 -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description="""Convert a TensorFlow Python file to 2.0 @@ -58,7 +58,7 @@ Simple usage: help=("If converting a whole tree of files, whether to " "copy the other files."), type=bool, - default=False) + default=True) parser.add_argument( "--reportfile", dest="report_filename", @@ -98,3 +98,7 @@ Simple usage: print("-" * 80) print("\n".join(errors)) print("\nMake sure to read the detailed log %r\n" % report_filename) + + +if __name__ == "__main__": + main() diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index 0414becc70..c490ebd480 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -97,8 +97,7 @@ class TestUpgrade(test_util.TensorFlowTestCase): "tf.train.noisy_linear_cosine_decay"]: text = "%s(a, b)\n" % decay - _, report, errors, new_text = self._upgrade(text) - self.assertEqual(text, new_text) + _, report, errors, _ = self._upgrade(text) self.assertEqual(errors, ["test.py:1: %s requires manual check." % decay]) self.assertIn("%s has been changed" % decay, report) @@ -216,7 +215,7 @@ class TestUpgrade(test_util.TensorFlowTestCase): text = "self.est.export_savedmodel(path)" _, report, unused_errors, unused_new_text = self._upgrade(text) self.assertIn( - "rename the function export_savedmodel() to export_saved_model()", + "rename the method export_savedmodel() to export_saved_model()", report) def testArgmin(self): diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index 34c600abaf..85c913f158 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -107,7 +107,7 @@ CONSOLE_SCRIPTS = [ # TensorBoard command, pip will inappropriately remove it during install, # even though the command is not removed, just moved to a different wheel. 'tensorboard = tensorboard.main:run_main', - 'tf_upgrade_v2 = tensorflow.tools.compatibility.tf_upgrade_v2:main', + 'tf_upgrade_v2 = tensorflow.tools.compatibility.tf_upgrade_v2_main:main', ] # pylint: enable=line-too-long -- GitLab From 8b9064ab985706fa62031d1dd0c961e9ceb82061 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 09:12:18 -0800 Subject: [PATCH 535/672] Don't skip MetaOptimizer if the feed nodes are Const or the shape is undefined. Fix bug in arithmetic optimizer: Skip Pow nodes with unknown input shapes. PiperOrigin-RevId: 223356331 --- .../common_runtime/graph_execution_state.cc | 82 ++++++++++++++----- .../optimizers/arithmetic_optimizer.cc | 18 ++-- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/tensorflow/core/common_runtime/graph_execution_state.cc b/tensorflow/core/common_runtime/graph_execution_state.cc index 0d36930324..9a56c67162 100644 --- a/tensorflow/core/common_runtime/graph_execution_state.cc +++ b/tensorflow/core/common_runtime/graph_execution_state.cc @@ -25,9 +25,11 @@ limitations under the License. #include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/common_runtime/optimization_registry.h" #include "tensorflow/core/common_runtime/placer.h" +#include "tensorflow/core/framework/attr_value.pb.h" #include "tensorflow/core/framework/graph.pb_text.h" #include "tensorflow/core/framework/graph_def_util.h" #include "tensorflow/core/framework/node_def.pb.h" +#include "tensorflow/core/framework/tensor.pb.h" #include "tensorflow/core/framework/versions.pb.h" #include "tensorflow/core/graph/algorithm.h" #include "tensorflow/core/graph/graph.h" @@ -37,6 +39,7 @@ limitations under the License. #include "tensorflow/core/graph/validate.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/lib/gtl/flatset.h" #include "tensorflow/core/lib/strings/stringprintf.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/types.h" @@ -393,6 +396,42 @@ Status ValidateFeedAndFetchDevices( } return Status::OK(); } + +Status GetFeedShapeAndTypeFromAttribute(const NodeDef& node, + PartialTensorShape* shape, + DataType* type) { + static const gtl::FlatSet* const kHasExplicitShapeAttribute = + CHECK_NOTNULL((new gtl::FlatSet{ + "Placeholder", "PlaceholderV2", "PlaceholderWithDefault", + "ParallelConcat", "ImmutableConst", "_ParallelConcatStart", + "InfeedDequeue", "OutfeedDequeue", "CollectiveBcastSend", + "CollectiveBcastRecv", "AccumulateNV2", "VariableV2", "Variable", + "TemporaryVariable", "NcclBroadcast", "_ScopedAllocator", + "_ScopedAllocatorConcat"})); + + // All the node types handled here have their output datatype set in + // either attribute 'dtype' or 'T'. + if (!GetNodeAttr(node, "dtype", type).ok() && + !GetNodeAttr(node, "T", type).ok()) { + return errors::InvalidArgument( + "Could not determine output type for feed node: ", node.name(), + " of type ", node.op()); + } + + // First handle the case of feeding a const node. + if (node.op() == "Const" && HasNodeAttr(node, "value")) { + *shape = + PartialTensorShape(node.attr().at("value").tensor().tensor_shape()); + } else if (kHasExplicitShapeAttribute->find(node.op()) != + kHasExplicitShapeAttribute->end()) { + TF_RETURN_IF_ERROR(GetNodeAttr(node, "shape", shape)); + } else { + return errors::InvalidArgument("Could not determine shape for feed node: ", + node.name(), " of type ", node.op()); + } + return Status::OK(); +} + } // namespace Status GraphExecutionState::PruneGraph( @@ -553,9 +592,6 @@ Status GraphExecutionState::OptimizeGraph( } if (grappler::MetaOptimizerEnabled(session_options_->config)) { - // Adding this functionality in steps. The first step is to make sure - // we don't break dependencies. The second step will be to turn the - // functionality on by default. grappler::GrapplerItem item; item.id = "tf_graph"; graph_->ToGraphDef(&item.graph); @@ -599,26 +635,30 @@ Status GraphExecutionState::OptimizeGraph( if (feeds.find(node.name()) == feeds.end()) { continue; } - if (node.attr().count("dtype") == 0 || - node.attr().count("shape") == 0) { - return errors::InvalidArgument("Missing node shape or type"); - } - TensorShapeProto shape_proto(node.attr().at("shape").shape()); - // If the shape of the placeholder value is only partially known, - // we're free to use any dimension we want to feed the placeholder. We - // choose 1 to minimize the memory impact. Note that this only matters - // if an optimizer choose to run the graph to build its cost model, - // which doesn't happen (yet) - if (shape_proto.unknown_rank()) { - shape_proto.set_unknown_rank(false); - } - for (auto& dim : *shape_proto.mutable_dim()) { - if (dim.size() < 0) { - dim.set_size(1); + // Get the type and shape of the feed node. + PartialTensorShape partial_shape; + DataType type; + TF_RETURN_IF_ERROR( + GetFeedShapeAndTypeFromAttribute(node, &partial_shape, &type)); + // If the shape of the placeholder is only partially known, we are free + // to set unknown dimensions of its shape to any value we desire. We + // choose 0 to minimize the memory impact. Note that this only matters + // if an optimizer chooses to run the graph. + TensorShape shape; + if (partial_shape.unknown_rank()) { + shape = TensorShape({0}); + } else { + for (int i = 0; i < partial_shape.dims(); ++i) { + if (partial_shape.dim_size(i) < 0) { + partial_shape.set_dim(i, 0); + } + } + if (!partial_shape.AsTensorShape(&shape)) { + return errors::InvalidArgument( + "Could not derive shape for feed node: ", node.DebugString()); } } - TensorShape shape(shape_proto); - DataType type = node.attr().at("dtype").type(); + Tensor fake_input(type, shape); item.feed.emplace_back(node.name(), fake_input); } diff --git a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc index e676323bf4..e3ac89b50d 100644 --- a/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/arithmetic_optimizer.cc @@ -2407,11 +2407,10 @@ class ConvertPowStage : public ArithmeticOptimizerStage { Status TrySimplify(NodeDef* node, string* simplified_node_name) override { const auto& pow_props = ctx().graph_properties->GetInputProperties(node->name())[1]; - for (int i = 0; i < pow_props.shape().dim_size(); ++i) { - if (pow_props.shape().dim(i).size() < 0) { - // skip if p is not fully defined. - return Status::OK(); - } + PartialTensorShape shape(pow_props.shape()); + if (!shape.IsFullyDefined()) { + // skip if p is not fully defined. + return Status::OK(); } if (TensorShape::IsValid(pow_props.shape()) && pow_props.has_value()) { Tensor pow(pow_props.dtype(), pow_props.shape()); @@ -2459,11 +2458,10 @@ class ConvertPowStage : public ArithmeticOptimizerStage { AddToOptimizationQueue(y); } else if (curr == complex128(0, 0) && ShapesSymbolicallyEqual(value_props.shape(), output_shape)) { - for (int i = 0; i < value_props.shape().dim_size(); ++i) { - if (value_props.shape().dim(i).size() < 0) { - // skip if b is not fully defined. - return Status::OK(); - } + PartialTensorShape shape(value_props.shape()); + if (!shape.IsFullyDefined()) { + // skip if b is not fully defined. + return Status::OK(); } if (TensorShape::IsValid(value_props.shape()) && value_props.has_value()) { -- GitLab From 30f5cf80481edad74dc3eae4e8add8e9b15874ea Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 09:15:09 -0800 Subject: [PATCH 536/672] Nit: Added a missing space in an error message. PiperOrigin-RevId: 223356708 --- tensorflow/python/client/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/python/client/session.py b/tensorflow/python/client/session.py index 22303e95c1..87a200ed33 100644 --- a/tensorflow/python/client/session.py +++ b/tensorflow/python/client/session.py @@ -1097,7 +1097,7 @@ class BaseSession(SessionInterface): if isinstance(subfeed_val, ops.Tensor): raise TypeError('The value of a feed cannot be a tf.Tensor object. ' 'Acceptable feed values include Python scalars, ' - 'strings, lists, numpy ndarrays, or TensorHandles.' + 'strings, lists, numpy ndarrays, or TensorHandles. ' 'For reference, the tensor object was ' + str(feed_val) + ' which was passed to the ' 'feed with key ' + str(feed) + '.') -- GitLab From 6498c22816a9af179739631d86ef0fd19560d435 Mon Sep 17 00:00:00 2001 From: Andy Ly Date: Thu, 29 Nov 2018 09:19:44 -0800 Subject: [PATCH 537/672] Replace GraphRewriter with GraphView and helper functions in ModelPruner. PiperOrigin-RevId: 223357322 --- tensorflow/core/grappler/optimizers/BUILD | 19 +- .../grappler/optimizers/graph_rewriter.cc | 214 ------------------ .../core/grappler/optimizers/graph_rewriter.h | 102 --------- .../grappler/optimizers/memory_optimizer.cc | 1 - .../core/grappler/optimizers/model_pruner.cc | 164 ++++++++++++-- 5 files changed, 152 insertions(+), 348 deletions(-) delete mode 100644 tensorflow/core/grappler/optimizers/graph_rewriter.cc delete mode 100644 tensorflow/core/grappler/optimizers/graph_rewriter.h diff --git a/tensorflow/core/grappler/optimizers/BUILD b/tensorflow/core/grappler/optimizers/BUILD index 8e6629565a..9149ee275d 100644 --- a/tensorflow/core/grappler/optimizers/BUILD +++ b/tensorflow/core/grappler/optimizers/BUILD @@ -178,22 +178,6 @@ tf_cuda_cc_test( ], ) -cc_library( - name = "graph_rewriter", - srcs = ["graph_rewriter.cc"], - hdrs = [ - "graph_rewriter.h", - ], - visibility = ["//visibility:public"], - deps = [ - "//tensorflow/core:framework", - "//tensorflow/core:protos_all_cc", - "//tensorflow/core/grappler:grappler_item", - "//tensorflow/core/grappler:op_types", - "//tensorflow/core/grappler:utils", - ], -) - cc_library( name = "graph_optimizer", hdrs = [ @@ -352,10 +336,10 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":graph_optimizer", - ":graph_rewriter", "//tensorflow/core:framework", "//tensorflow/core:protos_all_cc", "//tensorflow/core/grappler:grappler_item", + "//tensorflow/core/grappler:mutable_graph_view", "//tensorflow/core/grappler:op_types", "//tensorflow/core/grappler:utils", "@com_google_absl//absl/container:flat_hash_map", @@ -419,7 +403,6 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":graph_optimizer", - ":graph_rewriter", ":static_schedule", "//tensorflow/core:framework", "//tensorflow/core:lib", diff --git a/tensorflow/core/grappler/optimizers/graph_rewriter.cc b/tensorflow/core/grappler/optimizers/graph_rewriter.cc deleted file mode 100644 index b45ceb12a7..0000000000 --- a/tensorflow/core/grappler/optimizers/graph_rewriter.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ - -#include "tensorflow/core/grappler/optimizers/graph_rewriter.h" -#include -#include -#include "tensorflow/core/framework/function.pb.h" -#include "tensorflow/core/framework/node_def.pb.h" -#include "tensorflow/core/framework/node_def_util.h" -#include "tensorflow/core/framework/op.h" -#include "tensorflow/core/framework/op_def.pb.h" -#include "tensorflow/core/grappler/grappler_item.h" -#include "tensorflow/core/grappler/op_types.h" -#include "tensorflow/core/grappler/utils.h" - -namespace tensorflow { -namespace grappler { - -GraphRewriter::GraphRewriter(const GrapplerItem& item) { - OpRegistryInterface* op_registry = OpRegistry::Global(); - for (auto& node : item.graph.node()) { - NodeInfo* info = new NodeInfo(); - info->def = &node; - - const OpRegistrationData* op_reg_data = nullptr; - Status s = op_registry->LookUp(node.op(), &op_reg_data); - // TODO(bsteiner): make this not a best-effort lookup and evaluation? - if (s.ok()) { - DataTypeVector inputs; - s = InOutTypesForNode(node, op_reg_data->op_def, &inputs, &info->outputs); - if (!s.ok()) { - info->outputs.clear(); - } - } - - nodes_[node.name()].reset(info); - } - - std::unordered_set function_names; - for (const auto& function : item.graph.library().function()) { - function_names.insert(function.signature().name()); - } - - for (auto& node : item.graph.node()) { - RecordConnectivity(node, function_names); - } -} - -void GraphRewriter::ForwardInputs( - const NodeDef& original_node, - const std::unordered_set& nodes_to_delete, - NodeDef* new_node) { - ForwardInputsInternal(original_node, nodes_to_delete, false, new_node); - if (!new_node->name().empty()) { - optimized_nodes_[new_node->name()] = new_node; - } - // Reorder inputs such that control inputs come after regular inputs. - int pos = 0; - for (int i = 0; i < new_node->input_size(); ++i) { - if (!IsControlInput(new_node->input(i))) { - new_node->mutable_input()->SwapElements(pos, i); - ++pos; - } - } - DedupControlInputs(new_node); -} - -bool GraphRewriter::DrivesControlDependency(const NodeDef& node) const { - return control_dependency_drivers_.find(&node) != - control_dependency_drivers_.end(); -} - -bool GraphRewriter::FeedsMerge(const NodeDef& node) const { - return merge_feeders_.find(&node) != merge_feeders_.end(); -} - -bool GraphRewriter::IsDrivenByControlDependency(const NodeDef& node) const { - for (const auto& input : node.input()) { - CHECK(!input.empty()); - if (input[0] == '^') { - return true; - } - } - return false; -} - -bool GraphRewriter::IsConnectedToFunction(const NodeDef& node) const { - return function_neighbors_.find(&node) != function_neighbors_.end(); -} - -bool GraphRewriter::IsDrivenByAnotherDevice(const NodeDef& node) const { - return cross_device_receivers_.find(&node) != cross_device_receivers_.end(); -} - -bool GraphRewriter::ReceivesRefValue(const NodeDef& node) const { - return ref_receivers_.find(&node) != ref_receivers_.end(); -} - -bool GraphRewriter::IsDrivenBySwitch(const NodeDef& node) const { - return switch_receivers_.find(&node) != switch_receivers_.end(); -} - -bool GraphRewriter::RemovalIncreasesEdgeCount(const NodeDef& node) const { - const int in_degree = node.input_size(); - auto itr = nodes_.find(node.name()); - if (itr == nodes_.end()) { - return true; - } - const int out_degree = itr->second->out_degree; - return in_degree * out_degree > in_degree + out_degree; -} - -void GraphRewriter::RecordConnectivity( - const NodeDef& node, const std::unordered_set& function_names) { - const bool is_function = - function_names.find(node.op()) != function_names.end(); - - bool ref_receiver = false; - bool switch_receiver = false; - for (const auto& input : node.input()) { - int position = 0; - string input_node_name = ParseNodeName(input, &position); - auto itr = nodes_.find(input_node_name); - if (itr == nodes_.end()) { - continue; - } - - NodeInfo* fanin_info = itr->second.get(); - const NodeDef* fanin = fanin_info->def; - if (IsMerge(node)) { - merge_feeders_.insert(fanin); - } - // Update out_degree of fanin. - ++fanin_info->out_degree; - if (position < 0) { - // This is a control edge - control_dependency_drivers_.insert(fanin); - } else { - // This is a regular edge - if (function_names.find(fanin->op()) != function_names.end()) { - function_neighbors_.insert(&node); - } - if (is_function) { - function_neighbors_.insert(fanin); - } - if (IsSwitch(*fanin)) { - switch_receiver = true; - } - if (position < fanin_info->outputs.size() && - IsRefType(fanin_info->outputs[position])) { - ref_receiver = true; - } - } - if (fanin->device() != node.device()) { - cross_device_receivers_.insert(&node); - } - } - - if (ref_receiver) { - ref_receivers_.insert(&node); - } - if (switch_receiver) { - switch_receivers_.insert(&node); - } -} - -void GraphRewriter::ForwardInputsInternal( - const NodeDef& node, - const std::unordered_set& nodes_to_delete, - bool add_as_control, NodeDef* new_node) { - // To speed things up, use the optimized version of the node if - // available. - auto itr = optimized_nodes_.find(node.name()); - if (itr != optimized_nodes_.end()) { - for (const string& input : itr->second->input()) { - *new_node->add_input() = - add_as_control ? AsControlDependency(NodeName(input)) : input; - } - return; - } - for (const auto& input : node.input()) { - const string input_node_name = NodeName(input); - auto itr = nodes_.find(input_node_name); - if (itr == nodes_.end()) { - // Invalid input, preserve it as is. - *new_node->add_input() = - add_as_control ? AsControlDependency(NodeName(input)) : input; - continue; - } - const NodeDef* input_node = itr->second->def; - if (nodes_to_delete.find(input_node) != nodes_to_delete.end()) { - ForwardInputsInternal(*input_node, nodes_to_delete, - add_as_control || IsControlInput(input), new_node); - } else { - *new_node->add_input() = - add_as_control ? AsControlDependency(NodeName(input)) : input; - } - } -} - -} // end namespace grappler -} // end namespace tensorflow diff --git a/tensorflow/core/grappler/optimizers/graph_rewriter.h b/tensorflow/core/grappler/optimizers/graph_rewriter.h deleted file mode 100644 index 4a5a150dc9..0000000000 --- a/tensorflow/core/grappler/optimizers/graph_rewriter.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright 2017 The TensorFlow Authors. 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. -==============================================================================*/ - -#ifndef TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_GRAPH_REWRITER_H_ -#define TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_GRAPH_REWRITER_H_ - -#include -#include -#include "tensorflow/core/grappler/grappler_item.h" - -namespace tensorflow { -namespace grappler { - -// Tools and utilities to simplify common graph rewrites. -class GraphRewriter { - public: - GraphRewriter(const GrapplerItem& item); - - // Forward the inputs of original_node as needed to skip over the nodes that - // are to be deleted. In other words, if I is an input of 'original_node', and - // I doesn't belong to one of the nodes in 'nodes_to_delete', I will be an - // input to 'new_node'. On the other hand, if I belong to a node that will be - // deleted, I will be replaced with the inputs J of the deleted node (unless J - // belong to nodes that will be deleted, in which case we'll look for - // preserved inputs further down the graph). - void ForwardInputs(const NodeDef& original_node, - const std::unordered_set& nodes_to_delete, - NodeDef* new_node); - - // Returns true if at least one of the edges in the direct fanout of 'node' is - // a control dependency edge. - bool DrivesControlDependency(const NodeDef& node) const; - - // Returns true if at least one of the incident edges is a control dependency - // edge. - bool IsDrivenByControlDependency(const NodeDef& node) const; - - // Returns true if at least one of the nodes in the direct fanin or the direct - // fanout (excluding control dependencies) of 'node' is a function. - bool IsConnectedToFunction(const NodeDef& node) const; - - // Returns true if the node is driven by at least one node placed on another - // device. - bool IsDrivenByAnotherDevice(const NodeDef& node) const; - - // Returns true if the node has input from a stateful op. - bool ReceivesRefValue(const NodeDef& node) const; - - // Returns true if the node is driven by a Switch node. - bool IsDrivenBySwitch(const NodeDef& node) const; - - // Returns true if the node feeds a Merge node. - bool FeedsMerge(const NodeDef& node) const; - - // Returns true if removal of this degree would increase edge count, i.e. if - // in-degree * out-degree > in-degree + out-degree or if the condition could - // not be verified. - bool RemovalIncreasesEdgeCount(const NodeDef& node) const; - - private: - void RecordConnectivity(const NodeDef& node, - const std::unordered_set& function_names); - void ForwardInputsInternal( - const NodeDef& original_node, - const std::unordered_set& nodes_to_delete, - bool add_as_control, NodeDef* new_node); - - struct NodeInfo { - int out_degree = 0; - const NodeDef* def; - - // These are filled in when the NodeInfo is built, but not that they - // may be empty - if the op could not be loaded from the registry. - DataTypeVector outputs; - }; - - std::unordered_map> nodes_; - std::unordered_map optimized_nodes_; - std::unordered_set control_dependency_drivers_; - std::unordered_set function_neighbors_; - std::unordered_set cross_device_receivers_; - std::unordered_set ref_receivers_; - std::unordered_set switch_receivers_; - std::unordered_set merge_feeders_; -}; - -} // end namespace grappler -} // end namespace tensorflow - -#endif // TENSORFLOW_CORE_GRAPPLER_OPTIMIZERS_GRAPH_REWRITER_H_ diff --git a/tensorflow/core/grappler/optimizers/memory_optimizer.cc b/tensorflow/core/grappler/optimizers/memory_optimizer.cc index e0a913565f..453db5d91e 100644 --- a/tensorflow/core/grappler/optimizers/memory_optimizer.cc +++ b/tensorflow/core/grappler/optimizers/memory_optimizer.cc @@ -33,7 +33,6 @@ limitations under the License. #include "tensorflow/core/grappler/grappler_item.h" #include "tensorflow/core/grappler/mutable_graph_view.h" #include "tensorflow/core/grappler/op_types.h" -#include "tensorflow/core/grappler/optimizers/graph_rewriter.h" #include "tensorflow/core/grappler/optimizers/static_schedule.h" #include "tensorflow/core/grappler/utils.h" #include "tensorflow/core/grappler/utils/topological_sort.h" diff --git a/tensorflow/core/grappler/optimizers/model_pruner.cc b/tensorflow/core/grappler/optimizers/model_pruner.cc index 1be87a9d0d..c548c570e0 100644 --- a/tensorflow/core/grappler/optimizers/model_pruner.cc +++ b/tensorflow/core/grappler/optimizers/model_pruner.cc @@ -23,30 +23,164 @@ limitations under the License. #include "tensorflow/core/framework/function.pb.h" #include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/node_def_builder.h" +#include "tensorflow/core/framework/types.h" #include "tensorflow/core/framework/versions.pb.h" #include "tensorflow/core/grappler/grappler_item.h" +#include "tensorflow/core/grappler/mutable_graph_view.h" #include "tensorflow/core/grappler/op_types.h" -#include "tensorflow/core/grappler/optimizers/graph_rewriter.h" #include "tensorflow/core/grappler/utils.h" namespace tensorflow { namespace grappler { -bool IsTrivialOp(const NodeDef& node, const GraphRewriter& rewriter) { +bool IsTrivialIdentity(const NodeDef& node, + const MutableGraphView& graph_view) { + for (const auto input : + graph_view.GetFanins(node, /*include_controlling_nodes=*/true)) { + if (input.port_id == Graph::kControlSlot) { + // Node is driven by control dependency. + return false; + } else if (IsSwitch(*input.node)) { // Node is driven by switch. + return false; + } + } + for (const auto output : + graph_view.GetFanouts(node, /*include_controlled_nodes=*/true)) { + if (output.port_id == Graph::kControlSlot) { + // Node drives control dependency. + return false; + } else if (IsMerge(*output.node)) { // Node feeds merge. + return false; + } + } + return true; +} + +bool IsTrivialOp(const NodeDef& node, const MutableGraphView& graph_view) { // Remove the stop gradient nodes since they serve no purpose once the graph // is built. Also remove Identity ops. if (IsStopGradient(node)) { return true; } if (IsIdentity(node) || IsIdentityNSingleInput(node)) { - return !(rewriter.FeedsMerge(node) || rewriter.IsDrivenBySwitch(node) || - rewriter.IsDrivenByControlDependency(node) || - rewriter.DrivesControlDependency(node)); + return IsTrivialIdentity(node, graph_view); } return IsAddN(node) && NumNonControlInputs(node) <= 1; } +bool RemovalIncreasesEdgeCount(const NodeDef& node, + const MutableGraphView& graph_view) { + int in_degree = + graph_view.NumFanins(node, /*include_controlling_nodes=*/true); + int out_degree = + graph_view.NumFanouts(node, /*include_controlling_nodes=*/true); + return in_degree * out_degree > in_degree + out_degree; +} + +bool IsOutputPortRefValue(const NodeDef& node, int port_id, + const OpRegistryInterface& op_registry) { + const OpRegistrationData* op_reg_data = nullptr; + Status s = op_registry.LookUp(node.op(), &op_reg_data); + if (s.ok()) { + DataType output_type; + s = OutputTypeForNode(node, op_reg_data->op_def, port_id, &output_type); + if (s.ok() && IsRefType(output_type)) { + return true; + } + } + return false; +} + +bool CanRemoveNode(const NodeDef& node, const MutableGraphView& graph_view, + const absl::flat_hash_set& function_names, + const OpRegistryInterface& op_registry) { + if (RemovalIncreasesEdgeCount(node, graph_view)) { + return false; + } + for (const auto input : + graph_view.GetFanins(node, /*include_controlling_nodes=*/true)) { + if (node.device() != input.node->device()) { + // Node is driven by a different device. + return false; + } else if (input.port_id == Graph::kControlSlot) { + // Node is driven by control dependency. + continue; + } else if (function_names.find(input.node->op()) != function_names.end()) { + // Node input is a function call. + return false; + } else if (IsOutputPortRefValue(*input.node, input.port_id, op_registry)) { + return false; + } + } + for (const auto output : + graph_view.GetFanouts(node, /*include_controlled_nodes=*/false)) { + if (function_names.find(output.node->op()) != function_names.end()) { + // Node output is a function call. + return false; + } + } + return true; +} + +void ForwardInputsInternal( + const NodeDef& node, + const absl::flat_hash_set& nodes_to_delete, + bool add_as_control, NodeDef* new_node, + const absl::flat_hash_map& optimized_nodes, + const MutableGraphView& graph_view) { + // To speed things up, use the optimized version of the node if + // available. + auto itr = optimized_nodes.find(node.name()); + if (itr != optimized_nodes.end()) { + for (const string& input : itr->second->input()) { + *new_node->add_input() = + add_as_control ? AsControlDependency(NodeName(input)) : input; + } + return; + } + for (const auto& input : node.input()) { + const NodeDef* input_node = graph_view.GetNode(NodeName(input)); + if (input_node == nullptr) { + // Invalid input, preserve it as is. + *new_node->add_input() = + add_as_control ? AsControlDependency(NodeName(input)) : input; + continue; + } + if (nodes_to_delete.find(input_node) != nodes_to_delete.end()) { + ForwardInputsInternal(*input_node, nodes_to_delete, + add_as_control || IsControlInput(input), new_node, + optimized_nodes, graph_view); + } else { + *new_node->add_input() = + add_as_control ? AsControlDependency(NodeName(input)) : input; + } + } +} + +void ForwardInputs(const NodeDef& original_node, + const absl::flat_hash_set& nodes_to_delete, + NodeDef* new_node, + absl::flat_hash_map* optimized_nodes, + const MutableGraphView& graph_view) { + // Forwards inputs of nodes to be deleted to their respective outputs. + ForwardInputsInternal(original_node, nodes_to_delete, + /*add_as_control=*/false, new_node, *optimized_nodes, + graph_view); + if (!new_node->name().empty()) { + (*optimized_nodes)[new_node->name()] = new_node; + } + // Reorder inputs such that control inputs come after regular inputs. + int pos = 0; + for (int i = 0; i < new_node->input_size(); ++i) { + if (!IsControlInput(new_node->input(i))) { + new_node->mutable_input()->SwapElements(pos, i); + ++pos; + } + } + DedupControlInputs(new_node); +} + absl::flat_hash_map> IdentityNTerminalPorts( const NodeMap& node_map, const std::vector& terminal_nodes, int graph_size) { @@ -313,12 +447,17 @@ Status ModelPruner::Optimize(Cluster* cluster, const GrapplerItem& item, runnable_item = item; } - GraphRewriter rewriter(runnable_item); + MutableGraphView graph_view(&runnable_item.graph); + absl::flat_hash_set function_names; + for (const auto& function : item.graph.library().function()) { + function_names.insert(function.signature().name()); + } + OpRegistryInterface* op_registry = OpRegistry::Global(); // Check if we can further prune the graph, by removing the trivial ops. - std::unordered_set nodes_to_delete; + absl::flat_hash_set nodes_to_delete; for (auto& node : runnable_item.graph.node()) { - if (!IsTrivialOp(node, rewriter)) { + if (!IsTrivialOp(node, graph_view)) { continue; } @@ -341,10 +480,7 @@ Status ModelPruner::Optimize(Cluster* cluster, const GrapplerItem& item, // converting references to non-references. It is important to preserve // these non-references since the partitioner will avoid sending // non-references across partitions more than once. - if (!rewriter.RemovalIncreasesEdgeCount(node) && - !rewriter.IsConnectedToFunction(node) && - !rewriter.IsDrivenByAnotherDevice(node) && - !rewriter.ReceivesRefValue(node)) { + if (CanRemoveNode(node, graph_view, function_names, *op_registry)) { nodes_to_delete.insert(&node); } } @@ -360,13 +496,15 @@ Status ModelPruner::Optimize(Cluster* cluster, const GrapplerItem& item, const bool fetches_are_known = !item.fetch.empty(); pruned_graph->mutable_node()->Reserve(runnable_item.graph.node_size()); + absl::flat_hash_map optimized_nodes; for (auto& node : runnable_item.graph.node()) { if (!fetches_are_known || nodes_to_delete.find(&node) == nodes_to_delete.end()) { NodeDef* new_node = pruned_graph->add_node(); *new_node = node; new_node->clear_input(); - rewriter.ForwardInputs(node, nodes_to_delete, new_node); + ForwardInputs(node, nodes_to_delete, new_node, &optimized_nodes, + graph_view); } } VLOG(1) << "Pruned " << nodes_to_delete.size() -- GitLab From 6afcfdfb75857bbce7d680f272bc54231c351e97 Mon Sep 17 00:00:00 2001 From: Rohan Jain Date: Thu, 29 Nov 2018 09:36:29 -0800 Subject: [PATCH 538/672] Splitting up CapturedFunction into a CapturedFunction which handles the static state of functions like captured_inputs etc. and InstantiatedCapturedFunction that holds the handle and other state. CapturedFunctions are meant to be owned by the Dataset objects and InstantiatedCapturedFunctions by iterators. This is to facilitate splitting the Dataset and Iterator objects more naturally and create Dataset objects as we go. This CL also creates a FunctionHandleCache that owns all the function handles corresponding to an Iterator. Having this enables us to implement different semantics for clearing function state when an iterator is reset or when an iterator is re-started in a RepeatDataset. PiperOrigin-RevId: 223359901 --- tensorflow/core/BUILD | 1 + tensorflow/core/framework/dataset.cc | 3 + tensorflow/core/framework/dataset.h | 10 + .../core/framework/function_handle_cache.cc | 66 ++++++ .../core/framework/function_handle_cache.h | 53 +++++ .../core/kernels/data/captured_function.cc | 214 ++++++++---------- .../core/kernels/data/captured_function.h | 127 ++++++----- tensorflow/core/kernels/data/dataset_utils.cc | 8 +- tensorflow/core/kernels/data/dataset_utils.h | 4 +- .../numa_map_and_batch_dataset_op.cc | 8 +- .../core/kernels/data/filter_dataset_op.cc | 20 +- .../core/kernels/data/flat_map_dataset_op.cc | 7 +- .../core/kernels/data/generator_dataset_op.cc | 23 +- .../data/group_by_reducer_dataset_op.cc | 31 +-- .../data/group_by_window_dataset_op.cc | 25 +- .../kernels/data/interleave_dataset_op.cc | 8 +- tensorflow/core/kernels/data/iterator_ops.cc | 175 ++++++++------ .../kernels/data/map_and_batch_dataset_op.cc | 31 +-- .../core/kernels/data/map_dataset_op.cc | 25 +- .../kernels/data/multi_device_iterator_ops.cc | 50 ++-- .../core/kernels/data/optimize_dataset_op.cc | 7 + .../data/parallel_interleave_dataset_op.cc | 17 +- .../kernels/data/parallel_map_dataset_op.cc | 131 ++++++----- .../kernels/data/parallel_map_iterator.cc | 30 +-- .../core/kernels/data/parallel_map_iterator.h | 43 ++-- .../kernels/data/parse_example_dataset_op.cc | 199 ++++++++-------- .../core/kernels/data/scan_dataset_op.cc | 8 +- tensorflow/core/kernels/data/writer_ops.cc | 17 +- 28 files changed, 806 insertions(+), 535 deletions(-) create mode 100644 tensorflow/core/framework/function_handle_cache.cc create mode 100644 tensorflow/core/framework/function_handle_cache.h diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 7b46e8c9b4..97628a2561 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -869,6 +869,7 @@ tf_cuda_library( "framework/dataset_stateful_op_whitelist.h", "framework/device_base.h", "framework/function.h", + "framework/function_handle_cache.h", "framework/graph_def_util.h", "framework/graph_to_functiondef.h", "framework/kernel_def_builder.h", diff --git a/tensorflow/core/framework/dataset.cc b/tensorflow/core/framework/dataset.cc index fc6b5dde0c..6af14150b7 100644 --- a/tensorflow/core/framework/dataset.cc +++ b/tensorflow/core/framework/dataset.cc @@ -13,10 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ #include "tensorflow/core/framework/dataset.h" +#include #include "tensorflow/core/framework/device_base.h" +#include "tensorflow/core/framework/function.h" #include "tensorflow/core/graph/graph_def_builder.h" #include "tensorflow/core/graph/node_builder.h" +#include "tensorflow/core/platform/mutex.h" namespace tensorflow { namespace data { diff --git a/tensorflow/core/framework/dataset.h b/tensorflow/core/framework/dataset.h index 9b11449b30..b2689bbdb7 100644 --- a/tensorflow/core/framework/dataset.h +++ b/tensorflow/core/framework/dataset.h @@ -17,6 +17,7 @@ limitations under the License. #include #include +#include #include "tensorflow/core/framework/attr_value.pb.h" #include "tensorflow/core/framework/attr_value_util.h" @@ -259,6 +260,7 @@ class GraphDefBuilderWrapper { }; class StatsAggregator; +class FunctionHandleCache; // A cut-down version of `OpKernelContext` for running computations in // iterators. Note that we cannot simply use `OpKernelContext` here because we @@ -279,6 +281,7 @@ class IteratorContext { env(ctx->env()), function_library(ctx->function_library()), lib(ctx->lib()), + function_handle_cache(ctx->function_handle_cache()), model(ctx->model()), runner(*(ctx->runner())), runner_threadpool_size(ctx->runner_threadpool_size()), @@ -315,6 +318,9 @@ class IteratorContext { // The FunctionLibraryRuntime object to be used to make function calls. FunctionLibraryRuntime* lib = nullptr; + // A FunctionHandleCache that owns all the function handles. Not owned. + FunctionHandleCache* function_handle_cache = nullptr; + // If non-null, identifies the object used for performance modeling. std::shared_ptr model = nullptr; @@ -350,6 +356,10 @@ class IteratorContext { FunctionLibraryRuntime* lib() { return params_.lib; } + FunctionHandleCache* function_handle_cache() { + return params_.function_handle_cache; + } + const std::shared_ptr& model() { return params_.model; } std::function)>* runner() { diff --git a/tensorflow/core/framework/function_handle_cache.cc b/tensorflow/core/framework/function_handle_cache.cc new file mode 100644 index 0000000000..2b93b6b2f8 --- /dev/null +++ b/tensorflow/core/framework/function_handle_cache.cc @@ -0,0 +1,66 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#include "tensorflow/core/framework/function_handle_cache.h" + +#include "tensorflow/core/lib/gtl/map_util.h" +#include "tensorflow/core/lib/random/random.h" +#include "tensorflow/core/lib/strings/stringprintf.h" + +namespace tensorflow { +namespace data { + +FunctionHandleCache::FunctionHandleCache(FunctionLibraryRuntime* lib) + : lib_(lib), state_handle_(strings::Printf("%lld", random::New64())) {} + +FunctionHandleCache::~FunctionHandleCache() { + Status s = Clear(); + if (!s.ok()) { + LOG(ERROR) << "Failed to clear function handle cache: " << s.ToString(); + } +} + +Status FunctionHandleCache::Instantiate( + const string& function_name, AttrSlice attrs, + FunctionLibraryRuntime::InstantiateOptions options, + FunctionLibraryRuntime::Handle* handle) { + string key = Canonicalize(function_name, attrs, options); + FunctionLibraryRuntime::Handle h; + { + tf_shared_lock l(mu_); + h = gtl::FindWithDefault(handles_, key, kInvalidHandle); + } + if (h == kInvalidHandle) { + options.state_handle = state_handle_; + TF_RETURN_IF_ERROR( + lib_->Instantiate(function_name, attrs, options, handle)); + mutex_lock l(mu_); + handles_[key] = *handle; + } else { + *handle = h; + } + return Status::OK(); +} + +Status FunctionHandleCache::Clear() { + mutex_lock l(mu_); + for (auto entry : handles_) { + TF_RETURN_IF_ERROR(lib_->ReleaseHandle(entry.second)); + } + handles_.clear(); + return Status::OK(); +} + +} // namespace data +} // namespace tensorflow diff --git a/tensorflow/core/framework/function_handle_cache.h b/tensorflow/core/framework/function_handle_cache.h new file mode 100644 index 0000000000..2800a598e0 --- /dev/null +++ b/tensorflow/core/framework/function_handle_cache.h @@ -0,0 +1,53 @@ +/* Copyright 2018 The TensorFlow Authors. 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. +==============================================================================*/ +#ifndef TENSORFLOW_CORE_FRAMEWORK_FUNCTION_HANDLE_CACHE_H_ +#define TENSORFLOW_CORE_FRAMEWORK_FUNCTION_HANDLE_CACHE_H_ + +#include + +#include "tensorflow/core/framework/function.h" + +namespace tensorflow { +namespace data { + +class FunctionHandleCache { + public: + explicit FunctionHandleCache(FunctionLibraryRuntime* lib); + + ~FunctionHandleCache(); + + // Looks up the function to be instantiated in the cache first. If present, + // returns handle from there. Otherwise, instantiates a new function + // and stores handle in the cache. + Status Instantiate(const string& function_name, AttrSlice attrs, + FunctionLibraryRuntime::InstantiateOptions options, + FunctionLibraryRuntime::Handle* handle); + + // Releases all the handles in the cache, clearing out the state for all + // functions involved. + Status Clear(); + + private: + mutex mu_; + FunctionLibraryRuntime* lib_ = nullptr; // not owned + const string state_handle_; + std::unordered_map handles_ + GUARDED_BY(mu_); +}; + +} // namespace data +} // namespace tensorflow + +#endif // TENSORFLOW_CORE_FRAMEWORK_FUNCTION_HANDLE_CACHE_H_ diff --git a/tensorflow/core/kernels/data/captured_function.cc b/tensorflow/core/kernels/data/captured_function.cc index 64834e507f..973b6b0604 100644 --- a/tensorflow/core/kernels/data/captured_function.cc +++ b/tensorflow/core/kernels/data/captured_function.cc @@ -19,6 +19,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/function.h" #include "tensorflow/core/common_runtime/step_stats_collector.h" #include "tensorflow/core/framework/cancellation.h" +#include "tensorflow/core/framework/function_handle_cache.h" #include "tensorflow/core/framework/stats_aggregator.h" #include "tensorflow/core/lib/gtl/optional.h" #include "tensorflow/core/lib/random/random.h" @@ -118,10 +119,34 @@ Status CapturedFunction::Create( return Status::OK(); } -CapturedFunction::~CapturedFunction() { - if (lib_ != nullptr && f_handle_ != kInvalidHandle) { - lib_->ReleaseHandle(f_handle_).IgnoreError(); +Status CapturedFunction::Instantiate( + IteratorContext* ctx, std::unique_ptr* + instantiated_captured_function) { + // The context's runtime will be used for all subsequent calls. + FunctionLibraryRuntime* lib = ctx->lib(); + FunctionLibraryRuntime::InstantiateOptions inst_opts; + inst_opts.overlay_lib = ctx->function_library().get(); + inst_opts.create_kernels_eagerly = true; + if (!use_inter_op_parallelism_) { + inst_opts.executor_type = "SINGLE_THREADED_EXECUTOR"; } + + FunctionLibraryRuntime::Handle f_handle; + TF_RETURN_IF_ERROR(ctx->function_handle_cache()->Instantiate( + func_.name(), AttrSlice(&func_.attr()), inst_opts, &f_handle)); + const FunctionBody* fbody = lib->GetFunctionBody(f_handle); + if (fbody == nullptr) { + return errors::Internal("Failed to instantiate function body."); + } + + DataTypeVector ret_types; + for (const auto& ret_type : fbody->ret_types) { + ret_types.push_back(ret_type); + } + + instantiated_captured_function->reset(new InstantiatedCapturedFunction( + lib, f_handle, std::move(ret_types), *ctx->runner(), this)); + return Status::OK(); } namespace { @@ -244,35 +269,35 @@ class BorrowedArgsCallFrame : public CallFrameBase { } // namespace -Status CapturedFunction::GetHandle(IteratorContext* ctx, - FunctionLibraryRuntime::Handle* out_handle) { - tf_shared_lock l(mu_); - if (lib_ == nullptr) { - return errors::Internal("Captured function \"", func_.name(), - "\" was called before it was instantiated."); - } - if (ctx->lib() != lib_) { - return errors::Internal("Captured function \"", func_.name(), - "\" was called with a different " - "FunctionLibraryRuntime*, which is not permitted."); - } - *out_handle = f_handle_; - return Status::OK(); -} - -Status CapturedFunction::Run(IteratorContext* ctx, std::vector&& args, - std::vector* rets) { - FunctionLibraryRuntime::Handle handle; - TF_RETURN_IF_ERROR(GetHandle(ctx, &handle)); - +InstantiatedCapturedFunction::InstantiatedCapturedFunction( + FunctionLibraryRuntime* lib, FunctionLibraryRuntime::Handle f_handle, + DataTypeVector ret_types, std::function)> runner, + CapturedFunction* captured_func) + : lib_(lib), + f_handle_(f_handle), + ret_types_(std::move(ret_types)), + captured_runner_(std::move(runner)), + captured_func_(captured_func) {} + +// NOTE: We don't release f_handle_ here and instead delegate the function +// handle releasing to the FunctionHandleCache. This is because in some cases +// (RepeatDatasetOp in particular), we want to keep the function state (e.g. +// random number generator) even after the Iterator is reset after going through +// one epoch. +InstantiatedCapturedFunction::~InstantiatedCapturedFunction() {} + +Status InstantiatedCapturedFunction::Run(IteratorContext* ctx, + std::vector&& args, + std::vector* rets) const { FunctionLibraryRuntime::Options f_opts; - f_opts.step_id = CapturedFunction::generate_step_id(); - ScopedStepContainer step_container(f_opts.step_id, [ctx](const string& name) { - ctx->lib()->device()->resource_manager()->Cleanup(name).IgnoreError(); - }); + f_opts.step_id = InstantiatedCapturedFunction::generate_step_id(); + ScopedStepContainer step_container( + f_opts.step_id, [this](const string& name) { + lib_->device()->resource_manager()->Cleanup(name).IgnoreError(); + }); f_opts.step_container = &step_container; f_opts.runner = ctx->runner(); - if (ctx->lib()->device()->device_type() != DEVICE_CPU) { + if (lib_->device()->device_type() != DEVICE_CPU) { f_opts.create_rendezvous = true; } // TODO(mrry): Add cancellation manager support to IteratorContext @@ -284,10 +309,11 @@ Status CapturedFunction::Run(IteratorContext* ctx, std::vector&& args, CancellationManager c_mgr; f_opts.cancellation_manager = &c_mgr; - OwnedArgsCallFrame frame(std::move(args), &captured_inputs_, ret_types_); + OwnedArgsCallFrame frame(std::move(args), &captured_func_->captured_inputs(), + ret_types_); Notification n; Status s; - ctx->lib()->Run(f_opts, handle, &frame, [&n, &s](Status func_status) { + lib_->Run(f_opts, f_handle_, &frame, [&n, &s](Status func_status) { s.Update(func_status); n.Notify(); }); @@ -296,20 +322,18 @@ Status CapturedFunction::Run(IteratorContext* ctx, std::vector&& args, return frame.ConsumeRetvals(rets); } -Status CapturedFunction::RunWithBorrowedArgs(IteratorContext* ctx, - const std::vector& args, - std::vector* rets) { - FunctionLibraryRuntime::Handle handle; - TF_RETURN_IF_ERROR(GetHandle(ctx, &handle)); - +Status InstantiatedCapturedFunction::RunWithBorrowedArgs( + IteratorContext* ctx, const std::vector& args, + std::vector* rets) const { FunctionLibraryRuntime::Options f_opts; - f_opts.step_id = CapturedFunction::generate_step_id(); - ScopedStepContainer step_container(f_opts.step_id, [ctx](const string& name) { - ctx->lib()->device()->resource_manager()->Cleanup(name).IgnoreError(); - }); + f_opts.step_id = InstantiatedCapturedFunction::generate_step_id(); + ScopedStepContainer step_container( + f_opts.step_id, [this](const string& name) { + lib_->device()->resource_manager()->Cleanup(name).IgnoreError(); + }); f_opts.step_container = &step_container; f_opts.runner = ctx->runner(); - if (ctx->lib()->device()->device_type() != DEVICE_CPU) { + if (lib_->device()->device_type() != DEVICE_CPU) { f_opts.create_rendezvous = true; } // TODO(mrry): Add cancellation manager support to IteratorContext @@ -321,11 +345,12 @@ Status CapturedFunction::RunWithBorrowedArgs(IteratorContext* ctx, CancellationManager c_mgr; f_opts.cancellation_manager = &c_mgr; - BorrowedArgsCallFrame frame(args, &captured_inputs_, ret_types_); + BorrowedArgsCallFrame frame(args, &captured_func_->captured_inputs(), + ret_types_); Notification n; Status s; - ctx->lib()->Run(f_opts, handle, &frame, [&n, &s](Status func_status) { + lib_->Run(f_opts, f_handle_, &frame, [&n, &s](Status func_status) { s.Update(func_status); n.Notify(); }); @@ -334,65 +359,17 @@ Status CapturedFunction::RunWithBorrowedArgs(IteratorContext* ctx, return frame.ConsumeRetvals(rets); } -Status CapturedFunction::Instantiate(IteratorContext* ctx) { - mutex_lock l(mu_); - if (lib_ == nullptr) { - // The context's runtime will be used for all subsequent calls. - lib_ = ctx->lib(); - DCHECK(f_handle_ == kInvalidHandle); - FunctionLibraryRuntime::InstantiateOptions inst_opts; - inst_opts.overlay_lib = ctx->function_library().get(); - inst_opts.state_handle = std::to_string(random::New64()); - inst_opts.create_kernels_eagerly = true; - if (!use_inter_op_parallelism_) { - inst_opts.executor_type = "SINGLE_THREADED_EXECUTOR"; - } - Status s = (lib_->Instantiate(func_.name(), AttrSlice(&func_.attr()), - inst_opts, &f_handle_)); - TF_RETURN_IF_ERROR(s); - const FunctionBody* fbody = lib_->GetFunctionBody(f_handle_); - if (fbody == nullptr) { - return errors::Internal("Failed to instantiate function body."); - } - ret_types_ = fbody->ret_types; - } else { - if (ctx->lib() != lib_) { - return errors::Internal( - "Captured function was called with a different " - "FunctionLibraryRuntime*, which is not permitted."); - } - } - if (captured_runner_ == nullptr) { - captured_runner_ = *ctx->runner(); - } - return Status::OK(); -} - -Status CapturedFunction::RunInstantiated(const std::vector& args, - std::vector* rets) { - FunctionLibraryRuntime* lib; - FunctionLibraryRuntime::Handle handle; - std::function)>* runner; - { - tf_shared_lock l(mu_); - if (lib_ == nullptr) { - return errors::FailedPrecondition( - "`CapturedFunction::Instantiate()` must be called before a call to " - "`CapturedFunction::RunInstantiated()`."); - } - lib = lib_; - handle = f_handle_; - runner = &captured_runner_; - } - +Status InstantiatedCapturedFunction::RunInstantiated( + const std::vector& args, std::vector* rets) { FunctionLibraryRuntime::Options f_opts; - f_opts.step_id = CapturedFunction::generate_step_id(); - ScopedStepContainer step_container(f_opts.step_id, [lib](const string& name) { - lib->device()->resource_manager()->Cleanup(name).IgnoreError(); - }); + f_opts.step_id = InstantiatedCapturedFunction::generate_step_id(); + ScopedStepContainer step_container( + f_opts.step_id, [this](const string& name) { + lib_->device()->resource_manager()->Cleanup(name).IgnoreError(); + }); f_opts.step_container = &step_container; - f_opts.runner = runner; - if (lib->device()->device_type() != DEVICE_CPU) { + f_opts.runner = &captured_runner_; + if (lib_->device()->device_type() != DEVICE_CPU) { f_opts.create_rendezvous = true; } // TODO(mrry): Add cancellation manager support to IteratorContext @@ -404,11 +381,12 @@ Status CapturedFunction::RunInstantiated(const std::vector& args, CancellationManager c_mgr; f_opts.cancellation_manager = &c_mgr; - BorrowedArgsCallFrame frame(args, &captured_inputs_, ret_types_); + BorrowedArgsCallFrame frame(args, &captured_func_->captured_inputs(), + ret_types_); Notification n; Status s; - lib->Run(f_opts, handle, &frame, [&n, &s](Status func_status) { + lib_->Run(f_opts, f_handle_, &frame, [&n, &s](Status func_status) { s.Update(func_status); n.Notify(); }); @@ -417,33 +395,25 @@ Status CapturedFunction::RunInstantiated(const std::vector& args, return frame.ConsumeRetvals(rets); } -void CapturedFunction::RunAsync(IteratorContext* ctx, - std::vector&& args, - std::vector* rets, - FunctionLibraryRuntime::DoneCallback done, - const string& prefix) { +void InstantiatedCapturedFunction::RunAsync( + IteratorContext* ctx, std::vector&& args, std::vector* rets, + FunctionLibraryRuntime::DoneCallback done, const string& prefix) const { // NOTE(mrry): This method does not transfer ownership of `ctx`, and it may // be deleted before `done` is called. Take care not to capture `ctx` in any // code that may execute asynchronously in this function. - FunctionLibraryRuntime::Handle handle; - Status s = GetHandle(ctx, &handle); - if (!s.ok()) { - done(s); - return; - } - OwnedArgsCallFrame* frame = - new OwnedArgsCallFrame(std::move(args), &captured_inputs_, ret_types_); + OwnedArgsCallFrame* frame = new OwnedArgsCallFrame( + std::move(args), &captured_func_->captured_inputs(), ret_types_); FunctionLibraryRuntime::Options f_opts; - f_opts.step_id = CapturedFunction::generate_step_id(); - ResourceMgr* resource_mgr = ctx->lib()->device()->resource_manager(); + f_opts.step_id = InstantiatedCapturedFunction::generate_step_id(); + ResourceMgr* resource_mgr = lib_->device()->resource_manager(); ScopedStepContainer* step_container = new ScopedStepContainer( f_opts.step_id, [resource_mgr](const string& name) { resource_mgr->Cleanup(name).IgnoreError(); }); f_opts.step_container = step_container; f_opts.runner = ctx->runner(); - if (ctx->lib()->device()->device_type() != DEVICE_CPU) { + if (lib_->device()->device_type() != DEVICE_CPU) { f_opts.create_rendezvous = true; } // TODO(mrry): Add cancellation manager support to IteratorContext @@ -480,7 +450,7 @@ void CapturedFunction::RunAsync(IteratorContext* ctx, stats_aggregator->AddToHistogram( strings::StrCat( str_util::Split(prefix, "::", str_util::SkipEmpty()).back(), - "::", func_.name(), "::execution_time"), + "::", captured_func_->func().name(), "::execution_time"), {static_cast(stats_collector->processing_time())}); } if (model) { @@ -495,15 +465,13 @@ void CapturedFunction::RunAsync(IteratorContext* ctx, std::move(done), ctx->model(), ctx->stats_aggregator(), prefix, std::move(stats_collector), std::placeholders::_1); - ctx->lib()->Run(f_opts, handle, frame, std::move(callback)); + lib_->Run(f_opts, f_handle_, frame, std::move(callback)); } CapturedFunction::CapturedFunction(const NameAttrList& func, std::vector captured_inputs, bool use_inter_op_parallelism) : func_(func), - lib_(nullptr), - f_handle_(kInvalidHandle), captured_inputs_(std::move(captured_inputs)), use_inter_op_parallelism_(use_inter_op_parallelism) {} diff --git a/tensorflow/core/kernels/data/captured_function.h b/tensorflow/core/kernels/data/captured_function.h index c6a5fe9e1e..cffaf405ec 100644 --- a/tensorflow/core/kernels/data/captured_function.h +++ b/tensorflow/core/kernels/data/captured_function.h @@ -34,59 +34,41 @@ class ResourceMgr; namespace data { -// A `CapturedFunction` encapsulates a TensorFlow function and all of -// the runtime support required to execute it. +class CapturedFunction; + +// An InstantiatedCapturedFunction encapsulates all the runtime support needed +// to execute a tensorflow function. // -// The `Dataset`-related classes use `CapturedFunction` to execute -// TensorFlow functions outside a the normal `OpKernel::Compute()` -// context. -class CapturedFunction { +// While CapturedFunction (below) encapsulates the more permanent attributes +// of the function i.e. name, captured arguments etc., +// InstantiatedCapturedFunction encapsulates the more runtime aspects i.e. +// FunctionLibraryRuntime, function handle etc. +// +// The `Iterator-`related classes use `InstantiatedCapturedFunction` to execute +// functions outside a the normal `OpKernel::Compute()` context. +class InstantiatedCapturedFunction { public: - // Creates a new instance using a list of named attributes, fetching captured - // inputs from a context argument. - static Status Create(const NameAttrList& func, OpKernelContext* ctx, - const string& argument, - std::unique_ptr* out_function); - - // Creates a new instance using a list of named attributes, fetching captured - // inputs from a context argument. - // - // If `use_inter_op_parallelism` is false, the runtime may use an executor - // that is optimized for small functions. - static Status Create(const NameAttrList& func, OpKernelContext* ctx, - const string& argument, bool use_inter_op_parallelism, - std::unique_ptr* out_function); - - ~CapturedFunction(); + ~InstantiatedCapturedFunction(); - // Runs the "Captured function" using the given FLR and caches the lib and - // handle generated during instantiation. If Run is called with a different - // lib afterwards, generates an error. This method takes ownership of the - // tensors in `args`, in order to be able to deallocate them as early as + // Runs the "Instantiated Captured function". This method takes ownership of + // the tensors in `args`, in order to be able to deallocate them as early as // possible. Use `RunWithBorrowedArgs()` if the caller needs to retain // ownership of the `args`. Status Run(IteratorContext* ctx, std::vector&& args, - std::vector* rets); + std::vector* rets) const; // Synchronously runs the captured function on the given `args`, and stores // the results in `*rets`. Prefer to use `Run()` or `RunAsync()` when // possible. Status RunWithBorrowedArgs(IteratorContext* ctx, const std::vector& args, - std::vector* rets); - - // Explicitly instantiate this function for use in the given - // context. This method, and the context-less overload - // `RunInstantiated()` below can be useful for calling a captured - // function in cases where an `IteratorContext*` is not available - // (such as a destructor). - Status Instantiate(IteratorContext* ctx); + std::vector* rets) const; // Synchronously runs the captured function on the given `args`, and stores // the results in `*rets`. Prefer to use `Run()` or `RunAsync()` when - // possible. - // - // REQUIRES: `this->Instantiate()` must have been called before this method. + // possible. This can be useful for calling a captured + // function in cases where an `IteratorContext*` is not available + // (such as a destructor). Status RunInstantiated(const std::vector& args, std::vector* rets); @@ -97,16 +79,9 @@ class CapturedFunction { void RunAsync(IteratorContext* ctx, std::vector&& args, std::vector* rets, FunctionLibraryRuntime::DoneCallback done, - const string& prefix); - - // Returns the named list of function arguments. - const NameAttrList& func() { return func_; } + const string& prefix) const; - // Returns that additional captured inputs that will be passed to the function - // when `Run*()` is called. - const std::vector& captured_inputs() { return captured_inputs_; } - - // Returns a step ID for use when running a `CapturedFunction`. + // Returns a step ID for use when running an `InstantiatedCapturedFunction`. static int64 generate_step_id() { // Choose a step ID that is guaranteed not to clash with any // Session-generated step ID. DirectSession only generates @@ -116,26 +91,66 @@ class CapturedFunction { return -std::abs(static_cast(random::New64())); } + private: + InstantiatedCapturedFunction( + FunctionLibraryRuntime* lib, FunctionLibraryRuntime::Handle f_handle, + DataTypeVector ret_types, + std::function)> runner, + CapturedFunction* captured_func); + + friend class CapturedFunction; + + FunctionLibraryRuntime* const lib_; + const FunctionLibraryRuntime::Handle f_handle_; + const DataTypeVector ret_types_; + std::function)> captured_runner_; + CapturedFunction* const captured_func_; + + TF_DISALLOW_COPY_AND_ASSIGN(InstantiatedCapturedFunction); +}; + +// A `CapturedFunction` encapsulates a TensorFlow function, plus any "captured" +// arguments that it closed over in the user program. +class CapturedFunction { + public: + // Creates a new instance using a list of named attributes, fetching captured + // inputs from a context argument. + static Status Create(const NameAttrList& func, OpKernelContext* ctx, + const string& argument, + std::unique_ptr* out_function); + + // Creates a new instance using a list of named attributes, fetching captured + // inputs from a context argument. + // + // If `use_inter_op_parallelism` is false, the runtime may use an executor + // that is optimized for small functions. + static Status Create(const NameAttrList& func, OpKernelContext* ctx, + const string& argument, bool use_inter_op_parallelism, + std::unique_ptr* out_function); + + // Instantiates this function for use in the given context, providing an + // InstantiatedCapturedFunction that can be used to execute functions. + Status Instantiate(IteratorContext* ctx, + std::unique_ptr* + instantiated_captured_function); + + // Returns the named list of function arguments. + const NameAttrList& func() { return func_; } + + // Returns that additional captured inputs that will be passed to the function + const std::vector& captured_inputs() { return captured_inputs_; } + private: CapturedFunction(const NameAttrList& func, std::vector captured_inputs, bool use_inter_op_parallelism); - Status GetHandle(IteratorContext* ctx, - FunctionLibraryRuntime::Handle* out_handle); - - mutex mu_; const NameAttrList func_; - FunctionLibraryRuntime* lib_ GUARDED_BY(mu_); - FunctionLibraryRuntime::Handle f_handle_ GUARDED_BY(mu_); const std::vector captured_inputs_; - DataTypeSlice ret_types_; - std::function)> captured_runner_ = nullptr; const bool use_inter_op_parallelism_; TF_DISALLOW_COPY_AND_ASSIGN(CapturedFunction); }; - } // namespace data // TODO(b/114112161): Remove these aliases when all users have moved over to the diff --git a/tensorflow/core/kernels/data/dataset_utils.cc b/tensorflow/core/kernels/data/dataset_utils.cc index 1be38c4cb2..4d92d314d3 100644 --- a/tensorflow/core/kernels/data/dataset_utils.cc +++ b/tensorflow/core/kernels/data/dataset_utils.cc @@ -81,12 +81,12 @@ std::vector ComputeMoveVector(const std::vector& indices) { Status MakeIteratorFromInputElement( IteratorContext* ctx, const std::vector& input_element, - int64 thread_index, CapturedFunction* captured_func, StringPiece prefix, - std::unique_ptr* out_iterator) { + int64 thread_index, const InstantiatedCapturedFunction& inst_captured_func, + StringPiece prefix, std::unique_ptr* out_iterator) { std::vector return_values; - TF_RETURN_IF_ERROR( - captured_func->RunWithBorrowedArgs(ctx, input_element, &return_values)); + TF_RETURN_IF_ERROR(inst_captured_func.RunWithBorrowedArgs(ctx, input_element, + &return_values)); if (!(return_values.size() == 1 && return_values[0].dtype() == DT_VARIANT && TensorShapeUtils::IsScalar(return_values[0].shape()))) { diff --git a/tensorflow/core/kernels/data/dataset_utils.h b/tensorflow/core/kernels/data/dataset_utils.h index 0b2816119d..23a3d93ed1 100644 --- a/tensorflow/core/kernels/data/dataset_utils.h +++ b/tensorflow/core/kernels/data/dataset_utils.h @@ -44,8 +44,8 @@ std::vector ComputeMoveVector(const std::vector& indices); Status MakeIteratorFromInputElement( IteratorContext* ctx, const std::vector& input_element, - int64 thread_index, CapturedFunction* captured_func, StringPiece prefix, - std::unique_ptr* out_iterator); + int64 thread_index, const InstantiatedCapturedFunction& inst_captured_func, + StringPiece prefix, std::unique_ptr* out_iterator); // Returns Status::OK() if `expected` and `received` types match, // errors::InvalidArgument otherwise. diff --git a/tensorflow/core/kernels/data/experimental/numa_map_and_batch_dataset_op.cc b/tensorflow/core/kernels/data/experimental/numa_map_and_batch_dataset_op.cc index 068f854023..75eacb4b5b 100644 --- a/tensorflow/core/kernels/data/experimental/numa_map_and_batch_dataset_op.cc +++ b/tensorflow/core/kernels/data/experimental/numa_map_and_batch_dataset_op.cc @@ -206,7 +206,8 @@ class NumaMapAndBatchDatasetOp : public UnaryDatasetOpKernel { } TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - TF_RETURN_IF_ERROR(dataset()->captured_func_->Instantiate(ctx)); + TF_RETURN_IF_ERROR(dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_)); return Status::OK(); } @@ -1052,8 +1053,8 @@ class NumaMapAndBatchDatasetOp : public UnaryDatasetOpKernel { { tracing::ScopedActivity trace( "NumaMapAndBatch::Iterator::Worker::FunctionExecution"); - s = dataset()->captured_func_->Run(ctx.get(), std::move(input), - &return_values); + s = instantiated_captured_func_->Run(ctx.get(), std::move(input), + &return_values); } WORKER_VLOG(4) << "ran function for index: " << index << ", sequence_number: " << sequence_number; @@ -1099,6 +1100,7 @@ class NumaMapAndBatchDatasetOp : public UnaryDatasetOpKernel { const std::shared_ptr autotune_cond_var_; // The maximum number of parallel calls (can be auto-tuned). const std::shared_ptr num_parallel_calls_; + std::unique_ptr instantiated_captured_func_; // Caches the last-seen value of num_parallel_calls_->value to // short-circuit starting workers. diff --git a/tensorflow/core/kernels/data/filter_dataset_op.cc b/tensorflow/core/kernels/data/filter_dataset_op.cc index 40cbb12425..b8b657d343 100644 --- a/tensorflow/core/kernels/data/filter_dataset_op.cc +++ b/tensorflow/core/kernels/data/filter_dataset_op.cc @@ -34,7 +34,8 @@ namespace { class FilterDatasetOp : public UnaryDatasetOpKernel { public: using FilterIteratorPredicate = - std::function, bool*)>; + std::function, bool*)>; explicit FilterDatasetOp(OpKernelConstruction* ctx) : UnaryDatasetOpKernel(ctx) { @@ -55,13 +56,12 @@ class FilterDatasetOp : public UnaryDatasetOpKernel { FilterIteratorPredicate filter_pred; if (indices.empty()) { - CapturedFunction* raw_captured_func = captured_func.get(); - filter_pred = [raw_captured_func](IteratorContext* ctx, - const std::vector& args, - bool* out_matched) { + filter_pred = [](IteratorContext* ctx, + InstantiatedCapturedFunction* inst_captured_func, + const std::vector& args, bool* out_matched) { std::vector result; TF_RETURN_IF_ERROR( - raw_captured_func->RunWithBorrowedArgs(ctx, args, &result)); + inst_captured_func->RunWithBorrowedArgs(ctx, args, &result)); if (result.size() != 1 || result[0].dtype() != DT_BOOL || result[0].NumElements() != 1) { @@ -73,6 +73,7 @@ class FilterDatasetOp : public UnaryDatasetOpKernel { }; } else { filter_pred = [indices](IteratorContext* ctx, + InstantiatedCapturedFunction* inst_captured_func, const std::vector& args, bool* out_matched) { const Tensor& predicate = args[indices[0]]; @@ -169,7 +170,8 @@ class FilterDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } Status GetNextInternal(IteratorContext* ctx, @@ -197,7 +199,8 @@ class FilterDatasetOp : public UnaryDatasetOpKernel { return Status::OK(); } - TF_RETURN_IF_ERROR(filter_pred_(ctx, *out_tensors, &matched)); + TF_RETURN_IF_ERROR(filter_pred_( + ctx, instantiated_captured_func_.get(), *out_tensors, &matched)); if (!matched) { // Clear the output tensor list since it didn't match. out_tensors->clear(); @@ -274,6 +277,7 @@ class FilterDatasetOp : public UnaryDatasetOpKernel { int64 dropped_elements_ GUARDED_BY(mu_); const FilterIteratorPredicate filter_pred_; string prefix_end_; + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/flat_map_dataset_op.cc b/tensorflow/core/kernels/data/flat_map_dataset_op.cc index 9b42981ed7..3846334622 100644 --- a/tensorflow/core/kernels/data/flat_map_dataset_op.cc +++ b/tensorflow/core/kernels/data/flat_map_dataset_op.cc @@ -122,7 +122,8 @@ class FlatMapDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } Status GetNextInternal(IteratorContext* ctx, @@ -243,8 +244,7 @@ class FlatMapDatasetOp : public UnaryDatasetOpKernel { EXCLUSIVE_LOCKS_REQUIRED(mu_) { return MakeIteratorFromInputElement( ctx, captured_func_inputs_, element_index_++, - dataset()->captured_func_.get(), prefix(), - ¤t_element_iterator_); + *instantiated_captured_func_, prefix(), ¤t_element_iterator_); } mutex mu_; @@ -252,6 +252,7 @@ class FlatMapDatasetOp : public UnaryDatasetOpKernel { std::unique_ptr input_impl_ GUARDED_BY(mu_); std::unique_ptr current_element_iterator_ GUARDED_BY(mu_); std::vector captured_func_inputs_ GUARDED_BY(mu_); + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/generator_dataset_op.cc b/tensorflow/core/kernels/data/generator_dataset_op.cc index ed18d6ed9d..c089bfc45f 100644 --- a/tensorflow/core/kernels/data/generator_dataset_op.cc +++ b/tensorflow/core/kernels/data/generator_dataset_op.cc @@ -73,7 +73,8 @@ class GeneratorDatasetOp::Dataset : public DatasetBase { ~Iterator() override { if (!finalized_) { std::vector ignored; - Status s = dataset()->finalize_func_->RunInstantiated(state_, &ignored); + Status s = + instantiated_finalize_func_->RunInstantiated(state_, &ignored); if (!s.ok()) { LOG(WARNING) << "Error occurred when finalizing GeneratorDataset iterator: " @@ -83,9 +84,12 @@ class GeneratorDatasetOp::Dataset : public DatasetBase { } Status Initialize(IteratorContext* ctx) override { - TF_RETURN_IF_ERROR(dataset()->init_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR(dataset()->next_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR(dataset()->finalize_func_->Instantiate(ctx)); + TF_RETURN_IF_ERROR( + dataset()->init_func_->Instantiate(ctx, &instantiated_init_func_)); + TF_RETURN_IF_ERROR( + dataset()->next_func_->Instantiate(ctx, &instantiated_next_func_)); + TF_RETURN_IF_ERROR(dataset()->finalize_func_->Instantiate( + ctx, &instantiated_finalize_func_)); return Status::OK(); } @@ -96,7 +100,7 @@ class GeneratorDatasetOp::Dataset : public DatasetBase { if (!initialized_) { TF_RETURN_IF_ERROR( - dataset()->init_func_->RunWithBorrowedArgs(ctx, {}, &state_)); + instantiated_init_func_->RunWithBorrowedArgs(ctx, {}, &state_)); initialized_ = true; } @@ -105,8 +109,8 @@ class GeneratorDatasetOp::Dataset : public DatasetBase { return Status::OK(); } - Status s = - dataset()->next_func_->RunWithBorrowedArgs(ctx, state_, out_tensors); + Status s = instantiated_next_func_->RunWithBorrowedArgs(ctx, state_, + out_tensors); if (s.ok()) { *end_of_sequence = false; } else if (errors::IsOutOfRange(s)) { @@ -119,7 +123,7 @@ class GeneratorDatasetOp::Dataset : public DatasetBase { // finalize function. std::vector ignored; TF_RETURN_IF_ERROR( - dataset()->finalize_func_->RunInstantiated(state_, &ignored)); + instantiated_finalize_func_->RunInstantiated(state_, &ignored)); finalized_ = true; } return s; @@ -136,6 +140,9 @@ class GeneratorDatasetOp::Dataset : public DatasetBase { bool initialized_ GUARDED_BY(mu_) = false; bool finalized_ GUARDED_BY(mu_) = false; std::vector state_ GUARDED_BY(mu_); + std::unique_ptr instantiated_init_func_; + std::unique_ptr instantiated_next_func_; + std::unique_ptr instantiated_finalize_func_; }; const std::unique_ptr init_func_; diff --git a/tensorflow/core/kernels/data/group_by_reducer_dataset_op.cc b/tensorflow/core/kernels/data/group_by_reducer_dataset_op.cc index dc1925a21f..a01085491e 100644 --- a/tensorflow/core/kernels/data/group_by_reducer_dataset_op.cc +++ b/tensorflow/core/kernels/data/group_by_reducer_dataset_op.cc @@ -191,11 +191,14 @@ class GroupByReducerDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - TF_RETURN_IF_ERROR(dataset()->captured_key_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR(dataset()->captured_init_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR(dataset()->captured_reduce_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR( - dataset()->captured_finalize_func_->Instantiate(ctx)); + TF_RETURN_IF_ERROR(dataset()->captured_key_func_->Instantiate( + ctx, &instantiated_key_func_)); + TF_RETURN_IF_ERROR(dataset()->captured_init_func_->Instantiate( + ctx, &instantiated_init_func_)); + TF_RETURN_IF_ERROR(dataset()->captured_reduce_func_->Instantiate( + ctx, &instantiated_reduce_func_)); + TF_RETURN_IF_ERROR(dataset()->captured_finalize_func_->Instantiate( + ctx, &instantiated_finalize_func_)); return Status::OK(); } @@ -213,9 +216,8 @@ class GroupByReducerDatasetOp : public UnaryDatasetOpKernel { if (!end_of_input_) { // Run the key function on the input element. std::vector key_func_output; - TF_RETURN_IF_ERROR( - dataset()->captured_key_func_->RunWithBorrowedArgs( - ctx, next_input_element, &key_func_output)); + TF_RETURN_IF_ERROR(instantiated_key_func_->RunWithBorrowedArgs( + ctx, next_input_element, &key_func_output)); if (key_func_output.size() != 1 || key_func_output[0].dtype() != DT_INT64 || @@ -229,7 +231,7 @@ class GroupByReducerDatasetOp : public UnaryDatasetOpKernel { if (states_.find(key) == states_.end()) { // Run the init function to create the initial state. std::vector init_func_output; - TF_RETURN_IF_ERROR(dataset()->captured_init_func_->Run( + TF_RETURN_IF_ERROR(instantiated_init_func_->Run( ctx, std::move(key_func_output), &init_func_output)); states_[key] = init_func_output; } @@ -243,7 +245,7 @@ class GroupByReducerDatasetOp : public UnaryDatasetOpKernel { std::back_inserter(args)); std::vector reduce_func_output; - TF_RETURN_IF_ERROR(dataset()->captured_reduce_func_->Run( + TF_RETURN_IF_ERROR(instantiated_reduce_func_->Run( ctx, std::move(args), &reduce_func_output)); states_[key] = reduce_func_output; } else { @@ -259,9 +261,8 @@ class GroupByReducerDatasetOp : public UnaryDatasetOpKernel { *end_of_sequence = true; return Status::OK(); } - TF_RETURN_IF_ERROR( - dataset()->captured_finalize_func_->RunWithBorrowedArgs( - ctx, states_[keys_[keys_index_++]], out_tensors)); + TF_RETURN_IF_ERROR(instantiated_finalize_func_->RunWithBorrowedArgs( + ctx, states_[keys_[keys_index_++]], out_tensors)); *end_of_sequence = false; return Status::OK(); } @@ -384,6 +385,10 @@ class GroupByReducerDatasetOp : public UnaryDatasetOpKernel { std::map> states_ GUARDED_BY(mu_); std::vector keys_ GUARDED_BY(mu_); int64 keys_index_ GUARDED_BY(mu_) = 0; + std::unique_ptr instantiated_key_func_; + std::unique_ptr instantiated_init_func_; + std::unique_ptr instantiated_reduce_func_; + std::unique_ptr instantiated_finalize_func_; }; const NameAttrList& key_func() const { return captured_key_func_->func(); } diff --git a/tensorflow/core/kernels/data/group_by_window_dataset_op.cc b/tensorflow/core/kernels/data/group_by_window_dataset_op.cc index 64db5df31e..d9f504a170 100644 --- a/tensorflow/core/kernels/data/group_by_window_dataset_op.cc +++ b/tensorflow/core/kernels/data/group_by_window_dataset_op.cc @@ -175,10 +175,12 @@ class GroupByWindowDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - TF_RETURN_IF_ERROR(dataset()->captured_key_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR(dataset()->captured_reduce_func_->Instantiate(ctx)); - TF_RETURN_IF_ERROR( - dataset()->captured_window_size_func_->Instantiate(ctx)); + TF_RETURN_IF_ERROR(dataset()->captured_key_func_->Instantiate( + ctx, &instantiated_key_func_)); + TF_RETURN_IF_ERROR(dataset()->captured_reduce_func_->Instantiate( + ctx, &instantiated_reduce_func_)); + TF_RETURN_IF_ERROR(dataset()->captured_window_size_func_->Instantiate( + ctx, &instantiated_window_size_func_)); return Status::OK(); } @@ -215,9 +217,8 @@ class GroupByWindowDatasetOp : public UnaryDatasetOpKernel { // Run the key function on the input element to identify its // group. std::vector key_func_output; - TF_RETURN_IF_ERROR( - dataset()->captured_key_func_->RunWithBorrowedArgs( - ctx, next_input_element, &key_func_output)); + TF_RETURN_IF_ERROR(instantiated_key_func_->RunWithBorrowedArgs( + ctx, next_input_element, &key_func_output)); if (key_func_output.size() != 1 || key_func_output[0].dtype() != DT_INT64 || @@ -232,7 +233,7 @@ class GroupByWindowDatasetOp : public UnaryDatasetOpKernel { // Run the window size function on the key to identify its // window size. std::vector window_size_func_output; - TF_RETURN_IF_ERROR(dataset()->captured_window_size_func_->Run( + TF_RETURN_IF_ERROR(instantiated_window_size_func_->Run( ctx, std::move(key_func_output), &window_size_func_output)); if (window_size_func_output.size() != 1 || @@ -452,8 +453,8 @@ class GroupByWindowDatasetOp : public UnaryDatasetOpKernel { std::vector args( {std::move(key_arg), std::move(group_dataset_arg)}); std::vector return_values; - TF_RETURN_IF_ERROR(dataset()->captured_reduce_func_->Run( - ctx, std::move(args), &return_values)); + TF_RETURN_IF_ERROR(instantiated_reduce_func_->Run(ctx, std::move(args), + &return_values)); if (!(return_values.size() == 1 && return_values[0].dtype() == DT_VARIANT && @@ -482,6 +483,10 @@ class GroupByWindowDatasetOp : public UnaryDatasetOpKernel { std::map>> groups_ GUARDED_BY(mu_); std::unique_ptr current_group_iterator_ GUARDED_BY(mu_); std::map window_sizes_ GUARDED_BY(mu_); + std::unique_ptr instantiated_key_func_; + std::unique_ptr instantiated_reduce_func_; + std::unique_ptr + instantiated_window_size_func_; }; Status OtherArgumentsNodeAndType( diff --git a/tensorflow/core/kernels/data/interleave_dataset_op.cc b/tensorflow/core/kernels/data/interleave_dataset_op.cc index 9574e400a2..54e3645612 100644 --- a/tensorflow/core/kernels/data/interleave_dataset_op.cc +++ b/tensorflow/core/kernels/data/interleave_dataset_op.cc @@ -149,7 +149,8 @@ class InterleaveDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } void AdvanceToNextInCycle() EXCLUSIVE_LOCKS_REQUIRED(mu_) { @@ -195,7 +196,7 @@ class InterleaveDatasetOp : public UnaryDatasetOpKernel { if (!end_of_input_) { TF_RETURN_IF_ERROR(MakeIteratorFromInputElement( ctx, args_list_[cycle_index_], cycle_index_, - dataset()->captured_func_.get(), prefix(), + *instantiated_captured_func_, prefix(), ¤t_elements_[cycle_index_])); ++num_open_; } @@ -286,7 +287,7 @@ class InterleaveDatasetOp : public UnaryDatasetOpKernel { &args_list_[idx][i])); } TF_RETURN_IF_ERROR(MakeIteratorFromInputElement( - ctx, args_list_[idx], idx, dataset()->captured_func_.get(), + ctx, args_list_[idx], idx, *instantiated_captured_func_, prefix(), ¤t_elements_[idx])); TF_RETURN_IF_ERROR( RestoreInput(ctx, reader, current_elements_[idx])); @@ -306,6 +307,7 @@ class InterleaveDatasetOp : public UnaryDatasetOpKernel { int64 block_index_ GUARDED_BY(mu_) = 0; bool end_of_input_ GUARDED_BY(mu_) = false; size_t num_open_ GUARDED_BY(mu_) = 0; + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/iterator_ops.cc b/tensorflow/core/kernels/data/iterator_ops.cc index 98b67454d5..c50af846f9 100644 --- a/tensorflow/core/kernels/data/iterator_ops.cc +++ b/tensorflow/core/kernels/data/iterator_ops.cc @@ -19,6 +19,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/renamed_device.h" #include "tensorflow/core/common_runtime/threadpool_device.h" #include "tensorflow/core/framework/function.h" +#include "tensorflow/core/framework/function_handle_cache.h" #include "tensorflow/core/framework/iterator.pb.h" #include "tensorflow/core/framework/partial_tensor_shape.h" #include "tensorflow/core/framework/resource_op_kernel.h" @@ -59,25 +60,25 @@ class IteratorResource : public ResourceBase { std::unique_ptr pflr, FunctionLibraryRuntime* lib) : device_mgr_(std::move(device_mgr)), - flib_def_(std::move(flib_def)), - pflr_(std::move(pflr)), - lib_(lib), - iterator_(nullptr), + iterator_state_( + new State(std::move(flib_def), std::move(pflr), lib, nullptr)), output_dtypes_(output_dtypes), output_shapes_(output_shapes) {} Status GetNext(IteratorContext* ctx, std::vector* out_tensors, bool* end_of_sequence) { - IteratorContext::Params params(ctx); - std::shared_ptr captured_iterator; + std::shared_ptr captured_state; { tf_shared_lock l(mu_); - captured_iterator = iterator_; - params.lib = lib_; + captured_state = iterator_state_; } - if (captured_iterator) { - return captured_iterator->GetNext(IteratorContext(std::move(params)), - out_tensors, end_of_sequence); + if (captured_state->iterator) { + IteratorContext::Params params(ctx); + params.lib = captured_state->lib; + params.function_handle_cache = + captured_state->function_handle_cache.get(); + return captured_state->iterator->GetNext( + IteratorContext(std::move(params)), out_tensors, end_of_sequence); } else { return errors::FailedPrecondition( "GetNext() failed because the iterator has not been initialized. " @@ -92,13 +93,13 @@ class IteratorResource : public ResourceBase { } Status Save(SerializationContext* ctx, IteratorStateWriter* writer) { - std::shared_ptr captured_iterator; + std::shared_ptr captured_state; { tf_shared_lock l(mu_); - captured_iterator = iterator_; + captured_state = iterator_state_; } - if (captured_iterator) { - return captured_iterator->Save(ctx, writer); + if (captured_state) { + return captured_state->iterator->Save(ctx, writer); } else { return errors::FailedPrecondition( "Save() failed because the iterator has not been initialized. " @@ -130,64 +131,62 @@ class IteratorResource : public ResourceBase { // because some of the OpKernels in the graph might call functions that are // only defined in the loaded GraphDef. FunctionLibraryRuntime* lib; - std::unique_ptr device_mgr(nullptr); std::unique_ptr flib_def(nullptr); std::unique_ptr pflr(nullptr); TF_RETURN_IF_ERROR(ctx->function_library()->Clone(&flib_def, &pflr, &lib)); TF_RETURN_IF_ERROR(flib_def->AddLibrary(graph_def.library())); + std::unique_ptr new_state( + new State(std::move(flib_def), std::move(pflr), lib, nullptr)); TF_RETURN_IF_ERROR( - graph_runner.Run(&graph, lib, {}, {output_node}, &outputs)); + graph_runner.Run(&graph, new_state->lib, {}, {output_node}, &outputs)); TF_RETURN_IF_ERROR(GetDatasetFromVariantTensor(outputs[0], &dataset)); - std::unique_ptr iterator; - { - IteratorContext::Params params(ctx); - params.lib = lib; - TF_RETURN_IF_ERROR(dataset->MakeIterator( - IteratorContext(std::move(params)), "Iterator", &iterator)); - } - TF_RETURN_IF_ERROR( - VerifyTypesMatch(output_dtypes_, iterator->output_dtypes())); + IteratorContext::Params params(ctx); + params.lib = new_state->lib; + params.function_handle_cache = new_state->function_handle_cache.get(); + TF_RETURN_IF_ERROR(dataset->MakeIterator(IteratorContext(std::move(params)), + "Iterator", &new_state->iterator)); TF_RETURN_IF_ERROR( - VerifyShapesCompatible(output_shapes_, iterator->output_shapes())); + VerifyTypesMatch(output_dtypes_, new_state->iterator->output_dtypes())); + TF_RETURN_IF_ERROR(VerifyShapesCompatible( + output_shapes_, new_state->iterator->output_shapes())); { IteratorContext::Params params(ctx); - params.lib = lib; - DeviceBase* device = lib->device(); + params.lib = new_state->lib; + params.function_handle_cache = new_state->function_handle_cache.get(); + DeviceBase* device = new_state->lib->device(); params.allocator_getter = [device](AllocatorAttributes attrs) { return device->GetAllocator(attrs); }; IteratorContext iter_ctx(std::move(params)); - TF_RETURN_IF_ERROR(iterator->Restore(&iter_ctx, reader)); - } - - std::shared_ptr old_iterator; - { - mutex_lock l(mu_); - std::swap(device_mgr_, device_mgr); - std::swap(flib_def_, flib_def); - std::swap(pflr_, pflr); - lib_ = lib; - old_iterator = iterator_; - iterator_ = std::move(iterator); + TF_RETURN_IF_ERROR(new_state->iterator->Restore(&iter_ctx, reader)); } + mutex_lock l(mu_); + iterator_state_ = std::move(new_state); return Status::OK(); } Status AddLibrary(const FunctionLibraryDefinition& flib_def) { mutex_lock l(mu_); - return flib_def_->AddLibrary(flib_def); + return iterator_state_->flib_def->AddLibrary(flib_def); } Status SetIteratorFromDataset(OpKernelContext* ctx, DatasetBase* dataset) { - mutex_lock l(mu_); + std::shared_ptr new_state; + { + tf_shared_lock l(mu_); + new_state.reset(new State(iterator_state_->flib_def, + iterator_state_->pflr, iterator_state_->lib, + nullptr, nullptr)); + } + // Ensure that the iterator has access to all functions in the current // subgraph, because some functions may have been defined after the resource // was initially created. - Status s = flib_def_->AddLibrary( + Status s = new_state->flib_def->AddLibrary( *ctx->function_library()->GetFunctionLibraryDefinition()); if (!s.ok()) { @@ -196,29 +195,33 @@ class IteratorResource : public ResourceBase { // executing graph. In that case, we create a new function runtime for // this iterator, based on the current `OpKernelContext`, which will have // the functions we need. - iterator_.reset(); FunctionLibraryRuntime* lib; - std::unique_ptr device_mgr(nullptr); std::unique_ptr flib_def(nullptr); std::unique_ptr pflr(nullptr); TF_RETURN_IF_ERROR( ctx->function_library()->Clone(&flib_def, &pflr, &lib)); - std::swap(device_mgr_, device_mgr); - std::swap(flib_def_, flib_def); - std::swap(pflr_, pflr); - lib_ = lib; + new_state->flib_def = std::move(flib_def); + new_state->pflr = std::move(pflr); + new_state->lib = lib; } + new_state->function_handle_cache.reset( + new FunctionHandleCache(new_state->lib)); + // Create new iterator. std::unique_ptr iterator; IteratorContext::Params params(ctx); - params.lib = lib_; + params.lib = new_state->lib; + params.function_handle_cache = new_state->function_handle_cache.get(); TF_RETURN_IF_ERROR(dataset->MakeIterator(IteratorContext(std::move(params)), "Iterator", &iterator)); TF_RETURN_IF_ERROR( VerifyTypesMatch(output_dtypes_, iterator->output_dtypes())); TF_RETURN_IF_ERROR( VerifyShapesCompatible(output_shapes_, iterator->output_shapes())); - iterator_.reset(iterator.release()); + std::swap(new_state->iterator, iterator); + + mutex_lock l(mu_); + std::swap(iterator_state_, new_state); return Status::OK(); } @@ -231,12 +234,37 @@ class IteratorResource : public ResourceBase { } private: + struct State { + State(std::shared_ptr flib_def, + std::shared_ptr pflr, + FunctionLibraryRuntime* lib, std::unique_ptr iterator) + : flib_def(flib_def), + pflr(pflr), + lib(lib), + function_handle_cache(absl::make_unique(lib)), + iterator(std::move(iterator)) {} + + State(std::shared_ptr flib_def, + std::shared_ptr pflr, + FunctionLibraryRuntime* lib, + std::unique_ptr function_handle_cache, + std::unique_ptr iterator) + : flib_def(flib_def), + pflr(pflr), + lib(lib), + function_handle_cache(std::move(function_handle_cache)), + iterator(std::move(iterator)) {} + + std::shared_ptr flib_def; + std::shared_ptr pflr; + FunctionLibraryRuntime* lib = nullptr; // not owned. + std::unique_ptr function_handle_cache; + std::unique_ptr iterator; + }; + mutex mu_; - std::unique_ptr device_mgr_ GUARDED_BY(mu_); - std::unique_ptr flib_def_ GUARDED_BY(mu_); - std::unique_ptr pflr_ GUARDED_BY(mu_); - FunctionLibraryRuntime* lib_ GUARDED_BY(mu_) = nullptr; // not owned. - std::shared_ptr iterator_ GUARDED_BY(mu_); + const std::unique_ptr device_mgr_ GUARDED_BY(mu_); + std::shared_ptr iterator_state_ GUARDED_BY(mu_); const DataTypeVector output_dtypes_; const std::vector output_shapes_; }; @@ -641,10 +669,15 @@ class ToSingleElementOp : public AsyncOpKernel { OP_REQUIRES_OK_ASYNC( ctx, GetDatasetFromVariantTensor(ctx->input(0), &dataset), done); std::unique_ptr iterator; + IteratorContext::Params params(ctx); + std::unique_ptr function_handle_cache( + new FunctionHandleCache(params.lib)); + params.function_handle_cache = function_handle_cache.get(); + IteratorContext iter_ctx(std::move(params)); + OP_REQUIRES_OK_ASYNC( ctx, - dataset->MakeIterator(IteratorContext(ctx), "SingleElementIterator", - &iterator), + dataset->MakeIterator(&iter_ctx, "SingleElementIterator", &iterator), done); // NOTE(jsimsa): We must destroy the iterator before calling `done()`, to @@ -658,8 +691,8 @@ class ToSingleElementOp : public AsyncOpKernel { components.reserve(dataset->output_dtypes().size()); bool end_of_sequence = false; - Status s = raw_iterator->GetNext(IteratorContext(ctx), &components, - &end_of_sequence); + Status s = + raw_iterator->GetNext(&iter_ctx, &components, &end_of_sequence); if (!s.ok()) { ctx->SetStatus(s); return; @@ -674,8 +707,8 @@ class ToSingleElementOp : public AsyncOpKernel { } components.clear(); - Status s2 = raw_iterator->GetNext(IteratorContext(ctx), &components, - &end_of_sequence); + Status s2 = + raw_iterator->GetNext(&iter_ctx, &components, &end_of_sequence); if (!s2.ok()) { ctx->SetStatus(s2); return; @@ -724,8 +757,16 @@ class ReduceDatasetOp : public AsyncOpKernel { use_inter_op_parallelism_, &captured_func), done); - IteratorContext iter_ctx(ctx); - OP_REQUIRES_OK_ASYNC(ctx, captured_func->Instantiate(&iter_ctx), done); + IteratorContext::Params params(ctx); + std::unique_ptr function_handle_cache( + new FunctionHandleCache(params.lib)); + params.function_handle_cache = function_handle_cache.get(); + IteratorContext iter_ctx(std::move(params)); + std::unique_ptr instantiated_captured_func; + OP_REQUIRES_OK_ASYNC( + ctx, + captured_func->Instantiate(&iter_ctx, &instantiated_captured_func), + done); std::unique_ptr iterator; OP_REQUIRES_OK_ASYNC( @@ -759,8 +800,8 @@ class ReduceDatasetOp : public AsyncOpKernel { std::back_inserter(args)); std::vector reduce_func_output; - status = - captured_func->Run(&iter_ctx, std::move(args), &reduce_func_output); + status = instantiated_captured_func->Run(&iter_ctx, std::move(args), + &reduce_func_output); if (!status.ok()) { break; } diff --git a/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc b/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc index 014f37686f..ac001c22b9 100644 --- a/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc +++ b/tensorflow/core/kernels/data/map_and_batch_dataset_op.cc @@ -46,7 +46,8 @@ const int64 kMaxBatchResults = 16; class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { public: using MapAndBatchIteratorFunction = - std::function, + std::function, std::shared_ptr>, StatusCallback)>; explicit MapAndBatchDatasetOp(OpKernelConstruction* ctx) @@ -105,19 +106,20 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { MapAndBatchIteratorFunction map_func; CapturedFunction* raw_captured_func = captured_func.get(); if (indices.empty()) { - map_func = [raw_captured_func]( - IteratorContext* ctx, const string& prefix, - std::vector args, - std::shared_ptr> out_tensors, - StatusCallback done) { - raw_captured_func->RunAsync(ctx, std::move(args), out_tensors.get(), - std::move(done), prefix); + map_func = [](IteratorContext* ctx, + InstantiatedCapturedFunction* instantiated_captured_func, + const string& prefix, std::vector args, + std::shared_ptr> out_tensors, + StatusCallback done) { + instantiated_captured_func->RunAsync( + ctx, std::move(args), out_tensors.get(), std::move(done), prefix); }; } else { std::vector can_move = ComputeMoveVector(indices); map_func = [raw_captured_func, indices, can_move]( - IteratorContext* ctx, const string& prefix, - std::vector args, + IteratorContext* ctx, + InstantiatedCapturedFunction* instantiated_captured_func, + const string& prefix, std::vector args, std::shared_ptr> out_tensors, StatusCallback done) { const std::vector& captured_inputs = @@ -275,7 +277,8 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { } TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } Status GetNextInternal(IteratorContext* ctx, @@ -464,8 +467,9 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { // Apply the map function on `input_element`, storing the result in // `return_values`, and invoking `done` when finished. - map_func_(ctx.get(), prefix(), std::move(input_element), - std::move(return_values), std::move(done)); + map_func_(ctx.get(), instantiated_captured_func_.get(), prefix(), + std::move(input_element), std::move(return_values), + std::move(done)); } Status CopyPartialBatch(Tensor* output, const Tensor& value, @@ -785,6 +789,7 @@ class MapAndBatchDatasetOp : public UnaryDatasetOpKernel { // Identifies the maximum number of batch results to store. int64 max_batch_results_ GUARDED_BY(*mu_); string prefix_end_; + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/map_dataset_op.cc b/tensorflow/core/kernels/data/map_dataset_op.cc index ab20b83298..a4e61e02e2 100644 --- a/tensorflow/core/kernels/data/map_dataset_op.cc +++ b/tensorflow/core/kernels/data/map_dataset_op.cc @@ -30,8 +30,9 @@ namespace { class MapDatasetOp : public UnaryDatasetOpKernel { public: - using MapIteratorFunction = std::function, std::vector*)>; + using MapIteratorFunction = + std::function, std::vector*)>; explicit MapDatasetOp(OpKernelConstruction* ctx) : UnaryDatasetOpKernel(ctx) { OP_REQUIRES_OK(ctx, ctx->GetAttr("f", &func_)); @@ -54,15 +55,18 @@ class MapDatasetOp : public UnaryDatasetOpKernel { MapIteratorFunction map_func; CapturedFunction* raw_captured_func = captured_func.get(); if (indices.empty()) { - map_func = [raw_captured_func](IteratorContext* ctx, - std::vector args, - std::vector* out_tensors) { - return raw_captured_func->Run(ctx, std::move(args), out_tensors); + map_func = [](IteratorContext* ctx, + InstantiatedCapturedFunction* inst_captured_func, + std::vector args, + std::vector* out_tensors) { + return inst_captured_func->Run(ctx, std::move(args), out_tensors); }; } else { std::vector can_move = ComputeMoveVector(indices); map_func = [raw_captured_func, indices, can_move]( - IteratorContext* ctx, std::vector args, + IteratorContext* ctx, + InstantiatedCapturedFunction* inst_captured_func, + std::vector args, std::vector* out_tensors) { const std::vector& captured_inputs = raw_captured_func->captured_inputs(); @@ -177,7 +181,8 @@ class MapDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } Status GetNextInternal(IteratorContext* ctx, @@ -194,7 +199,8 @@ class MapDatasetOp : public UnaryDatasetOpKernel { return Status::OK(); } - Status s = map_func_(ctx, args, out_tensors); + Status s = map_func_(ctx, instantiated_captured_func_.get(), args, + out_tensors); if (errors::IsOutOfRange(s)) { // `f` may deliberately raise `errors::OutOfRange` to indicate // that we should terminate the iteration early. @@ -226,6 +232,7 @@ class MapDatasetOp : public UnaryDatasetOpKernel { private: std::unique_ptr input_impl_; const MapIteratorFunction map_func_; + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/multi_device_iterator_ops.cc b/tensorflow/core/kernels/data/multi_device_iterator_ops.cc index 5268007e3d..a070456414 100644 --- a/tensorflow/core/kernels/data/multi_device_iterator_ops.cc +++ b/tensorflow/core/kernels/data/multi_device_iterator_ops.cc @@ -17,6 +17,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/process_function_library_runtime.h" #include "tensorflow/core/framework/dataset.h" #include "tensorflow/core/framework/function.h" +#include "tensorflow/core/framework/function_handle_cache.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/resource_op_kernel.h" #include "tensorflow/core/kernels/data/dataset_utils.h" @@ -40,18 +41,21 @@ using MultiDeviceIteratorCallback = class MultiDeviceIterator : public ResourceBase { public: - MultiDeviceIterator(const DataTypeVector& output_types, - const std::vector& output_shapes, - const std::vector& devices, - std::unique_ptr flib_def, - std::unique_ptr pflr, - FunctionLibraryRuntime* lib) + MultiDeviceIterator( + const DataTypeVector& output_types, + const std::vector& output_shapes, + const std::vector& devices, + std::unique_ptr flib_def, + std::unique_ptr pflr, + FunctionLibraryRuntime* lib, + std::unique_ptr function_handle_cache) : output_types_(output_types), output_shapes_(output_shapes), devices_(devices), flib_def_(std::move(flib_def)), pflr_(std::move(pflr)), - lib_(lib) { + lib_(lib), + function_handle_cache_(std::move(function_handle_cache)) { DCHECK(lib_ != nullptr); } @@ -93,6 +97,7 @@ class MultiDeviceIterator : public ResourceBase { } else { IteratorContext::Params params(ctx); params.lib = lib_; + params.function_handle_cache = function_handle_cache_.get(); IteratorContext iter_ctx(std::move(params)); tf_shared_lock l(mu_); multi_device_buffer_->GetNextFromShard( @@ -116,6 +121,10 @@ class MultiDeviceIterator : public ResourceBase { return lib_; } + FunctionHandleCache* function_handle_cache() { + return function_handle_cache_.get(); + } + private: // A private class that uses a background thread to keep a per device buffer // full. @@ -340,6 +349,7 @@ class MultiDeviceIterator : public ResourceBase { const std::unique_ptr flib_def_; const std::unique_ptr pflr_; FunctionLibraryRuntime* const lib_ = nullptr; // not owned. + const std::unique_ptr function_handle_cache_; std::shared_ptr lib_def_ GUARDED_BY(mu_); int64 incarnation_id_ GUARDED_BY(mu_) = 0; @@ -383,21 +393,24 @@ class MultiDeviceIteratorHandleOp : public OpKernel { std::unique_ptr pflr(nullptr); OP_REQUIRES_OK(context, context->function_library()->Clone( &flib_def, &pflr, &lib)); + std::unique_ptr function_handle_cache( + new FunctionHandleCache(lib)); ResourceMgr* mgr = context->resource_manager(); OP_REQUIRES_OK(context, cinfo_.Init(mgr, def())); MultiDeviceIterator* resource; - OP_REQUIRES_OK( - context, - mgr->LookupOrCreate( - cinfo_.container(), cinfo_.name(), &resource, - [this, lib, &flib_def, &pflr](MultiDeviceIterator** ret) - EXCLUSIVE_LOCKS_REQUIRED(mu_) { - *ret = new MultiDeviceIterator( - output_types_, output_shapes_, devices_, - std::move(flib_def), std::move(pflr), lib); - return Status::OK(); - })); + OP_REQUIRES_OK(context, + mgr->LookupOrCreate( + cinfo_.container(), cinfo_.name(), &resource, + [this, lib, &flib_def, &pflr, + &function_handle_cache](MultiDeviceIterator** ret) + EXCLUSIVE_LOCKS_REQUIRED(mu_) { + *ret = new MultiDeviceIterator( + output_types_, output_shapes_, devices_, + std::move(flib_def), std::move(pflr), lib, + std::move(function_handle_cache)); + return Status::OK(); + })); Status s = VerifyResource(resource); if (TF_PREDICT_FALSE(!s.ok())) { @@ -463,6 +476,7 @@ class MultiDeviceIteratorInitOp : public OpKernel { std::unique_ptr iterator; IteratorContext::Params params(ctx); params.lib = resource->lib(); + params.function_handle_cache = resource->function_handle_cache(); IteratorContext iter_ctx(std::move(params)); OP_REQUIRES_OK( ctx, dataset->MakeIterator(std::move(iter_ctx), "Iterator", &iterator)); diff --git a/tensorflow/core/kernels/data/optimize_dataset_op.cc b/tensorflow/core/kernels/data/optimize_dataset_op.cc index f5bb35d360..cac6c43565 100644 --- a/tensorflow/core/kernels/data/optimize_dataset_op.cc +++ b/tensorflow/core/kernels/data/optimize_dataset_op.cc @@ -19,6 +19,7 @@ limitations under the License. #include "tensorflow/core/common_runtime/process_function_library_runtime.h" #include "tensorflow/core/framework/dataset.h" #include "tensorflow/core/framework/device_base.h" +#include "tensorflow/core/framework/function_handle_cache.h" #include "tensorflow/core/framework/partial_tensor_shape.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/graph/graph_constructor.h" @@ -124,6 +125,9 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { TF_RETURN_IF_ERROR( ctx->function_library()->Clone(&flib_def_, &pflr_, &lib_)); + // Create a FunctionHandleCache. + function_handle_cache_.reset(new FunctionHandleCache(lib_)); + // Some functions may have been modified without having their names // changed (for example, nested dataset graphs from FlatMap or // Interleave). To avoid name conflicts, we remove these functions from @@ -176,6 +180,7 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { IteratorContext::Params params(ctx); params.lib = dataset()->lib_; + params.function_handle_cache = dataset()->function_handle_cache_.get(); return dataset()->optimized_input_->MakeIterator( IteratorContext(std::move(params)), prefix(), &input_impl_); } @@ -185,6 +190,7 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { bool* end_of_sequence) override { IteratorContext::Params params(ctx); params.lib = dataset()->lib_; + params.function_handle_cache = dataset()->function_handle_cache_.get(); return input_impl_->GetNext(IteratorContext(std::move(params)), out_tensors, end_of_sequence); } @@ -284,6 +290,7 @@ class OptimizeDatasetOp : public UnaryDatasetOpKernel { FunctionLibraryRuntime* lib_ = nullptr; std::unique_ptr pflr_ = nullptr; std::unique_ptr flib_def_ = nullptr; + std::unique_ptr function_handle_cache_ = nullptr; const DatasetBase* input_; const std::vector optimizations_; const DataTypeVector output_types_; diff --git a/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc b/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc index 23e6adc57a..b5a1679082 100644 --- a/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc +++ b/tensorflow/core/kernels/data/parallel_interleave_dataset_op.cc @@ -249,7 +249,8 @@ class ParallelInterleaveDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } // It is implemented so that it matches the deterministic interleave @@ -693,7 +694,7 @@ class ParallelInterleaveDatasetOp : public UnaryDatasetOpKernel { worker_thread_states_[thread_index].iterator_creation_status = MakeIteratorFromInputElement( ctx.get(), worker_thread_states_[thread_index].input, - thread_index, dataset()->captured_func_.get(), prefix(), + thread_index, *instantiated_captured_func_, prefix(), &worker_thread_states_[thread_index].iterator); iterator_creation_status = worker_thread_states_[thread_index].iterator_creation_status; @@ -927,7 +928,7 @@ class ParallelInterleaveDatasetOp : public UnaryDatasetOpKernel { std::unique_ptr iterator; Status s = MakeIteratorFromInputElement( ctx, worker_thread_states_[index].input, index, - dataset()->captured_func_.get(), prefix(), &iterator); + *instantiated_captured_func_, prefix(), &iterator); TF_RETURN_IF_ERROR(RestoreInput(ctx, reader, iterator)); worker_thread_states_[index].iterator.swap(iterator); } @@ -1032,6 +1033,8 @@ class ParallelInterleaveDatasetOp : public UnaryDatasetOpKernel { // input_impl_ is reset when we have exhausted its input. std::unique_ptr input_impl_ GUARDED_BY(mu_); + std::unique_ptr instantiated_captured_func_; + // The WorkerState structs the worker threads operate on. // workers_ elements are in at most one of interleave_ and staging_. std::vector workers_ GUARDED_BY(mu_); @@ -1268,7 +1271,8 @@ class ParallelInterleaveDatasetV2Op : public UnaryDatasetOpKernel { } TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } Status GetNextInternal(IteratorContext* ctx, @@ -1511,7 +1515,7 @@ class ParallelInterleaveDatasetV2Op : public UnaryDatasetOpKernel { if (!end_of_input_) { Status status = MakeIteratorFromInputElement( ctx.get(), args_list_[cycle_index_], cycle_index_, - dataset()->captured_func_.get(), prefix(), + *instantiated_captured_func_, prefix(), ¤t_elements_[cycle_index_]); if (!status.ok()) { invocation_results_.emplace_back(new InvocationResult()); @@ -1658,7 +1662,7 @@ class ParallelInterleaveDatasetV2Op : public UnaryDatasetOpKernel { &args_list_[idx][i])); } TF_RETURN_IF_ERROR(MakeIteratorFromInputElement( - ctx, args_list_[idx], idx, dataset()->captured_func_.get(), + ctx, args_list_[idx], idx, *instantiated_captured_func_.get(), prefix(), ¤t_elements_[idx])); TF_RETURN_IF_ERROR( RestoreInput(ctx, reader, current_elements_[idx])); @@ -1722,6 +1726,7 @@ class ParallelInterleaveDatasetV2Op : public UnaryDatasetOpKernel { // Identifies whether background activity should be cancelled. bool cancelled_ GUARDED_BY(*mu_) = false; string prefix_end_; + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/parallel_map_dataset_op.cc b/tensorflow/core/kernels/data/parallel_map_dataset_op.cc index 6e4005ff6d..6fe582c9ae 100644 --- a/tensorflow/core/kernels/data/parallel_map_dataset_op.cc +++ b/tensorflow/core/kernels/data/parallel_map_dataset_op.cc @@ -61,52 +61,9 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { std::vector indices; OP_REQUIRES_OK(ctx, ComputeShortCircuitIndices(ctx, func_, &indices)); - ParallelMapIteratorFunction map_func; - CapturedFunction* raw_captured_func = captured_func.get(); - if (indices.empty()) { - map_func = [raw_captured_func](IteratorContext* ctx, const string& prefix, - std::vector args, - std::vector* out_tensors, - StatusCallback done) { - raw_captured_func->RunAsync(ctx, std::move(args), out_tensors, - std::move(done), prefix); - }; - if (!use_inter_op_parallelism_) { - map_func = [map_func](IteratorContext* ctx, const string& prefix, - std::vector args, - std::vector* out_tensors, - StatusCallback done) { - (*ctx->runner())(std::bind(map_func, ctx, prefix, std::move(args), - out_tensors, std::move(done))); - }; - } - } else { - std::vector can_move = ComputeMoveVector(indices); - map_func = [raw_captured_func, indices, can_move]( - IteratorContext* ctx, const string& prefix, - std::vector args, std::vector* out_tensors, - StatusCallback done) { - const std::vector& captured_inputs = - raw_captured_func->captured_inputs(); - size_t num_args = args.size(); - for (size_t i = 0; i < indices.size(); ++i) { - if (indices[i] < num_args) { - if (can_move[i]) { - out_tensors->push_back(std::move(args[indices[i]])); - } else { - out_tensors->push_back(args[indices[i]]); - } - } else { - out_tensors->push_back(captured_inputs[indices[i] - num_args]); - } - } - done(Status::OK()); - }; - } - *output = new Dataset(ctx, input, func_, num_parallel_calls, output_types_, output_shapes_, use_inter_op_parallelism_, sloppy_, - std::move(captured_func), std::move(map_func)); + std::move(captured_func), indices); } private: @@ -118,7 +75,7 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { const std::vector& output_shapes, bool use_inter_op_parallelism, bool sloppy, std::unique_ptr captured_func, - ParallelMapIteratorFunction map_func) + const std::vector indices) : DatasetBase(DatasetContext(ctx)), input_(input), func_(func), @@ -128,7 +85,9 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { use_inter_op_parallelism_(use_inter_op_parallelism), sloppy_(sloppy), captured_func_(std::move(captured_func)), - map_func_(std::move(map_func)) { + indices_(indices), + can_move_(indices.empty() ? std::vector() + : ComputeMoveVector(indices)) { input_->Ref(); } @@ -136,13 +95,15 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { std::unique_ptr MakeIteratorInternal( const string& prefix) const override { - auto init_func = [this](IteratorContext* ctx) { - return captured_func_->Instantiate(ctx); - }; - + std::unique_ptr parallel_map_functor(nullptr); + if (indices_.empty()) { + parallel_map_functor.reset(new ParallelMapDatasetFunctor(this)); + } else { + parallel_map_functor.reset(new ShortCircuitFunctor(this)); + } return NewParallelMapIterator( {this, strings::StrCat(prefix, "::ParallelMap")}, input_, - std::move(init_func), map_func_, num_parallel_calls_, sloppy_); + std::move(parallel_map_functor), num_parallel_calls_, sloppy_); } const DataTypeVector& output_dtypes() const override { @@ -215,6 +176,71 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { } private: + class ShortCircuitFunctor : public ParallelMapFunctor { + public: + explicit ShortCircuitFunctor(const Dataset* dataset) + : dataset_(dataset) {} + + void MapFunc(IteratorContext* ctx, const string& prefix, + std::vector input_element, + std::vector* result, StatusCallback done) override { + const std::vector& captured_inputs = + dataset_->captured_func_->captured_inputs(); + size_t num_args = input_element.size(); + for (size_t i = 0; i < dataset_->indices_.size(); ++i) { + if (dataset_->indices_[i] < num_args) { + if (dataset_->can_move_[i]) { + result->push_back( + std::move(input_element[dataset_->indices_[i]])); + } else { + result->push_back(input_element[dataset_->indices_[i]]); + } + } else { + result->push_back( + captured_inputs[dataset_->indices_[i] - num_args]); + } + } + done(Status::OK()); + } + + const Dataset* const dataset_; + }; + + class ParallelMapDatasetFunctor : public ParallelMapFunctor { + public: + explicit ParallelMapDatasetFunctor(const Dataset* dataset) + : dataset_(dataset) {} + + Status InitFunc(IteratorContext* ctx) override { + return dataset_->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); + } + + void MapFunc(IteratorContext* ctx, const string& prefix, + std::vector input_element, + std::vector* result, StatusCallback done) override { + auto map_func = [this](IteratorContext* ctx, const string& prefix, + std::vector input_element, + std::vector* result, + StatusCallback done) { + instantiated_captured_func_->RunAsync( + ctx, std::move(input_element), result, std::move(done), prefix); + }; + if (!dataset_->use_inter_op_parallelism_) { + (*ctx->runner())(std::bind(map_func, ctx, prefix, + std::move(input_element), result, + std::move(done))); + } else { + map_func(ctx, prefix, std::move(input_element), result, + std::move(done)); + } + } + + private: + const Dataset* const dataset_; + std::unique_ptr instantiated_captured_func_; + }; + const DatasetBase* const input_; const NameAttrList func_; const int32 num_parallel_calls_; @@ -223,7 +249,8 @@ class ParallelMapDatasetOp : public UnaryDatasetOpKernel { const bool use_inter_op_parallelism_; const bool sloppy_; const std::unique_ptr captured_func_; - const ParallelMapIteratorFunction map_func_; + const std::vector indices_; + const std::vector can_move_; }; DataTypeVector output_types_; diff --git a/tensorflow/core/kernels/data/parallel_map_iterator.cc b/tensorflow/core/kernels/data/parallel_map_iterator.cc index 5d6c12ede9..02ccf6b004 100644 --- a/tensorflow/core/kernels/data/parallel_map_iterator.cc +++ b/tensorflow/core/kernels/data/parallel_map_iterator.cc @@ -34,13 +34,11 @@ class ParallelMapIterator : public DatasetBaseIterator { public: ParallelMapIterator(const typename DatasetBaseIterator::BaseParams& params, const DatasetBase* input_dataset, - std::function init_func, - ParallelMapIteratorFunction map_func, + std::unique_ptr parallel_map_functor, int32 num_parallel_calls, bool sloppy) : DatasetBaseIterator(params), input_dataset_(input_dataset), - init_func_(std::move(init_func)), - map_func_(std::move(map_func)), + parallel_map_functor_(std::move(parallel_map_functor)), mu_(std::make_shared()), cond_var_(std::make_shared()), num_parallel_calls_(std::make_shared( @@ -70,10 +68,7 @@ class ParallelMapIterator : public DatasetBaseIterator { } TF_RETURN_IF_ERROR( input_dataset_->MakeIterator(ctx, prefix(), &input_impl_)); - if (init_func_) { - TF_RETURN_IF_ERROR(init_func_(ctx)); - } - return Status::OK(); + return parallel_map_functor_->InitFunc(ctx); } Status GetNextInternal(IteratorContext* ctx, std::vector* out_tensors, @@ -225,8 +220,9 @@ class ParallelMapIterator : public DatasetBaseIterator { // Apply the map function on `input_element`, storing the result in // `result->return_values`, and invoking `done` when finished. - map_func_(ctx.get(), prefix(), std::move(input_element), - &result->return_values, std::move(done)); + parallel_map_functor_->MapFunc(ctx.get(), prefix(), + std::move(input_element), + &result->return_values, std::move(done)); } Status ProcessResult(const std::shared_ptr& result, @@ -360,8 +356,7 @@ class ParallelMapIterator : public DatasetBaseIterator { } const DatasetBase* const input_dataset_; // Not owned. - const std::function init_func_; - const ParallelMapIteratorFunction map_func_; + std::unique_ptr parallel_map_functor_; // Used for coordination between the main thread and the runner thread. const std::shared_ptr mu_; // Used for coordination between the main thread and the runner thread. In @@ -390,12 +385,11 @@ class ParallelMapIterator : public DatasetBaseIterator { std::unique_ptr NewParallelMapIterator( const DatasetBaseIterator::BaseParams& params, const DatasetBase* input_dataset, - std::function init_func, - ParallelMapIteratorFunction map_func, int32 num_parallel_calls, - bool sloppy) { - return MakeUnique( - params, input_dataset, std::move(init_func), std::move(map_func), - num_parallel_calls, sloppy); + std::unique_ptr parallel_map_functor, + int32 num_parallel_calls, bool sloppy) { + return MakeUnique(params, input_dataset, + std::move(parallel_map_functor), + num_parallel_calls, sloppy); } } // namespace data diff --git a/tensorflow/core/kernels/data/parallel_map_iterator.h b/tensorflow/core/kernels/data/parallel_map_iterator.h index d715b9a497..08c16a6c11 100644 --- a/tensorflow/core/kernels/data/parallel_map_iterator.h +++ b/tensorflow/core/kernels/data/parallel_map_iterator.h @@ -22,28 +22,33 @@ limitations under the License. namespace tensorflow { namespace data { -// A function that transforms elements of one dataset into another -// asynchronously. The arguments are: -// 1. An `IteratorContext*` for the context in which the function should -// execute. -// 2. A `std::vector` containing the input element. -// 3. A `std::vector*` to which the function will write the result. -// 4. A `StatusCallback` that should be invoked when the function is complete. -using ParallelMapIteratorFunction = - std::function, - std::vector*, StatusCallback)>; - -// Returns a new iterator that applies `map_func` to the elements of -// `input_dataset` using the given degree of parallelism. `init_func` (if -// specified) will be executed when the iterator is initialized (see -// `IteratorBase::Initialize()`) and enables the user to specify error checking -// logic that can fail early. +class ParallelMapFunctor { + public: + virtual ~ParallelMapFunctor() {} + + // A function that runs when the Iterator is initialized. It enables the user + // to specify error checking logic that can fail early. + virtual Status InitFunc(IteratorContext* ctx) { return Status::OK(); } + + // A function that transforms elements of one dataset into another + // asynchronously. The arguments are: + // 1. An `IteratorContext*` for the context in which the function should + // execute. + // 2. A `std::vector` containing the input element. + // 3. A `std::vector*` to which the function will write the result. + // 4. A `StatusCallback` that should be invoked when the function is complete. + virtual void MapFunc(IteratorContext* ctx, const string& prefix, + std::vector input, std::vector* output, + StatusCallback callback) = 0; +}; + +// Returns a new iterator that uses `parallel_map_functor` to apply `MapFunc` +// to the elements of `input_dataset` using the given degree of parallelism. std::unique_ptr NewParallelMapIterator( const DatasetBaseIterator::BaseParams& params, const DatasetBase* input_dataset, - std::function init_func, - ParallelMapIteratorFunction map_func, int32 num_parallel_calls, - bool sloppy); + std::unique_ptr parallel_map_functor, + int32 num_parallel_calls, bool sloppy); } // namespace data } // namespace tensorflow diff --git a/tensorflow/core/kernels/data/parse_example_dataset_op.cc b/tensorflow/core/kernels/data/parse_example_dataset_op.cc index 608b39d5f5..c4ab4b28df 100644 --- a/tensorflow/core/kernels/data/parse_example_dataset_op.cc +++ b/tensorflow/core/kernels/data/parse_example_dataset_op.cc @@ -183,99 +183,11 @@ class ParseExampleDatasetOp : public UnaryDatasetOpKernel { std::unique_ptr MakeIteratorInternal( const string& prefix) const override { - auto map_fn = [this](IteratorContext* ctx, const string& prefix, - std::vector input_element, - std::vector* result, StatusCallback done) { - (*ctx->runner())([this, ctx, input_element, result, done]() { - thread::ThreadPool* device_threadpool = - ctx->lib()->device()->tensorflow_cpu_worker_threads()->workers; - std::vector slice_vec; - for (const Tensor& t : input_element) { - auto serialized_t = t.flat(); - gtl::ArraySlice slice(serialized_t.data(), - serialized_t.size()); - for (auto it = slice.begin(); it != slice.end(); it++) - slice_vec.push_back(*it); - } - example::FastParseExampleConfig config = config_; - // local copy of config_ for modification. - auto stats_aggregator = ctx->stats_aggregator(); - if (stats_aggregator) { - config.collect_feature_stats = true; - } - example::Result example_result; - Status s = FastParseExample(config, slice_vec, {}, device_threadpool, - &example_result); - if (s.ok()) { - (*result).resize(key_to_output_index_.size()); - for (int d = 0; d < dense_keys_.size(); ++d) { - int output_index = key_to_output_index_.at(dense_keys_[d]); - CHECK(example_result.dense_values[d].dtype() == - output_dtypes()[output_index]) - << "Got wrong type for FastParseExample return value " << d - << " (expected " - << DataTypeString(output_dtypes()[output_index]) << ", got " - << DataTypeString(example_result.dense_values[d].dtype()) - << ")."; - CHECK(output_shapes()[output_index].IsCompatibleWith( - example_result.dense_values[d].shape())) - << "Got wrong shape for FastParseExample return value " << d - << " (expected " - << output_shapes()[output_index].DebugString() << ", got " - << example_result.dense_values[d].shape().DebugString() - << ")."; - (*result)[output_index] = example_result.dense_values[d]; - } - for (int d = 0; d < sparse_keys_.size(); ++d) { - int output_index = key_to_output_index_.at(sparse_keys_[d]); - (*result)[output_index] = - Tensor(ctx->allocator({}), DT_VARIANT, {3}); - Tensor& serialized_sparse = (*result)[output_index]; - auto serialized_sparse_t = serialized_sparse.vec(); - serialized_sparse_t(0) = example_result.sparse_indices[d]; - serialized_sparse_t(1) = example_result.sparse_values[d]; - serialized_sparse_t(2) = example_result.sparse_shapes[d]; - CHECK(serialized_sparse.dtype() == output_dtypes()[output_index]) - << "Got wrong type for FastParseExample return value " << d - << " (expected " - << DataTypeString(output_dtypes()[output_index]) << ", got " - << DataTypeString(serialized_sparse.dtype()) << ")."; - CHECK(output_shapes()[output_index].IsCompatibleWith( - serialized_sparse.shape())) - << "Got wrong shape for FastParseExample return value " << d - << " (expected " - << output_shapes()[output_index].DebugString() << ", got " - << serialized_sparse.shape().DebugString() << ")."; - } - // TODO(b/111553342): User provided tags instead of fixed tag. - if (stats_aggregator) { - stats_aggregator->IncrementCounter( - "examples_count", "trainer", - example_result.feature_stats.size()); - for (example::PerExampleFeatureStats feature_stats : - example_result.feature_stats) { - stats_aggregator->AddToHistogram( - "features", - {static_cast(feature_stats.features_count)}); - stats_aggregator->IncrementCounter( - "features_count", "trainer", feature_stats.features_count); - stats_aggregator->IncrementCounter( - "feature_values_count", "trainer", - feature_stats.feature_values_count); - stats_aggregator->AddToHistogram( - "feature-values", - {static_cast(feature_stats.feature_values_count)}); - } - } - } - done(s); - }); - }; - + std::unique_ptr parse_example_functor( + new ParseExampleFunctor(this)); return NewParallelMapIterator( {this, strings::StrCat(prefix, "::ParseExample")}, input_, - /*init_func=*/nullptr, std::move(map_fn), num_parallel_calls_, - sloppy_); + std::move(parse_example_functor), num_parallel_calls_, sloppy_); } const DataTypeVector& output_dtypes() const override { @@ -341,6 +253,111 @@ class ParseExampleDatasetOp : public UnaryDatasetOpKernel { } private: + class ParseExampleFunctor : public ParallelMapFunctor { + public: + explicit ParseExampleFunctor(const Dataset* dataset) + : dataset_(dataset) {} + + void MapFunc(IteratorContext* ctx, const string& prefix, + std::vector input, std::vector* output, + StatusCallback callback) override { + (*ctx->runner())([this, ctx, input, output, callback]() { + thread::ThreadPool* device_threadpool = + ctx->lib()->device()->tensorflow_cpu_worker_threads()->workers; + std::vector slice_vec; + for (const Tensor& t : input) { + auto serialized_t = t.flat(); + gtl::ArraySlice slice(serialized_t.data(), + serialized_t.size()); + for (auto it = slice.begin(); it != slice.end(); it++) + slice_vec.push_back(*it); + } + example::FastParseExampleConfig config = dataset_->config_; + // local copy of config_ for modification. + auto stats_aggregator = ctx->stats_aggregator(); + if (stats_aggregator) { + config.collect_feature_stats = true; + } + example::Result example_result; + Status s = FastParseExample(config, slice_vec, {}, device_threadpool, + &example_result); + if (s.ok()) { + (*output).resize(dataset_->key_to_output_index_.size()); + for (int d = 0; d < dataset_->dense_keys_.size(); ++d) { + int output_index = + dataset_->key_to_output_index_.at(dataset_->dense_keys_[d]); + DCHECK(example_result.dense_values[d].dtype() == + dataset_->output_dtypes()[output_index]) + << "Got wrong type for FastParseExample return value " << d + << " (expected " + << DataTypeString(dataset_->output_dtypes()[output_index]) + << ", got " + << DataTypeString(example_result.dense_values[d].dtype()) + << ")."; + DCHECK(dataset_->output_shapes()[output_index].IsCompatibleWith( + example_result.dense_values[d].shape())) + << "Got wrong shape for FastParseExample return value " << d + << " (expected " + << dataset_->output_shapes()[output_index].DebugString() + << ", got " + << example_result.dense_values[d].shape().DebugString() + << ")."; + (*output)[output_index] = example_result.dense_values[d]; + } + for (int d = 0; d < dataset_->sparse_keys_.size(); ++d) { + int output_index = + dataset_->key_to_output_index_.at(dataset_->sparse_keys_[d]); + (*output)[output_index] = + Tensor(ctx->allocator({}), DT_VARIANT, {3}); + Tensor& serialized_sparse = (*output)[output_index]; + auto serialized_sparse_t = serialized_sparse.vec(); + serialized_sparse_t(0) = example_result.sparse_indices[d]; + serialized_sparse_t(1) = example_result.sparse_values[d]; + serialized_sparse_t(2) = example_result.sparse_shapes[d]; + DCHECK(serialized_sparse.dtype() == + dataset_->output_dtypes()[output_index]) + << "Got wrong type for FastParseExample return value " << d + << " (expected " + << DataTypeString(dataset_->output_dtypes()[output_index]) + << ", got " << DataTypeString(serialized_sparse.dtype()) + << ")."; + DCHECK(dataset_->output_shapes()[output_index].IsCompatibleWith( + serialized_sparse.shape())) + << "Got wrong shape for FastParseExample return value " << d + << " (expected " + << dataset_->output_shapes()[output_index].DebugString() + << ", got " << serialized_sparse.shape().DebugString() + << ")."; + } + // TODO(b/111553342): User provided tags instead of fixed tag. + if (stats_aggregator) { + stats_aggregator->IncrementCounter( + "examples_count", "trainer", + example_result.feature_stats.size()); + for (example::PerExampleFeatureStats feature_stats : + example_result.feature_stats) { + stats_aggregator->AddToHistogram( + "features", + {static_cast(feature_stats.features_count)}); + stats_aggregator->IncrementCounter( + "features_count", "trainer", feature_stats.features_count); + stats_aggregator->IncrementCounter( + "feature_values_count", "trainer", + feature_stats.feature_values_count); + stats_aggregator->AddToHistogram( + "feature-values", + {static_cast(feature_stats.feature_values_count)}); + } + } + } + callback(s); + }); + } + + private: + const Dataset* dataset_; + }; + const DatasetBase* const input_; const std::vector dense_defaults_; const std::vector sparse_keys_; diff --git a/tensorflow/core/kernels/data/scan_dataset_op.cc b/tensorflow/core/kernels/data/scan_dataset_op.cc index d9182d15be..12d07f1919 100644 --- a/tensorflow/core/kernels/data/scan_dataset_op.cc +++ b/tensorflow/core/kernels/data/scan_dataset_op.cc @@ -143,7 +143,8 @@ class ScanDatasetOp : public UnaryDatasetOpKernel { Status Initialize(IteratorContext* ctx) override { TF_RETURN_IF_ERROR( dataset()->input_->MakeIterator(ctx, prefix(), &input_impl_)); - return dataset()->captured_func_->Instantiate(ctx); + return dataset()->captured_func_->Instantiate( + ctx, &instantiated_captured_func_); } Status GetNextInternal(IteratorContext* ctx, @@ -168,8 +169,8 @@ class ScanDatasetOp : public UnaryDatasetOpKernel { state_and_output.reserve(dataset()->state_types_.size() + output_dtypes().size()); - Status s = dataset()->captured_func_->Run(ctx, std::move(args), - &state_and_output); + Status s = instantiated_captured_func_->Run(ctx, std::move(args), + &state_and_output); if (s.ok()) { state_.clear(); size_t i = 0; @@ -252,6 +253,7 @@ class ScanDatasetOp : public UnaryDatasetOpKernel { mutex mu_; std::unique_ptr input_impl_ GUARDED_BY(mu_); std::vector state_ GUARDED_BY(mu_); + std::unique_ptr instantiated_captured_func_; }; const DatasetBase* const input_; diff --git a/tensorflow/core/kernels/data/writer_ops.cc b/tensorflow/core/kernels/data/writer_ops.cc index 66e759a135..c00089d06f 100644 --- a/tensorflow/core/kernels/data/writer_ops.cc +++ b/tensorflow/core/kernels/data/writer_ops.cc @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/framework/dataset.h" +#include "tensorflow/core/framework/function_handle_cache.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/kernels/data/dataset_utils.h" #include "tensorflow/core/kernels/ops_util.h" @@ -67,20 +68,24 @@ class ToTFRecordOp : public AsyncOpKernel { OP_REQUIRES_OK_ASYNC( ctx, GetDatasetFromVariantTensor(ctx->input(0), &dataset), done); std::unique_ptr iterator; + IteratorContext::Params params(ctx); + std::unique_ptr function_handle_cache( + new FunctionHandleCache(params.lib)); + params.function_handle_cache = function_handle_cache.get(); + IteratorContext iter_ctx(std::move(params)); + OP_REQUIRES_OK_ASYNC( ctx, - dataset->MakeIterator(IteratorContext(ctx), "ToTFRecordOpIterator", - &iterator), + dataset->MakeIterator(&iter_ctx, "ToTFRecordOpIterator", &iterator), done); std::vector components; components.reserve(dataset->output_dtypes().size()); bool end_of_sequence; do { - OP_REQUIRES_OK_ASYNC(ctx, - iterator->GetNext(IteratorContext(ctx), - &components, &end_of_sequence), - done); + OP_REQUIRES_OK_ASYNC( + ctx, iterator->GetNext(&iter_ctx, &components, &end_of_sequence), + done); if (!end_of_sequence) { OP_REQUIRES_OK_ASYNC( -- GitLab From f6e8f7a1fb7c530a98ba93d40dba1f6c859a873b Mon Sep 17 00:00:00 2001 From: Brennan Saeta Date: Thu, 29 Nov 2018 09:53:22 -0800 Subject: [PATCH 539/672] [tf.data]: Deprecate dataset.shard. In preparation for a distributed-aware tf.data system, and TF 2.0, this CL deprecates the legacy `.shard` method on tf.data.Dataset objects. The old behavior is preserved under an experimental `filter_for_shard` dataset transformation, as well as in the V1 API (albeit now marked with a deprecation warning). PiperOrigin-RevId: 223362539 --- .../python/data/experimental/__init__.py | 2 + tensorflow/python/data/experimental/ops/BUILD | 13 ++ .../experimental/ops/filter_for_shard_ops.py | 106 +++++++++++++++ tensorflow/python/data/ops/BUILD | 1 + tensorflow/python/data/ops/dataset_ops.py | 128 ++++++++---------- tensorflow/python/distribute/BUILD | 1 + tensorflow/python/distribute/input_ops.py | 13 +- .../v1/tensorflow.data.experimental.pbtxt | 4 + .../golden/v2/tensorflow.data.-dataset.pbtxt | 4 - ...ow.data.-fixed-length-record-dataset.pbtxt | 4 - .../tensorflow.data.-t-f-record-dataset.pbtxt | 4 - .../tensorflow.data.-text-line-dataset.pbtxt | 4 - ...rflow.data.experimental.-csv-dataset.pbtxt | 4 - ...ow.data.experimental.-random-dataset.pbtxt | 4 - ...rflow.data.experimental.-sql-dataset.pbtxt | 4 - .../v2/tensorflow.data.experimental.pbtxt | 4 + 16 files changed, 194 insertions(+), 106 deletions(-) create mode 100644 tensorflow/python/data/experimental/ops/filter_for_shard_ops.py diff --git a/tensorflow/python/data/experimental/__init__.py b/tensorflow/python/data/experimental/__init__.py index 12aa0a09e1..8cec75b599 100644 --- a/tensorflow/python/data/experimental/__init__.py +++ b/tensorflow/python/data/experimental/__init__.py @@ -39,6 +39,7 @@ See [Importing Data](https://tensorflow.org/guide/datasets) for an overview. @@copy_to_device @@dense_to_sparse_batch @@enumerate_dataset +@@filter_for_shard @@get_next_as_optional @@get_single_element @@group_by_reducer @@ -74,6 +75,7 @@ from tensorflow.python.data.experimental.ops.batching import unbatch from tensorflow.python.data.experimental.ops.counter import Counter from tensorflow.python.data.experimental.ops.enumerate_ops import enumerate_dataset from tensorflow.python.data.experimental.ops.error_ops import ignore_errors +from tensorflow.python.data.experimental.ops.filter_for_shard_ops import filter_for_shard from tensorflow.python.data.experimental.ops.get_single_element import get_single_element from tensorflow.python.data.experimental.ops.grouping import bucket_by_sequence_length from tensorflow.python.data.experimental.ops.grouping import group_by_reducer diff --git a/tensorflow/python/data/experimental/ops/BUILD b/tensorflow/python/data/experimental/ops/BUILD index f9544857a1..f85e774887 100644 --- a/tensorflow/python/data/experimental/ops/BUILD +++ b/tensorflow/python/data/experimental/ops/BUILD @@ -139,6 +139,18 @@ py_library( ], ) +py_library( + name = "filter_for_shard_ops", + srcs = ["filter_for_shard_ops.py"], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow/python:dtypes", + "//tensorflow/python:math_ops", + "//tensorflow/python:ops", + "//tensorflow/python:tensor_util", + ], +) + py_library( name = "error_ops", srcs = ["error_ops.py"], @@ -403,6 +415,7 @@ py_library( ":counter", ":enumerate_ops", ":error_ops", + ":filter_for_shard_ops", ":get_single_element", ":grouping", ":indexed_dataset_ops", diff --git a/tensorflow/python/data/experimental/ops/filter_for_shard_ops.py b/tensorflow/python/data/experimental/ops/filter_for_shard_ops.py new file mode 100644 index 0000000000..91d3dca3e9 --- /dev/null +++ b/tensorflow/python/data/experimental/ops/filter_for_shard_ops.py @@ -0,0 +1,106 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Naive shard dataset transformation.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_util +from tensorflow.python.ops import math_ops +from tensorflow.python.util.tf_export import tf_export + + +@tf_export("data.experimental.filter_for_shard") +def filter_for_shard(num_shards, shard_index): + """Creates a `Dataset` that includes only 1/`num_shards` of this dataset. + + This dataset operator is very useful when running distributed training, as + it allows each worker to read a unique subset. + + When reading a single input file, you can skip elements as follows: + + ```python + d = tf.data.TFRecordDataset(FLAGS.input_file) + d = d.apply(tf.data.experimental.naive_shard(FLAGS.num_workers, + FLAGS.worker_index)) + d = d.repeat(FLAGS.num_epochs) + d = d.shuffle(FLAGS.shuffle_buffer_size) + d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads) + ``` + + Important caveats: + + - Be sure to shard before you use any randomizing operator (such as + shuffle). + - Generally it is best if the shard operator is used early in the dataset + pipeline. For example, when reading from a set of TFRecord files, shard + before converting the dataset to input samples. This avoids reading every + file on every worker. The following is an example of an efficient + sharding strategy within a complete pipeline: + + ```python + d = Dataset.list_files(FLAGS.pattern) + d = d.apply(tf.data.experimental.naive_shard(FLAGS.num_workers, + FLAGS.worker_index)) + d = d.repeat(FLAGS.num_epochs) + d = d.shuffle(FLAGS.shuffle_buffer_size) + d = d.interleave(tf.data.TFRecordDataset, + cycle_length=FLAGS.num_readers, block_length=1) + d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads) + ``` + + Args: + num_shards: A `tf.int64` scalar `tf.Tensor`, representing the number of + shards operating in parallel. + shard_index: A `tf.int64` scalar `tf.Tensor`, representing the worker index. + + Returns: + A `Dataset` transformation function, which can be passed to + `tf.data.Dataset.apply`. + + Raises: + ValueError: if `num_shards` or `shard_index` are illegal values. Note: error + checking is done on a best-effort basis, and errors aren't guaranteed to + be caught upon dataset creation. (e.g. providing in a placeholder tensor + bypasses the early checking, and will instead result in an error during + a session.run call.) + """ + num_shards = ops.convert_to_tensor( + num_shards, name="num_shards", dtype=dtypes.int64) + num_shards_static = tensor_util.constant_value(num_shards) + shard_index = ops.convert_to_tensor(shard_index, name="shard_index", + dtype=dtypes.int64) + shard_index_static = tensor_util.constant_value(shard_index) + + if num_shards_static is not None and num_shards_static < 1: + raise ValueError("num_shards must be >= 1; got: %s" % num_shards_static) + if shard_index_static is not None and shard_index_static < 0: + raise ValueError("shard_index must be >= 0; got: %s" % shard_index_static) + if (shard_index_static is not None and num_shards_static is not None and + shard_index_static >= num_shards_static): + raise ValueError("shard_index must be < num_shards; %s is not < %s" % + (shard_index_static, num_shards_static)) + + def filter_fn(elem_index, _): + mod_result = math_ops.mod(elem_index, num_shards) + return math_ops.equal(mod_result, shard_index) + + def _apply_fn(dataset): + # pylint: disable=protected-access + return dataset._enumerate().filter(filter_fn).map(lambda _, elem: elem) + + return _apply_fn diff --git a/tensorflow/python/data/ops/BUILD b/tensorflow/python/data/ops/BUILD index dcbb0f1868..27c9175ccb 100644 --- a/tensorflow/python/data/ops/BUILD +++ b/tensorflow/python/data/ops/BUILD @@ -26,6 +26,7 @@ py_library( "//tensorflow/python:tensor_shape", "//tensorflow/python:tensor_util", "//tensorflow/python:util", + "//tensorflow/python/data/experimental/ops:filter_for_shard_ops", "//tensorflow/python/data/experimental/ops:stats_options", "//tensorflow/python/data/experimental/ops:threading_options", "//tensorflow/python/data/util:nest", diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 71175fc6a2..51123aaf44 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -26,6 +26,7 @@ import numpy as np import six from tensorflow.python.compat import compat +from tensorflow.python.data.experimental.ops import filter_for_shard_ops from tensorflow.python.data.experimental.ops import stats_options from tensorflow.python.data.experimental.ops import threading_options from tensorflow.python.data.ops import iterator_ops @@ -821,78 +822,6 @@ class DatasetV2(object): """ return SkipDataset(self, count) - def shard(self, num_shards, index): - """Creates a `Dataset` that includes only 1/`num_shards` of this dataset. - - This dataset operator is very useful when running distributed training, as - it allows each worker to read a unique subset. - - When reading a single input file, you can skip elements as follows: - - ```python - d = tf.data.TFRecordDataset(FLAGS.input_file) - d = d.shard(FLAGS.num_workers, FLAGS.worker_index) - d = d.repeat(FLAGS.num_epochs) - d = d.shuffle(FLAGS.shuffle_buffer_size) - d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads) - ``` - - Important caveats: - - - Be sure to shard before you use any randomizing operator (such as - shuffle). - - Generally it is best if the shard operator is used early in the dataset - pipeline. For example, when reading from a set of TFRecord files, shard - before converting the dataset to input samples. This avoids reading every - file on every worker. The following is an example of an efficient - sharding strategy within a complete pipeline: - - ```python - d = Dataset.list_files(FLAGS.pattern) - d = d.shard(FLAGS.num_workers, FLAGS.worker_index) - d = d.repeat(FLAGS.num_epochs) - d = d.shuffle(FLAGS.shuffle_buffer_size) - d = d.interleave(tf.data.TFRecordDataset, - cycle_length=FLAGS.num_readers, block_length=1) - d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads) - ``` - - Args: - num_shards: A `tf.int64` scalar `tf.Tensor`, representing the number of - shards operating in parallel. - index: A `tf.int64` scalar `tf.Tensor`, representing the worker index. - - Returns: - Dataset: A `Dataset`. - - Raises: - ValueError: if `num_shards` or `index` are illegal values. Note: error - checking is done on a best-effort basis, and errors aren't guaranteed - to be caught upon dataset creation. (e.g. providing in a placeholder - tensor bypasses the early checking, and will instead result in an error - during a session.run call.) - """ - num_shards = ops.convert_to_tensor( - num_shards, name="num_shards", dtype=dtypes.int64) - num_shards_static = tensor_util.constant_value(num_shards) - index = ops.convert_to_tensor(index, name="index", dtype=dtypes.int64) - index_static = tensor_util.constant_value(index) - - if num_shards_static is not None and num_shards_static < 1: - raise ValueError("num_shards must be >= 1; got: %s" % num_shards_static) - if index_static is not None and index_static < 0: - raise ValueError("index must be >= 0; got: %s" % index_static) - if (index_static is not None and num_shards_static is not None and - index_static >= num_shards_static): - raise ValueError("index must be <= num_shards; %s is not < %s" % - (index_static, num_shards_static)) - - def filter_fn(elem_index, _): - mod_result = math_ops.mod(elem_index, num_shards) - return math_ops.equal(mod_result, index) - - return self._enumerate().filter(filter_fn).map(lambda _, elem: elem) - def batch(self, batch_size, drop_remainder=False): """Combines consecutive elements of this dataset into batches. @@ -1486,9 +1415,60 @@ class DatasetV1(DatasetV2): def skip(self, count): return DatasetV1Adapter(super(DatasetV1, self).skip(count)) - @functools.wraps(DatasetV2.shard) + @deprecation.deprecated( + None, "Use `dataset.apply(tf.data.experimental.filter_for_shard(...))`.") def shard(self, num_shards, index): - return DatasetV1Adapter(super(DatasetV1, self).shard(num_shards, index)) + """Creates a `Dataset` that includes only 1/`num_shards` of this dataset. + + This dataset operator is very useful when running distributed training, as + it allows each worker to read a unique subset. + + When reading a single input file, you can skip elements as follows: + + ```python + d = tf.data.TFRecordDataset(FLAGS.input_file) + d = d.shard(FLAGS.num_workers, FLAGS.worker_index) + d = d.repeat(FLAGS.num_epochs) + d = d.shuffle(FLAGS.shuffle_buffer_size) + d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads) + ``` + + Important caveats: + + - Be sure to shard before you use any randomizing operator (such as + shuffle). + - Generally it is best if the shard operator is used early in the dataset + pipeline. For example, when reading from a set of TFRecord files, shard + before converting the dataset to input samples. This avoids reading every + file on every worker. The following is an example of an efficient + sharding strategy within a complete pipeline: + + ```python + d = Dataset.list_files(FLAGS.pattern) + d = d.shard(FLAGS.num_workers, FLAGS.worker_index) + d = d.repeat(FLAGS.num_epochs) + d = d.shuffle(FLAGS.shuffle_buffer_size) + d = d.interleave(tf.data.TFRecordDataset, + cycle_length=FLAGS.num_readers, block_length=1) + d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads) + ``` + + Args: + num_shards: A `tf.int64` scalar `tf.Tensor`, representing the number of + shards operating in parallel. + index: A `tf.int64` scalar `tf.Tensor`, representing the worker index. + + Returns: + Dataset: A `Dataset`. + + Raises: + ValueError: if `num_shards` or `index` are illegal values. Note: error + checking is done on a best-effort basis, and errors aren't guaranteed + to be caught upon dataset creation. (e.g. providing in a placeholder + tensor bypasses the early checking, and will instead result in an error + during a session.run call.) + """ + return self.apply(filter_for_shard_ops.filter_for_shard(num_shards, index)) @functools.wraps(DatasetV2.batch) def batch(self, batch_size, drop_remainder=False): diff --git a/tensorflow/python/distribute/BUILD b/tensorflow/python/distribute/BUILD index 5afbcec3a9..ec438d00f0 100644 --- a/tensorflow/python/distribute/BUILD +++ b/tensorflow/python/distribute/BUILD @@ -245,6 +245,7 @@ py_library( srcs = ["input_ops.py"], deps = [ "//tensorflow/python:framework_ops", + "//tensorflow/python/data/experimental/ops:filter_for_shard_ops", "//tensorflow/python/data/util:nest", ], ) diff --git a/tensorflow/python/distribute/input_ops.py b/tensorflow/python/distribute/input_ops.py index c40b2bf27a..d7974942a1 100644 --- a/tensorflow/python/distribute/input_ops.py +++ b/tensorflow/python/distribute/input_ops.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.python.data.experimental.ops import filter_for_shard_ops from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.ops import readers from tensorflow.python.data.util import nest @@ -41,7 +42,8 @@ def auto_shard_dataset(dataset, num_shards, index): dataset: A `tf.data.Dataset` instance, typically the result of a bunch of dataset transformations. num_shards: A `tf.int64` scalar `tf.Tensor`, representing the number of - shards operating in parallel. Same usage as in `Dataset.shard`. + shards operating in parallel. Same usage as in + `tf.data.experimental.filter_for_shard`. index: A `tf.int64` scalar `tf.Tensor`, representing the worker index. Same usage as in `Dataset.shard`. @@ -74,9 +76,11 @@ def auto_shard_dataset(dataset, num_shards, index): # constructor. Eventually we will change all cases to clone datasets # instead of updating in-place. return dataset._clone( - filenames=dataset._filenames.shard(num_shards, index)) + filenames=dataset._filenames.apply( + filter_for_shard_ops.filter_for_shard(num_shards, index))) elif isinstance(dataset, dataset_ops.RangeDataset): - return dataset.shard(num_shards, index) + return dataset.apply( + filter_for_shard_ops.filter_for_shard(num_shards, index)) elif hasattr(dataset, "_map_func"): # TODO(priyag): Make this check more robust by enforcing some common # property on all map/flatmap/interleave datasets. @@ -142,6 +146,7 @@ def auto_shard_dataset(dataset, num_shards, index): # TODO(priyag): This will shard the filenames before any shuffling of the # filename dataset. It might be desirable to shard after shuffling # filenames? If so, how do we achieve that? - return dataset.shard(num_shards, index) + return dataset.apply( + filter_for_shard_ops.filter_for_shard(num_shards, index)) return _auto_shard_impl(dataset=dataset, found_reader_op=False) diff --git a/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt index 7bc3faaedc..a3cb799fc3 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.data.experimental.pbtxt @@ -68,6 +68,10 @@ tf_module { name: "enumerate_dataset" argspec: "args=[\'start\'], varargs=None, keywords=None, defaults=[\'0\'], " } + member_method { + name: "filter_for_shard" + argspec: "args=[\'num_shards\', \'shard_index\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "get_next_as_optional" argspec: "args=[\'iterator\'], varargs=None, keywords=None, defaults=None" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.-dataset.pbtxt index 9394f4b767..39a6e1ee71 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.-dataset.pbtxt @@ -97,10 +97,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.-fixed-length-record-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.-fixed-length-record-dataset.pbtxt index 8c32c773b7..ef367238d0 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.-fixed-length-record-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.-fixed-length-record-dataset.pbtxt @@ -100,10 +100,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.-t-f-record-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.-t-f-record-dataset.pbtxt index 9f32bce109..a8fc6fbec1 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.-t-f-record-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.-t-f-record-dataset.pbtxt @@ -99,10 +99,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.-text-line-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.-text-line-dataset.pbtxt index 0eedfdbfe1..697f371344 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.-text-line-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.-text-line-dataset.pbtxt @@ -100,10 +100,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-csv-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-csv-dataset.pbtxt index 08214ec3cf..17ac098910 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-csv-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-csv-dataset.pbtxt @@ -100,10 +100,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-random-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-random-dataset.pbtxt index 608253298e..f005d36e1a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-random-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-random-dataset.pbtxt @@ -100,10 +100,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-sql-dataset.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-sql-dataset.pbtxt index 3335eb1dc7..b0c0b73ad6 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-sql-dataset.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.-sql-dataset.pbtxt @@ -100,10 +100,6 @@ tf_class { name: "repeat" argspec: "args=[\'self\', \'count\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "shard" - argspec: "args=[\'self\', \'num_shards\', \'index\'], varargs=None, keywords=None, defaults=None" - } member_method { name: "shuffle" argspec: "args=[\'self\', \'buffer_size\', \'seed\', \'reshuffle_each_iteration\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " diff --git a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt index 7bc3faaedc..a3cb799fc3 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.data.experimental.pbtxt @@ -68,6 +68,10 @@ tf_module { name: "enumerate_dataset" argspec: "args=[\'start\'], varargs=None, keywords=None, defaults=[\'0\'], " } + member_method { + name: "filter_for_shard" + argspec: "args=[\'num_shards\', \'shard_index\'], varargs=None, keywords=None, defaults=None" + } member_method { name: "get_next_as_optional" argspec: "args=[\'iterator\'], varargs=None, keywords=None, defaults=None" -- GitLab From bfec75923018512a782fc8405de1d61857edcc94 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Thu, 29 Nov 2018 10:02:50 -0800 Subject: [PATCH 540/672] Test that all outputs of the converter are in the v2 API. Fixes issue where piecewise_constant was a warning only despite not being a part of the v2 API. PiperOrigin-RevId: 223364226 --- tensorflow/tools/compatibility/BUILD | 3 + tensorflow/tools/compatibility/renames_v2.py | 6 +- .../tools/compatibility/tf_upgrade_v2.py | 6 +- .../tools/compatibility/tf_upgrade_v2_test.py | 65 ++++++++++++++++++- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/tensorflow/tools/compatibility/BUILD b/tensorflow/tools/compatibility/BUILD index 197fa75015..152a79f542 100644 --- a/tensorflow/tools/compatibility/BUILD +++ b/tensorflow/tools/compatibility/BUILD @@ -78,8 +78,11 @@ py_test( srcs_version = "PY2AND3", deps = [ ":tf_upgrade_v2", + "//tensorflow:tensorflow_py", "//tensorflow/python:client_testlib", "//tensorflow/python:framework_test_lib", + "//tensorflow/tools/common:public_api", + "//tensorflow/tools/common:traverse", "@six_archive//:six", ], ) diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index ae57478473..ba93cbbfa9 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -97,6 +97,7 @@ renames = { 'tf.check_numerics': 'tf.debugging.check_numerics', 'tf.cholesky': 'tf.linalg.cholesky', 'tf.cholesky_solve': 'tf.linalg.cholesky_solve', + 'tf.clip_by_average_norm': 'tf.compat.v1.clip_by_average_norm', 'tf.colocate_with': 'tf.compat.v1.colocate_with', 'tf.conj': 'tf.math.conj', 'tf.container': 'tf.compat.v1.container', @@ -107,7 +108,6 @@ renames = { 'tf.create_partitioned_variables': 'tf.compat.v1.create_partitioned_variables', 'tf.cross': 'tf.linalg.cross', 'tf.cumprod': 'tf.math.cumprod', - 'tf.data.Iterator': 'tf.compat.v1.data.Iterator', 'tf.debugging.is_finite': 'tf.math.is_finite', 'tf.debugging.is_inf': 'tf.math.is_inf', 'tf.debugging.is_nan': 'tf.math.is_nan', @@ -358,7 +358,6 @@ renames = { 'tf.nn.depthwise_conv2d_native_backprop_filter': 'tf.nn.depthwise_conv2d_backprop_filter', 'tf.nn.depthwise_conv2d_native_backprop_input': 'tf.nn.depthwise_conv2d_backprop_input', 'tf.nn.dynamic_rnn': 'tf.compat.v1.nn.dynamic_rnn', - 'tf.nn.fused_batch_norm': 'tf.compat.v1.nn.fused_batch_norm', 'tf.nn.log_uniform_candidate_sampler': 'tf.random.log_uniform_candidate_sampler', 'tf.nn.quantized_avg_pool': 'tf.compat.v1.nn.quantized_avg_pool', 'tf.nn.quantized_conv2d': 'tf.compat.v1.nn.quantized_conv2d', @@ -427,13 +426,14 @@ renames = { 'tf.rsqrt': 'tf.math.rsqrt', 'tf.saved_model.Builder': 'tf.compat.v1.saved_model.Builder', 'tf.saved_model.LEGACY_INIT_OP_KEY': 'tf.compat.v1.saved_model.LEGACY_INIT_OP_KEY', + 'tf.saved_model.MAIN_OP_KEY': 'tf.compat.v1.saved_model.MAIN_OP_KEY', 'tf.saved_model.TRAINING': 'tf.saved_model.TRANING', 'tf.saved_model.build_tensor_info': 'tf.compat.v1.saved_model.build_tensor_info', 'tf.saved_model.builder.SavedModelBuilder': 'tf.compat.v1.saved_model.builder.SavedModelBuilder', 'tf.saved_model.constants.ASSETS_DIRECTORY': 'tf.saved_model.ASSETS_DIRECTORY', 'tf.saved_model.constants.ASSETS_KEY': 'tf.saved_model.ASSETS_KEY', 'tf.saved_model.constants.LEGACY_INIT_OP_KEY': 'tf.compat.v1.saved_model.constants.LEGACY_INIT_OP_KEY', - 'tf.saved_model.constants.MAIN_OP_KEY': 'tf.saved_model.MAIN_OP_KEY', + 'tf.saved_model.constants.MAIN_OP_KEY': 'tf.compat.v1.saved_model.constants.MAIN_OP_KEY', 'tf.saved_model.constants.SAVED_MODEL_FILENAME_PB': 'tf.saved_model.SAVED_MODEL_FILENAME_PB', 'tf.saved_model.constants.SAVED_MODEL_FILENAME_PBTXT': 'tf.saved_model.SAVED_MODEL_FILENAME_PBTXT', 'tf.saved_model.constants.SAVED_MODEL_SCHEMA_VERSION': 'tf.saved_model.SAVED_MODEL_SCHEMA_VERSION', diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2.py b/tensorflow/tools/compatibility/tf_upgrade_v2.py index 242bbbc3a7..f8c1f4111f 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2.py @@ -433,6 +433,10 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): "tf.math.confusion_matrix", "tf.decode_csv": "tf.io.decode_csv", + "tf.data.Iterator": + "tf.compat.v1.data.Iterator", + "tf.nn.fused_batch_norm": + "tf.compat.v1.nn.fused_batch_norm", } # pylint: enable=line-too-long @@ -681,7 +685,7 @@ class TFAPIChangeSpec(ast_edits.APIChangeSpec): " module if you need command line parsing.", "tf.train.exponential_decay": decay_function_comment, - "tf.train.piecewise_constant": + "tf.train.piecewise_constant_decay": decay_function_comment, "tf.train.polynomial_decay": decay_function_comment, diff --git a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py index c490ebd480..9c334451bf 100644 --- a/tensorflow/tools/compatibility/tf_upgrade_v2_test.py +++ b/tensorflow/tools/compatibility/tf_upgrade_v2_test.py @@ -17,11 +17,21 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function + import os import tempfile + import six +import tensorflow as tf +# OSS TF V2 import placeholder. + + from tensorflow.python.framework import test_util from tensorflow.python.platform import test as test_lib +from tensorflow.python.util import tf_decorator +from tensorflow.python.util import tf_export +from tensorflow.tools.common import public_api +from tensorflow.tools.common import traverse from tensorflow.tools.compatibility import ast_edits from tensorflow.tools.compatibility import tf_upgrade_v2 @@ -64,6 +74,51 @@ class TestUpgrade(test_util.TensorFlowTestCase): _, unused_report, unused_errors, new_text = self._upgrade(text) self.assertEqual(new_text, "tf.math.rsqrt(tf.math.log_sigmoid(3.8))\n") + def testAllAPI(self): + if not hasattr(tf.compat, "v2"): + return + + v2_symbols = set([]) + attr_v2 = tf_export.API_ATTRS[ + tf_export.TENSORFLOW_API_NAME].names + + def symbol_collector(unused_path, unused_parent, children): + for child in children: + _, attr = tf_decorator.unwrap(child[1]) + if not hasattr(attr, "__dict__"): + continue + api_names_v2 = attr.__dict__.get(attr_v2, []) + for name in api_names_v2: + v2_symbols.add("tf." + name) + + visitor = public_api.PublicAPIVisitor(symbol_collector) + traverse.traverse(tf.compat.v2, visitor) + + attr_v1 = ( + tf_export.API_ATTRS_V1[tf_export.TENSORFLOW_API_NAME].names) + + # Converts all symbols in the v1 namespace to the v2 namespace, raising + # an error if the target of the conversion is not in the v2 namespace. + def conversion_visitor(unused_path, unused_parent, children): + for child in children: + _, attr = tf_decorator.unwrap(child[1]) + if not hasattr(attr, "__dict__"): + continue + api_names = attr.__dict__.get(attr_v1, []) + for name in api_names: + _, _, _, text = self._upgrade("tf." + name) + if (text and + not text.startswith("tf.compat.v1") and + text not in v2_symbols): + self.assertFalse( + True, "Symbol %s generated from %s not in v2 API" % ( + text, name)) + + visitor = public_api.PublicAPIVisitor(conversion_visitor) + visitor.do_not_descend_map["tf"].append("contrib") + visitor.private_map["tf.compat"] = ["v1", "v2"] + traverse.traverse(tf.compat.v1, visitor) + def testRenameConstant(self): text = "tf.MONOLITHIC_BUILD\n" _, unused_report, unused_errors, new_text = self._upgrade(text) @@ -89,7 +144,7 @@ class TestUpgrade(test_util.TensorFlowTestCase): "tf.boolean_mask(tensor=a, mask=b, name=c, axis=d)\n") def testLearningRateDecay(self): - for decay in ["tf.train.exponential_decay", "tf.train.piecewise_constant", + for decay in ["tf.train.exponential_decay", "tf.train.polynomial_decay", "tf.train.natural_exp_decay", "tf.train.inverse_time_decay", "tf.train.cosine_decay", "tf.train.cosine_decay_restarts", @@ -101,6 +156,14 @@ class TestUpgrade(test_util.TensorFlowTestCase): self.assertEqual(errors, ["test.py:1: %s requires manual check." % decay]) self.assertIn("%s has been changed" % decay, report) + def testPiecewiseDecay(self): + text = "tf.train.piecewise_constant_decay(a, b)\n" + _, report, errors, _ = self._upgrade(text) + self.assertEqual( + errors, + ["test.py:1: tf.train.piecewise_constant_decay requires manual check."]) + self.assertIn("tf.train.piecewise_constant_decay has been changed", report) + def testEstimatorLossReductionChange(self): classes = [ "LinearClassifier", "LinearRegressor", "DNNLinearCombinedClassifier", -- GitLab From 51d694e20b5593d98514878af859a34bb39454b2 Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Thu, 29 Nov 2018 10:16:10 -0800 Subject: [PATCH 541/672] Add publicly available corpus for string_split_v2 fuzz. PiperOrigin-RevId: 223366651 --- tensorflow/core/kernels/fuzzing/BUILD | 4 ++++ .../00fd47bf73afcb72e7ed51bffd5f5fec | 1 + .../14908973e6720513a5f37676cb9fcc29 | 1 + .../2779ba7c4d23eee9f79efa3660084c5d | 1 + .../5bf16424630b5afbcffe711fb9834440 | 1 + .../89734a96b93275e495a9498b806fafe1 | 1 + .../d5606def44fdbb9385dd764612069db0 | Bin 0 -> 42 bytes 7 files changed, 9 insertions(+) create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split_v2/00fd47bf73afcb72e7ed51bffd5f5fec create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split_v2/14908973e6720513a5f37676cb9fcc29 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split_v2/2779ba7c4d23eee9f79efa3660084c5d create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split_v2/5bf16424630b5afbcffe711fb9834440 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split_v2/89734a96b93275e495a9498b806fafe1 create mode 100644 tensorflow/core/kernels/fuzzing/corpus/string_split_v2/d5606def44fdbb9385dd764612069db0 diff --git a/tensorflow/core/kernels/fuzzing/BUILD b/tensorflow/core/kernels/fuzzing/BUILD index 193041241c..7d59beb09b 100644 --- a/tensorflow/core/kernels/fuzzing/BUILD +++ b/tensorflow/core/kernels/fuzzing/BUILD @@ -28,8 +28,12 @@ tf_oss_fuzz_corpus("string_to_number") tf_ops_fuzz_target_lib("string_split") +tf_oss_fuzz_corpus("string_split") + tf_ops_fuzz_target_lib("string_split_v2") +tf_oss_fuzz_corpus("string_split_v2") + tf_ops_fuzz_target_lib("encode_base64") tf_ops_fuzz_target_lib("decode_base64") diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/00fd47bf73afcb72e7ed51bffd5f5fec b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/00fd47bf73afcb72e7ed51bffd5f5fec new file mode 100644 index 0000000000..f1410e184b --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/00fd47bf73afcb72e7ed51bffd5f5fec @@ -0,0 +1 @@ +./abc./de./fg./ha./bc./de./fg./ha./bc./de./ \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/14908973e6720513a5f37676cb9fcc29 b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/14908973e6720513a5f37676cb9fcc29 new file mode 100644 index 0000000000..e118d2d351 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/14908973e6720513a5f37676cb9fcc29 @@ -0,0 +1 @@ +./, abcde./, fg./, ha./, bc./, de./, fg./, ha \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/2779ba7c4d23eee9f79efa3660084c5d b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/2779ba7c4d23eee9f79efa3660084c5d new file mode 100644 index 0000000000..9a6c809197 --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/2779ba7c4d23eee9f79efa3660084c5d @@ -0,0 +1 @@ +./,abcd./,ef./,gh./,ab./,cd./,ef./,gh./,ab./ \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/5bf16424630b5afbcffe711fb9834440 b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/5bf16424630b5afbcffe711fb9834440 new file mode 100644 index 0000000000..4cd522da7b --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/5bf16424630b5afbcffe711fb9834440 @@ -0,0 +1 @@ +.ab.cd.ef.gh.ab.cd.ef.gh.ab.cd.ef.gh.ab.cd \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/89734a96b93275e495a9498b806fafe1 b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/89734a96b93275e495a9498b806fafe1 new file mode 100644 index 0000000000..5301a91d8e --- /dev/null +++ b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/89734a96b93275e495a9498b806fafe1 @@ -0,0 +1 @@ +./, ?abcdef./, ?gh./, ?ab./, ?cd./, ?ef./, ?gh \ No newline at end of file diff --git a/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/d5606def44fdbb9385dd764612069db0 b/tensorflow/core/kernels/fuzzing/corpus/string_split_v2/d5606def44fdbb9385dd764612069db0 new file mode 100644 index 0000000000000000000000000000000000000000..304b0d66fe08fd1a29827488727702dd9b9bce3e GIT binary patch literal 42 ScmZQbOiE5kO-s)pNCN;-W)Kzt literal 0 HcmV?d00001 -- GitLab From d2253ab51816bd3c536a7574fff5e6b705a801a8 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 10:16:39 -0800 Subject: [PATCH 542/672] Adding more checks for categorical splits. PiperOrigin-RevId: 223366746 --- .../boosted_trees/kernels/split_handler_ops.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/boosted_trees/kernels/split_handler_ops.cc b/tensorflow/contrib/boosted_trees/kernels/split_handler_ops.cc index 8edb5d6c64..6d78e27e8f 100644 --- a/tensorflow/contrib/boosted_trees/kernels/split_handler_ops.cc +++ b/tensorflow/contrib/boosted_trees/kernels/split_handler_ops.cc @@ -834,8 +834,13 @@ class BuildCategoricalEqualitySplitsOp : public OpKernel { root_gradient_stats *= normalizer_ratio; NodeStats root_stats = state->ComputeNodeStats(root_gradient_stats); int32 best_feature_idx = 0; + bool best_feature_updated = false; NodeStats best_right_node_stats(0); NodeStats best_left_node_stats(0); + CHECK(end_index - start_index >= 2) + << "Partition should have a non bias feature. Start index " + << start_index << " and end index " << end_index; + for (int64 feature_idx = start_index + 1; feature_idx < end_index; ++feature_idx) { GradientStats left_gradient_stats(*gradients_t, *hessians_t, @@ -845,11 +850,13 @@ class BuildCategoricalEqualitySplitsOp : public OpKernel { root_gradient_stats - left_gradient_stats; NodeStats left_stats = state->ComputeNodeStats(left_gradient_stats); NodeStats right_stats = state->ComputeNodeStats(right_gradient_stats); - if (left_stats.gain + right_stats.gain > best_gain) { + if (!best_feature_updated || + left_stats.gain + right_stats.gain > best_gain) { best_gain = left_stats.gain + right_stats.gain; best_left_node_stats = left_stats; best_right_node_stats = right_stats; best_feature_idx = feature_idx; + best_feature_updated = true; } } SplitInfo split_info; @@ -864,7 +871,7 @@ class BuildCategoricalEqualitySplitsOp : public OpKernel { << feature_ids(best_feature_idx, 0) << ", " << feature_ids(best_feature_idx, 1) << "\nPartition IDS: " << partition_ids(start_index) << " " - << partition_ids(best_feature_idx); + << partition_ids(best_feature_idx) << " and best gain " << best_gain; equality_split->set_feature_id(feature_ids(best_feature_idx, 0)); auto* left_child = split_info.mutable_left_child(); auto* right_child = split_info.mutable_right_child(); -- GitLab From 2b559a9a086f7e8e79557c642c6d4f5115f855c5 Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Thu, 29 Nov 2018 10:21:35 -0800 Subject: [PATCH 543/672] Improves constant shape inference for resource variables. PiperOrigin-RevId: 223367586 --- .../kernel_tests/resource_variable_ops_test.py | 9 +++++++++ tensorflow/python/ops/resource_variable_ops.py | 14 +++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tensorflow/python/kernel_tests/resource_variable_ops_test.py b/tensorflow/python/kernel_tests/resource_variable_ops_test.py index 30563092c8..d30ab6a9c2 100644 --- a/tensorflow/python/kernel_tests/resource_variable_ops_test.py +++ b/tensorflow/python/kernel_tests/resource_variable_ops_test.py @@ -29,6 +29,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_util from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops @@ -137,6 +138,14 @@ class ResourceVariableOpsTest(test_util.TensorFlowTestCase): self.evaluate(v[0].assign(2.0)) self.assertAllEqual(self.evaluate(v), [2.0, 2.0]) + @test_util.run_in_graph_and_eager_modes + def testVariableShape(self): + v = resource_variable_ops.ResourceVariable([1., 1.]) + self.assertAllEqual( + tensor_util.constant_value( + resource_variable_ops.variable_shape(v.handle)), + [2]) + def testDifferentAssignGraph(self): with ops.Graph().as_default(): v = resource_variable_ops.ResourceVariable(1.0) diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index 5c74dffb05..1066b357b4 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -26,6 +26,7 @@ from tensorflow.core.framework import variable_pb2 from tensorflow.python import pywrap_tensorflow from tensorflow.python.eager import context from tensorflow.python.eager import tape +from tensorflow.python.framework import constant_op from tensorflow.python.framework import cpp_shape_inference_pb2 from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -64,6 +65,7 @@ def eager_safe_variable_handle(shape, dtype, shared_name, name, graph_mode): name=name, container=container) if graph_mode: + handle._handle_data = get_resource_handle_data(handle) # pylint: disable=protected-access return handle # We do not want two distinct ResourceVariable objects for the same @@ -1410,13 +1412,23 @@ def _ReadGrad(_, grad): return grad +def variable_shape(handle, out_type=dtypes.int32): + if getattr( + handle, "_handle_data", None) is None or not handle._handle_data.is_set: + return gen_resource_variable_ops.variable_shape(handle, out_type=out_type) + shape_proto = handle._handle_data.shape_and_type[0].shape + if shape_proto.unknown_rank or any(x.size == -1 for x in shape_proto.dim): + return gen_resource_variable_ops.variable_shape(handle, out_type=out_type) + return constant_op.constant([x.size for x in shape_proto.dim], dtype=out_type) + + @ops.RegisterGradient("ResourceGather") def _GatherGrad(op, grad): """Gradient for gather op.""" # Build appropriately shaped IndexedSlices handle = op.inputs[0] indices = op.inputs[1] - params_shape = gen_resource_variable_ops.variable_shape(handle) + params_shape = variable_shape(handle) size = array_ops.expand_dims(array_ops.size(indices), 0) values_shape = array_ops.concat([size, params_shape[1:]], 0) values = array_ops.reshape(grad, values_shape) -- GitLab From f1263f34f5b0ce7800e6cc9fdc8c3e572e1966f9 Mon Sep 17 00:00:00 2001 From: Rick Chao Date: Thu, 29 Nov 2018 10:51:56 -0800 Subject: [PATCH 544/672] Update the error message for missing output files in create_python_api.py. PiperOrigin-RevId: 223373079 --- tensorflow/python/tools/api/generator/create_python_api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/tools/api/generator/create_python_api.py b/tensorflow/python/tools/api/generator/create_python_api.py index be988c572c..51c2bfba7c 100644 --- a/tensorflow/python/tools/api/generator/create_python_api.py +++ b/tensorflow/python/tools/api/generator/create_python_api.py @@ -463,8 +463,9 @@ def create_api_files(output_files, packages, root_init_template, output_dir, raise ValueError( """Missing outputs for genrule:\n%s. Be sure to add these targets to tensorflow/python/tools/api/generator/api_init_files_v1.bzl and -tensorflow/python/tools/api/generator/api_init_files.bzl""" % ',\n'.join( - sorted(missing_output_files))) +tensorflow/python/tools/api/generator/api_init_files.bzl (tensorflow repo), or +tensorflow_estimator/python/estimator/api/api_gen.bzl (estimator repo)""" + % ',\n'.join(sorted(missing_output_files))) def main(): -- GitLab From a1f1abbe53e937cb7fe59ab4992dc9d107f8f0c2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 10:52:26 -0800 Subject: [PATCH 545/672] Add broadcasting support for RaggedTensors RELNOTES: Broadcasting support for Ragged Tensors. PiperOrigin-RevId: 223373179 --- tensorflow/python/ops/ragged/BUILD | 34 ++ tensorflow/python/ops/ragged/__init__.py | 9 + .../python/ops/ragged/ragged_array_ops.py | 87 +-- .../ops/ragged/ragged_elementwise_ops.py | 55 +- .../ops/ragged/ragged_elementwise_ops_test.py | 55 +- .../python/ops/ragged/ragged_factory_ops.py | 30 + tensorflow/python/ops/ragged/ragged_tensor.py | 1 + .../python/ops/ragged/ragged_tensor_shape.py | 570 ++++++++++++++++++ .../ops/ragged/ragged_tensor_shape_test.py | 487 +++++++++++++++ .../ops/ragged/ragged_to_sparse_op_test.py | 3 +- tensorflow/python/ops/ragged/ragged_util.py | 49 ++ 11 files changed, 1273 insertions(+), 107 deletions(-) create mode 100644 tensorflow/python/ops/ragged/ragged_tensor_shape.py create mode 100644 tensorflow/python/ops/ragged/ragged_tensor_shape_test.py diff --git a/tensorflow/python/ops/ragged/BUILD b/tensorflow/python/ops/ragged/BUILD index 9ff5f26804..8608bda647 100644 --- a/tensorflow/python/ops/ragged/BUILD +++ b/tensorflow/python/ops/ragged/BUILD @@ -33,6 +33,7 @@ py_library( ":ragged_math_ops", ":ragged_operators", ":ragged_tensor", + ":ragged_tensor_shape", ":ragged_tensor_value", ":ragged_util", ":segment_id_ops", @@ -155,6 +156,7 @@ py_library( deps = [ ":ragged_factory_ops", ":ragged_tensor", + ":ragged_tensor_shape", ":ragged_util", "//tensorflow/python:array_ops", "//tensorflow/python:clip_ops", @@ -190,6 +192,25 @@ py_library( ], ) +py_library( + name = "ragged_tensor_shape", + srcs = ["ragged_tensor_shape.py"], + srcs_version = "PY2AND3", + deps = [ + ":ragged_array_ops", + ":ragged_conversion_ops", + ":ragged_factory_ops", + ":ragged_tensor", + ":ragged_util", + "//tensorflow/python:array_ops", + "//tensorflow/python:dtypes", + "//tensorflow/python:framework_ops", + "//tensorflow/python:math_ops", + "//tensorflow/python:tensor_shape", + "//tensorflow/python:tensor_util", + ], +) + py_library( name = "ragged_tensor_value", srcs = ["ragged_tensor_value.py"], @@ -207,6 +228,7 @@ py_library( "//tensorflow/python:dtypes", "//tensorflow/python:framework_ops", "//tensorflow/python:math_ops", + "//tensorflow/python:ragged_math_ops_gen", ], ) @@ -690,3 +712,15 @@ py_test( "@absl_py//absl/testing:parameterized", ], ) + +py_test( + name = "ragged_tensor_shape_test", + srcs = ["ragged_tensor_shape_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":ragged", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + "@absl_py//absl/testing:parameterized", + ], +) diff --git a/tensorflow/python/ops/ragged/__init__.py b/tensorflow/python/ops/ragged/__init__.py index 3a28848545..3e802485a3 100644 --- a/tensorflow/python/ops/ragged/__init__.py +++ b/tensorflow/python/ops/ragged/__init__.py @@ -143,6 +143,11 @@ The following operations are specific to ragged tensors: @@make_elementwise_op + +@@RaggedTensorDynamicShape +@@broadcast_to +@@broadcast_dynamic_shape + """ @@ -214,6 +219,10 @@ from tensorflow.python.ops.ragged.ragged_tensor import is_ragged from tensorflow.python.ops.ragged.ragged_tensor import RaggedTensor from tensorflow.python.ops.ragged.ragged_tensor import RaggedTensorType +from tensorflow.python.ops.ragged.ragged_tensor_shape import broadcast_dynamic_shape +from tensorflow.python.ops.ragged.ragged_tensor_shape import broadcast_to +from tensorflow.python.ops.ragged.ragged_tensor_shape import RaggedTensorDynamicShape + from tensorflow.python.ops.ragged.ragged_tensor_value import RaggedTensorValue from tensorflow.python.ops.ragged.segment_id_ops import row_splits_to_segment_ids diff --git a/tensorflow/python/ops/ragged/ragged_array_ops.py b/tensorflow/python/ops/ragged/ragged_array_ops.py index 815f48a4b1..603e39d1dc 100644 --- a/tensorflow/python/ops/ragged/ragged_array_ops.py +++ b/tensorflow/python/ops/ragged/ragged_array_ops.py @@ -225,6 +225,28 @@ def row_lengths(rt_input, axis=1, name=None): return array_ops.ones(shape[:axis], dtypes.int64) * shape[axis] +def nested_row_lengths(rt_input, name=None): + """Returns a tuple containing the row_lengths for all ragged dimensions. + + `nested_row_lengths(rt)` is a tuple containing the `row_lengths` tensors for + all ragged dimensions in `rt`, ordered from outermost to innermost. + + Args: + rt_input: A potentially ragged tensor. + name: A name prefix for the returned tensors (optional). + + Returns: + A `tuple` of 1-D `int64` `Tensors`. The length of the tuple is equal to + `rt_input.ragged_rank`. + """ + with ops.name_scope(name, 'RaggedNestedRowLengths', [rt_input]): + rt_nested_row_lengths = [] + while isinstance(rt_input, ragged_tensor.RaggedTensor): + rt_nested_row_lengths.append(row_lengths(rt_input)) + rt_input = rt_input.values + return tuple(rt_nested_row_lengths) + + #=============================================================================== # Bounding Shape #=============================================================================== @@ -451,8 +473,7 @@ def batch_gather(params, indices, name=None): adjusted_indices = math_ops.to_int64(indices) + adjustments return gather(params.values, adjusted_indices) else: - raise ValueError( - 'batch shape from indices does not match params shape') + raise ValueError('batch shape from indices does not match params shape') #=============================================================================== @@ -719,7 +740,7 @@ def boolean_mask(data, mask, keepdims=False, name=None): int_mask = ragged_functional_ops.map_inner_values( math_ops.cast, mask, dtype=dtypes.int64) masked_row_lengths = ragged_math_ops.reduce_sum(int_mask, axis=1) - splits.append(_lengths_to_splits(masked_row_lengths)) + splits.append(ragged_util.lengths_to_splits(masked_row_lengths)) mask = mask.values data = data.values @@ -741,7 +762,7 @@ def boolean_mask(data, mask, keepdims=False, name=None): # masks back to a splits tensor. lengths = row_lengths(data) masked_lengths = array_ops.boolean_mask(lengths, mask) - masked_splits = _lengths_to_splits(masked_lengths) + masked_splits = ragged_util.lengths_to_splits(masked_lengths) # Get the masked values: first get row ids corresponding to each # value, then use tf.gather to build a boolean mask that's false for @@ -977,7 +998,7 @@ def _ragged_stack_concat_axis_0(rt_inputs, stack_values): # If we are performing a stack operation, then add another splits. if stack_values: stack_lengths = array_ops.stack([nrows(rt) for rt in rt_inputs]) - stack_splits = _lengths_to_splits(stack_lengths) + stack_splits = ragged_util.lengths_to_splits(stack_lengths) concatenated_nested_splits.insert(0, stack_splits) return ragged_factory_ops.from_nested_row_splits(concatenated_inner_values, @@ -1131,7 +1152,8 @@ def _tile_ragged_values(rt_input, multiples, const_multiples=None): # Repeat each element in this ragged dimension `multiples[axis]` times. if const_multiples is None or const_multiples[axis] != 1: - inner_value_ids = _repeat_ranges(inner_value_ids, splits, multiples[axis]) + inner_value_ids = ragged_util.repeat_ranges(inner_value_ids, splits, + multiples[axis]) prev_splits = splits @@ -1200,15 +1222,15 @@ def _tile_ragged_splits(rt_input, multiples, const_multiples=None): for d in range(axis - 1, -1, -1): if const_multiples is None or const_multiples[d + 1] != 1: splits = projected_splits[d][axis - 1] * repeats - output_lengths = _repeat_ranges(output_lengths, splits, - multiples[d + 1]) + output_lengths = ragged_util.repeat_ranges(output_lengths, splits, + multiples[d + 1]) repeats *= multiples[d + 1] # Tile splits for the outermost (uniform) dimension. output_lengths = array_ops.tile(output_lengths, multiples[:1]) # Convert to splits. - result_splits.append(_lengths_to_splits(output_lengths)) + result_splits.append(ragged_util.lengths_to_splits(output_lengths)) return result_splits @@ -1436,11 +1458,6 @@ def _coordinate_where(condition): #=============================================================================== -def _lengths_to_splits(lengths): - """Returns splits corresponding to the given lengths.""" - return array_ops.concat([[0], math_ops.cumsum(lengths)], axis=0) - - def _increase_ragged_rank_to(rt_input, ragged_rank): """Adds ragged dimensions to `rt_input` so it has the desired ragged rank.""" if ragged_rank > 0: @@ -1460,45 +1477,3 @@ def _concat_ragged_splits(splits_list): pieces.append(splits[1:] + splits_offset) splits_offset += splits[-1] return array_ops.concat(pieces, axis=0) - - -def _repeat_ranges(params, splits, multiple): - """Repeats each range of `params` (as specified by `splits`) `multiple` times. - - Let the `i`th range of `params` be defined as - `params[splits[i]:splits[i + 1]]`. Then this function returns a tensor - containing range 0 repeated `multiple` times, followed by range 1 repeated - `multiple`, ..., followed by the last range repeated `multiple` times. - - Args: - params: The `Tensor` whose values should be repeated. - splits: A splits tensor indicating the ranges of `params` that should be - repeated. - multiple: The number of times each range should be repeated. - - Returns: - A `Tensor` with the same rank and type as `params`. - - #### Example: - ```python - >>> _repeat_ranges(['a', 'b', 'c'], [0, 2, 3], 3) - ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'c', 'c'] - ``` - """ - # Repeat each split value `multiple` times. E.g., if `splits=[0 3 4]` and - # `multiples=3`, then `repeated_splits=[0 0 0 3 3 3 4 4 4]`. - repeated_splits = array_ops.tile( - array_ops.expand_dims(splits, axis=1), array_ops.stack([1, multiple])) - repeated_splits = array_ops.reshape(repeated_splits, [-1]) - - # Divide the splits into repeated starts & repeated limits. E.g., if - # `repeated_splits=[0 0 0 3 3 3 4 4 4]` then `repeated_starts=[0 0 0 3 3 3]` - # and `repeated_limits=[3 3 3 4 4 4]`. - n_splits = array_ops.shape(repeated_splits, out_type=dtypes.int64)[0] - repeated_starts = repeated_splits[:n_splits - multiple] - repeated_limits = repeated_splits[multiple:] - - # Get indices for each range from starts to limits, and use those to gather - # the values in the desired repetition pattern. - offsets = ragged_math_ops.range(repeated_starts, repeated_limits).values - return array_ops.gather(params, offsets) diff --git a/tensorflow/python/ops/ragged/ragged_elementwise_ops.py b/tensorflow/python/ops/ragged/ragged_elementwise_ops.py index edf721b5a7..a497500a6a 100644 --- a/tensorflow/python/ops/ragged/ragged_elementwise_ops.py +++ b/tensorflow/python/ops/ragged/ragged_elementwise_ops.py @@ -28,7 +28,7 @@ from tensorflow.python.ops import parsing_ops from tensorflow.python.ops import string_ops from tensorflow.python.ops.ragged import ragged_factory_ops from tensorflow.python.ops.ragged import ragged_tensor -from tensorflow.python.ops.ragged import ragged_util +from tensorflow.python.ops.ragged import ragged_tensor_shape from tensorflow.python.util import tf_decorator from tensorflow.python.util import tf_export from tensorflow.python.util import tf_inspect @@ -209,28 +209,45 @@ def _broadcast_elementwise_args(elementwise_args): if not any(is_ragged): return elementwise_args, (), () - # Support limited broadcasting (namely, scalar + ragged). Full - # broadcasting support will be added later. - if all((ragged_tensor.is_ragged(t) or t.shape.ndims == 0) - for t in elementwise_args.values()): + # If we have a single ragged tensor plus a set of scalars, then we can + # rely on the underlying elementwise op to do broadcasting. + if (sum(is_ragged) == 1 and + all((ragged_tensor.is_ragged(t) or t.shape.ndims == 0) + for t in elementwise_args.values())): nested_splits_lists = [ t.nested_row_splits for t in elementwise_args.values() - if ragged_tensor.is_ragged(t) - ] - if len(nested_splits_lists) == 1: - checks = () - else: - if any(t.shape.ndims is None for t in elementwise_args.values()): - raise ValueError('Ragged elementwise ops require that rank (number ' - 'of dimensions) be statically known.') - if len(set(t.shape.ndims for t in elementwise_args.values())) != 1: - raise ValueError('Ragged elementwise ops do not support ' - 'broadcasting yet') - checks = ragged_util.assert_splits_match(nested_splits_lists) - return (elementwise_args, nested_splits_lists[0], checks) + if ragged_tensor.is_ragged(t)][0] + return elementwise_args, nested_splits_lists, () + else: - raise ValueError('Ragged elementwise ops do not support broadcasting yet') + # Get the shapes of all the elementwise arguments. + shapes = [ragged_tensor_shape.RaggedTensorDynamicShape.from_tensor(t) + for t in elementwise_args.values()] + + # Broadcast the shapes to all have the same rank (the max rank). + ranks = [t.shape.ndims for t in elementwise_args.values()] + if any(rank is None for rank in ranks): + raise ValueError('Unable to broadcast: unknown rank') + broadcast_rank = max(ranks) + shapes = [shape.broadcast_to_rank(broadcast_rank) for shape in shapes] + + # For each dimension, broadcast the shapes to be compatible. + for axis in range(broadcast_rank): + # For each i, broadcast shape[i+1] to be compatible with shape[i]; and + # then finally broadcast shape[0] to be compatible with shape[-1]. + for i in range(len(shapes)): + j = (i + 1) % len(shapes) + dim_size = shapes[i].dimension_size(axis) + shapes[j] = shapes[j].broadcast_dimension(axis, dim_size) + broadcast_shape = shapes[0] + + # Broadcast every elementwise arg to the shape that we calculated. + elementwise_args = dict([ + (key, ragged_tensor_shape.broadcast_to(t, broadcast_shape, False)) + for (key, t) in elementwise_args.items()]) + nested_splits_lists = list(elementwise_args.values())[0].nested_row_splits + return elementwise_args, nested_splits_lists, () # A list of symbols that should be exported in the "ragged" package. diff --git a/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py b/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py index 5dfa5cff45..26e6b8b6d4 100644 --- a/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py +++ b/tensorflow/python/ops/ragged/ragged_elementwise_ops_test.py @@ -399,44 +399,37 @@ class RaggedElementwiseOpsTest(test_util.TensorFlowTestCase, y = ragged.from_row_splits( array_ops.placeholder_with_default([1, 2, 3], shape=None), x.row_splits) with self.assertRaisesRegexp( - ValueError, r'Ragged elementwise ops require that rank \(number ' - r'of dimensions\) be statically known.'): + ValueError, r'Unable to broadcast: unknown rank'): ragged.add(x, y) - def testBroadcastError1(self): - x = ragged.constant([[1, 2], [3]]) - y = [[12]] - with self.assertRaisesRegexp( - ValueError, 'Ragged elementwise ops do not support broadcasting yet'): - ragged.add(x, y) - - def testBroadcastError2(self): - x = ragged.constant([[[1, 2], [3, 4]], [[5]]], ragged_rank=2) - y = ragged.constant([[[8], [3]], [[2]]], ragged_rank=1) - with self.assertRaisesRegexp(ValueError, - 'Inputs must have identical ragged splits'): - ragged.add(x, y) - - def testBroadcastError3(self): - x = ragged.constant([[[1, 2], [3]], [[4, 5], [6]]], ragged_rank=2) - y = ragged.constant([[7, 8], [9]], ragged_rank=1) - with self.assertRaisesRegexp( - ValueError, 'Ragged elementwise ops do not support broadcasting yet'): - ragged.add(x, y) - - def testBroadcastError4(self): - x = ragged.constant([[[1]]]) - y = ragged.constant([[1]]) - with self.assertRaisesRegexp( - ValueError, 'Ragged elementwise ops do not support broadcasting yet'): - ragged.add(x, y) + @parameterized.parameters([ + dict( + x=ragged.constant_value([[1, 2], [3]]), + y=[[10]], + expected=[[11, 12], [13]]), + dict( + x=ragged.constant_value([[[1, 2], [3, 4]], [[5]]], ragged_rank=2), + y=ragged.constant_value([[[10], [20]], [[30]]], ragged_rank=1), + expected=[[[11, 12], [23, 24]], [[35]]]), + dict( + x=ragged.constant_value([[[1]]]), + y=ragged.constant_value([[1]]), + expected=[[[2]]]), + ]) + def testBroadcastAdd(self, x, y, expected): + x = ragged.convert_to_tensor_or_ragged_tensor(x, dtype=dtypes.int32) + y = ragged.convert_to_tensor_or_ragged_tensor(y, dtype=dtypes.int32) + result = x + y + with self.cached_session(): + self.assertEqual(result.eval().tolist(), expected) def testShapeMismatch(self): x = ragged.constant([[1, 2, 3], [4, 5]]) y = ragged.constant([[1, 2, 3], [4, 5, 6]]) with self.assertRaisesRegexp(errors.InvalidArgumentError, - 'Inputs must have identical ragged splits'): - ragged.add(x, y) + 'Incompatible shapes'): + with self.cached_session(): + ragged.add(x, y).eval() def testDocstring(self): self.assertRegexpMatches( diff --git a/tensorflow/python/ops/ragged/ragged_factory_ops.py b/tensorflow/python/ops/ragged/ragged_factory_ops.py index de3a2d5b10..d1f301bc58 100644 --- a/tensorflow/python/ops/ragged/ragged_factory_ops.py +++ b/tensorflow/python/ops/ragged/ragged_factory_ops.py @@ -676,3 +676,33 @@ def from_nested_row_splits(inner_values, nested_row_splits, name=None): for splits in reversed(nested_row_splits): result = from_row_splits(result, splits) return result + + +def from_nested_row_lengths(inner_values, nested_row_lengths, name=None): + """Creates a `RaggedTensor` from a nested list of `row_lengths` tensors. + + Equivalent to: + + ```python + result = inner_values + for row_lengths in reversed(nested_row_lengths): + result = from_row_lengths(result, row_lengths) + ``` + + Args: + inner_values: A potentially ragged tensor. + nested_row_lengths: A list of 1-D int64 tensors. The `i`th tensor is used + as the `row_lengths` for the `i`th ragged dimension. + name: A name prefix for the RaggedTensor (optional). + + Returns: + A `RaggedTensor` (or `inner_values` if `nested_row_lengths` is empty). + """ + if isinstance(nested_row_lengths, ops.Tensor): + raise TypeError('nested_row_lengths must be a list of Tensors') + with ops.name_scope(name, 'RaggedFromNestedRowlengths', + [inner_values] + list(nested_row_lengths)): + result = inner_values + for lengths in reversed(nested_row_lengths): + result = from_row_lengths(result, lengths) + return result diff --git a/tensorflow/python/ops/ragged/ragged_tensor.py b/tensorflow/python/ops/ragged/ragged_tensor.py index abb27fc3c0..90f0dafd99 100644 --- a/tensorflow/python/ops/ragged/ragged_tensor.py +++ b/tensorflow/python/ops/ragged/ragged_tensor.py @@ -257,6 +257,7 @@ class RaggedTensor(object): raise TypeError("Row-partitioning argument must be a Tensor.") values.shape.with_rank_at_least(1) row_splits.shape.assert_has_rank(1) + row_splits.set_shape([None]) self._values = values self._row_splits = row_splits diff --git a/tensorflow/python/ops/ragged/ragged_tensor_shape.py b/tensorflow/python/ops/ragged/ragged_tensor_shape.py new file mode 100644 index 0000000000..9129b4b10b --- /dev/null +++ b/tensorflow/python/ops/ragged/ragged_tensor_shape.py @@ -0,0 +1,570 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Shapes & broadcasting for RaggedTensors.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import constant_op +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_util +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops.ragged import ragged_array_ops +from tensorflow.python.ops.ragged import ragged_conversion_ops +from tensorflow.python.ops.ragged import ragged_factory_ops +from tensorflow.python.ops.ragged import ragged_tensor +from tensorflow.python.ops.ragged import ragged_util + + +class RaggedTensorDynamicShape(object): + """A collection of tensors encoding the shape of a potentially ragged tensor. + + Each `RaggedTensorDynamicShape` consists of an ordered list of dimension + sizes. There are two dimension types: + + * "Uniform dimensions" are dimenisons where all slices have the same + length. `RaggedTensorDynamicShape` records the size of each uniform + dimension using a single scalar integer. + + * "Ragged dimensions" are dimensions whose slices may have different + lengths. `RaggedTensorDynamicShape` records the size of each ragged + dimension using an integer vector containing the slice lengths for all + the slices across that dimension. + + Furthermore, there are two ways a dimension might be encoded: + + * "Partitioned dimensions" are dimensions that are encoded using a + `RaggedTensor`'s `nested_row_splits`. The outermostmost partitioned + dimension must be uniform, and the innermost partitioned dimension must + be ragged. + + * "Inner dimensions" are dimensions that are encoded using a + `RaggedTensor`'s `inner_values`. Inner dimensions are always uniform. + + The sizes of partitioned dimensions are recorded using `partitioned_dim_sizes` + and `inner_dim_sizes`: + + * `paritioned_dim_sizes` is a list of tensors (one for each partitioned + dimension). + + * For uniform dimensions, the tensor is an integer scalar specifying the + size of all slices across that dimension. + * For ragged dimensions, the tensor is an integer vector specifying the + size of each slice across that dimension. + + * `inner_dim_sizes` is a single integer vector, where each element + specifies the size of a single inner dimension. + + Examples: + + Tensor | Ragged | Partitioned Dim Sizes | Inner Dim + : Rank : : Sizes + ------------------------------ | ------ | ---------------------- | ---------- + `[[1, 2, 3], [4, 5, 6]]` | 0 | | `2, 3` + `[[1, 2], [], [3, 4, 5]]` | 1 | `3, (2, 0, 3)` | + `[[[1, 2], [3, 4]], [[5, 6]]]` | 1 | `2, (2, 1)` | 2 + `[[[1, 2], [3]], [[4, 5]]]` | 2 | `2, (2, 1), (2, 1, 2)` | + """ + + def __init__(self, partitioned_dim_sizes, inner_dim_sizes): + """Creates a RaggedTensorDynamicShape. + + Args: + partitioned_dim_sizes: A `list` of 0-D or 1-D integer `Tensor`, one for + each partitioned dimension. If dimension `d` is uniform, then + `partitioned_dim_sizes[d]` must be an integer scalar, specifying the + size of all slices across dimension `d`. If dimension `d` is ragged, + then `partitioned_dim_sizes[d]` must be an integer vector, specifying + the size of each slice across dimension `d`. + inner_dim_sizes: A 1-D integer `Tensor`, whose length is equal to the + number of inner dimensions. `inner_dim_sizes[n]` is the size of all + slices across the `n`th inner dimension (which is the + `(len(partitioned_dim_sizes)+n)`th dimension in the overall tensor. + """ + assert isinstance(partitioned_dim_sizes, (list, tuple)) + with ops.name_scope(None, 'RaggedTensorDynamicShape', + (partitioned_dim_sizes, inner_dim_sizes)): + partitioned_dim_sizes = tuple( + ragged_util.convert_to_int_tensor( + size, dtype=dtypes.int64, name='partitioned_dimension_size') + for size in partitioned_dim_sizes) + inner_dim_sizes = ragged_util.convert_to_int_tensor( + inner_dim_sizes, dtype=dtypes.int64, name='inner_dim_sizes') + + # Validate shapes. + if partitioned_dim_sizes: + for axis, dimension_size in enumerate(partitioned_dim_sizes): + if dimension_size.shape.ndims is None: + raise ValueError( + 'rank of partitioned_dim_sizes[%d] is unknown' % axis) + dimension_size.shape.with_rank_at_most(1) + if partitioned_dim_sizes[0].shape.ndims == 1: + raise ValueError('outermost partitioned dimension must be uniform') + if partitioned_dim_sizes[-1].shape.ndims == 0: + raise ValueError('innermost partitioned dimension must be ragged') + inner_dim_sizes.shape.assert_has_rank(1) + + self._partitioned_dim_sizes = partitioned_dim_sizes + self._inner_dim_sizes = inner_dim_sizes + + def __repr__(self): + return ('RaggedTensorDynamicShape' + '(partitioned_dim_sizes=%r, inner_dim_sizes=%r)' % + (self._partitioned_dim_sizes, self._inner_dim_sizes)) + + @staticmethod + def from_dim_sizes(dim_sizes): + """Constructs a ragged shape from a list of dimension sizes. + + This list contains a single tensor for each dimension, where the tensor + is a scalar if the dimension is uniform, or a vector if the dimension is + ragged. + + Args: + dim_sizes: List of int64 scalars or vectors. + + Returns: + A RaggedTensorDynamicShape. + """ + with ops.name_scope(None, 'RaggedTensorDynamicShapeFromDimensionSizes', + [dim_sizes]): + dim_sizes = tuple( + ragged_util.convert_to_int_tensor( + size, dtype=dtypes.int64, name='dim_sizes') for size in dim_sizes) + # Split the dimensions into partitioned & inner dimensions. + inner_split = 0 + for dim, dim_size in enumerate(dim_sizes): + if dim_size.shape.ndims == 1: + inner_split = dim + 1 + elif dim_size.shape.ndims != 0: + raise ValueError('Each dim_size must be a scalar or a vector') + return RaggedTensorDynamicShape(dim_sizes[:inner_split], + dim_sizes[inner_split:]) + + @classmethod + def from_tensor(cls, rt_input): + """Constructs a ragged shape for a potentially ragged tensor.""" + with ops.name_scope(None, 'RaggedTensorDynamicShapeFromTensor', [rt_input]): + rt_input = ragged_factory_ops.convert_to_tensor_or_ragged_tensor(rt_input) + if not ragged_tensor.is_ragged(rt_input): + return cls([], array_ops.shape(rt_input)) + else: + partitioned_dim_sizes = ((ragged_array_ops.nrows(rt_input),) + + ragged_array_ops.nested_row_lengths(rt_input)) + return RaggedTensorDynamicShape( + partitioned_dim_sizes, + array_ops.shape(rt_input.inner_values)[1:]) + + def dimension_size(self, axis): + """Returns the size of slices across the specified dimension.""" + if not isinstance(axis, int): + raise TypeError('axis must be an integer') + partitioned_ndims = len(self._partitioned_dim_sizes) + if axis < partitioned_ndims: + return self._partitioned_dim_sizes[axis] + else: + return self._inner_dim_sizes[axis - partitioned_ndims] + + def is_ragged(self, axis): + """Returns true if the indicated dimension is ragged.""" + if not isinstance(axis, int): + raise TypeError('axis must be an integer') + rank = self.rank + if axis < 0: + raise ValueError('Negative axis values are not supported') + elif rank is not None and axis >= rank: + raise ValueError('Expected axis=%s < rank=%s' % (axis, rank)) + else: + return (axis > 0 and axis < len(self._partitioned_dim_sizes) and + self._partitioned_dim_sizes[axis].shape.ndims == 1) + + @property + def rank(self): + """The number of dimensions in this shape, or None if unknown.""" + inner_ndims = self._inner_dim_sizes.shape[0].value + if inner_ndims is None: + return None + else: + return len(self._partitioned_dim_sizes) + inner_ndims + + @property + def partitioned_dim_sizes(self): + """The partitioned dimension sizes for this shape. + + Returns: + A `list` of 0-D or 1-D integer `Tensor`. + """ + return self._partitioned_dim_sizes + + @property + def inner_dim_sizes(self): + """The inner dimension sizes for this shape. + + Returns: + A 1-D integer `Tensor`. + """ + return self._inner_dim_sizes + + @property + def num_partitioned_dimensions(self): + """The number of partitioned dimensions in this shape.""" + return len(self._partitioned_dim_sizes) + + @property + def num_inner_dimensions(self): + """The number of inner dimensions, or `None` if not statically known.""" + return self._inner_dim_sizes.shape[0].value + + def broadcast_to_rank(self, rank): + """Adds leading size-1 dimensions to broadcast `self` to the given rank. + + E.g., if `shape1` is `[3, (D2), 4]`, then `shape1.broadcast_to_rank(5)` + is `[1, 1, 3, (D2), 4]`. + + Args: + rank: The rank for the returned shape. + + Returns: + A RaggedTensorDynamicShape with `rank` dimensions, whose inner dimensions + have the same size as `self` and whose outer dimensions have size `1`. + + Raises: + ValueError: If `self.rank` is unknown or greater than `rank`. + """ + if self.rank is None: + raise ValueError('Unable to broadcast: self.rank is unknown') + dims_to_add = rank - self.rank + if dims_to_add < 0: + raise ValueError('Unable to broadcast: rank=%d must be greater than ' + 'self.rank=%d.' % (rank, self.rank)) + elif dims_to_add == 0: + return self + elif self._partitioned_dim_sizes: + partitioned_dims = (1,) * dims_to_add + self._partitioned_dim_sizes + return RaggedTensorDynamicShape(partitioned_dims, self._inner_dim_sizes) + else: + inner_dims = array_ops.concat( + [array_ops.ones([dims_to_add], dtypes.int64), self.inner_dim_sizes], + axis=0) + return RaggedTensorDynamicShape([], inner_dims) + + def broadcast_dimension(self, axis, lengths): + """Returns a shape that is broadcast-compatible with self & lengths. + + * If dimension[axis] is uniform and lengths is a scalar, the check + that either lengths==1 or axis==1 or lengths==axis, and tile + dimension[axis] with tf.where(lengths==axis, 1, axis) repeats. + + * If dimension[axis] is uniform and lengths is a vector, then check + that dimension[axis]==1, and raggedly tile dimension[axis] with + lengths repeats. (we can skip tiling if we statically know that + slice_lengths == 1??) + + * If dimension[axis] is ragged and lengths is a scalar, then check + that lengths==1. + + * If dimension[axis] is ragged and lengths is a vector, then check + that self.dimension_size(axis) == lengths. + + Args: + axis: `int`. The dimension to broadcast. + lengths: 0-D or 1-D integer `Tensor`. + + Returns: + A `RaggedTensorDynamicShape`. + """ + lengths = ragged_util.convert_to_int_tensor( + lengths, name='lengths', dtype=dtypes.int64) + # Check whether lengths is a scalar (for uniform dimensions) or + # vector (for ragged dimensions). + if lengths.shape.ndims is None: + raise ValueError('lengths must have a known rank.') + elif lengths.shape.ndims > 1: + raise ValueError('lengths must be a scalar or vector') + else: + lengths_is_scalar = (lengths.shape.ndims == 0) + + # Verify that the shapes are compatible. + if self.is_ragged(axis): + if lengths_is_scalar: + condition = math_ops.equal(lengths, 1) + else: + condition = math_ops.reduce_all( + math_ops.equal(lengths, self.dimension_size(axis))) + else: + axis_dim_size = self.dimension_size(axis) + if lengths_is_scalar: + condition = ( + math_ops.equal(lengths, 1) | math_ops.equal(axis_dim_size, 1) + | math_ops.equal(axis_dim_size, lengths)) + else: + condition = math_ops.equal(axis_dim_size, 1) + broadcast_err = [ + 'Unable to broadcast: dimension size mismatch in dimension', axis, + 'lengths=', lengths, 'dim_size=', + self.dimension_size(axis) + ] + broadcast_check = control_flow_ops.Assert( + condition, data=broadcast_err, summarize=10) + + with ops.control_dependencies([broadcast_check]): + # Partitioned dimensions: + if axis < self.num_partitioned_dimensions: + if self.is_ragged(axis): + # Use an identity op to make sure the check actually gets run. + return RaggedTensorDynamicShape( + self._partitioned_dim_sizes, + array_ops.identity(self.inner_dim_sizes)) + else: + return self._broadcast_uniform_partitioned_dimension(axis, lengths) + + # Inner dimensions: + else: + if lengths_is_scalar: + return self._broadcast_inner_dimension_to_uniform(axis, lengths) + else: + if axis == 0: + raise ValueError('Unable to broadcast: ' + 'outermost dimension must be uniform.') + return self._broadcast_inner_dimension_to_ragged(axis, lengths) + + def num_slices_in_dimension(self, axis): + """Returns the total number of slices across the indicated dimension.""" + if axis < 0: + return constant_op.constant(1, dtype=dtypes.int64) + elif self.is_ragged(axis): + return math_ops.reduce_sum(self._partitioned_dim_sizes[axis]) + else: + return self.dimension_size(axis) * self.num_slices_in_dimension(axis - 1) + + def _broadcast_uniform_partitioned_dimension(self, axis, lengths): + """Broadcasts the partitioned dimension `axis` to match `lengths`.""" + axis_dim_size = self.dimension_size(axis) + partitioned_sizes = list(self._partitioned_dim_sizes[:axis]) + + if lengths.shape.ndims == 0: + lengths = array_ops.where( + math_ops.equal(axis_dim_size, 1), lengths, axis_dim_size) + repeats = array_ops.where(math_ops.equal(axis_dim_size, 1), lengths, 1) + splits = array_ops.stack([0, self.num_slices_in_dimension(axis)]) + else: + splits = math_ops.range( + array_ops.size(lengths, out_type=dtypes.int64) + 1) + repeats = lengths + + partitioned_sizes.append(lengths) + + for dim_size in self._partitioned_dim_sizes[axis + 1:]: + if dim_size.shape.ndims == 0: + partitioned_sizes.append(dim_size) + splits *= dim_size + else: + partitioned_sizes.append( + ragged_util.repeat_ranges(dim_size, splits, repeats)) + splits = array_ops.gather( + ragged_util.lengths_to_splits(dim_size), splits) + inner_sizes = self._inner_dim_sizes + return RaggedTensorDynamicShape(partitioned_sizes, inner_sizes) + + def _broadcast_inner_dimension_to_uniform(self, axis, length): + """Broadcasts the inner dimension `axis` to match `lengths`.""" + dim_size = self.dimension_size(axis) + axis_in_inner_dims = axis - self.num_partitioned_dimensions + partitioned_sizes = self._partitioned_dim_sizes + inner_sizes = array_ops.concat([ + self._inner_dim_sizes[:axis_in_inner_dims], + [array_ops.where(math_ops.equal(dim_size, 1), length, dim_size)], + self._inner_dim_sizes[axis_in_inner_dims + 1:] + ], + axis=0) + return RaggedTensorDynamicShape(partitioned_sizes, inner_sizes) + + def _broadcast_inner_dimension_to_ragged(self, axis, lengths): + axis_in_inner_dims = axis - self.num_partitioned_dimensions + partitioned_sizes = ( + self._partitioned_dim_sizes + tuple([ + self._inner_dim_sizes[i] for i in range(axis_in_inner_dims) + ]) + (lengths,)) + inner_sizes = self._inner_dim_sizes[axis_in_inner_dims + 1:] + return RaggedTensorDynamicShape(partitioned_sizes, inner_sizes) + + +def broadcast_dynamic_shape(shape_x, shape_y): + """Returns the shape formed by broadcasting two shapes to be compatible. + + Args: + shape_x: A `RaggedTensorDynamicShape` + shape_y: A `RaggedTensorDynamicShape` + + Returns: + A `RaggedTensorDynamicShape`. + Raises: + ValueError: If `shape_x` and `shape_y` are not broadcast-compatible. + """ + if not isinstance(shape_x, RaggedTensorDynamicShape): + raise TypeError('shape_x must be a RaggedTensorDynamicShape') + if not isinstance(shape_y, RaggedTensorDynamicShape): + raise TypeError('shape_y must be a RaggedTensorDynamicShape') + + # Broadcast both shapes to have the same rank. + if shape_x.rank is None or shape_y.rank is None: + raise ValueError('Unable to broadcast: unknown rank') + broadcast_rank = max(shape_x.rank, shape_y.rank) + shape_x = shape_x.broadcast_to_rank(broadcast_rank) + shape_y = shape_y.broadcast_to_rank(broadcast_rank) + + # Broadcast dimensions one at a time, starting from the outermost dimension. + for axis in range(broadcast_rank): + shape_x = shape_x.broadcast_dimension(axis, shape_y.dimension_size(axis)) + shape_y = shape_y.broadcast_dimension(axis, shape_x.dimension_size(axis)) + + return shape_x + + +def broadcast_to(rt_input, shape, broadcast_inner_dimensions=True): + """Broadcasts a potentially ragged tensor to a ragged shape. + + Tiles `rt_input` as necessary to match the given shape. + + Behavior is undefined if `rt_input` is not broadcast-compatible with `shape`. + + Args: + rt_input: The potentially ragged tensor to broadcast. + shape: A `RaggedTensorDynamicShape` + broadcast_inner_dimensions: If false, then inner dimensions will not be + tiled. + + Returns: + A potentially ragged tensor whose values are taken from + `rt_input`, and whose shape matches `shape`. + """ + if not isinstance(shape, RaggedTensorDynamicShape): + raise TypeError('shape must be a RaggedTensorDynamicShape') + rt_input = ragged_factory_ops.convert_to_tensor_or_ragged_tensor(rt_input) + + # Broadcasting to a uniform shape. + if shape.num_partitioned_dimensions == 0: + return _broadcast_to_uniform_shape(rt_input, shape, + broadcast_inner_dimensions) + else: + return _broadcast_to_ragged_shape(rt_input, shape, + broadcast_inner_dimensions) + + +def _broadcast_to_uniform_shape(rt_input, shape, broadcast_inner_dimensions): + """Broadcasts rt_input to the uniform shape `shape`.""" + if isinstance(rt_input, ragged_tensor.RaggedTensor): + raise ValueError('Incompatible with shape: ragged rank mismatch') + if broadcast_inner_dimensions: + return array_ops.broadcast_to(rt_input, shape.inner_dim_sizes) + else: + return rt_input + + +def _broadcast_to_ragged_shape(rt_input, dst_shape, broadcast_inner_dimensions): + """Broadcasts rt_input to the ragged shape `dst_shape`.""" + # dst_shape's rank and ragged_rank must be greater than or equal to rt_input's + if rt_input.shape.ndims is None or dst_shape.rank is None: + raise ValueError('Unable to broadcast: unknown rank') + if rt_input.shape.ndims > dst_shape.rank: + raise ValueError('Incompatible with shape: rank mismatch') + if (isinstance(rt_input, ragged_tensor.RaggedTensor) and + rt_input.ragged_rank >= dst_shape.num_partitioned_dimensions): + raise ValueError('Incompatible with shape: ragged rank mismatch') + + src_shape = RaggedTensorDynamicShape.from_tensor(rt_input) + src_shape = src_shape.broadcast_to_rank(dst_shape.rank) + + # Add dimensions to rt_input so its rank and ragged_rank matches dst_shape. + if dst_shape.rank > rt_input.shape.ndims: + if rt_input.shape.ndims < dst_shape.num_inner_dimensions + 1: + rt_input = array_ops.reshape( + rt_input, array_ops.concat([[-1], dst_shape.inner_dim_sizes], axis=0)) + for _ in range(dst_shape.rank - rt_input.shape.ndims): + rt_input = ragged_factory_ops.from_row_lengths( + rt_input, [ragged_array_ops.nrows(rt_input)]) + + # Add ragged dimensions to match dst_shape. + if ragged_tensor.is_ragged(rt_input): + inner_rank_diff = ( + rt_input.inner_values.shape.ndims - 1 - dst_shape.num_inner_dimensions) + if inner_rank_diff > 0: + rt_input = rt_input.with_inner_values( + ragged_conversion_ops.from_tensor( + rt_input.inner_values, ragged_rank=inner_rank_diff)) + else: + rt_input = ragged_conversion_ops.from_tensor( + rt_input, ragged_rank=dst_shape.num_partitioned_dimensions - 1) + + # Do broadcasting for any dimensions that will remain uniform. We can do + # these all at once, since they're independent of one another. + multiples = [1] * dst_shape.rank + for axis in range(dst_shape.num_partitioned_dimensions): + if not src_shape.is_ragged(axis) and not dst_shape.is_ragged(axis): + src_size = src_shape.dimension_size(axis) + dst_size = dst_shape.dimension_size(axis) + if ((tensor_util.constant_value(src_size) in (1, None)) and + (tensor_util.constant_value(dst_size) != 1)): + multiples[axis] = array_ops.where( + math_ops.equal(src_size, 1), dst_size, 1) + if not all(isinstance(v, int) and v == 1 for v in multiples): + multiples = array_ops.stack(multiples, axis=0) + rt_input = ragged_array_ops.tile(rt_input, multiples) + + if broadcast_inner_dimensions: + rt_input = rt_input.with_inner_values( + array_ops.reshape( + rt_input.inner_values, + array_ops.concat([[-1], dst_shape.inner_dim_sizes], axis=0))) + + # Do broadcasting for dimensions that become ragged. We must do these from + # outermost to innermost. + for axis in range(dst_shape.num_partitioned_dimensions): + if not src_shape.is_ragged(axis) and dst_shape.is_ragged(axis): + dst_size = dst_shape.dimension_size(axis) + rt_input = _ragged_tile_axis(rt_input, axis, dst_size) + + return rt_input + + +def _ragged_tile_axis(rt_input, axis, repeats): + """Tile a dimension of a RaggedTensor to match a ragged shape.""" + assert axis > 0 # Outermost dimension may not be ragged. + + if not ragged_tensor.is_ragged(rt_input): + rt_input = ragged_conversion_ops.from_tensor(rt_input, ragged_rank=1) + + if axis > 1: + return rt_input.with_values( + _ragged_tile_axis(rt_input.values, axis - 1, repeats)) + else: + src_row_splits = rt_input.nested_row_splits + src_row_lengths = ragged_array_ops.nested_row_lengths(rt_input) + splits = src_row_splits[0] + + dst_row_lengths = [repeats] + for i in range(1, len(src_row_lengths)): + dst_row_lengths.append( + ragged_util.repeat_ranges(src_row_lengths[i], splits, repeats)) + splits = array_ops.gather(src_row_splits[i], splits) + dst_values = ragged_util.repeat_ranges(rt_input.inner_values, splits, + repeats) + return ragged_factory_ops.from_nested_row_lengths(dst_values, + dst_row_lengths) + diff --git a/tensorflow/python/ops/ragged/ragged_tensor_shape_test.py b/tensorflow/python/ops/ragged/ragged_tensor_shape_test.py new file mode 100644 index 0000000000..9c2dd26050 --- /dev/null +++ b/tensorflow/python/ops/ragged/ragged_tensor_shape_test.py @@ -0,0 +1,487 @@ +# Copyright 2018 The TensorFlow Authors. 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. +# ============================================================================== +"""Tests for tf.ragged.ragged_tensor_shape.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from absl.testing import parameterized +import numpy as np + +from tensorflow.python.framework import dtypes +from tensorflow.python.framework import test_util +from tensorflow.python.ops import ragged +from tensorflow.python.platform import googletest + + +class RaggedTensorShapeTest(test_util.TensorFlowTestCase, + parameterized.TestCase): + + def assertShapeEq(self, x, y): + assert isinstance(x, ragged.RaggedTensorDynamicShape) + assert isinstance(y, ragged.RaggedTensorDynamicShape) + x_partitioned_dim_sizes = [ + splits.eval().tolist() # + for splits in x.partitioned_dim_sizes + ] + y_partitioned_dim_sizes = [ + splits.eval().tolist() # + for splits in y.partitioned_dim_sizes + ] + self.assertEqual(x_partitioned_dim_sizes, y_partitioned_dim_sizes) + self.assertEqual(x.inner_dim_sizes.eval().tolist(), + y.inner_dim_sizes.eval().tolist()) + + @parameterized.parameters([ + dict(value='x', expected_dim_sizes=[]), + dict(value=['a', 'b', 'c'], expected_dim_sizes=[3]), + dict(value=[['a', 'b', 'c'], ['d', 'e', 'f']], expected_dim_sizes=[2, 3]), + dict( + value=[[['a', 'b', 'c'], ['d', 'e', 'f']]], + expected_dim_sizes=[1, 2, 3]), + dict( + value=ragged.constant_value([['a', 'b', 'c'], ['d', 'e']]), + expected_dim_sizes=[2, [3, 2]]), + dict( + value=ragged.constant_value([[['a', 'b', 'c'], ['d', 'e']]]), + expected_dim_sizes=[1, [2], [3, 2]]), + dict( + value=ragged.constant_value([[['a', 'b', 'c'], ['d', 'e', 'f']]], + ragged_rank=1), + expected_dim_sizes=[1, [2], 3]), + dict( + value=ragged.constant_value([[[[1], [2]], [[3], [4]]], + [[[5], [6]]]], ragged_rank=1), + expected_dim_sizes=[2, [2, 1], 2, 1]), + dict( + value=ragged.constant_value([[10, 20], [30]]), + expected_dim_sizes=[2, [2, 1]]), + # Docstring examples: + dict(value=[[1, 2, 3], [4, 5, 6]], expected_dim_sizes=[2, 3]), + dict( + value=ragged.constant_value([[1, 2], [], [3, 4, 5]]), + expected_dim_sizes=[3, [2, 0, 3]]), + dict( + value=ragged.constant_value([[[1, 2], [3, 4]], [[5, 6]]], + ragged_rank=1), + expected_dim_sizes=[2, [2, 1], 2]), + dict( + value=ragged.constant_value([[[1, 2], [3]], [[4, 5]]]), + expected_dim_sizes=[2, [2, 1], [2, 1, 2]]), + ]) + def testFromTensor(self, value, expected_dim_sizes): + shape = ragged.RaggedTensorDynamicShape.from_tensor(value) + expected = ragged.RaggedTensorDynamicShape.from_dim_sizes( + expected_dim_sizes) + with self.cached_session(): + self.assertShapeEq(shape, expected) + + @parameterized.parameters([ + dict(dim_sizes=[], rank=0, expected_dim_sizes=[]), + dict(dim_sizes=[], rank=3, expected_dim_sizes=[1, 1, 1]), + dict(dim_sizes=[3], rank=1, expected_dim_sizes=[3]), + dict(dim_sizes=[3], rank=3, expected_dim_sizes=[1, 1, 3]), + dict(dim_sizes=[2, 3], rank=3, expected_dim_sizes=[1, 2, 3]), + dict(dim_sizes=[3, [3, 2, 4]], rank=2, expected_dim_sizes=[3, [3, 2, 4]]), + dict( + dim_sizes=[3, [3, 2, 4]], + rank=4, + expected_dim_sizes=[1, 1, 3, [3, 2, 4]]), + dict( + dim_sizes=[3, [3, 2, 4], 2, 3], + rank=5, + expected_dim_sizes=[1, 3, [3, 2, 4], 2, 3]), + ]) + def testBroadcastToRank(self, dim_sizes, rank, expected_dim_sizes): + shape = ragged.RaggedTensorDynamicShape.from_dim_sizes(dim_sizes) + expected = ragged.RaggedTensorDynamicShape.from_dim_sizes( + expected_dim_sizes) + broadcasted_shape = shape.broadcast_to_rank(rank) + with self.cached_session(): + self.assertShapeEq(broadcasted_shape, expected) + self.assertEqual(broadcasted_shape.rank, rank) + + @parameterized.parameters([ + #========================================================================= + # dimension[axis] is uniform inner; and row_lengths is a scalar + #========================================================================= + # shape: [BROADCAST(UNIFORM), UNIFORM, UNIFORM] + dict(axis=0, + row_length=3, + original_dim_sizes=[1, 4, 5], + broadcast_dim_sizes=[3, 4, 5]), + + # shape: [UNIFORM, UNIFORM, BROADCAST(UNIFORM)] + dict(axis=2, + row_length=5, + original_dim_sizes=[3, 4, 1], + broadcast_dim_sizes=[3, 4, 5]), + + # shape: [UNIFORM, RAGGED, BROADCAST(UNIFORM)] + dict(axis=2, + row_length=5, + original_dim_sizes=[3, [3, 2, 8], 1], + broadcast_dim_sizes=[3, [3, 2, 8], 5]), + + # shape: [UNIFORM, RAGGED, RAGGED, UNIFORM, UNIFORM, BROADCAST(UNIFORM)] + dict(axis=5, + row_length=5, + original_dim_sizes=[2, [2, 1], [3, 2, 8], 3, 4, 1], + broadcast_dim_sizes=[2, [2, 1], [3, 2, 8], 3, 4, 5]), + + #========================================================================= + # dimension[axis] is uniform inner; and row_lengths is a vector + #========================================================================= + # shape: [UNIFORM, BROADCAST(UNIFORM)] + dict(axis=1, + row_length=[2, 0, 1], + original_dim_sizes=[3, 1], + broadcast_dim_sizes=[3, [2, 0, 1]]), + # shape: [UNIFORM, BROADCAST(UNIFORM), UNIFORM] + dict(axis=1, + row_length=[2, 0, 1], + original_dim_sizes=[3, 1, 5], + broadcast_dim_sizes=[3, [2, 0, 1], 5]), + + # shape: [UNIFORM, UNIFORM, BROADCAST(UNIFORM)] + dict(axis=2, + row_length=[2, 0, 1, 3, 8, 2, 3, 4, 1, 8, 7, 0], + original_dim_sizes=[4, 3, 1], + broadcast_dim_sizes=[4, 3, [2, 0, 1, 3, 8, 2, 3, 4, 1, 8, 7, 0]]), + + # shape: [UNIFORM, RAGGED, BROADCAST(UNIFORM)] + dict(axis=2, + row_length=[2, 5, 3], + original_dim_sizes=[2, [2, 1], 1], + broadcast_dim_sizes=[2, [2, 1], [2, 5, 3]]), + + # shape: [UNIFORM, RAGGED, UNIFORM, UNIFORM, BROADCAST(UNIFORM), UNIFORM] + dict(axis=4, + row_length=list(range(18)), + original_dim_sizes=[2, [2, 1], 3, 2, 1, 8], + broadcast_dim_sizes=[2, [2, 1], 3, 2, list(range(18)), 8]), + + #========================================================================= + # dimension[axis] is uniform partitioned; and row_lengths is a scalar + #========================================================================= + # shape: [BROADCAST(UNIFORM), RAGGED] + dict(axis=0, + row_length=3, + original_dim_sizes=[1, [5]], + broadcast_dim_sizes=[3, [5, 5, 5]]), + + # shape: [BROADCAST(UNIFORM), UNIFORM, RAGGED] + dict(axis=0, + row_length=2, + original_dim_sizes=[1, 3, [3, 0, 2]], + broadcast_dim_sizes=[2, 3, [3, 0, 2, 3, 0, 2]]), + + # shape: [BROADCAST(UNIFORM), RAGGED, RAGGED, UNIFORM, UNIFORM] + dict(axis=0, + row_length=3, + original_dim_sizes=[1, [3], [3, 5, 2], 9, 4, 5], + broadcast_dim_sizes=[3, [3, 3, 3], [3, 5, 2, 3, 5, 2, 3, 5, 2], + 9, 4, 5]), + + # shape: [BROADCAST(UNIFORM), UNIFORM, RAGGED, UNIFORM] + dict(axis=0, + row_length=2, + original_dim_sizes=[1, 2, [2, 1], [3, 5, 2], 2], + broadcast_dim_sizes=[2, 2, [2, 1, 2, 1], [3, 5, 2, 3, 5, 2], 2]), + + # shape: [UNIFORM, BROADCAST(UNIFORM), RAGGED, UNIFORM] + dict(axis=1, + row_length=2, + original_dim_sizes=[3, 1, [4, 0, 2], 5], + broadcast_dim_sizes=[3, 2, [4, 0, 2, 4, 0, 2], 5]), + + # shape: [UNIFORM, BROADCAST(UNIFORM), RAGGED] + dict(axis=1, + row_length=1, + original_dim_sizes=[2, 3, (1, 2, 3, 4, 5, 6)], + broadcast_dim_sizes=[2, 3, (1, 2, 3, 4, 5, 6)]), + + #========================================================================= + # dimension[axis] is uniform partitioned; and row_lengths is a vector + #========================================================================= + # shape: [UNIFORM, BROADCAST(UNIFORM), RAGGED, UNIFORM] + dict(axis=1, + row_length=[4, 1, 2], + original_dim_sizes=[ + 3, # axis=0 + 1, # axis=1 (broadcast) + [3, 1, 2], # axis=2 + 5], # axis=3 + broadcast_dim_sizes=[ + 3, # axis=0 + [4, 1, 2], # axis=1 (broadcast) + [3, 3, 3, 3, 1, 2, 2], # axis=2 + 5]), # axis=3 + + # shape: [UNIFORM, BROADCAST(UNIFORM), RAGGED, RAGGED] + dict(axis=1, + row_length=[2, 0, 3], + original_dim_sizes=[ + 3, # axis=0 + 1, # axis=1 (broadcast) + [3, 1, 2], # axis=2 + [3, 1, 4, 1, 5, 9]], # axis=3 + broadcast_dim_sizes=[ + 3, # axis=0 + [2, 0, 3], # axis=1 (broadcast) + [3, 3, 2, 2, 2], # axis=2 + [3, 1, 4, 3, 1, 4, 5, 9, 5, 9, 5, 9]]), # axis=3 + + # shape: [UNIFORM, RAGGED, BROADCAST(UNIFORM), RAGGED, RAGGED, UNIFORM] + dict(axis=2, + row_length=[4, 1, 2], + original_dim_sizes=[ + 3, # axis=0 + [2, 0, 1], # axis=1 + 1, # axis=2 (broadcast) + [3, 2, 1], # axis=3 + [1, 0, 1, 0, 2, 3], # axis=4 + 5], # axis=5 + broadcast_dim_sizes=[ + 3, # axis=0 + [2, 0, 1], # axis=2 + [4, 1, 2], # axis=2 (broadcast) + [3, 3, 3, 3, 2, 1, 1], # axis=3 + [1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, # axis=4 + 2, 3, 3], + 5]), # axis=5 + + dict(axis=0, + row_length=2, + original_dim_sizes=[1, 1, 2, (2, 1)], + broadcast_dim_sizes=[2, 1, 2, (2, 1, 2, 1)]), + dict(axis=1, + row_length=(2, 1), + original_dim_sizes=[2, 1, 2, (2, 1, 2, 1)], + broadcast_dim_sizes=[2, (2, 1), 2, (2, 1, 2, 1, 2, 1)]), + dict(axis=2, + row_length=2, + original_dim_sizes=[2, (2, 1), 2, (2, 1, 2, 1, 2, 1)], + broadcast_dim_sizes=[2, (2, 1), 2, (2, 1, 2, 1, 2, 1)]), + dict(axis=3, + row_length=(2, 1, 2, 1, 2, 1), + original_dim_sizes=[2, (2, 1), 2, 1], + broadcast_dim_sizes=[2, (2, 1), 2, (2, 1, 2, 1, 2, 1)]), + ]) # pyformat: disable + def testBroadcastDimension(self, axis, row_length, original_dim_sizes, + broadcast_dim_sizes): + """Tests for the broadcast_dimension method. + + Verifies that: + + * `original.broadcast_dimension(axis, row_length) == broadcast` + * `broadcast.broadcast_dimension(axis, row_length) == broadcast` + * `broadcast.broadcast_dimension(axis, 1) == broadcast` + + Args: + axis: The axis to broadcast + row_length: The slice lengths to broadcast to. + original_dim_sizes: The dimension sizes before broadcasting. + original_dim_sizes[axis] should be equal to `1` or `row_length`. + broadcast_dim_sizes: THe dimension sizes after broadcasting. + """ + original_shape = ragged.RaggedTensorDynamicShape.from_dim_sizes( + original_dim_sizes) + broadcast_shape = ragged.RaggedTensorDynamicShape.from_dim_sizes( + broadcast_dim_sizes) + self.assertEqual(original_shape.rank, broadcast_shape.rank) + with self.cached_session(): + # shape[axis].value == 1 and row_length > 1: + bcast1 = original_shape.broadcast_dimension(axis, row_length) + # shape[axis].value > 1 and row_length == shape[axis].value: + bcast2 = broadcast_shape.broadcast_dimension(axis, row_length) + # shape[axis].value > 1 and row_length == 1: + bcast3 = broadcast_shape.broadcast_dimension(axis, 1) + + self.assertShapeEq(bcast1, broadcast_shape) + self.assertShapeEq(bcast2, broadcast_shape) + self.assertShapeEq(bcast3, broadcast_shape) + + @parameterized.parameters( + [ + # Broadcast scalar + dict(x_dims=[], y_dims=[], expected_dims=[]), + dict(x_dims=[], y_dims=[2], expected_dims=[2]), + dict(x_dims=[], y_dims=[2, 3], expected_dims=[2, 3]), + dict( + x_dims=[], + y_dims=[2, (2, 3), (5, 7, 2, 0, 9)], + expected_dims=[2, (2, 3), (5, 7, 2, 0, 9)]), + # Broadcast vector + dict(x_dims=[3], y_dims=[4, 2, 3], expected_dims=[4, 2, 3]), + dict(x_dims=[1], y_dims=[4, 2, 3], expected_dims=[4, 2, 3]), + dict(x_dims=[3], y_dims=[4, 2, 1], expected_dims=[4, 2, 3]), + dict( + x_dims=[3], + y_dims=[3, (2, 3, 1), 1], + expected_dims=[3, (2, 3, 1), 3]), + dict(x_dims=[1], y_dims=[3, (2, 1, 3)], expected_dims=[3, (2, 1, 3)]), + dict( + x_dims=[1], + y_dims=[3, (2, 1, 3), 8], + expected_dims=[3, (2, 1, 3), 8]), + dict( + x_dims=[1], + y_dims=[2, (2, 3), (5, 7, 2, 0, 9)], + expected_dims=[2, (2, 3), (5, 7, 2, 0, 9)]), + # Mixed broadcasting + dict( + x_dims=[ + 1, # axis=0 + 3, # axis=1 + (3, 0, 2), # axis=2 + 1, # axis=3 + 2, # axis=4 + ], + y_dims=[ + 2, # axis=0 + 1, # axis=1 + 1, # axis=2 + (7, 2), # axis=3 + 1, # axis=4 + ], + expected_dims=[ + 2, # axis=0 + 3, # axis=1 + (3, 0, 2, 3, 0, 2), # axis=2 + (7, 7, 7, 7, 7, 2, 2, 2, 2, 2), # axis=3 + 2, # axis=4 + ]), + dict( + x_dims=[2, (2, 1), 2, 1], + y_dims=[1, 1, 2, (2, 1)], + expected_dims=[2, (2, 1), 2, (2, 1, 2, 1, 2, 1)]), + ]) + def testBroadcastDynamicShape(self, x_dims, y_dims, expected_dims): + x_shape = ragged.RaggedTensorDynamicShape.from_dim_sizes(x_dims) + y_shape = ragged.RaggedTensorDynamicShape.from_dim_sizes(y_dims) + expected = ragged.RaggedTensorDynamicShape.from_dim_sizes(expected_dims) + result1 = ragged.broadcast_dynamic_shape(x_shape, y_shape) + result2 = ragged.broadcast_dynamic_shape(y_shape, x_shape) + with self.cached_session(): + self.assertShapeEq(expected, result1) + self.assertShapeEq(expected, result2) + + def testRepr(self): + shape = ragged.RaggedTensorDynamicShape.from_dim_sizes([2, (2, 1), 2, 1]) + self.assertRegexpMatches( + repr(shape), + r'RaggedTensorDynamicShape\(' + r'partitioned_dim_sizes=\(<[^>]+>, <[^>]+>\), ' + r'inner_dim_sizes=<[^>]+>\)') + + @parameterized.parameters([ + dict( + x=[[10], [20], [30]], # shape=[3, 1] + dim_sizes=[3, 2], + expected=[[10, 10], [20, 20], [30, 30]]), + dict( + x=[[10], [20], [30]], # shape=[3, 1] + dim_sizes=[3, [3, 0, 2]], + expected=ragged.constant_value([[10, 10, 10], [], [30, 30]], + dtype=np.int32)), + dict( + x=[[[1, 2, 3]], [[4, 5, 6]]], # shape = [2, 1, 3] + dim_sizes=[2, [2, 3], 3], + expected=ragged.constant_value( + [[[1, 2, 3], [1, 2, 3]], [[4, 5, 6], [4, 5, 6], [4, 5, 6]]], + dtype=np.int32, + ragged_rank=1)), + dict( + x=[[[1]], [[2]]], # shape = [2, 1, 1] + dim_sizes=[2, [2, 3], [0, 2, 1, 2, 0]], + expected=ragged.constant_value([[[], [1, 1]], [[2], [2, 2], []]], + dtype=np.int32, + ragged_rank=2)), + dict( + x=10, + dim_sizes=[3, [3, 0, 2]], + expected=ragged.constant_value([[10, 10, 10], [], [10, 10]])), + ]) + def testRaggedBroadcastTo(self, x, dim_sizes, expected): + shape = ragged.RaggedTensorDynamicShape.from_dim_sizes(dim_sizes) + result = ragged.broadcast_to(x, shape) + with self.cached_session(): + self.assertEqual( + getattr(result, 'ragged_rank', 0), getattr(expected, 'ragged_rank', + 0)) + if hasattr(expected, 'tolist'): + expected = expected.tolist() + self.assertEqual(result.eval().tolist(), expected) + + @parameterized.parameters([ + dict( + doc='x.shape=[3, (D1)]; y.shape=[3, 1]; bcast.shape=[3, (D1)]', + x=ragged.constant_value([[1, 2, 3], [], [4, 5]], dtype=np.int32), + y=[[10], [20], [30]], + expected=ragged.constant_value([[11, 12, 13], [], [34, 35]])), + dict( + doc='x.shape=[3, (D1)]; y.shape=[]; bcast.shape=[3, (D1)]', + x=ragged.constant_value([[1, 2, 3], [], [4, 5]], dtype=np.int32), + y=10, + expected=ragged.constant_value([[11, 12, 13], [], [14, 15]])), + dict( + doc='x.shape=[1, (D1)]; y.shape=[3, 1]; bcast.shape=[3, (D1)]', + x=ragged.constant_value([[1, 2, 3]], dtype=np.int32), + y=[[10], [20], [30]], + expected=ragged.constant_value( + [[11, 12, 13], [21, 22, 23], [31, 32, 33]], dtype=np.int32)), + dict( + doc=('x.shape=[2, (D1), 1]; y.shape=[1, (D2)]; ' + 'bcast.shape=[2, (D1), (D2)]'), + x=ragged.constant_value([[[1], [2], [3]], [[4]]], ragged_rank=1), + y=ragged.constant_value([[10, 20, 30]]), + expected=ragged.constant_value([[[11, 21, 31], [12, 22, 32], + [13, 23, 33]], [[14, 24, 34]]])), + dict( + doc=('x.shape=[2, (D1), 1]; y.shape=[1, 1, 4]; ' + 'bcast.shape=[2, (D1), 4]'), + x=ragged.constant_value([[[10], [20]], [[30]]], ragged_rank=1), + y=[[[1, 2, 3, 4]]], + expected=ragged.constant_value( + [[[11, 12, 13, 14], [21, 22, 23, 24]], [[31, 32, 33, 34]]], + ragged_rank=1)), + dict( + doc=('x.shape=[2, (D1), 2, 1]; y.shape=[2, (D2)]; ' + 'bcast.shape=[2, (D1), (2), (D2)'), + x=ragged.constant_value([[[[1], [2]], [[3], [4]]], + [[[5], [6]]]], + ragged_rank=1), + y=ragged.constant_value([[10, 20], [30]]), + expected=ragged.constant_value( + [[[[11, 21], [32]], [[13, 23], [34]]], + [[[15, 25], [36]]]])), + ]) + def testRaggedAddWithBroadcasting(self, x, y, expected, doc): + expected_rrank = getattr(expected, 'ragged_rank', 0) + x = ragged.convert_to_tensor_or_ragged_tensor(x, dtype=dtypes.int32) + y = ragged.convert_to_tensor_or_ragged_tensor(y, dtype=dtypes.int32) + result = x + y + result_rrank = getattr(result, 'ragged_rank', 0) + self.assertEqual(expected_rrank, result_rrank) + if hasattr(expected, 'tolist'): + expected = expected.tolist() + with self.cached_session(): + self.assertEqual(result.eval().tolist(), expected) + + +if __name__ == '__main__': + googletest.main() diff --git a/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py b/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py index 2fd31837c6..cb8e82c00d 100644 --- a/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py +++ b/tensorflow/python/ops/ragged/ragged_to_sparse_op_test.py @@ -23,6 +23,7 @@ from tensorflow.python.framework import errors from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import gradients_impl +from tensorflow.python.ops import math_ops from tensorflow.python.ops import ragged from tensorflow.python.platform import googletest @@ -178,7 +179,7 @@ class RaggedTensorToSparseOpTest(test_util.TensorFlowTestCase): ragged_rank=2) rt2 = ragged.constant([[[[9.0, 8.0], [7.0, 6.0]], [[5.0, 4.0]]]], ragged_rank=2) - rt = rt1 + rt2 * 2.0 + rt = ragged.map_inner_values(math_ops.add, rt1, rt2 * 2.0) st = ragged.to_sparse(rt) g1, g2 = gradients_impl.gradients(st.values, [rt1.inner_values, diff --git a/tensorflow/python/ops/ragged/ragged_util.py b/tensorflow/python/ops/ragged/ragged_util.py index 03f050de51..a832f937d1 100644 --- a/tensorflow/python/ops/ragged/ragged_util.py +++ b/tensorflow/python/ops/ragged/ragged_util.py @@ -25,6 +25,7 @@ from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops +from tensorflow.python.ops import gen_ragged_math_ops from tensorflow.python.ops import math_ops @@ -229,3 +230,51 @@ def _with_nonzero_rank(data): return array_ops.reshape( data, array_ops.concat([[1], data_shape], axis=0)[-data_ndims:]) + + +def lengths_to_splits(lengths): + """Returns splits corresponding to the given lengths.""" + return array_ops.concat([[0], math_ops.cumsum(lengths)], axis=-1) + + +def repeat_ranges(params, splits, repeats): + """Repeats each range of `params` (as specified by `splits`) `repeats` times. + + Let the `i`th range of `params` be defined as + `params[splits[i]:splits[i + 1]]`. Then this function returns a tensor + containing range 0 repeated `repeats[0]` times, followed by range 1 repeated + `repeats[1]`, ..., followed by the last range repeated `repeats[-1]` times. + + Args: + params: The `Tensor` whose values should be repeated. + splits: A splits tensor indicating the ranges of `params` that should be + repeated. + repeats: The number of times each range should be repeated. Supports + broadcasting from a scalar value. + + Returns: + A `Tensor` with the same rank and type as `params`. + + #### Example: + ```python + >>> repeat_ranges(['a', 'b', 'c'], [0, 2, 3], 3) + ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'c', 'c'] + ``` + """ + # Divide `splits` into starts and limits, and repeat them `repeats` times. + if repeats.shape.ndims != 0: + repeated_starts = repeat(splits[:-1], repeats, axis=0) + repeated_limits = repeat(splits[1:], repeats, axis=0) + else: + # Optimization: we can just call repeat once, and then slice the result. + repeated_splits = repeat(splits, repeats, axis=0) + n_splits = array_ops.shape(repeated_splits, out_type=dtypes.int64)[0] + repeated_starts = repeated_splits[:n_splits - repeats] + repeated_limits = repeated_splits[repeats:] + + # Get indices for each range from starts to limits, and use those to gather + # the values in the desired repetition pattern. + one = array_ops.ones((), repeated_starts.dtype) + offsets = gen_ragged_math_ops.ragged_range( + repeated_starts, repeated_limits, one) + return array_ops.gather(params, offsets.rt_dense_values) -- GitLab From 6d14dcba7225d205f2e7834551f42385802aa2cf Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Thu, 29 Nov 2018 11:07:17 -0800 Subject: [PATCH 546/672] Update the windows RBE toolchain image PiperOrigin-RevId: 223376167 --- third_party/toolchains/preconfig/win_1803/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/toolchains/preconfig/win_1803/BUILD b/third_party/toolchains/preconfig/win_1803/BUILD index 45209d260d..ac599bc2f3 100644 --- a/third_party/toolchains/preconfig/win_1803/BUILD +++ b/third_party/toolchains/preconfig/win_1803/BUILD @@ -17,7 +17,7 @@ platform( remote_execution_properties = """ properties:{ name:"container-image" - value:"docker://gcr.io/tensorflow-testing/tf-rbe-win@sha256:bd22c6bfff6afc1fa4304ec4411df2410d93645494117585332a4e2258358422" + value:"docker://gcr.io/tensorflow-testing/tf-rbe-win@sha256:fbc5713566011cc27fc3651183a6e7c2fd56fc6f006618c53f8fc71e742feebd" } properties:{ name: "OSFamily" value: "Windows" -- GitLab From 2e87f3502f28d8c112d4cd13fa3f23615b5fad5f Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Thu, 29 Nov 2018 11:11:30 -0800 Subject: [PATCH 547/672] More tf v2 API work. PiperOrigin-RevId: 223376950 --- .../core/api_def/python_api/api_def_LinSpace.pbtxt | 1 + tensorflow/core/api_def/python_api/api_def_Log.pbtxt | 1 + .../core/api_def/python_api/api_def_Log1p.pbtxt | 1 + tensorflow/tools/api/golden/v2/tensorflow.pbtxt | 12 ------------ tensorflow/tools/compatibility/renames_v2.py | 3 +++ 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/tensorflow/core/api_def/python_api/api_def_LinSpace.pbtxt b/tensorflow/core/api_def/python_api/api_def_LinSpace.pbtxt index b1de2cb207..3835661be5 100644 --- a/tensorflow/core/api_def/python_api/api_def_LinSpace.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_LinSpace.pbtxt @@ -2,6 +2,7 @@ op { graph_op_name: "LinSpace" endpoint { name: "lin_space" + deprecation_version: 2 } endpoint { name: "linspace" diff --git a/tensorflow/core/api_def/python_api/api_def_Log.pbtxt b/tensorflow/core/api_def/python_api/api_def_Log.pbtxt index ac4a4454c7..b6d2da6d32 100644 --- a/tensorflow/core/api_def/python_api/api_def_Log.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_Log.pbtxt @@ -5,5 +5,6 @@ op { } endpoint { name: "log" + deprecation_version: 2 } } diff --git a/tensorflow/core/api_def/python_api/api_def_Log1p.pbtxt b/tensorflow/core/api_def/python_api/api_def_Log1p.pbtxt index 5a2d77a417..e3da451de3 100644 --- a/tensorflow/core/api_def/python_api/api_def_Log1p.pbtxt +++ b/tensorflow/core/api_def/python_api/api_def_Log1p.pbtxt @@ -5,5 +5,6 @@ op { } endpoint { name: "log1p" + deprecation_version: 2 } } diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt index 98ea3b6839..2a30688b46 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt @@ -736,10 +736,6 @@ tf_module { name: "less_equal" argspec: "args=[\'x\', \'y\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " } - member_method { - name: "lin_space" - argspec: "args=[\'start\', \'stop\', \'num\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } member_method { name: "linspace" argspec: "args=[\'start\', \'stop\', \'num\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " @@ -752,14 +748,6 @@ tf_module { name: "load_op_library" argspec: "args=[\'library_filename\'], varargs=None, keywords=None, defaults=None" } - member_method { - name: "log" - argspec: "args=[\'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } - member_method { - name: "log1p" - argspec: "args=[\'x\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " - } member_method { name: "logical_and" argspec: "args=[\'x\', \'y\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], " diff --git a/tensorflow/tools/compatibility/renames_v2.py b/tensorflow/tools/compatibility/renames_v2.py index ba93cbbfa9..dda7943821 100644 --- a/tensorflow/tools/compatibility/renames_v2.py +++ b/tensorflow/tools/compatibility/renames_v2.py @@ -259,8 +259,11 @@ renames = { 'tf.layers.separable_conv2d': 'tf.compat.v1.layers.separable_conv2d', 'tf.lbeta': 'tf.math.lbeta', 'tf.lgamma': 'tf.math.lgamma', + 'tf.lin_space': 'tf.linspace', 'tf.local_variables': 'tf.compat.v1.local_variables', 'tf.local_variables_initializer': 'tf.compat.v1.local_variables_initializer', + 'tf.log': 'tf.math.log', + 'tf.log1p': 'tf.math.log1p', 'tf.log_sigmoid': 'tf.math.log_sigmoid', 'tf.logging.DEBUG': 'tf.compat.v1.logging.DEBUG', 'tf.logging.ERROR': 'tf.compat.v1.logging.ERROR', -- GitLab From 5839858d0fff35ae9eb58d2697366a97a4944e86 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Thu, 29 Nov 2018 11:12:26 -0800 Subject: [PATCH 548/672] Make TF unittests use TEST_TMPDIR if it is set. PiperOrigin-RevId: 223377097 --- tensorflow/python/platform/googletest.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tensorflow/python/platform/googletest.py b/tensorflow/python/platform/googletest.py index 8141cf92c5..4d34c508da 100644 --- a/tensorflow/python/platform/googletest.py +++ b/tensorflow/python/platform/googletest.py @@ -104,10 +104,13 @@ def GetTempDir(): """Return a temporary directory for tests to use.""" global _googletest_temp_dir if not _googletest_temp_dir: - first_frame = tf_inspect.stack()[-1][0] - temp_dir = os.path.join(tempfile.gettempdir(), - os.path.basename(tf_inspect.getfile(first_frame))) - temp_dir = tempfile.mkdtemp(prefix=temp_dir.rstrip('.py')) + if os.environ.get('TEST_TMPDIR'): + temp_dir = tempfile.mkdtemp(prefix=os.environ['TEST_TMPDIR']) + else: + first_frame = tf_inspect.stack()[-1][0] + temp_dir = os.path.join(tempfile.gettempdir(), + os.path.basename(tf_inspect.getfile(first_frame))) + temp_dir = tempfile.mkdtemp(prefix=temp_dir.rstrip('.py')) def delete_temp_dir(dirname=temp_dir): try: -- GitLab From b5e3e7c66523c3dbb6324b2fb093fb8fc253102c Mon Sep 17 00:00:00 2001 From: Guangda Lai Date: Thu, 29 Nov 2018 11:19:56 -0800 Subject: [PATCH 549/672] Choose the TensorRT version automatically based on cuda version. PiperOrigin-RevId: 223378409 --- tensorflow/contrib/tensorrt/convert/convert_graph.cc | 2 +- tensorflow/contrib/tensorrt/convert/convert_nodes.cc | 2 +- tensorflow/contrib/tensorrt/convert/convert_nodes.h | 2 +- tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc | 2 +- .../contrib/tensorrt/custom_plugin_examples/inc_op_plugin.h | 2 +- tensorflow/contrib/tensorrt/kernels/trt_engine_op.h | 2 +- tensorflow/contrib/tensorrt/log/trt_logger.h | 2 +- tensorflow/contrib/tensorrt/plugin/trt_plugin.h | 2 +- tensorflow/contrib/tensorrt/plugin/trt_plugin_factory.h | 2 +- tensorflow/contrib/tensorrt/plugin/trt_plugin_factory_test.cc | 2 +- tensorflow/contrib/tensorrt/plugin/trt_plugin_utils.h | 2 +- tensorflow/contrib/tensorrt/resources/trt_allocator.h | 2 +- tensorflow/contrib/tensorrt/resources/trt_int8_calibrator.h | 2 +- tensorflow/contrib/tensorrt/resources/trt_resources.h | 2 +- tensorflow/contrib/tensorrt/shape_fn/trt_shfn.cc | 2 +- tensorflow/contrib/tensorrt/tensorrt_test.cc | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_graph.cc b/tensorflow/contrib/tensorrt/convert/convert_graph.cc index 3b32f72bc1..ecbd4ea802 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_graph.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_graph.cc @@ -59,7 +59,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT #include "cuda/include/cuda_runtime_api.h" -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { namespace convert { diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index fee095668e..938cadc7c4 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -48,7 +48,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" // Check if the types are equal. Cast to int first so that failure log message // would work! diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.h b/tensorflow/contrib/tensorrt/convert/convert_nodes.h index 54e19b7395..daa3111192 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.h +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.h @@ -34,7 +34,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index 443033379f..4790622e83 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -44,7 +44,7 @@ limitations under the License. #if GOOGLE_TENSORRT #include "cuda/include/cuda.h" #include "cuda/include/cuda_runtime_api.h" -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/custom_plugin_examples/inc_op_plugin.h b/tensorflow/contrib/tensorrt/custom_plugin_examples/inc_op_plugin.h index 189e9c939b..f658e45569 100644 --- a/tensorflow/contrib/tensorrt/custom_plugin_examples/inc_op_plugin.h +++ b/tensorflow/contrib/tensorrt/custom_plugin_examples/inc_op_plugin.h @@ -23,7 +23,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h index b545f497f3..b801480a30 100644 --- a/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h +++ b/tensorflow/contrib/tensorrt/kernels/trt_engine_op.h @@ -31,7 +31,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT #include "cuda/include/cuda_runtime_api.h" -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/log/trt_logger.h b/tensorflow/contrib/tensorrt/log/trt_logger.h index 96ccacb791..58d9d05d01 100644 --- a/tensorflow/contrib/tensorrt/log/trt_logger.h +++ b/tensorflow/contrib/tensorrt/log/trt_logger.h @@ -20,7 +20,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/plugin/trt_plugin.h b/tensorflow/contrib/tensorrt/plugin/trt_plugin.h index 754920b60c..167e8197a7 100644 --- a/tensorflow/contrib/tensorrt/plugin/trt_plugin.h +++ b/tensorflow/contrib/tensorrt/plugin/trt_plugin.h @@ -24,7 +24,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory.h b/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory.h index bbae9fb65c..51393d2092 100644 --- a/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory.h +++ b/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory.h @@ -27,7 +27,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory_test.cc b/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory_test.cc index 129bdcdbc2..2346cb9ba0 100644 --- a/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory_test.cc +++ b/tensorflow/contrib/tensorrt/plugin/trt_plugin_factory_test.cc @@ -23,7 +23,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/plugin/trt_plugin_utils.h b/tensorflow/contrib/tensorrt/plugin/trt_plugin_utils.h index 274ce42fec..5ded702c41 100644 --- a/tensorflow/contrib/tensorrt/plugin/trt_plugin_utils.h +++ b/tensorflow/contrib/tensorrt/plugin/trt_plugin_utils.h @@ -23,7 +23,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/resources/trt_allocator.h b/tensorflow/contrib/tensorrt/resources/trt_allocator.h index f857a9de05..b03fe7b8b5 100644 --- a/tensorflow/contrib/tensorrt/resources/trt_allocator.h +++ b/tensorflow/contrib/tensorrt/resources/trt_allocator.h @@ -22,7 +22,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" #endif // GOOGLE_TENSORRT #endif // GOOGLE_CUDA diff --git a/tensorflow/contrib/tensorrt/resources/trt_int8_calibrator.h b/tensorflow/contrib/tensorrt/resources/trt_int8_calibrator.h index 65466c9741..e8f08ad9f4 100644 --- a/tensorflow/contrib/tensorrt/resources/trt_int8_calibrator.h +++ b/tensorflow/contrib/tensorrt/resources/trt_int8_calibrator.h @@ -26,7 +26,7 @@ limitations under the License. #if GOOGLE_TENSORRT #include "cuda/include/cuda_runtime_api.h" -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/resources/trt_resources.h b/tensorflow/contrib/tensorrt/resources/trt_resources.h index aac9e5c7bd..0be5d44f7a 100644 --- a/tensorflow/contrib/tensorrt/resources/trt_resources.h +++ b/tensorflow/contrib/tensorrt/resources/trt_resources.h @@ -31,7 +31,7 @@ limitations under the License. #if GOOGLE_CUDA #if GOOGLE_TENSORRT -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace tensorrt { diff --git a/tensorflow/contrib/tensorrt/shape_fn/trt_shfn.cc b/tensorflow/contrib/tensorrt/shape_fn/trt_shfn.cc index f30dba59ad..ad9703325f 100644 --- a/tensorflow/contrib/tensorrt/shape_fn/trt_shfn.cc +++ b/tensorflow/contrib/tensorrt/shape_fn/trt_shfn.cc @@ -23,7 +23,7 @@ limitations under the License. #if GOOGLE_TENSORRT #include "tensorflow/contrib/tensorrt/log/trt_logger.h" #include "tensorflow/core/lib/core/errors.h" -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace shape_inference { diff --git a/tensorflow/contrib/tensorrt/tensorrt_test.cc b/tensorflow/contrib/tensorrt/tensorrt_test.cc index 769982c645..102a1d3891 100644 --- a/tensorflow/contrib/tensorrt/tensorrt_test.cc +++ b/tensorflow/contrib/tensorrt/tensorrt_test.cc @@ -22,7 +22,7 @@ limitations under the License. #if GOOGLE_TENSORRT #include "cuda/include/cuda.h" #include "cuda/include/cuda_runtime_api.h" -#include "tensorrt/include/NvInfer.h" +#include "tensorrt/NvInfer.h" namespace tensorflow { namespace { -- GitLab From fd6ecc5e9d813a6c2e5c74603f891aac19ed2618 Mon Sep 17 00:00:00 2001 From: Leon Graser Date: Thu, 29 Nov 2018 11:27:15 -0800 Subject: [PATCH 550/672] fixed typo from of to or --- tensorflow/go/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/go/README.md b/tensorflow/go/README.md index 3989f9b25a..f53f6fc989 100644 --- a/tensorflow/go/README.md +++ b/tensorflow/go/README.md @@ -23,7 +23,7 @@ from source. - [bazel](https://www.bazel.build/versions/master/docs/install.html) - Environment to build TensorFlow from source code - ([Linux of macOS](https://www.tensorflow.org/install/source)). + ([Linux or macOS](https://www.tensorflow.org/install/source)). If you don't need GPU support, then try the following: ```sh -- GitLab From 7beeb3d3fb3a1471a20bb82c1749196f65ba9a73 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Thu, 29 Nov 2018 11:20:49 -0800 Subject: [PATCH 551/672] Add tiling-based layout to protobuf. PiperOrigin-RevId: 223378550 --- .../g3doc/images/xla_array_layout_figure1.png | Bin 0 -> 20398 bytes .../g3doc/images/xla_array_layout_figure2.png | Bin 0 -> 7913 bytes .../compiler/xla/g3doc/layout_with_tiling.md | 159 ++++++++++++++++++ tensorflow/compiler/xla/layout_util.cc | 7 + tensorflow/compiler/xla/shape_util.cc | 17 ++ tensorflow/compiler/xla/xla_data.proto | 24 +++ 6 files changed, 207 insertions(+) create mode 100644 tensorflow/compiler/xla/g3doc/images/xla_array_layout_figure1.png create mode 100644 tensorflow/compiler/xla/g3doc/images/xla_array_layout_figure2.png create mode 100644 tensorflow/compiler/xla/g3doc/layout_with_tiling.md diff --git a/tensorflow/compiler/xla/g3doc/images/xla_array_layout_figure1.png b/tensorflow/compiler/xla/g3doc/images/xla_array_layout_figure1.png new file mode 100644 index 0000000000000000000000000000000000000000..00cefe4c7806c1c09dd51499375e720bfb0baac6 GIT binary patch literal 20398 zcmeAS@N?(olHy`uVBq!ia0y~yU@m81V07bPV_;x7*_CF_z~Eo%>EaktaqI0}-Wrjs zd;fp@8~sjqEn{HtY_5!u6(I{3En2|FtHLNEqNSmg;ULGv!ofdr!Hq6f*52@dEXRv& zVxl6t8X93aiDyjYFNOX8|EQ%GsZYLXGx4V9rupArm&Vl1w6y8b~&{Zx(@?D zG7i5@FSYERCG=W(}cw{DpCgAX7< zhu;MUT6S&?^ES?%ymQ@z!^|MTw})9)_kQ1bkF(;ir3*;lLLIO9!*^zUU~{&_uWYdf ziDtD5EZhztQ(P!Jv$*6(EGk%wR{G=uP zBy8rg#Px@=G-c$#qV~U{au;9y7PX58=i>w^ z*kb=PEIL^)zyAu)MHaAtvX%F;Z?{xuz5ng_3w=+rkDc zX4iCA?D8I~*%!8V9R};nwZ5^|h;d!;l;0(rZ`G~VeNq5&r^D^V#>wxDbQeziopm=h za7kK6nmL~=$b=UE>KDhN)?Ue~ocO}FEY8X$xcX<;+G)oUL8dhnWLTWua*J`bXjEXty%x-$s1qz%w|4Q z2C`e>S=Ee$poFb^C(cT2f4ejD#ww%f-y?E!m!wIg1#B&f>Nh`F{6{5dvs+xXRi0n} zvTLHxW-b6FuLZIaxqi<~TXK4?ysh+l@ZpFk@4mfCrh8{SUOP>GZb){BLbl)i15=`{t(K3yqA7ens1dXZ)?vD7|$p zd+L(g*RSiIc-yjf{ztX2_1O&PcW=HrsgjkkW#MMakLR8QC^-B&=;+z9)c8VMg!+qS zpBbyS+!7Pc;aU@x(-hY(7nJihe%jSlHrHQvmK1XLrLM9}Tlh!+qHyNje-{=y=X3wC z6@FEBEOAHo$=A0|o!>eAr}Uv}76*+I!B=Z#*p4*#t=rUdxWP;$?_1Q`JGZNs+Lm4W z8hzID&kw#m|D{rnZhr3>_S$hr_b%Dp?#Hrf0$g`IW@cc>?fZ7?Wr2^_JU5*ezt^;Y z^?zZ>sdiSM8W#P&yeWU~fu%1z=hS)K4-hE0tADXFW_4+C{_&k>KX0}*$#AVa$8S8(}`aMay-m20kO{Jwd%QqD>w z==)(?pKH}Q(p-%5a(~Lcc1e$ZR>9k4rgB~S-Iuy|@6Q%ry}m48xZnA0-L84dAFjt}P%JH(h%P;N9Tl3xJ z>YcC$n`LFMg}$gfvvJ<>D`79{=B=ABH8s}m!Or}~*B`n6=6&WnePwdV>!0fkoWt*a zzy5x?iTRzG0o%gbn|H~1>x=L3-}Y7F<>w9i^orjtKd*dh}DKed_-Ep6}oH{OkE%`Ek0KgHERH zNftilBoBX_0s%oX=%=jWQ= ziJZRqZ0F}FUg=xPi_RZqIj*&Q`ihkg&&i}4GJ0>neOUCtwkoH7x$8x|epOC+-=bg7 z)cSH`mfSR#k7FvbhfHj^ExR7hGcftnT()IW7MSD~;as|7}Q|`qNhP;_(lb^Q!jS^43U9 zc=LHzmcZ%@{MK{iJg*zxezz-r@okg$^0w!eo_oBrKK{$DXD!xM?-*Kq|4SIE2yZko za>_Tn6?Q;6-!JCw{B7d1Cts4gcVMY{+dakVW#;~KBt_=l6U%onQ2(UMRlY2I#hG-A zCmEk5f^8lyKG!q-SxU_O$6Dt(_q$jJn)Yu$_JyzP6Zf%QdzZCY3!gcXZ|0}oVd>02 zH+d=J!Oi~_9yFYvrPgl4_>k4^If^VN9^66_uRZLYCLbVoOTG8>#q>@ z@%iBQsU{;}cYoS5zuoC)(&fvu49cALZ|;8=X?M1rPfADo&U@|U*S(o1|Ni^7R`<+# z@ycz%FY07tfA2i=d)G|P-dDDH&JX?Kjd|nhY>U*sh?=L*K3BWN{Kn?HET0da{P(P7 z_p_P{j0}zmI~bCD|DO~ql(=wh#)rwtRqk4I9@bSEz2N0uc6{YFOZDPg$w__^-(Q}r zo04l{eP^a{RQiwfxw+Qrf6gWE@YC5`>vv?Yv#~U9xt;oL&u35SgNqN(eVMqrTq(E7 zYu0Y@6P&j98gdS~6eb_PChM{1_!*vsYii}r6@FNKJUeSg_NxoGG9I2ww|~8t@7{vP zJg!&oCC{(jbN0<+h4Xf5Cf{V{)|TWR|9Lad?tFb`y7jL;rx&qSe{bi0<~+e`|MA{! z=k2za8|`O)e0HCRdHU>UKc~4@uD!mC+3X>oL-mGf&J7Zm>sMIHux&|Qc3t)MoRD{) z=WH;&!X;(JS;7>?eJHj_cw6j^8=a}%hvrtEvs4S&nSID>mh`(h2OhpH{cPP?{_eHx zwQC19zJ2rkbMKZj8OIf`f!r$1Tkd=3I4AGhWZ}cHiCZ2&zA__|zbILrZ^mt}vnnQY z&lX(p?fs+o>*^iV*$+bBtlX{hJ?}Qp`kr0B`3hgEb7KxpEnsJ0xF9xj@}<4JXL(*+ z5t$ju6FldhWxjsrYSmqSOy7UaS)nGAxFh=hfo+qUILg;4c3Yj%kFLJq6%~!aSx-H5XGERxtGoRzr+7{I>|YOknIGo0R_0a-zGGluxK*}8`u)7d zjg1B2smuJ{Kb!mIa4FNO$&+d&P^|q;{ zf9k%*Q~t~)>d&iVb3CnQ3BNm|GrelQ%>3tONAF&~;_%{TUSIC>w!XEi#SD)>ugtg` zx-B^PX58Vq*=ff#1Lvi0%l1g@K0H^r=+CsIf-Kd!&+iB9FqY2?nKA!jXQ|gBUCWCH z?9$CY{L}kpnf5L>?^E7o$vBzRv^%lyzDI4je%a@O(+*|^299pYMWIP)Q_p-}qkZjU zsnE`&rJI&7T2?Jg`A;h33eV4-xx+R6)}5DpZfXJHyVARI*Q8yx=?^mI ze$}P+XP(!Ap<~-%yW}$xf?3MnAASGij_KXMWx_7kWqtoD7Q>DLC;d&${VT-s+p$L2R}`25TF9ZSk3)^(fRPXG}4qvQme$iuruhDz? z>WF2Qb=GII_gt4beeUedWv`hhDSfuyd$s1p=JUc&mhG6f;zmXtyVjZa9lQNZFYZyB zs#c-?`MMYbg94k+`*vgRXL7;WA*dy{VT<9jnp?q&t2GJr+!ZOOlSPUc>>mZ z8SS`z(q{=@aoRj@&b$kLAN7{xR?Yo1=l87R>pt7eHN7?`an`)IB0HRWBNyDUvn)#! zF>$u}Y{VF-`OA*QMESDu3@OOXXdgd;Nyp?rVZuzF&_#e!*rx(|)U4$F^n0wd+1J z{8~HpF>mKOex7Z!f9IMUuiH{S|7^R&uZrl|LP?Aa3>VJ*_}ann@yON^_b~T+pbi^H zxkLMtsL6%PcZ+RUoGZ-0z|dm7z`6Kp#;@eFfKk?n}o5jzjRNgLE_x)9o?R9E-{hN!AAK33Iwf^Gi4kx|GP_1H;4WHHzoMq zy~)$Qwa+cTAFH4=^VX-&pXcA-Q~6oy`R}Kvr{_Q0F3-Tgu<_dAEX%OlnOke06|Ih} z2%aahH$L$8y?=MvgUkxMWd7W`{&aD+@l${4d6WLO=AX>}ULWziZtc~yGbbiF*VnEt zz5Q?c(+k@ErytJ0qki>zub}0+*&*k5#PRLjy!+hWPetM(PxYcS>i-K5;g`2FDP8RPRZ5B#|q7#Nb4 z&c1prYVDn@*K5r#W!0{oCJ?gYvcU3%euw9_?NK-s<8x^4cG0~N!k?;CPcOW_-JQ35 zY4)_!3m^AQYhj6U;ou+&0Bc%XHDl>gC1Ld_>l^M%cHF4WR;*8AU|YhS@-qk0q0nq!*efdy+1wa z@ZJ9P!XHfTe6=cY@T&SUL6hHJW^zFI?c(Xv!&NtK%A4DtIxkrFZ}**x7nS&+dmtwv{Jk%S0}kT zLHu<=xb%l}7Awm-p80k^J9UqdS>-gB{YIWLL;mutr(P4Mh)i6i)t1V{z@VV^Yj(nQ z^DyZv1>siz#WeTl_?&5um3ZhE{dEHO(+{$hTOY3bbSMAxeYsQpnH#v3?_^$9oE6o) ze0q6Y&B7d6W3^`o^)}4feXK_!@N&01s7iAMMq#l5Z;9zQK#_w)7+ z&hqy8_cbQn3C@c%SpVwa$MBQSYkwcHxzQ^6ZVQ{gdgRah_t#IZFZ0~cp4uk(E-9$^ z`PTG)kM(hW?`01gfhw07x7UOTyzb50Rg#jiw=A*MdiVEtbLuwzTUFQ|_qu-CpXAKE zJ1y3`zvmqiu&g+%`ssJv@)n^tPLk7JN|>DJDs2T1FtNB*zb&yyTOX0XW5xOHPxe+{ zKN`E^@~z#|&)dKMaKGRFT--l}d57leO%AAi^zqY?rIH`T-);Gp_c5t0l`SXi+Z(0* zUyYNmK07ln_TlzzscUY%iM%O#(>Q%<>(yr|=Qn+;cZ-b3J$L7(Xx;1fW2?^2ogFKf zT6_M+mYc;|n>Mfgp5&3cZR`Kdo6@JXUd=mma^;703#Cq%oxZfRzHoi^tJvozFW!sm zocNdW?#{{7#I32P58eCE`u%gfK!=N3L~gc(w4U|1i0Wl$c5s*b+p4hpS*_f)DpKY{W*evHeU-oeZ+FYpwC5?| z_WSEMw_MGOFxYRk=D+SOx%x+)%|eS(Pk-WT-Tqy$^4(6^(8PE9MZaD90CKBYRIZnV zv|Y`Wz)!R7ryq~qarx^zyI0rN{@ScxZ@EQy!iGb0^-A<6cGyOzMf|UGTDdcL*S)#d z?i%V$E^yzWd`Iw|RmzUt`DbSZ96sC3fA6R3jE8xDe|>FNiCOtaoJDCOb0W{l5UIRF zHk{nLciz@V+P%EB_1EO&UB_Z~Tvl`cyZ@H!na5cXX_Y%Yii{ri!Hmq$aj+oG#SHX8l;l=$h9^m$gHclRp43rbq+xvKd{DCzInvFBWF zw%iQWnKNIO{l4AazqM}1<Mri9Nz8Jad;808^Zzk=v&;8sO-|S4P`RUfa;Db$y!#6C_kX`{WK>%) z_x8NMCu@yrPP9&{{Q9)9b+_hbwUd|i^QPJVd22qY?&Srm?U@@cueYw-8M^N59;*oj z=GxU$-c%+}t%>=!WJ&s**yr2c*S+6$Yr^(_59eItFPD1b<*gbNs5r6k@vHmm4!)a} zee3Q9pF^_HI5X6lJj?o!tibe#@48m2o$$`zn;q}>U8lnCLDRv~rZ|Cze#~>(toPQO zWPN^Z=iB-3-%Klyzb}`uWA}$gj$5an-~Ynq{%@VgdFkIDu?oHmVw)dXeN+0~7TbN6 z{^#tToBaG7&lP2Vr&r=*{q*4A*Y~znZFMPopBH#u*0j9E8tRC}&-!LrHx!5$?U1fJ zy2DKL-Ii9_cb}#`yS2C4@#-B@v3DgF%f8*YyCoy$&7r&dYK3N6g(@9AYHC}RntJ6< zBQ)i$*tz&wUjh4;<%u(ygWIm`eEVpN;I|EDba&sIAib%GiL*S)|NF7e(%H>%YYxw4 zGnXw}dDy6(XZMnGxtE{&ZLEIVG$+8dJ@sAf>$>WQXB~pfS?jOApX=~_b@=;<(#v`H z^CHqxm%6z1{@VY#yGvzLNv7}X`|(P*w*?lnBm1H)l_}Tu&Px}~b4xT=%iYU~zyA7* z@tgHl2fO0d+g9oC`DhPHo?UTk<_0`nZvSh2mEwE-d^>&a^ceYw9o0|G^{@J^`1Bx| z|Hk#q6Su1$m|AZAu345pZ`+;s=lE6by#4(*O49Zj({9_{wJU4q3V+J`|IbCT{_N3j zE!wX8YZY#AhJJgqa_2eOPg|Zo3xc~WIYJE-+6!!3toLuLxLM!2OXLv$`(3J6mI~yZ z{~x!)TXD^v*T+6gbBfsBSNhHYmL;vT-bqa3ESXYp+^T#{@o}qig*$@pILceBv)--P z*)8_&(xpp9mo8s+{}e9>j>>h-?bccEILgmi&9q9K%=fxXEw?Lm$K_Jv&FkdT`F~#f zYO;6x{l9yEelyZ>Y}?(t{jPfO`W@TueVyzct9zYSTDf@rKEn$I+pAyuZu<3Yb#4CX zxrRR9a?W$>+*up5`A(dZ+w>`wyPurB^}4(3{sisylDab^uiw^PQLz2jKAoBKN>}dn zTXD_6`uhI=2mRkHd{;HwFHAILM|A0T=c506`>*VL_ci|AbZxiZ$=U1AO{px-<1@K) zx8!?HWYPUUR@ZH}RnO(wo3tUO%-3!2?I_bbYhyGg-rTHeq<`wa(%P4GuU7KK7H=;~ zb@}$@bKc=F0ZQc(Uk0` zN6qJDe=S(Pna6tT>Fn!gS8n!u!L6^ieRiCm?5DQ}4&8lw|LpXG;=EI*o_@bx{D<8C zkDI?eov3{5#OnPw#65QGR!raXih7JF6Z*Oy5;xGUI_O0l%u~}JJ z>6e?!5B%D7JuCQ&)xY2-XhxNocJtt&yA$=67A<*rE;8!rW&8Il%^$yW{~bR~e(gTn z3kBa_%fFu@{=Rxm+>YJFZu9Pb`IH;{?6mUsC+tG+PJLfL>CyG~UwF%>*8gj)t)1}D zulo6y)otec<*eQwyu38yOLlhqZrl7dlXhAzetTMff6?|kHK%`AZO?u`_ngC;z2%Or zySIPer!OskGfMxCrLXhd)@HqF_9A~xClqXdx?g@{^IY>gnYaJks*<$JTM=XZ`BcK8 zxozgL+M)XIZv>hjnL7Qt&!eT+w;nFIekF0{)2D(rH!Q4c(AMpZcXZk;@Ru}pS?Zzm#lbG^Y!Kd zwUCR6GZ(wf&5ysPIMd4H^3L4Hi_K3KpRd2aZ_VCvDVAi(cXb~R%`V%J{jT85HLmhs ze{ZFKetTMc$=vko4_K{qg0tV>Ic#M5C3ElH8HT35)t{^~K<>XRXPvuprQl4Hm5vU+=Q}qs|Jh(2^t69$Xbn{52|UES{gR%+4hx{azEI78D?`zLV< zx1G3u+U)j1Kj(ShZe)JA+!>Y^WukY1Gjv|Xm!G#dL%*zMvz_a*^!?1gZyT;pns9wi z!E)hc7L%8~2sDX61G0?W{cL_%DL9sca}!vPW|>QbNxKgFVmJRTlVeIel1X8 z4N7&1Gv6xQ*}8S9fXM^fePym0-imuZ9oGG(qMfMQy1+62c7IyyHjyU2^EDqfvO7g{ zCBBdTe%)`0(6Jy6>$+cEvfmCxaVh@4xU}g0H0#6BT#nW6zrF9jUHY!r0#o zu0Q$;t{*%cTfJ&0_oA)aXYE$zs1gmkojNVd&kvsR*xje@%=vjWaqCRuv=e_Si&r1ccpA3j^563t_1Z5Mi9bEH z=jY9jC2VbNYkOyQq%JS5 zTyyR1$9O4lfUcW*`_9hEGtt#|-`jI8?MB+dt6rrGOJ46%`4`;`HgIdu>C?OWI71;} z4T_wzvZm#Rra3n@*sZ&_r}x(Gc6M0@yKq1@2(u_$%kGDVUzwx|`YRwwi5a2JcCbv}rldX%%p?f$*-}+1fc_ zd*>`0nNE?_Z$Z5Qgncj-tEzhU{kKV2K5 zzO9LD7dtaMS}<(3Y4Nj#bKY2rCT@KbX}sp|{7}KL)92=uYNW^cxkl((S3g_$^K*K5 z%hgTksq&|0TCZ1HV|Myhz4n99maBPljGtfl$}JYsay9Hu@p=3CHJ?tJui5{N_12dn zo&E89D*ip^7K@1&4BP$x-_`$I#s8=4#a5-e|FB;syguS#UjNIZ$v;_4POGhM{dST8 z60{5q4u9ipwD06@yjAwPh{>JBcVYe%qt#zQd1%GXl+p~E<4e8<;$Jc zwgUGZi=Xi^Feqdlc%9g~TT6D;$%`5BLTjhxZ{52r(=nr{;r45>l`~b1uV{vY(tH+Z z++Aa@V~hOjwP8;=i)?*%+?G7>EzC7*n*EDAafj}%uiq1Vi7h7N z{V(3__q3Ds__}_YwtIZ= z`(M`6)=dI6#6S&@ZtFOHojbOFud$u{aZdH?y7_xcR>hS0w$;wQw|wj2yN%4I2lEav z{J(8_Bes~=w48xq!DC6YoQQbs8&e~6+ZSKlm(z3Q%aY2MoC%fMdG5@Q!-U`5Ib>cm;Ub}KL3TH35+YFcAu{46&t+xT^=$@1s#_86aARlfJP6>pVe>+V(G zuX(* z$8}#US8uo3RvnvQT7Iu!dw%?ps<%o(F)^1nhlja=owNVU5lzdm+qqkVV$aN3I77Di z+q&MZx8zobM&x&2qZ+)3TGbgu2Cg5`%zOCz3b+bzde z5|I|oTYh=@nW?Ikr<08qcA4MF%)fU-+WqGA`VFN^W2?nOb`)Q~+A9_MecPQFP+E7m zy~MUCEJ1qR-lA*QO_!ywJG86jz?#JAlP6BRIA8f{Vdnd&O`M5V3r{f$Uy5qpS6DJ* z`MTWeYHev|>UUl)(LDF`o~{4J{dQX_md4DRlz0DIw|owt$(>l^Uwdwyj!J(XqgPqH z^vO91v5FnDjWWaDK2@Baa^hb2{fU$Ptz6I9zjxaG^1>N~!*hk7Y?(X1s_$>`AhIi{Y7wWYx*qqX~ zQ>5wKq?1oD zH7Iy9wkxh_Z!-`+@@uxjv{zr|%`|gWSGkxLJ3qf^=C-$L9ip=umaRRNl~i@(%kRC< z%4Cfq6Kszey`6aZ_|=C~!@Lb|FaORPnAvdqRdMaCow<<=w@bwQ-ivYdZ-ovT+QM5r+=h-FdtfBlp%aGu#M(N(Wnwabm2#kgZ~ z7i;I-Jj;`=Q?|88c;B3`N4wUZ`26|Y<8|fRGGpUj*yz6vES|SL`@Yr3Q;WC0?Yg3q zWOtx+?zd-eO|O6F%-CHS7A^g(@AZZ=%&Y5!>L0%A{P}75yt}LUqZOaeU9|sL=#J{2 z>8o9xYh(CM>*$HSyxLvBzF;qV!x9a~1y^T(n`9!O6?N;_ua=2v=5Nn_nDGtA_XHCCcSfBf`^4#mc-|p_RJ6$ZJUJ);EJm=zH zy9Mn$Z~MN@%haExSG$0F*6Ud%s%ke<*>}Xw?c8irlww>YH?em4Ts76=ebV(0-%Zng z8vcAv>5etGHwOJVv;L9Roxk6I&3^h}`v2f}Gpr2%9lGnS-??O&k&f_1zZt@_D-PXW zJyU(t;^>M`yEdq*ubVgdhUrm9e?9KE|N57A z@_lRM=`|H+}e?eQ$_EPsV{L!IdjpFNZyNd6K(}k6l*&nxDO?iSH?W zIl20W@0#*YDJQSD*z*0%zE2O!KR?#G^EdNW#?Skg{U;sQ_wC+4Yxh!b*Sx(`3&ed4 zRvAw@5#9c9<>|PvxC+A-BJ5Q-IH!YjP^QyKr*x zzqMH-V>{d+gx>L9H$ zJHKo_6y_?^vinldL^<0zal6e-b%L)yxcFd+ZP2+lX=)X3jSm0U^6@DC-j-Y9G&5M{ z{g;ePh9wMg3=9e~cMtKEOKtl1=dWqd)wdR!``+&BlYS?6YEygisnw_7yq{aJ-0}6| zndUbS8z)PCNRoV4(sst*-!`yrcT(Eh(r-C4gV$~_)%wP$zs$5;>dltpc|SkhT78J4 zTx#2z2UC~rO=Mh}5dvWmcPKXGUE9J?oy4lN1AkgSAlAj?2pqz6+S1{N(+0 zzsdGFH5(td>@I&NKGSfG+Ks(M)o;JPD|pUg^Y&o(Re`e+t-BXh7eD!YB=6e33UR3iz%)_?d}+jrtw;)r0xNANU04RlQKlxbXPA z3tDnET7`??{_busnUeoXE&!1nnOy*7Dq?&un*M~%&-w5iTIN$Bd z{r&KrbZ1cMm+&Va>PsfA(u<#Z_?qF5*H1M+ZQgG7EB` zEw^*ceJ1nw+xo@*zczDI#j7>9UN`3$r>C4e%bm`8?cE$h&#rx6eSaE!wAfjF>uYIV z^dxilXXnmNob%JN=ycD^PrHNtCw|}muQamwYQ*nd3ud#OX8pX0IeWYBY@Pjfd$&)K ztDmE@|6^O#_Vee@Ze+R>v^tVeW7EN`P($tAr%#@-{4;5_yRSa`r`o`YCprW_ozJiJ zF3Z0aQvG{zzum9Q>_7izESzq2@?_ZD6D{_s3=9k$x_9ncWKWDKd){vJbJ^Zcp3{Y& z91J}D=6&+jv=raz=jWZ}+ao(?s@By`&Y+(kc(-2HJ#})`EW7e9oj7wRI~zmCIh=XX>hToS*L9k$x2ue`WP_(Jeu1!lXW575Jp~ zCbq}Hr$?cQ$KAXXs(pAB7RQ691;C_dG-HKK4ARxu2cQkmhJ2OcI?*E z|MvP$=7GzR#@THda)mpjL5-eu(#PlPgRGcYuzcaWUOP!c{<4jH<+oP3eVgpOa{2YP z-Sg*O_P-}_$M_j&D%LOh=*+!u1HNyUKIRd+U2l^~agoMBy)6aH-FgHf_wEXv=Ct9^ zU9Q|eKbaU99AB|;C`1^4ki+!iLDmwp2GBYqZta$h?y!O|rSK9A;R~IaQ`{CsA zlj^a%L)P#4_2~y!`Ch+C&7H^F3e3-#vkyfx%%%cjqR( z<400=Y<~Ujk-?qJ4cWpE_0A;D)H+b`{KSb9FY;S=`-W*>mb2xp{j(Bm52*9nvO6rK z^3O;1W+utUR^4rVeR2QFn zqx<;0o%1L6PY7a zd;50PGd;J%M$$&0!O)j4U#>1WvFvJD_KVF;aZL4Gj9bb-tDXIQ_s+@U(}%LW^CN#v zKRere{l8}51X^{-mN(|&sOQC%`W z0+-ePd{lS$^__1|CY^rr$#MCqubH(>+~wkaHojcpkR*{PNTllVTiE906wQ#ThAtPPw-5F8W=4`rf>rAC+ak`&A_v)v*bN+8P@Ymb_ zeee6dvd_MypPTpbP3PaVqIoSqVzlJ2X|z4~s|=d%mjx>HY2YyI_0e@EiMgB#ph zGpZkbROf5^`Tl92^}7o5Gmq<^&n@5QyMvXZym#9{Oa0r9=d8aNi9I}bw|Tkax!Sw- z^XBONmfxp%q2T$ugVwnZI`?glEx0Q=$?WqShxXKWa|+kqb$-70-@%X5Pu{fMr?*~z zhRlr(XYNkC`?cytn0wgoIRCS;-OX`}B)9E6o%J;A_KJh+ZP{#jBNDHD@|$b8-fGRm zd$-<2e~n)_FUIcU5n=hZoquO;-pto#dMEbwoHZ{Et7Qu|LXPsJH_W)fBkx% z_AIPb^4+yN+tsf8*I&Q)TU6nU+y8%_um4v#<>0ZTmy-{~_;1r6mL6LcwZOF8|E`6f z(XTmL`Oo}Tmfx1oo0<6iPAb2gfX9w%%}Kgr4EIOF?CbBl= z{-c+r>*}9hn`!j6Y4h9Dx0m-%e|_%l?N<-;+*8_Z-)zzf3Vr@-k;g=xUY)Jc|2^vO zSJ`B}i_(4Z^@8igSlg;|7tWeRF9!MJ@?!gSJU^dgnLpIqQ}BKB^LgE`uiM`{eAivR z_KV|*_4R@e`4sM$?*6*_)4dtGtqTsm{d0ML-u2s-rsdP;O^>PGeeLnt-{)>Nwp#O+ z#lNpzQ(~`tF|TUww@1E}PmCS3NsO3MZE#uvb z7TFu>7}p)X`}_TV`B$&yzil|PA^Y7SzVgKU`H3?dPDZ@dz0HF4eI=@Ta!Hh>0q4;!uAnH-V!=gOYIV)iX_ z6K8@(c4PN|=8KzBS@())-&wn1pWFr3%WKzXuURmCnYX^cyA?Z?!Ly~WcN|t~on^hi z_eRoI&KB!Kv3Ee)lG1K$NUUA6VEYlS%IY(VUN)ZJeqq3La~|a;LQ&+m#Y>W)4B{ANzQsFF-_9#!e!UX-(R)pM6F-Gw+7@U(4f2EyIa>c zcr1Lzml3?Td}-A@*B#1tK+9^xr}gyo`~wxmKDBX<-q$WbJO>F#LmlA^>q~3Ggib#M z&v%%XcU+o1{mS0z@8*4Wzh2Z{+in^5TK?&}xeyyx?99&FFeK&9G zxwE|G_vOm>f3eALDtT}3r+4aKCkt?U2Vpo-UqAyc2n^+}XPMt+9^q2lHzzd**l?=$h zQTWf7{IKWC+IC;oo0(ki8~=&@W#PFWw_dY9-=m`*U$D4#XL(fK-UrvC9_D=$O}`o6 zT~{&JN2<(i?(Jo9x5C@zT@8-gk<4RS&e*a$Q`+s6<>Knw)7S6#>SX=Ga(nNtpG?24 z_O5yO?pF2XDBC-k4X1ZLsrg-Wu;p}W;4Rjz+igo9TkL-MwA=5k=h;|>hvzawCu&Iw zODeM~v1hHmX9?ybr0XJao17PBAOsqbfFc!h7uojH-4 zDjv?6vHi}RnOCLWJv(!Lnk9GA{j_suSIx7`pQUqZrtsx&p4Zovot`;SwL9(Hl-bMg z%6RSm+7`V!zUt-DTi+Yw`ksEDucj9E`F8!05*0`D{nE3f-kp=!>fEf+smqc@>od&M7y-PiSQz18I{zjDWP?Xz{~Rn<>!n8WyW-TuPAOUpLQ-e6^W zfiv{j7wcHL9a%1WU%!{PUb9WzzxsXIxgFDH?GBTh_S5MJ>r3gE+AAl9?0)(EyUV+k z#yr8*U!sf_a)An8#=^Jv)#oUD%sAdBJN44a;Edb|SKpR; z%q95n-SB>U*FO8NPP<<|(RBXY^<+uo%&l9?q&|H4wLmSza_{ktMTPs{l@+V`7hb<- zyRX8fTP+_suIplga)&iuoui*HGGYlZ3 zWgqIPfGW#|9dgqom9pL)vik>`dVQ!j!x+*&xVUHK=Y0_cf1A2C+_Kev_w)H=f4iS; zUqiUIynGr_m*2Yk`yR+ugv_cbtvm{+BtiZ`fp#l zHr)EYf4j<+$)~H|@BQANm{*_nt>^smbpN#+tIwXARi}}D45UW(^gd9d_y9A1%dcPe zORvX%Kl=Ip{-&m;^usp)`0ai?uujaYe|c$X`KNdR4nfm$p?lw)dBANL(2nJU0mb6r zsA6VdV2Bb0<*&eEcF<~ba2WN?vIgyX)?M&S?_Ab7A>oxfSFcdG!w8yf{JF<_`VN`N zKMzgQo%(61{?Yiekydcu`I9`4{Sf4_XW{FH^xu6cV+_hp?s z*0;6#-J@;K)~!0V&hpPw+wXhM=i4(dFj!5w{`|bSq^Z`vwv=g8J+EGL5AS9>EobW_ zIZM*(>`XRk*=aX7FAsTl<6~ybwL7^t6ei7DHJ$6{TToZLJ!$@j*B8zlI`o6He6m_+ zO8WoJ--`0`YOc)5xyp_OruA;p^Akyk7tJwe528^L7vGU#;wmEnZeSbr;W}eYM}V*UMUcDc<>P){m7t zFY_A)1-VSq+q%E@+01ml4^U69-F|PC<=2)|)CVVyuZDN)c|TZ*Toz5^EC)qQ!MviXHCxi1 zndh}N^qIK?SFhf(uHb@#^^KVYfsy(QU*GE+rTLtF+80#3Z0{zi4BN@iZrr|pJ*Iu> zx3|)tuiK>kUjP36la&3P#S+s%yJz~2n)77v&TCWTWx2I_sp10Li_ce|kDkB(U3;7K z+pVj2%OBlmzx?pGE#m&p^S+g^ZvTJq%AC-!Yb`gc->u|aEtT>8O=iXKsOIJCcYb^F zvhY&vx-~iTP0Md_ul&8grt<7RehC5H9YUbV`wIsT&lN5*dEz@KqWIE!?z!1}r+sVK zQndQYgR8UpZ?26#`}ykgwR?m5?WA;9h?q-EFuB3HEz3-XSr)7R?Z>HDIX^8vm@ZDZ{+w|kk_a3k9qSvlx z|FSnDHg5g;WbbX+xyv_Ko-LpK_Wj0v@r&L^{*z*4V0hrc?9pg>@b2Y^9hVc*nPQig z-j#a&iOcrk)_v*=|&HK$d>R&UsLc|WK6JI%D)b!!jYN#AmFS#6X2g^g?P&ih%nM^5|vKXI9p z-{uy)*?iaOyrEvt$KPJ}t&isZsLkI$|I6N`4_7tv+fSSMI5Oql`|K~ZEA6vm<*wXG zNOziRcQ5SozuSxMXJ@E902Pd(hvr%rmzIQL*3RFD)rQ7K3@LN;wWeQyMpw#MSWKj8+>0LHME^`i+StuoYm3Ahvw!vH}5LF z-Li}&G5^EGd;V{GzxX2!Q4v+_1vdA{uUCF?2S z{Sz(oq&98a(Leiqb#hbXUbkO&wjKSttF-%@#j{^>&(gQeniu`PdgbIwJL{j_EDQ_{ zGg@|Qs9&0UCg7~l{K>cc>~62VeERy8IMvI}5z8ExasCcjq8Q}d$fhYQAQUb1Zq7Zi zTAuS?pFZ26T6t*Nye0Z3-&elfTe9tOR_nXR`AmgVUzf>#Gv7Ax?;7JLA=PZL*Tv0* z7A&{;{UEFQPt&yNl4{XUf8N|X&mq!U=W=PxqODHlD~#W(e}B8Qj`8&Sy%}x3Rr7EA zJ>O}$cX{1$-KdVQ+|$$kzu_0~@t^liOMJKU&d>KQUcV+<^w&GATv%DvwC~VPzxmCt3y)X(Kbw0`seDKFn&;;@4XVy;t-EORy=Z^K8_vmJtKLa* zmp`j`RlChv@y?eAQ)k^;zv8yZ=M?fKifcJ0yx)`W+xzle zTi^1^JvE;zgnxh|Mwzdicgq!Q?lB0`{K6GRm^+##h{~#E#;sFrUAZ?c6+_ZFQgRdt95f zR_M$&EnDa3QoQAUFACbqX3f7Csb!uSP-I)Tba(j%%ZKNxlivGmdML|RwdCQs7KQ2+ zi~RF%Wh{Tbdg6q4Ure55ua9OvEY`i)=DEys+vhv)y`1~iZhgpR7RN|or=YMY4r=qB zD$bI9cjusAfAjfj{fl30!m19ZOnE#ZvuetBcWE=w42FsIovmA*otqQU|BY|^7wg8a zuUoUu`SkfcxL9!E(DRw^-%4hA?J%BPedF*mpN`c==T%Ry++Ez)cyGJvL%mal*BQhsO3gle~4UahJA z^w#7j=10!v--r*M?qra-?7&LP%a5Oa;h34Q@t*ZcpJ<+Pt2vi!-pzV;CQedShrdYo zgzmEMW{Ocej1LA?$9Ml>>b>Tfm7S4xR;^|CMZ5Rya?gIQ&G+14?0D~G;_Isie(PO~ zv_Eh2Z;FOvarb5sW@kgt420JXWA(LP(^i*MZ8I^bXrA)&;>#;n3WRhuW=;M-v97eZ zuJMw-$V{t)Y5b>6ZpUR;<%a##c^Z(A7k&BK;kl6>yNym=;_&<>BRy-2TRijr$N7Ez z7JH-a6+Dlcv2RP`g7-S26J8WY`)&E<|GoNx?Z@8NJA1!<`(b8!$8vr1&xS?O%HQuM zWxWgX>0KTldr#~;&nyN828W1;>kjOGH=UE)`mSwK8pmv7*4pJ_Et6xVw}^*#ArJ}dmQ{B{`I9-VrzN^0?*xNjFyF0YQZ_Flfzzii9H(;&zC9G?5~=FNP+ zsO_`n>wbGFdh@Es+mPn&8M7z93R*txv`$uB);8;d>M~vN42Gu_MRufpTT?#i-j#xM zr<~UFpV)=Zl&0F5rrfjAf4=YOxix)j1>TuiEevk=FjKvgd49&s1ukc@Lm$kVT9T}M zT=C-9s2oH4-M4RNKjSM;D+@Gq7VG{y>-E;?WV!75m2cjzQ=I5KQ}gQg+Q+fR8#EuD zd)b?_hV8-^udo@a?KeGjM&S6xb-&Au_L{Sv6YzWf<2S45=Cx0b9h%0unbnVfS*6{~dC5~= z3WsezyK!Us|D2qQCG)SREq|Tv{=4O}%;x@;ynE&M{LYWt-TQ1~X=Uf0v_1BdZQjqW z*>7d}K3n+d*K;|iKASm*zCNq7di{1b>&h3U=JSJSS4h)_(tHRa?1Rzf;;Szf}bFyBHi^x9k?XF0-|y*WmgRB`46X zSB3`VC7YwOe5Y+|OAE@$wVJ(f^W9@=x}YPm=-AMtf>jr${jCo&oY(n2&1VP5I8RqU Jmvv4FO#qulvt$4O literal 0 HcmV?d00001 diff --git a/tensorflow/compiler/xla/g3doc/images/xla_array_layout_figure2.png b/tensorflow/compiler/xla/g3doc/images/xla_array_layout_figure2.png new file mode 100644 index 0000000000000000000000000000000000000000..6439c6e40272ae6b2954e9d7f3de2df470a2b36d GIT binary patch literal 7913 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 YV|3EW+_cv-FfcH9y85}Sb4q9e0BqX ![](images/xla_array_layout_figure1.png) + +Figure 1 + +Figure 1 shows how an array F32[3,5] is laid out in memory with 2x2 tiling. A +shape with this layout is written as F32[3,5]{1,0:(2,2)}, where 1,0 relates to +the physical order of dimensions (minor_to_major field in Layout) while (2,2) +after the colon indicates tiling of the physical dimensions by a 2x2 tile. + +Intuitively tiles are laid out to cover the shape and then within each tile, +elements are then laid out without tiling, as in the example above, where the +right part of the example shows the layout in memory, including the white +padding elements that are added in order to have complete 2x2 tiles even though +the original array bounds are not even. + +The extra elements in the padding are not required to contain any particular +value. + +## Linear index formulas for tiling given a shape and a tile + +Without tiling, an element e=(en, en-1, ... , +e1) in an array with array bounds d=(dn, dn-1, +... , d1) (d1 is the most minor dimension) is laid out by major to +minor order at position: + +   linear_index(e, d) \ += linear_index((en, en-1, ... , e1), +(dn, dn-1, ... , d1)) \ += endn-1...d1 + +en-1dn-2...d1 + ... + e1 + +For simplicity of notation in this document we assume a tile has the same number +of dimensions as the array. In XLA's implementation of tiling, this is +generalized to tilings with fewer dimensions by leaving the initial most-major +dimensions unchanged and applying the tiling only to the most minor dimensions, +so that the tiling that is specified mentions a suffix of the physical +dimensions of the shape being tiled. + +When tiling of size (tn, tn-1, ... , t1) is +used, an element in the array with indices (en, en-1, ... +, e1) is mapped to this position in the final layout: + +   linear_index_with_tile(e, d, t) \ += linear_index((⌊e/t⌋, e mod t), (⌈d/t⌉, t))     (arithmetic is +elementwise, (a,b) is concatenation) \ += linear_index((⌊en/tn⌋, ... , +⌊e1/t1⌋, en mod tn, ... , +e1 mod t1), (⌈dn/tn⌉, ... , +⌈d1/t1⌉, tn, tn-1, ... , +t1)) \ += linear_index((⌊en/tn⌋, ... , +⌊e1/t1⌋), (⌈dn/tn⌉, ... , +⌈d1/t1⌉))∙tntn-1...t1 + +linear_index((en mod tn, ... , e1 mod +t1), (tn, tn-1, ... , t1)) + +The layout can be thought of as having two parts: +(⌊en/tn⌋, ... , ⌊e1/t1⌋), which +corresponds to a tile index in an array of tiles of size +(⌈dn/tn⌉, ... , ⌈d1/t1⌉), and +(en mod tn, ... , e1 mod t1), which +corresponds to a within-tile index. The ceil function appears in +⌈di/ti⌉ because if tiles overrun the bounds of the larger +array, padding is inserted as in Figure 1. Both the tiles and elements within +tiles are laid out recursively without tiling. + +For the example in Figure 1, element (2,3) has tile index (1,1), and within-tile +index (0,1), for a combined coordinate vector of (1, 1, 0, 1). The tile indices +have bounds (2, 3) and the tile itself is (2, 2) for a combined vector of (2, 3, +2, 2). The linear index with tile for the element with index (2, 3) in the +logical shape is then + +   linear_index_with_tile((2,3), (3,5), (2,2)) \ += linear_index((1,1,0,1), (2,3,2,2)) \ += linear_index((1,1), (2,3)) ∙ 2 ∙ 2 + linear_index((0,1), (2,2)) \ += (1 ∙ 3 + 1) ∙ 2 ∙ 2 + (0 ∙ 2 + 1) \ += 17. + +# Tiling as pad-reshape-transpose + +Tiling-based layout operates as follows: \ +Consider an array of dimensions (dn, dn-1, ... , d1) (d1 +is the most minor dimension). When it’s laid out with tiling of size +(tn, tn-1, ... , t1) (t1 is the most +minor dimension), that tiling can be described in terms of pad-reshape-transpose +in the following way. + +1. The array is padded to (⌈dn/tn⌉∙tn, ... , + ⌈d1/t1⌉∙t1). +2. Each dimension i is broken into (⌈di/ti⌉, + ti), i.e. the array is reshaped to \ +     (⌈dn/tn⌉, tn, ... , + ⌈d1/t1⌉, t1). \ + There is no physical layout change in this reshape by itself, so this + reshape is a bitcast. If one is not explicitly thinking of a tiling, this + reshape could express any shape with the same number of elements as the + padded shape - the example here is of how to express a tile in this way. +3. A transpose happens by moving tn, ... , t1 to the most + minor dimensions while keeping their relative order, so that the order of + dimensions from most major to most minor becomes \ +     (⌈dn/tn⌉, ... , + ⌈d1/t1⌉, tn, ... , t1). + +The final shape has the prefix \ +    (⌈dn/tn⌉, ... , +⌈d1/t1⌉), which describes the number of tiles in each +dimension. An element in the array (en, ... , e1) is +mapped to this element in the final shape: \ +    (⌊en/tn⌋, ... , +⌊e0/t0⌋, en mod tn, ... , +e1 mod t1). It is easy to see that the linear index of the +element follows the formula above as expected. + +# Repeated tiling + +XLA's tiling becomes even more flexible by applying it repeatedly. + +

vZd%xd(SYt9!aXY_Y`NPb)Kb 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

@H!{2liR=)l(KkK}p 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∨uwp|Q7Hvg9{wGM3iX5$t+V|Sa? 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